|
@@ -7,13 +7,13 @@ package repo
|
|
import (
|
|
import (
|
|
"fmt"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http"
|
|
|
|
+ "net/url"
|
|
"strings"
|
|
"strings"
|
|
|
|
|
|
- jsoniter "github.com/json-iterator/go"
|
|
|
|
- "github.com/unknwon/com"
|
|
|
|
-
|
|
|
|
- git "github.com/gogs/git-module"
|
|
|
|
|
|
+ "github.com/gogs/git-module"
|
|
api "github.com/gogs/go-gogs-client"
|
|
api "github.com/gogs/go-gogs-client"
|
|
|
|
+ jsoniter "github.com/json-iterator/go"
|
|
|
|
+ "gopkg.in/macaron.v1"
|
|
|
|
|
|
"gogs.io/gogs/internal/conf"
|
|
"gogs.io/gogs/internal/conf"
|
|
"gogs.io/gogs/internal/context"
|
|
"gogs.io/gogs/internal/context"
|
|
@@ -23,89 +23,163 @@ import (
|
|
)
|
|
)
|
|
|
|
|
|
const (
|
|
const (
|
|
- WEBHOOKS = "repo/settings/webhook/base"
|
|
|
|
- WEBHOOK_NEW = "repo/settings/webhook/new"
|
|
|
|
- ORG_WEBHOOK_NEW = "org/settings/webhook_new"
|
|
|
|
|
|
+ tmplRepoSettingsWebhooks = "repo/settings/webhook/base"
|
|
|
|
+ tmplRepoSettingsWebhookNew = "repo/settings/webhook/new"
|
|
|
|
+ tmplOrgSettingsWebhooks = "org/settings/webhooks"
|
|
|
|
+ tmplOrgSettingsWebhookNew = "org/settings/webhook_new"
|
|
)
|
|
)
|
|
|
|
|
|
-func Webhooks(c *context.Context) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings.hooks")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["BaseLink"] = c.Repo.RepoLink
|
|
|
|
- c.Data["Description"] = c.Tr("repo.settings.hooks_desc", "https://github.com/gogs/docs-api/blob/master/Repositories/Webhooks.md")
|
|
|
|
- c.Data["Types"] = conf.Webhook.Types
|
|
|
|
-
|
|
|
|
- ws, err := db.GetWebhooksByRepoID(c.Repo.Repository.ID)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get webhooks by repository ID")
|
|
|
|
- return
|
|
|
|
|
|
+func InjectOrgRepoContext() macaron.Handler {
|
|
|
|
+ return func(c *context.Context) {
|
|
|
|
+ orCtx, err := getOrgRepoContext(c)
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.Error(err, "get organization or repository context")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ c.Map(orCtx)
|
|
}
|
|
}
|
|
- c.Data["Webhooks"] = ws
|
|
|
|
-
|
|
|
|
- c.Success(WEBHOOKS)
|
|
|
|
}
|
|
}
|
|
|
|
|
|
-type OrgRepoCtx struct {
|
|
|
|
- OrgID int64
|
|
|
|
- RepoID int64
|
|
|
|
- Link string
|
|
|
|
- NewTemplate string
|
|
|
|
|
|
+type orgRepoContext struct {
|
|
|
|
+ OrgID int64
|
|
|
|
+ RepoID int64
|
|
|
|
+ Link string
|
|
|
|
+ TmplList string
|
|
|
|
+ TmplNew string
|
|
}
|
|
}
|
|
|
|
|
|
-// getOrgRepoCtx determines whether this is a repo context or organization context.
|
|
|
|
-func getOrgRepoCtx(c *context.Context) (*OrgRepoCtx, error) {
|
|
|
|
|
|
+// getOrgRepoContext determines whether this is a repo context or organization context.
|
|
|
|
+func getOrgRepoContext(c *context.Context) (*orgRepoContext, error) {
|
|
if len(c.Repo.RepoLink) > 0 {
|
|
if len(c.Repo.RepoLink) > 0 {
|
|
- c.Data["PageIsRepositoryContext"] = true
|
|
|
|
- return &OrgRepoCtx{
|
|
|
|
- RepoID: c.Repo.Repository.ID,
|
|
|
|
- Link: c.Repo.RepoLink,
|
|
|
|
- NewTemplate: WEBHOOK_NEW,
|
|
|
|
|
|
+ c.PageIs("RepositoryContext")
|
|
|
|
+ return &orgRepoContext{
|
|
|
|
+ RepoID: c.Repo.Repository.ID,
|
|
|
|
+ Link: c.Repo.RepoLink,
|
|
|
|
+ TmplList: tmplRepoSettingsWebhooks,
|
|
|
|
+ TmplNew: tmplRepoSettingsWebhookNew,
|
|
}, nil
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
|
|
if len(c.Org.OrgLink) > 0 {
|
|
if len(c.Org.OrgLink) > 0 {
|
|
- c.Data["PageIsOrganizationContext"] = true
|
|
|
|
- return &OrgRepoCtx{
|
|
|
|
- OrgID: c.Org.Organization.ID,
|
|
|
|
- Link: c.Org.OrgLink,
|
|
|
|
- NewTemplate: ORG_WEBHOOK_NEW,
|
|
|
|
|
|
+ c.PageIs("OrganizationContext")
|
|
|
|
+ return &orgRepoContext{
|
|
|
|
+ OrgID: c.Org.Organization.ID,
|
|
|
|
+ Link: c.Org.OrgLink,
|
|
|
|
+ TmplList: tmplOrgSettingsWebhooks,
|
|
|
|
+ TmplNew: tmplOrgSettingsWebhookNew,
|
|
}, nil
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
|
|
- return nil, errors.New("Unable to set OrgRepo context")
|
|
|
|
|
|
+ return nil, errors.New("unable to determine context")
|
|
}
|
|
}
|
|
|
|
|
|
-func checkHookType(c *context.Context) string {
|
|
|
|
|
|
+func Webhooks(c *context.Context, orCtx *orgRepoContext) {
|
|
|
|
+ c.Title("repo.settings.hooks")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.Data["Types"] = conf.Webhook.Types
|
|
|
|
+
|
|
|
|
+ var err error
|
|
|
|
+ var ws []*db.Webhook
|
|
|
|
+ if orCtx.RepoID > 0 {
|
|
|
|
+ c.Data["Description"] = c.Tr("repo.settings.hooks_desc")
|
|
|
|
+ ws, err = db.GetWebhooksByRepoID(orCtx.RepoID)
|
|
|
|
+ } else {
|
|
|
|
+ c.Data["Description"] = c.Tr("org.settings.hooks_desc")
|
|
|
|
+ ws, err = db.GetWebhooksByOrgID(orCtx.OrgID)
|
|
|
|
+ }
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.Error(err, "get webhooks")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ c.Data["Webhooks"] = ws
|
|
|
|
+
|
|
|
|
+ c.Success(orCtx.TmplList)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func WebhooksNew(c *context.Context, orCtx *orgRepoContext) {
|
|
|
|
+ c.Title("repo.settings.add_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksNew")
|
|
|
|
+
|
|
|
|
+ allowed := false
|
|
hookType := strings.ToLower(c.Params(":type"))
|
|
hookType := strings.ToLower(c.Params(":type"))
|
|
- if !com.IsSliceContainsStr(conf.Webhook.Types, hookType) {
|
|
|
|
|
|
+ for _, typ := range conf.Webhook.Types {
|
|
|
|
+ if hookType == typ {
|
|
|
|
+ allowed = true
|
|
|
|
+ c.Data["HookType"] = typ
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ if !allowed {
|
|
c.NotFound()
|
|
c.NotFound()
|
|
- return ""
|
|
|
|
|
|
+ return
|
|
}
|
|
}
|
|
- return hookType
|
|
|
|
|
|
+
|
|
|
|
+ c.Success(orCtx.TmplNew)
|
|
}
|
|
}
|
|
|
|
|
|
-func WebhooksNew(c *context.Context) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings.add_webhook")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksNew"] = true
|
|
|
|
- c.Data["Webhook"] = db.Webhook{HookEvent: &db.HookEvent{}}
|
|
|
|
|
|
+var localHostnames = []string{
|
|
|
|
+ "localhost",
|
|
|
|
+ "127.0.0.1",
|
|
|
|
+ "::1",
|
|
|
|
+ "0:0:0:0:0:0:0:1",
|
|
|
|
+}
|
|
|
|
|
|
- orCtx, err := getOrgRepoCtx(c)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get organization repository context")
|
|
|
|
|
|
+// isLocalHostname returns true if given hostname is a known local address.
|
|
|
|
+func isLocalHostname(hostname string) bool {
|
|
|
|
+ for _, local := range localHostnames {
|
|
|
|
+ if hostname == local {
|
|
|
|
+ return true
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return false
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func validateWebhook(actor *db.User, l macaron.Locale, w *db.Webhook) (field string, msg string, ok bool) {
|
|
|
|
+ if !actor.IsAdmin {
|
|
|
|
+ // 🚨 SECURITY: Local addresses must not be allowed by non-admins to prevent SSRF,
|
|
|
|
+ // see https://github.com/gogs/gogs/issues/5366 for details.
|
|
|
|
+ payloadURL, err := url.Parse(w.URL)
|
|
|
|
+ if err != nil {
|
|
|
|
+ return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_parse_payload_url", err), false
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if isLocalHostname(payloadURL.Hostname()) {
|
|
|
|
+ return "PayloadURL", l.Tr("repo.settings.webhook.err_cannot_use_local_addresses"), false
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return "", "", true
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func validateAndCreateWebhook(c *context.Context, orCtx *orgRepoContext, w *db.Webhook) {
|
|
|
|
+ c.Data["Webhook"] = w
|
|
|
|
+
|
|
|
|
+ if c.HasError() {
|
|
|
|
+ c.Success(orCtx.TmplNew)
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- c.Data["HookType"] = checkHookType(c)
|
|
|
|
- if c.Written() {
|
|
|
|
|
|
+ field, msg, ok := validateWebhook(c.User, c.Locale, w)
|
|
|
|
+ if !ok {
|
|
|
|
+ c.FormErr(field)
|
|
|
|
+ c.RenderWithErr(msg, orCtx.TmplNew, nil)
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if err := w.UpdateEvent(); err != nil {
|
|
|
|
+ c.Error(err, "update event")
|
|
|
|
+ return
|
|
|
|
+ } else if err := db.CreateWebhook(w); err != nil {
|
|
|
|
+ c.Error(err, "create webhook")
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- c.Data["BaseLink"] = orCtx.Link
|
|
|
|
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
|
|
+ c.Flash.Success(c.Tr("repo.settings.add_hook_success"))
|
|
|
|
+ c.Redirect(orCtx.Link + "/settings/hooks")
|
|
}
|
|
}
|
|
|
|
|
|
-func ParseHookEvent(f form.Webhook) *db.HookEvent {
|
|
|
|
|
|
+func toHookEvent(f form.Webhook) *db.HookEvent {
|
|
return &db.HookEvent{
|
|
return &db.HookEvent{
|
|
PushOnly: f.PushOnly(),
|
|
PushOnly: f.PushOnly(),
|
|
SendEverything: f.SendEverything(),
|
|
SendEverything: f.SendEverything(),
|
|
@@ -123,25 +197,12 @@ func ParseHookEvent(f form.Webhook) *db.HookEvent {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-func WebHooksNewPost(c *context.Context, f form.NewWebhook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings.add_webhook")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksNew"] = true
|
|
|
|
- c.Data["Webhook"] = db.Webhook{HookEvent: &db.HookEvent{}}
|
|
|
|
|
|
+func WebhooksNewPost(c *context.Context, orCtx *orgRepoContext, f form.NewWebhook) {
|
|
|
|
+ c.Title("repo.settings.add_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksNew")
|
|
c.Data["HookType"] = "gogs"
|
|
c.Data["HookType"] = "gogs"
|
|
|
|
|
|
- orCtx, err := getOrgRepoCtx(c)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get organization repository context")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
- c.Data["BaseLink"] = orCtx.Link
|
|
|
|
-
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
contentType := db.JSON
|
|
contentType := db.JSON
|
|
if db.HookContentType(f.ContentType) == db.FORM {
|
|
if db.HookContentType(f.ContentType) == db.FORM {
|
|
contentType = db.FORM
|
|
contentType = db.FORM
|
|
@@ -149,49 +210,32 @@ func WebHooksNewPost(c *context.Context, f form.NewWebhook) {
|
|
|
|
|
|
w := &db.Webhook{
|
|
w := &db.Webhook{
|
|
RepoID: orCtx.RepoID,
|
|
RepoID: orCtx.RepoID,
|
|
|
|
+ OrgID: orCtx.OrgID,
|
|
URL: f.PayloadURL,
|
|
URL: f.PayloadURL,
|
|
ContentType: contentType,
|
|
ContentType: contentType,
|
|
Secret: f.Secret,
|
|
Secret: f.Secret,
|
|
- HookEvent: ParseHookEvent(f.Webhook),
|
|
|
|
|
|
+ HookEvent: toHookEvent(f.Webhook),
|
|
IsActive: f.Active,
|
|
IsActive: f.Active,
|
|
HookTaskType: db.GOGS,
|
|
HookTaskType: db.GOGS,
|
|
- OrgID: orCtx.OrgID,
|
|
|
|
}
|
|
}
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.CreateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "create webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.add_hook_success"))
|
|
|
|
- c.Redirect(orCtx.Link + "/settings/hooks")
|
|
|
|
|
|
+ validateAndCreateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
-func SlackHooksNewPost(c *context.Context, f form.NewSlackHook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksNew"] = true
|
|
|
|
- c.Data["Webhook"] = db.Webhook{HookEvent: &db.HookEvent{}}
|
|
|
|
-
|
|
|
|
- orCtx, err := getOrgRepoCtx(c)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get organization repository context")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
|
|
+func WebhooksSlackNewPost(c *context.Context, orCtx *orgRepoContext, f form.NewSlackHook) {
|
|
|
|
+ c.Title("repo.settings.add_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksNew")
|
|
|
|
+ c.Data["HookType"] = "slack"
|
|
|
|
|
|
- meta, err := jsoniter.Marshal(&db.SlackMeta{
|
|
|
|
|
|
+ meta := &db.SlackMeta{
|
|
Channel: f.Channel,
|
|
Channel: f.Channel,
|
|
Username: f.Username,
|
|
Username: f.Username,
|
|
IconURL: f.IconURL,
|
|
IconURL: f.IconURL,
|
|
Color: f.Color,
|
|
Color: f.Color,
|
|
- })
|
|
|
|
|
|
+ }
|
|
|
|
+ c.Data["SlackMeta"] = meta
|
|
|
|
+
|
|
|
|
+ p, err := jsoniter.Marshal(meta)
|
|
if err != nil {
|
|
if err != nil {
|
|
c.Error(err, "marshal JSON")
|
|
c.Error(err, "marshal JSON")
|
|
return
|
|
return
|
|
@@ -201,47 +245,29 @@ func SlackHooksNewPost(c *context.Context, f form.NewSlackHook) {
|
|
RepoID: orCtx.RepoID,
|
|
RepoID: orCtx.RepoID,
|
|
URL: f.PayloadURL,
|
|
URL: f.PayloadURL,
|
|
ContentType: db.JSON,
|
|
ContentType: db.JSON,
|
|
- HookEvent: ParseHookEvent(f.Webhook),
|
|
|
|
|
|
+ HookEvent: toHookEvent(f.Webhook),
|
|
IsActive: f.Active,
|
|
IsActive: f.Active,
|
|
HookTaskType: db.SLACK,
|
|
HookTaskType: db.SLACK,
|
|
- Meta: string(meta),
|
|
|
|
|
|
+ Meta: string(p),
|
|
OrgID: orCtx.OrgID,
|
|
OrgID: orCtx.OrgID,
|
|
}
|
|
}
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.CreateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "create webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.add_hook_success"))
|
|
|
|
- c.Redirect(orCtx.Link + "/settings/hooks")
|
|
|
|
|
|
+ validateAndCreateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
-// FIXME: merge logic to Slack
|
|
|
|
-func DiscordHooksNewPost(c *context.Context, f form.NewDiscordHook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksNew"] = true
|
|
|
|
- c.Data["Webhook"] = db.Webhook{HookEvent: &db.HookEvent{}}
|
|
|
|
|
|
+func WebhooksDiscordNewPost(c *context.Context, orCtx *orgRepoContext, f form.NewDiscordHook) {
|
|
|
|
+ c.Title("repo.settings.add_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksNew")
|
|
|
|
+ c.Data["HookType"] = "discord"
|
|
|
|
|
|
- orCtx, err := getOrgRepoCtx(c)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get organization repository context")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- meta, err := jsoniter.Marshal(&db.SlackMeta{
|
|
|
|
|
|
+ meta := &db.SlackMeta{
|
|
Username: f.Username,
|
|
Username: f.Username,
|
|
IconURL: f.IconURL,
|
|
IconURL: f.IconURL,
|
|
Color: f.Color,
|
|
Color: f.Color,
|
|
- })
|
|
|
|
|
|
+ }
|
|
|
|
+ c.Data["SlackMeta"] = meta
|
|
|
|
+
|
|
|
|
+ p, err := jsoniter.Marshal(meta)
|
|
if err != nil {
|
|
if err != nil {
|
|
c.Error(err, "marshal JSON")
|
|
c.Error(err, "marshal JSON")
|
|
return
|
|
return
|
|
@@ -251,72 +277,37 @@ func DiscordHooksNewPost(c *context.Context, f form.NewDiscordHook) {
|
|
RepoID: orCtx.RepoID,
|
|
RepoID: orCtx.RepoID,
|
|
URL: f.PayloadURL,
|
|
URL: f.PayloadURL,
|
|
ContentType: db.JSON,
|
|
ContentType: db.JSON,
|
|
- HookEvent: ParseHookEvent(f.Webhook),
|
|
|
|
|
|
+ HookEvent: toHookEvent(f.Webhook),
|
|
IsActive: f.Active,
|
|
IsActive: f.Active,
|
|
HookTaskType: db.DISCORD,
|
|
HookTaskType: db.DISCORD,
|
|
- Meta: string(meta),
|
|
|
|
|
|
+ Meta: string(p),
|
|
OrgID: orCtx.OrgID,
|
|
OrgID: orCtx.OrgID,
|
|
}
|
|
}
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.CreateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "create webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.add_hook_success"))
|
|
|
|
- c.Redirect(orCtx.Link + "/settings/hooks")
|
|
|
|
|
|
+ validateAndCreateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
-func DingtalkHooksNewPost(c *context.Context, f form.NewDingtalkHook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksNew"] = true
|
|
|
|
- c.Data["Webhook"] = db.Webhook{HookEvent: &db.HookEvent{}}
|
|
|
|
-
|
|
|
|
- orCtx, err := getOrgRepoCtx(c)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get organization repository context")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
|
|
+func WebhooksDingtalkNewPost(c *context.Context, orCtx *orgRepoContext, f form.NewDingtalkHook) {
|
|
|
|
+ c.Title("repo.settings.add_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksNew")
|
|
|
|
+ c.Data["HookType"] = "dingtalk"
|
|
|
|
|
|
w := &db.Webhook{
|
|
w := &db.Webhook{
|
|
RepoID: orCtx.RepoID,
|
|
RepoID: orCtx.RepoID,
|
|
URL: f.PayloadURL,
|
|
URL: f.PayloadURL,
|
|
ContentType: db.JSON,
|
|
ContentType: db.JSON,
|
|
- HookEvent: ParseHookEvent(f.Webhook),
|
|
|
|
|
|
+ HookEvent: toHookEvent(f.Webhook),
|
|
IsActive: f.Active,
|
|
IsActive: f.Active,
|
|
HookTaskType: db.DINGTALK,
|
|
HookTaskType: db.DINGTALK,
|
|
OrgID: orCtx.OrgID,
|
|
OrgID: orCtx.OrgID,
|
|
}
|
|
}
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.CreateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "create webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.add_hook_success"))
|
|
|
|
- c.Redirect(orCtx.Link + "/settings/hooks")
|
|
|
|
|
|
+ validateAndCreateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
-func checkWebhook(c *context.Context) (*OrgRepoCtx, *db.Webhook) {
|
|
|
|
- c.Data["RequireHighlightJS"] = true
|
|
|
|
-
|
|
|
|
- orCtx, err := getOrgRepoCtx(c)
|
|
|
|
- if err != nil {
|
|
|
|
- c.Error(err, "get organization repository context")
|
|
|
|
- return nil, nil
|
|
|
|
- }
|
|
|
|
- c.Data["BaseLink"] = orCtx.Link
|
|
|
|
|
|
+func loadWebhook(c *context.Context, orCtx *orgRepoContext) *db.Webhook {
|
|
|
|
+ c.RequireHighlightJS()
|
|
|
|
|
|
|
|
+ var err error
|
|
var w *db.Webhook
|
|
var w *db.Webhook
|
|
if orCtx.RepoID > 0 {
|
|
if orCtx.RepoID > 0 {
|
|
w, err = db.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id"))
|
|
w, err = db.GetWebhookOfRepoByID(c.Repo.Repository.ID, c.ParamsInt64(":id"))
|
|
@@ -325,70 +316,61 @@ func checkWebhook(c *context.Context) (*OrgRepoCtx, *db.Webhook) {
|
|
}
|
|
}
|
|
if err != nil {
|
|
if err != nil {
|
|
c.NotFoundOrError(err, "get webhook")
|
|
c.NotFoundOrError(err, "get webhook")
|
|
- return nil, nil
|
|
|
|
|
|
+ return nil
|
|
}
|
|
}
|
|
|
|
+ c.Data["Webhook"] = w
|
|
|
|
|
|
switch w.HookTaskType {
|
|
switch w.HookTaskType {
|
|
case db.SLACK:
|
|
case db.SLACK:
|
|
- c.Data["SlackHook"] = w.GetSlackHook()
|
|
|
|
|
|
+ c.Data["SlackMeta"] = w.SlackMeta()
|
|
c.Data["HookType"] = "slack"
|
|
c.Data["HookType"] = "slack"
|
|
case db.DISCORD:
|
|
case db.DISCORD:
|
|
- c.Data["SlackHook"] = w.GetSlackHook()
|
|
|
|
|
|
+ c.Data["SlackMeta"] = w.SlackMeta()
|
|
c.Data["HookType"] = "discord"
|
|
c.Data["HookType"] = "discord"
|
|
case db.DINGTALK:
|
|
case db.DINGTALK:
|
|
c.Data["HookType"] = "dingtalk"
|
|
c.Data["HookType"] = "dingtalk"
|
|
default:
|
|
default:
|
|
c.Data["HookType"] = "gogs"
|
|
c.Data["HookType"] = "gogs"
|
|
}
|
|
}
|
|
|
|
+ c.Data["FormURL"] = fmt.Sprintf("%s/settings/hooks/%s/%d", orCtx.Link, c.Data["HookType"], w.ID)
|
|
|
|
+ c.Data["DeleteURL"] = fmt.Sprintf("%s/settings/hooks/delete", orCtx.Link)
|
|
|
|
|
|
c.Data["History"], err = w.History(1)
|
|
c.Data["History"], err = w.History(1)
|
|
if err != nil {
|
|
if err != nil {
|
|
c.Error(err, "get history")
|
|
c.Error(err, "get history")
|
|
- return nil, nil
|
|
|
|
|
|
+ return nil
|
|
}
|
|
}
|
|
- return orCtx, w
|
|
|
|
|
|
+ return w
|
|
}
|
|
}
|
|
|
|
|
|
-func WebHooksEdit(c *context.Context) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings.update_webhook")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksEdit"] = true
|
|
|
|
|
|
+func WebhooksEdit(c *context.Context, orCtx *orgRepoContext) {
|
|
|
|
+ c.Title("repo.settings.update_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksEdit")
|
|
|
|
|
|
- orCtx, w := checkWebhook(c)
|
|
|
|
|
|
+ loadWebhook(c, orCtx)
|
|
if c.Written() {
|
|
if c.Written() {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- c.Data["Webhook"] = w
|
|
|
|
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
|
|
+ c.Success(orCtx.TmplNew)
|
|
}
|
|
}
|
|
|
|
|
|
-func WebHooksEditPost(c *context.Context, f form.NewWebhook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings.update_webhook")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksEdit"] = true
|
|
|
|
-
|
|
|
|
- orCtx, w := checkWebhook(c)
|
|
|
|
- if c.Written() {
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
|
|
+func validateAndUpdateWebhook(c *context.Context, orCtx *orgRepoContext, w *db.Webhook) {
|
|
c.Data["Webhook"] = w
|
|
c.Data["Webhook"] = w
|
|
|
|
|
|
if c.HasError() {
|
|
if c.HasError() {
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
|
|
+ c.Success(orCtx.TmplNew)
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
- contentType := db.JSON
|
|
|
|
- if db.HookContentType(f.ContentType) == db.FORM {
|
|
|
|
- contentType = db.FORM
|
|
|
|
|
|
+ field, msg, ok := validateWebhook(c.User, c.Locale, w)
|
|
|
|
+ if !ok {
|
|
|
|
+ c.FormErr(field)
|
|
|
|
+ c.RenderWithErr(msg, orCtx.TmplNew, nil)
|
|
|
|
+ return
|
|
}
|
|
}
|
|
|
|
|
|
- w.URL = f.PayloadURL
|
|
|
|
- w.ContentType = contentType
|
|
|
|
- w.Secret = f.Secret
|
|
|
|
- w.HookEvent = ParseHookEvent(f.Webhook)
|
|
|
|
- w.IsActive = f.Active
|
|
|
|
if err := w.UpdateEvent(); err != nil {
|
|
if err := w.UpdateEvent(); err != nil {
|
|
c.Error(err, "update event")
|
|
c.Error(err, "update event")
|
|
return
|
|
return
|
|
@@ -401,19 +383,36 @@ func WebHooksEditPost(c *context.Context, f form.NewWebhook) {
|
|
c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
|
|
c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
|
|
}
|
|
}
|
|
|
|
|
|
-func SlackHooksEditPost(c *context.Context, f form.NewSlackHook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksEdit"] = true
|
|
|
|
|
|
+func WebhooksEditPost(c *context.Context, orCtx *orgRepoContext, f form.NewWebhook) {
|
|
|
|
+ c.Title("repo.settings.update_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksEdit")
|
|
|
|
|
|
- orCtx, w := checkWebhook(c)
|
|
|
|
|
|
+ w := loadWebhook(c, orCtx)
|
|
if c.Written() {
|
|
if c.Written() {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- c.Data["Webhook"] = w
|
|
|
|
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
|
|
+ contentType := db.JSON
|
|
|
|
+ if db.HookContentType(f.ContentType) == db.FORM {
|
|
|
|
+ contentType = db.FORM
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ w.URL = f.PayloadURL
|
|
|
|
+ w.ContentType = contentType
|
|
|
|
+ w.Secret = f.Secret
|
|
|
|
+ w.HookEvent = toHookEvent(f.Webhook)
|
|
|
|
+ w.IsActive = f.Active
|
|
|
|
+ validateAndUpdateWebhook(c, orCtx, w)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func WebhooksSlackEditPost(c *context.Context, orCtx *orgRepoContext, f form.NewSlackHook) {
|
|
|
|
+ c.Title("repo.settings.update_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksEdit")
|
|
|
|
+
|
|
|
|
+ w := loadWebhook(c, orCtx)
|
|
|
|
+ if c.Written() {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
|
|
|
|
@@ -430,36 +429,20 @@ func SlackHooksEditPost(c *context.Context, f form.NewSlackHook) {
|
|
|
|
|
|
w.URL = f.PayloadURL
|
|
w.URL = f.PayloadURL
|
|
w.Meta = string(meta)
|
|
w.Meta = string(meta)
|
|
- w.HookEvent = ParseHookEvent(f.Webhook)
|
|
|
|
|
|
+ w.HookEvent = toHookEvent(f.Webhook)
|
|
w.IsActive = f.Active
|
|
w.IsActive = f.Active
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.UpdateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "update webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.update_hook_success"))
|
|
|
|
- c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
|
|
|
|
|
|
+ validateAndUpdateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
-// FIXME: merge logic to Slack
|
|
|
|
-func DiscordHooksEditPost(c *context.Context, f form.NewDiscordHook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksEdit"] = true
|
|
|
|
|
|
+func WebhooksDiscordEditPost(c *context.Context, orCtx *orgRepoContext, f form.NewDiscordHook) {
|
|
|
|
+ c.Title("repo.settings.update_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksEdit")
|
|
|
|
|
|
- orCtx, w := checkWebhook(c)
|
|
|
|
|
|
+ w := loadWebhook(c, orCtx)
|
|
if c.Written() {
|
|
if c.Written() {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- c.Data["Webhook"] = w
|
|
|
|
-
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
|
|
|
|
meta, err := jsoniter.Marshal(&db.SlackMeta{
|
|
meta, err := jsoniter.Marshal(&db.SlackMeta{
|
|
Username: f.Username,
|
|
Username: f.Username,
|
|
@@ -473,53 +456,28 @@ func DiscordHooksEditPost(c *context.Context, f form.NewDiscordHook) {
|
|
|
|
|
|
w.URL = f.PayloadURL
|
|
w.URL = f.PayloadURL
|
|
w.Meta = string(meta)
|
|
w.Meta = string(meta)
|
|
- w.HookEvent = ParseHookEvent(f.Webhook)
|
|
|
|
|
|
+ w.HookEvent = toHookEvent(f.Webhook)
|
|
w.IsActive = f.Active
|
|
w.IsActive = f.Active
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.UpdateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "update webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.update_hook_success"))
|
|
|
|
- c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
|
|
|
|
|
|
+ validateAndUpdateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
-func DingtalkHooksEditPost(c *context.Context, f form.NewDingtalkHook) {
|
|
|
|
- c.Data["Title"] = c.Tr("repo.settings")
|
|
|
|
- c.Data["PageIsSettingsHooks"] = true
|
|
|
|
- c.Data["PageIsSettingsHooksEdit"] = true
|
|
|
|
|
|
+func WebhooksDingtalkEditPost(c *context.Context, orCtx *orgRepoContext, f form.NewDingtalkHook) {
|
|
|
|
+ c.Title("repo.settings.update_webhook")
|
|
|
|
+ c.PageIs("SettingsHooks")
|
|
|
|
+ c.PageIs("SettingsHooksEdit")
|
|
|
|
|
|
- orCtx, w := checkWebhook(c)
|
|
|
|
|
|
+ w := loadWebhook(c, orCtx)
|
|
if c.Written() {
|
|
if c.Written() {
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- c.Data["Webhook"] = w
|
|
|
|
-
|
|
|
|
- if c.HasError() {
|
|
|
|
- c.Success(orCtx.NewTemplate)
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
|
|
|
|
w.URL = f.PayloadURL
|
|
w.URL = f.PayloadURL
|
|
- w.HookEvent = ParseHookEvent(f.Webhook)
|
|
|
|
|
|
+ w.HookEvent = toHookEvent(f.Webhook)
|
|
w.IsActive = f.Active
|
|
w.IsActive = f.Active
|
|
- if err := w.UpdateEvent(); err != nil {
|
|
|
|
- c.Error(err, "update event")
|
|
|
|
- return
|
|
|
|
- } else if err := db.UpdateWebhook(w); err != nil {
|
|
|
|
- c.Error(err, "update webhook")
|
|
|
|
- return
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- c.Flash.Success(c.Tr("repo.settings.update_hook_success"))
|
|
|
|
- c.Redirect(fmt.Sprintf("%s/settings/hooks/%d", orCtx.Link, w.ID))
|
|
|
|
|
|
+ validateAndUpdateWebhook(c, orCtx, w)
|
|
}
|
|
}
|
|
|
|
|
|
func TestWebhook(c *context.Context) {
|
|
func TestWebhook(c *context.Context) {
|
|
-
|
|
|
|
var (
|
|
var (
|
|
commitID string
|
|
commitID string
|
|
commitMessage string
|
|
commitMessage string
|
|
@@ -634,14 +592,20 @@ func RedeliveryWebhook(c *context.Context) {
|
|
c.Status(http.StatusOK)
|
|
c.Status(http.StatusOK)
|
|
}
|
|
}
|
|
|
|
|
|
-func DeleteWebhook(c *context.Context) {
|
|
|
|
- if err := db.DeleteWebhookOfRepoByID(c.Repo.Repository.ID, c.QueryInt64("id")); err != nil {
|
|
|
|
- c.Flash.Error("DeleteWebhookByRepoID: " + err.Error())
|
|
|
|
|
|
+func DeleteWebhook(c *context.Context, orCtx *orgRepoContext) {
|
|
|
|
+ var err error
|
|
|
|
+ if orCtx.RepoID > 0 {
|
|
|
|
+ err = db.DeleteWebhookOfRepoByID(orCtx.RepoID, c.QueryInt64("id"))
|
|
} else {
|
|
} else {
|
|
- c.Flash.Success(c.Tr("repo.settings.webhook_deletion_success"))
|
|
|
|
|
|
+ err = db.DeleteWebhookOfOrgByID(orCtx.OrgID, c.QueryInt64("id"))
|
|
|
|
+ }
|
|
|
|
+ if err != nil {
|
|
|
|
+ c.Error(err, "delete webhook")
|
|
|
|
+ return
|
|
}
|
|
}
|
|
|
|
+ c.Flash.Success(c.Tr("repo.settings.webhook_deletion_success"))
|
|
|
|
|
|
c.JSONSuccess(map[string]interface{}{
|
|
c.JSONSuccess(map[string]interface{}{
|
|
- "redirect": c.Repo.RepoLink + "/settings/hooks",
|
|
|
|
|
|
+ "redirect": orCtx.Link + "/settings/hooks",
|
|
})
|
|
})
|
|
}
|
|
}
|