Skip to content

Commit 06daf4e

Browse files
committed
add issue subscriber API
1 parent c4f9d06 commit 06daf4e

File tree

5 files changed

+378
-0
lines changed

5 files changed

+378
-0
lines changed

.golangci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ issues:
7373
- path: routers/routes/routes.go
7474
linters:
7575
- dupl
76+
- path: routers/api/v1/repo/issue.go
77+
linters:
78+
- dupl
7679
- path: routers/repo/view.go
7780
linters:
7881
- dupl

modules/structs/issue.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,9 @@ type EditPriorityOption struct {
113113
// required:true
114114
Priority int `json:"priority"`
115115
}
116+
117+
// IssueWatchers list of subscribers of an issue
118+
type IssueWatchers struct {
119+
// required:true
120+
Subscribers []string `json:"subscribers"`
121+
}

routers/api/v1/api.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,11 @@ func RegisterRoutes(m *macaron.Macaron) {
688688
m.Post("/start", reqToken(), repo.StartIssueStopwatch)
689689
m.Post("/stop", reqToken(), repo.StopIssueStopwatch)
690690
})
691+
m.Group("/subscriptions", func() {
692+
m.Get("", reqToken(), bind(api.IssueWatchers{}), repo.GetIssueWatchers)
693+
m.Put("/:user", reqToken(), repo.AddIssueSubscription)
694+
m.Delete("/:user", reqToken(), repo.DelIssueSubscription)
695+
})
691696
})
692697
}, mustEnableIssuesOrPulls)
693698
m.Group("/labels", func() {

routers/api/v1/repo/issue.go

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,3 +598,208 @@ func StopIssueStopwatch(ctx *context.APIContext) {
598598

599599
ctx.Status(201)
600600
}
601+
602+
// AddIssueSubscription add user to subscription list
603+
func AddIssueSubscription(ctx *context.APIContext) {
604+
// swagger:operation PUT /repos/{owner}/{repo}/issues/{index}/subscriptions/{user} issue issueAddSubscription
605+
// ---
606+
// summary: Add user to subscription list
607+
// consumes:
608+
// - application/json
609+
// produces:
610+
// - application/json
611+
// parameters:
612+
// - name: owner
613+
// in: path
614+
// description: owner of the repo
615+
// type: string
616+
// required: true
617+
// - name: repo
618+
// in: path
619+
// description: name of the repo
620+
// type: string
621+
// required: true
622+
// - name: index
623+
// in: path
624+
// description: index of the issue
625+
// type: integer
626+
// format: int64
627+
// required: true
628+
// - name: user
629+
// in: path
630+
// description: user witch subscribe to issue
631+
// type: string
632+
// required: true
633+
// responses:
634+
// "201":
635+
// "$ref": "#/responses/empty"
636+
// "304":
637+
// description: User has no right to add subscribe of other user
638+
// "404":
639+
// description: Issue not found
640+
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
641+
if err != nil {
642+
if models.IsErrIssueNotExist(err) {
643+
ctx.NotFound()
644+
} else {
645+
ctx.Error(500, "GetIssueByIndex", err)
646+
}
647+
648+
return
649+
}
650+
651+
user, err := models.GetUserByName(ctx.Params(":user"))
652+
if err != nil {
653+
if models.IsErrUserNotExist(err) {
654+
ctx.NotFound()
655+
} else {
656+
ctx.Error(500, "GetUserByName", err)
657+
return
658+
}
659+
}
660+
661+
if user.ID != ctx.User.ID && !ctx.User.IsAdmin {
662+
ctx.Error(403, "User", nil)
663+
return
664+
}
665+
666+
if err := models.CreateOrUpdateIssueWatch(user.ID, issue.ID, true); err != nil {
667+
ctx.Error(500, "CreateOrUpdateIssueWatch", err)
668+
return
669+
}
670+
671+
ctx.Status(201)
672+
}
673+
674+
// DelIssueSubscription remove user to subscription list
675+
func DelIssueSubscription(ctx *context.APIContext) {
676+
// swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/subscriptions/{user} issue issueDeleteSubscription
677+
// ---
678+
// summary: Delete user from subscription list
679+
// consumes:
680+
// - application/json
681+
// produces:
682+
// - application/json
683+
// parameters:
684+
// - name: owner
685+
// in: path
686+
// description: owner of the repo
687+
// type: string
688+
// required: true
689+
// - name: repo
690+
// in: path
691+
// description: name of the repo
692+
// type: string
693+
// required: true
694+
// - name: index
695+
// in: path
696+
// description: index of the issue
697+
// type: integer
698+
// format: int64
699+
// required: true
700+
// - name: user
701+
// in: path
702+
// description: user witch unsubscribe to issue
703+
// type: string
704+
// required: true
705+
// responses:
706+
// "201":
707+
// "$ref": "#/responses/empty"
708+
// "304":
709+
// description: User has no right to remove subscribe of other user
710+
// "404":
711+
// description: Issue not found
712+
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
713+
if err != nil {
714+
if models.IsErrIssueNotExist(err) {
715+
ctx.NotFound()
716+
} else {
717+
ctx.Error(500, "GetIssueByIndex", err)
718+
}
719+
720+
return
721+
}
722+
723+
user, err := models.GetUserByName(ctx.Params(":user"))
724+
if err != nil {
725+
if models.IsErrUserNotExist(err) {
726+
ctx.NotFound()
727+
} else {
728+
ctx.Error(500, "GetUserByName", err)
729+
return
730+
}
731+
}
732+
733+
if user.ID != ctx.User.ID && !ctx.User.IsAdmin {
734+
ctx.Error(403, "User", nil)
735+
return
736+
}
737+
738+
if err := models.CreateOrUpdateIssueWatch(user.ID, issue.ID, false); err != nil {
739+
ctx.Error(500, "CreateOrUpdateIssueWatch", err)
740+
return
741+
}
742+
743+
ctx.Status(201)
744+
}
745+
746+
// GetIssueWatchers return subscribers of an issue
747+
func GetIssueWatchers(ctx *context.APIContext, form api.IssueWatchers) {
748+
// swagger:operation GET /repos/{owner}/{repo}/issues/{index}/subscriptions issue issueSubscriptions
749+
// ---
750+
// summary: Get users who subscribed on an issue.
751+
// consumes:
752+
// - application/json
753+
// produces:
754+
// - application/json
755+
// parameters:
756+
// - name: owner
757+
// in: path
758+
// description: owner of the repo
759+
// type: string
760+
// required: true
761+
// - name: repo
762+
// in: path
763+
// description: name of the repo
764+
// type: string
765+
// required: true
766+
// - name: index
767+
// in: path
768+
// description: index of the issue
769+
// type: integer
770+
// format: int64
771+
// required: true
772+
// responses:
773+
// "201":
774+
// "$ref": "#/responses/empty"
775+
// "404":
776+
// description: Issue not found
777+
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
778+
if err != nil {
779+
if models.IsErrIssueNotExist(err) {
780+
ctx.NotFound()
781+
} else {
782+
ctx.Error(500, "GetIssueByIndex", err)
783+
}
784+
785+
return
786+
}
787+
788+
var subscribers []string
789+
790+
iw, err := models.GetIssueWatchers(issue.ID)
791+
if err != nil {
792+
ctx.Error(500, "GetIssueWatchers", err)
793+
return
794+
}
795+
796+
for _, s := range iw {
797+
user, err := models.GetUserByID(s.UserID)
798+
if err != nil {
799+
continue
800+
}
801+
subscribers = append(subscribers, user.LoginName)
802+
}
803+
804+
ctx.JSON(200, api.IssueWatchers{Subscribers: subscribers})
805+
}

0 commit comments

Comments
 (0)