Add subject-type filter to list notification API endpoints (#16177)

Close #15886
This commit is contained in:
6543 2021-06-16 19:04:37 +02:00 committed by GitHub
parent f4d3bf7867
commit 9273601064
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 105 additions and 43 deletions

View file

@ -74,6 +74,7 @@ type FindNotificationOptions struct {
RepoID int64 RepoID int64
IssueID int64 IssueID int64
Status []NotificationStatus Status []NotificationStatus
Source []NotificationSource
UpdatedAfterUnix int64 UpdatedAfterUnix int64
UpdatedBeforeUnix int64 UpdatedBeforeUnix int64
} }
@ -93,6 +94,9 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond {
if len(opts.Status) > 0 { if len(opts.Status) > 0 {
cond = cond.And(builder.In("notification.status", opts.Status)) cond = cond.And(builder.In("notification.status", opts.Status))
} }
if len(opts.Source) > 0 {
cond = cond.And(builder.In("notification.source", opts.Source))
}
if opts.UpdatedAfterUnix != 0 { if opts.UpdatedAfterUnix != 0 {
cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix}) cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix})
} }
@ -111,13 +115,13 @@ func (opts *FindNotificationOptions) ToSession(e Engine) *xorm.Session {
return sess return sess
} }
func getNotifications(e Engine, options FindNotificationOptions) (nl NotificationList, err error) { func getNotifications(e Engine, options *FindNotificationOptions) (nl NotificationList, err error) {
err = options.ToSession(e).OrderBy("notification.updated_unix DESC").Find(&nl) err = options.ToSession(e).OrderBy("notification.updated_unix DESC").Find(&nl)
return return
} }
// GetNotifications returns all notifications that fit to the given options. // GetNotifications returns all notifications that fit to the given options.
func GetNotifications(opts FindNotificationOptions) (NotificationList, error) { func GetNotifications(opts *FindNotificationOptions) (NotificationList, error) {
return getNotifications(x, opts) return getNotifications(x, opts)
} }

View file

@ -6,10 +6,12 @@ package notify
import ( import (
"net/http" "net/http"
"strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/utils"
) )
// NewAvailable check if unread notifications exist // NewAvailable check if unread notifications exist
@ -22,3 +24,44 @@ func NewAvailable(ctx *context.APIContext) {
// "$ref": "#/responses/NotificationCount" // "$ref": "#/responses/NotificationCount"
ctx.JSON(http.StatusOK, api.NotificationCount{New: models.CountUnread(ctx.User)}) ctx.JSON(http.StatusOK, api.NotificationCount{New: models.CountUnread(ctx.User)})
} }
func getFindNotificationOptions(ctx *context.APIContext) *models.FindNotificationOptions {
before, since, err := utils.GetQueryBeforeSince(ctx)
if err != nil {
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return nil
}
opts := &models.FindNotificationOptions{
ListOptions: utils.GetListOptions(ctx),
UserID: ctx.User.ID,
UpdatedBeforeUnix: before,
UpdatedAfterUnix: since,
}
if !ctx.QueryBool("all") {
statuses := ctx.QueryStrings("status-types")
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
}
subjectTypes := ctx.QueryStrings("subject-type")
if len(subjectTypes) != 0 {
opts.Source = subjectToSource(subjectTypes)
}
return opts
}
func subjectToSource(value []string) (result []models.NotificationSource) {
for _, v := range value {
switch strings.ToLower(v) {
case "issue":
result = append(result, models.NotificationSourceIssue)
case "pull":
result = append(result, models.NotificationSourcePullRequest)
case "commit":
result = append(result, models.NotificationSourceCommit)
case "repository":
result = append(result, models.NotificationSourceRepository)
}
}
return
}

View file

