repo_hook.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package v1
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "slices"
  6. "github.com/cockroachdb/errors"
  7. "gogs.io/gogs/internal/context"
  8. "gogs.io/gogs/internal/database"
  9. "gogs.io/gogs/internal/route/api/v1/types"
  10. )
  11. // https://github.com/gogs/go-gogs-client/wiki/Repositories#list-hooks
  12. func listHooks(c *context.APIContext) {
  13. hooks, err := database.GetWebhooksByRepoID(c.Repo.Repository.ID)
  14. if err != nil {
  15. c.Errorf(err, "get webhooks by repository ID")
  16. return
  17. }
  18. apiHooks := make([]*types.RepositoryHook, len(hooks))
  19. for i := range hooks {
  20. apiHooks[i] = toRepositoryHook(c.Repo.RepoLink, hooks[i])
  21. }
  22. c.JSONSuccess(&apiHooks)
  23. }
  24. // https://github.com/gogs/go-gogs-client/wiki/Repositories#create-a-hook
  25. type createHookRequest struct {
  26. Type string `json:"type" binding:"Required"`
  27. Config map[string]string `json:"config" binding:"Required"`
  28. Events []string `json:"events"`
  29. Active bool `json:"active"`
  30. }
  31. func createHook(c *context.APIContext, form createHookRequest) {
  32. if !database.IsValidHookTaskType(form.Type) {
  33. c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Invalid hook type."))
  34. return
  35. }
  36. for _, name := range []string{"url", "content_type"} {
  37. if _, ok := form.Config[name]; !ok {
  38. c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Missing config option: "+name))
  39. return
  40. }
  41. }
  42. if !database.IsValidHookContentType(form.Config["content_type"]) {
  43. c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Invalid content type."))
  44. return
  45. }
  46. if len(form.Events) == 0 {
  47. form.Events = []string{"push"}
  48. }
  49. w := &database.Webhook{
  50. RepoID: c.Repo.Repository.ID,
  51. URL: form.Config["url"],
  52. ContentType: database.ToHookContentType(form.Config["content_type"]),
  53. Secret: form.Config["secret"],
  54. HookEvent: &database.HookEvent{
  55. ChooseEvents: true,
  56. HookEvents: database.HookEvents{
  57. Create: slices.Contains(form.Events, string(database.HookEventTypeCreate)),
  58. Delete: slices.Contains(form.Events, string(database.HookEventTypeDelete)),
  59. Fork: slices.Contains(form.Events, string(database.HookEventTypeFork)),
  60. Push: slices.Contains(form.Events, string(database.HookEventTypePush)),
  61. Issues: slices.Contains(form.Events, string(database.HookEventTypeIssues)),
  62. IssueComment: slices.Contains(form.Events, string(database.HookEventTypeIssueComment)),
  63. PullRequest: slices.Contains(form.Events, string(database.HookEventTypePullRequest)),
  64. Release: slices.Contains(form.Events, string(database.HookEventTypeRelease)),
  65. },
  66. },
  67. IsActive: form.Active,
  68. HookTaskType: database.ToHookTaskType(form.Type),
  69. }
  70. if w.HookTaskType == database.SLACK {
  71. channel, ok := form.Config["channel"]
  72. if !ok {
  73. c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Missing config option: channel"))
  74. return
  75. }
  76. meta, err := json.Marshal(&database.SlackMeta{
  77. Channel: channel,
  78. Username: form.Config["username"],
  79. IconURL: form.Config["icon_url"],
  80. Color: form.Config["color"],
  81. })
  82. if err != nil {
  83. c.Errorf(err, "marshal JSON")
  84. return
  85. }
  86. w.Meta = string(meta)
  87. }
  88. if err := w.UpdateEvent(); err != nil {
  89. c.Errorf(err, "update event")
  90. return
  91. } else if err := database.CreateWebhook(w); err != nil {
  92. c.Errorf(err, "create webhook")
  93. return
  94. }
  95. c.JSON(http.StatusCreated, toRepositoryHook(c.Repo.RepoLink, w))
  96. }
  97. // https://github.com/gogs/go-gogs-client/wiki/Repositories#edit-a-hook
  98. type editHookRequest struct {
  99. Config map[string]string `json:"config"`
  100. Events []string `json:"events"`
  101. Active *bool `json:"active"`
  102. }
  103. func editHook(c *context.APIContext, form editHookRequest) {
  104. w, err := database.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id"))
  105. if err != nil {
  106. c.NotFoundOrError(err, "get webhook of repository by ID")
  107. return
  108. }
  109. if form.Config != nil {
  110. if url, ok := form.Config["url"]; ok {
  111. w.URL = url
  112. }
  113. if ct, ok := form.Config["content_type"]; ok {
  114. if !database.IsValidHookContentType(ct) {
  115. c.ErrorStatus(http.StatusUnprocessableEntity, errors.New("Invalid content type."))
  116. return
  117. }
  118. w.ContentType = database.ToHookContentType(ct)
  119. }
  120. if w.HookTaskType == database.SLACK {
  121. if channel, ok := form.Config["channel"]; ok {
  122. meta, err := json.Marshal(&database.SlackMeta{
  123. Channel: channel,
  124. Username: form.Config["username"],
  125. IconURL: form.Config["icon_url"],
  126. Color: form.Config["color"],
  127. })
  128. if err != nil {
  129. c.Errorf(err, "marshal JSON")
  130. return
  131. }
  132. w.Meta = string(meta)
  133. }
  134. }
  135. }
  136. // Update events
  137. if len(form.Events) == 0 {
  138. form.Events = []string{"push"}
  139. }
  140. w.PushOnly = false
  141. w.SendEverything = false
  142. w.ChooseEvents = true
  143. w.Create = slices.Contains(form.Events, string(database.HookEventTypeCreate))
  144. w.Delete = slices.Contains(form.Events, string(database.HookEventTypeDelete))
  145. w.Fork = slices.Contains(form.Events, string(database.HookEventTypeFork))
  146. w.Push = slices.Contains(form.Events, string(database.HookEventTypePush))
  147. w.Issues = slices.Contains(form.Events, string(database.HookEventTypeIssues))
  148. w.IssueComment = slices.Contains(form.Events, string(database.HookEventTypeIssueComment))
  149. w.PullRequest = slices.Contains(form.Events, string(database.HookEventTypePullRequest))
  150. w.Release = slices.Contains(form.Events, string(database.HookEventTypeRelease))
  151. if err = w.UpdateEvent(); err != nil {
  152. c.Errorf(err, "update event")
  153. return
  154. }
  155. if form.Active != nil {
  156. w.IsActive = *form.Active
  157. }
  158. if err := database.UpdateWebhook(w); err != nil {
  159. c.Errorf(err, "update webhook")
  160. return
  161. }
  162. c.JSONSuccess(toRepositoryHook(c.Repo.RepoLink, w))
  163. }
  164. func deleteHook(c *context.APIContext) {
  165. if err := database.DeleteWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id")); err != nil {
  166. c.Errorf(err, "delete webhook of repository by ID")
  167. return
  168. }
  169. c.NoContent()
  170. }