aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
author无闻 <joe2010xtmf@163.com>2014-09-01 00:12:58 +0800
committer无闻 <joe2010xtmf@163.com>2014-09-01 00:12:58 +0800
commit1ed67798acb532dd2e62d2f3cbdde7b34219bfec (patch)
tree1ec707518cb37307cd05fa5cf6ef6bbf670caf9b
parent5e6091a30ae4befd68041aaff3f70d7334ce1b1c (diff)
parent2bce24068dc3c64ee5e501c48b7f080c48383970 (diff)
downloadgitea-1ed67798acb532dd2e62d2f3cbdde7b34219bfec.tar.gz
gitea-1ed67798acb532dd2e62d2f3cbdde7b34219bfec.zip
Merge pull request #379 from compressed/slack
Slack Support
-rw-r--r--cmd/web.go6
-rw-r--r--conf/locale/locale_en-US.ini5
-rw-r--r--models/action.go35
-rw-r--r--models/slack.go114
-rw-r--r--models/webhook.go86
-rw-r--r--modules/auth/repo_form.go24
-rw-r--r--public/ng/css/gogs.css26
-rw-r--r--public/ng/js/gogs.js18
-rw-r--r--public/ng/less/gogs/settings.less16
-rw-r--r--routers/repo/setting.go126
-rw-r--r--templates/repo/settings/gogs_hook.tmpl23
-rw-r--r--templates/repo/settings/hook_new.tmpl39
-rw-r--r--templates/repo/settings/hook_settings.tmpl15
-rw-r--r--templates/repo/settings/hook_types.tmpl11
-rw-r--r--templates/repo/settings/slack_hook.tmpl20
15 files changed, 485 insertions, 79 deletions
diff --git a/cmd/web.go b/cmd/web.go
index e0ef3a76a3..275d3fb90e 100644
--- a/cmd/web.go
+++ b/cmd/web.go
@@ -284,9 +284,11 @@ func runWeb(*cli.Context) {
r.Route("/collaboration", "GET,POST", repo.SettingsCollaboration)
r.Get("/hooks", repo.Webhooks)
r.Get("/hooks/new", repo.WebHooksNew)
- r.Post("/hooks/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
+ r.Post("/hooks/gogs/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost)
+ r.Post("/hooks/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost)
r.Get("/hooks/:id", repo.WebHooksEdit)
- r.Post("/hooks/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
+ r.Post("/hooks/gogs/:id", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksEditPost)
+ r.Post("/hooks/slack/:id", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksEditPost)
})
}, reqSignIn, middleware.RepoAssignment(true), reqTrueOwner)
diff --git a/conf/locale/locale_en-US.ini b/conf/locale/locale_en-US.ini
index a99eb92e7e..946d560461 100644
--- a/conf/locale/locale_en-US.ini
+++ b/conf/locale/locale_en-US.ini
@@ -234,6 +234,11 @@ settings.update_webhook = Update Webhook
settings.update_hook_success = Webhook has been updated.
settings.delete_webhook = Delete Webhook
settings.recent_deliveries = Recent Deliveries
+settings.hook_type = Hook Type
+settings.add_slack_hook_desc = Add <a href="http://slack.com">Slack</a> integration to your repository.
+settings.slack_token = Token
+settings.slack_domain = Domain
+settings.slack_channel = Channel
[org]
org_name_holder = Organization Name
diff --git a/models/action.go b/models/action.go
index b5f692c49f..d536c84dd0 100644
--- a/models/action.go
+++ b/models/action.go
@@ -266,14 +266,33 @@ func CommitRepoAction(userId, repoUserId int64, userName, actEmail string,
continue
}
- p.Secret = w.Secret
- CreateHookTask(&HookTask{
- Type: WEBHOOK,
- Url: w.Url,
- Payload: p,
- ContentType: w.ContentType,
- IsSsl: w.IsSsl,
- })
+ switch w.HookTaskType {
+ case SLACK:
+ {
+ s, err := GetSlackPayload(p, w.Meta)
+ if err != nil {
+ return errors.New("action.GetSlackPayload: " + err.Error())
+ }
+ CreateHookTask(&HookTask{
+ Type: w.HookTaskType,
+ Url: w.Url,
+ BasePayload: s,
+ ContentType: w.ContentType,
+ IsSsl: w.IsSsl,
+ })
+ }
+ default:
+ {
+ p.Secret = w.Secret
+ CreateHookTask(&HookTask{
+ Type: w.HookTaskType,
+ Url: w.Url,
+ BasePayload: p,
+ ContentType: w.ContentType,
+ IsSsl: w.IsSsl,
+ })
+ }
+ }
}
return nil
}
diff --git a/models/slack.go b/models/slack.go
new file mode 100644
index 0000000000..0a55740947
--- /dev/null
+++ b/models/slack.go
@@ -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, "&", "&amp;", -1)
+ first = strings.Replace(first, "<", "&lt;", -1)
+ first = strings.Replace(first, ">", "&gt;", -1)
+ return first
+}
diff --git a/models/webhook.go b/models/webhook.go
index ced7936646..55ed4844ed 100644
--- a/models/webhook.go
+++ b/models/webhook.go
@@ -7,6 +7,7 @@ package models
import (
"encoding/json"
"errors"
+ "io/ioutil"
"time"
"github.com/gogits/gogs/modules/httplib"
@@ -33,15 +34,17 @@ type HookEvent struct {
// Webhook represents a web hook object.
type Webhook struct {
- Id int64
- RepoId int64
- Url string `xorm:"TEXT"`
- ContentType HookContentType
- Secret string `xorm:"TEXT"`
- Events string `xorm:"TEXT"`
- *HookEvent `xorm:"-"`
- IsSsl bool
- IsActive bool
+ Id int64
+ RepoId int64
+ Url string `xorm:"TEXT"`
+ ContentType HookContentType
+ Secret string `xorm:"TEXT"`
+ Events string `xorm:"TEXT"`
+ *HookEvent `xorm:"-"`
+ IsSsl bool
+ IsActive bool
+ HookTaskType HookTaskType
+ Meta string `xorm:"TEXT"` // store hook-specific attributes
}
// GetEvent handles conversion from Events to HookEvent.
@@ -52,6 +55,14 @@ func (w *Webhook) GetEvent() {
}
}
+func (w *Webhook) GetSlackHook() *Slack {
+ s := &Slack{}
+ if err := json.Unmarshal([]byte(w.Meta), s); err != nil {
+ log.Error(4, "webhook.GetSlackHook(%d): %v", w.Id, err)
+ }
+ return s
+}
+
// UpdateEvent handles conversion from HookEvent to Events.
func (w *Webhook) UpdateEvent() error {
data, err := json.Marshal(w.HookEvent)
@@ -119,8 +130,8 @@ func DeleteWebhook(hookId int64) error {
type HookTaskType int
const (
- WEBHOOK HookTaskType = iota + 1
- SERVICE
+ GOGS HookTaskType = iota + 1
+ SLACK
)
type HookEventType string
@@ -152,6 +163,10 @@ type PayloadRepo struct {
Private bool `json:"private"`
}
+type BasePayload interface {
+ GetJSONPayload() ([]byte, error)
+}
+
// Payload represents a payload information of hook.
type Payload struct {
Secret string `json:"secret"`
@@ -161,25 +176,33 @@ type Payload struct {
Pusher *PayloadAuthor `json:"pusher"`
}
+func (p Payload) GetJSONPayload() ([]byte, error) {
+ data, err := json.Marshal(p)
+ if err != nil {
+ return []byte{}, err
+ }
+ return data, nil
+}
+
// HookTask represents a hook task.
type HookTask struct {
Id int64
Uuid string
Type HookTaskType
Url string
- *Payload `xorm:"-"`
+ BasePayload `xorm:"-"`
PayloadContent string `xorm:"TEXT"`
ContentType HookContentType
EventType HookEventType
IsSsl bool
- IsDeliveried bool
+ IsDelivered bool
IsSucceed bool
}
// CreateHookTask creates a new hook task,
// it handles conversion from Payload to PayloadContent.
func CreateHookTask(t *HookTask) error {
- data, err := json.Marshal(t.Payload)
+ data, err := t.BasePayload.GetJSONPayload()
if err != nil {
return err
}
@@ -198,7 +221,7 @@ func UpdateHookTask(t *HookTask) error {
// DeliverHooks checks and delivers undelivered hooks.
func DeliverHooks() {
timeout := time.Duration(setting.WebhookDeliverTimeout) * time.Second
- x.Where("is_deliveried=?", false).Iterate(new(HookTask),
+ x.Where("is_delivered=?", false).Iterate(new(HookTask),
func(idx int, bean interface{}) error {
t := bean.(*HookTask)
req := httplib.Post(t.Url).SetTimeout(timeout, timeout).
@@ -212,13 +235,36 @@ func DeliverHooks() {
req.Param("payload", t.PayloadContent)
}
- t.IsDeliveried = true
+ t.IsDelivered = true
// TODO: record response.
- if _, err := req.Response(); err != nil {
- log.Error(4, "Delivery: %v", err)
- } else {
- t.IsSucceed = true
+ switch t.Type {
+ case GOGS:
+ {
+ if _, err := req.Response(); err != nil {
+ log.Error(4, "Delivery: %v", err)
+ } else {
+ t.IsSucceed = true
+ }
+ }
+ case SLACK:
+ {
+ if res, err := req.Response(); err != nil {
+ log.Error(4, "Delivery: %v", err)
+ } else {
+ defer res.Body.Close()
+ contents, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ log.Error(4, "%s", err)
+ } else {
+ if string(contents) != "ok" {
+ log.Error(4, "slack failed with: %s", string(contents))
+ } else {
+ t.IsSucceed = true
+ }
+ }
+ }
+ }
}
if err := UpdateHookTask(t); err != nil {
diff --git a/modules/auth/repo_form.go b/modules/auth/repo_form.go
index 3eb0cbc564..5fd1114052 100644
--- a/modules/auth/repo_form.go
+++ b/modules/auth/repo_form.go
@@ -69,17 +69,31 @@ func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs *binding.Errors, l
// \/ \/ \/ \/ \/ \/
type NewWebhookForm struct {
- PayloadUrl string `form:"payload_url" binding:"Required;Url"`
- ContentType string `form:"content_type" binding:"Required"`
- Secret string `form:"secret"`
- PushOnly bool `form:"push_only"`
- Active bool `form:"active"`
+ HookTaskType string `form:"hook_type" binding:"Required"`
+ PayloadUrl string `form:"payload_url" binding:"Required;Url"`
+ ContentType string `form:"content_type" binding:"Required"`
+ Secret string `form:"secret"`
+ PushOnly bool `form:"push_only"`
+ Active bool `form:"active"`
}
func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) {
validate(errs, ctx.Data, f, l)
}
+type NewSlackHookForm struct {
+ HookTaskType string `form:"hook_type" binding:"Required"`
+ Domain string `form:"domain" binding:"Required`
+ Token string `form:"token" binding:"Required"`
+ Channel string `form:"channel" binding:"Required"`
+ PushOnly bool `form:"push_only"`
+ Active bool `form:"active"`
+}
+
+func (f *NewSlackHookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) {
+ validate(errs, ctx.Data, f, l)
+}
+
// .___
// | | ______ ________ __ ____
// | |/ ___// ___/ | \_/ __ \
diff --git a/public/ng/css/gogs.css b/public/ng/css/gogs.css
index d81d6f3149..0840833755 100644
--- a/public/ng/css/gogs.css
+++ b/public/ng/css/gogs.css
@@ -1403,14 +1403,16 @@ The register and sign-in page style
#auth-setting-form,
#org-setting-form,
#repo-setting-form,
-#user-profile-form {
+#user-profile-form,
+.repo-setting-form {
background-color: #FFF;
padding: 30px 0;
}
#auth-setting-form textarea,
#org-setting-form textarea,
#repo-setting-form textarea,
-#user-profile-form textarea {
+#user-profile-form textarea,
+.repo-setting-form textarea {
margin-left: 4px;
height: 100px;
}
@@ -1418,24 +1420,38 @@ The register and sign-in page style
#org-setting-form label,
#repo-setting-form label,
#user-profile-form label,
+.repo-setting-form label,
#auth-setting-form .form-label,
#org-setting-form .form-label,
#repo-setting-form .form-label,
-#user-profile-form .form-label {
+#user-profile-form .form-label,
+.repo-setting-form .form-label {
width: 240px;
}
#auth-setting-form .ipt,
#org-setting-form .ipt,
#repo-setting-form .ipt,
-#user-profile-form .ipt {
+#user-profile-form .ipt,
+.repo-setting-form .ipt {
width: 360px;
}
#auth-setting-form .field,
#org-setting-form .field,
#repo-setting-form .field,
-#user-profile-form .field {
+#user-profile-form .field,
+.repo-setting-form .field {
margin-bottom: 24px;
}
+#hook-type {
+ padding: 10px 0 0 0;
+ background-color: #fff;
+}
+#hook-type .field {
+ margin-bottom: 24px;
+}
+#hook-type label {
+ width: 240px;
+}
#repo-hooks-panel,
#repo-hooks-history-panel,
#user-social-panel,
diff --git a/public/ng/js/gogs.js b/public/ng/js/gogs.js
index bade9f3420..c08a887a4c 100644
--- a/public/ng/js/gogs.js
+++ b/public/ng/js/gogs.js
@@ -359,6 +359,22 @@ function initRepoSetting() {
return true;
}
});
+
+ // web hook type change
+ $('select#hook-type').on("change", function () {
+ hookTypes = ['Gogs','Slack'];
+
+ var curHook = $(this).val();
+ hookTypes.forEach(function(hookType) {
+ if (curHook === hookType) {
+ $('div#'+hookType.toLowerCase()).toggleShow();
+ }
+ else {
+ $('div#'+hookType.toLowerCase()).toggleHide();
+ }
+ });
+ });
+
$('#transfer-button').click(function () {
$('#transfer-form').show();
});
@@ -594,4 +610,4 @@ function homepage() {
}
$('#promo-form').attr('action', '/user/sign_up');
});
-} \ No newline at end of file
+}
diff --git a/public/ng/less/gogs/settings.less b/public/ng/less/gogs/settings.less
index b246a947ec..80c00f2dbe 100644
--- a/public/ng/less/gogs/settings.less
+++ b/public/ng/less/gogs/settings.less
@@ -34,7 +34,8 @@
#auth-setting-form,
#org-setting-form,
#repo-setting-form,
-#user-profile-form {
+#user-profile-form,
+.repo-setting-form {
background-color: #FFF;
padding: 30px 0;
textarea {
@@ -53,6 +54,17 @@
}
}
+#hook-type {
+ padding: 10px 0 0 0;
+ background-color: #fff;
+ .field {
+ margin-bottom: 24px;
+ }
+ label {
+ width: 240px;
+ }
+}
+
#repo-hooks-panel,
#repo-hooks-history-panel,
#user-social-panel,
@@ -109,4 +121,4 @@
.field {
margin-bottom: 24px;
}
-} \ No newline at end of file
+}
diff --git a/routers/repo/setting.go b/routers/repo/setting.go
index 24c1b13a5e..fba9eed6a2 100644
--- a/routers/repo/setting.go
+++ b/routers/repo/setting.go
@@ -5,6 +5,7 @@
package repo
import (
+ "encoding/json"
"fmt"
"strings"
"time"
@@ -272,11 +273,17 @@ func Webhooks(ctx *middleware.Context) {
ctx.HTML(200, HOOKS)
}
+func renderHookTypes(ctx *middleware.Context) {
+ ctx.Data["HookTypes"] = []string{"Gogs", "Slack"}
+ ctx.Data["HookType"] = "Gogs"
+}
+
func WebHooksNew(ctx *middleware.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["PageIsSettingsHooksNew"] = true
ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
+ renderHookTypes(ctx)
ctx.HTML(200, HOOK_NEW)
}
@@ -304,8 +311,11 @@ func WebHooksNewPost(ctx *middleware.Context, form auth.NewWebhookForm) {
HookEvent: &models.HookEvent{
PushOnly: form.PushOnly,
},
- IsActive: form.Active,
+ IsActive: form.Active,
+ HookTaskType: models.GOGS,
+ Meta: "",
}
+
if err := w.UpdateEvent(); err != nil {
ctx.Handle(500, "UpdateEvent", err)
return
@@ -338,6 +348,19 @@ func WebHooksEdit(ctx *middleware.Context) {
}
return
}
+
+ // set data per HookTaskType
+ switch w.HookTaskType {
+ case models.SLACK:
+ {
+ ctx.Data["SlackHook"] = w.GetSlackHook()
+ ctx.Data["HookType"] = "slack"
+ }
+ default:
+ {
+ ctx.Data["HookType"] = "gogs"
+ }
+ }
w.GetEvent()
ctx.Data["Webhook"] = w
ctx.HTML(200, HOOK_NEW)
@@ -394,3 +417,104 @@ func WebHooksEditPost(ctx *middleware.Context, form auth.NewWebhookForm) {
ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId))
}
+
+func SlackHooksNewPost(ctx *middleware.Context, form auth.NewSlackHookForm) {
+ ctx.Data["Title"] = ctx.Tr("repo.settings")
+ ctx.Data["PageIsSettingsHooks"] = true
+ ctx.Data["PageIsSettingsHooksNew"] = true
+ ctx.Data["Webhook"] = models.Webhook{HookEvent: &models.HookEvent{}}
+
+ if ctx.HasError() {
+ ctx.HTML(200, HOOK_NEW)
+ return
+ }
+
+ meta, err := json.Marshal(&models.Slack{
+ Domain: form.Domain,
+ Channel: form.Channel,
+ Token: form.Token,
+ })
+ if err != nil {
+ ctx.Handle(500, "SlackHooksNewPost: JSON marshal failed: ", err)
+ return
+ }
+
+ w := &models.Webhook{
+ RepoId: ctx.Repo.Repository.Id,
+ Url: models.GetSlackURL(form.Domain, form.Token),
+ ContentType: models.JSON,
+ Secret: "",
+ HookEvent: &models.HookEvent{
+ PushOnly: form.PushOnly,
+ },
+ IsActive: form.Active,
+ HookTaskType: models.SLACK,
+ Meta: string(meta),
+ }
+ 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(ctx.Repo.RepoLink + "/settings/hooks")
+}
+
+func SlackHooksEditPost(ctx *middleware.Context, form auth.NewSlackHookForm) {
+ ctx.Data["Title"] = ctx.Tr("repo.settings")
+ ctx.Data["PageIsSettingsHooks"] = true
+ ctx.Data["PageIsSettingsHooksEdit"] = true
+
+ hookId := com.StrTo(ctx.Params(":id")).MustInt64()
+ fmt.Println("hookId slack=%d", hookId)
+ if hookId == 0 {
+ ctx.Handle(404, "setting.WebHooksEditPost", nil)
+ return
+ }
+
+ w, err := models.GetWebhookById(hookId)
+ if err != nil {
+ if err == models.ErrWebhookNotExist {
+ ctx.Handle(404, "GetWebhookById", nil)
+ } else {
+ ctx.Handle(500, "GetWebhookById", err)
+ }
+ return
+ }
+ w.GetEvent()
+ ctx.Data["Webhook"] = w
+
+ if ctx.HasError() {
+ ctx.HTML(200, HOOK_NEW)
+ return
+ }
+ meta, err := json.Marshal(&models.Slack{
+ Domain: form.Domain,
+ Channel: form.Channel,
+ Token: form.Token,
+ })
+ if err != nil {
+ ctx.Handle(500, "SlackHooksNewPost: JSON marshal failed: ", err)
+ return
+ }
+
+ w.Url = models.GetSlackURL(form.Domain, form.Token)
+ w.Meta = string(meta)
+ w.HookEvent = &models.HookEvent{
+ PushOnly: form.PushOnly,
+ }
+ 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, "SlackHooksEditPost", err)
+ return
+ }
+
+ ctx.Flash.Success(ctx.Tr("repo.settings.update_hook_success"))
+ ctx.Redirect(fmt.Sprintf("%s/settings/hooks/%d", ctx.Repo.RepoLink, hookId))
+}
diff --git a/templates/repo/settings/gogs_hook.tmpl b/templates/repo/settings/gogs_hook.tmpl
new file mode 100644
index 0000000000..678d640baf
--- /dev/null
+++ b/templates/repo/settings/gogs_hook.tmpl
@@ -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>
diff --git a/templates/repo/settings/hook_new.tmpl b/templates/repo/settings/hook_new.tmpl
index 2cd0eacb6a..7a450282b1 100644
--- a/templates/repo/settings/hook_new.tmpl
+++ b/templates/repo/settings/hook_new.tmpl
@@ -13,40 +13,9 @@
<div class="panel-header">
<strong>{{if .PageIsSettingsHooksNew}}{{.i18n.Tr "repo.settings.add_webhook"}}{{else}}{{.i18n.Tr "repo.settings.update_webhook"}}{{end}}</strong>
</div>
- <form class="form form-align panel-body" id="repo-setting-form" action="{{.RepoLink}}/settings/hooks/{{if .PageIsSettingsHooksNew}}new{{else}}{{.Webhook.Id}}{{end}}" method="post">
- {{.CsrfTokenHtml}}
- <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>
- <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>
- </form>
+ {{template "repo/settings/hook_types" .}}
+ {{template "repo/settings/gogs_hook" .}}
+ {{template "repo/settings/slack_hook" .}}
</div>
</div>
{{if .PageIsSettingsHooksEdit}}
@@ -67,4 +36,4 @@
</div>
</div>
</div>
-{{template "ng/base/footer" .}} \ No newline at end of file
+{{template "ng/base/footer" .}}
diff --git a/templates/repo/settings/hook_settings.tmpl b/templates/repo/settings/hook_settings.tmpl
new file mode 100644
index 0000000000..7bf4e2a36c
--- /dev/null
+++ b/templates/repo/settings/hook_settings.tmpl
@@ -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>
diff --git a/templates/repo/settings/hook_types.tmpl b/templates/repo/settings/hook_types.tmpl
new file mode 100644
index 0000000000..782e2a4e73
--- /dev/null
+++ b/templates/repo/settings/hook_types.tmpl
@@ -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}}
diff --git a/templates/repo/settings/slack_hook.tmpl b/templates/repo/settings/slack_hook.tmpl
new file mode 100644
index 0000000000..e68571a081
--- /dev/null
+++ b/templates/repo/settings/slack_hook.tmpl
@@ -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>