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.

webhook.go 33KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  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. "errors"
  8. "fmt"
  9. "net/http"
  10. "path"
  11. "strings"
  12. "code.gitea.io/gitea/models"
  13. "code.gitea.io/gitea/modules/base"
  14. "code.gitea.io/gitea/modules/context"
  15. "code.gitea.io/gitea/modules/convert"
  16. "code.gitea.io/gitea/modules/git"
  17. "code.gitea.io/gitea/modules/json"
  18. "code.gitea.io/gitea/modules/setting"
  19. api "code.gitea.io/gitea/modules/structs"
  20. "code.gitea.io/gitea/modules/util"
  21. "code.gitea.io/gitea/modules/web"
  22. "code.gitea.io/gitea/services/forms"
  23. "code.gitea.io/gitea/services/webhook"
  24. )
  25. const (
  26. tplHooks base.TplName = "repo/settings/webhook/base"
  27. tplHookNew base.TplName = "repo/settings/webhook/new"
  28. tplOrgHookNew base.TplName = "org/settings/hook_new"
  29. tplAdminHookNew base.TplName = "admin/hook_new"
  30. )
  31. // Webhooks render web hooks list page
  32. func Webhooks(ctx *context.Context) {
  33. ctx.Data["Title"] = ctx.Tr("repo.settings.hooks")
  34. ctx.Data["PageIsSettingsHooks"] = true
  35. ctx.Data["BaseLink"] = ctx.Repo.RepoLink + "/settings/hooks"
  36. ctx.Data["BaseLinkNew"] = ctx.Repo.RepoLink + "/settings/hooks"
  37. ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://docs.gitea.io/en-us/webhooks/")
  38. ws, err := models.ListWebhooksByOpts(&models.ListWebhookOptions{RepoID: ctx.Repo.Repository.ID})
  39. if err != nil {
  40. ctx.ServerError("GetWebhooksByRepoID", err)
  41. return
  42. }
  43. ctx.Data["Webhooks"] = ws
  44. ctx.HTML(http.StatusOK, tplHooks)
  45. }
  46. type orgRepoCtx struct {
  47. OrgID int64
  48. RepoID int64
  49. IsAdmin bool
  50. IsSystemWebhook bool
  51. Link string
  52. LinkNew string
  53. NewTemplate base.TplName
  54. }
  55. // getOrgRepoCtx determines whether this is a repo, organization, or admin (both default and system) context.
  56. func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
  57. if len(ctx.Repo.RepoLink) > 0 {
  58. return &orgRepoCtx{
  59. RepoID: ctx.Repo.Repository.ID,
  60. Link: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
  61. LinkNew: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
  62. NewTemplate: tplHookNew,
  63. }, nil
  64. }
  65. if len(ctx.Org.OrgLink) > 0 {
  66. return &orgRepoCtx{
  67. OrgID: ctx.Org.Organization.ID,
  68. Link: path.Join(ctx.Org.OrgLink, "settings/hooks"),
  69. LinkNew: path.Join(ctx.Org.OrgLink, "settings/hooks"),
  70. NewTemplate: tplOrgHookNew,
  71. }, nil
  72. }
  73. if ctx.User.IsAdmin {
  74. // Are we looking at default webhooks?
  75. if ctx.Params(":configType") == "default-hooks" {
  76. return &orgRepoCtx{
  77. IsAdmin: true,
  78. Link: path.Join(setting.AppSubURL, "/admin/hooks"),
  79. LinkNew: path.Join(setting.AppSubURL, "/admin/default-hooks"),
  80. NewTemplate: tplAdminHookNew,
  81. }, nil
  82. }
  83. // Must be system webhooks instead
  84. return &orgRepoCtx{
  85. IsAdmin: true,
  86. IsSystemWebhook: true,
  87. Link: path.Join(setting.AppSubURL, "/admin/hooks"),
  88. LinkNew: path.Join(setting.AppSubURL, "/admin/system-hooks"),
  89. NewTemplate: tplAdminHookNew,
  90. }, nil
  91. }
  92. return nil, errors.New("Unable to set OrgRepo context")
  93. }
  94. func checkHookType(ctx *context.Context) string {
  95. hookType := strings.ToLower(ctx.Params(":type"))
  96. if !util.IsStringInSlice(hookType, setting.Webhook.Types, true) {
  97. ctx.NotFound("checkHookType", nil)
  98. return ""
  99. }
  100. return hookType
  101. }
  102. // WebhooksNew render creating webhook page
  103. func WebhooksNew(ctx *context.Context) {
  104. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  105. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  106. orCtx, err := getOrgRepoCtx(ctx)
  107. if err != nil {
  108. ctx.ServerError("getOrgRepoCtx", err)
  109. return
  110. }
  111. if orCtx.IsAdmin && orCtx.IsSystemWebhook {
  112. ctx.Data["PageIsAdminSystemHooks"] = true
  113. ctx.Data["PageIsAdminSystemHooksNew"] = true
  114. } else if orCtx.IsAdmin {
  115. ctx.Data["PageIsAdminDefaultHooks"] = true
  116. ctx.Data["PageIsAdminDefaultHooksNew"] = true
  117. } else {
  118. ctx.Data["PageIsSettingsHooks"] = true
  119. ctx.Data["PageIsSettingsHooksNew"] = true
  120. }
  121. hookType := checkHookType(ctx)
  122. ctx.Data["HookType"] = hookType
  123. if ctx.Written() {
  124. return
  125. }
  126. if hookType == "discord" {
  127. ctx.Data["DiscordHook"] = map[string]interface{}{
  128. "Username": "Gitea",
  129. "IconURL": setting.AppURL + "img/favicon.png",
  130. }
  131. }
  132. ctx.Data["BaseLink"] = orCtx.LinkNew
  133. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  134. }
  135. // ParseHookEvent convert web form content to models.HookEvent
  136. func ParseHookEvent(form forms.WebhookForm) *models.HookEvent {
  137. return &models.HookEvent{
  138. PushOnly: form.PushOnly(),
  139. SendEverything: form.SendEverything(),
  140. ChooseEvents: form.ChooseEvents(),
  141. HookEvents: models.HookEvents{
  142. Create: form.Create,
  143. Delete: form.Delete,
  144. Fork: form.Fork,
  145. Issues: form.Issues,
  146. IssueAssign: form.IssueAssign,
  147. IssueLabel: form.IssueLabel,
  148. IssueMilestone: form.IssueMilestone,
  149. IssueComment: form.IssueComment,
  150. Release: form.Release,
  151. Push: form.Push,
  152. PullRequest: form.PullRequest,
  153. PullRequestAssign: form.PullRequestAssign,
  154. PullRequestLabel: form.PullRequestLabel,
  155. PullRequestMilestone: form.PullRequestMilestone,
  156. PullRequestComment: form.PullRequestComment,
  157. PullRequestReview: form.PullRequestReview,
  158. PullRequestSync: form.PullRequestSync,
  159. Repository: form.Repository,
  160. },
  161. BranchFilter: form.BranchFilter,
  162. }
  163. }
  164. // GiteaHooksNewPost response for creating Gitea webhook
  165. func GiteaHooksNewPost(ctx *context.Context) {
  166. form := web.GetForm(ctx).(*forms.NewWebhookForm)
  167. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  168. ctx.Data["PageIsSettingsHooks"] = true
  169. ctx.Data["PageIsSettingsHooksNew"] = true
  170. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  171. ctx.Data["HookType"] = models.GITEA
  172. orCtx, err := getOrgRepoCtx(ctx)
  173. if err != nil {
  174. ctx.ServerError("getOrgRepoCtx", err)
  175. return
  176. }
  177. ctx.Data["BaseLink"] = orCtx.LinkNew
  178. if ctx.HasError() {
  179. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  180. return
  181. }
  182. contentType := models.ContentTypeJSON
  183. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  184. contentType = models.ContentTypeForm
  185. }
  186. w := &models.Webhook{
  187. RepoID: orCtx.RepoID,
  188. URL: form.PayloadURL,
  189. HTTPMethod: form.HTTPMethod,
  190. ContentType: contentType,
  191. Secret: form.Secret,
  192. HookEvent: ParseHookEvent(form.WebhookForm),
  193. IsActive: form.Active,
  194. Type: models.GITEA,
  195. OrgID: orCtx.OrgID,
  196. IsSystemWebhook: orCtx.IsSystemWebhook,
  197. }
  198. if err := w.UpdateEvent(); err != nil {
  199. ctx.ServerError("UpdateEvent", err)
  200. return
  201. } else if err := models.CreateWebhook(w); err != nil {
  202. ctx.ServerError("CreateWebhook", err)
  203. return
  204. }
  205. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  206. ctx.Redirect(orCtx.Link)
  207. }
  208. // GogsHooksNewPost response for creating webhook
  209. func GogsHooksNewPost(ctx *context.Context) {
  210. form := web.GetForm(ctx).(*forms.NewGogshookForm)
  211. newGogsWebhookPost(ctx, *form, models.GOGS)
  212. }
  213. // newGogsWebhookPost response for creating gogs hook
  214. func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind models.HookType) {
  215. ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
  216. ctx.Data["PageIsSettingsHooks"] = true
  217. ctx.Data["PageIsSettingsHooksNew"] = true
  218. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  219. ctx.Data["HookType"] = models.GOGS
  220. orCtx, err := getOrgRepoCtx(ctx)
  221. if err != nil {
  222. ctx.ServerError("getOrgRepoCtx", err)
  223. return
  224. }
  225. ctx.Data["BaseLink"] = orCtx.LinkNew
  226. if ctx.HasError() {
  227. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  228. return
  229. }
  230. contentType := models.ContentTypeJSON
  231. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  232. contentType = models.ContentTypeForm
  233. }
  234. w := &models.Webhook{
  235. RepoID: orCtx.RepoID,
  236. URL: form.PayloadURL,
  237. ContentType: contentType,
  238. Secret: form.Secret,
  239. HookEvent: ParseHookEvent(form.WebhookForm),
  240. IsActive: form.Active,
  241. Type: kind,
  242. OrgID: orCtx.OrgID,
  243. IsSystemWebhook: orCtx.IsSystemWebhook,
  244. }
  245. if err := w.UpdateEvent(); err != nil {
  246. ctx.ServerError("UpdateEvent", err)
  247. return
  248. } else if err := models.CreateWebhook(w); err != nil {
  249. ctx.ServerError("CreateWebhook", err)
  250. return
  251. }
  252. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  253. ctx.Redirect(orCtx.Link)
  254. }
  255. // DiscordHooksNewPost response for creating discord hook
  256. func DiscordHooksNewPost(ctx *context.Context) {
  257. form := web.GetForm(ctx).(*forms.NewDiscordHookForm)
  258. ctx.Data["Title"] = ctx.Tr("repo.settings")
  259. ctx.Data["PageIsSettingsHooks"] = true
  260. ctx.Data["PageIsSettingsHooksNew"] = true
  261. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  262. ctx.Data["HookType"] = models.DISCORD
  263. orCtx, err := getOrgRepoCtx(ctx)
  264. if err != nil {
  265. ctx.ServerError("getOrgRepoCtx", err)
  266. return
  267. }
  268. if ctx.HasError() {
  269. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  270. return
  271. }
  272. meta, err := json.Marshal(&webhook.DiscordMeta{
  273. Username: form.Username,
  274. IconURL: form.IconURL,
  275. })
  276. if err != nil {
  277. ctx.ServerError("Marshal", err)
  278. return
  279. }
  280. w := &models.Webhook{
  281. RepoID: orCtx.RepoID,
  282. URL: form.PayloadURL,
  283. ContentType: models.ContentTypeJSON,
  284. HookEvent: ParseHookEvent(form.WebhookForm),
  285. IsActive: form.Active,
  286. Type: models.DISCORD,
  287. Meta: string(meta),
  288. OrgID: orCtx.OrgID,
  289. IsSystemWebhook: orCtx.IsSystemWebhook,
  290. }
  291. if err := w.UpdateEvent(); err != nil {
  292. ctx.ServerError("UpdateEvent", err)
  293. return
  294. } else if err := models.CreateWebhook(w); err != nil {
  295. ctx.ServerError("CreateWebhook", err)
  296. return
  297. }
  298. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  299. ctx.Redirect(orCtx.Link)
  300. }
  301. // DingtalkHooksNewPost response for creating dingtalk hook
  302. func DingtalkHooksNewPost(ctx *context.Context) {
  303. form := web.GetForm(ctx).(*forms.NewDingtalkHookForm)
  304. ctx.Data["Title"] = ctx.Tr("repo.settings")
  305. ctx.Data["PageIsSettingsHooks"] = true
  306. ctx.Data["PageIsSettingsHooksNew"] = true
  307. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  308. ctx.Data["HookType"] = models.DINGTALK
  309. orCtx, err := getOrgRepoCtx(ctx)
  310. if err != nil {
  311. ctx.ServerError("getOrgRepoCtx", err)
  312. return
  313. }
  314. if ctx.HasError() {
  315. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  316. return
  317. }
  318. w := &models.Webhook{
  319. RepoID: orCtx.RepoID,
  320. URL: form.PayloadURL,
  321. ContentType: models.ContentTypeJSON,
  322. HookEvent: ParseHookEvent(form.WebhookForm),
  323. IsActive: form.Active,
  324. Type: models.DINGTALK,
  325. Meta: "",
  326. OrgID: orCtx.OrgID,
  327. IsSystemWebhook: orCtx.IsSystemWebhook,
  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. // TelegramHooksNewPost response for creating telegram hook
  340. func TelegramHooksNewPost(ctx *context.Context) {
  341. form := web.GetForm(ctx).(*forms.NewTelegramHookForm)
  342. ctx.Data["Title"] = ctx.Tr("repo.settings")
  343. ctx.Data["PageIsSettingsHooks"] = true
  344. ctx.Data["PageIsSettingsHooksNew"] = true
  345. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  346. ctx.Data["HookType"] = models.TELEGRAM
  347. orCtx, err := getOrgRepoCtx(ctx)
  348. if err != nil {
  349. ctx.ServerError("getOrgRepoCtx", err)
  350. return
  351. }
  352. if ctx.HasError() {
  353. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  354. return
  355. }
  356. meta, err := json.Marshal(&webhook.TelegramMeta{
  357. BotToken: form.BotToken,
  358. ChatID: form.ChatID,
  359. })
  360. if err != nil {
  361. ctx.ServerError("Marshal", err)
  362. return
  363. }
  364. w := &models.Webhook{
  365. RepoID: orCtx.RepoID,
  366. URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID),
  367. ContentType: models.ContentTypeJSON,
  368. HookEvent: ParseHookEvent(form.WebhookForm),
  369. IsActive: form.Active,
  370. Type: models.TELEGRAM,
  371. Meta: string(meta),
  372. OrgID: orCtx.OrgID,
  373. IsSystemWebhook: orCtx.IsSystemWebhook,
  374. }
  375. if err := w.UpdateEvent(); err != nil {
  376. ctx.ServerError("UpdateEvent", err)
  377. return
  378. } else if err := models.CreateWebhook(w); err != nil {
  379. ctx.ServerError("CreateWebhook", err)
  380. return
  381. }
  382. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  383. ctx.Redirect(orCtx.Link)
  384. }
  385. // MatrixHooksNewPost response for creating a Matrix hook
  386. func MatrixHooksNewPost(ctx *context.Context) {
  387. form := web.GetForm(ctx).(*forms.NewMatrixHookForm)
  388. ctx.Data["Title"] = ctx.Tr("repo.settings")
  389. ctx.Data["PageIsSettingsHooks"] = true
  390. ctx.Data["PageIsSettingsHooksNew"] = true
  391. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  392. ctx.Data["HookType"] = models.MATRIX
  393. orCtx, err := getOrgRepoCtx(ctx)
  394. if err != nil {
  395. ctx.ServerError("getOrgRepoCtx", err)
  396. return
  397. }
  398. if ctx.HasError() {
  399. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  400. return
  401. }
  402. meta, err := json.Marshal(&webhook.MatrixMeta{
  403. HomeserverURL: form.HomeserverURL,
  404. Room: form.RoomID,
  405. AccessToken: form.AccessToken,
  406. MessageType: form.MessageType,
  407. })
  408. if err != nil {
  409. ctx.ServerError("Marshal", err)
  410. return
  411. }
  412. w := &models.Webhook{
  413. RepoID: orCtx.RepoID,
  414. URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, form.RoomID),
  415. ContentType: models.ContentTypeJSON,
  416. HTTPMethod: "PUT",
  417. HookEvent: ParseHookEvent(form.WebhookForm),
  418. IsActive: form.Active,
  419. Type: models.MATRIX,
  420. Meta: string(meta),
  421. OrgID: orCtx.OrgID,
  422. IsSystemWebhook: orCtx.IsSystemWebhook,
  423. }
  424. if err := w.UpdateEvent(); err != nil {
  425. ctx.ServerError("UpdateEvent", err)
  426. return
  427. } else if err := models.CreateWebhook(w); err != nil {
  428. ctx.ServerError("CreateWebhook", err)
  429. return
  430. }
  431. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  432. ctx.Redirect(orCtx.Link)
  433. }
  434. // MSTeamsHooksNewPost response for creating MS Teams hook
  435. func MSTeamsHooksNewPost(ctx *context.Context) {
  436. form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm)
  437. ctx.Data["Title"] = ctx.Tr("repo.settings")
  438. ctx.Data["PageIsSettingsHooks"] = true
  439. ctx.Data["PageIsSettingsHooksNew"] = true
  440. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  441. ctx.Data["HookType"] = models.MSTEAMS
  442. orCtx, err := getOrgRepoCtx(ctx)
  443. if err != nil {
  444. ctx.ServerError("getOrgRepoCtx", err)
  445. return
  446. }
  447. if ctx.HasError() {
  448. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  449. return
  450. }
  451. w := &models.Webhook{
  452. RepoID: orCtx.RepoID,
  453. URL: form.PayloadURL,
  454. ContentType: models.ContentTypeJSON,
  455. HookEvent: ParseHookEvent(form.WebhookForm),
  456. IsActive: form.Active,
  457. Type: models.MSTEAMS,
  458. Meta: "",
  459. OrgID: orCtx.OrgID,
  460. IsSystemWebhook: orCtx.IsSystemWebhook,
  461. }
  462. if err := w.UpdateEvent(); err != nil {
  463. ctx.ServerError("UpdateEvent", err)
  464. return
  465. } else if err := models.CreateWebhook(w); err != nil {
  466. ctx.ServerError("CreateWebhook", err)
  467. return
  468. }
  469. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  470. ctx.Redirect(orCtx.Link)
  471. }
  472. // SlackHooksNewPost response for creating slack hook
  473. func SlackHooksNewPost(ctx *context.Context) {
  474. form := web.GetForm(ctx).(*forms.NewSlackHookForm)
  475. ctx.Data["Title"] = ctx.Tr("repo.settings")
  476. ctx.Data["PageIsSettingsHooks"] = true
  477. ctx.Data["PageIsSettingsHooksNew"] = true
  478. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  479. ctx.Data["HookType"] = models.SLACK
  480. orCtx, err := getOrgRepoCtx(ctx)
  481. if err != nil {
  482. ctx.ServerError("getOrgRepoCtx", err)
  483. return
  484. }
  485. if ctx.HasError() {
  486. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  487. return
  488. }
  489. if form.HasInvalidChannel() {
  490. ctx.Flash.Error(ctx.Tr("repo.settings.add_webhook.invalid_channel_name"))
  491. ctx.Redirect(orCtx.LinkNew + "/slack/new")
  492. return
  493. }
  494. meta, err := json.Marshal(&webhook.SlackMeta{
  495. Channel: strings.TrimSpace(form.Channel),
  496. Username: form.Username,
  497. IconURL: form.IconURL,
  498. Color: form.Color,
  499. })
  500. if err != nil {
  501. ctx.ServerError("Marshal", err)
  502. return
  503. }
  504. w := &models.Webhook{
  505. RepoID: orCtx.RepoID,
  506. URL: form.PayloadURL,
  507. ContentType: models.ContentTypeJSON,
  508. HookEvent: ParseHookEvent(form.WebhookForm),
  509. IsActive: form.Active,
  510. Type: models.SLACK,
  511. Meta: string(meta),
  512. OrgID: orCtx.OrgID,
  513. IsSystemWebhook: orCtx.IsSystemWebhook,
  514. }
  515. if err := w.UpdateEvent(); err != nil {
  516. ctx.ServerError("UpdateEvent", err)
  517. return
  518. } else if err := models.CreateWebhook(w); err != nil {
  519. ctx.ServerError("CreateWebhook", err)
  520. return
  521. }
  522. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  523. ctx.Redirect(orCtx.Link)
  524. }
  525. // FeishuHooksNewPost response for creating feishu hook
  526. func FeishuHooksNewPost(ctx *context.Context) {
  527. form := web.GetForm(ctx).(*forms.NewFeishuHookForm)
  528. ctx.Data["Title"] = ctx.Tr("repo.settings")
  529. ctx.Data["PageIsSettingsHooks"] = true
  530. ctx.Data["PageIsSettingsHooksNew"] = true
  531. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  532. ctx.Data["HookType"] = models.FEISHU
  533. orCtx, err := getOrgRepoCtx(ctx)
  534. if err != nil {
  535. ctx.ServerError("getOrgRepoCtx", err)
  536. return
  537. }
  538. if ctx.HasError() {
  539. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  540. return
  541. }
  542. w := &models.Webhook{
  543. RepoID: orCtx.RepoID,
  544. URL: form.PayloadURL,
  545. ContentType: models.ContentTypeJSON,
  546. HookEvent: ParseHookEvent(form.WebhookForm),
  547. IsActive: form.Active,
  548. Type: models.FEISHU,
  549. Meta: "",
  550. OrgID: orCtx.OrgID,
  551. IsSystemWebhook: orCtx.IsSystemWebhook,
  552. }
  553. if err := w.UpdateEvent(); err != nil {
  554. ctx.ServerError("UpdateEvent", err)
  555. return
  556. } else if err := models.CreateWebhook(w); err != nil {
  557. ctx.ServerError("CreateWebhook", err)
  558. return
  559. }
  560. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  561. ctx.Redirect(orCtx.Link)
  562. }
  563. // WechatworkHooksNewPost response for creating wechatwork hook
  564. func WechatworkHooksNewPost(ctx *context.Context) {
  565. form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm)
  566. ctx.Data["Title"] = ctx.Tr("repo.settings")
  567. ctx.Data["PageIsSettingsHooks"] = true
  568. ctx.Data["PageIsSettingsHooksNew"] = true
  569. ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
  570. ctx.Data["HookType"] = models.WECHATWORK
  571. orCtx, err := getOrgRepoCtx(ctx)
  572. if err != nil {
  573. ctx.ServerError("getOrgRepoCtx", err)
  574. return
  575. }
  576. if ctx.HasError() {
  577. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  578. return
  579. }
  580. w := &models.Webhook{
  581. RepoID: orCtx.RepoID,
  582. URL: form.PayloadURL,
  583. ContentType: models.ContentTypeJSON,
  584. HookEvent: ParseHookEvent(form.WebhookForm),
  585. IsActive: form.Active,
  586. Type: models.WECHATWORK,
  587. Meta: "",
  588. OrgID: orCtx.OrgID,
  589. IsSystemWebhook: orCtx.IsSystemWebhook,
  590. }
  591. if err := w.UpdateEvent(); err != nil {
  592. ctx.ServerError("UpdateEvent", err)
  593. return
  594. } else if err := models.CreateWebhook(w); err != nil {
  595. ctx.ServerError("CreateWebhook", err)
  596. return
  597. }
  598. ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
  599. ctx.Redirect(orCtx.Link)
  600. }
  601. func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
  602. ctx.Data["RequireHighlightJS"] = true
  603. orCtx, err := getOrgRepoCtx(ctx)
  604. if err != nil {
  605. ctx.ServerError("getOrgRepoCtx", err)
  606. return nil, nil
  607. }
  608. ctx.Data["BaseLink"] = orCtx.Link
  609. var w *models.Webhook
  610. if orCtx.RepoID > 0 {
  611. w, err = models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
  612. } else if orCtx.OrgID > 0 {
  613. w, err = models.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
  614. } else if orCtx.IsAdmin {
  615. w, err = models.GetSystemOrDefaultWebhook(ctx.ParamsInt64(":id"))
  616. }
  617. if err != nil || w == nil {
  618. if models.IsErrWebhookNotExist(err) {
  619. ctx.NotFound("GetWebhookByID", nil)
  620. } else {
  621. ctx.ServerError("GetWebhookByID", err)
  622. }
  623. return nil, nil
  624. }
  625. ctx.Data["HookType"] = w.Type
  626. switch w.Type {
  627. case models.SLACK:
  628. ctx.Data["SlackHook"] = webhook.GetSlackHook(w)
  629. case models.DISCORD:
  630. ctx.Data["DiscordHook"] = webhook.GetDiscordHook(w)
  631. case models.TELEGRAM:
  632. ctx.Data["TelegramHook"] = webhook.GetTelegramHook(w)
  633. case models.MATRIX:
  634. ctx.Data["MatrixHook"] = webhook.GetMatrixHook(w)
  635. }
  636. ctx.Data["History"], err = w.History(1)
  637. if err != nil {
  638. ctx.ServerError("History", err)
  639. }
  640. return orCtx, w
  641. }
  642. // WebHooksEdit render editing web hook page
  643. func WebHooksEdit(ctx *context.Context) {
  644. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  645. ctx.Data["PageIsSettingsHooks"] = true
  646. ctx.Data["PageIsSettingsHooksEdit"] = true
  647. orCtx, w := checkWebhook(ctx)
  648. if ctx.Written() {
  649. return
  650. }
  651. ctx.Data["Webhook"] = w
  652. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  653. }
  654. // WebHooksEditPost response for editing web hook
  655. func WebHooksEditPost(ctx *context.Context) {
  656. form := web.GetForm(ctx).(*forms.NewWebhookForm)
  657. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  658. ctx.Data["PageIsSettingsHooks"] = true
  659. ctx.Data["PageIsSettingsHooksEdit"] = true
  660. orCtx, w := checkWebhook(ctx)
  661. if ctx.Written() {
  662. return
  663. }
  664. ctx.Data["Webhook"] = w
  665. if ctx.HasError() {
  666. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  667. return
  668. }
  669. contentType := models.ContentTypeJSON
  670. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  671. contentType = models.ContentTypeForm
  672. }
  673. w.URL = form.PayloadURL
  674. w.ContentType = contentType
  675. w.Secret = form.Secret
  676. w.HookEvent = ParseHookEvent(form.WebhookForm)
  677. w.IsActive = form.Active
  678. w.HTTPMethod = form.HTTPMethod
  679. if err := w.UpdateEvent(); err != nil {
  680. ctx.ServerError("UpdateEvent", err)
  681. return
  682. } else if err := models.UpdateWebhook(w); err != nil {
  683. ctx.ServerError("WebHooksEditPost", err)
  684. return
  685. }
  686. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  687. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  688. }
  689. // GogsHooksEditPost response for editing gogs hook
  690. func GogsHooksEditPost(ctx *context.Context) {
  691. form := web.GetForm(ctx).(*forms.NewGogshookForm)
  692. ctx.Data["Title"] = ctx.Tr("repo.settings.update_webhook")
  693. ctx.Data["PageIsSettingsHooks"] = true
  694. ctx.Data["PageIsSettingsHooksEdit"] = true
  695. orCtx, w := checkWebhook(ctx)
  696. if ctx.Written() {
  697. return
  698. }
  699. ctx.Data["Webhook"] = w
  700. if ctx.HasError() {
  701. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  702. return
  703. }
  704. contentType := models.ContentTypeJSON
  705. if models.HookContentType(form.ContentType) == models.ContentTypeForm {
  706. contentType = models.ContentTypeForm
  707. }
  708. w.URL = form.PayloadURL
  709. w.ContentType = contentType
  710. w.Secret = form.Secret
  711. w.HookEvent = ParseHookEvent(form.WebhookForm)
  712. w.IsActive = form.Active
  713. if err := w.UpdateEvent(); err != nil {
  714. ctx.ServerError("UpdateEvent", err)
  715. return
  716. } else if err := models.UpdateWebhook(w); err != nil {
  717. ctx.ServerError("GogsHooksEditPost", err)
  718. return
  719. }
  720. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  721. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  722. }
  723. // SlackHooksEditPost response for editing slack hook
  724. func SlackHooksEditPost(ctx *context.Context) {
  725. form := web.GetForm(ctx).(*forms.NewSlackHookForm)
  726. ctx.Data["Title"] = ctx.Tr("repo.settings")
  727. ctx.Data["PageIsSettingsHooks"] = true
  728. ctx.Data["PageIsSettingsHooksEdit"] = true
  729. orCtx, w := checkWebhook(ctx)
  730. if ctx.Written() {
  731. return
  732. }
  733. ctx.Data["Webhook"] = w
  734. if ctx.HasError() {
  735. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  736. return
  737. }
  738. if form.HasInvalidChannel() {
  739. ctx.Flash.Error(ctx.Tr("repo.settings.add_webhook.invalid_channel_name"))
  740. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  741. return
  742. }
  743. meta, err := json.Marshal(&webhook.SlackMeta{
  744. Channel: strings.TrimSpace(form.Channel),
  745. Username: form.Username,
  746. IconURL: form.IconURL,
  747. Color: form.Color,
  748. })
  749. if err != nil {
  750. ctx.ServerError("Marshal", err)
  751. return
  752. }
  753. w.URL = form.PayloadURL
  754. w.Meta = string(meta)
  755. w.HookEvent = ParseHookEvent(form.WebhookForm)
  756. w.IsActive = form.Active
  757. if err := w.UpdateEvent(); err != nil {
  758. ctx.ServerError("UpdateEvent", err)
  759. return
  760. } else if err := models.UpdateWebhook(w); err != nil {
  761. ctx.ServerError("UpdateWebhook", err)
  762. return
  763. }
  764. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  765. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  766. }
  767. // DiscordHooksEditPost response for editing discord hook
  768. func DiscordHooksEditPost(ctx *context.Context) {
  769. form := web.GetForm(ctx).(*forms.NewDiscordHookForm)
  770. ctx.Data["Title"] = ctx.Tr("repo.settings")
  771. ctx.Data["PageIsSettingsHooks"] = true
  772. ctx.Data["PageIsSettingsHooksEdit"] = true
  773. orCtx, w := checkWebhook(ctx)
  774. if ctx.Written() {
  775. return
  776. }
  777. ctx.Data["Webhook"] = w
  778. if ctx.HasError() {
  779. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  780. return
  781. }
  782. meta, err := json.Marshal(&webhook.DiscordMeta{
  783. Username: form.Username,
  784. IconURL: form.IconURL,
  785. })
  786. if err != nil {
  787. ctx.ServerError("Marshal", err)
  788. return
  789. }
  790. w.URL = form.PayloadURL
  791. w.Meta = string(meta)
  792. w.HookEvent = ParseHookEvent(form.WebhookForm)
  793. w.IsActive = form.Active
  794. if err := w.UpdateEvent(); err != nil {
  795. ctx.ServerError("UpdateEvent", err)
  796. return
  797. } else if err := models.UpdateWebhook(w); err != nil {
  798. ctx.ServerError("UpdateWebhook", err)
  799. return
  800. }
  801. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  802. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  803. }
  804. // DingtalkHooksEditPost response for editing discord hook
  805. func DingtalkHooksEditPost(ctx *context.Context) {
  806. form := web.GetForm(ctx).(*forms.NewDingtalkHookForm)
  807. ctx.Data["Title"] = ctx.Tr("repo.settings")
  808. ctx.Data["PageIsSettingsHooks"] = true
  809. ctx.Data["PageIsSettingsHooksEdit"] = true
  810. orCtx, w := checkWebhook(ctx)
  811. if ctx.Written() {
  812. return
  813. }
  814. ctx.Data["Webhook"] = w
  815. if ctx.HasError() {
  816. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  817. return
  818. }
  819. w.URL = form.PayloadURL
  820. w.HookEvent = ParseHookEvent(form.WebhookForm)
  821. w.IsActive = form.Active
  822. if err := w.UpdateEvent(); err != nil {
  823. ctx.ServerError("UpdateEvent", err)
  824. return
  825. } else if err := models.UpdateWebhook(w); err != nil {
  826. ctx.ServerError("UpdateWebhook", err)
  827. return
  828. }
  829. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  830. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  831. }
  832. // TelegramHooksEditPost response for editing discord hook
  833. func TelegramHooksEditPost(ctx *context.Context) {
  834. form := web.GetForm(ctx).(*forms.NewTelegramHookForm)
  835. ctx.Data["Title"] = ctx.Tr("repo.settings")
  836. ctx.Data["PageIsSettingsHooks"] = true
  837. ctx.Data["PageIsSettingsHooksEdit"] = true
  838. orCtx, w := checkWebhook(ctx)
  839. if ctx.Written() {
  840. return
  841. }
  842. ctx.Data["Webhook"] = w
  843. if ctx.HasError() {
  844. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  845. return
  846. }
  847. meta, err := json.Marshal(&webhook.TelegramMeta{
  848. BotToken: form.BotToken,
  849. ChatID: form.ChatID,
  850. })
  851. if err != nil {
  852. ctx.ServerError("Marshal", err)
  853. return
  854. }
  855. w.Meta = string(meta)
  856. w.URL = fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID)
  857. w.HookEvent = ParseHookEvent(form.WebhookForm)
  858. w.IsActive = form.Active
  859. if err := w.UpdateEvent(); err != nil {
  860. ctx.ServerError("UpdateEvent", err)
  861. return
  862. } else if err := models.UpdateWebhook(w); err != nil {
  863. ctx.ServerError("UpdateWebhook", err)
  864. return
  865. }
  866. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  867. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  868. }
  869. // MatrixHooksEditPost response for editing a Matrix hook
  870. func MatrixHooksEditPost(ctx *context.Context) {
  871. form := web.GetForm(ctx).(*forms.NewMatrixHookForm)
  872. ctx.Data["Title"] = ctx.Tr("repo.settings")
  873. ctx.Data["PageIsSettingsHooks"] = true
  874. ctx.Data["PageIsSettingsHooksEdit"] = true
  875. orCtx, w := checkWebhook(ctx)
  876. if ctx.Written() {
  877. return
  878. }
  879. ctx.Data["Webhook"] = w
  880. if ctx.HasError() {
  881. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  882. return
  883. }
  884. meta, err := json.Marshal(&webhook.MatrixMeta{
  885. HomeserverURL: form.HomeserverURL,
  886. Room: form.RoomID,
  887. AccessToken: form.AccessToken,
  888. MessageType: form.MessageType,
  889. })
  890. if err != nil {
  891. ctx.ServerError("Marshal", err)
  892. return
  893. }
  894. w.Meta = string(meta)
  895. w.URL = fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, form.RoomID)
  896. w.HookEvent = ParseHookEvent(form.WebhookForm)
  897. w.IsActive = form.Active
  898. if err := w.UpdateEvent(); err != nil {
  899. ctx.ServerError("UpdateEvent", err)
  900. return
  901. } else if err := models.UpdateWebhook(w); err != nil {
  902. ctx.ServerError("UpdateWebhook", err)
  903. return
  904. }
  905. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  906. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  907. }
  908. // MSTeamsHooksEditPost response for editing MS Teams hook
  909. func MSTeamsHooksEditPost(ctx *context.Context) {
  910. form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm)
  911. ctx.Data["Title"] = ctx.Tr("repo.settings")
  912. ctx.Data["PageIsSettingsHooks"] = true
  913. ctx.Data["PageIsSettingsHooksEdit"] = true
  914. orCtx, w := checkWebhook(ctx)
  915. if ctx.Written() {
  916. return
  917. }
  918. ctx.Data["Webhook"] = w
  919. if ctx.HasError() {
  920. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  921. return
  922. }
  923. w.URL = form.PayloadURL
  924. w.HookEvent = ParseHookEvent(form.WebhookForm)
  925. w.IsActive = form.Active
  926. if err := w.UpdateEvent(); err != nil {
  927. ctx.ServerError("UpdateEvent", err)
  928. return
  929. } else if err := models.UpdateWebhook(w); err != nil {
  930. ctx.ServerError("UpdateWebhook", err)
  931. return
  932. }
  933. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  934. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  935. }
  936. // FeishuHooksEditPost response for editing feishu hook
  937. func FeishuHooksEditPost(ctx *context.Context) {
  938. form := web.GetForm(ctx).(*forms.NewFeishuHookForm)
  939. ctx.Data["Title"] = ctx.Tr("repo.settings")
  940. ctx.Data["PageIsSettingsHooks"] = true
  941. ctx.Data["PageIsSettingsHooksEdit"] = true
  942. orCtx, w := checkWebhook(ctx)
  943. if ctx.Written() {
  944. return
  945. }
  946. ctx.Data["Webhook"] = w
  947. if ctx.HasError() {
  948. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  949. return
  950. }
  951. w.URL = form.PayloadURL
  952. w.HookEvent = ParseHookEvent(form.WebhookForm)
  953. w.IsActive = form.Active
  954. if err := w.UpdateEvent(); err != nil {
  955. ctx.ServerError("UpdateEvent", err)
  956. return
  957. } else if err := models.UpdateWebhook(w); err != nil {
  958. ctx.ServerError("UpdateWebhook", err)
  959. return
  960. }
  961. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  962. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  963. }
  964. // WechatworkHooksEditPost response for editing wechatwork hook
  965. func WechatworkHooksEditPost(ctx *context.Context) {
  966. form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm)
  967. ctx.Data["Title"] = ctx.Tr("repo.settings")
  968. ctx.Data["PageIsSettingsHooks"] = true
  969. ctx.Data["PageIsSettingsHooksEdit"] = true
  970. orCtx, w := checkWebhook(ctx)
  971. if ctx.Written() {
  972. return
  973. }
  974. ctx.Data["Webhook"] = w
  975. if ctx.HasError() {
  976. ctx.HTML(http.StatusOK, orCtx.NewTemplate)
  977. return
  978. }
  979. w.URL = form.PayloadURL
  980. w.HookEvent = ParseHookEvent(form.WebhookForm)
  981. w.IsActive = form.Active
  982. if err := w.UpdateEvent(); err != nil {
  983. ctx.ServerError("UpdateEvent", err)
  984. return
  985. } else if err := models.UpdateWebhook(w); err != nil {
  986. ctx.ServerError("UpdateWebhook", err)
  987. return
  988. }
  989. ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
  990. ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
  991. }
  992. // TestWebhook test if web hook is work fine
  993. func TestWebhook(ctx *context.Context) {
  994. hookID := ctx.ParamsInt64(":id")
  995. w, err := models.GetWebhookByRepoID(ctx.Repo.Repository.ID, hookID)
  996. if err != nil {
  997. ctx.Flash.Error("GetWebhookByID: " + err.Error())
  998. ctx.Status(500)
  999. return
  1000. }
  1001. // Grab latest commit or fake one if it's empty repository.
  1002. commit := ctx.Repo.Commit
  1003. if commit == nil {
  1004. ghost := models.NewGhostUser()
  1005. commit = &git.Commit{
  1006. ID: git.MustIDFromString(git.EmptySHA),
  1007. Author: ghost.NewGitSig(),
  1008. Committer: ghost.NewGitSig(),
  1009. CommitMessage: "This is a fake commit",
  1010. }
  1011. }
  1012. apiUser := convert.ToUserWithAccessMode(ctx.User, models.AccessModeNone)
  1013. apiCommit := &api.PayloadCommit{
  1014. ID: commit.ID.String(),
  1015. Message: commit.Message(),
  1016. URL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
  1017. Author: &api.PayloadUser{
  1018. Name: commit.Author.Name,
  1019. Email: commit.Author.Email,
  1020. },
  1021. Committer: &api.PayloadUser{
  1022. Name: commit.Committer.Name,
  1023. Email: commit.Committer.Email,
  1024. },
  1025. }
  1026. p := &api.PushPayload{
  1027. Ref: git.BranchPrefix + ctx.Repo.Repository.DefaultBranch,
  1028. Before: commit.ID.String(),
  1029. After: commit.ID.String(),
  1030. Commits: []*api.PayloadCommit{apiCommit},
  1031. HeadCommit: apiCommit,
  1032. Repo: convert.ToRepo(ctx.Repo.Repository, models.AccessModeNone),
  1033. Pusher: apiUser,
  1034. Sender: apiUser,
  1035. }
  1036. if err := webhook.PrepareWebhook(w, ctx.Repo.Repository, models.HookEventPush, p); err != nil {
  1037. ctx.Flash.Error("PrepareWebhook: " + err.Error())
  1038. ctx.Status(500)
  1039. } else {
  1040. ctx.Flash.Info(ctx.Tr("repo.settings.webhook.test_delivery_success"))
  1041. ctx.Status(200)
  1042. }
  1043. }
  1044. // DeleteWebhook delete a webhook
  1045. func DeleteWebhook(ctx *context.Context) {
  1046. if err := models.DeleteWebhookByRepoID(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil {
  1047. ctx.Flash.Error("DeleteWebhookByRepoID: " + err.Error())
  1048. } else {
  1049. ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
  1050. }
  1051. ctx.JSON(http.StatusOK, map[string]interface{}{
  1052. "redirect": ctx.Repo.RepoLink + "/settings/hooks",
  1053. })
  1054. }