Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add user webhooks #21563

Merged
merged 30 commits into from
Mar 10, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
a3c56ac
Add user webhooks.
KN4CK3R Oct 23, 2022
fb2df43
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Oct 23, 2022
2b9459c
Add migration.
KN4CK3R Oct 23, 2022
2c1cb14
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Nov 2, 2022
e4e51a3
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Nov 5, 2022
9960582
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Nov 17, 2022
989da06
lint
KN4CK3R Nov 17, 2022
9cee676
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Nov 23, 2022
0ddb01f
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Nov 24, 2022
502888b
Fix fixture.
KN4CK3R Nov 24, 2022
6a4543a
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Dec 19, 2022
7cf0e95
Add suggestions.
KN4CK3R Dec 20, 2022
6bb8d13
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Dec 20, 2022
21e481b
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Jan 14, 2023
bc0284f
Fix migration.
KN4CK3R Jan 15, 2023
5ebaf78
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Jan 15, 2023
78772e1
fmt
KN4CK3R Jan 15, 2023
42f710e
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Jan 21, 2023
ebd031e
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Feb 1, 2023
381162a
Merge branch 'main' into feature-user-webhooks
zeripath Feb 6, 2023
08ec5d8
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Feb 17, 2023
3fe01b6
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Feb 19, 2023
530f094
Merge branch 'main' into feature-user-webhooks
lunny Feb 19, 2023
3dedb26
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Feb 19, 2023
a6d42d9
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Feb 20, 2023
8703215
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Mar 9, 2023
4bf1491
Use new database checks.
KN4CK3R Mar 9, 2023
5f580eb
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Mar 9, 2023
8973f99
Fix column name in new methods.
KN4CK3R Mar 10, 2023
5c577dd
Merge branch 'main' of https://github.com/go-gitea/gitea into feature…
KN4CK3R Mar 10, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ var migrations = []Migration{
NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable),
// v235 -> v236
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
// v236 -> v237
NewMigration("Rename Webhook org_id to owner_id", v1_19.RenameWebhookOrgToOwner),
}

// GetCurrentDBVersion returns the current db version
Expand Down
37 changes: 37 additions & 0 deletions models/migrations/v1_19/v236.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2022 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 v1_19 //nolint

import (
"code.gitea.io/gitea/models/migrations/base"

"xorm.io/xorm"
)

func RenameWebhookOrgToOwner(x *xorm.Engine) error {
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
OrgID int64
OwnerID int64 `xorm:"INDEX"`
}

sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}

if err := sess.Sync2(new(Webhook)); err != nil {
return err
}
if _, err := sess.Exec("UPDATE webhook SET owner_id = org_id"); err != nil {
return err
}
if err := base.DropTableColumns(sess, "webhook", "org_id"); err != nil {
return err
}
KN4CK3R marked this conversation as resolved.
Show resolved Hide resolved

return sess.Commit()
}
34 changes: 17 additions & 17 deletions models/webhook/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const (
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook
OrgID int64 `xorm:"INDEX"`
OwnerID int64 `xorm:"INDEX"`
IsSystemWebhook bool
URL string `xorm:"url TEXT"`
HTTPMethod string `xorm:"http_method"`
Expand Down Expand Up @@ -474,19 +474,19 @@ func GetWebhookByRepoID(repoID, id int64) (*Webhook, error) {
})
}

// GetWebhookByOrgID returns webhook of organization by given ID.
func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
// GetWebhookByOwnerID returns webhook of a user or organization by given ID.
func GetWebhookByOwnerID(ownerID, id int64) (*Webhook, error) {
return getWebhook(&Webhook{
ID: id,
OrgID: orgID,
ID: id,
OwnerID: ownerID,
})
}

// ListWebhookOptions are options to filter webhooks on ListWebhooksByOpts
type ListWebhookOptions struct {
db.ListOptions
RepoID int64
OrgID int64
OwnerID int64
IsActive util.OptionalBool
}

