本站源代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

889 lines
23KB

  1. // Copyright 2015 The Gogs Authors. All rights reserved.
  2. // Copyright 2017 The Gitea Authors. All rights reserved.
  3. // Use of this source code is governed by a MIT-style
  4. // license that can be found in the LICENSE file.
  5. package repo
  6. import (
  7. "encoding/json"
  8. "errors"
  9. "fmt"
  10. "path"
  11. "strings"
  12. "code.gitea.io/gitea/models"
  13. "code.gitea.io/gitea/modules/auth"
  14. "code.gitea.io/gitea/modules/base"
  15. "code.gitea.io/gitea/modules/context"
  16. "code.gitea.io/gitea/modules/git"
  17. "code.gitea.io/gitea/modules/setting"
  18. api "code.gitea.io/gitea/modules/structs"
  19. "github.com/unknwon/com"
  20. )
  21. const (
  22. tplHooks base.TplName = "repo/settings/webhook/base"
  23. tplHookNew base.TplName = "repo/settings/webhook/new"
  24. tplOrgHookNew base.TplName = "org/settings/hook_new"
  25. tplAdminHookNew base.TplName = "admin/hook_new"
  26. )
  27. // Webhooks render web hooks list page
  28. func Webhooks(ctx *context.Context) {
  29. ctx.Data["Title"] = ctx.Tr("repo.settings.hooks")
  30. ctx.Data["PageIsSettingsHooks"] = true
  31. ctx.Data["BaseLink"] = ctx.Repo.RepoLink + "/settings/hooks"
  32. ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://docs.gitea.io/en-us/webhooks/")
  33. ws, err := models.GetWebhooksByRepoID(ctx.Repo.Repository.ID)
  34. if err != nil {
  35. ctx.ServerError("GetWebhooksByRepoID", err)
  36. return
  37. }
  38. ctx.Data["Webhooks"] = ws
  39. ctx.HTML(200, tplHooks)
  40. }
  41. type orgRepoCtx struct {
  42. OrgID int64
  43. RepoID int64
  44. IsAdmin bool
  45. Link string
  46. NewTemplate base.TplName
  47. }
  48. // getOrgRepoCtx determines whether this is a repo, organization, or admin context.
  49. func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
  50. if len(ctx.Repo.RepoLink) > 0 {
  51. return &orgRepoCtx{
  52. RepoID: ctx.Repo.Repository.ID,
  53. Link: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
  54. NewTemplate: tplHookNew,
  55. }, nil
  56. }
  57. if len(ctx.Org.OrgLink) > 0 {
  58. return &orgRepoCtx{
  59. OrgID: ctx.Org.Organization.ID,
  60. Link: path.Join(ctx.Org.OrgLink, "settings/hooks"),
  61. NewTemplate: tplOrgHookNew,
  62. }, nil
  63. }
  64. if ctx.User.IsAdmin {
  65. return &orgRepoCtx{
  66. IsAdmin: true,
  67. Link: path.Join(setting.AppSubURL, "/admin/hooks"),
  68. NewTemplate: tplAdminHookNew,
  69. }, nil
  70. }
  71. return nil, errors.New("Unable to set OrgRepo context")
  72. }
  73. func checkHookType(ctx *context.Context) string {
  74. hookType := strings.ToLower(ctx.Params(":type"))
  75. if !com.IsSliceContainsStr(setting.Webhook.Types, hookType) {
  76. ctx.NotFound("checkHookType", nil)
  77. return ""
  78. }
  79. return hookType
  80. }
  81. // WebhooksNew render creating webhook page
  82. func WebhooksNew(ctx *context.Context) {
  83. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  84. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  85. orCtx, err := getOrgRepoCtx(ctx)
  86. if err != nil {
  87. ctx.ServerError("getOrgRepoCtx", err)
  88. return
  89. }
  90. if orCtx.IsAdmin {
  91. ctx.Data["PageIsAdminHooks"] = true
  92. ctx.Data["PageIsAdminHooksNew"] = true
  93. } else {
  94. ctx.Data["PageIsSettingsHooks"] = true
  95. ctx.Data["PageIsSettingsHooksNew"] = true
  96. }
  97. hookType := checkHookType(ctx)
  98. ctx.Data["HookType"] = hookType
  99. if ctx.Written() {
  100. return
  101. }
  102. if hookType == "discord" {
  103. ctx.Data["DiscordHook"] = map[string]interface{}{
  104. "Username": "Gitea",
  105. "IconURL": setting.AppURL + "img/favicon.png",
  106. }
  107. }
  108. ctx.Data["BaseLink"] = orCtx.Link
  109. ctx.HTML(200, orCtx.NewTemplate)
  110. }
  111. // ParseHookEvent convert web form content to models.HookEvent
  112. func ParseHookEvent(form auth.WebhookForm) *models.HookEvent {
  113. return &models.HookEvent{
  114. PushOnly: form.PushOnly(),
  115. SendEverything: form.SendEverything(),
  116. ChooseEvents: form.ChooseEvents(),
  117. HookEvents: models.HookEvents{
  118. Create: form.Create,
  119. Delete: form.Delete,
  120. Fork: form.Fork,
  121. Issues: form.Issues,
  122. IssueComment: form.IssueComment,
  123. Release: form.Release,
  124. Push: form.Push,
  125. PullRequest: form.PullRequest,
  126. Repository: form.Repository,
  127. },
  128. BranchFilter: form.BranchFilter,
  129. }
  130. }
  131. // WebHooksNewPost response for creating webhook
  132. func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) {
  133. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  134. ctx.Data["PageIsSettingsHooks"] = true
  135. ctx.Data["PageIsSettingsHooksNew"] = true
  136. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  137. ctx.Data["HookType"] = "gitea"
  138. orCtx, err := getOrgRepoCtx(ctx)
  139. if err != nil {
  140. ctx.ServerError("getOrgRepoCtx", err)
  141. return
  142. }
  143. ctx.Data["BaseLink"] = orCtx.Link
  144. if ctx.HasError() {
  145. ctx.HTML(200, orCtx.NewTemplate)
  146. return
  147. }
  148. contentType := models.ContentTypeJSON
  149. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  150. contentType = models.ContentTypeForm
  151. }
  152. w := &models.Webhook{
  153. RepoID: orCtx.RepoID,
  154. URL: form.PayloadURL,
  155. HTTPMethod: form.HTTPMethod,
  156. ContentType: contentType,
  157. Secret: form.Secret,
  158. HookEvent: ParseHookEvent(form.WebhookForm),
  159. IsActive: form.Active,
  160. HookTaskType: models.GITEA,
  161. OrgID: orCtx.OrgID,
  162. }
  163. if err := w.UpdateEvent(); err != nil {
  164. ctx.ServerError("UpdateEvent", err)
  165. return
  166. } else if err := models.CreateWebhook(w); err != nil {
  167. ctx.ServerError("CreateWebhook", err)
  168. return
  169. }
  170. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  171. ctx.Redirect(orCtx.Link)
  172. }
  173. // GogsHooksNewPost response for creating webhook
  174. func GogsHooksNewPost(ctx *context.Context, form auth.NewGogshookForm) {
  175. newGogsWebhookPost(ctx, form, models.GOGS)
  176. }
  177. // newGogsWebhookPost response for creating gogs hook
  178. func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind models.HookTaskType) {
  179. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  180. ctx.Data["PageIsSettingsHooks"] = true
  181. ctx.Data["PageIsSettingsHooksNew"] = true
  182. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  183. ctx.Data["HookType"] = "gogs"
  184. orCtx, err := getOrgRepoCtx(ctx)
  185. if err != nil {
  186. ctx.ServerError("getOrgRepoCtx", err)
  187. return
  188. }
  189. ctx.Data["BaseLink"] = orCtx.Link
  190. if ctx.HasError() {
  191. ctx.HTML(200, orCtx.NewTemplate)
  192. return
  193. }
  194. contentType := models.ContentTypeJSON
  195. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  196. contentType = models.ContentTypeForm
  197. }
  198. w := &models.Webhook{
  199. RepoID: orCtx.RepoID,
  200. URL: form.PayloadURL,
  201. ContentType: contentType,
  202. Secret: form.Secret,
  203. HookEvent: ParseHookEvent(form.WebhookForm),
  204. IsActive: form.Active,
  205. HookTaskType: kind,
  206. OrgID: orCtx.OrgID,
  207. }
  208. if err := w.UpdateEvent(); err != nil {
  209. ctx.ServerError("UpdateEvent", err)
  210. return
  211. } else if err := models.CreateWebhook(w); err != nil {
  212. ctx.ServerError("CreateWebhook", err)
  213. return
  214. }
  215. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  216. ctx.Redirect(orCtx.Link)
  217. }
  218. // DiscordHooksNewPost response for creating discord hook
  219. func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
  220. ctx.Data["Title"] = ctx.Tr("repo.settings")
  221. ctx.Data["PageIsSettingsHooks"] = true
  222. ctx.Data["PageIsSettingsHooksNew"] = true
  223. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  224. orCtx, err := getOrgRepoCtx(ctx)
  225. if err != nil {
  226. ctx.ServerError("getOrgRepoCtx", err)
  227. return
  228. }
  229. if ctx.HasError() {
  230. ctx.HTML(200, orCtx.NewTemplate)
  231. return
  232. }
  233. meta, err := json.Marshal(&models.DiscordMeta{
  234. Username: form.Username,
  235. IconURL: form.IconURL,
  236. })
  237. if err != nil {
  238. ctx.ServerError("Marshal", err)
  239. return
  240. }
  241. w := &models.Webhook{
  242. RepoID: orCtx.RepoID,
  243. URL: form.PayloadURL,
  244. ContentType: models.ContentTypeJSON,
  245. HookEvent: ParseHookEvent(form.WebhookForm),
  246. IsActive: form.Active,
  247. HookTaskType: models.DISCORD,
  248. Meta: string(meta),
  249. OrgID: orCtx.OrgID,
  250. }
  251. if err := w.UpdateEvent(); err != nil {
  252. ctx.ServerError("UpdateEvent", err)
  253. return
  254. } else if err := models.CreateWebhook(w); err != nil {
  255. ctx.ServerError("CreateWebhook", err)
  256. return
  257. }
  258. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  259. ctx.Redirect(orCtx.Link)
  260. }
  261. // DingtalkHooksNewPost response for creating dingtalk hook
  262. func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) {
  263. ctx.Data["Title"] = ctx.Tr("repo.settings")
  264. ctx.Data["PageIsSettingsHooks"] = true
  265. ctx.Data["PageIsSettingsHooksNew"] = true
  266. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  267. orCtx, err := getOrgRepoCtx(ctx)
  268. if err != nil {
  269. ctx.ServerError("getOrgRepoCtx", err)
  270. return
  271. }
  272. if ctx.HasError() {
  273. ctx.HTML(200, orCtx.NewTemplate)
  274. return
  275. }
  276. w := &models.Webhook{
  277. RepoID: orCtx.RepoID,
  278. URL: form.PayloadURL,
  279. ContentType: models.ContentTypeJSON,
  280. HookEvent: ParseHookEvent(form.WebhookForm),
  281. IsActive: form.Active,
  282. HookTaskType: models.DINGTALK,
  283. Meta: "",
  284. OrgID: orCtx.OrgID,
  285. }
  286. if err := w.UpdateEvent(); err != nil {
  287. ctx.ServerError("UpdateEvent", err)
  288. return
  289. } else if err := models.CreateWebhook(w); err != nil {
  290. ctx.ServerError("CreateWebhook", err)
  291. return
  292. }
  293. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  294. ctx.Redirect(orCtx.Link)
  295. }
  296. // TelegramHooksNewPost response for creating telegram hook
  297. func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) {
  298. ctx.Data["Title"] = ctx.Tr("repo.settings")
  299. ctx.Data["PageIsSettingsHooks"] = true
  300. ctx.Data["PageIsSettingsHooksNew"] = true
  301. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  302. orCtx, err := getOrgRepoCtx(ctx)
  303. if err != nil {
  304. ctx.ServerError("getOrgRepoCtx", err)
  305. return
  306. }
  307. if ctx.HasError() {
  308. ctx.HTML(200, orCtx.NewTemplate)
  309. return
  310. }
  311. meta, err := json.Marshal(&models.TelegramMeta{
  312. BotToken: form.BotToken,
  313. ChatID: form.ChatID,
  314. })
  315. if err != nil {
  316. ctx.ServerError("Marshal", err)
  317. return
  318. }
  319. w := &models.Webhook{
  320. RepoID: orCtx.RepoID,
  321. URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID),
  322. ContentType: models.ContentTypeJSON,
  323. HookEvent: ParseHookEvent(form.WebhookForm),
  324. IsActive: form.Active,
  325. HookTaskType: models.TELEGRAM,
  326. Meta: string(meta),
  327. OrgID: orCtx.OrgID,
  328. }
  329. if err := w.UpdateEvent(); err != nil {
  330. ctx.ServerError("UpdateEvent", err)
  331. return
  332. } else if err := models.CreateWebhook(w); err != nil {
  333. ctx.ServerError("CreateWebhook", err)
  334. return
  335. }
  336. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  337. ctx.Redirect(orCtx.Link)
  338. }
  339. // MSTeamsHooksNewPost response for creating MS Teams hook
  340. func MSTeamsHooksNewPost(ctx *context.Context, form auth.NewMSTeamsHookForm) {
  341. ctx.Data["Title"] = ctx.Tr("repo.settings")
  342. ctx.Data["PageIsSettingsHooks"] = true
  343. ctx.Data["PageIsSettingsHooksNew"] = true
  344. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  345. orCtx, err := getOrgRepoCtx(ctx)
  346. if err != nil {
  347. ctx.ServerError("getOrgRepoCtx", err)
  348. return
  349. }
  350. if ctx.HasError() {
  351. ctx.HTML(200, orCtx.NewTemplate)
  352. return
  353. }
  354. w := &models.Webhook{
  355. RepoID: orCtx.RepoID,
  356. URL: form.PayloadURL,
  357. ContentType: models.ContentTypeJSON,
  358. HookEvent: ParseHookEvent(form.WebhookForm),
  359. IsActive: form.Active,
  360. HookTaskType: models.MSTEAMS,
  361. Meta: "",
  362. OrgID: orCtx.OrgID,
  363. }
  364. if err := w.UpdateEvent(); err != nil {
  365. ctx.ServerError("UpdateEvent", err)
  366. return
  367. } else if err := models.CreateWebhook(w); err != nil {
  368. ctx.ServerError("CreateWebhook", err)
  369. return
  370. }
  371. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  372. ctx.Redirect(orCtx.Link)
  373. }
  374. // SlackHooksNewPost response for creating slack hook
  375. func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
  376. ctx.Data["Title"] = ctx.Tr("repo.settings")
  377. ctx.Data["PageIsSettingsHooks"] = true
  378. ctx.Data["PageIsSettingsHooksNew"] = true
  379. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  380. orCtx, err := getOrgRepoCtx(ctx)
  381. if err != nil {
  382. ctx.ServerError("getOrgRepoCtx", err)
  383. return
  384. }
  385. if ctx.HasError() {
  386. ctx.HTML(200, orCtx.NewTemplate)
  387. return
  388. }
  389. if form.HasInvalidChannel() {
  390. ctx.Flash.Error(ctx.Tr("repo.settings.add_webhook.invalid_channel_name"))
  391. ctx.Redirect(orCtx.Link + "/settings/hooks/slack/new")
  392. return
  393. }
  394. meta, err := json.Marshal(&models.SlackMeta{
  395. Channel: strings.TrimSpace(form.Channel),
  396. Username: form.Username,
  397. IconURL: form.IconURL,
  398. Color: form.Color,
  399. })
  400. if err != nil {
  401. ctx.ServerError("Marshal", err)
  402. return
  403. }
  404. w := &models.Webhook{
  405. RepoID: orCtx.RepoID,
  406. URL: form.PayloadURL,
  407. ContentType: models.ContentTypeJSON,
  408. HookEvent: ParseHookEvent(form.WebhookForm),
  409. IsActive: form.Active,
  410. HookTaskType: models.SLACK,
  411. Meta: string(meta),
  412. OrgID: orCtx.OrgID,
  413. }
  414. if err := w.UpdateEvent(); err != nil {
  415. ctx.ServerError("UpdateEvent", err)
  416. return
  417. } else if err := models.CreateWebhook(w); err != nil {
  418. ctx.ServerError("CreateWebhook", err)
  419. return
  420. }
  421. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  422. ctx.Redirect(orCtx.Link)
  423. }
  424. func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
  425. ctx.Data["RequireHighlightJS"] = true
  426. orCtx, err := getOrgRepoCtx(ctx)
  427. if err != nil {
  428. ctx.ServerError("getOrgRepoCtx", err)
  429. return nil, nil
  430. }
  431. ctx.Data["BaseLink"] = orCtx.Link
  432. var w *models.Webhook
  433. if orCtx.RepoID > 0 {
  434. w, err = models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
  435. } else if orCtx.OrgID > 0 {
  436. w, err = models.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
  437. } else {
  438. w, err = models.GetDefaultWebhook(ctx.ParamsInt64(":id"))
  439. }
  440. if err != nil {
  441. if models.IsErrWebhookNotExist(err) {
  442. ctx.NotFound("GetWebhookByID", nil)
  443. } else {
  444. ctx.ServerError("GetWebhookByID", err)
  445. }
  446. return nil, nil
  447. }
  448. ctx.Data["HookType"] = w.HookTaskType.Name()
  449. switch w.HookTaskType {
  450. case models.SLACK:
  451. ctx.Data["SlackHook"] = w.GetSlackHook()
  452. case models.DISCORD:
  453. ctx.Data["DiscordHook"] = w.GetDiscordHook()
  454. case models.TELEGRAM:
  455. ctx.Data["TelegramHook"] = w.GetTelegramHook()
  456. }
  457. ctx.Data["History"], err = w.History(1)
  458. if err != nil {
  459. ctx.ServerError("History", err)
  460. }
  461. return orCtx, w
  462. }
  463. // WebHooksEdit render editing web hook page
  464. func WebHooksEdit(ctx *context.Context) {
  465. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  466. ctx.Data["PageIsSettingsHooks"] = true
  467. ctx.Data["PageIsSettingsHooksEdit"] = true
  468. orCtx, w := checkWebhook(ctx)
  469. if ctx.Written() {
  470. return
  471. }
  472. ctx.Data["Webhook"] = w
  473. ctx.HTML(200, orCtx.NewTemplate)
  474. }
  475. // WebHooksEditPost response for editing web hook
  476. func WebHooksEditPost(ctx *context.Context, form auth.NewWebhookForm) {
  477. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  478. ctx.Data["PageIsSettingsHooks"] = true
  479. ctx.Data["PageIsSettingsHooksEdit"] = true
  480. orCtx, w := checkWebhook(ctx)
  481. if ctx.Written() {
  482. return
  483. }
  484. ctx.Data["Webhook"] = w
  485. if ctx.HasError() {
  486. ctx.HTML(200, orCtx.NewTemplate)
  487. return
  488. }
  489. contentType := models.ContentTypeJSON
  490. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  491. contentType = models.ContentTypeForm
  492. }
  493. w.URL = form.PayloadURL
  494. w.ContentType = contentType
  495. w.Secret = form.Secret
  496. w.HookEvent = ParseHookEvent(form.WebhookForm)
  497. w.IsActive = form.Active
  498. w.HTTPMethod = form.HTTPMethod
  499. if err := w.UpdateEvent(); err != nil {
  500. ctx.ServerError("UpdateEvent", err)
  501. return
  502. } else if err := models.UpdateWebhook(w); err != nil {
  503. ctx.ServerError("WebHooksEditPost", err)
  504. return
  505. }
  506. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  507. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  508. }
  509. // GogsHooksEditPost response for editing gogs hook
  510. func GogsHooksEditPost(ctx *context.Context, form auth.NewGogshookForm) {
  511. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  512. ctx.Data["PageIsSettingsHooks"] = true
  513. ctx.Data["PageIsSettingsHooksEdit"] = true
  514. orCtx, w := checkWebhook(ctx)
  515. if ctx.Written() {
  516. return
  517. }
  518. ctx.Data["Webhook"] = w
  519. if ctx.HasError() {
  520. ctx.HTML(200, orCtx.NewTemplate)
  521. return
  522. }
  523. contentType := models.ContentTypeJSON
  524. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  525. contentType = models.ContentTypeForm
  526. }
  527. w.URL = form.PayloadURL
  528. w.ContentType = contentType
  529. w.Secret = form.Secret
  530. w.HookEvent = ParseHookEvent(form.WebhookForm)
  531. w.IsActive = form.Active
  532. if err := w.UpdateEvent(); err != nil {
  533. ctx.ServerError("UpdateEvent", err)
  534. return
  535. } else if err := models.UpdateWebhook(w); err != nil {
  536. ctx.ServerError("GogsHooksEditPost", err)
  537. return
  538. }
  539. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  540. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  541. }
  542. // SlackHooksEditPost response for editing slack hook
  543. func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
  544. ctx.Data["Title"] = ctx.Tr("repo.settings")
  545. ctx.Data["PageIsSettingsHooks"] = true
  546. ctx.Data["PageIsSettingsHooksEdit"] = true
  547. orCtx, w := checkWebhook(ctx)
  548. if ctx.Written() {
  549. return
  550. }
  551. ctx.Data["Webhook"] = w
  552. if ctx.HasError() {
  553. ctx.HTML(200, orCtx.NewTemplate)
  554. return
  555. }
  556. if form.HasInvalidChannel() {
  557. ctx.Flash.Error(ctx.Tr("repo.settings.add_webhook.invalid_channel_name"))
  558. ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
  559. return
  560. }
  561. meta, err := json.Marshal(&models.SlackMeta{
  562. Channel: strings.TrimSpace(form.Channel),
  563. Username: form.Username,
  564. IconURL: form.IconURL,
  565. Color: form.Color,
  566. })
  567. if err != nil {
  568. ctx.ServerError("Marshal", err)
  569. return
  570. }
  571. w.URL = form.PayloadURL
  572. w.Meta = string(meta)
  573. w.HookEvent = ParseHookEvent(form.WebhookForm)
  574. w.IsActive = form.Active
  575. if err := w.UpdateEvent(); err != nil {
  576. ctx.ServerError("UpdateEvent", err)
  577. return
  578. } else if err := models.UpdateWebhook(w); err != nil {
  579. ctx.ServerError("UpdateWebhook", err)
  580. return
  581. }
  582. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  583. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  584. }
  585. // DiscordHooksEditPost response for editing discord hook
  586. func DiscordHooksEditPost(ctx *context.Context, form auth.NewDiscordHookForm) {
  587. ctx.Data["Title"] = ctx.Tr("repo.settings")
  588. ctx.Data["PageIsSettingsHooks"] = true
  589. ctx.Data["PageIsSettingsHooksEdit"] = true
  590. orCtx, w := checkWebhook(ctx)
  591. if ctx.Written() {
  592. return
  593. }
  594. ctx.Data["Webhook"] = w
  595. if ctx.HasError() {
  596. ctx.HTML(200, orCtx.NewTemplate)
  597. return
  598. }
  599. meta, err := json.Marshal(&models.DiscordMeta{
  600. Username: form.Username,
  601. IconURL: form.IconURL,
  602. })
  603. if err != nil {
  604. ctx.ServerError("Marshal", err)
  605. return
  606. }
  607. w.URL = form.PayloadURL
  608. w.Meta = string(meta)
  609. w.HookEvent = ParseHookEvent(form.WebhookForm)
  610. w.IsActive = form.Active
  611. if err := w.UpdateEvent(); err != nil {
  612. ctx.ServerError("UpdateEvent", err)
  613. return
  614. } else if err := models.UpdateWebhook(w); err != nil {
  615. ctx.ServerError("UpdateWebhook", err)
  616. return
  617. }
  618. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  619. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  620. }
  621. // DingtalkHooksEditPost response for editing discord hook
  622. func DingtalkHooksEditPost(ctx *context.Context, form auth.NewDingtalkHookForm) {
  623. ctx.Data["Title"] = ctx.Tr("repo.settings")
  624. ctx.Data["PageIsSettingsHooks"] = true
  625. ctx.Data["PageIsSettingsHooksEdit"] = true
  626. orCtx, w := checkWebhook(ctx)
  627. if ctx.Written() {
  628. return
  629. }
  630. ctx.Data["Webhook"] = w
  631. if ctx.HasError() {
  632. ctx.HTML(200, orCtx.NewTemplate)
  633. return
  634. }
  635. w.URL = form.PayloadURL
  636. w.HookEvent = ParseHookEvent(form.WebhookForm)
  637. w.IsActive = form.Active
  638. if err := w.UpdateEvent(); err != nil {
  639. ctx.ServerError("UpdateEvent", err)
  640. return
  641. } else if err := models.UpdateWebhook(w); err != nil {
  642. ctx.ServerError("UpdateWebhook", err)
  643. return
  644. }
  645. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  646. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  647. }
  648. // TelegramHooksEditPost response for editing discord hook
  649. func TelegramHooksEditPost(ctx *context.Context, form auth.NewTelegramHookForm) {
  650. ctx.Data["Title"] = ctx.Tr("repo.settings")
  651. ctx.Data["PageIsSettingsHooks"] = true
  652. ctx.Data["PageIsSettingsHooksEdit"] = true
  653. orCtx, w := checkWebhook(ctx)
  654. if ctx.Written() {
  655. return
  656. }
  657. ctx.Data["Webhook"] = w
  658. if ctx.HasError() {
  659. ctx.HTML(200, orCtx.NewTemplate)
  660. return
  661. }
  662. meta, err := json.Marshal(&models.TelegramMeta{
  663. BotToken: form.BotToken,
  664. ChatID: form.ChatID,
  665. })
  666. if err != nil {
  667. ctx.ServerError("Marshal", err)
  668. return
  669. }
  670. w.Meta = string(meta)
  671. w.URL = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID)
  672. w.HookEvent = ParseHookEvent(form.WebhookForm)
  673. w.IsActive = form.Active
  674. if err := w.UpdateEvent(); err != nil {
  675. ctx.ServerError("UpdateEvent", err)
  676. return
  677. } else if err := models.UpdateWebhook(w); err != nil {
  678. ctx.ServerError("UpdateWebhook", err)
  679. return
  680. }
  681. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  682. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  683. }
  684. // MSTeamsHooksEditPost response for editing MS Teams hook
  685. func MSTeamsHooksEditPost(ctx *context.Context, form auth.NewMSTeamsHookForm) {
  686. ctx.Data["Title"] = ctx.Tr("repo.settings")
  687. ctx.Data["PageIsSettingsHooks"] = true
  688. ctx.Data["PageIsSettingsHooksEdit"] = true
  689. orCtx, w := checkWebhook(ctx)
  690. if ctx.Written() {
  691. return
  692. }
  693. ctx.Data["Webhook"] = w
  694. if ctx.HasError() {
  695. ctx.HTML(200, orCtx.NewTemplate)
  696. return
  697. }
  698. w.URL = form.PayloadURL
  699. w.HookEvent = ParseHookEvent(form.WebhookForm)
  700. w.IsActive = form.Active
  701. if err := w.UpdateEvent(); err != nil {
  702. ctx.ServerError("UpdateEvent", err)
  703. return
  704. } else if err := models.UpdateWebhook(w); err != nil {
  705. ctx.ServerError("UpdateWebhook", err)
  706. return
  707. }
  708. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  709. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  710. }
  711. // TestWebhook test if web hook is work fine
  712. func TestWebhook(ctx *context.Context) {
  713. hookID := ctx.ParamsInt64(":id")
  714. w, err := models.GetWebhookByRepoID(ctx.Repo.Repository.ID, hookID)
  715. if err != nil {
  716. ctx.Flash.Error("GetWebhookByID: " + err.Error())
  717. ctx.Status(500)
  718. return
  719. }
  720. // Grab latest commit or fake one if it's empty repository.
  721. commit := ctx.Repo.Commit
  722. if commit == nil {
  723. ghost := models.NewGhostUser()
  724. commit = &git.Commit{
  725. ID: git.MustIDFromString(git.EmptySHA),
  726. Author: ghost.NewGitSig(),
  727. Committer: ghost.NewGitSig(),
  728. CommitMessage: "This is a fake commit",
  729. }
  730. }
  731. apiUser := ctx.User.APIFormat()
  732. p := &api.PushPayload{
  733. Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch,
  734. Before: commit.ID.String(),
  735. After: commit.ID.String(),
  736. Commits: []*api.PayloadCommit{
  737. {
  738. ID: commit.ID.String(),
  739. Message: commit.Message(),
  740. URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
  741. Author: &api.PayloadUser{
  742. Name: commit.Author.Name,
  743. Email: commit.Author.Email,
  744. },
  745. Committer: &api.PayloadUser{
  746. Name: commit.Committer.Name,
  747. Email: commit.Committer.Email,
  748. },
  749. },
  750. },
  751. Repo: ctx.Repo.Repository.APIFormat(models.AccessModeNone),
  752. Pusher: apiUser,
  753. Sender: apiUser,
  754. }
  755. if err := models.PrepareWebhook(w, ctx.Repo.Repository, models.HookEventPush, p); err != nil {
  756. ctx.Flash.Error("PrepareWebhook: " + err.Error())
  757. ctx.Status(500)
  758. } else {
  759. go models.HookQueue.Add(ctx.Repo.Repository.ID)
  760. ctx.Flash.Info(ctx.Tr("repo.settings.webhook.test_delivery_success"))
  761. ctx.Status(200)
  762. }
  763. }
  764. // DeleteWebhook delete a webhook
  765. func DeleteWebhook(ctx *context.Context) {
  766. if err := models.DeleteWebhookByRepoID(ctx.Repo.Repository.ID, ctx.QueryInt64("id")); err != nil {
  767. ctx.Flash.Error("DeleteWebhookByRepoID: " + err.Error())
  768. } else {
  769. ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
  770. }
  771. ctx.JSON(200, map[string]interface{}{
  772. "redirect": ctx.Repo.RepoLink + "/settings/hooks",
  773. })
  774. }
上海开阖软件有限公司 沪ICP备12045867号-1