code.gitea.io/gitea@v1.21.7/routers/api/v1/repo/milestone.go (about) 1 // Copyright 2016 The Gogs Authors. All rights reserved. 2 // Copyright 2020 The Gitea Authors. 3 // SPDX-License-Identifier: MIT 4 5 package repo 6 7 import ( 8 "net/http" 9 "strconv" 10 "time" 11 12 issues_model "code.gitea.io/gitea/models/issues" 13 "code.gitea.io/gitea/modules/context" 14 api "code.gitea.io/gitea/modules/structs" 15 "code.gitea.io/gitea/modules/timeutil" 16 "code.gitea.io/gitea/modules/web" 17 "code.gitea.io/gitea/routers/api/v1/utils" 18 "code.gitea.io/gitea/services/convert" 19 ) 20 21 // ListMilestones list milestones for a repository 22 func ListMilestones(ctx *context.APIContext) { 23 // swagger:operation GET /repos/{owner}/{repo}/milestones issue issueGetMilestonesList 24 // --- 25 // summary: Get all of a repository's opened milestones 26 // produces: 27 // - application/json 28 // parameters: 29 // - name: owner 30 // in: path 31 // description: owner of the repo 32 // type: string 33 // required: true 34 // - name: repo 35 // in: path 36 // description: name of the repo 37 // type: string 38 // required: true 39 // - name: state 40 // in: query 41 // description: Milestone state, Recognized values are open, closed and all. Defaults to "open" 42 // type: string 43 // - name: name 44 // in: query 45 // description: filter by milestone name 46 // type: string 47 // - name: page 48 // in: query 49 // description: page number of results to return (1-based) 50 // type: integer 51 // - name: limit 52 // in: query 53 // description: page size of results 54 // type: integer 55 // responses: 56 // "200": 57 // "$ref": "#/responses/MilestoneList" 58 // "404": 59 // "$ref": "#/responses/notFound" 60 61 milestones, total, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{ 62 ListOptions: utils.GetListOptions(ctx), 63 RepoID: ctx.Repo.Repository.ID, 64 State: api.StateType(ctx.FormString("state")), 65 Name: ctx.FormString("name"), 66 }) 67 if err != nil { 68 ctx.Error(http.StatusInternalServerError, "GetMilestones", err) 69 return 70 } 71 72 apiMilestones := make([]*api.Milestone, len(milestones)) 73 for i := range milestones { 74 apiMilestones[i] = convert.ToAPIMilestone(milestones[i]) 75 } 76 77 ctx.SetTotalCountHeader(total) 78 ctx.JSON(http.StatusOK, &apiMilestones) 79 } 80 81 // GetMilestone get a milestone for a repository by ID and if not available by name 82 func GetMilestone(ctx *context.APIContext) { 83 // swagger:operation GET /repos/{owner}/{repo}/milestones/{id} issue issueGetMilestone 84 // --- 85 // summary: Get a milestone 86 // produces: 87 // - application/json 88 // parameters: 89 // - name: owner 90 // in: path 91 // description: owner of the repo 92 // type: string 93 // required: true 94 // - name: repo 95 // in: path 96 // description: name of the repo 97 // type: string 98 // required: true 99 // - name: id 100 // in: path 101 // description: the milestone to get, identified by ID and if not available by name 102 // type: string 103 // required: true 104 // responses: 105 // "200": 106 // "$ref": "#/responses/Milestone" 107 // "404": 108 // "$ref": "#/responses/notFound" 109 110 milestone := getMilestoneByIDOrName(ctx) 111 if ctx.Written() { 112 return 113 } 114 115 ctx.JSON(http.StatusOK, convert.ToAPIMilestone(milestone)) 116 } 117 118 // CreateMilestone create a milestone for a repository 119 func CreateMilestone(ctx *context.APIContext) { 120 // swagger:operation POST /repos/{owner}/{repo}/milestones issue issueCreateMilestone 121 // --- 122 // summary: Create a milestone 123 // consumes: 124 // - application/json 125 // produces: 126 // - application/json 127 // parameters: 128 // - name: owner 129 // in: path 130 // description: owner of the repo 131 // type: string 132 // required: true 133 // - name: repo 134 // in: path 135 // description: name of the repo 136 // type: string 137 // required: true 138 // - name: body 139 // in: body 140 // schema: 141 // "$ref": "#/definitions/CreateMilestoneOption" 142 // responses: 143 // "201": 144 // "$ref": "#/responses/Milestone" 145 // "404": 146 // "$ref": "#/responses/notFound" 147 form := web.GetForm(ctx).(*api.CreateMilestoneOption) 148 149 if form.Deadline == nil { 150 defaultDeadline, _ := time.ParseInLocation("2006-01-02", "9999-12-31", time.Local) 151 form.Deadline = &defaultDeadline 152 } 153 154 milestone := &issues_model.Milestone{ 155 RepoID: ctx.Repo.Repository.ID, 156 Name: form.Title, 157 Content: form.Description, 158 DeadlineUnix: timeutil.TimeStamp(form.Deadline.Unix()), 159 } 160 161 if form.State == "closed" { 162 milestone.IsClosed = true 163 milestone.ClosedDateUnix = timeutil.TimeStampNow() 164 } 165 166 if err := issues_model.NewMilestone(ctx, milestone); err != nil { 167 ctx.Error(http.StatusInternalServerError, "NewMilestone", err) 168 return 169 } 170 ctx.JSON(http.StatusCreated, convert.ToAPIMilestone(milestone)) 171 } 172 173 // EditMilestone modify a milestone for a repository by ID and if not available by name 174 func EditMilestone(ctx *context.APIContext) { 175 // swagger:operation PATCH /repos/{owner}/{repo}/milestones/{id} issue issueEditMilestone 176 // --- 177 // summary: Update a milestone 178 // consumes: 179 // - application/json 180 // produces: 181 // - application/json 182 // parameters: 183 // - name: owner 184 // in: path 185 // description: owner of the repo 186 // type: string 187 // required: true 188 // - name: repo 189 // in: path 190 // description: name of the repo 191 // type: string 192 // required: true 193 // - name: id 194 // in: path 195 // description: the milestone to edit, identified by ID and if not available by name 196 // type: string 197 // required: true 198 // - name: body 199 // in: body 200 // schema: 201 // "$ref": "#/definitions/EditMilestoneOption" 202 // responses: 203 // "200": 204 // "$ref": "#/responses/Milestone" 205 // "404": 206 // "$ref": "#/responses/notFound" 207 form := web.GetForm(ctx).(*api.EditMilestoneOption) 208 milestone := getMilestoneByIDOrName(ctx) 209 if ctx.Written() { 210 return 211 } 212 213 if len(form.Title) > 0 { 214 milestone.Name = form.Title 215 } 216 if form.Description != nil { 217 milestone.Content = *form.Description 218 } 219 if form.Deadline != nil && !form.Deadline.IsZero() { 220 milestone.DeadlineUnix = timeutil.TimeStamp(form.Deadline.Unix()) 221 } 222 223 oldIsClosed := milestone.IsClosed 224 if form.State != nil { 225 milestone.IsClosed = *form.State == string(api.StateClosed) 226 } 227 228 if err := issues_model.UpdateMilestone(ctx, milestone, oldIsClosed); err != nil { 229 ctx.Error(http.StatusInternalServerError, "UpdateMilestone", err) 230 return 231 } 232 ctx.JSON(http.StatusOK, convert.ToAPIMilestone(milestone)) 233 } 234 235 // DeleteMilestone delete a milestone for a repository by ID and if not available by name 236 func DeleteMilestone(ctx *context.APIContext) { 237 // swagger:operation DELETE /repos/{owner}/{repo}/milestones/{id} issue issueDeleteMilestone 238 // --- 239 // summary: Delete a milestone 240 // parameters: 241 // - name: owner 242 // in: path 243 // description: owner of the repo 244 // type: string 245 // required: true 246 // - name: repo 247 // in: path 248 // description: name of the repo 249 // type: string 250 // required: true 251 // - name: id 252 // in: path 253 // description: the milestone to delete, identified by ID and if not available by name 254 // type: string 255 // required: true 256 // responses: 257 // "204": 258 // "$ref": "#/responses/empty" 259 // "404": 260 // "$ref": "#/responses/notFound" 261 262 m := getMilestoneByIDOrName(ctx) 263 if ctx.Written() { 264 return 265 } 266 267 if err := issues_model.DeleteMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, m.ID); err != nil { 268 ctx.Error(http.StatusInternalServerError, "DeleteMilestoneByRepoID", err) 269 return 270 } 271 ctx.Status(http.StatusNoContent) 272 } 273 274 // getMilestoneByIDOrName get milestone by ID and if not available by name 275 func getMilestoneByIDOrName(ctx *context.APIContext) *issues_model.Milestone { 276 mile := ctx.Params(":id") 277 mileID, _ := strconv.ParseInt(mile, 0, 64) 278 279 if mileID != 0 { 280 milestone, err := issues_model.GetMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, mileID) 281 if err == nil { 282 return milestone 283 } else if !issues_model.IsErrMilestoneNotExist(err) { 284 ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err) 285 return nil 286 } 287 } 288 289 milestone, err := issues_model.GetMilestoneByRepoIDANDName(ctx, ctx.Repo.Repository.ID, mile) 290 if err != nil { 291 if issues_model.IsErrMilestoneNotExist(err) { 292 ctx.NotFound() 293 return nil 294 } 295 ctx.Error(http.StatusInternalServerError, "GetMilestoneByRepoID", err) 296 return nil 297 } 298 299 return milestone 300 }