mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-28 12:16:17 +01:00
* 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
This commit is contained in:
parent
ce274d652f
commit
44de66bf50
9 changed files with 107 additions and 5 deletions
|
@ -81,6 +81,10 @@ func TestAPINotification(t *testing.T) {
|
||||||
assert.EqualValues(t, thread5.Issue.APIURL(), apiN.Subject.URL)
|
assert.EqualValues(t, thread5.Issue.APIURL(), apiN.Subject.URL)
|
||||||
assert.EqualValues(t, thread5.Repository.HTMLURL(), apiN.Repository.HTMLURL)
|
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 --
|
// -- mark notifications as read --
|
||||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
||||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
@ -103,4 +107,8 @@ func TestAPINotification(t *testing.T) {
|
||||||
assert.Equal(t, models.NotificationStatusUnread, thread5.Status)
|
assert.Equal(t, models.NotificationStatusUnread, thread5.Status)
|
||||||
thread5 = models.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification)
|
thread5 = models.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification)
|
||||||
assert.Equal(t, models.NotificationStatusRead, thread5.Status)
|
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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -324,7 +323,7 @@ func (issue *Issue) GetIsRead(userID int64) error {
|
||||||
|
|
||||||
// APIURL returns the absolute APIURL to this issue.
|
// APIURL returns the absolute APIURL to this issue.
|
||||||
func (issue *Issue) APIURL() string {
|
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.
|
// HTMLURL returns the absolute URL to this issue.
|
||||||
|
|
|
@ -8,7 +8,6 @@ package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/git"
|
"code.gitea.io/gitea/modules/git"
|
||||||
|
@ -249,7 +248,7 @@ func (c *Comment) APIURL() string {
|
||||||
return ""
|
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
|
// IssueURL formats a URL-string to the issue
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path"
|
"path"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
api "code.gitea.io/gitea/modules/structs"
|
api "code.gitea.io/gitea/modules/structs"
|
||||||
"code.gitea.io/gitea/modules/timeutil"
|
"code.gitea.io/gitea/modules/timeutil"
|
||||||
|
@ -294,6 +295,20 @@ func notificationsForUser(e Engine, user *User, statuses []NotificationStatus, p
|
||||||
return
|
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
|
// APIFormat converts a Notification to api.NotificationThread
|
||||||
func (n *Notification) APIFormat() *api.NotificationThread {
|
func (n *Notification) APIFormat() *api.NotificationThread {
|
||||||
result := &api.NotificationThread{
|
result := &api.NotificationThread{
|
||||||
|
@ -388,7 +403,7 @@ func (n *Notification) loadComment(e Engine) (err error) {
|
||||||
if n.Comment == nil && n.CommentID > 0 {
|
if n.Comment == nil && n.CommentID > 0 {
|
||||||
n.Comment, err = GetCommentByID(n.CommentID)
|
n.Comment, err = GetCommentByID(n.CommentID)
|
||||||
if err != nil {
|
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
|
return nil
|
||||||
|
|
|
@ -26,3 +26,8 @@ type NotificationSubject struct {
|
||||||
LatestCommentURL string `json:"latest_comment_url"`
|
LatestCommentURL string `json:"latest_comment_url"`
|
||||||
Type string `json:"type" binding:"In(Issue,Pull,Commit)"`
|
Type string `json:"type" binding:"In(Issue,Pull,Commit)"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NotificationCount number of unread notifications
|
||||||
|
type NotificationCount struct {
|
||||||
|
New int64 `json:"new"`
|
||||||
|
}
|
||||||
|
|
|
@ -518,6 +518,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
m.Combo("").
|
m.Combo("").
|
||||||
Get(notify.ListNotifications).
|
Get(notify.ListNotifications).
|
||||||
Put(notify.ReadNotifications)
|
Put(notify.ReadNotifications)
|
||||||
|
m.Get("/new", notify.NewAvailable)
|
||||||
m.Combo("/threads/:id").
|
m.Combo("/threads/:id").
|
||||||
Get(notify.GetThread).
|
Get(notify.GetThread).
|
||||||
Patch(notify.ReadThread)
|
Patch(notify.ReadThread)
|
||||||
|
|
33
routers/api/v1/notify/notifications.go
Normal file
33
routers/api/v1/notify/notifications.go
Normal file
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,3 +21,10 @@ type swaggerNotificationThreadList struct {
|
||||||
// in:body
|
// in:body
|
||||||
Body []api.NotificationThread `json:"body"`
|
Body []api.NotificationThread `json:"body"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Number of unread notifications
|
||||||
|
// swagger:response NotificationCount
|
||||||
|
type swaggerNotificationCount struct {
|
||||||
|
// in:body
|
||||||
|
Body api.NotificationCount `json:"body"`
|
||||||
|
}
|
||||||
|
|
|
@ -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}": {
|
"/notifications/threads/{id}": {
|
||||||
"get": {
|
"get": {
|
||||||
"consumes": [
|
"consumes": [
|
||||||
|
@ -10911,6 +10928,18 @@
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/modules/structs"
|
"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": {
|
"NotificationSubject": {
|
||||||
"description": "NotificationSubject contains the notification subject (Issue/Pull/Commit)",
|
"description": "NotificationSubject contains the notification subject (Issue/Pull/Commit)",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
|
@ -12397,6 +12426,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"NotificationCount": {
|
||||||
|
"description": "Number of unread notifications",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/NotificationCount"
|
||||||
|
}
|
||||||
|
},
|
||||||
"NotificationThread": {
|
"NotificationThread": {
|
||||||
"description": "NotificationThread",
|
"description": "NotificationThread",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
|
Loading…
Reference in a new issue