@ -13,7 +13,6 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/api/v1/utils"
) )
func statusStringToNotificationStatus(status string) models.NotificationStatus { func statusStringToNotificationStatus(status string) models.NotificationStatus {
@ -67,7 +66,6 @@ func ListRepoNotifications(ctx *context.APIContext) {
// in: query // in: query
// description: If true, show notifications marked as read. Default value is false // description: If true, show notifications marked as read. Default value is false
// type: string // type: string
// required: false
// - name: status-types // - name: status-types
// in: query // in: query
// description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned" // description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned"
@ -75,19 +73,24 @@ func ListRepoNotifications(ctx *context.APIContext) {
// collectionFormat: multi // collectionFormat: multi
// items: // items:
// type: string // type: string
// required: false // - name: subject-type
// in: query
// description: "filter notifications by subject type"
// type: array
// collectionFormat: multi
// items:
// type: string
// enum: [issue,pull,commit,repository]
// - name: since // - name: since
// in: query // in: query
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
// type: string // type: string
// format: date-time // format: date-time
// required: false
// - name: before // - name: before
// in: query // in: query
// description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format
// type: string // type: string
// format: date-time // format: date-time
// required: false
// - name: page // - name: page
// in: query // in: query
// description: page number of results to return (1-based) // description: page number of results to return (1-based)
@ -99,24 +102,12 @@ func ListRepoNotifications(ctx *context.APIContext) {
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/NotificationThreadList" // "$ref": "#/responses/NotificationThreadList"
opts := getFindNotificationOptions(ctx)
before, since, err := utils.GetQueryBeforeSince(ctx) if ctx.Written() {
if err != nil {
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return return
} }
opts := models.FindNotificationOptions{ opts.RepoID = ctx.Repo.Repository.ID
ListOptions: utils.GetListOptions(ctx),
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
UpdatedBeforeUnix: before,
UpdatedAfterUnix: since,
}
if !ctx.QueryBool("all") {
statuses := ctx.QueryStrings("status-types")
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
}
nl, err := models.GetNotifications(opts) nl, err := models.GetNotifications(opts)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
@ -192,7 +183,7 @@ func ReadRepoNotifications(ctx *context.APIContext) {
} }
} }
opts := models.FindNotificationOptions{ opts := &models.FindNotificationOptions{
UserID: ctx.User.ID, UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID, RepoID: ctx.Repo.Repository.ID,
UpdatedBeforeUnix: lastRead, UpdatedBeforeUnix: lastRead,

View file

@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/convert"
"code.gitea.io/gitea/routers/api/v1/utils"
) )
// ListNotifications list users's notification threads // ListNotifications list users's notification threads
@ -29,7 +28,6 @@ func ListNotifications(ctx *context.APIContext) {
// in: query // in: query
// description: If true, show notifications marked as read. Default value is false // description: If true, show notifications marked as read. Default value is false
// type: string // type: string
// required: false
// - name: status-types // - name: status-types
// in: query // in: query
// description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned." // description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned."
@ -37,19 +35,24 @@ func ListNotifications(ctx *context.APIContext) {
// collectionFormat: multi // collectionFormat: multi
// items: // items:
// type: string // type: string
// required: false // - name: subject-type
// in: query
// description: "filter notifications by subject type"
// type: array
// collectionFormat: multi
// items:
// type: string
// enum: [issue,pull,commit,repository]
// - name: since // - name: since
// in: query // in: query
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
// type: string // type: string
// format: date-time // format: date-time
// required: false
// - name: before // - name: before
// in: query // in: query
// description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format
// type: string // type: string
// format: date-time // format: date-time
// required: false
// - name: page // - name: page
// in: query // in: query
// description: page number of results to return (1-based) // description: page number of results to return (1-based)
@ -61,22 +64,11 @@ func ListNotifications(ctx *context.APIContext) {
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/NotificationThreadList" // "$ref": "#/responses/NotificationThreadList"
opts := getFindNotificationOptions(ctx)
before, since, err := utils.GetQueryBeforeSince(ctx) if ctx.Written() {
if err != nil {
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return return
} }
opts := models.FindNotificationOptions{
ListOptions: utils.GetListOptions(ctx),
UserID: ctx.User.ID,
UpdatedBeforeUnix: before,
UpdatedAfterUnix: since,
}
if !ctx.QueryBool("all") {
statuses := ctx.QueryStrings("status-types")
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
}
nl, err := models.GetNotifications(opts) nl, err := models.GetNotifications(opts)
if err != nil { if err != nil {
ctx.InternalServerError(err) ctx.InternalServerError(err)
@ -141,7 +133,7 @@ func ReadNotifications(ctx *context.APIContext) {
lastRead = tmpLastRead.Unix() lastRead = tmpLastRead.Unix()
} }
} }
opts := models.FindNotificationOptions{ opts := &models.FindNotificationOptions{
UserID: ctx.User.ID, UserID: ctx.User.ID,
UpdatedBeforeUnix: lastRead, UpdatedBeforeUnix: lastRead,
} }

View file

@ -645,6 +645,22 @@
"name": "status-types", "name": "status-types",
"in": "query" "in": "query"
}, },
{
"type": "array",
"items": {
"enum": [
"issue",
"pull",
"commit",
"repository"
],
"type": "string"
},
"collectionFormat": "multi",
"description": "filter notifications by subject type",
"name": "subject-type",
"in": "query"
},
{ {
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",
@ -6805,6 +6821,22 @@
"name": "status-types", "name": "status-types",
"in": "query" "in": "query"
}, },
{
"type": "array",
"items": {
"enum": [
"issue",
"pull",
"commit",
"repository"
],
"type": "string"
},
"collectionFormat": "multi",
"description": "filter notifications by subject type",
"name": "subject-type",
"in": "query"
},
{ {
"type": "string", "type": "string",
"format": "date-time", "format": "date-time",