Skip to content

Commit 9dfdf80

Browse files
adelowotechknowlogick
authored andcommitted
Expose issue stopwatch toggling via API (#5970)
1 parent cc48c12 commit 9dfdf80

File tree

3 files changed

+248
-0
lines changed

3 files changed

+248
-0
lines changed

routers/api/v1/api.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,10 @@ func RegisterRoutes(m *macaron.Macaron) {
557557
})
558558

559559
m.Combo("/deadline").Post(reqToken(), bind(api.EditDeadlineOption{}), repo.UpdateIssueDeadline)
560+
m.Group("/stopwatch", func() {
561+
m.Post("/start", reqToken(), repo.StartIssueStopwatch)
562+
m.Post("/stop", reqToken(), repo.StopIssueStopwatch)
563+
})
560564
})
561565
}, mustEnableIssuesOrPulls)
562566
m.Group("/labels", func() {

routers/api/v1/repo/issue.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,3 +439,141 @@ func UpdateIssueDeadline(ctx *context.APIContext, form api.EditDeadlineOption) {
439439

440440
ctx.JSON(201, api.IssueDeadline{Deadline: &deadline})
441441
}
442+
443+
// StartIssueStopwatch creates a stopwatch for the given issue.
444+
func StartIssueStopwatch(ctx *context.APIContext) {
445+
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/start issue issueStartStopWatch
446+
// ---
447+
// summary: Start stopwatch on an issue.
448+
// consumes:
449+
// - application/json
450+
// produces:
451+
// - application/json
452+
// parameters:
453+
// - name: owner
454+
// in: path
455+
// description: owner of the repo
456+
// type: string
457+
// required: true
458+
// - name: repo
459+
// in: path
460+
// description: name of the repo
461+
// type: string
462+
// required: true
463+
// - name: index
464+
// in: path
465+
// description: index of the issue to create the stopwatch on
466+
// type: integer
467+
// format: int64
468+
// required: true
469+
// responses:
470+
// "201":
471+
// "$ref": "#/responses/empty"
472+
// "403":
473+
// description: Not repo writer, user does not have rights to toggle stopwatch
474+
// "404":
475+
// description: Issue not found
476+
// "409":
477+
// description: Cannot start a stopwatch again if it already exists
478+
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
479+
if err != nil {
480+
if models.IsErrIssueNotExist(err) {
481+
ctx.Status(404)
482+
} else {
483+
ctx.Error(500, "GetIssueByIndex", err)
484+
}
485+
486+
return
487+
}
488+
489+
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
490+
ctx.Status(403)
491+
return
492+
}
493+
494+
if !ctx.Repo.CanUseTimetracker(issue, ctx.User) {
495+
ctx.Status(403)
496+
return
497+
}
498+
499+
if models.StopwatchExists(ctx.User.ID, issue.ID) {
500+
ctx.Error(409, "StopwatchExists", "a stopwatch has already been started for this issue")
501+
return
502+
}
503+
504+
if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil {
505+
ctx.Error(500, "CreateOrStopIssueStopwatch", err)
506+
return
507+
}
508+
509+
ctx.Status(201)
510+
}
511+
512+
// StopIssueStopwatch stops a stopwatch for the given issue.
513+
func StopIssueStopwatch(ctx *context.APIContext) {
514+
// swagger:operation POST /repos/{owner}/{repo}/issues/{index}/stopwatch/stop issue issueStopWatch
515+
// ---
516+
// summary: Stop an issue's existing stopwatch.
517+
// consumes:
518+
// - application/json
519+
// produces:
520+
// - application/json
521+
// parameters:
522+
// - name: owner
523+
// in: path
524+
// description: owner of the repo
525+
// type: string
526+
// required: true
527+
// - name: repo
528+
// in: path
529+
// description: name of the repo
530+
// type: string
531+
// required: true
532+
// - name: index
533+
// in: path
534+
// description: index of the issue to stop the stopwatch on
535+
// type: integer
536+
// format: int64
537+
// required: true
538+
// responses:
539+
// "201":
540+
// "$ref": "#/responses/empty"
541+
// "403":
542+
// description: Not repo writer, user does not have rights to toggle stopwatch
543+
// "404":
544+
// description: Issue not found
545+
// "409":
546+
// description: Cannot stop a non existent stopwatch
547+
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
548+
if err != nil {
549+
if models.IsErrIssueNotExist(err) {
550+
ctx.Status(404)
551+
} else {
552+
ctx.Error(500, "GetIssueByIndex", err)
553+
}
554+
555+
return
556+
}
557+
558+
if !ctx.Repo.CanWrite(models.UnitTypeIssues) {
559+
ctx.Status(403)
560+
return
561+
}
562+
563+
if !ctx.Repo.CanUseTimetracker(issue, ctx.User) {
564+
ctx.Status(403)
565+
return
566+
}
567+
568+
if !models.StopwatchExists(ctx.User.ID, issue.ID) {
569+
ctx.Error(409, "StopwatchExists", "cannot stop a non existent stopwatch")
570+
return
571+
}
572+
573+
if err := models.CreateOrStopIssueStopwatch(ctx.User, issue); err != nil {
574+
ctx.Error(500, "CreateOrStopIssueStopwatch", err)
575+
return
576+
}
577+
578+
ctx.Status(201)
579+
}

templates/swagger/v1_json.tmpl

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2942,6 +2942,112 @@
29422942
}
29432943
}
29442944
},
2945+
"/repos/{owner}/{repo}/issues/{index}/stopwatch/start": {
2946+
"post": {
2947+
"consumes": [
2948+
"application/json"
2949+
],
2950+
"produces": [
2951+
"application/json"
2952+
],
2953+
"tags": [
2954+
"issue"
2955+
],
2956+
"summary": "Start stopwatch on an issue.",
2957+
"operationId": "issueStartStopWatch",
2958+
"parameters": [
2959+
{
2960+
"type": "string",
2961+
"description": "owner of the repo",
2962+
"name": "owner",
2963+
"in": "path",
2964+
"required": true
2965+
},
2966+
{
2967+
"type": "string",
2968+
"description": "name of the repo",
2969+
"name": "repo",
2970+
"in": "path",
2971+
"required": true
2972+
},
2973+
{
2974+
"type": "integer",
2975+
"format": "int64",
2976+
"description": "index of the issue to create the stopwatch on",
2977+
"name": "index",
2978+
"in": "path",
2979+
"required": true
2980+
}
2981+
],
2982+
"responses": {
2983+
"201": {
2984+
"$ref": "#/responses/empty"
2985+
},
2986+
"403": {
2987+
"description": "Not repo writer, user does not have rights to toggle stopwatch"
2988+
},
2989+
"404": {
2990+
"description": "Issue not found"
2991+
},
2992+
"409": {
2993+
"description": "Cannot start a stopwatch again if it already exists"
2994+
}
2995+
}
2996+
}
2997+
},
2998+
"/repos/{owner}/{repo}/issues/{index}/stopwatch/stop": {
2999+
"post": {
3000+
"consumes": [
3001+
"application/json"
3002+
],
3003+
"produces": [
3004+
"application/json"
3005+
],
3006+
"tags": [
3007+
"issue"
3008+
],
3009+
"summary": "Stop an issue's existing stopwatch.",
3010+
"operationId": "issueStopWatch",
3011+
"parameters": [
3012+
{
3013+
"type": "string",
3014+
"description": "owner of the repo",
3015+
"name": "owner",
3016+
"in": "path",
3017+
"required": true
3018+
},
3019+
{
3020+
"type": "string",
3021+
"description": "name of the repo",
3022+
"name": "repo",
3023+
"in": "path",
3024+
"required": true
3025+
},
3026+
{
3027+
"type": "integer",
3028+
"format": "int64",
3029+
"description": "index of the issue to stop the stopwatch on",
3030+
"name": "index",
3031+
"in": "path",
3032+
"required": true
3033+
}
3034+
],
3035+
"responses": {
3036+
"201": {
3037+
"$ref": "#/responses/empty"
3038+
},
3039+
"403": {
3040+
"description": "Not repo writer, user does not have rights to toggle stopwatch"
3041+
},
3042+
"404": {
3043+
"description": "Issue not found"
3044+
},
3045+
"409": {
3046+
"description": "Cannot stop a non existent stopwatch"
3047+
}
3048+
}
3049+
}
3050+
},
29453051
"/repos/{owner}/{repo}/keys": {
29463052
"get": {
29473053
"produces": [

0 commit comments

Comments
 (0)