Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 1 commit into from
Jun 16, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions models/notification.go
Original file line number Diff line number Diff line change
@@ -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)
}

43 changes: 43 additions & 0 deletions routers/api/v1/notify/notifications.go
Original file line number Diff line number Diff line change
@@ -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
}
33 changes: 12 additions & 21 deletions routers/api/v1/notify/repo.go
Original file line number Diff line number Diff line change
@@ -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,27 +66,31 @@ 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"
// type: array
// 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,
32 changes: 12 additions & 20 deletions routers/api/v1/notify/user.go
Original file line number Diff line number Diff line change
@@ -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,27 +28,31 @@ 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."
// type: array
// 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,
}
32 changes: 32 additions & 0 deletions templates/swagger/v1_json.tmpl
Original file line number Diff line number Diff line change
@@ -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",