From 3963625b6ef6f4d4f16959466c077593a1f908db Mon Sep 17 00:00:00 2001 From: Aaron F Date: Sun, 4 Sep 2022 21:54:23 +0200 Subject: [PATCH] Webhook for Wiki changes (#20219) Add support for triggering webhook notifications on wiki changes. This PR contains frontend and backend for webhook notifications on wiki actions (create a new page, rename a page, edit a page and delete a page). The frontend got a new checkbox under the Custom Event -> Repository Events section. There is only one checkbox for create/edit/rename/delete actions, because it makes no sense to separate it and others like releases or packages follow the same schema. ![image](https://user-images.githubusercontent.com/121972/177018803-26851196-831f-4fde-9a4c-9e639b0e0d6b.png) The actions itself are separated, so that different notifications will be executed (with the "action" field). All the webhook receivers implement the new interface method (Wiki) and the corresponding tests. When implementing this, I encounter a little bug on editing a wiki page. Creating and editing a wiki page is technically the same action and will be handled by the ```updateWikiPage``` function. But the function need to know if it is a new wiki page or just a change. This distinction is done by the ```action``` parameter, but this will not be sent by the frontend (on form submit). This PR will fix this by adding the ```action``` parameter with the values ```_new``` or ```_edit```, which will be used by the ```updateWikiPage``` function. I've done integration tests with matrix and gitea (http). ![image](https://user-images.githubusercontent.com/121972/177018795-eb5cdc01-9ba3-483e-a6b7-ed0e313a71fb.png) Fix #16457 Signed-off-by: Aaron Fischer --- models/webhook/hooktask.go | 3 + models/webhook/webhook.go | 8 ++ models/webhook/webhook_test.go | 2 +- modules/notification/base/notifier.go | 3 + modules/notification/base/null.go | 12 +++ modules/notification/notification.go | 21 ++++++ modules/notification/webhook/webhook.go | 38 ++++++++++ modules/structs/hook.go | 33 +++++++++ options/locale/locale_en-US.ini | 2 + routers/api/v1/repo/wiki.go | 5 ++ routers/api/v1/utils/hook.go | 2 + routers/web/repo/webhook.go | 1 + routers/web/repo/wiki.go | 7 ++ services/forms/repo_form.go | 13 ++-- services/webhook/dingtalk.go | 8 ++ services/webhook/dingtalk_test.go | 38 ++++++++++ services/webhook/discord.go | 14 ++++ services/webhook/discord_test.go | 47 ++++++++++++ services/webhook/feishu.go | 7 ++ services/webhook/feishu_test.go | 29 ++++++++ services/webhook/general.go | 29 ++++++++ services/webhook/general_test.go | 54 ++++++++++++++ services/webhook/matrix.go | 7 ++ services/webhook/matrix_test.go | 32 ++++++++ services/webhook/msteams.go | 16 ++++ services/webhook/msteams_test.go | 74 +++++++++++++++++++ services/webhook/packagist.go | 5 ++ services/webhook/packagist_test.go | 20 +++++ services/webhook/payloader.go | 3 + services/webhook/slack.go | 7 ++ services/webhook/slack_test.go | 29 ++++++++ services/webhook/telegram.go | 7 ++ services/webhook/telegram_test.go | 29 ++++++++ services/webhook/wechatwork.go | 7 ++ services/wiki/wiki.go | 2 +- templates/repo/settings/webhook/settings.tmpl | 11 +++ templates/repo/wiki/new.tmpl | 2 +- 37 files changed, 618 insertions(+), 9 deletions(-) diff --git a/models/webhook/hooktask.go b/models/webhook/hooktask.go index 4415518cf00..2adfcaa60dd 100644 --- a/models/webhook/hooktask.go +++ b/models/webhook/hooktask.go @@ -47,6 +47,7 @@ const ( HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected" HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment" HookEventPullRequestSync HookEventType = "pull_request_sync" + HookEventWiki HookEventType = "wiki" HookEventRepository HookEventType = "repository" HookEventRelease HookEventType = "release" HookEventPackage HookEventType = "package" @@ -76,6 +77,8 @@ func (h HookEventType) Event() string { return "pull_request_rejected" case HookEventPullRequestReviewComment: return "pull_request_comment" + case HookEventWiki: + return "wiki" case HookEventRepository: return "repository" case HookEventRelease: diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 478a6a29ff2..ac092206309 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -132,6 +132,7 @@ type HookEvents struct { PullRequestComment bool `json:"pull_request_comment"` PullRequestReview bool `json:"pull_request_review"` PullRequestSync bool `json:"pull_request_sync"` + Wiki bool `json:"wiki"` Repository bool `json:"repository"` Release bool `json:"release"` Package bool `json:"package"` @@ -328,6 +329,12 @@ func (w *Webhook) HasPullRequestSyncEvent() bool { (w.ChooseEvents && w.HookEvents.PullRequestSync) } +// HasWikiEvent returns true if hook enabled wiki event. +func (w *Webhook) HasWikiEvent() bool { + return w.SendEverything || + (w.ChooseEvents && w.HookEvent.Wiki) +} + // HasReleaseEvent returns if hook enabled release event. func (w *Webhook) HasReleaseEvent() bool { return w.SendEverything || @@ -373,6 +380,7 @@ func (w *Webhook) EventCheckers() []struct { {w.HasPullRequestRejectedEvent, HookEventPullRequestReviewRejected}, {w.HasPullRequestCommentEvent, HookEventPullRequestReviewComment}, {w.HasPullRequestSyncEvent, HookEventPullRequestSync}, + {w.HasWikiEvent, HookEventWiki}, {w.HasRepositoryEvent, HookEventRepository}, {w.HasReleaseEvent, HookEventRelease}, {w.HasPackageEvent, HookEventPackage}, diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index 1d77ee2a41a..7ec7edc0b77 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -71,7 +71,7 @@ func TestWebhook_EventsArray(t *testing.T) { "issues", "issue_assign", "issue_label", "issue_milestone", "issue_comment", "pull_request", "pull_request_assign", "pull_request_label", "pull_request_milestone", "pull_request_comment", "pull_request_review_approved", "pull_request_review_rejected", - "pull_request_review_comment", "pull_request_sync", "repository", "release", + "pull_request_review_comment", "pull_request_sync", "wiki", "repository", "release", "package", }, (&Webhook{ diff --git a/modules/notification/base/notifier.go b/modules/notification/base/notifier.go index 541731ddbf1..d6cec92e19b 100644 --- a/modules/notification/base/notifier.go +++ b/modules/notification/base/notifier.go @@ -45,6 +45,9 @@ type Notifier interface { issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User) NotifyUpdateComment(*user_model.User, *issues_model.Comment, string) NotifyDeleteComment(*user_model.User, *issues_model.Comment) + NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) + NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) + NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) NotifyNewRelease(rel *repo_model.Release) NotifyUpdateRelease(doer *user_model.User, rel *repo_model.Release) NotifyDeleteRelease(doer *user_model.User, rel *repo_model.Release) diff --git a/modules/notification/base/null.go b/modules/notification/base/null.go index 4f382b3d01b..b113ae79e1e 100644 --- a/modules/notification/base/null.go +++ b/modules/notification/base/null.go @@ -78,6 +78,18 @@ func (*NullNotifier) NotifyUpdateComment(doer *user_model.User, c *issues_model. func (*NullNotifier) NotifyDeleteComment(doer *user_model.User, c *issues_model.Comment) { } +// NotifyNewWikiPage places a place holder function +func (*NullNotifier) NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +} + +// NotifyEditWikiPage places a place holder function +func (*NullNotifier) NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { +} + +// NotifyDeleteWikiPage places a place holder function +func (*NullNotifier) NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) { +} + // NotifyNewRelease places a place holder function func (*NullNotifier) NotifyNewRelease(rel *repo_model.Release) { } diff --git a/modules/notification/notification.go b/modules/notification/notification.go index 713cc72aacd..693c7f5c22f 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -40,6 +40,27 @@ func NewContext() { RegisterNotifier(mirror.NewNotifier()) } +// NotifyNewWikiPage notifies creating new wiki pages to notifiers +func NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { + for _, notifier := range notifiers { + notifier.NotifyNewWikiPage(doer, repo, page, comment) + } +} + +// NotifyEditWikiPage notifies editing or renaming wiki pages to notifiers +func NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { + for _, notifier := range notifiers { + notifier.NotifyEditWikiPage(doer, repo, page, comment) + } +} + +// NotifyDeleteWikiPage notifies deleting wiki pages to notifiers +func NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) { + for _, notifier := range notifiers { + notifier.NotifyDeleteWikiPage(doer, repo, page) + } +} + // NotifyCreateIssueComment notifies issue comment related message to notifiers func NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index ed3b53e3e79..0eb2099a206 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -501,6 +501,44 @@ func (m *webhookNotifier) NotifyDeleteComment(doer *user_model.User, comment *is } } +func (m *webhookNotifier) NotifyNewWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { + // Add to hook queue for created wiki page. + if err := webhook_services.PrepareWebhooks(repo, webhook.HookEventWiki, &api.WikiPayload{ + Action: api.HookWikiCreated, + Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Sender: convert.ToUser(doer, nil), + Page: page, + Comment: comment, + }); err != nil { + log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) + } +} + +func (m *webhookNotifier) NotifyEditWikiPage(doer *user_model.User, repo *repo_model.Repository, page, comment string) { + // Add to hook queue for edit wiki page. + if err := webhook_services.PrepareWebhooks(repo, webhook.HookEventWiki, &api.WikiPayload{ + Action: api.HookWikiEdited, + Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Sender: convert.ToUser(doer, nil), + Page: page, + Comment: comment, + }); err != nil { + log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) + } +} + +func (m *webhookNotifier) NotifyDeleteWikiPage(doer *user_model.User, repo *repo_model.Repository, page string) { + // Add to hook queue for edit wiki page. + if err := webhook_services.PrepareWebhooks(repo, webhook.HookEventWiki, &api.WikiPayload{ + Action: api.HookWikiDeleted, + Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Sender: convert.ToUser(doer, nil), + Page: page, + }); err != nil { + log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err) + } +} + func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue *issues_model.Issue, addedLabels, removedLabels []*issues_model.Label, ) { diff --git a/modules/structs/hook.go b/modules/structs/hook.go index 07d51915dea..132b24b8563 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -397,6 +397,39 @@ type ReviewPayload struct { Content string `json:"content"` } +// __ __.__ __ .__ +// / \ / \__| | _|__| +// \ \/\/ / | |/ / | +// \ /| | <| | +// \__/\ / |__|__|_ \__| +// \/ \/ + +// HookWikiAction an action that happens to a wiki page +type HookWikiAction string + +const ( + // HookWikiCreated created + HookWikiCreated HookWikiAction = "created" + // HookWikiEdited edited + HookWikiEdited HookWikiAction = "edited" + // HookWikiDeleted deleted + HookWikiDeleted HookWikiAction = "deleted" +) + +// WikiPayload payload for repository webhooks +type WikiPayload struct { + Action HookWikiAction `json:"action"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` + Page string `json:"page"` + Comment string `json:"comment"` +} + +// JSONPayload JSON representation of the payload +func (p *WikiPayload) JSONPayload() ([]byte, error) { + return json.MarshalIndent(p, "", " ") +} + //__________ .__ __ //\______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index ba647771e30..6845680ccfb 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1956,6 +1956,8 @@ settings.event_delete = Delete settings.event_delete_desc = Branch or tag deleted. settings.event_fork = Fork settings.event_fork_desc = Repository forked. +settings.event_wiki = Wiki +settings.event_wiki_desc = Wiki page created, renamed, edited or deleted. settings.event_release = Release settings.event_release_desc = Release published, updated or deleted in a repository. settings.event_push = Push diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 82542d1ab85..6d956485427 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -85,6 +86,7 @@ func NewWikiPage(ctx *context.APIContext) { wikiPage := getWikiPage(ctx, wikiName) if !ctx.Written() { + notification.NotifyNewWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName, form.Message) ctx.JSON(http.StatusCreated, wikiPage) } } @@ -152,6 +154,7 @@ func EditWikiPage(ctx *context.APIContext) { wikiPage := getWikiPage(ctx, newWikiName) if !ctx.Written() { + notification.NotifyEditWikiPage(ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message) ctx.JSON(http.StatusOK, wikiPage) } } @@ -242,6 +245,8 @@ func DeleteWikiPage(ctx *context.APIContext) { return } + notification.NotifyDeleteWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName) + ctx.Status(http.StatusNoContent) } diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index ba008f587c6..7e4dfca9adf 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -126,6 +126,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID PullRequestComment: pullHook(form.Events, string(webhook.HookEventPullRequestComment)), PullRequestReview: pullHook(form.Events, "pull_request_review"), PullRequestSync: pullHook(form.Events, string(webhook.HookEventPullRequestSync)), + Wiki: util.IsStringInSlice(string(webhook.HookEventWiki), form.Events, true), Repository: util.IsStringInSlice(string(webhook.HookEventRepository), form.Events, true), Release: util.IsStringInSlice(string(webhook.HookEventRelease), form.Events, true), }, @@ -249,6 +250,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh w.Delete = util.IsStringInSlice(string(webhook.HookEventDelete), form.Events, true) w.Fork = util.IsStringInSlice(string(webhook.HookEventFork), form.Events, true) w.Repository = util.IsStringInSlice(string(webhook.HookEventRepository), form.Events, true) + w.Wiki = util.IsStringInSlice(string(webhook.HookEventWiki), form.Events, true) w.Release = util.IsStringInSlice(string(webhook.HookEventRelease), form.Events, true) w.BranchFilter = form.BranchFilter diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index 7e659de0da7..a8939e72bd6 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -178,6 +178,7 @@ func ParseHookEvent(form forms.WebhookForm) *webhook.HookEvent { PullRequestComment: form.PullRequestComment, PullRequestReview: form.PullRequestReview, PullRequestSync: form.PullRequestSync, + Wiki: form.Wiki, Repository: form.Repository, Package: form.Package, }, diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 0c161568bd0..0f349547cdd 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -25,6 +25,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" + "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -705,6 +706,8 @@ func NewWikiPost(ctx *context.Context) { return } + notification.NotifyNewWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName, form.Message) + ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.NameToSubURL(wikiName)) } @@ -747,6 +750,8 @@ func EditWikiPost(ctx *context.Context) { return } + notification.NotifyEditWikiPage(ctx.Doer, ctx.Repo.Repository, newWikiName, form.Message) + ctx.Redirect(ctx.Repo.RepoLink + "/wiki/" + wiki_service.NameToSubURL(newWikiName)) } @@ -762,6 +767,8 @@ func DeleteWikiPagePost(ctx *context.Context) { return } + notification.NotifyDeleteWikiPage(ctx.Doer, ctx.Repo.Repository, wikiName) + ctx.JSON(http.StatusOK, map[string]interface{}{ "redirect": ctx.Repo.RepoLink + "/wiki/", }) diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 7a4a2123ebd..4eb20d297f2 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -215,12 +215,12 @@ func (f *ProtectBranchForm) Validate(req *http.Request, errs binding.Errors) bin return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// __ __ ___. .__ .__ __ -// / \ / \ ____\_ |__ | |__ | |__ ____ | | __ -// \ \/\/ // __ \| __ \| | \| | \ / _ \| |/ / -// \ /\ ___/| \_\ \ Y \ Y ( <_> ) < -// \__/\ / \___ >___ /___| /___| /\____/|__|_ \ -// \/ \/ \/ \/ \/ \/ +// __ __ ___. .__ __ +// / \ / \ ____\_ |__ | |__ ____ ____ | | __ +// \ \/\/ // __ \| __ \| | \ / _ \ / _ \| |/ / +// \ /\ ___/| \_\ \ Y ( <_> | <_> ) < +// \__/\ / \___ >___ /___| /\____/ \____/|__|_ \ +// \/ \/ \/ \/ \/ // WebhookForm form for changing web hook type WebhookForm struct { @@ -242,6 +242,7 @@ type WebhookForm struct { PullRequestComment bool PullRequestReview bool PullRequestSync bool + Wiki bool Repository bool Package bool Active bool diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index 06b73c38d64..5112bdb347f 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -107,6 +107,14 @@ func (d *DingtalkPayload) Issue(p *api.IssuePayload) (api.Payloader, error) { return createDingtalkPayload(issueTitle, text+"\r\n\r\n"+attachmentText, "view issue", p.Issue.HTMLURL), nil } +// Wiki implements PayloadConvertor Wiki method +func (d *DingtalkPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, _, _ := getWikiPayloadInfo(p, noneLinkFormatter, true) + url := p.Repository.HTMLURL + "/wiki/" + url.PathEscape(p.Page) + + return createDingtalkPayload(text, text, "view wiki", url), nil +} + // IssueComment implements PayloadConvertor IssueComment method func (d *DingtalkPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) { text, issueTitle, _ := getIssueCommentPayloadInfo(p, noneLinkFormatter, true) diff --git a/services/webhook/dingtalk_test.go b/services/webhook/dingtalk_test.go index b66b5e43a82..efc9601c127 100644 --- a/services/webhook/dingtalk_test.go +++ b/services/webhook/dingtalk_test.go @@ -189,6 +189,44 @@ func TestDingTalkPayload(t *testing.T) { assert.Equal(t, "http://localhost:3000/test/repo", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(DingtalkPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DingtalkPayload{}, pl) + + assert.Equal(t, "[test/repo] New wiki page 'index' (Wiki change comment) by user1", pl.(*DingtalkPayload).ActionCard.Text) + assert.Equal(t, "[test/repo] New wiki page 'index' (Wiki change comment) by user1", pl.(*DingtalkPayload).ActionCard.Title) + assert.Equal(t, "view wiki", pl.(*DingtalkPayload).ActionCard.SingleTitle) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DingtalkPayload{}, pl) + + assert.Equal(t, "[test/repo] Wiki page 'index' edited (Wiki change comment) by user1", pl.(*DingtalkPayload).ActionCard.Text) + assert.Equal(t, "[test/repo] Wiki page 'index' edited (Wiki change comment) by user1", pl.(*DingtalkPayload).ActionCard.Title) + assert.Equal(t, "view wiki", pl.(*DingtalkPayload).ActionCard.SingleTitle) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DingtalkPayload{}, pl) + + assert.Equal(t, "[test/repo] Wiki page 'index' deleted by user1", pl.(*DingtalkPayload).ActionCard.Text) + assert.Equal(t, "[test/repo] Wiki page 'index' deleted by user1", pl.(*DingtalkPayload).ActionCard.Title) + assert.Equal(t, "view wiki", pl.(*DingtalkPayload).ActionCard.SingleTitle) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/discord.go b/services/webhook/discord.go index ae5460b9a7a..7b6f0f0b1db 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -7,6 +7,7 @@ package webhook import ( "errors" "fmt" + "net/url" "strconv" "strings" @@ -235,6 +236,19 @@ func (d *DiscordPayload) Repository(p *api.RepositoryPayload) (api.Payloader, er return d.createPayload(p.Sender, title, "", url, color), nil } +// Wiki implements PayloadConvertor Wiki method +func (d *DiscordPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, color, _ := getWikiPayloadInfo(p, noneLinkFormatter, false) + htmlLink := p.Repository.HTMLURL + "/wiki/" + url.PathEscape(p.Page) + + var description string + if p.Action != api.HookWikiDeleted { + description = p.Comment + } + + return d.createPayload(p.Sender, text, description, htmlLink, color), nil +} + // Release implements PayloadConvertor Release method func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, color := getReleasePayloadInfo(p, noneLinkFormatter, false) diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index 8fe20c01024..8e4e60a7ff0 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -212,6 +212,53 @@ func TestDiscordPayload(t *testing.T) { assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(DiscordPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DiscordPayload{}, pl) + + assert.Len(t, pl.(*DiscordPayload).Embeds, 1) + assert.Equal(t, "[test/repo] New wiki page 'index' (Wiki change comment)", pl.(*DiscordPayload).Embeds[0].Title) + assert.Equal(t, "Wiki change comment", pl.(*DiscordPayload).Embeds[0].Description) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.(*DiscordPayload).Embeds[0].URL) + assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name) + assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL) + assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DiscordPayload{}, pl) + + assert.Len(t, pl.(*DiscordPayload).Embeds, 1) + assert.Equal(t, "[test/repo] Wiki page 'index' edited (Wiki change comment)", pl.(*DiscordPayload).Embeds[0].Title) + assert.Equal(t, "Wiki change comment", pl.(*DiscordPayload).Embeds[0].Description) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.(*DiscordPayload).Embeds[0].URL) + assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name) + assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL) + assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &DiscordPayload{}, pl) + + assert.Len(t, pl.(*DiscordPayload).Embeds, 1) + assert.Equal(t, "[test/repo] Wiki page 'index' deleted", pl.(*DiscordPayload).Embeds[0].Title) + assert.Empty(t, pl.(*DiscordPayload).Embeds[0].Description) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.(*DiscordPayload).Embeds[0].URL) + assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name) + assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL) + assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/feishu.go b/services/webhook/feishu.go index 5b20c7dda7e..782684d0ffb 100644 --- a/services/webhook/feishu.go +++ b/services/webhook/feishu.go @@ -145,6 +145,13 @@ func (f *FeishuPayload) Repository(p *api.RepositoryPayload) (api.Payloader, err return nil, nil } +// Wiki implements PayloadConvertor Wiki method +func (f *FeishuPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, _, _ := getWikiPayloadInfo(p, noneLinkFormatter, true) + + return newFeishuTextPayload(text), nil +} + // Release implements PayloadConvertor Release method func (f *FeishuPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true) diff --git a/services/webhook/feishu_test.go b/services/webhook/feishu_test.go index d862b015e79..85cfb759fe1 100644 --- a/services/webhook/feishu_test.go +++ b/services/webhook/feishu_test.go @@ -145,6 +145,35 @@ func TestFeishuPayload(t *testing.T) { assert.Equal(t, "[test/repo] Repository created", pl.(*FeishuPayload).Content.Text) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(FeishuPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &FeishuPayload{}, pl) + + assert.Equal(t, "[test/repo] New wiki page 'index' (Wiki change comment) by user1", pl.(*FeishuPayload).Content.Text) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &FeishuPayload{}, pl) + + assert.Equal(t, "[test/repo] Wiki page 'index' edited (Wiki change comment) by user1", pl.(*FeishuPayload).Content.Text) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &FeishuPayload{}, pl) + + assert.Equal(t, "[test/repo] Wiki page 'index' deleted by user1", pl.(*FeishuPayload).Content.Text) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/general.go b/services/webhook/general.go index e8006fabaee..5be177d339d 100644 --- a/services/webhook/general.go +++ b/services/webhook/general.go @@ -161,6 +161,35 @@ func getReleasePayloadInfo(p *api.ReleasePayload, linkFormatter linkFormatter, w return text, color } +func getWikiPayloadInfo(p *api.WikiPayload, linkFormatter linkFormatter, withSender bool) (string, int, string) { + repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) + pageLink := linkFormatter(p.Repository.HTMLURL+"/wiki/"+url.PathEscape(p.Page), p.Page) + + var text string + color := greenColor + + switch p.Action { + case api.HookWikiCreated: + text = fmt.Sprintf("[%s] New wiki page '%s'", repoLink, pageLink) + case api.HookWikiEdited: + text = fmt.Sprintf("[%s] Wiki page '%s' edited", repoLink, pageLink) + color = yellowColor + case api.HookWikiDeleted: + text = fmt.Sprintf("[%s] Wiki page '%s' deleted", repoLink, pageLink) + color = redColor + } + + if p.Action != api.HookWikiDeleted && p.Comment != "" { + text += fmt.Sprintf(" (%s)", p.Comment) + } + + if withSender { + text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName)) + } + + return text, color, pageLink +} + func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFormatter, withSender bool) (string, string, int) { repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) issueTitle := fmt.Sprintf("#%d %s", p.Issue.Index, p.Issue.Title) diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go index 4d73afe060a..4acf51ac71d 100644 --- a/services/webhook/general_test.go +++ b/services/webhook/general_test.go @@ -195,6 +195,22 @@ func pullRequestCommentTestPayload() *api.IssueCommentPayload { } } +func wikiTestPayload() *api.WikiPayload { + return &api.WikiPayload{ + Repository: &api.Repository{ + HTMLURL: "http://localhost:3000/test/repo", + Name: "repo", + FullName: "test/repo", + }, + Sender: &api.User{ + UserName: "user1", + AvatarURL: "http://localhost:3000/user1/avatar", + }, + Page: "index", + Comment: "Wiki change comment", + } +} + func pullReleaseTestPayload() *api.ReleasePayload { return &api.ReleasePayload{ Action: api.HookReleasePublished, @@ -469,6 +485,44 @@ func TestGetPullRequestPayloadInfo(t *testing.T) { } } +func TestGetWikiPayloadInfo(t *testing.T) { + p := wikiTestPayload() + + cases := []struct { + action api.HookWikiAction + text string + color int + link string + }{ + { + api.HookWikiCreated, + "[test/repo] New wiki page 'index' (Wiki change comment) by user1", + greenColor, + "index", + }, + { + api.HookWikiEdited, + "[test/repo] Wiki page 'index' edited (Wiki change comment) by user1", + yellowColor, + "index", + }, + { + api.HookWikiDeleted, + "[test/repo] Wiki page 'index' deleted by user1", + redColor, + "index", + }, + } + + for i, c := range cases { + p.Action = c.action + text, color, link := getWikiPayloadInfo(p, noneLinkFormatter, true) + assert.Equal(t, c.text, text, "case %d", i) + assert.Equal(t, c.color, color, "case %d", i) + assert.Equal(t, c.link, link, "case %d", i) + } +} + func TestGetReleasePayloadInfo(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index a42ab2a93e0..f4c4cf0e9a0 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -143,6 +143,13 @@ func (m *MatrixPayloadUnsafe) IssueComment(p *api.IssueCommentPayload) (api.Payl return getMatrixPayloadUnsafe(text, nil, m.AccessToken, m.MsgType), nil } +// Wiki implements PayloadConvertor Wiki method +func (m *MatrixPayloadUnsafe) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, _, _ := getWikiPayloadInfo(p, MatrixLinkFormatter, true) + + return getMatrixPayloadUnsafe(text, nil, m.AccessToken, m.MsgType), nil +} + // Release implements PayloadConvertor Release method func (m *MatrixPayloadUnsafe) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, MatrixLinkFormatter, true) diff --git a/services/webhook/matrix_test.go b/services/webhook/matrix_test.go index 34196aedf04..4cab845330c 100644 --- a/services/webhook/matrix_test.go +++ b/services/webhook/matrix_test.go @@ -156,6 +156,38 @@ func TestMatrixPayload(t *testing.T) { assert.Equal(t, `[test/repo] Repository created by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(MatrixPayloadUnsafe) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MatrixPayloadUnsafe{}, pl) + + assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] New wiki page '[index](http://localhost:3000/test/repo/wiki/index)' (Wiki change comment) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body) + assert.Equal(t, `[test/repo] New wiki page 'index' (Wiki change comment) by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MatrixPayloadUnsafe{}, pl) + + assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Wiki page '[index](http://localhost:3000/test/repo/wiki/index)' edited (Wiki change comment) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body) + assert.Equal(t, `[test/repo] Wiki page 'index' edited (Wiki change comment) by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MatrixPayloadUnsafe{}, pl) + + assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Wiki page '[index](http://localhost:3000/test/repo/wiki/index)' deleted by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body) + assert.Equal(t, `[test/repo] Wiki page 'index' deleted by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 59e2e934939..1406004781b 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -6,6 +6,7 @@ package webhook import ( "fmt" + "net/url" "strings" webhook_model "code.gitea.io/gitea/models/webhook" @@ -266,6 +267,21 @@ func (m *MSTeamsPayload) Repository(p *api.RepositoryPayload) (api.Payloader, er ), nil } +// Wiki implements PayloadConvertor Wiki method +func (m *MSTeamsPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + title, color, _ := getWikiPayloadInfo(p, noneLinkFormatter, false) + + return createMSTeamsPayload( + p.Repository, + p.Sender, + title, + "", + p.Repository.HTMLURL+"/wiki/"+url.PathEscape(p.Page), + color, + &MSTeamsFact{"Repository:", p.Repository.FullName}, + ), nil +} + // Release implements PayloadConvertor Release method func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { title, color := getReleasePayloadInfo(p, noneLinkFormatter, false) diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go index 3fdf47c1ae8..8292beed7f8 100644 --- a/services/webhook/msteams_test.go +++ b/services/webhook/msteams_test.go @@ -330,6 +330,80 @@ func TestMSTeamsPayload(t *testing.T) { assert.Equal(t, "http://localhost:3000/test/repo", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(MSTeamsPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MSTeamsPayload{}, pl) + + assert.Equal(t, "[test/repo] New wiki page 'index' (Wiki change comment)", pl.(*MSTeamsPayload).Title) + assert.Equal(t, "[test/repo] New wiki page 'index' (Wiki change comment)", pl.(*MSTeamsPayload).Summary) + assert.Len(t, pl.(*MSTeamsPayload).Sections, 1) + assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle) + assert.Equal(t, "", pl.(*MSTeamsPayload).Sections[0].Text) + assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2) + for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts { + if fact.Name == "Repository:" { + assert.Equal(t, p.Repository.FullName, fact.Value) + } else { + t.Fail() + } + } + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1) + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MSTeamsPayload{}, pl) + + assert.Equal(t, "[test/repo] Wiki page 'index' edited (Wiki change comment)", pl.(*MSTeamsPayload).Title) + assert.Equal(t, "[test/repo] Wiki page 'index' edited (Wiki change comment)", pl.(*MSTeamsPayload).Summary) + assert.Len(t, pl.(*MSTeamsPayload).Sections, 1) + assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle) + assert.Equal(t, "", pl.(*MSTeamsPayload).Sections[0].Text) + assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2) + for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts { + if fact.Name == "Repository:" { + assert.Equal(t, p.Repository.FullName, fact.Value) + } else { + t.Fail() + } + } + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1) + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &MSTeamsPayload{}, pl) + + assert.Equal(t, "[test/repo] Wiki page 'index' deleted", pl.(*MSTeamsPayload).Title) + assert.Equal(t, "[test/repo] Wiki page 'index' deleted", pl.(*MSTeamsPayload).Summary) + assert.Len(t, pl.(*MSTeamsPayload).Sections, 1) + assert.Equal(t, "user1", pl.(*MSTeamsPayload).Sections[0].ActivitySubtitle) + assert.Empty(t, pl.(*MSTeamsPayload).Sections[0].Text) + assert.Len(t, pl.(*MSTeamsPayload).Sections[0].Facts, 2) + for _, fact := range pl.(*MSTeamsPayload).Sections[0].Facts { + if fact.Name == "Repository:" { + assert.Equal(t, p.Repository.FullName, fact.Value) + } else { + t.Fail() + } + } + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1) + assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1) + assert.Equal(t, "http://localhost:3000/test/repo/wiki/index", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/packagist.go b/services/webhook/packagist.go index ace93b13ff0..5badc7462ac 100644 --- a/services/webhook/packagist.go +++ b/services/webhook/packagist.go @@ -94,6 +94,11 @@ func (f *PackagistPayload) Repository(p *api.RepositoryPayload) (api.Payloader, return nil, nil } +// Wiki implements PayloadConvertor Wiki method +func (f *PackagistPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + return nil, nil +} + // Release implements PayloadConvertor Release method func (f *PackagistPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { return nil, nil diff --git a/services/webhook/packagist_test.go b/services/webhook/packagist_test.go index 08912924d26..4a24b76523c 100644 --- a/services/webhook/packagist_test.go +++ b/services/webhook/packagist_test.go @@ -116,6 +116,26 @@ func TestPackagistPayload(t *testing.T) { require.Nil(t, pl) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(PackagistPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.Nil(t, pl) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.Nil(t, pl) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.Nil(t, pl) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/payloader.go b/services/webhook/payloader.go index 0e09dd1b1e0..a9d01c98915 100644 --- a/services/webhook/payloader.go +++ b/services/webhook/payloader.go @@ -22,6 +22,7 @@ type PayloadConvertor interface { Review(*api.PullRequestPayload, webhook_model.HookEventType) (api.Payloader, error) Repository(*api.RepositoryPayload) (api.Payloader, error) Release(*api.ReleasePayload) (api.Payloader, error) + Wiki(*api.WikiPayload) (api.Payloader, error) } func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_model.HookEventType) (api.Payloader, error) { @@ -51,6 +52,8 @@ func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_model.H return s.Repository(p.(*api.RepositoryPayload)) case webhook_model.HookEventRelease: return s.Release(p.(*api.ReleasePayload)) + case webhook_model.HookEventWiki: + return s.Wiki(p.(*api.WikiPayload)) } return s, nil } diff --git a/services/webhook/slack.go b/services/webhook/slack.go index e3d0d406de3..63cc6f8ca24 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -157,6 +157,13 @@ func (s *SlackPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, }}), nil } +// Wiki implements PayloadConvertor Wiki method +func (s *SlackPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, _, _ := getWikiPayloadInfo(p, SlackLinkFormatter, true) + + return s.createPayload(text, nil), nil +} + // Release implements PayloadConvertor Release method func (s *SlackPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, SlackLinkFormatter, true) diff --git a/services/webhook/slack_test.go b/services/webhook/slack_test.go index 0f08785d25e..3af38b5158c 100644 --- a/services/webhook/slack_test.go +++ b/services/webhook/slack_test.go @@ -145,6 +145,35 @@ func TestSlackPayload(t *testing.T) { assert.Equal(t, "[] Repository created by ", pl.(*SlackPayload).Text) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(SlackPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &SlackPayload{}, pl) + + assert.Equal(t, "[] New wiki page '' (Wiki change comment) by ", pl.(*SlackPayload).Text) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &SlackPayload{}, pl) + + assert.Equal(t, "[] Wiki page '' edited (Wiki change comment) by ", pl.(*SlackPayload).Text) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &SlackPayload{}, pl) + + assert.Equal(t, "[] Wiki page '' deleted by ", pl.(*SlackPayload).Text) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go index 64211493ec6..13471d864e5 100644 --- a/services/webhook/telegram.go +++ b/services/webhook/telegram.go @@ -171,6 +171,13 @@ func (t *TelegramPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e return nil, nil } +// Wiki implements PayloadConvertor Wiki method +func (t *TelegramPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, _, _ := getWikiPayloadInfo(p, htmlLinkFormatter, true) + + return createTelegramPayload(text), nil +} + // Release implements PayloadConvertor Release method func (t *TelegramPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, htmlLinkFormatter, true) diff --git a/services/webhook/telegram_test.go b/services/webhook/telegram_test.go index 2f83090166f..5ca78d05081 100644 --- a/services/webhook/telegram_test.go +++ b/services/webhook/telegram_test.go @@ -145,6 +145,35 @@ func TestTelegramPayload(t *testing.T) { assert.Equal(t, `[test/repo] Repository created`, pl.(*TelegramPayload).Message) }) + t.Run("Wiki", func(t *testing.T) { + p := wikiTestPayload() + + d := new(TelegramPayload) + p.Action = api.HookWikiCreated + pl, err := d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &TelegramPayload{}, pl) + + assert.Equal(t, `[test/repo] New wiki page 'index' (Wiki change comment) by user1`, pl.(*TelegramPayload).Message) + + p.Action = api.HookWikiEdited + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &TelegramPayload{}, pl) + + assert.Equal(t, `[test/repo] Wiki page 'index' edited (Wiki change comment) by user1`, pl.(*TelegramPayload).Message) + + p.Action = api.HookWikiDeleted + pl, err = d.Wiki(p) + require.NoError(t, err) + require.NotNil(t, pl) + require.IsType(t, &TelegramPayload{}, pl) + + assert.Equal(t, `[test/repo] Wiki page 'index' deleted by user1`, pl.(*TelegramPayload).Message) + }) + t.Run("Release", func(t *testing.T) { p := pullReleaseTestPayload() diff --git a/services/webhook/wechatwork.go b/services/webhook/wechatwork.go index de8b7770665..bd4c3e08512 100644 --- a/services/webhook/wechatwork.go +++ b/services/webhook/wechatwork.go @@ -166,6 +166,13 @@ func (f *WechatworkPayload) Repository(p *api.RepositoryPayload) (api.Payloader, return nil, nil } +// Wiki implements PayloadConvertor Wiki method +func (f *WechatworkPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { + text, _, _ := getWikiPayloadInfo(p, noneLinkFormatter, true) + + return newWechatworkMarkdownPayload(text), nil +} + // Release implements PayloadConvertor Release method func (f *WechatworkPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true) diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index ac5283bbebc..b341b048cc6 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -118,7 +118,7 @@ func prepareWikiFileName(gitRepo *git.Repository, wikiName string) (bool, string return foundEscaped, escaped, nil } -// updateWikiPage adds a new page to the repository wiki. +// updateWikiPage adds a new page or edits an existing page in repository wiki. func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldWikiName, newWikiName, content, message string, isNew bool) (err error) { if err = nameAllowed(newWikiName); err != nil { return err diff --git a/templates/repo/settings/webhook/settings.tmpl b/templates/repo/settings/webhook/settings.tmpl index 98a916dc12b..57cf8a2f305 100644 --- a/templates/repo/settings/webhook/settings.tmpl +++ b/templates/repo/settings/webhook/settings.tmpl @@ -98,6 +98,17 @@ + +
+
+
+ + + {{.i18n.Tr "repo.settings.event_wiki_desc"}} +
+
+
+
diff --git a/templates/repo/wiki/new.tmpl b/templates/repo/wiki/new.tmpl index d3085a1068d..26c19c0a43f 100644 --- a/templates/repo/wiki/new.tmpl +++ b/templates/repo/wiki/new.tmpl @@ -11,7 +11,7 @@
{{end}} -
+ {{.CsrfTokenHtml}}