summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--integrations/api_notification_test.go8
-rw-r--r--models/issue.go3
-rw-r--r--models/issue_comment.go3
-rw-r--r--models/notification.go17
-rw-r--r--modules/structs/notifications.go5
-rw-r--r--routers/api/v1/api.go1
-rw-r--r--routers/api/v1/notify/notifications.go33
-rw-r--r--routers/api/v1/swagger/notify.go7
-rw-r--r--templates/swagger/v1_json.tmpl35
9 files changed, 107 insertions, 5 deletions
diff --git a/integrations/api_notification_test.go b/integrations/api_notification_test.go
index 2c5477dfb0..baab00f6d2 100644
--- a/integrations/api_notification_test.go
+++ b/integrations/api_notification_test.go
@@ -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)
@@ -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)
}
diff --git a/models/issue.go b/models/issue.go
index 25765292ae..b6408365f7 100644
--- a/models/issue.go
+++ b/models/issue.go
@@ -7,7 +7,6 @@ package models
import (
"fmt"
- "path"
"regexp"
"sort"
"strconv"
@@ -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.
diff --git a/models/issue_comment.go b/models/issue_comment.go
index 8f54d9656a..699b8f0487 100644
--- a/models/issue_comment.go
+++ b/models/issue_comment.go
@@ -8,7 +8,6 @@ package models
import (
"fmt"
- "path"
"strings"
"code.gitea.io/gitea/modules/git"
@@ -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
diff --git a/models/notification.go b/models/notification.go
index 8e9bca0dc6..403c53243d 100644
--- a/models/notification.go
+++ b/models/notification.go
@@ -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"
@@ -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{
@@ -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
diff --git a/modules/structs/notifications.go b/modules/structs/notifications.go
index b1e8b7781c..b6c9774a97 100644
--- a/modules/structs/notifications.go
+++ b/modules/structs/notifications.go
@@ -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"`
+}
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 86c7450173..4c9f9dd03e 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -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)
diff --git a/routers/api/v1/notify/notifications.go b/routers/api/v1/notify/notifications.go
new file mode 100644
index 0000000000..847fe3313e
--- /dev/null
+++ b/routers/api/v1/notify/notifications.go
@@ -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)
+ }
+}
diff --git a/routers/api/v1/swagger/notify.go b/routers/api/v1/swagger/notify.go
index 7d45da0e12..cd30d496e0 100644
--- a/routers/api/v1/swagger/notify.go
+++ b/routers/api/v1/swagger/notify.go
@@ -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"`
+}
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index a2baac1364..8ff4597b2e 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -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": [
@@ -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",
@@ -12397,6 +12426,12 @@
}
}
},
+ "NotificationCount": {
+ "description": "Number of unread notifications",
+ "schema": {
+ "$ref": "#/definitions/NotificationCount"
+ }
+ },
"NotificationThread": {
"description": "NotificationThread",
"schema": {