Skip to content

Commit 078e2b2

Browse files
lengyuqua1012112796zhaoxinMeanozeripath
authored
Add support for corporate WeChat webhooks (#15910)
* 企业微信webhook * 企业微信webhook * 企业微信webhook * Update templates/admin/hook_new.tmpl Co-authored-by: a1012112796 <[email protected]> * Update services/webhook/wechatwork.go Co-authored-by: a1012112796 <[email protected]> * 修善wechatwork * 修善wechatwork * fix * Update locale_cs-CZ.ini fix * fix build * fix * fix build * make webhooks.zh-cn.md * delet unnecessary blank line * delet unnecessary blank line * 企业微信webhook * 企业微信webhook * 企业微信webhook * Update templates/admin/hook_new.tmpl Co-authored-by: a1012112796 <[email protected]> * Update services/webhook/wechatwork.go Co-authored-by: a1012112796 <[email protected]> * 修善wechatwork * 修善wechatwork * fix * fix build * fix * fix build * make webhooks.zh-cn.md * delet unnecessary blank line * delet unnecessary blank line * 企业微信webhook * 企业微信webhook * 企业微信webhook * 企业微信webhook * 企业微信webhook * fix * fix * 企业微信webhook * 企业微信webhook * 企业微信webhook * fix wechat * fix wechat * fix wechat * fix wechat * Fix invalid params and typo of email templates (#16394) Signed-off-by: Meano <[email protected]> * Add LRU mem cache implementation (#16226) The current default memory cache implementation is unbounded in size and number of objects cached. This is hardly ideal. This PR proposes creating a TwoQueue LRU cache as the underlying cache for Gitea. The cache is limited by the number of objects stored in the cache (rather than size) for simplicity. The default number of objects is 50000 - which is perhaps too small as most of our objects cached are going to be much less than 1kB. It may be worth considering using a different LRU implementation that actively limits sizes or avoids GC - however, this is just a beginning implementation. Signed-off-by: Andrew Thornton <[email protected]> * [skip ci] Updated translations via Crowdin * Replace `plugins/docker` with `techknowlogick/drone-docker`in ci (#16407) * plugins/docker -> techknowlogick/drone-docker * It is multi-arch * docs: rewrite email setup (#16404) * Add intro for both the docs page and mailer methods * Fix numbering level in SMTP section * Recommends implicit TLS Signed-off-by: Bagas Sanjaya <[email protected]> * Validate Issue Index before querying DB (#16406) * Fix external renderer (#16401) * fix external renderer * use GBackground context as fallback * no fallback, return error Co-authored-by: Lauris BH <[email protected]> * Add checkbox to delete pull branch after successful merge (#16049) * Add checkbox to delete pull branch after successful merge * Omit DeleteBranchAfterMerge field in json * Log a warning instead of error when PR head branch deleted * Add DefaultDeleteBranchAfterMerge to PullRequestConfig * Add support for delete_branch_after_merge via API * Fix for API: the branch should be deleted from the HEAD repo If head and base repo are the same, reuse the already opened ctx.Repo.GitRepo * Don't delegate to CleanupBranch, only reuse branch deletion code CleanupBranch contains too much logic that has already been performed by the Merge * Reuse gitrepo in MergePullRequest Co-authored-by: Andrew Thornton <[email protected]> * [skip ci] Updated translations via Crowdin * Detect encoding changes while parsing diff (#16330) * Detect encoding changes while parsing diff * Let branch/tag name be a valid ref to get CI status (#16400) * fix #16384# * refactor: move shared helper func to utils package * extend Tests * use ctx.Repo.GitRepo if not nil * fix * fix * 企业微信webhook * 企业微信webhook * 企业微信webhook * fix build * fix build * Apply suggestions from code review Co-authored-by: a1012112796 <[email protected]> Co-authored-by: myheavily <myheavily> Co-authored-by: zhaoxin <[email protected]> Co-authored-by: Meano <[email protected]> Co-authored-by: zeripath <[email protected]> Co-authored-by: GiteaBot <[email protected]> Co-authored-by: 6543 <[email protected]> Co-authored-by: Bagas Sanjaya <[email protected]> Co-authored-by: Norwin <[email protected]> Co-authored-by: Lauris BH <[email protected]> Co-authored-by: Jimmy Praet <[email protected]> Co-authored-by: Lunny Xiao <[email protected]>
1 parent afb040e commit 078e2b2

File tree

24 files changed

+364
-30
lines changed

24 files changed

+364
-30
lines changed

docs/content/doc/features/webhooks.en-us.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ All event pushes are POST requests. The methods currently supported are:
2727
- Telegram
2828
- Microsoft Teams
2929
- Feishu
30+
- Wechatwork
3031

3132
### Event information
3233

docs/content/doc/features/webhooks.zh-cn.md

+13
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,17 @@ menu:
1515

1616
# Webhooks
1717

18+
Gitea 的存储 webhook。这可以有存储库管路设定页 `/:username/:reponame/settings/hooks` 中的。Webhook 也可以按照组织调整或全系统调整,所有时间的推送都是POST请求
19+
。此方法目前被下列服务支援:
20+
21+
- Gitea (也可以是 GET 請求)
22+
- Gogs
23+
- Slack
24+
- Discord
25+
- Dingtalk
26+
- Telegram
27+
- Microsoft Teams
28+
- Feishu
29+
- Wechatwork
30+
1831
## TBD

docs/content/doc/features/webhooks.zh-tw.md

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Gitea 的儲存庫事件支援 web hook。這可以有儲存庫管理員在設
2626
- Telegram
2727
- Microsoft Teams
2828
- Feishu
29+
- Wechatwork
2930

3031
### 事件資訊
3132

models/migrations/v161.go

+11-9
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,20 @@ func convertTaskTypeToString(x *xorm.Engine) error {
1919
MSTEAMS
2020
FEISHU
2121
MATRIX
22+
WECHATWORK
2223
)
2324

2425
hookTaskTypes := map[int]string{
25-
GITEA: "gitea",
26-
GOGS: "gogs",
27-
SLACK: "slack",
28-
DISCORD: "discord",
29-
DINGTALK: "dingtalk",
30-
TELEGRAM: "telegram",
31-
MSTEAMS: "msteams",
32-
FEISHU: "feishu",
33-
MATRIX: "matrix",
26+
GITEA: "gitea",
27+
GOGS: "gogs",
28+
SLACK: "slack",
29+
DISCORD: "discord",
30+
DINGTALK: "dingtalk",
31+
TELEGRAM: "telegram",
32+
MSTEAMS: "msteams",
33+
FEISHU: "feishu",
34+
MATRIX: "matrix",
35+
WECHATWORK: "wechatwork",
3436
}
3537

3638
type HookTask struct {

models/migrations/v162.go

+11-9
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,20 @@ func convertWebhookTaskTypeToString(x *xorm.Engine) error {
1919
MSTEAMS
2020
FEISHU
2121
MATRIX
22+
WECHATWORK
2223
)
2324

2425
hookTaskTypes := map[int]string{
25-
GITEA: "gitea",
26-
GOGS: "gogs",
27-
SLACK: "slack",
28-
DISCORD: "discord",
29-
DINGTALK: "dingtalk",
30-
TELEGRAM: "telegram",
31-
MSTEAMS: "msteams",
32-
FEISHU: "feishu",
33-
MATRIX: "matrix",
26+
GITEA: "gitea",
27+
GOGS: "gogs",
28+
SLACK: "slack",
29+
DISCORD: "discord",
30+
DINGTALK: "dingtalk",
31+
TELEGRAM: "telegram",
32+
MSTEAMS: "msteams",
33+
FEISHU: "feishu",
34+
MATRIX: "matrix",
35+
WECHATWORK: "wechatwork",
3436
}
3537

3638
type Webhook struct {

models/webhook.go

+10-9
Original file line numberDiff line numberDiff line change
@@ -114,15 +114,16 @@ type HookType = string
114114

115115
// Types of webhooks
116116
const (
117-
GITEA HookType = "gitea"
118-
GOGS HookType = "gogs"
119-
SLACK HookType = "slack"
120-
DISCORD HookType = "discord"
121-
DINGTALK HookType = "dingtalk"
122-
TELEGRAM HookType = "telegram"
123-
MSTEAMS HookType = "msteams"
124-
FEISHU HookType = "feishu"
125-
MATRIX HookType = "matrix"
117+
GITEA HookType = "gitea"
118+
GOGS HookType = "gogs"
119+
SLACK HookType = "slack"
120+
DISCORD HookType = "discord"
121+
DINGTALK HookType = "dingtalk"
122+
TELEGRAM HookType = "telegram"
123+
MSTEAMS HookType = "msteams"
124+
FEISHU HookType = "feishu"
125+
MATRIX HookType = "matrix"
126+
WECHATWORK HookType = "wechatwork"
126127
)
127128

128129
// HookStatus is the status of a web hook

modules/setting/webhook.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func newWebhookService() {
3636
Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
3737
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
3838
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
39-
Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix"}
39+
Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams", "feishu", "matrix", "wechatwork"}
4040
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
4141
Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("")
4242
if Webhook.ProxyURL != "" {

modules/structs/hook.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type CreateHookOptionConfig map[string]string
4242
// CreateHookOption options when create a hook
4343
type CreateHookOption struct {
4444
// required: true
45-
// enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu
45+
// enum: dingtalk,discord,gitea,gogs,msteams,slack,telegram,feishu,wechatwork
4646
Type string `json:"type" binding:"Required"`
4747
// required: true
4848
Config CreateHookOptionConfig `json:"config" binding:"Required"`

options/locale/locale_cs-CZ.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1758,6 +1758,7 @@ settings.add_telegram_hook_desc=Integrovat <a href="%s">Telegram</a> do vašeho
17581758
settings.add_matrix_hook_desc=Integrovat <a href="%s">Matrix</a> do vašeho repozitáře.
17591759
settings.add_msteams_hook_desc=Integrovat <a href="%s">Microsoft Teams</a> do vašeho repozitáře.
17601760
settings.add_feishu_hook_desc=Integrovat <a href="%s">Feishu</a> do vašeho repozitáře.
1761+
settings.add_wechatwork_hook_desc=Integrovat <a href="%s">Wechatwork</a> do vašeho repozitáře.
17611762
settings.deploy_keys=Klíče pro nasazení
17621763
settings.add_deploy_key=Přidat klíč pro nasazení
17631764
settings.deploy_key_desc=Klíče pro nasazení mají k tomuto repozitáři přístup pouze pro čtení.

options/locale/locale_en-US.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,7 @@ settings.add_telegram_hook_desc = Integrate <a href="%s">Telegram</a> into your
18481848
settings.add_matrix_hook_desc = Integrate <a href="%s">Matrix</a> into your repository.
18491849
settings.add_msteams_hook_desc = Integrate <a href="%s">Microsoft Teams</a> into your repository.
18501850
settings.add_feishu_hook_desc = Integrate <a href="%s">Feishu</a> into your repository.
1851+
settings.add_Wechat_hook_desc = Integrate <a href="%s">Wechatwork</a> into your repository.
18511852
settings.deploy_keys = Deploy Keys
18521853
settings.add_deploy_key = Add Deploy Key
18531854
settings.deploy_key_desc = Deploy keys have read-only pull access to the repository.

options/locale/locale_zh-CN.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,7 @@ settings.add_telegram_hook_desc=将 <a href="%s">Telegram</a> 集成到您的仓
18481848
settings.add_matrix_hook_desc=将 <a href="%s">Matrix</a> 集成到您的仓库中。
18491849
settings.add_msteams_hook_desc=将 <a href="%s">Microsoft Teams</a> 集成到您的仓库中。
18501850
settings.add_feishu_hook_desc=将 <a href="%s">Feishu</a> 集成到您的仓库中。
1851+
settings.add_wechatwork_hook_desc=将 <a href="%s">Wechatwork</a> 集成到您的仓库中。
18511852
settings.deploy_keys=部署密钥
18521853
settings.add_deploy_key=添加部署密钥
18531854
settings.deploy_key_desc=部署密钥具有对仓库的只读拉取权限。

options/locale/locale_zh-TW.ini

+1
Original file line numberDiff line numberDiff line change
@@ -1833,6 +1833,7 @@ settings.add_telegram_hook_desc=將 <a href="%s">Telegram</a> 整合到您的儲
18331833
settings.add_matrix_hook_desc=將 <a href="%s">Matrix</a> 整合到您的儲存庫。
18341834
settings.add_msteams_hook_desc=將 <a href="%s">Microsoft Teams</a> 整合到您的儲存庫。
18351835
settings.add_feishu_hook_desc=將 <a href="%s">Feishu</a> 整合到您的儲存庫。
1836+
settings.add_wechatwork_hook_desc=将 <a href="%s">Wechatwork</a> 整合到您的儲存庫。
18361837
settings.deploy_keys=部署金鑰
18371838
settings.add_deploy_key=新增部署金鑰
18381839
settings.deploy_key_desc=部署金鑰具有唯讀權限,可拉取此儲存庫。

public/img/wechatwork.png

9.12 KB
Loading

routers/web/repo/webhook.go

+77
Original file line numberDiff line numberDiff line change
@@ -638,6 +638,50 @@ func FeishuHooksNewPost(ctx *context.Context) {
638638
ctx.Redirect(orCtx.Link)
639639
}
640640

641+
// WechatworkHooksNewPost response for creating wechatwork hook
642+
func WechatworkHooksNewPost(ctx *context.Context) {
643+
form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm)
644+
645+
ctx.Data["Title"] = ctx.Tr("repo.settings")
646+
ctx.Data["PageIsSettingsHooks"] = true
647+
ctx.Data["PageIsSettingsHooksNew"] = true
648+
ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
649+
ctx.Data["HookType"] = models.WECHATWORK
650+
651+
orCtx, err := getOrgRepoCtx(ctx)
652+
if err != nil {
653+
ctx.ServerError("getOrgRepoCtx", err)
654+
return
655+
}
656+
657+
if ctx.HasError() {
658+
ctx.HTML(http.StatusOK, orCtx.NewTemplate)
659+
return
660+
}
661+
662+
w := &models.Webhook{
663+
RepoID: orCtx.RepoID,
664+
URL: form.PayloadURL,
665+
ContentType: models.ContentTypeJSON,
666+
HookEvent: ParseHookEvent(form.WebhookForm),
667+
IsActive: form.Active,
668+
Type: models.WECHATWORK,
669+
Meta: "",
670+
OrgID: orCtx.OrgID,
671+
IsSystemWebhook: orCtx.IsSystemWebhook,
672+
}
673+
if err := w.UpdateEvent(); err != nil {
674+
ctx.ServerError("UpdateEvent", err)
675+
return
676+
} else if err := models.CreateWebhook(w); err != nil {
677+
ctx.ServerError("CreateWebhook", err)
678+
return
679+
}
680+
681+
ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
682+
ctx.Redirect(orCtx.Link)
683+
}
684+
641685
func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) {
642686
ctx.Data["RequireHighlightJS"] = true
643687

@@ -1062,6 +1106,39 @@ func FeishuHooksEditPost(ctx *context.Context) {
10621106
ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
10631107
}
10641108

1109+
// WechatworkHooksEditPost response for editing wechatwork hook
1110+
func WechatworkHooksEditPost(ctx *context.Context) {
1111+
form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm)
1112+
ctx.Data["Title"] = ctx.Tr("repo.settings")
1113+
ctx.Data["PageIsSettingsHooks"] = true
1114+
ctx.Data["PageIsSettingsHooksEdit"] = true
1115+
1116+
orCtx, w := checkWebhook(ctx)
1117+
if ctx.Written() {
1118+
return
1119+
}
1120+
ctx.Data["Webhook"] = w
1121+
1122+
if ctx.HasError() {
1123+
ctx.HTML(http.StatusOK, orCtx.NewTemplate)
1124+
return
1125+
}
1126+
1127+
w.URL = form.PayloadURL
1128+
w.HookEvent = ParseHookEvent(form.WebhookForm)
1129+
w.IsActive = form.Active
1130+
if err := w.UpdateEvent(); err != nil {
1131+
ctx.ServerError("UpdateEvent", err)
1132+
return
1133+
} else if err := models.UpdateWebhook(w); err != nil {
1134+
ctx.ServerError("UpdateWebhook", err)
1135+
return
1136+
}
1137+
1138+
ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
1139+
ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID))
1140+
}
1141+
10651142
// TestWebhook test if web hook is work fine
10661143
func TestWebhook(ctx *context.Context) {
10671144
hookID := ctx.ParamsInt64(":id")

routers/web/web.go

+5
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,7 @@ func RegisterRoutes(m *web.Route) {
425425
m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
426426
m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
427427
m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
428+
m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
428429
}, webhooksEnabled)
429430

430431
m.Group("/{configType:default-hooks|system-hooks}", func() {
@@ -438,6 +439,8 @@ func RegisterRoutes(m *web.Route) {
438439
m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
439440
m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
440441
m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
442+
m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
443+
441444
})
442445

443446
m.Group("/auths", func() {
@@ -628,6 +631,7 @@ func RegisterRoutes(m *web.Route) {
628631
m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
629632
m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
630633
m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
634+
m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
631635
m.Get("/{id}", repo.WebHooksEdit)
632636
m.Post("/{id}/test", repo.TestWebhook)
633637
m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.WebHooksEditPost)
@@ -639,6 +643,7 @@ func RegisterRoutes(m *web.Route) {
639643
m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
640644
m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
641645
m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
646+
m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
642647
}, webhooksEnabled)
643648

644649
m.Group("/keys", func() {

services/forms/repo_form.go

+12
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,18 @@ func (f *NewFeishuHookForm) Validate(req *http.Request, errs binding.Errors) bin
382382
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
383383
}
384384

385+
// NewWechatWorkHookForm form for creating wechatwork hook
386+
type NewWechatWorkHookForm struct {
387+
PayloadURL string `binding:"Required;ValidUrl"`
388+
WebhookForm
389+
}
390+
391+
// Validate validates the fields
392+
func (f *NewWechatWorkHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
393+
ctx := context.GetContext(req)
394+
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
395+
}
396+
385397
// .___
386398
// | | ______ ________ __ ____
387399
// | |/ ___// ___/ | \_/ __ \

services/webhook/webhook.go

+4
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ var (
5252
name: models.MATRIX,
5353
payloadCreator: GetMatrixPayload,
5454
},
55+
models.WECHATWORK: {
56+
name: models.WECHATWORK,
57+
payloadCreator: GetWechatworkPayload,
58+
},
5559
}
5660
)
5761

0 commit comments

Comments
 (0)