webhook: add native Discord support

master
Unknwon 2017-02-18 00:54:56 -05:00
parent 266586e866
commit a07b1f630a
No known key found for this signature in database
GPG Key ID: 25B575AE3213B2B3
20 changed files with 428 additions and 60 deletions

View File

@ -407,9 +407,11 @@ func runWeb(ctx *cli.Context) error {
m.Get("/:type/new", repo.WebhooksNew)
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Get("/:id", repo.WebHooksEdit)
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
})
m.Route("/delete", "GET,POST", org.SettingsDelete)
@ -457,10 +459,12 @@ func runWeb(ctx *cli.Context) error {
m.Get("/:type/new", repo.WebhooksNew)
m.Post("/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Get("/:id", repo.WebHooksEdit)
m.Post("/:id/test", repo.TestWebhook)
m.Post("/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
m.Post("/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/:id", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Group("/git", func() {
m.Get("", repo.SettingsGitHooks)

View File

@ -761,6 +761,7 @@ settings.delete_webhook = Delete Webhook
settings.recent_deliveries = Recent Deliveries
settings.hook_type = Hook Type
settings.add_slack_hook_desc = Add <a href="%s">Slack</a> integration to your repository.
settings.add_discord_hook_desc = Add <a href="%s">Discord</a> integration to your repository.
settings.slack_token = Token
settings.slack_domain = Domain
settings.slack_channel = Channel

View File

@ -16,7 +16,7 @@ import (
"github.com/gogits/gogs/modules/setting"
)
const APP_VER = "0.9.156.0217"
const APP_VER = "0.9.157.0218"
func init() {
setting.AppVer = APP_VER

View File

@ -505,26 +505,30 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
apiRepo := repo.APIFormat(nil)
switch opType {
case ACTION_COMMIT_REPO: // Push
compareURL := setting.AppUrl + opts.Commits.CompareURL
if isNewBranch {
compareURL = ""
if err = PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "branch",
Repo: apiRepo,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks (new branch): %v", err)
}
}
if err = PrepareWebhooks(repo, HOOK_EVENT_PUSH, &api.PushPayload{
Ref: opts.RefFullName,
Before: opts.OldCommitID,
After: opts.NewCommitID,
CompareURL: setting.AppUrl + opts.Commits.CompareURL,
CompareURL: compareURL,
Commits: opts.Commits.ToApiPayloadCommits(repo.HTMLURL()),
Repo: apiRepo,
Pusher: apiPusher,
Sender: apiPusher,
}); err != nil {
return fmt.Errorf("PrepareWebhooks: %v", err)
}
if isNewBranch {
return PrepareWebhooks(repo, HOOK_EVENT_CREATE, &api.CreatePayload{
Ref: refName,
RefType: "branch",
Repo: apiRepo,
Sender: apiPusher,
})
return fmt.Errorf("PrepareWebhooks (new commit): %v", err)
}
case ACTION_PUSH_TAG: // Create

View File

@ -292,6 +292,7 @@ type HookTaskType int
const (
GOGS HookTaskType = iota + 1
SLACK
DISCORD
)
var hookTaskTypes = map[string]HookTaskType{
@ -458,6 +459,10 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
var payloader api.Payloader
for _, w := range ws {
if !w.IsActive {
continue
}
switch event {
case HOOK_EVENT_CREATE:
if !w.HasCreateEvent() {
@ -476,12 +481,15 @@ func PrepareWebhooks(repo *Repository, event HookEventType, p api.Payloader) err
// Use separate objects so modifcations won't be made on payload on non-Gogs type hooks.
switch w.HookTaskType {
case SLACK:
// FIXME: dirty fix for buggy support of Discord for Slack-type webhook.
// Should remove this if we want to support Discord fully as its own.
payloader, err = GetSlackPayload(strings.Contains(w.URL, ".discordapp.com/"), p, event, w.Meta)
payloader, err = GetSlackPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetSlackPayload: %v", err)
}
case DISCORD:
payloader, err = GetDiscordPayload(p, event, w.Meta)
if err != nil {
return fmt.Errorf("GetDiscordPayload: %v", err)
}
default:
p.SetSecret(w.Secret)
payloader = p

213
models/webhook_discord.go Normal file
View File

@ -0,0 +1,213 @@
// Copyright 2017 The Gogs 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"
"fmt"
"strings"
"github.com/gogits/git-module"
api "github.com/gogits/go-gogs-client"
)
type DiscordEmbedFooterObject struct {
Text string `json:"text"`
}
type DiscordEmbedAuthorObject struct {
Name string `json:"name"`
URL string `json:"url"`
IconURL string `json:"icon_url"`
}
type DiscordEmbedFieldObject struct {
Name string `json:"name"`
Value string `json:"value"`
}
type DiscordEmbedObject struct {
Title string `json:"title"`
Description string `json:"description"`
URL string `json:"url"`
Footer *DiscordEmbedFooterObject `json:"footer"`
Author *DiscordEmbedAuthorObject `json:"author"`
Fields []*DiscordEmbedFieldObject `json:"fields"`
}
type DiscordPayload struct {
Content string `json:"content"`
Username string `json:"username"`
AvatarURL string `json:"avatar_url"`
Embeds []*DiscordEmbedObject `json:"embeds"`
}
func (p *DiscordPayload) SetSecret(_ string) {}
func (p *DiscordPayload) JSONPayload() ([]byte, error) {
data, err := json.MarshalIndent(p, "", " ")
if err != nil {
return []byte{}, err
}
return data, nil
}
func DiscordLinkFormatter(url string, text string) string {
return fmt.Sprintf("[%s](%s)", text, url)
}
func DiscordSHALinkFormatter(url string, text string) string {
return fmt.Sprintf("[`%s`](%s)", text, url)
}
func getDiscordCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*DiscordPayload, error) {
// Created tag/branch
refName := git.RefEndName(p.Ref)
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
content := fmt.Sprintf("Created new %s: %s/%s", p.RefType, repoLink, refLink)
return &DiscordPayload{
Username: slack.Username,
AvatarURL: slack.IconURL,
Embeds: []*DiscordEmbedObject{{
Description: content,
Author: &DiscordEmbedAuthorObject{
Name: p.Sender.UserName,
IconURL: p.Sender.AvatarUrl,
},
}},
}, nil
}
func getDiscordPushPayload(p *api.PushPayload, slack *SlackMeta) (*DiscordPayload, error) {
// n new commits
var (
branchName = git.RefEndName(p.Ref)
commitDesc string
commitString string
)
if len(p.Commits) == 1 {
commitDesc = "1 new commit"
} else {
commitDesc = fmt.Sprintf("%d new commits", len(p.Commits))
}
if len(p.CompareURL) > 0 {
commitString = DiscordLinkFormatter(p.CompareURL, commitDesc)
} else {
commitString = commitDesc
}
repoLink := DiscordLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
branchLink := DiscordLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
content := fmt.Sprintf("Pushed %s to %s/%s:\n", commitString, repoLink, branchLink)
// for each commit, generate attachment text
for i, commit := range p.Commits {
content += fmt.Sprintf("%s %s - %s", DiscordSHALinkFormatter(commit.URL, commit.ID[:7]), SlackShortTextFormatter(commit.Message), commit.Author.Name)
// add linebreak to each commit but the last
if i < len(p.Commits)-1 {
content += "\n"
}
}
return &DiscordPayload{
Username: slack.Username,
AvatarURL: slack.IconURL,
Embeds: []*DiscordEmbedObject{{
Description: content,
Author: &DiscordEmbedAuthorObject{
Name: p.Sender.UserName,
IconURL: p.Sender.AvatarUrl,
},
}},
}, nil
}
func getDiscordPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*DiscordPayload, error) {
title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title)
url := fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index)
content := ""
fields := make([]*DiscordEmbedFieldObject, 0, 1)
switch p.Action {
case api.HOOK_ISSUE_OPENED:
title = "New pull request: " + title
content = p.PullRequest.Body
case api.HOOK_ISSUE_CLOSED:
if p.PullRequest.HasMerged {
title = "Pull request merged: " + title
} else {
title = "Pull request closed: " + title
}
case api.HOOK_ISSUE_REOPENED:
title = "Pull request re-opened: " + title
case api.HOOK_ISSUE_EDITED:
title = "Pull request edited: " + title
content = p.PullRequest.Body
case api.HOOK_ISSUE_ASSIGNED:
title = "Pull request assigned: " + title
fields = []*DiscordEmbedFieldObject{{
Name: "New Assignee",
Value: p.PullRequest.Assignee.UserName,
}}
case api.HOOK_ISSUE_UNASSIGNED:
title = "Pull request unassigned: " + title
case api.HOOK_ISSUE_LABEL_UPDATED:
title = "Pull request labels updated: " + title
labels := make([]string, len(p.PullRequest.Labels))
for i := range p.PullRequest.Labels {
labels[i] = p.PullRequest.Labels[i].Name
}
fields = []*DiscordEmbedFieldObject{{
Name: "Labels",
Value: strings.Join(labels, ", "),
}}
case api.HOOK_ISSUE_LABEL_CLEARED:
title = "Pull request labels cleared: " + title
case api.HOOK_ISSUE_SYNCHRONIZED:
title = "Pull request synchronized: " + title
}
return &DiscordPayload{
Username: slack.Username,
AvatarURL: slack.IconURL,
Embeds: []*DiscordEmbedObject{{
Title: title,
Description: content,
URL: url,
Footer: &DiscordEmbedFooterObject{
Text: p.Repository.FullName,
},
Author: &DiscordEmbedAuthorObject{
Name: p.Sender.UserName,
IconURL: p.Sender.AvatarUrl,
},
Fields: fields,
}},
}, nil
}
func GetDiscordPayload(p api.Payloader, event HookEventType, meta string) (*DiscordPayload, error) {
d := new(DiscordPayload)
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
return d, fmt.Errorf("GetDiscordPayload meta json: %v", err)
}
switch event {
case HOOK_EVENT_CREATE:
return getDiscordCreatePayload(p.(*api.CreatePayload), slack)
case HOOK_EVENT_PUSH:
return getDiscordPushPayload(p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), slack)
}
return d, nil
}

View File

@ -6,7 +6,6 @@ package models
import (
"encoding/json"
"errors"
"fmt"
"strings"
@ -23,16 +22,6 @@ type SlackMeta struct {
Color string `json:"color"`
}
type SlackPayload struct {
Channel string `json:"channel"`
Text string `json:"text"`
Username string `json:"username"`
IconURL string `json:"icon_url"`
UnfurlLinks int `json:"unfurl_links"`
LinkNames int `json:"link_names"`
Attachments []SlackAttachment `json:"attachments"`
}
type SlackAttachment struct {
Fallback string `json:"fallback"`
Color string `json:"color"`
@ -40,6 +29,16 @@ type SlackAttachment struct {
Text string `json:"text"`
}
type SlackPayload struct {
Channel string `json:"channel"`
Text string `json:"text"`
Username string `json:"username"`
IconURL string `json:"icon_url"`
UnfurlLinks int `json:"unfurl_links"`
LinkNames int `json:"link_names"`
Attachments []*SlackAttachment `json:"attachments"`
}
func (p *SlackPayload) SetSecret(_ string) {}
func (p *SlackPayload) JSONPayload() ([]byte, error) {
@ -72,21 +71,13 @@ func SlackLinkFormatter(url string, text string) string {
return fmt.Sprintf("<%s|%s>", url, SlackTextFormatter(text))
}
func replaceBadCharsForDiscord(in string) string {
return strings.NewReplacer("[", "", "]", ":", ":", "/").Replace(in)
}
func getSlackCreatePayload(isDiscord bool, p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
func getSlackCreatePayload(p *api.CreatePayload, slack *SlackMeta) (*SlackPayload, error) {
// Created tag/branch
refName := git.RefEndName(p.Ref)
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
refLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+refName, refName)
format := "[%s:%s] %s created by %s"
if isDiscord {
format = replaceBadCharsForDiscord(format)
}
text := fmt.Sprintf(format, repoLink, refLink, p.RefType, p.Sender.UserName)
text := fmt.Sprintf("[%s:%s] %s created by %s", repoLink, refLink, p.RefType, p.Sender.UserName)
return &SlackPayload{
Channel: slack.Channel,
@ -96,7 +87,7 @@ func getSlackCreatePayload(isDiscord bool, p *api.CreatePayload, slack *SlackMet
}, nil
}
func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
func getSlackPushPayload(p *api.PushPayload, slack *SlackMeta) (*SlackPayload, error) {
// n new commits
var (
branchName = git.RefEndName(p.Ref)
@ -117,11 +108,7 @@ func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (
repoLink := SlackLinkFormatter(p.Repo.HTMLURL, p.Repo.Name)
branchLink := SlackLinkFormatter(p.Repo.HTMLURL+"/src/"+branchName, branchName)
format := "[%s:%s] %s pushed by %s"
if isDiscord {
format = replaceBadCharsForDiscord(format)
}
text := fmt.Sprintf(format, repoLink, branchLink, commitString, p.Pusher.UserName)
text := fmt.Sprintf("[%s:%s] %s pushed by %s", repoLink, branchLink, commitString, p.Pusher.UserName)
var attachmentText string
// for each commit, generate attachment text
@ -138,14 +125,14 @@ func getSlackPushPayload(isDiscord bool, p *api.PushPayload, slack *SlackMeta) (
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
Attachments: []SlackAttachment{{
Attachments: []*SlackAttachment{{
Color: slack.Color,
Text: attachmentText,
}},
}, nil
}
func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
func getSlackPullRequestPayload(p *api.PullRequestPayload, slack *SlackMeta) (*SlackPayload, error) {
senderLink := SlackLinkFormatter(setting.AppUrl+p.Sender.UserName, p.Sender.UserName)
titleLink := SlackLinkFormatter(fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index),
fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title))
@ -185,7 +172,7 @@ func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack
Text: text,
Username: slack.Username,
IconURL: slack.IconURL,
Attachments: []SlackAttachment{{
Attachments: []*SlackAttachment{{
Color: slack.Color,
Title: title,
Text: attachmentText,
@ -193,21 +180,21 @@ func getSlackPullRequestPayload(isDiscord bool, p *api.PullRequestPayload, slack
}, nil
}
func GetSlackPayload(isDiscord bool, p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
func GetSlackPayload(p api.Payloader, event HookEventType, meta string) (*SlackPayload, error) {
s := new(SlackPayload)
slack := &SlackMeta{}
if err := json.Unmarshal([]byte(meta), &slack); err != nil {
return s, errors.New("GetSlackPayload meta json:" + err.Error())
return s, fmt.Errorf("GetSlackPayload meta json: %v", err)
}
switch event {
case HOOK_EVENT_CREATE:
return getSlackCreatePayload(isDiscord, p.(*api.CreatePayload), slack)
return getSlackCreatePayload(p.(*api.CreatePayload), slack)
case HOOK_EVENT_PUSH:
return getSlackPushPayload(isDiscord, p.(*api.PushPayload), slack)
return getSlackPushPayload(p.(*api.PushPayload), slack)
case HOOK_EVENT_PULL_REQUEST:
return getSlackPullRequestPayload(isDiscord, p.(*api.PullRequestPayload), slack)
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
}
return s, nil

View File

@ -173,6 +173,17 @@ func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs binding.Errors) b
return validate(errs, ctx.Data, f, ctx.Locale)
}
type NewDiscordHookForm struct {
PayloadURL string `binding:"Required;Url"`
Username string
IconURL string
WebhookForm
}
func (f *NewDiscordHookForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors {
return validate(errs, ctx.Data, f, ctx.Locale)
}
// .___
// | | ______ ________ __ ____
// | |/ ___// ___/ | \_/ __ \

File diff suppressed because one or more lines are too long

View File

@ -821,7 +821,7 @@ func newWebhookService() {
Webhook.QueueLength = sec.Key("QUEUE_LENGTH").MustInt(1000)
Webhook.DeliverTimeout = sec.Key("DELIVER_TIMEOUT").MustInt(5)
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
Webhook.Types = []string{"gogs", "slack"}
Webhook.Types = []string{"gogs", "slack", "discord"}
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
}

View File

@ -84,6 +84,17 @@
"outputPathIsSetByUser": 0,
"processed": 1
},
"\/img\/discord.png": {
"fileType": 32768,
"ignore": 0,
"ignoreWasSetByUser": 0,
"initialSize": 1559,
"inputAbbreviatedPath": "\/img\/discord.png",
"outputAbbreviatedPath": "\/img\/discord.png",
"outputPathIsOutsideProject": 0,
"outputPathIsSetByUser": 0,
"processed": 0
},
"\/img\/favicon.png": {
"fileType": 32768,
"ignore": 0,

View File

@ -2291,6 +2291,9 @@ footer .ui.language .menu {
margin-left: 20px;
display: block;
}
.repository.settings.webhooks .types .menu .item {
padding: 10px !important;
}
.repository.settings.webhook .events .column {
padding-bottom: 0;
}

BIN
public/img/discord.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1329,6 +1329,14 @@
}
}
&.webhooks {
.types {
.menu .item {
padding: 10px !important;
}
}
}
&.webhook {
.events {
.column {

View File

@ -211,6 +211,55 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) {
ctx.Redirect(orCtx.Link + "/settings/hooks")
}
// FIXME: merge logic to Slack
func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) {
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.Handle(500, "getOrgRepoCtx", err)
return
}
if ctx.HasError() {
ctx.HTML(200, orCtx.NewTemplate)
return
}
meta, err := json.Marshal(&models.SlackMeta{
Username: form.Username,
IconURL: form.IconURL,
})
if err != nil {
ctx.Handle(500, "Marshal", err)
return
}
w := &models.Webhook{
RepoID: orCtx.RepoID,
URL: form.PayloadURL,
ContentType: models.JSON,
HookEvent: ParseHookEvent(form.WebhookForm),
IsActive: form.Active,
HookTaskType: models.DISCORD,
Meta: string(meta),
OrgID: orCtx.OrgID,
}
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return
} else if err := models.CreateWebhook(w); err != nil {
ctx.Handle(500, "CreateWebhook", err)
return
}
ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success"))
ctx.Redirect(orCtx.Link + "/settings/hooks")
}
func checkWebhook(ctx *context.Context) (*OrgRepoCtx, *models.Webhook) {
ctx.Data["RequireHighlightJS"] = true
@ -240,6 +289,9 @@ func checkWebhook(ctx *context.Context) (*OrgRepoCtx, *models.Webhook) {
case models.SLACK:
ctx.Data["SlackHook"] = w.GetSlackHook()
ctx.Data["HookType"] = "slack"
case models.DISCORD:
ctx.Data["SlackHook"] = w.GetSlackHook()
ctx.Data["HookType"] = "discord"
default:
ctx.Data["HookType"] = "gogs"
}
@ -346,6 +398,48 @@ func SlackHooksEditPost(ctx *context.Context, form auth.NewSlackHookForm) {
ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
}
// FIXME: merge logic to Slack
func DiscordHooksEditPost(ctx *context.Context, form auth.NewDiscordHookForm) {
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.SlackMeta{
Username: form.Username,
IconURL: form.IconURL,
})
if err != nil {
ctx.Handle(500, "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.Handle(500, "UpdateEvent", err)
return
} else if err := models.UpdateWebhook(w); err != nil {
ctx.Handle(500, "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))
}
func TestWebhook(ctx *context.Context) {
var authorUsername, committerUsername string

View File

@ -1 +1 @@
0.9.156.0217
0.9.157.0218

View File

@ -0,0 +1,20 @@
{{if eq .HookType "discord"}}
<p>{{.i18n.Tr "repo.settings.add_discord_hook_desc" "https://discordapp.com/" | Str2html}}</p>
<form class="ui form" action="{{.BaseLink}}/settings/hooks/discord/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.ID}}{{end}}" method="post">
{{.CsrfTokenHtml}}
<div class="required field {{if .Err_PayloadURL}}error{{end}}">
<label for="payload_url">{{.i18n.Tr "repo.settings.payload_url"}}</label>
<input id="payload_url" name="payload_url" type="url" value="{{.Webhook.URL}}" autofocus required>
</div>
<div class="field">
<label for="username">{{.i18n.Tr "repo.settings.slack_username"}}</label>
<input id="username" name="username" value="{{.SlackHook.Username}}" placeholder="e.g. Gogs">
</div>
<div class="field">
<label for="icon_url">{{.i18n.Tr "repo.settings.slack_icon_url"}}</label>
<input id="icon_url" name="icon_url" value="{{.SlackHook.IconURL}}" placeholder="e.g. https://example.com/img/favicon.png">
</div>
{{template "repo/settings/hook_settings" .}}
</form>
{{end}}

View File

@ -3,14 +3,17 @@
<h4 class="ui top attached header">
{{.i18n.Tr "repo.settings.hooks"}}
<div class="ui right">
<div class="ui floating1 jump dropdown">
<div class="ui types jump dropdown">
<div class="ui blue tiny button">{{.i18n.Tr "repo.settings.add_webhook"}}</div>
<div class="menu">
<a class="item" href="{{.BaseLink}}/settings/hooks/gogs/new">
<img class="img-10" src="{{AppSubUrl}}/img/favicon.png">Gogs
<img class="img-12" src="{{AppSubUrl}}/img/favicon.png">Gogs
</a>
<a class="item" href="{{.BaseLink}}/settings/hooks/slack/new">
<img class="img-10" src="{{AppSubUrl}}/img/slack.png">Slack
<img class="img-12" src="{{AppSubUrl}}/img/slack.png">Slack
</a>
<a class="item" href="{{.BaseLink}}/settings/hooks/discord/new">
<img class="img-12" src="{{AppSubUrl}}/img/discord.png">Discord
</a>
</div>
</div>

View File

@ -11,14 +11,15 @@
<div class="ui right">
{{if eq .HookType "gogs"}}
<img class="img-13" src="{{AppSubUrl}}/img/favicon.png">
{{else if eq .HookType "slack"}}
<img class="img-13" src="{{AppSubUrl}}/img/slack.png">
{{else}}
<img class="img-13" src="{{AppSubUrl}}/img/{{.HookType}}.png">
{{end}}
</div>
</h4>
<div class="ui attached segment">
{{template "repo/settings/hook_gogs" .}}
{{template "repo/settings/hook_slack" .}}
{{template "repo/settings/hook_discord" .}}
</div>
{{template "repo/settings/hook_history" .}}

View File

@ -1,5 +1,5 @@
{{if eq .HookType "slack"}}
<p>{{.i18n.Tr "repo.settings.add_slack_hook_desc" "http://slack.com" | Str2html}}</p>
<p>{{.i18n.Tr "repo.settings.add_slack_hook_desc" "https://slack.com" | Str2html}}</p>
<form class="ui form" action="{{.BaseLink}}/settings/hooks/slack/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.ID}}{{end}}" method="post">
{{.CsrfTokenHtml}}
<div class="required field {{if .Err_PayloadURL}}error{{end}}">