diff --git a/models/webhook.go b/models/webhook.go index a764455f5f39a..a7daae9c56939 100644 --- a/models/webhook.go +++ b/models/webhook.go @@ -141,6 +141,16 @@ func (w *Webhook) GetDiscordHook() *DiscordMeta { return s } +// GetWorkwechatHook returns work wechat metadata +func (w *Webhook) GetWorkwechatHook() *WorkwechatMeta { + s := &WorkwechatMeta{} + + if err := json.Unmarshal([]byte(w.Meta), s); err != nil { + log.Error(4, "webhook.GetWorkwechatMetaHook(%d): %v", w.ID, err) + } + return s +} + // History returns history of webhook by given conditions. func (w *Webhook) History(page int) ([]*HookTask, error) { return HookTasks(w.ID, page) @@ -381,14 +391,16 @@ const ( GITEA DISCORD DINGTALK + WORKWECHAT ) var hookTaskTypes = map[string]HookTaskType{ - "gitea": GITEA, - "gogs": GOGS, - "slack": SLACK, - "discord": DISCORD, - "dingtalk": DINGTALK, + "gitea": GITEA, + "gogs": GOGS, + "slack": SLACK, + "discord": DISCORD, + "dingtalk": DINGTALK, + "workwechat": WORKWECHAT, } // ToHookTaskType returns HookTaskType by given name. @@ -409,6 +421,8 @@ func (t HookTaskType) Name() string { return "discord" case DINGTALK: return "dingtalk" + case WORKWECHAT: + return "workwechat" } return "" } @@ -581,6 +595,11 @@ func prepareWebhook(e Engine, w *Webhook, repo *Repository, event HookEventType, if err != nil { return fmt.Errorf("GetDingtalkPayload: %v", err) } + case WORKWECHAT: + payloader, err = GetWorkwechatPayload(p, event, w.Meta) + if err != nil { + return fmt.Errorf("GetWorkwechatPayload: %v", err) + } default: p.SetSecret(w.Secret) payloader = p diff --git a/models/webhook_workwechat.go b/models/webhook_workwechat.go new file mode 100644 index 0000000000000..0f57338ca2069 --- /dev/null +++ b/models/webhook_workwechat.go @@ -0,0 +1,405 @@ +// Copyright 2018 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package models + +import ( + "encoding/json" + "errors" + "fmt" + "strings" + + "code.gitea.io/git" + api "code.gitea.io/sdk/gitea" +) + +type ( + // Text message + Text struct { + Content string `json:"content"` + } + + //TextCard message + TextCard struct { + Title string `json:"title"` + Description string `json:"description"` + URL string `json:"url"` + ButtonText string `json:"btntxt"` + } + //WorkwechatPayload represents + WorkwechatPayload struct { + ChatID string `json:"chatid"` + MsgType string `json:"msgtype"` + Text Text `json:"text"` + TextCard TextCard `json:"textcard"` + Safe int `json:"safe"` + } + + // WorkwechatMeta contains the work wechat metadata + WorkwechatMeta struct { + ChatID string `json:"chatid"` + } +) + +// SetSecret sets the workwechat secret +func (p *WorkwechatPayload) SetSecret(_ string) {} + +// JSONPayload Marshals the WorkwechatPayload to json +func (p *WorkwechatPayload) JSONPayload() ([]byte, error) { + data, err := json.MarshalIndent(p, "", " ") + if err != nil { + return []byte{}, err + } + return data, nil +} + +func getWorkwechatCreatePayload(p *api.CreatePayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + // created tag/branch + refName := git.RefEndName(p.Ref) + title := fmt.Sprintf("[%s] %s %s created", p.Repo.FullName, p.RefType, refName) + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Title: title, + Description: title, + ButtonText: fmt.Sprintf("view ref %s", refName), + URL: p.Repo.HTMLURL + "/src/" + refName, + }, + }, nil +} + +func getWorkwechatDeletePayload(p *api.DeletePayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + // created tag/branch + refName := git.RefEndName(p.Ref) + title := fmt.Sprintf("[%s] %s %s deleted", p.Repo.FullName, p.RefType, refName) + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Title: title, + Description: title, + ButtonText: fmt.Sprintf("view ref %s", refName), + URL: p.Repo.HTMLURL + "/src/" + refName, + }, + }, nil +} + +func getWorkwechatForkPayload(p *api.ForkPayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + title := fmt.Sprintf("%s is forked to %s", p.Forkee.FullName, p.Repo.FullName) + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title, + Title: title, + ButtonText: fmt.Sprintf("view forked repo %s", p.Repo.FullName), + URL: p.Repo.HTMLURL, + }, + }, nil +} + +func getWorkwechatPushPayload(p *api.PushPayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + var ( + branchName = git.RefEndName(p.Ref) + commitDesc string + ) + + var titleLink, linkText string + if len(p.Commits) == 1 { + commitDesc = "1 new commit" + titleLink = p.Commits[0].URL + linkText = fmt.Sprintf("view commit %s", p.Commits[0].ID[:7]) + } else { + commitDesc = fmt.Sprintf("%d new commits", len(p.Commits)) + titleLink = p.CompareURL + linkText = fmt.Sprintf("view commit %s...%s", p.Commits[0].ID[:7], p.Commits[len(p.Commits)-1].ID[:7]) + } + if titleLink == "" { + titleLink = p.Repo.HTMLURL + "/src/" + branchName + } + + title := fmt.Sprintf("[%s:%s] %s", p.Repo.FullName, branchName, commitDesc) + + var text string + // for each commit, generate attachment text + for i, commit := range p.Commits { + var authorName string + if commit.Author != nil { + authorName = " - " + commit.Author.Name + } + text += fmt.Sprintf("[%s](%s) %s", commit.ID[:7], commit.URL, + strings.TrimRight(commit.Message, "\r\n")) + authorName + // add linebreak to each commit but the last + if i < len(p.Commits)-1 { + text += "\n" + } + } + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: text, + Title: title, + ButtonText: linkText, + URL: titleLink, + }, + }, nil +} + +func getWorkwechatIssuesPayload(p *api.IssuePayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + var text, title string + switch p.Action { + case api.HookIssueOpened: + title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueClosed: + title = fmt.Sprintf("[%s] Issue closed: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueReOpened: + title = fmt.Sprintf("[%s] Issue re-opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueEdited: + title = fmt.Sprintf("[%s] Issue edited: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueAssigned: + title = fmt.Sprintf("[%s] Issue assigned to %s: #%d %s", p.Repository.FullName, + p.Issue.Assignee.UserName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueUnassigned: + title = fmt.Sprintf("[%s] Issue unassigned: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueLabelUpdated: + title = fmt.Sprintf("[%s] Issue labels updated: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueLabelCleared: + title = fmt.Sprintf("[%s] Issue labels cleared: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueSynchronized: + title = fmt.Sprintf("[%s] Issue synchronized: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueMilestoned: + title = fmt.Sprintf("[%s] Issue milestone: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + case api.HookIssueDemilestoned: + title = fmt.Sprintf("[%s] Issue clear milestone: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title) + text = p.Issue.Body + } + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title + "\r\n\r\n" + text, + //Markdown: "# " + title + "\n" + text, + Title: title, + ButtonText: "view issue", + URL: p.Issue.URL, + }, + }, nil +} + +func getWorkwechatIssueCommentPayload(p *api.IssueCommentPayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + title := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) + url := fmt.Sprintf("%s/issues/%d#%s", p.Repository.HTMLURL, p.Issue.Index, CommentHashTag(p.Comment.ID)) + var content string + switch p.Action { + case api.HookIssueCommentCreated: + title = "New comment: " + title + content = p.Comment.Body + case api.HookIssueCommentEdited: + title = "Comment edited: " + title + content = p.Comment.Body + case api.HookIssueCommentDeleted: + title = "Comment deleted: " + title + url = fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index) + content = p.Comment.Body + } + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title + "\r\n\r\n" + content, + Title: title, + ButtonText: "view issue comment", + URL: url, + }, + }, nil +} + +func getWorkwechatPullRequestPayload(p *api.PullRequestPayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + var text, title string + switch p.Action { + case api.HookIssueOpened: + title = fmt.Sprintf("[%s] Pull request opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueClosed: + if p.PullRequest.HasMerged { + title = fmt.Sprintf("[%s] Pull request merged: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + } else { + title = fmt.Sprintf("[%s] Pull request closed: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + } + text = p.PullRequest.Body + case api.HookIssueReOpened: + title = fmt.Sprintf("[%s] Pull request re-opened: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueEdited: + title = fmt.Sprintf("[%s] Pull request edited: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueAssigned: + list, err := MakeAssigneeList(&Issue{ID: p.PullRequest.ID}) + if err != nil { + return &WorkwechatPayload{}, err + } + title = fmt.Sprintf("[%s] Pull request assigned to %s: #%d %s", p.Repository.FullName, + list, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueUnassigned: + title = fmt.Sprintf("[%s] Pull request unassigned: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueLabelUpdated: + title = fmt.Sprintf("[%s] Pull request labels updated: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueLabelCleared: + title = fmt.Sprintf("[%s] Pull request labels cleared: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueSynchronized: + title = fmt.Sprintf("[%s] Pull request synchronized: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueMilestoned: + title = fmt.Sprintf("[%s] Pull request milestone: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + case api.HookIssueDemilestoned: + title = fmt.Sprintf("[%s] Pull request clear milestone: #%d %s", p.Repository.FullName, p.Index, p.PullRequest.Title) + text = p.PullRequest.Body + } + + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title + "\r\n\r\n" + text, + //Markdown: "# " + title + "\n" + text, + Title: title, + ButtonText: "view pull request", + URL: p.PullRequest.HTMLURL, + }, + }, nil +} + +func getWorkwechatRepositoryPayload(p *api.RepositoryPayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + var title, url string + switch p.Action { + case api.HookRepoCreated: + title = fmt.Sprintf("[%s] Repository created", p.Repository.FullName) + url = p.Repository.HTMLURL + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title, + Title: title, + ButtonText: "view repository", + URL: url, + }, + }, nil + case api.HookRepoDeleted: + title = fmt.Sprintf("[%s] Repository deleted", p.Repository.FullName) + return &WorkwechatPayload{ + MsgType: "text", + Text: struct { + Content string `json:"content"` + }{ + Content: title, + }, + }, nil + } + + return nil, nil +} + +func getWorkwechatReleasePayload(p *api.ReleasePayload, meta *WorkwechatMeta) (*WorkwechatPayload, error) { + var title, url string + switch p.Action { + case api.HookReleasePublished: + title = fmt.Sprintf("[%s] Release created", p.Release.TagName) + url = p.Release.URL + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title, + Title: title, + ButtonText: "view release", + URL: url, + }, + }, nil + case api.HookReleaseUpdated: + title = fmt.Sprintf("[%s] Release updated", p.Release.TagName) + url = p.Release.URL + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title, + Title: title, + ButtonText: "view release", + URL: url, + }, + }, nil + + case api.HookReleaseDeleted: + title = fmt.Sprintf("[%s] Release deleted", p.Release.TagName) + url = p.Release.URL + return &WorkwechatPayload{ + ChatID: meta.ChatID, + MsgType: "textcard", + TextCard: TextCard{ + Description: title, + Title: title, + ButtonText: "view release", + URL: url, + }, + }, nil + } + + return nil, nil +} + +// GetWorkwechatPayload converts a work wechat webhook into a WorkwechatPayload +func GetWorkwechatPayload(p api.Payloader, event HookEventType, meta string) (*WorkwechatPayload, error) { + s := new(WorkwechatPayload) + + workwechatMeta := &WorkwechatMeta{} + if err := json.Unmarshal([]byte(meta), &workwechatMeta); err != nil { + return s, errors.New("GetWorkwechatPayload meta json:" + err.Error()) + } + switch event { + case HookEventCreate: + return getWorkwechatCreatePayload(p.(*api.CreatePayload), workwechatMeta) + case HookEventDelete: + return getWorkwechatDeletePayload(p.(*api.DeletePayload), workwechatMeta) + case HookEventFork: + return getWorkwechatForkPayload(p.(*api.ForkPayload), workwechatMeta) + case HookEventIssues: + return getWorkwechatIssuesPayload(p.(*api.IssuePayload), workwechatMeta) + case HookEventIssueComment: + return getWorkwechatIssueCommentPayload(p.(*api.IssueCommentPayload), workwechatMeta) + case HookEventPush: + return getWorkwechatPushPayload(p.(*api.PushPayload), workwechatMeta) + case HookEventPullRequest: + return getWorkwechatPullRequestPayload(p.(*api.PullRequestPayload), workwechatMeta) + case HookEventRepository: + return getWorkwechatRepositoryPayload(p.(*api.RepositoryPayload), workwechatMeta) + case HookEventRelease: + return getWorkwechatReleasePayload(p.(*api.ReleasePayload), workwechatMeta) + } + + return s, nil +} diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go index 0a97b08c71564..21a2282abf898 100644 --- a/modules/auth/repo_form.go +++ b/modules/auth/repo_form.go @@ -263,6 +263,18 @@ func (f *NewDingtalkHookForm) Validate(ctx *macaron.Context, errs binding.Errors return validate(errs, ctx.Data, f, ctx.Locale) } +// NewWorkwechatHookForm form for creating work wechat hook +type NewWorkwechatHookForm struct { + PayloadURL string `binding:"Required;ValidUrl"` + ChatID string `form:"chatid"` + WebhookForm +} + +// Validate validates the fields +func (f *NewWorkwechatHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { + return validate(errs, ctx.Data, f, ctx.Locale) +} + // .___ // | | ______ ________ __ ____ // | |/ ___// ___/ | \_/ __ \ diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 4c016f3489bb2..1c5b557ee095e 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -1219,6 +1219,7 @@ func NewContext() { // Explicitly disable credential helper, otherwise Git credentials might leak git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") } + } // NewServices initializes the services diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index c5a62cb4885a6..57a62018b230e 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1158,6 +1158,8 @@ settings.slack_domain = Domain settings.slack_channel = Channel settings.add_discord_hook_desc = Integrate Discord into your repository. settings.add_dingtalk_hook_desc = Integrate Dingtalk into your repository. +settings.add_workwechat_hook_desc = Integrate Work Wechat into your repository. +settings.workwechat_chatid=Chat ID settings.deploy_keys = Deploy Keys settings.add_deploy_key = Add Deploy Key settings.deploy_key_desc = Deploy keys have read-only pull access to the repository. diff --git a/public/img/workwechat.ico b/public/img/workwechat.ico new file mode 100644 index 0000000000000..a7f24f5aaad28 Binary files /dev/null and b/public/img/workwechat.ico differ diff --git a/routers/api/v1/convert/convert.go b/routers/api/v1/convert/convert.go index 6569d21ab89a0..a106ba1b8b875 100644 --- a/routers/api/v1/convert/convert.go +++ b/routers/api/v1/convert/convert.go @@ -166,8 +166,10 @@ func ToHook(repoLink string, w *models.Webhook) *api.Hook { config["username"] = s.Username config["icon_url"] = s.IconURL config["color"] = s.Color + } else if w.HookTaskType == models.WORKWECHAT { + s := w.GetWorkwechatHook() + config["chatid"] = s.ChatID } - return &api.Hook{ ID: w.ID, Type: w.HookTaskType.Name(), diff --git a/routers/repo/webhook.go b/routers/repo/webhook.go index 6c69354c700eb..559383cded09e 100644 --- a/routers/repo/webhook.go +++ b/routers/repo/webhook.go @@ -105,6 +105,10 @@ func WebhooksNew(ctx *context.Context) { "Username": "Gitea", "IconURL": setting.AppURL + "img/favicon.png", } + } else if hookType == "workwechat" { + ctx.Data["WorkwechatHook"] = map[string]interface{}{ + "ChatID": "gitea", + } } ctx.Data["BaseLink"] = orCtx.Link @@ -314,6 +318,52 @@ func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) { ctx.Redirect(orCtx.Link + "/settings/hooks") } +// WorkwechatHooksNewPost response for creating work wechat hook +func WorkwechatHooksNewPost(ctx *context.Context, form auth.NewWorkwechatHookForm) { + ctx.Data["Title"] = ctx.Tr("repo.settings") + ctx.Data["PageIsSettingsHooks"] = true + ctx.Data["PageIsSettingsHooksNew"] = true + ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}} + + orCtx, err := getOrgRepoCtx(ctx) + if err != nil { + ctx.ServerError("getOrgRepoCtx", err) + return + } + + if ctx.HasError() { + ctx.HTML(200, orCtx.NewTemplate) + return + } + meta, err := json.Marshal(&models.WorkwechatMeta{ + ChatID: form.ChatID, + }) + if err != nil { + ctx.ServerError("Marshal", err) + return + } + w := &models.Webhook{ + RepoID: orCtx.RepoID, + URL: form.PayloadURL, + ContentType: models.ContentTypeJSON, + HookEvent: ParseHookEvent(form.WebhookForm), + IsActive: form.Active, + HookTaskType: models.WORKWECHAT, + Meta: string(meta), + OrgID: orCtx.OrgID, + } + if err := w.UpdateEvent(); err != nil { + ctx.ServerError("UpdateEvent", err) + return + } else if err := models.CreateWebhook(w); err != nil { + ctx.ServerError("CreateWebhook", err) + return + } + + ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) + ctx.Redirect(orCtx.Link + "/settings/hooks") +} + // SlackHooksNewPost response for creating slack hook func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) { ctx.Data["Title"] = ctx.Tr("repo.settings") @@ -402,6 +452,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) { ctx.Data["SlackHook"] = w.GetSlackHook() case models.DISCORD: ctx.Data["DiscordHook"] = w.GetDiscordHook() + case models.WORKWECHAT: + ctx.Data["WorkwechatHook"] = w.GetWorkwechatHook() } ctx.Data["History"], err = w.History(1) @@ -596,7 +648,7 @@ func DiscordHooksEditPost(ctx *context.Context, form auth.NewDiscordHookForm) { ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID)) } -// DingtalkHooksEditPost response for editing discord hook +// DingtalkHooksEditPost response for editing dingtalk hook func DingtalkHooksEditPost(ctx *context.Context, form auth.NewDingtalkHookForm) { ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsHooks"] = true @@ -628,6 +680,46 @@ func DingtalkHooksEditPost(ctx *context.Context, form auth.NewDingtalkHookForm) ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID)) } +// WorkwechatHooksEditPost response for editing work wechat hook +func WorkwechatHooksEditPost(ctx *context.Context, form auth.NewWorkwechatHookForm) { + ctx.Data["Title"] = ctx.Tr("repo.settings") + ctx.Data["PageIsSettingsHooks"] = true + ctx.Data["PageIsSettingsHooksEdit"] = true + + orCtx, w := checkWebhook(ctx) + if ctx.Written() { + return + } + ctx.Data["Webhook"] = w + + if ctx.HasError() { + ctx.HTML(200, orCtx.NewTemplate) + return + } + meta, err := json.Marshal(&models.WorkwechatMeta{ + ChatID: form.ChatID, + }) + if err != nil { + ctx.ServerError("Marshal", err) + return + } + + w.URL = form.PayloadURL + w.Meta = string(meta) + w.HookEvent = ParseHookEvent(form.WebhookForm) + w.IsActive = form.Active + if err := w.UpdateEvent(); err != nil { + ctx.ServerError("UpdateEvent", err) + return + } else if err := models.UpdateWebhook(w); err != nil { + ctx.ServerError("UpdateWebhook", err) + return + } + + ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success")) + ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID)) +} + // TestWebhook test if web hook is work fine func TestWebhook(ctx *context.Context) { hookID := ctx.ParamsInt64(":id") diff --git a/routers/routes/routes.go b/routers/routes/routes.go index b73b030a51e09..91753f0bbe6d5 100644 --- a/routers/routes/routes.go +++ b/routers/routes/routes.go @@ -484,12 +484,14 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) + m.Post("/workwechat/new", bindIgnErr(auth.NewWorkwechatHookForm{}), repo.WorkwechatHooksNewPost) m.Get("/:id", repo.WebHooksEdit) m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) m.Post("/gogs/:id", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksEditPost) m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) + m.Post("/workwechat/:id", bindIgnErr(auth.NewWorkwechatHookForm{}), repo.WorkwechatHooksEditPost) }) m.Route("/delete", "GET,POST", org.SettingsDelete) @@ -537,6 +539,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) m.Post("/dingtalk/new", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) + m.Post("/workwechat/new", bindIgnErr(auth.NewWorkwechatHookForm{}), repo.WorkwechatHooksNewPost) m.Get("/:id", repo.WebHooksEdit) m.Post("/:id/test", repo.TestWebhook) m.Post("/gitea/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost) @@ -544,6 +547,7 @@ func RegisterRoutes(m *macaron.Macaron) { m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost) m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost) m.Post("/dingtalk/:id", bindIgnErr(auth.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) + m.Post("/workwechat/:id", bindIgnErr(auth.NewWorkwechatHookForm{}), repo.WorkwechatHooksEditPost) m.Group("/git", func() { m.Get("", repo.GitHooks) diff --git a/templates/org/settings/hook_new.tmpl b/templates/org/settings/hook_new.tmpl index 809009b66b7b4..c3cdf1b24a97a 100644 --- a/templates/org/settings/hook_new.tmpl +++ b/templates/org/settings/hook_new.tmpl @@ -18,7 +18,9 @@ {{else if eq .HookType "discord"}} {{else if eq .HookType "dingtalk"}} - + + {{else if eq .HookType "workwechat"}} + {{end}} @@ -28,6 +30,7 @@ {{template "repo/settings/webhook/slack" .}} {{template "repo/settings/webhook/discord" .}} {{template "repo/settings/webhook/dingtalk" .}} + {{template "repo/settings/webhook/workwechat" .}} {{template "repo/settings/webhook/history" .}} diff --git a/templates/repo/settings/webhook/list.tmpl b/templates/repo/settings/webhook/list.tmpl index d98976cf5b400..cdef0d4829677 100644 --- a/templates/repo/settings/webhook/list.tmpl +++ b/templates/repo/settings/webhook/list.tmpl @@ -20,6 +20,9 @@ Dingtalk + + Work Wechat + diff --git a/templates/repo/settings/webhook/new.tmpl b/templates/repo/settings/webhook/new.tmpl index 1b3d114577a4e..b4ad5cfb7d423 100644 --- a/templates/repo/settings/webhook/new.tmpl +++ b/templates/repo/settings/webhook/new.tmpl @@ -17,6 +17,8 @@ {{else if eq .HookType "dingtalk"}} + {{else if eq .HookType "workwechat"}} + {{end}} @@ -26,6 +28,7 @@ {{template "repo/settings/webhook/slack" .}} {{template "repo/settings/webhook/discord" .}} {{template "repo/settings/webhook/dingtalk" .}} + {{template "repo/settings/webhook/workwechat" .}} {{template "repo/settings/webhook/history" .}} diff --git a/templates/repo/settings/webhook/workwechat.tmpl b/templates/repo/settings/webhook/workwechat.tmpl new file mode 100644 index 0000000000000..fa1012efc29e6 --- /dev/null +++ b/templates/repo/settings/webhook/workwechat.tmpl @@ -0,0 +1,15 @@ +{{if eq .HookType "workwechat"}} +

{{.i18n.Tr "repo.settings.add_workwechat_hook_desc" "https://work.weixin.qq.com" | Str2html}}

+
+ {{.CsrfTokenHtml}} +
+ + +
+
+ + +
+ {{template "repo/settings/webhook/settings" .}} +
+{{end}}