Skip to content

Commit

Permalink
[API] add endpoint to check notifications [Extend #9488] (#9595)
Browse files Browse the repository at this point in the history
* introduce GET /notifications/new

* add TEST

* use Sprintf instead of path.Join

* Error more verbose

* return number of notifications if unreaded exist

* 200 http status for available notifications
  • Loading branch information
6543 authored and sapk committed Jan 14, 2020
1 parent ce274d6 commit 44de66b
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 5 deletions.
8 changes: 8 additions & 0 deletions integrations/api_notification_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ func TestAPINotification(t *testing.T) {
assert.EqualValues(t, thread5.Issue.APIURL(), apiN.Subject.URL)
assert.EqualValues(t, thread5.Repository.HTMLURL(), apiN.Repository.HTMLURL)

// -- check notifications --
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications/new?token=%s", token))
resp = session.MakeRequest(t, req, http.StatusOK)

// -- mark notifications as read --
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
resp = session.MakeRequest(t, req, http.StatusOK)
Expand All @@ -103,4 +107,8 @@ func TestAPINotification(t *testing.T) {
assert.Equal(t, models.NotificationStatusUnread, thread5.Status)
thread5 = models.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification)
assert.Equal(t, models.NotificationStatusRead, thread5.Status)

// -- check notifications --
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications/new?token=%s", token))
resp = session.MakeRequest(t, req, http.StatusNoContent)
}
3 changes: 1 addition & 2 deletions models/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package models

import (
"fmt"
"path"
"regexp"
"sort"
"strconv"
Expand Down Expand Up @@ -324,7 +323,7 @@ func (issue *Issue) GetIsRead(userID int64) error {

// APIURL returns the absolute APIURL to this issue.
func (issue *Issue) APIURL() string {
return issue.Repo.APIURL() + "/" + path.Join("issues", fmt.Sprint(issue.Index))
return fmt.Sprintf("%s/issues/%d", issue.Repo.APIURL(), issue.Index)
}

// HTMLURL returns the absolute URL to this issue.
Expand Down
3 changes: 1 addition & 2 deletions models/issue_comment.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ package models

import (
"fmt"
"path"
"strings"

"code.gitea.io/gitea/modules/git"
Expand Down Expand Up @@ -249,7 +248,7 @@ func (c *Comment) APIURL() string {
return ""
}

return c.Issue.Repo.APIURL() + "/" + path.Join("issues/comments", fmt.Sprint(c.ID))
return fmt.Sprintf("%s/issues/comments/%d", c.Issue.Repo.APIURL(), c.ID)
}

// IssueURL formats a URL-string to the issue
Expand Down
17 changes: 16 additions & 1 deletion models/notification.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"path"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
Expand Down Expand Up @@ -294,6 +295,20 @@ func notificationsForUser(e Engine, user *User, statuses []NotificationStatus, p
return
}

// CountUnread count unread notifications for a user
func CountUnread(user *User) int64 {
return countUnread(x, user.ID)
}

func countUnread(e Engine, userID int64) int64 {
exist, err := e.Where("user_id = ?", userID).And("status = ?", NotificationStatusUnread).Count(new(Notification))
if err != nil {
log.Error("countUnread", err)
return 0
}
return exist
}

// APIFormat converts a Notification to api.NotificationThread
func (n *Notification) APIFormat() *api.NotificationThread {
result := &api.NotificationThread{
Expand Down Expand Up @@ -388,7 +403,7 @@ func (n *Notification) loadComment(e Engine) (err error) {
if n.Comment == nil && n.CommentID > 0 {
n.Comment, err = GetCommentByID(n.CommentID)
if err != nil {
return fmt.Errorf("GetCommentByID [%d]: %v", n.CommentID, err)
return fmt.Errorf("GetCommentByID [%d] for issue ID [%d]: %v", n.CommentID, n.IssueID, err)
}
}
return nil
Expand Down
5 changes: 5 additions & 0 deletions modules/structs/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,8 @@ type NotificationSubject struct {
LatestCommentURL string `json:"latest_comment_url"`
Type string `json:"type" binding:"In(Issue,Pull,Commit)"`
}

// NotificationCount number of unread notifications
type NotificationCount struct {
New int64 `json:"new"`
}
1 change: 1 addition & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Combo("").
Get(notify.ListNotifications).
Put(notify.ReadNotifications)
m.Get("/new", notify.NewAvailable)
m.Combo("/threads/:id").
Get(notify.GetThread).
Patch(notify.ReadThread)
Expand Down
33 changes: 33 additions & 0 deletions routers/api/v1/notify/notifications.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package notify

import (
"net/http"

"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
)

// NewAvailable check if unread notifications exist
func NewAvailable(ctx *context.APIContext) {
// swagger:operation GET /notifications/new notification notifyNewAvailable
// ---
// summary: Check if unread notifications exist
// responses:
// "200":
// "$ref": "#/responses/NotificationCount"
// "204":
// description: No unread notification

count := models.CountUnread(ctx.User)

if count > 0 {
ctx.JSON(http.StatusOK, api.NotificationCount{New: count})
} else {
ctx.Status(http.StatusNoContent)
}
}
7 changes: 7 additions & 0 deletions routers/api/v1/swagger/notify.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,10 @@ type swaggerNotificationThreadList struct {
// in:body
Body []api.NotificationThread `json:"body"`
}

// Number of unread notifications
// swagger:response NotificationCount
type swaggerNotificationCount struct {
// in:body
Body api.NotificationCount `json:"body"`
}
35 changes: 35 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -494,6 +494,23 @@
}
}
},
"/notifications/new": {
"get": {
"tags": [
"notification"
],
"summary": "Check if unread notifications exist",
"operationId": "notifyNewAvailable",
"responses": {
"200": {
"$ref": "#/responses/NotificationCount"
},
"204": {
"description": "No unread notification"
}
}
}
},
"/notifications/threads/{id}": {
"get": {
"consumes": [
Expand Down Expand Up @@ -10911,6 +10928,18 @@
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"NotificationCount": {
"description": "NotificationCount number of unread notifications",
"type": "object",
"properties": {
"new": {
"type": "integer",
"format": "int64",
"x-go-name": "New"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
},
"NotificationSubject": {
"description": "NotificationSubject contains the notification subject (Issue/Pull/Commit)",
"type": "object",
Expand Down Expand Up @@ -12397,6 +12426,12 @@
}
}
},
"NotificationCount": {
"description": "Number of unread notifications",
"schema": {
"$ref": "#/definitions/NotificationCount"
}
},
"NotificationThread": {
"description": "NotificationThread",
"schema": {
Expand Down

0 comments on commit 44de66b

Please sign in to comment.