From 36f2306d5f4bfa66a8298d724d460ac2ac4d903a Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Tue, 5 Feb 2019 16:53:43 +0100 Subject: [PATCH 1/5] allow issue stopwatch to be toggled via an api call --- routers/api/v1/api.go | 1 + routers/api/v1/repo/issue.go | 62 ++++++++++++++++++++++++++++++++++ templates/swagger/v1_json.tmpl | 50 +++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 55f5c6629062b..952d93b360d12 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -557,6 +557,7 @@ func RegisterRoutes(m *macaron.Macaron) { }) m.Combo("/deadline").Post(reqToken(), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline) + m.Post("/stopwatch/toggle", reqToken(), repo.ToggleIssueStopwatch) }) }, mustEnableIssuesOrPulls) m.Group("/labels", func() { diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 1cb9c2f81920e..439c933717989 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -439,3 +439,65 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) { ctx.JSON(201, api.IssueDeadline{Deadline: &deadline}) } + +// ToggleIssueStopwatch creates or stops a stopwatch for the given issue. +func ToggleIssueStopwatch(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/toggle issue issueToggleStopWatch + // --- + // summary: Toggle stopwatch on an issue. + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue to create or stop the stopwatch on + // type: integer + // format: int64 + // required: true + // responses: + // "201": + // "$ref": "#/responses/empty" + // "403": + // description: Not repo writer or user does not have rights to toggle stopwatch + // "404": + // description: Issue not found + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrIssueNotExist(err) { + ctx.Status(404) + } else { + ctx.Error(500, "GetIssueByIndex", err) + } + + return + } + + if !ctx.Repo.CanWrite(models.UnitTypeIssues) { + ctx.Status(403) + return + } + + if !ctx.Repo.CanUseTimetracker(issue, ctx.User) { + ctx.Status(403) + return + } + + if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil { + ctx.ServerError("CreateOrStopIssueStopwatch", err) + return + } + + ctx.Status(201) +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index bde496c7f1474..4011a832ec054 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2924,6 +2924,56 @@ } } }, + "/repos/{owner}/{repo}/issues/{index}/stopwatch/toggle": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "issue" + ], + "summary": "Toggle stopwatch on an issue.", + "operationId": "issueToggleStopWatch", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "index of the issue to create or stop the stopwatch on", + "name": "index", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "$ref": "#/responses/empty" + }, + "403": { + "description": "Not repo writer or user does not have rights to toggle stopwatch" + }, + "404": { + "description": "Issue not found" + } + } + } + }, "/repos/{owner}/{repo}/keys": { "get": { "produces": [ From 2f9fb240e3bcd3e2fe29dd4ab6709c8823ff007b Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Tue, 5 Feb 2019 23:06:49 +0100 Subject: [PATCH 2/5] split toggle endpoint into 'start' and 'stop' to make it more explicit --- routers/api/v1/api.go | 5 +- routers/api/v1/repo/issue.go | 84 +++++++++++++++++++++++++++++++--- templates/swagger/v1_json.tmpl | 58 +++++++++++++++++++++-- 3 files changed, 136 insertions(+), 11 deletions(-) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 952d93b360d12..c5a5488a812c8 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -557,7 +557,10 @@ func RegisterRoutes(m *macaron.Macaron) { }) m.Combo("/deadline").Post(reqToken(), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline) - m.Post("/stopwatch/toggle", reqToken(), repo.ToggleIssueStopwatch) + m.Group("/stopwatch", func() { + m.Post("/start", reqToken(), repo.StartIssueStopwatch) + m.Post("/stop", reqToken(), repo.StopIssueStopwatch) + }) }) }, mustEnableIssuesOrPulls) m.Group("/labels", func() { diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 439c933717989..1eb1c9568a45e 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -440,11 +440,11 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) { ctx.JSON(201, api.IssueDeadline{Deadline: &deadline}) } -// ToggleIssueStopwatch creates or stops a stopwatch for the given issue. -func ToggleIssueStopwatch(ctx *context.APIContext) { - // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/toggle issue issueToggleStopWatch +// StartIssueStopwatch creates or stops a stopwatch for the given issue. +func StartIssueStopwatch(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/start issue issueStartStopWatch // --- - // summary: Toggle stopwatch on an issue. + // summary: Start stopwatch on an issue. // consumes: // - application/json // produces: @@ -470,7 +470,7 @@ func ToggleIssueStopwatch(ctx *context.APIContext) { // "201": // "$ref": "#/responses/empty" // "403": - // description: Not repo writer or user does not have rights to toggle stopwatch + // description: Not repo writer, user does not have rights to toggle stopwatch or trying to start a stopwatch again if it already exists // "404": // description: Issue not found issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) @@ -494,8 +494,80 @@ func ToggleIssueStopwatch(ctx *context.APIContext) { return } + if models.StopwatchExists(ctx.User.ID, issue.ID) { + ctx.Error(403, "StopwatchExists", "a stopwatch has already been started for this issue") + return + } + + if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil { + ctx.Error(500, "CreateOrStopIssueStopwatch", err) + return + } + + ctx.Status(201) +} + +// StopIssueStopwatch creates or stops a stopwatch for the given issue. +func StopIssueStopwatch(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/stop issue issueStopWatch + // --- + // summary: Stop an issue's existing stopwatch. + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue to create or stop the stopwatch on + // type: integer + // format: int64 + // required: true + // responses: + // "201": + // "$ref": "#/responses/empty" + // "403": + // description: Not repo writer, user does not have rights to toggle stopwatch or trying to stop a non existent stopwatch + // "404": + // description: Issue not found + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrIssueNotExist(err) { + ctx.Status(404) + } else { + ctx.Error(500, "GetIssueByIndex", err) + } + + return + } + + if !ctx.Repo.CanWrite(models.UnitTypeIssues) { + ctx.Status(403) + return + } + + if !ctx.Repo.CanUseTimetracker(issue, ctx.User) { + ctx.Status(403) + return + } + + if !models.StopwatchExists(ctx.User.ID, issue.ID) { + ctx.Error(403, "StopwatchExists", "cannot stop a non existent stopwatch") + return + } + if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil { - ctx.ServerError("CreateOrStopIssueStopwatch", err) + ctx.Error(500, "CreateOrStopIssueStopwatch", err) return } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 4011a832ec054..fc52ad808b32e 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2924,7 +2924,7 @@ } } }, - "/repos/{owner}/{repo}/issues/{index}/stopwatch/toggle": { + "/repos/{owner}/{repo}/issues/{index}/stopwatch/start": { "post": { "consumes": [ "application/json" @@ -2935,8 +2935,8 @@ "tags": [ "issue" ], - "summary": "Toggle stopwatch on an issue.", - "operationId": "issueToggleStopWatch", + "summary": "Start stopwatch on an issue.", + "operationId": "issueStartStopWatch", "parameters": [ { "type": "string", @@ -2966,7 +2966,57 @@ "$ref": "#/responses/empty" }, "403": { - "description": "Not repo writer or user does not have rights to toggle stopwatch" + "description": "Not repo writer, user does not have rights to toggle stopwatch or trying to start a stopwatch again if it already exists" + }, + "404": { + "description": "Issue not found" + } + } + } + }, + "/repos/{owner}/{repo}/issues/{index}/stopwatch/stop": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "issue" + ], + "summary": "Stop an issue's existing stopwatch.", + "operationId": "issueStopWatch", + "parameters": [ + { + "type": "string", + "description": "owner of the repo", + "name": "owner", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "name of the repo", + "name": "repo", + "in": "path", + "required": true + }, + { + "type": "integer", + "format": "int64", + "description": "index of the issue to create or stop the stopwatch on", + "name": "index", + "in": "path", + "required": true + } + ], + "responses": { + "201": { + "$ref": "#/responses/empty" + }, + "403": { + "description": "Not repo writer, user does not have rights to toggle stopwatch or trying to stop a non existent stopwatch" }, "404": { "description": "Issue not found" From 132960f139acc9f98deb0086604a08af00ccc3da Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Tue, 5 Feb 2019 23:13:04 +0100 Subject: [PATCH 3/5] update swagger docs --- routers/api/v1/repo/issue.go | 4 ++-- templates/swagger/v1_json.tmpl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 1eb1c9568a45e..881d588760e23 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -462,7 +462,7 @@ func StartIssueStopwatch(ctx *context.APIContext) { // required: true // - name: index // in: path - // description: index of the issue to create or stop the stopwatch on + // description: index of the issue to create the stopwatch on // type: integer // format: int64 // required: true @@ -529,7 +529,7 @@ func StopIssueStopwatch(ctx *context.APIContext) { // required: true // - name: index // in: path - // description: index of the issue to create or stop the stopwatch on + // description: index of the issue to stop the stopwatch on // type: integer // format: int64 // required: true diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index fc52ad808b32e..1abf8056a633a 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2955,7 +2955,7 @@ { "type": "integer", "format": "int64", - "description": "index of the issue to create or stop the stopwatch on", + "description": "index of the issue to create the stopwatch on", "name": "index", "in": "path", "required": true @@ -3005,7 +3005,7 @@ { "type": "integer", "format": "int64", - "description": "index of the issue to create or stop the stopwatch on", + "description": "index of the issue to stop the stopwatch on", "name": "index", "in": "path", "required": true From 95b92cff3195859e0dd6dde4ec4196c3ebc06570 Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Tue, 5 Feb 2019 23:23:04 +0100 Subject: [PATCH 4/5] fix godoc --- routers/api/v1/repo/issue.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 881d588760e23..3795772fda17e 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -440,7 +440,7 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) { ctx.JSON(201, api.IssueDeadline{Deadline: &deadline}) } -// StartIssueStopwatch creates or stops a stopwatch for the given issue. +// StartIssueStopwatch creates a stopwatch for the given issue. func StartIssueStopwatch(ctx *context.APIContext) { // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/start issue issueStartStopWatch // --- @@ -507,7 +507,7 @@ func StartIssueStopwatch(ctx *context.APIContext) { ctx.Status(201) } -// StopIssueStopwatch creates or stops a stopwatch for the given issue. +// StopIssueStopwatch stops a stopwatch for the given issue. func StopIssueStopwatch(ctx *context.APIContext) { // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/stop issue issueStopWatch // --- From 53786c7de2d9a609fbf424d713adcae32e870e5f Mon Sep 17 00:00:00 2001 From: Lanre Adelowo Date: Wed, 6 Feb 2019 09:52:12 +0100 Subject: [PATCH 5/5] use 409 instead of 403 --- routers/api/v1/repo/issue.go | 12 ++++++++---- templates/swagger/v1_json.tmpl | 10 ++++++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 3795772fda17e..d339d8f0b771d 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -470,9 +470,11 @@ func StartIssueStopwatch(ctx *context.APIContext) { // "201": // "$ref": "#/responses/empty" // "403": - // description: Not repo writer, user does not have rights to toggle stopwatch or trying to start a stopwatch again if it already exists + // description: Not repo writer, user does not have rights to toggle stopwatch // "404": // description: Issue not found + // "409": + // description: Cannot start a stopwatch again if it already exists issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { @@ -495,7 +497,7 @@ func StartIssueStopwatch(ctx *context.APIContext) { } if models.StopwatchExists(ctx.User.ID, issue.ID) { - ctx.Error(403, "StopwatchExists", "a stopwatch has already been started for this issue") + ctx.Error(409, "StopwatchExists", "a stopwatch has already been started for this issue") return } @@ -537,9 +539,11 @@ func StopIssueStopwatch(ctx *context.APIContext) { // "201": // "$ref": "#/responses/empty" // "403": - // description: Not repo writer, user does not have rights to toggle stopwatch or trying to stop a non existent stopwatch + // description: Not repo writer, user does not have rights to toggle stopwatch // "404": // description: Issue not found + // "409": + // description: Cannot stop a non existent stopwatch issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrIssueNotExist(err) { @@ -562,7 +566,7 @@ func StopIssueStopwatch(ctx *context.APIContext) { } if !models.StopwatchExists(ctx.User.ID, issue.ID) { - ctx.Error(403, "StopwatchExists", "cannot stop a non existent stopwatch") + ctx.Error(409, "StopwatchExists", "cannot stop a non existent stopwatch") return } diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 1abf8056a633a..908bbb37d544a 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -2966,10 +2966,13 @@ "$ref": "#/responses/empty" }, "403": { - "description": "Not repo writer, user does not have rights to toggle stopwatch or trying to start a stopwatch again if it already exists" + "description": "Not repo writer, user does not have rights to toggle stopwatch" }, "404": { "description": "Issue not found" + }, + "409": { + "description": "Cannot start a stopwatch again if it already exists" } } } @@ -3016,10 +3019,13 @@ "$ref": "#/responses/empty" }, "403": { - "description": "Not repo writer, user does not have rights to toggle stopwatch or trying to stop a non existent stopwatch" + "description": "Not repo writer, user does not have rights to toggle stopwatch" }, "404": { "description": "Issue not found" + }, + "409": { + "description": "Cannot stop a non existent stopwatch" } } }