mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08: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:
		@@ -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": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user