commit
1ed67798ac
@ -0,0 +1,114 @@ |
|||||||
|
// Copyright 2014 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" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"strings" |
||||||
|
) |
||||||
|
|
||||||
|
const ( |
||||||
|
SLACK_COLOR string = "#dd4b39" |
||||||
|
) |
||||||
|
|
||||||
|
type Slack struct { |
||||||
|
Domain string `json:"domain"` |
||||||
|
Token string `json:"token"` |
||||||
|
Channel string `json:"channel"` |
||||||
|
} |
||||||
|
|
||||||
|
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 { |
||||||
|
Color string `json:"color"` |
||||||
|
Text string `json:"text"` |
||||||
|
} |
||||||
|
|
||||||
|
func GetSlackURL(domain string, token string) string { |
||||||
|
return fmt.Sprintf( |
||||||
|
"https://%s.slack.com/services/hooks/incoming-webhook?token=%s", |
||||||
|
domain, |
||||||
|
token, |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
func (p SlackPayload) GetJSONPayload() ([]byte, error) { |
||||||
|
data, err := json.Marshal(p) |
||||||
|
if err != nil { |
||||||
|
return []byte{}, err |
||||||
|
} |
||||||
|
return data, nil |
||||||
|
} |
||||||
|
|
||||||
|
func GetSlackPayload(p *Payload, meta string) (*SlackPayload, error) { |
||||||
|
slack := &Slack{} |
||||||
|
slackPayload := &SlackPayload{} |
||||||
|
if err := json.Unmarshal([]byte(meta), &slack); err != nil { |
||||||
|
return slackPayload, errors.New("GetSlackPayload meta json:" + err.Error()) |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: handle different payload types: push, new branch, delete branch etc.
|
||||||
|
// when they are added to gogs. Only handles push now
|
||||||
|
return getSlackPushPayload(p, slack) |
||||||
|
} |
||||||
|
|
||||||
|
func getSlackPushPayload(p *Payload, slack *Slack) (*SlackPayload, error) { |
||||||
|
// n new commits
|
||||||
|
refSplit := strings.Split(p.Ref, "/") |
||||||
|
branchName := refSplit[len(refSplit)-1] |
||||||
|
var commitString string |
||||||
|
|
||||||
|
// TODO: add commit compare before/after link when gogs adds it
|
||||||
|
if len(p.Commits) == 1 { |
||||||
|
commitString = "1 new commit" |
||||||
|
} else { |
||||||
|
commitString = fmt.Sprintf("%d new commits", len(p.Commits)) |
||||||
|
} |
||||||
|
|
||||||
|
text := fmt.Sprintf("[%s:%s] %s pushed by %s", p.Repo.Name, branchName, commitString, p.Pusher.Name) |
||||||
|
var attachmentText string |
||||||
|
|
||||||
|
// for each commit, generate attachment text
|
||||||
|
for i, commit := range p.Commits { |
||||||
|
attachmentText += fmt.Sprintf("<%s|%s>: %s - %s", commit.Url, commit.Id[:7], SlackFormatter(commit.Message), commit.Author.Name) |
||||||
|
// add linebreak to each commit but the last
|
||||||
|
if i < len(p.Commits)-1 { |
||||||
|
attachmentText += "\n" |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
slackAttachments := []SlackAttachment{{Color: SLACK_COLOR, Text: attachmentText}} |
||||||
|
|
||||||
|
return &SlackPayload{ |
||||||
|
Channel: slack.Channel, |
||||||
|
Text: text, |
||||||
|
Username: "gogs", |
||||||
|
IconUrl: "https://raw.githubusercontent.com/gogits/gogs/master/public/img/favicon.png", |
||||||
|
UnfurlLinks: 0, |
||||||
|
LinkNames: 0, |
||||||
|
Attachments: slackAttachments, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// see: https://api.slack.com/docs/formatting
|
||||||
|
func SlackFormatter(s string) string { |
||||||
|
// take only first line of commit
|
||||||
|
first := strings.Split(s, "\n")[0] |
||||||
|
// replace & < >
|
||||||
|
first = strings.Replace(first, "&", "&", -1) |
||||||
|
first = strings.Replace(first, "<", "<", -1) |
||||||
|
first = strings.Replace(first, ">", ">", -1) |
||||||
|
return first |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
<div id="gogs" class="{{if (and .PageIsSettingsHooksEdit (not (eq .HookType "gogs")))}}hidden{{end}}"> |
||||||
|
<form class="form form-align panel-body repo-setting-form" id="repo-setting-form-gogs" action="{{.RepoLink}}/settings/hooks/gogs/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.Id}}{{end}}" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<input type="hidden" name="hook_type" value="gogs"> |
||||||
|
<div class="text-center panel-desc">{{.i18n.Tr "repo.settings.add_webhook_desc" | Str2html}}</div> |
||||||
|
<div class="field"> |
||||||
|
<label class="req" for="payload-url">{{.i18n.Tr "repo.settings.payload_url"}}</label> |
||||||
|
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="payload-url" name="payload_url" type="url" value="{{.Webhook.Url}}" required /> |
||||||
|
</div> |
||||||
|
<div class="field"> |
||||||
|
<label class="req">{{.i18n.Tr "repo.settings.content_type"}}</label> |
||||||
|
<select name="content_type"> |
||||||
|
<option value="1" {{if or .PageIsSettingsHooksNew (eq .Webhook.ContentType 1)}}selected{{end}}>application/json</option> |
||||||
|
<option value="2" {{if eq .Webhook.ContentType 2}}selected{{end}}>application/x-www-form-urlencoded</option> |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
<div class="field"> |
||||||
|
<label for="secret">{{.i18n.Tr "repo.settings.secret"}}</label> |
||||||
|
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="secret" name="secret" type="password" value="{{.Webhook.Secret}}" autocomplete="off" /> |
||||||
|
</div> |
||||||
|
{{template "repo/settings/hook_settings" .}} |
||||||
|
</form> |
||||||
|
</div> |
@ -0,0 +1,15 @@ |
|||||||
|
<div class="field"> |
||||||
|
<h4 class="text-center">{{.i18n.Tr "repo.settings.event_desc"}}</h4> |
||||||
|
<label></label> |
||||||
|
<input name="push_only" type="radio" {{if or .PageIsSettingsHooksNew .Webhook.PushOnly}}checked{{end}}> {{.i18n.Tr "repo.settings.event_push_only" | Str2html}} |
||||||
|
</div> |
||||||
|
<div class="field"> |
||||||
|
<label for="active">{{.i18n.Tr "repo.settings.active"}}</label> |
||||||
|
<input class="ipt-chk" id="active" name="active" type="checkbox" {{if or .PageIsSettingsHooksNew .Webhook.IsActive}}checked{{end}} /> |
||||||
|
<span>{{.i18n.Tr "repo.settings.active_helper"}}</span> |
||||||
|
</div> |
||||||
|
<div class="field"> |
||||||
|
<label></label> |
||||||
|
<button class="btn btn-green btn-large btn-radius">{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}</button> |
||||||
|
{{if .PageIsSettingsHooksEdit}}<a class="btn btn-red btn-large btn-link btn-radius" href="{{.RepoLink}}/settings/hooks?remove={{.Webhook.Id}}"><strong>{{.i18n.Tr "repo.settings.delete_webhook"}}</strong></a>{{end}} |
||||||
|
</div> |
@ -0,0 +1,11 @@ |
|||||||
|
{{if .PageIsSettingsHooksNew}} |
||||||
|
<div id="hook-type" class="form-align"> |
||||||
|
<label class="req">{{.i18n.Tr "repo.settings.hook_type"}}</label> |
||||||
|
<select name="hook_type" id="hook-type" class="form-control"> |
||||||
|
{{if .HookType}}<option value="{{.HookType}}">{{.HookType}}</option>{{end}} |
||||||
|
{{range .HookTypes}} |
||||||
|
{{if not (eq $.HookType .)}}<option value="{{.}}" >{{.}}</option>{{end}} |
||||||
|
{{end}} |
||||||
|
</select> |
||||||
|
</div> |
||||||
|
{{end}} |
@ -0,0 +1,20 @@ |
|||||||
|
<div id="slack" class="{{if or .PageIsSettingsHooksNew (and .PageIsSettingsHooksEdit (not (eq .HookType "slack")))}}hidden{{end}}"> |
||||||
|
<form class="form form-align panel-body repo-setting-form" id="repo-setting-form-slack" action="{{.RepoLink}}/settings/hooks/slack/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.Id}}{{end}}" method="post"> |
||||||
|
{{.CsrfTokenHtml}} |
||||||
|
<input type="hidden" name="hook_type" value="slack"> |
||||||
|
<div class="text-center panel-desc">{{.i18n.Tr "repo.settings.add_slack_hook_desc" | Str2html}}</div> |
||||||
|
<div class="field"> |
||||||
|
<label class="req" for="domain">{{.i18n.Tr "repo.settings.slack_domain"}}</label> |
||||||
|
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="domain" name="domain" type="text" value="{{.SlackHook.Domain}}" placeholde="myslack" required /> |
||||||
|
</div> |
||||||
|
<div class="field"> |
||||||
|
<label class="req" for="token">{{.i18n.Tr "repo.settings.slack_token"}}</label> |
||||||
|
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="token" name="token" type="text" value="{{.SlackHook.Token}}" autocomplete="off" required /> |
||||||
|
</div> |
||||||
|
<div class="field"> |
||||||
|
<label class="req" for="channel">{{.i18n.Tr "repo.settings.slack_channel"}}</label> |
||||||
|
<input class="ipt ipt-large ipt-radius {{if .Err_UserName}}ipt-error{{end}}" id="channel" name="channel" type="text" value="{{.SlackHook.Channel}}" placeholder="#general" required /> |
||||||
|
</div> |
||||||
|
{{template "repo/settings/hook_settings" .}} |
||||||
|
</form> |
||||||
|
</div> |
Loading…
Reference in new issue