code.gitea.io/gitea@v1.21.7/routers/api/v1/notify/repo.go (about) 1 // Copyright 2020 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package notify 5 6 import ( 7 "net/http" 8 "strings" 9 "time" 10 11 activities_model "code.gitea.io/gitea/models/activities" 12 "code.gitea.io/gitea/modules/context" 13 "code.gitea.io/gitea/modules/log" 14 "code.gitea.io/gitea/modules/structs" 15 "code.gitea.io/gitea/services/convert" 16 ) 17 18 func statusStringToNotificationStatus(status string) activities_model.NotificationStatus { 19 switch strings.ToLower(strings.TrimSpace(status)) { 20 case "unread": 21 return activities_model.NotificationStatusUnread 22 case "read": 23 return activities_model.NotificationStatusRead 24 case "pinned": 25 return activities_model.NotificationStatusPinned 26 default: 27 return 0 28 } 29 } 30 31 func statusStringsToNotificationStatuses(statuses, defaultStatuses []string) []activities_model.NotificationStatus { 32 if len(statuses) == 0 { 33 statuses = defaultStatuses 34 } 35 results := make([]activities_model.NotificationStatus, 0, len(statuses)) 36 for _, status := range statuses { 37 notificationStatus := statusStringToNotificationStatus(status) 38 if notificationStatus > 0 { 39 results = append(results, notificationStatus) 40 } 41 } 42 return results 43 } 44 45 // ListRepoNotifications list users's notification threads on a specific repo 46 func ListRepoNotifications(ctx *context.APIContext) { 47 // swagger:operation GET /repos/{owner}/{repo}/notifications notification notifyGetRepoList 48 // --- 49 // summary: List users's notification threads on a specific repo 50 // consumes: 51 // - application/json 52 // produces: 53 // - application/json 54 // parameters: 55 // - name: owner 56 // in: path 57 // description: owner of the repo 58 // type: string 59 // required: true 60 // - name: repo 61 // in: path 62 // description: name of the repo 63 // type: string 64 // required: true 65 // - name: all 66 // in: query 67 // description: If true, show notifications marked as read. Default value is false 68 // type: boolean 69 // - name: status-types 70 // in: query 71 // description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned" 72 // type: array 73 // collectionFormat: multi 74 // items: 75 // type: string 76 // - name: subject-type 77 // in: query 78 // description: "filter notifications by subject type" 79 // type: array 80 // collectionFormat: multi 81 // items: 82 // type: string 83 // enum: [issue,pull,commit,repository] 84 // - name: since 85 // in: query 86 // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format 87 // type: string 88 // format: date-time 89 // - name: before 90 // in: query 91 // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format 92 // type: string 93 // format: date-time 94 // - name: page 95 // in: query 96 // description: page number of results to return (1-based) 97 // type: integer 98 // - name: limit 99 // in: query 100 // description: page size of results 101 // type: integer 102 // responses: 103 // "200": 104 // "$ref": "#/responses/NotificationThreadList" 105 opts := getFindNotificationOptions(ctx) 106 if ctx.Written() { 107 return 108 } 109 opts.RepoID = ctx.Repo.Repository.ID 110 111 totalCount, err := activities_model.CountNotifications(ctx, opts) 112 if err != nil { 113 ctx.InternalServerError(err) 114 return 115 } 116 117 nl, err := activities_model.GetNotifications(ctx, opts) 118 if err != nil { 119 ctx.InternalServerError(err) 120 return 121 } 122 err = nl.LoadAttributes(ctx) 123 if err != nil { 124 ctx.InternalServerError(err) 125 return 126 } 127 128 ctx.SetTotalCountHeader(totalCount) 129 130 ctx.JSON(http.StatusOK, convert.ToNotifications(ctx, nl)) 131 } 132 133 // ReadRepoNotifications mark notification threads as read on a specific repo 134 func ReadRepoNotifications(ctx *context.APIContext) { 135 // swagger:operation PUT /repos/{owner}/{repo}/notifications notification notifyReadRepoList 136 // --- 137 // summary: Mark notification threads as read, pinned or unread on a specific repo 138 // consumes: 139 // - application/json 140 // produces: 141 // - application/json 142 // parameters: 143 // - name: owner 144 // in: path 145 // description: owner of the repo 146 // type: string 147 // required: true 148 // - name: repo 149 // in: path 150 // description: name of the repo 151 // type: string 152 // required: true 153 // - name: all 154 // in: query 155 // description: If true, mark all notifications on this repo. Default value is false 156 // type: string 157 // required: false 158 // - name: status-types 159 // in: query 160 // description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread." 161 // type: array 162 // collectionFormat: multi 163 // items: 164 // type: string 165 // required: false 166 // - name: to-status 167 // in: query 168 // description: Status to mark notifications as. Defaults to read. 169 // type: string 170 // required: false 171 // - name: last_read_at 172 // in: query 173 // description: Describes the last point that notifications were checked. Anything updated since this time will not be updated. 174 // type: string 175 // format: date-time 176 // required: false 177 // responses: 178 // "205": 179 // "$ref": "#/responses/NotificationThreadList" 180 181 lastRead := int64(0) 182 qLastRead := ctx.FormTrim("last_read_at") 183 if len(qLastRead) > 0 { 184 tmpLastRead, err := time.Parse(time.RFC3339, qLastRead) 185 if err != nil { 186 ctx.Error(http.StatusBadRequest, "Parse", err) 187 return 188 } 189 if !tmpLastRead.IsZero() { 190 lastRead = tmpLastRead.Unix() 191 } 192 } 193 194 opts := &activities_model.FindNotificationOptions{ 195 UserID: ctx.Doer.ID, 196 RepoID: ctx.Repo.Repository.ID, 197 UpdatedBeforeUnix: lastRead, 198 } 199 200 if !ctx.FormBool("all") { 201 statuses := ctx.FormStrings("status-types") 202 opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"}) 203 log.Error("%v", opts.Status) 204 } 205 nl, err := activities_model.GetNotifications(ctx, opts) 206 if err != nil { 207 ctx.InternalServerError(err) 208 return 209 } 210 211 targetStatus := statusStringToNotificationStatus(ctx.FormString("to-status")) 212 if targetStatus == 0 { 213 targetStatus = activities_model.NotificationStatusRead 214 } 215 216 changed := make([]*structs.NotificationThread, 0, len(nl)) 217 218 for _, n := range nl { 219 notif, err := activities_model.SetNotificationStatus(ctx, n.ID, ctx.Doer, targetStatus) 220 if err != nil { 221 ctx.InternalServerError(err) 222 return 223 } 224 _ = notif.LoadAttributes(ctx) 225 changed = append(changed, convert.ToNotificationThread(ctx, notif)) 226 } 227 ctx.JSON(http.StatusResetContent, changed) 228 }