System-wide webhooks (#10546)
* Create system webhook column (and migration) * Create system webhook DB methods Based on the default webhook ones * Modify router to handle system webhooks and default ones * Remove old unused admin nav template * Adjust orgRepoCtx to differentiate system and default webhook URLs * Assign IsSystemWebhook when creating webhooks * Correctly use booleans for IsSystemWebhook * Use system webhooks when preparing webhooks for payload * Add UI and locale changes * Use router params to differentiate admin hook pages * Fix deleting admin webhooks and rename method * Add clarity to webhook docs * Revert "Remove old unused admin nav template" This reverts commit 191a20a7389fe5f6256b0ad6aafd04b9b0e295c5. * Rename WebHooksNewPost to GiteaHooksNewPost for clarity * Reintroduce blank line lost during merge conflict Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Co-authored-by: Lauris BH <lauris@nix.lv>
This commit is contained in:
		
							parent
							
								
									b8551f8532
								
							
						
					
					
						commit
						a9f4489bbc
					
				
					 10 changed files with 232 additions and 122 deletions
				
			
		|  | @ -15,24 +15,24 @@ menu: | ||||||
| 
 | 
 | ||||||
| # Webhooks | # Webhooks | ||||||
| 
 | 
 | ||||||
| Gitea supports web hooks for repository events. This can be found in the settings | Gitea supports web hooks for repository events. This can be configured in the settings | ||||||
| page `/:username/:reponame/settings/hooks`. All event pushes are POST requests. | page `/:username/:reponame/settings/hooks` by a repository admin. Webhooks can also be configured on a per-organization and whole system basis. | ||||||
| The methods currently supported are: | All event pushes are POST requests. The methods currently supported are: | ||||||
| 
 | 
 | ||||||
| - Gitea | - Gitea (can also be a GET request) | ||||||
| - Gogs | - Gogs | ||||||
| - Slack | - Slack | ||||||
| - Discord | - Discord | ||||||
| - Dingtalk | - Dingtalk | ||||||
| - Telegram | - Telegram | ||||||
| - Microsoft Teams | - Microsoft Teams | ||||||
|  | - Feishu | ||||||
| 
 | 
 | ||||||
| ### Event information | ### Event information | ||||||
| 
 | 
 | ||||||
| The following is an example of event information that will be sent by Gitea to | The following is an example of event information that will be sent by Gitea to | ||||||
| a Payload URL: | a Payload URL: | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| ``` | ``` | ||||||
| X-GitHub-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473 | X-GitHub-Delivery: f6266f16-1bf3-46a5-9ea4-602e06ead473 | ||||||
| X-GitHub-Event: push | X-GitHub-Event: push | ||||||
|  |  | ||||||
|  | @ -194,6 +194,8 @@ var migrations = []Migration{ | ||||||
| 	NewMigration("remove dependencies from deleted repositories", purgeUnusedDependencies), | 	NewMigration("remove dependencies from deleted repositories", purgeUnusedDependencies), | ||||||
| 	// v130 -> v131
 | 	// v130 -> v131
 | ||||||
| 	NewMigration("Expand webhooks for more granularity", expandWebhooks), | 	NewMigration("Expand webhooks for more granularity", expandWebhooks), | ||||||
|  | 	// v131 -> v132
 | ||||||
|  | 	NewMigration("Add IsSystemWebhook column to webhooks table", addSystemWebhookColumn), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Migrate database to current version
 | // Migrate database to current version
 | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								models/migrations/v131.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								models/migrations/v131.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,22 @@ | ||||||
|  | // Copyright 2020 The Gitea 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 migrations | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"fmt" | ||||||
|  | 
 | ||||||
|  | 	"xorm.io/xorm" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func addSystemWebhookColumn(x *xorm.Engine) error { | ||||||
|  | 	type Webhook struct { | ||||||
|  | 		IsSystemWebhook bool `xorm:"NOT NULL DEFAULT false"` | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if err := x.Sync2(new(Webhook)); err != nil { | ||||||
|  | 		return fmt.Errorf("Sync2: %v", err) | ||||||
|  | 	} | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | @ -99,21 +99,22 @@ const ( | ||||||
| 
 | 
 | ||||||
| // Webhook represents a web hook object.
 | // Webhook represents a web hook object.
 | ||||||
| type Webhook struct { | type Webhook struct { | ||||||
| 	ID           int64  `xorm:"pk autoincr"` | 	ID              int64 `xorm:"pk autoincr"` | ||||||
| 	RepoID       int64  `xorm:"INDEX"` | 	RepoID          int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook
 | ||||||
| 	OrgID        int64  `xorm:"INDEX"` | 	OrgID           int64 `xorm:"INDEX"` | ||||||
| 	URL          string `xorm:"url TEXT"` | 	IsSystemWebhook bool | ||||||
| 	Signature    string `xorm:"TEXT"` | 	URL             string `xorm:"url TEXT"` | ||||||
| 	HTTPMethod   string `xorm:"http_method"` | 	Signature       string `xorm:"TEXT"` | ||||||
| 	ContentType  HookContentType | 	HTTPMethod      string `xorm:"http_method"` | ||||||
| 	Secret       string `xorm:"TEXT"` | 	ContentType     HookContentType | ||||||
| 	Events       string `xorm:"TEXT"` | 	Secret          string `xorm:"TEXT"` | ||||||
| 	*HookEvent   `xorm:"-"` | 	Events          string `xorm:"TEXT"` | ||||||
| 	IsSSL        bool `xorm:"is_ssl"` | 	*HookEvent      `xorm:"-"` | ||||||
| 	IsActive     bool `xorm:"INDEX"` | 	IsSSL           bool `xorm:"is_ssl"` | ||||||
| 	HookTaskType HookTaskType | 	IsActive        bool `xorm:"INDEX"` | ||||||
| 	Meta         string     `xorm:"TEXT"` // store hook-specific attributes
 | 	HookTaskType    HookTaskType | ||||||
| 	LastStatus   HookStatus // Last delivery status
 | 	Meta            string     `xorm:"TEXT"` // store hook-specific attributes
 | ||||||
|  | 	LastStatus      HookStatus // Last delivery status
 | ||||||
| 
 | 
 | ||||||
| 	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | 	CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` | ||||||
| 	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | 	UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` | ||||||
|  | @ -401,7 +402,7 @@ func GetWebhooksByOrgID(orgID int64, listOptions ListOptions) ([]*Webhook, error | ||||||
| func GetDefaultWebhook(id int64) (*Webhook, error) { | func GetDefaultWebhook(id int64) (*Webhook, error) { | ||||||
| 	webhook := &Webhook{ID: id} | 	webhook := &Webhook{ID: id} | ||||||
| 	has, err := x. | 	has, err := x. | ||||||
| 		Where("repo_id=? AND org_id=?", 0, 0). | 		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). | ||||||
| 		Get(webhook) | 		Get(webhook) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return nil, err | 		return nil, err | ||||||
|  | @ -419,7 +420,33 @@ func GetDefaultWebhooks() ([]*Webhook, error) { | ||||||
| func getDefaultWebhooks(e Engine) ([]*Webhook, error) { | func getDefaultWebhooks(e Engine) ([]*Webhook, error) { | ||||||
| 	webhooks := make([]*Webhook, 0, 5) | 	webhooks := make([]*Webhook, 0, 5) | ||||||
| 	return webhooks, e. | 	return webhooks, e. | ||||||
| 		Where("repo_id=? AND org_id=?", 0, 0). | 		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). | ||||||
|  | 		Find(&webhooks) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetSystemWebhook returns admin system webhook by given ID.
 | ||||||
|  | func GetSystemWebhook(id int64) (*Webhook, error) { | ||||||
|  | 	webhook := &Webhook{ID: id} | ||||||
|  | 	has, err := x. | ||||||
|  | 		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). | ||||||
|  | 		Get(webhook) | ||||||
|  | 	if err != nil { | ||||||
|  | 		return nil, err | ||||||
|  | 	} else if !has { | ||||||
|  | 		return nil, ErrWebhookNotExist{id} | ||||||
|  | 	} | ||||||
|  | 	return webhook, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // GetSystemWebhooks returns all admin system webhooks.
 | ||||||
|  | func GetSystemWebhooks() ([]*Webhook, error) { | ||||||
|  | 	return getSystemWebhooks(x) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func getSystemWebhooks(e Engine) ([]*Webhook, error) { | ||||||
|  | 	webhooks := make([]*Webhook, 0, 5) | ||||||
|  | 	return webhooks, e. | ||||||
|  | 		Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). | ||||||
| 		Find(&webhooks) | 		Find(&webhooks) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -471,8 +498,8 @@ func DeleteWebhookByOrgID(orgID, id int64) error { | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DeleteDefaultWebhook deletes an admin-default webhook by given ID.
 | // DeleteDefaultSystemWebhook deletes an admin-configured default or system webhook (where Org and Repo ID both 0)
 | ||||||
| func DeleteDefaultWebhook(id int64) error { | func DeleteDefaultSystemWebhook(id int64) error { | ||||||
| 	sess := x.NewSession() | 	sess := x.NewSession() | ||||||
| 	defer sess.Close() | 	defer sess.Close() | ||||||
| 	if err := sess.Begin(); err != nil { | 	if err := sess.Begin(); err != nil { | ||||||
|  |  | ||||||
|  | @ -181,6 +181,13 @@ func prepareWebhooks(repo *models.Repository, event models.HookEventType, p api. | ||||||
| 		ws = append(ws, orgHooks...) | 		ws = append(ws, orgHooks...) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	// Add any admin-defined system webhooks
 | ||||||
|  | 	systemHooks, err := models.GetSystemWebhooks() | ||||||
|  | 	if err != nil { | ||||||
|  | 		return fmt.Errorf("GetSystemWebhooks: %v", err) | ||||||
|  | 	} | ||||||
|  | 	ws = append(ws, systemHooks...) | ||||||
|  | 
 | ||||||
| 	if len(ws) == 0 { | 	if len(ws) == 0 { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -1753,6 +1753,7 @@ users = User Accounts | ||||||
| organizations = Organizations | organizations = Organizations | ||||||
| repositories = Repositories | repositories = Repositories | ||||||
| hooks = Default Webhooks | hooks = Default Webhooks | ||||||
|  | systemhooks = System Webhooks | ||||||
| authentication = Authentication Sources | authentication = Authentication Sources | ||||||
| emails = User Emails | emails = User Emails | ||||||
| config = Configuration | config = Configuration | ||||||
|  | @ -1889,6 +1890,10 @@ hooks.desc = Webhooks automatically make HTTP POST requests to a server when cer | ||||||
| hooks.add_webhook = Add Default Webhook | hooks.add_webhook = Add Default Webhook | ||||||
| hooks.update_webhook = Update Default Webhook | hooks.update_webhook = Update Default Webhook | ||||||
| 
 | 
 | ||||||
|  | systemhooks.desc = Webhooks automatically make HTTP POST requests to a server when certain Gitea events trigger. Webhooks defined will act on all repositories on the system, so please consider any performance implications this may have. Read more in the <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">webhooks guide</a>. | ||||||
|  | systemhooks.add_webhook = Add System Webhook | ||||||
|  | systemhooks.update_webhook = Update System Webhook | ||||||
|  | 
 | ||||||
| auths.auth_manage_panel = Authentication Source Management | auths.auth_manage_panel = Authentication Source Management | ||||||
| auths.new = Add Authentication Source | auths.new = Add Authentication Source | ||||||
| auths.name = Name | auths.name = Name | ||||||
|  |  | ||||||
|  | @ -12,20 +12,32 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	// tplAdminHooks template path for render hook settings
 | 	// tplAdminHooks template path to render hook settings
 | ||||||
| 	tplAdminHooks base.TplName = "admin/hooks" | 	tplAdminHooks base.TplName = "admin/hooks" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // DefaultWebhooks render admin-default webhook list page
 | // DefaultOrSystemWebhooks renders both admin default and system webhook list pages
 | ||||||
| func DefaultWebhooks(ctx *context.Context) { | func DefaultOrSystemWebhooks(ctx *context.Context) { | ||||||
| 	ctx.Data["Title"] = ctx.Tr("admin.hooks") | 	var ws []*models.Webhook | ||||||
| 	ctx.Data["PageIsAdminHooks"] = true | 	var err error | ||||||
| 	ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks" | 
 | ||||||
| 	ctx.Data["Description"] = ctx.Tr("admin.hooks.desc") | 	// Are we looking at default webhooks?
 | ||||||
|  | 	if ctx.Params(":configType") == "hooks" { | ||||||
|  | 		ctx.Data["Title"] = ctx.Tr("admin.hooks") | ||||||
|  | 		ctx.Data["Description"] = ctx.Tr("admin.hooks.desc") | ||||||
|  | 		ctx.Data["PageIsAdminHooks"] = true | ||||||
|  | 		ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/hooks" | ||||||
|  | 		ws, err = models.GetDefaultWebhooks() | ||||||
|  | 	} else { | ||||||
|  | 		ctx.Data["Title"] = ctx.Tr("admin.systemhooks") | ||||||
|  | 		ctx.Data["Description"] = ctx.Tr("admin.systemhooks.desc") | ||||||
|  | 		ctx.Data["PageIsAdminSystemHooks"] = true | ||||||
|  | 		ctx.Data["BaseLink"] = setting.AppSubURL + "/admin/system-hooks" | ||||||
|  | 		ws, err = models.GetSystemWebhooks() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	ws, err := models.GetDefaultWebhooks() |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		ctx.ServerError("GetWebhooksDefaults", err) | 		ctx.ServerError("GetWebhooksAdmin", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -33,15 +45,22 @@ func DefaultWebhooks(ctx *context.Context) { | ||||||
| 	ctx.HTML(200, tplAdminHooks) | 	ctx.HTML(200, tplAdminHooks) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // DeleteDefaultWebhook response for delete admin-default webhook
 | // DeleteDefaultOrSystemWebhook handler to delete an admin-defined system or default webhook
 | ||||||
| func DeleteDefaultWebhook(ctx *context.Context) { | func DeleteDefaultOrSystemWebhook(ctx *context.Context) { | ||||||
| 	if err := models.DeleteDefaultWebhook(ctx.QueryInt64("id")); err != nil { | 	if err := models.DeleteDefaultSystemWebhook(ctx.QueryInt64("id")); err != nil { | ||||||
| 		ctx.Flash.Error("DeleteDefaultWebhook: " + err.Error()) | 		ctx.Flash.Error("DeleteDefaultWebhook: " + err.Error()) | ||||||
| 	} else { | 	} else { | ||||||
| 		ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) | 		ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ctx.JSON(200, map[string]interface{}{ | 	// Are we looking at default webhooks?
 | ||||||
| 		"redirect": setting.AppSubURL + "/admin/hooks", | 	if ctx.Params(":configType") == "hooks" { | ||||||
| 	}) | 		ctx.JSON(200, map[string]interface{}{ | ||||||
|  | 			"redirect": setting.AppSubURL + "/admin/hooks", | ||||||
|  | 		}) | ||||||
|  | 	} else { | ||||||
|  | 		ctx.JSON(200, map[string]interface{}{ | ||||||
|  | 			"redirect": setting.AppSubURL + "/admin/system-hooks", | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -49,14 +49,15 @@ func Webhooks(ctx *context.Context) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type orgRepoCtx struct { | type orgRepoCtx struct { | ||||||
| 	OrgID       int64 | 	OrgID           int64 | ||||||
| 	RepoID      int64 | 	RepoID          int64 | ||||||
| 	IsAdmin     bool | 	IsAdmin         bool | ||||||
| 	Link        string | 	IsSystemWebhook bool | ||||||
| 	NewTemplate base.TplName | 	Link            string | ||||||
|  | 	NewTemplate     base.TplName | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // getOrgRepoCtx determines whether this is a repo, organization, or admin context.
 | // getOrgRepoCtx determines whether this is a repo, organization, or admin (both default and system) context.
 | ||||||
| func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { | func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { | ||||||
| 	if len(ctx.Repo.RepoLink) > 0 { | 	if len(ctx.Repo.RepoLink) > 0 { | ||||||
| 		return &orgRepoCtx{ | 		return &orgRepoCtx{ | ||||||
|  | @ -75,10 +76,21 @@ func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ctx.User.IsAdmin { | 	if ctx.User.IsAdmin { | ||||||
|  | 		// Are we looking at default webhooks?
 | ||||||
|  | 		if ctx.Params(":configType") == "hooks" { | ||||||
|  | 			return &orgRepoCtx{ | ||||||
|  | 				IsAdmin:     true, | ||||||
|  | 				Link:        path.Join(setting.AppSubURL, "/admin/hooks"), | ||||||
|  | 				NewTemplate: tplAdminHookNew, | ||||||
|  | 			}, nil | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		// Must be system webhooks instead
 | ||||||
| 		return &orgRepoCtx{ | 		return &orgRepoCtx{ | ||||||
| 			IsAdmin:     true, | 			IsAdmin:         true, | ||||||
| 			Link:        path.Join(setting.AppSubURL, "/admin/hooks"), | 			IsSystemWebhook: true, | ||||||
| 			NewTemplate: tplAdminHookNew, | 			Link:            path.Join(setting.AppSubURL, "/admin/system-hooks"), | ||||||
|  | 			NewTemplate:     tplAdminHookNew, | ||||||
| 		}, nil | 		}, nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -105,7 +117,10 @@ func WebhooksNew(ctx *context.Context) { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if orCtx.IsAdmin { | 	if orCtx.IsAdmin && orCtx.IsSystemWebhook { | ||||||
|  | 		ctx.Data["PageIsAdminSystemHooks"] = true | ||||||
|  | 		ctx.Data["PageIsAdminSystemHooksNew"] = true | ||||||
|  | 	} else if orCtx.IsAdmin { | ||||||
| 		ctx.Data["PageIsAdminHooks"] = true | 		ctx.Data["PageIsAdminHooks"] = true | ||||||
| 		ctx.Data["PageIsAdminHooksNew"] = true | 		ctx.Data["PageIsAdminHooksNew"] = true | ||||||
| 	} else { | 	} else { | ||||||
|  | @ -159,8 +174,8 @@ func ParseHookEvent(form auth.WebhookForm) *models.HookEvent { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WebHooksNewPost response for creating webhook
 | // GiteaHooksNewPost response for creating Gitea webhook
 | ||||||
| func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { | func GiteaHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { | ||||||
| 	ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") | 	ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") | ||||||
| 	ctx.Data["PageIsSettingsHooks"] = true | 	ctx.Data["PageIsSettingsHooks"] = true | ||||||
| 	ctx.Data["PageIsSettingsHooksNew"] = true | 	ctx.Data["PageIsSettingsHooksNew"] = true | ||||||
|  | @ -185,15 +200,16 @@ func WebHooksNewPost(ctx *context.Context, form auth.NewWebhookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		HTTPMethod:   form.HTTPMethod, | 		HTTPMethod:      form.HTTPMethod, | ||||||
| 		ContentType:  contentType, | 		ContentType:     contentType, | ||||||
| 		Secret:       form.Secret, | 		Secret:          form.Secret, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.GITEA, | 		HookTaskType:    models.GITEA, | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -238,14 +254,15 @@ func newGogsWebhookPost(ctx *context.Context, form auth.NewGogshookForm, kind mo | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		ContentType:  contentType, | 		ContentType:     contentType, | ||||||
| 		Secret:       form.Secret, | 		Secret:          form.Secret, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: kind, | 		HookTaskType:    kind, | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -287,14 +304,15 @@ func DiscordHooksNewPost(ctx *context.Context, form auth.NewDiscordHookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		ContentType:  models.ContentTypeJSON, | 		ContentType:     models.ContentTypeJSON, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.DISCORD, | 		HookTaskType:    models.DISCORD, | ||||||
| 		Meta:         string(meta), | 		Meta:            string(meta), | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -327,14 +345,15 @@ func DingtalkHooksNewPost(ctx *context.Context, form auth.NewDingtalkHookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		ContentType:  models.ContentTypeJSON, | 		ContentType:     models.ContentTypeJSON, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.DINGTALK, | 		HookTaskType:    models.DINGTALK, | ||||||
| 		Meta:         "", | 		Meta:            "", | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -376,14 +395,15 @@ func TelegramHooksNewPost(ctx *context.Context, form auth.NewTelegramHookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID), | 		URL:             fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", form.BotToken, form.ChatID), | ||||||
| 		ContentType:  models.ContentTypeJSON, | 		ContentType:     models.ContentTypeJSON, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.TELEGRAM, | 		HookTaskType:    models.TELEGRAM, | ||||||
| 		Meta:         string(meta), | 		Meta:            string(meta), | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -416,14 +436,15 @@ func MSTeamsHooksNewPost(ctx *context.Context, form auth.NewMSTeamsHookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		ContentType:  models.ContentTypeJSON, | 		ContentType:     models.ContentTypeJSON, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.MSTEAMS, | 		HookTaskType:    models.MSTEAMS, | ||||||
| 		Meta:         "", | 		Meta:            "", | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -473,14 +494,15 @@ func SlackHooksNewPost(ctx *context.Context, form auth.NewSlackHookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		ContentType:  models.ContentTypeJSON, | 		ContentType:     models.ContentTypeJSON, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.SLACK, | 		HookTaskType:    models.SLACK, | ||||||
| 		Meta:         string(meta), | 		Meta:            string(meta), | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -513,14 +535,15 @@ func FeishuHooksNewPost(ctx *context.Context, form auth.NewFeishuHookForm) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	w := &models.Webhook{ | 	w := &models.Webhook{ | ||||||
| 		RepoID:       orCtx.RepoID, | 		RepoID:          orCtx.RepoID, | ||||||
| 		URL:          form.PayloadURL, | 		URL:             form.PayloadURL, | ||||||
| 		ContentType:  models.ContentTypeJSON, | 		ContentType:     models.ContentTypeJSON, | ||||||
| 		HookEvent:    ParseHookEvent(form.WebhookForm), | 		HookEvent:       ParseHookEvent(form.WebhookForm), | ||||||
| 		IsActive:     form.Active, | 		IsActive:        form.Active, | ||||||
| 		HookTaskType: models.FEISHU, | 		HookTaskType:    models.FEISHU, | ||||||
| 		Meta:         "", | 		Meta:            "", | ||||||
| 		OrgID:        orCtx.OrgID, | 		OrgID:           orCtx.OrgID, | ||||||
|  | 		IsSystemWebhook: orCtx.IsSystemWebhook, | ||||||
| 	} | 	} | ||||||
| 	if err := w.UpdateEvent(); err != nil { | 	if err := w.UpdateEvent(); err != nil { | ||||||
| 		ctx.ServerError("UpdateEvent", err) | 		ctx.ServerError("UpdateEvent", err) | ||||||
|  | @ -549,6 +572,8 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *models.Webhook) { | ||||||
| 		w, err = models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")) | 		w, err = models.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")) | ||||||
| 	} else if orCtx.OrgID > 0 { | 	} else if orCtx.OrgID > 0 { | ||||||
| 		w, err = models.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id")) | 		w, err = models.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id")) | ||||||
|  | 	} else if orCtx.IsSystemWebhook { | ||||||
|  | 		w, err = models.GetSystemWebhook(ctx.ParamsInt64(":id")) | ||||||
| 	} else { | 	} else { | ||||||
| 		w, err = models.GetDefaultWebhook(ctx.ParamsInt64(":id")) | 		w, err = models.GetDefaultWebhook(ctx.ParamsInt64(":id")) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | @ -458,11 +458,11 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||||
| 			m.Post("/delete", admin.DeleteRepo) | 			m.Post("/delete", admin.DeleteRepo) | ||||||
| 		}) | 		}) | ||||||
| 
 | 
 | ||||||
| 		m.Group("/hooks", func() { | 		m.Group("/^:configType(hooks|system-hooks)$", func() { | ||||||
| 			m.Get("", admin.DefaultWebhooks) | 			m.Get("", admin.DefaultOrSystemWebhooks) | ||||||
| 			m.Post("/delete", admin.DeleteDefaultWebhook) | 			m.Post("/delete", admin.DeleteDefaultOrSystemWebhook) | ||||||
| 			m.Get("/:type/new", repo.WebhooksNew) | 			m.Get("/:type/new", repo.WebhooksNew) | ||||||
| 			m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) | 			m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost) | ||||||
| 			m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) | 			m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) | ||||||
| 			m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | 			m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | ||||||
| 			m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | 			m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | ||||||
|  | @ -569,7 +569,7 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||||
| 					m.Get("", org.Webhooks) | 					m.Get("", org.Webhooks) | ||||||
| 					m.Post("/delete", org.DeleteWebhook) | 					m.Post("/delete", org.DeleteWebhook) | ||||||
| 					m.Get("/:type/new", repo.WebhooksNew) | 					m.Get("/:type/new", repo.WebhooksNew) | ||||||
| 					m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) | 					m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost) | ||||||
| 					m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) | 					m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) | ||||||
| 					m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | 					m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | ||||||
| 					m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | 					m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | ||||||
|  | @ -635,7 +635,7 @@ func RegisterRoutes(m *macaron.Macaron) { | ||||||
| 				m.Get("", repo.Webhooks) | 				m.Get("", repo.Webhooks) | ||||||
| 				m.Post("/delete", repo.DeleteWebhook) | 				m.Post("/delete", repo.DeleteWebhook) | ||||||
| 				m.Get("/:type/new", repo.WebhooksNew) | 				m.Get("/:type/new", repo.WebhooksNew) | ||||||
| 				m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.WebHooksNewPost) | 				m.Post("/gitea/new", bindIgnErr(auth.NewWebhookForm{}), repo.GiteaHooksNewPost) | ||||||
| 				m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) | 				m.Post("/gogs/new", bindIgnErr(auth.NewGogshookForm{}), repo.GogsHooksNewPost) | ||||||
| 				m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | 				m.Post("/slack/new", bindIgnErr(auth.NewSlackHookForm{}), repo.SlackHooksNewPost) | ||||||
| 				m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | 				m.Post("/discord/new", bindIgnErr(auth.NewDiscordHookForm{}), repo.DiscordHooksNewPost) | ||||||
|  |  | ||||||
|  | @ -14,6 +14,9 @@ | ||||||
| 	<a class="{{if .PageIsAdminHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks"> | 	<a class="{{if .PageIsAdminHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/hooks"> | ||||||
| 		{{.i18n.Tr "admin.hooks"}} | 		{{.i18n.Tr "admin.hooks"}} | ||||||
| 	</a> | 	</a> | ||||||
|  | 	<a class="{{if .PageIsAdminSystemHooks}}active{{end}} item" href="{{AppSubUrl}}/admin/system-hooks"> | ||||||
|  | 		{{.i18n.Tr "admin.systemhooks"}} | ||||||
|  | 	</a> | ||||||
| 	<a class="{{if .PageIsAdminAuthentications}}active{{end}} item" href="{{AppSubUrl}}/admin/auths"> | 	<a class="{{if .PageIsAdminAuthentications}}active{{end}} item" href="{{AppSubUrl}}/admin/auths"> | ||||||
| 		{{.i18n.Tr "admin.authentication"}} | 		{{.i18n.Tr "admin.authentication"}} | ||||||
| 	</a> | 	</a> | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue