From 92736010646d4a5cfd3430c6f57bbf4cbd8951da Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Wed, 16 Jun 2021 19:04:37 +0200 Subject: [PATCH] Add subject-type filter to list notification API endpoints (#16177) Close #15886 --- models/notification.go | 8 +++-- routers/api/v1/notify/notifications.go | 43 ++++++++++++++++++++++++++ routers/api/v1/notify/repo.go | 33 +++++++------------- routers/api/v1/notify/user.go | 32 +++++++------------ templates/swagger/v1_json.tmpl | 32 +++++++++++++++++++ 5 files changed, 105 insertions(+), 43 deletions(-) diff --git a/models/notification.go b/models/notification.go index dcb032207..56abd0ed8 100644 --- a/models/notification.go +++ b/models/notification.go @@ -74,6 +74,7 @@ type FindNotificationOptions struct { RepoID int64 IssueID int64 Status []NotificationStatus + Source []NotificationSource UpdatedAfterUnix int64 UpdatedBeforeUnix int64 } @@ -93,6 +94,9 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond { if len(opts.Status) > 0 { 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 { cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix}) } @@ -111,13 +115,13 @@ func (opts *FindNotificationOptions) ToSession(e Engine) *xorm.Session { 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) return } // 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) } diff --git a/routers/api/v1/notify/notifications.go b/routers/api/v1/notify/notifications.go index 71dd7d949..a5e095a3b 100644 --- a/routers/api/v1/notify/notifications.go +++ b/routers/api/v1/notify/notifications.go @@ -6,10 +6,12 @@ package notify import ( "net/http" + "strings" "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/routers/api/v1/utils" ) // NewAvailable check if unread notifications exist @@ -22,3 +24,44 @@ func NewAvailable(ctx *context.APIContext) { // "$ref": "#/responses/NotificationCount" 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 +} diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 0a75fcd30..4deb16a22 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -13,7 +13,6 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/routers/api/v1/utils" ) func statusStringToNotificationStatus(status string) models.NotificationStatus { @@ -67,7 +66,6 @@ func ListRepoNotifications(ctx *context.APIContext) { // in: query // description: If true, show notifications marked as read. Default value is false // type: string - // required: false // - name: status-types // in: query // 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 // items: // 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 // in: query // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format // type: string // format: date-time - // required: false // - name: before // in: query // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format // type: string // format: date-time - // required: false // - name: page // in: query // description: page number of results to return (1-based) @@ -99,24 +102,12 @@ func ListRepoNotifications(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/NotificationThreadList" - - before, since, err := utils.GetQueryBeforeSince(ctx) - if err != nil { - ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) + opts := getFindNotificationOptions(ctx) + if ctx.Written() { return } - opts := models.FindNotificationOptions{ - ListOptions: utils.GetListOptions(ctx), - UserID: ctx.User.ID, - RepoID: ctx.Repo.Repository.ID, - UpdatedBeforeUnix: before, - UpdatedAfterUnix: since, - } + opts.RepoID = ctx.Repo.Repository.ID - if !ctx.QueryBool("all") { - statuses := ctx.QueryStrings("status-types") - opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"}) - } nl, err := models.GetNotifications(opts) if err != nil { ctx.InternalServerError(err) @@ -192,7 +183,7 @@ func ReadRepoNotifications(ctx *context.APIContext) { } } - opts := models.FindNotificationOptions{ + opts := &models.FindNotificationOptions{ UserID: ctx.User.ID, RepoID: ctx.Repo.Repository.ID, UpdatedBeforeUnix: lastRead, diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index e739c6a38..1ff62622b 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/convert" - "code.gitea.io/gitea/routers/api/v1/utils" ) // ListNotifications list users's notification threads @@ -29,7 +28,6 @@ func ListNotifications(ctx *context.APIContext) { // in: query // description: If true, show notifications marked as read. Default value is false // type: string - // required: false // - name: status-types // in: query // 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 // items: // 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 // in: query // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format // type: string // format: date-time - // required: false // - name: before // in: query // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format // type: string // format: date-time - // required: false // - name: page // in: query // description: page number of results to return (1-based) @@ -61,22 +64,11 @@ func ListNotifications(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/NotificationThreadList" - - before, since, err := utils.GetQueryBeforeSince(ctx) - if err != nil { - ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) + opts := getFindNotificationOptions(ctx) + if ctx.Written() { 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) if err != nil { ctx.InternalServerError(err) @@ -141,7 +133,7 @@ func ReadNotifications(ctx *context.APIContext) { lastRead = tmpLastRead.Unix() } } - opts := models.FindNotificationOptions{ + opts := &models.FindNotificationOptions{ UserID: ctx.User.ID, UpdatedBeforeUnix: lastRead, } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index e3ac4a4c8..8ad9ae5a4 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -645,6 +645,22 @@ "name": "status-types", "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", "format": "date-time", @@ -6805,6 +6821,22 @@ "name": "status-types", "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", "format": "date-time",