Expand All @@ -495,8 +495,8 @@ func (opts *ListWebhookOptions) toCond() builder.Cond {
if opts.RepoID != 0 {
cond = cond.And(builder.Eq{"webhook.repo_id": opts.RepoID})
}
if opts.OrgID != 0 {
cond = cond.And(builder.Eq{"webhook.org_id": opts.OrgID})
if opts.OwnerID != 0 {
cond = cond.And(builder.Eq{"webhook.owner_id": opts.OwnerID})
}
if !opts.IsActive.IsNone() {
cond = cond.And(builder.Eq{"webhook.is_active": opts.IsActive.IsTrue()})
Expand Down Expand Up @@ -529,15 +529,15 @@ func CountWebhooksByOpts(opts *ListWebhookOptions) (int64, error) {
func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false).
Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, false).
Find(&webhooks)
}

// GetSystemOrDefaultWebhook returns admin system or default webhook by given ID.
func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) {
webhook := &Webhook{ID: id}
has, err := db.GetEngine(db.DefaultContext).
Where("repo_id=? AND org_id=?", 0, 0).
Where("repo_id=? AND owner_id=?", 0, 0).
Get(webhook)
if err != nil {
return nil, err
Expand All @@ -552,11 +552,11 @@ func GetSystemWebhooks(ctx context.Context, isActive util.OptionalBool) ([]*Webh
webhooks := make([]*Webhook, 0, 5)
if isActive.IsNone() {
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, true).
Find(&webhooks)
}
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
Where("repo_id=? AND owner_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
Find(&webhooks)
}

Expand Down Expand Up @@ -600,11 +600,11 @@ func DeleteWebhookByRepoID(repoID, id int64) error {
})
}

// DeleteWebhookByOrgID deletes webhook of organization by given ID.
func DeleteWebhookByOrgID(orgID, id int64) error {
// DeleteWebhookByOwnerID deletes webhook of a user or organization by given ID.
func DeleteWebhookByOwnerID(ownerID, id int64) error {
return deleteWebhook(&Webhook{
ID: id,
OrgID: orgID,
ID: id,
OwnerID: ownerID,
})
}

Expand All @@ -617,7 +617,7 @@ func DeleteDefaultSystemWebhook(id int64) error {
defer committer.Close()

count, err := db.GetEngine(ctx).
Where("repo_id=? AND org_id=?", 0, 0).
Where("repo_id=? AND owner_id=?", 0, 0).
Delete(&Webhook{ID: id})
if err != nil {
return err
Expand Down
24 changes: 12 additions & 12 deletions models/webhook/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ func TestGetWebhookByRepoID(t *testing.T) {
assert.True(t, IsErrWebhookNotExist(err))
}

func TestGetWebhookByOrgID(t *testing.T) {
func TestGetWebhookByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
hook, err := GetWebhookByOrgID(3, 3)
hook, err := GetWebhookByOwnerID(3, 3)
assert.NoError(t, err)
assert.Equal(t, int64(3), hook.ID)

_, err = GetWebhookByOrgID(unittest.NonexistentID, unittest.NonexistentID)
_, err = GetWebhookByOwnerID(unittest.NonexistentID, unittest.NonexistentID)
assert.Error(t, err)
assert.True(t, IsErrWebhookNotExist(err))
}
Expand All @@ -140,19 +140,19 @@ func TestGetWebhooksByRepoID(t *testing.T) {
}
}

func TestGetActiveWebhooksByOrgID(t *testing.T) {
func TestGetActiveWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OrgID: 3, IsActive: util.OptionalBoolTrue})
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)
assert.True(t, hooks[0].IsActive)
}
}

func TestGetWebhooksByOrgID(t *testing.T) {
func TestGetWebhooksByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OrgID: 3})
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)
Expand Down Expand Up @@ -181,13 +181,13 @@ func TestDeleteWebhookByRepoID(t *testing.T) {
assert.True(t, IsErrWebhookNotExist(err))
}

func TestDeleteWebhookByOrgID(t *testing.T) {
func TestDeleteWebhookByOwnerID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 3, OrgID: 3})
assert.NoError(t, DeleteWebhookByOrgID(3, 3))
unittest.AssertNotExistsBean(t, &Webhook{ID: 3, OrgID: 3})
unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 3, OwnerID: 3})
assert.NoError(t, DeleteWebhookByOwnerID(3, 3))
unittest.AssertNotExistsBean(t, &Webhook{ID: 3, OwnerID: 3})

err := DeleteWebhookByOrgID(unittest.NonexistentID, unittest.NonexistentID)
err := DeleteWebhookByOwnerID(unittest.NonexistentID, unittest.NonexistentID)
assert.Error(t, err)
assert.True(t, IsErrWebhookNotExist(err))
}
Expand Down
2 changes: 2 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -808,6 +808,8 @@ remove_account_link = Remove Linked Account
remove_account_link_desc = Removing a linked account will revoke its access to your Gitea account. Continue?
remove_account_link_success = The linked account has been removed.

hooks.desc = Add webhooks which will be triggered for <strong>all repositories</strong> under this user.
KN4CK3R marked this conversation as resolved.
Show resolved Hide resolved

