assert.EqualValues(t, false, apiNL[2].Pinned)
// -- GET /repos/{owner}/{repo}/notifications --
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?token=%s", user2.Name, repo1.Name, token))
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?status-types=unread&token=%s", user2.Name, repo1.Name, token))
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiNL)
assert.True(t, new.New > 0)
// -- 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?status-types=unread&token=%s", token))
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiNL)
assert.Len(t, apiNL, 2)
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
resp = session.MakeRequest(t, req, http.StatusResetContent)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiNL)
assert.Len(t, apiNL, 1)
var apiNL []api.NotificationThread
// -- 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?status-types=unread&token=%s", token))
resp := session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiNL)
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
resp = session.MakeRequest(t, req, http.StatusResetContent)
- req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
+ req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s&status-types=unread", token))
resp = session.MakeRequest(t, req, http.StatusOK)
DecodeJSON(t, resp, &apiNL)
assert.Len(t, apiNL, 1)
UserID int64
RepoID int64
IssueID int64
- Status NotificationStatus
+ Status []NotificationStatus
UpdatedAfterUnix int64
UpdatedBeforeUnix int64
}
if opts.IssueID != 0 {
cond = cond.And(builder.Eq{"notification.issue_id": opts.IssueID})
}
- if opts.Status != 0 {
- cond = cond.And(builder.Eq{"notification.status": opts.Status})
+ if len(opts.Status) > 0 {
+ cond = cond.And(builder.In("notification.status", opts.Status))
}
if opts.UpdatedAfterUnix != 0 {
cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix})
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/routers/api/v1/utils"
)
+func statusStringToNotificationStatus(status string) models.NotificationStatus {
+ switch strings.ToLower(strings.TrimSpace(status)) {
+ case "unread":
+ return models.NotificationStatusUnread
+ case "read":
+ return models.NotificationStatusRead
+ case "pinned":
+ return models.NotificationStatusPinned
+ default:
+ return 0
+ }
+}
+
+func statusStringsToNotificationStatuses(statuses []string, defaultStatuses []string) []models.NotificationStatus {
+ if len(statuses) == 0 {
+ statuses = defaultStatuses
+ }
+ results := make([]models.NotificationStatus, 0, len(statuses))
+ for _, status := range statuses {
+ notificationStatus := statusStringToNotificationStatus(status)
+ if notificationStatus > 0 {
+ results = append(results, notificationStatus)
+ }
+ }
+ return results
+}
+
// ListRepoNotifications list users's notification threads on a specific repo
func ListRepoNotifications(ctx *context.APIContext) {
// swagger:operation GET /repos/{owner}/{repo}/notifications notification notifyGetRepoList
// 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: since
// in: query
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
UpdatedBeforeUnix: before,
UpdatedAfterUnix: since,
}
- qAll := strings.Trim(ctx.Query("all"), " ")
- if qAll != "true" {
- opts.Status = models.NotificationStatusUnread
+
+ if !ctx.QueryBool("all") {
+ statuses := ctx.QueryStrings("status-types")
+ opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
}
nl, err := models.GetNotifications(opts)
if err != nil {
func ReadRepoNotifications(ctx *context.APIContext) {
// swagger:operation PUT /repos/{owner}/{repo}/notifications notification notifyReadRepoList
// ---
- // summary: Mark notification threads as read on a specific repo
+ // summary: Mark notification threads as read, pinned or unread on a specific repo
// consumes:
// - application/json
// produces:
// description: name of the repo
// type: string
// required: true
+ // - name: all
+ // in: query
+ // description: If true, mark all notifications on this repo. Default value is false
+ // type: string
+ // required: false
+ // - name: status-types
+ // in: query
+ // description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread."
+ // type: array
+ // collectionFormat: multi
+ // items:
+ // type: string
+ // required: false
+ // - name: to-status
+ // in: query
+ // description: Status to mark notifications as. Defaults to read.
+ // type: string
+ // required: false
// - name: last_read_at
// in: query
// description: Describes the last point that notifications were checked. Anything updated since this time will not be updated.
lastRead = tmpLastRead.Unix()
}
}
+
opts := models.FindNotificationOptions{
UserID: ctx.User.ID,
RepoID: ctx.Repo.Repository.ID,
UpdatedBeforeUnix: lastRead,
- Status: models.NotificationStatusUnread,
+ }
+
+ if !ctx.QueryBool("all") {
+ statuses := ctx.QueryStrings("status-types")
+ opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
+ log.Error("%v", opts.Status)
}
nl, err := models.GetNotifications(opts)
if err != nil {
return
}
+ targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
+ if targetStatus == 0 {
+ targetStatus = models.NotificationStatusRead
+ }
+
for _, n := range nl {
- err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
+ err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
if err != nil {
ctx.InternalServerError(err)
return
// description: id of notification thread
// type: string
// required: true
+ // - name: to-status
+ // in: query
+ // description: Status to mark notifications as
+ // type: string
+ // default: read
+ // required: false
// responses:
// "205":
// "$ref": "#/responses/empty"
return
}
- err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
+ targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
+ if targetStatus == 0 {
+ targetStatus = models.NotificationStatusRead
+ }
+
+ err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
if err != nil {
ctx.InternalServerError(err)
return
// 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: since
// in: query
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
UpdatedBeforeUnix: before,
UpdatedAfterUnix: since,
}
- qAll := strings.Trim(ctx.Query("all"), " ")
- if qAll != "true" {
- opts.Status = models.NotificationStatusUnread
+ 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.JSON(http.StatusOK, nl.APIFormat())
}
-// ReadNotifications mark notification threads as read
+// ReadNotifications mark notification threads as read, unread, or pinned
func ReadNotifications(ctx *context.APIContext) {
// swagger:operation PUT /notifications notification notifyReadList
// ---
- // summary: Mark notification threads as read
+ // summary: Mark notification threads as read, pinned or unread
// consumes:
// - application/json
// produces:
// type: string
// format: date-time
// required: false
+ // - name: all
+ // in: query
+ // description: If true, mark all notifications on this repo. Default value is false
+ // type: string
+ // required: false
+ // - name: status-types
+ // in: query
+ // description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread."
+ // type: array
+ // collectionFormat: multi
+ // items:
+ // type: string
+ // required: false
+ // - name: to-status
+ // in: query
+ // description: Status to mark notifications as, Defaults to read.
+ // type: string
+ // required: false
// responses:
// "205":
// "$ref": "#/responses/empty"
opts := models.FindNotificationOptions{
UserID: ctx.User.ID,
UpdatedBeforeUnix: lastRead,
- Status: models.NotificationStatusUnread,
+ }
+ if !ctx.QueryBool("all") {
+ statuses := ctx.QueryStrings("status-types")
+ opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
}
nl, err := models.GetNotifications(opts)
if err != nil {
return
}
+ targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
+ if targetStatus == 0 {
+ targetStatus = models.NotificationStatusRead
+ }
+
for _, n := range nl {
- err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
+ err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
if err != nil {
ctx.InternalServerError(err)
return
"name": "all",
"in": "query"
},
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread \u0026 pinned.",
+ "name": "status-types",
+ "in": "query"
+ },
{
"type": "string",
"format": "date-time",
"tags": [
"notification"
],
- "summary": "Mark notification threads as read",
+ "summary": "Mark notification threads as read, pinned or unread",
"operationId": "notifyReadList",
"parameters": [
{
"description": "Describes the last point that notifications were checked. Anything updated since this time will not be updated.",
"name": "last_read_at",
"in": "query"
+ },
+ {
+ "type": "string",
+ "description": "If true, mark all notifications on this repo. Default value is false",
+ "name": "all",
+ "in": "query"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread.",
+ "name": "status-types",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "Status to mark notifications as, Defaults to read.",
+ "name": "to-status",
+ "in": "query"
}
],
"responses": {
"name": "id",
"in": "path",
"required": true
+ },
+ {
+ "type": "string",
+ "default": "read",
+ "description": "Status to mark notifications as",
+ "name": "to-status",
+ "in": "query"
}
],
"responses": {
"name": "all",
"in": "query"
},
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread \u0026 pinned",
+ "name": "status-types",
+ "in": "query"
+ },
{
"type": "string",
"format": "date-time",
"tags": [
"notification"
],
- "summary": "Mark notification threads as read on a specific repo",
+ "summary": "Mark notification threads as read, pinned or unread on a specific repo",
"operationId": "notifyReadRepoList",
"parameters": [
{
"in": "path",
"required": true
},
+ {
+ "type": "string",
+ "description": "If true, mark all notifications on this repo. Default value is false",
+ "name": "all",
+ "in": "query"
+ },
+ {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "collectionFormat": "multi",
+ "description": "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread.",
+ "name": "status-types",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "Status to mark notifications as. Defaults to read.",
+ "name": "to-status",
+ "in": "query"
+ },
{
"type": "string",
"format": "date-time",