orgs_none = You are not a member of any organizations.
repos_none = You do not own any repositories

Expand Down
8 changes: 8 additions & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -774,6 +774,14 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/subscriptions", user.GetMyWatchedRepos)

m.Get("/teams", org.ListUserTeams)

m.Group("/hooks", func() {
m.Combo("").Get(user.ListHooks).
Post(bind(api.CreateHookOption{}), user.CreateHook)
m.Combo("/{id}").Get(user.GetHook).
Patch(bind(api.EditHookOption{}), user.EditHook).
Delete(user.DeleteHook)
}, reqWebhooksEnabled())
}, reqToken())

// Repositories
Expand Down
79 changes: 23 additions & 56 deletions routers/api/v1/org/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package org
import (
"net/http"

"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/convert"
api "code.gitea.io/gitea/modules/structs"
Expand Down Expand Up @@ -40,34 +39,10 @@ func ListHooks(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/HookList"

opts := &webhook.ListWebhookOptions{
ListOptions: utils.GetListOptions(ctx),
OrgID: ctx.Org.Organization.ID,
}

count, err := webhook.CountWebhooksByOpts(opts)
if err != nil {
ctx.InternalServerError(err)
return
}

orgHooks, err := webhook.ListWebhooksByOpts(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}

hooks := make([]*api.Hook, len(orgHooks))
for i, hook := range orgHooks {
hooks[i], err = convert.ToHook(ctx.Org.Organization.AsUser().HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
}
}

ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, hooks)
utils.ListOwnerHooks(
ctx,
ctx.ContextUser,
)
}

// GetHook get an organization's hook by id
Expand All @@ -93,14 +68,12 @@ func GetHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"

org := ctx.Org.Organization
hookID := ctx.ParamsInt64(":id")
hook, err := utils.GetOrgHook(ctx, org.ID, hookID)
hook, err := utils.GetOwnerHook(ctx, ctx.ContextUser.ID, ctx.ParamsInt64("id"))
if err != nil {
return
}

apiHook, err := convert.ToHook(org.AsUser().HomeLink(), hook)
apiHook, err := convert.ToHook(ctx.ContextUser.HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
Expand Down Expand Up @@ -132,15 +105,14 @@ func CreateHook(ctx *context.APIContext) {
// "201":
// "$ref": "#/responses/Hook"

form := web.GetForm(ctx).(*api.CreateHookOption)
// TODO in body params
if !utils.CheckCreateHookOption(ctx, form) {
return
}
utils.AddOrgHook(ctx, form)
utils.AddOwnerHook(
ctx,
ctx.ContextUser,
web.GetForm(ctx).(*api.CreateHookOption),
)
}

// EditHook modify a hook of a repository
// EditHook modify a hook of an organization
func EditHook(ctx *context.APIContext) {
// swagger:operation PATCH /orgs/{org}/hooks/{id} organization orgEditHook
// ---
Expand Down Expand Up @@ -169,11 +141,12 @@ func EditHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"

form := web.GetForm(ctx).(*api.EditHookOption)

// TODO in body params
hookID := ctx.ParamsInt64(":id")
utils.EditOrgHook(ctx, form, hookID)
utils.EditOwnerHook(
ctx,
ctx.ContextUser,
web.GetForm(ctx).(*api.EditHookOption),
ctx.ParamsInt64("id"),
)
}

// DeleteHook delete a hook of an organization
Expand All @@ -199,15 +172,9 @@ func DeleteHook(ctx *context.APIContext) {
// "204":
// "$ref": "#/responses/empty"

org := ctx.Org.Organization
hookID := ctx.ParamsInt64(":id")
if err := webhook.DeleteWebhookByOrgID(org.ID, hookID); err != nil {
if webhook.IsErrWebhookNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOrgID", err)
}
return
}
ctx.Status(http.StatusNoContent)
utils.DeleteOwnerHook(
ctx,
ctx.ContextUser,
ctx.ParamsInt64("id"),
)
}
6 changes: 1 addition & 5 deletions routers/api/v1/repo/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,8 @@ func CreateHook(ctx *context.APIContext) {
// responses:
// "201":
// "$ref": "#/responses/Hook"
form := web.GetForm(ctx).(*api.CreateHookOption)

if !utils.CheckCreateHookOption(ctx, form) {
return
}
utils.AddRepoHook(ctx, form)
utils.AddRepoHook(ctx, web.GetForm(ctx).(*api.CreateHookOption))
}

// EditHook modify a hook of a repository
Expand Down
Loading