diff --git a/CHANGELOG.md b/CHANGELOG.md index e9ba23b4c4..e82430e2ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,203 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). -## [1.17.4](https://github.com/go-gitea/gitea/releases/tag/1.17.4) - 2022-12-21 +## [1.18.0](https://github.com/go-gitea/gitea/releases/tag/v1.18.0) - 2022-12-29 + +* SECURITY + * Remove ReverseProxy authentication from the API (#22219) (#22251) + * Support Go Vulnerability Management (#21139) + * Forbid HTML string tooltips (#20935) +* BREAKING + * Rework mailer settings (#18982) + * Remove U2F support (#20141) + * Refactor `i18n` to `locale` (#20153) + * Enable contenthash in filename for dynamic assets (#20813) +* FEATURES + * Add color previews in markdown (#21474) + * Allow package version sorting (#21453) + * Add support for Chocolatey/NuGet v2 API (#21393) + * Add API endpoint to get changed files of a PR (#21177) + * Add filetree on left of diff view (#21012) + * Support Issue forms and PR forms (#20987) + * Add support for Vagrant packages (#20930) + * Add support for `npm unpublish` (#20688) + * Add badge capabilities to users (#20607) + * Add issue filter for Author (#20578) + * Add KaTeX rendering to Markdown. (#20571) + * Add support for Pub packages (#20560) + * Support localized README (#20508) + * Add support mCaptcha as captcha provider (#20458) + * Add team member invite by email (#20307) + * Added email notification option to receive all own messages (#20179) + * Switch Unicode Escaping to a VSCode-like system (#19990) + * Add user/organization code search (#19977) + * Only show relevant repositories on explore page (#19361) + * User keypairs and HTTP signatures for ActivityPub federation using go-ap (#19133) + * Add sitemap support (#18407) + * Allow creation of OAuth2 applications for orgs (#18084) + * Add system setting table with cache and also add cache supports for user setting (#18058) + * Add pages to view watched repos and subscribed issues/PRs (#17156) + * Support Proxy protocol (#12527) + * Implement sync push mirror on commit (#19411) +* API + * Allow empty assignees on pull request edit (#22150) (#22214) + * Make external issue tracker regexp configurable via API (#21338) + * Add name field for org api (#21270) + * Show teams with no members if user is admin (#21204) + * Add latest commit's SHA to content response (#20398) + * Add allow_rebase_update, default_delete_branch_after_merge to repository api response (#20079) + * Add new endpoints for push mirrors management (#19841) +* ENHANCEMENTS + * Add setting to disable the git apply step in test patch (#22130) (#22170) + * Multiple improvements for comment edit diff (#21990) (#22007) + * Fix button in branch list, avoid unexpected page jump before restore branch actually done (#21562) (#21928) + * Fix flex layout for repo list icons (#21896) (#21920) + * Fix vertical align of committer avatar rendered by email address (#21884) (#21918) + * Fix setting HTTP headers after write (#21833) (#21877) + * Color and Style enhancements (#21784, #21799) (#21868) + * Ignore line anchor links with leading zeroes (#21728) (#21776) + * Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) (#21738) + * Use CSS color-scheme instead of invert (#21616) (#21623) + * Respect user's locale when rendering the date range in the repo activity page (#21410) + * Change `commits-table` column width (#21564) + * Refactor git command arguments and make all arguments to be safe to be used (#21535) + * CSS color enhancements (#21534) + * Add link to user profile in markdown mention only if user exists (#21533, #21554) + * Add option to skip index dirs (#21501) + * Diff file tree tweaks (#21446) + * Localize all timestamps (#21440) + * Add `code` highlighting in issue titles (#21432) + * Use Name instead of DisplayName in LFS Lock (#21415) + * Consolidate more CSS colors into variables (#21402) + * Redirect to new repository owner (#21398) + * Use ISO date format instead of hard-coded English date format for date range in repo activity page (#21396) + * Use weighted algorithm for string matching when finding files in repo (#21370) + * Show private data in feeds (#21369) + * Refactor parseTreeEntries, speed up tree list (#21368) + * Add GET and DELETE endpoints for Docker blob uploads (#21367) + * Add nicer error handling on template compile errors (#21350) + * Add `stat` to `ToCommit` function for speed (#21337) + * Support instance-wide OAuth2 applications (#21335) + * Record OAuth client type at registration (#21316) + * Add new CSS variables --color-accent and --color-small-accent (#21305) + * Improve error descriptions for unauthorized_client (#21292) + * Case-insensitive "find files in repo" (#21269) + * Consolidate more CSS rules, fix inline code on arc-green (#21260) + * Log real ip of requests from ssh (#21216) + * Save files in local storage as group readable (#21198) + * Enable fluid page layout on medium size viewports (#21178) + * File header tweaks (#21175) + * Added missing headers on user packages page (#21172) + * Display image digest for container packages (#21170) + * Skip dirty check for team forms (#21154) + * Keep path when creating a new branch (#21153) + * Remove fomantic image module (#21145) + * Make labels clickable in the comments section. (#21137) + * Sort branches and tags by date descending (#21136) + * Better repo API unit checks (#21130) + * Improve commit status icons (#21124) + * Limit length of repo description and repo url input fields (#21119) + * Show .editorconfig errors in frontend (#21088) + * Allow poster to choose reviewers (#21084) + * Remove black labels and CSS cleanup (#21003) + * Make e-mail sanity check more precise (#20991) + * Use native inputs in whitespace dropdown (#20980) + * Enhance package date display (#20928) + * Display total blob size of a package version (#20927) + * Show language name on hover (#20923) + * Show instructions for all generic package files (#20917) + * Refactor AssertExistsAndLoadBean to use generics (#20797) + * Move the official website link at the footer of gitea (#20777) + * Add support for full name in reverse proxy auth (#20776) + * Remove useless JS operation for relative time tooltips (#20756) + * Replace some icons with SVG (#20741) + * Change commit status icons to SVG (#20736) + * Improve single repo action for issue and pull requests (#20730) + * Allow multiple files in generic packages (#20661) + * Add option to create new issue from /issues page (#20650) + * Background color of private list-items updated (#20630) + * Added search input field to issue filter (#20623) + * Increase default item listing size `ISSUE_PAGING_NUM` to 20 (#20547) + * Modify milestone search keywords to be case insensitive again (#20513) + * Show hint to link package to repo when viewing empty repo package list (#20504) + * Add Tar ZSTD support (#20493) + * Make code review checkboxes clickable (#20481) + * Add "X-Gitea-Object-Type" header for GET `/raw/` & `/media/` API (#20438) + * Display project in issue list (#20434) + * Prepend commit message to template content when opening a new PR (#20429) + * Replace fomantic popup module with tippy.js (#20428) + * Allow to specify colors for text in markup (#20363) + * Allow access to the Public Organization Member lists with minimal permissions (#20330) + * Use default values when provided values are empty (#20318) + * Vertical align navbar avatar at middle (#20302) + * Delete cancel button in repo creation page (#21381) + * Include login_name in adminCreateUser response (#20283) + * fix: icon margin in user/settings/repos (#20281) + * Remove blue text on migrate page (#20273) + * Modify milestone search keywords to be case insensitive (#20266) + * Move some files into models' sub packages (#20262) + * Add tooltip to repo icons in explore page (#20241) + * Remove deprecated licenses (#20222) + * Webhook for Wiki changes (#20219) + * Share HTML template renderers and create a watcher framework (#20218) + * Allow enable LDAP source and disable user sync via CLI (#20206) + * Adds a checkbox to select all issues/PRs (#20177) + * Refactor `i18n` to `locale` (#20153) + * Disable status checks in template if none found (#20088) + * Allow manager logging to set SQL (#20064) + * Add order by for assignee no sort issue (#20053) + * Take a stab at porting existing components to Vue3 (#20044) + * Add doctor command to write commit-graphs (#20007) + * Add support for authentication based on reverse proxy email (#19949) + * Enable spellcheck for EasyMDE, use contenteditable mode (#19776) + * Allow specifying SECRET_KEY_URI, similar to INTERNAL_TOKEN_URI (#19663) + * Rework mailer settings (#18982) + * Add option to purge users (#18064) + * Add author search input (#21246) + * Make rss/atom identifier globally unique (#21550) +* BUGFIXES + * Auth interface return error when verify failure (#22119) (#22259) + * Use complete SHA to create and query commit status (#22244) (#22257) + * Update bleve and zapx to fix unaligned atomic (#22031) (#22218) + * Prevent panic in doctor command when running default checks (#21791) (#21807) + * Load GitRepo in API before deleting issue (#21720) (#21796) + * Ignore line anchor links with leading zeroes (#21728) (#21776) + * Set last login when activating account (#21731) (#21755) + * Fix UI language switching bug (#21597) (#21749) + * Quick fixes monaco-editor error: "vs.editor.nullLanguage" (#21734) (#21738) + * Allow local package identifiers for PyPI packages (#21690) (#21727) + * Deal with markdown template without metadata (#21639) (#21654) + * Fix opaque background on mermaid diagrams (#21642) (#21652) + * Fix repository adoption on Windows (#21646) (#21650) + * Sync git hooks when config file path changed (#21619) (#21626) + * Fix 500 on PR files API (#21602) (#21607) + * Fix `Timestamp.IsZero` (#21593) (#21603) + * Fix viewing user subscriptions (#21482) + * Fix mermaid-related bugs (#21431) + * Fix branch dropdown shifting on page load (#21428) + * Fix default theme-auto selector when nologin (#21346) + * Fix and improve incorrect error messages (#21342) + * Fix formatted link for PR review notifications to matrix (#21319) + * Center-aligning content of WebAuthN page (#21127) + * Remove follow from commits by file (#20765) + * Fix commit status popup (#20737) + * Fix init mail render logic (#20704) + * Use correct page size for link header pagination (#20546) + * Preserve unix socket file (#20499) + * Use tippy.js for context popup (#20393) + * Add missing parameter for error in log message (#20144) + * Do not allow organisation owners add themselves as collaborator (#20043) + * Rework file highlight rendering and fix yaml copy-paste (#19967) + * Improve code diff highlight, fix incorrect rendered diff result (#19958) +* TESTING + * Improve OAuth integration tests (#21390) + * Add playwright tests (#20123) +* BUILD + * Switch to building with go1.19 (#20695) + * Update JS dependencies, adjust eslint (#20659) + * Add more linters to improve code readability (#19989) + +## [1.17.4](https://github.com/go-gitea/gitea/releases/tag/v1.17.4) - 2022-12-21 * SECURITY * Do not allow Ghost access to limited visible user/org (#21849) (#21875) diff --git a/docs/config.yaml b/docs/config.yaml index b80602cb61..fbd7d8d810 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,10 +18,10 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.17.4 + version: 1.18.0 minGoVersion: 1.18 goVersion: 1.19 - minNodeVersion: 14 + minNodeVersion: 16 search: nav repo: "https://github.com/go-gitea/gitea" docContentPath: "docs/content" diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 3ccef3130c..3b2ff4cbbf 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -782,9 +782,9 @@ and - `GRAVATAR_SOURCE`: **gravatar**: Can be `gravatar`, `duoshuo` or anything like `http://cn.gravatar.com/avatar/`. -- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only. +- `DISABLE_GRAVATAR`: **false**: Enable this to use local avatars only. **DEPRECATED [v1.18+]** moved to database. Use admin panel to configure. - `ENABLE_FEDERATED_AVATAR`: **false**: Enable support for federated avatars (see - [http://www.libravatar.org](http://www.libravatar.org)). + [http://www.libravatar.org](http://www.libravatar.org)). **DEPRECATED [v1.18+]** moved to database. Use admin panel to configure. - `AVATAR_STORAGE_TYPE`: **default**: Storage type defined in `[storage.xxx]`. Default is `default` which will read `[storage]` if no section `[storage]` will be a type `local`. - `AVATAR_UPLOAD_PATH`: **data/avatars**: Path to store user avatar image files. diff --git a/docs/content/doc/installation/from-package.en-us.md b/docs/content/doc/installation/from-package.en-us.md index 3f75f26a53..c9df0d21be 100644 --- a/docs/content/doc/installation/from-package.en-us.md +++ b/docs/content/doc/installation/from-package.en-us.md @@ -43,6 +43,14 @@ Arch Linux ARM provides packages for [aarch64](https://archlinuxarm.org/packages pacman -S gitea ``` +## Gentoo Linux + +The rolling release distribution has [Gitea](https://packages.gentoo.org/packages/www-apps/gitea) in their official community repository and package updates are provided with new Gitea releases. + +```sh +emerge gitea -va +``` + ## Canonical Snap There is a [Gitea Snap](https://snapcraft.io/gitea) package which follows the latest stable version. diff --git a/docs/content/doc/usage/email-setup.en-us.md b/docs/content/doc/usage/email-setup.en-us.md index 05cc19c134..6d6b18786c 100644 --- a/docs/content/doc/usage/email-setup.en-us.md +++ b/docs/content/doc/usage/email-setup.en-us.md @@ -76,12 +76,15 @@ The following configuration should work with GMail's SMTP server: ```ini [mailer] ENABLED = true +HOST = smtp.gmail.com:465 ; Remove this line for Gitea >= 1.18.0 SMTP_ADDR = smtp.gmail.com SMTP_PORT = 465 -FROM = example@gmail.com -USER = example@gmail.com +FROM = example.user@gmail.com +USER = example.user PASSWD = *** MAILER_TYPE = smtp IS_TLS_ENABLED = true -HELO_HOSTNAME = example.com ``` + +Note that you'll need to create and use an [App password](https://support.google.com/accounts/answer/185833?hl=en) by enabling 2FA on your Google +account. You won't be able to use your Google account password directly. diff --git a/go.mod b/go.mod index 43c2cce196..0bc40781a1 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/gliderlabs/ssh v0.3.5 github.com/go-ap/activitypub v0.0.0-20220917143152-e4e7018838c0 github.com/go-ap/jsonld v0.0.0-20220917142617-76bf51585778 - github.com/go-chi/chi/v5 v5.0.7 + github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 github.com/go-enry/go-enry/v2 v2.8.3 github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e diff --git a/go.sum b/go.sum index 2166f89c5c..adf1e657f2 100644 --- a/go.sum +++ b/go.sum @@ -482,8 +482,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= -github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= +github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-enry/go-enry/v2 v2.8.3 h1:BwvNrN58JqBJhyyVdZSl5QD3xoxEEGYUrRyPh31FGhw= diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index ecd9041e65..be019184eb 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -64,11 +64,16 @@ func (key *GPGKey) AfterLoad(session *xorm.Session) { // PaddedKeyID show KeyID padded to 16 characters func (key *GPGKey) PaddedKeyID() string { - if len(key.KeyID) > 15 { - return key.KeyID + return PaddedKeyID(key.KeyID) +} + +// PaddedKeyID show KeyID padded to 16 characters +func PaddedKeyID(keyID string) string { + if len(keyID) > 15 { + return keyID } zeros := "0000000000000000" - return zeros[0:16-len(key.KeyID)] + key.KeyID + return zeros[0:16-len(keyID)] + keyID } // ListGPGKeys returns a list of public keys belongs to given user. diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index ca0334cc0b..8a8d4fce15 100644 --- a/models/asymkey/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -5,7 +5,6 @@ package asymkey import ( "context" - "errors" "fmt" "strings" @@ -59,9 +58,9 @@ func calcFingerprintSSHKeygen(publicKeyContent string) (string, error) { if strings.Contains(stderr, "is not a public key file") { return "", ErrKeyUnableVerify{stderr} } - return "", fmt.Errorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr) + return "", util.NewInvalidArgumentErrorf("'ssh-keygen -lf %s' failed with error '%s': %s", tmpPath, err, stderr) } else if len(stdout) < 2 { - return "", errors.New("not enough output for calculating fingerprint: " + stdout) + return "", util.NewInvalidArgumentErrorf("not enough output for calculating fingerprint: %s", stdout) } return strings.Split(stdout, " ")[1], nil } diff --git a/models/asymkey/ssh_key_parse.go b/models/asymkey/ssh_key_parse.go index b3eecb2c9b..1df6db6fa7 100644 --- a/models/asymkey/ssh_key_parse.go +++ b/models/asymkey/ssh_key_parse.go @@ -10,7 +10,6 @@ import ( "encoding/base64" "encoding/binary" "encoding/pem" - "errors" "fmt" "math/big" "os" @@ -122,7 +121,7 @@ func parseKeyString(content string) (string, error) { parts := strings.SplitN(content, " ", 3) switch len(parts) { case 0: - return "", errors.New("empty key") + return "", util.NewInvalidArgumentErrorf("empty key") case 1: keyContent = parts[0] case 2: @@ -167,7 +166,7 @@ func CheckPublicKeyString(content string) (_ string, err error) { content = strings.TrimRight(content, "\n\r") if strings.ContainsAny(content, "\n\r") { - return "", errors.New("only a single line with a single key please") + return "", util.NewInvalidArgumentErrorf("only a single line with a single key please") } // remove any unnecessary whitespace now diff --git a/models/asymkey/ssh_key_principals.go b/models/asymkey/ssh_key_principals.go index f00c3f3e9e..6d43437ec1 100644 --- a/models/asymkey/ssh_key_principals.go +++ b/models/asymkey/ssh_key_principals.go @@ -4,7 +4,6 @@ package asymkey import ( - "errors" "fmt" "strings" @@ -12,6 +11,7 @@ import ( "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" ) // __________ .__ .__ .__ @@ -70,7 +70,7 @@ func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, e content = strings.TrimSpace(content) if strings.ContainsAny(content, "\r\n") { - return "", errors.New("only a single line with a single principal please") + return "", util.NewInvalidArgumentErrorf("only a single line with a single principal please") } // check all the allowed principals, email, username or anything diff --git a/models/avatars/avatar.go b/models/avatars/avatar.go index 7ccb782fa6..4386142861 100644 --- a/models/avatars/avatar.go +++ b/models/avatars/avatar.go @@ -153,8 +153,7 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return DefaultAvatarLink() } - enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar) - enableFederatedAvatar := enableFederatedAvatarSetting.GetValueBool() + enableFederatedAvatar := system_model.GetSettingBool(system_model.KeyPictureEnableFederatedAvatar) var err error if enableFederatedAvatar && system_model.LibravatarService != nil { @@ -175,9 +174,7 @@ func generateEmailAvatarLink(email string, size int, final bool) string { return urlStr } - disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) - - disableGravatar := disableGravatarSetting.GetValueBool() + disableGravatar := system_model.GetSettingBool(system_model.KeyPictureDisableGravatar) if !disableGravatar { // copy GravatarSourceURL, because we will modify its Path. avatarURLCopy := *system_model.GravatarSourceURL diff --git a/models/db/context.go b/models/db/context.go index c8ad0c1aa2..3db8b16528 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -188,7 +188,10 @@ func EstimateCount(ctx context.Context, bean interface{}) (int64, error) { case schemas.MYSQL: _, err = e.Context(ctx).SQL("SELECT table_rows FROM information_schema.tables WHERE tables.table_name = ? AND tables.table_schema = ?;", tablename, x.Dialect().URI().DBName).Get(&rows) case schemas.POSTGRES: - _, err = e.Context(ctx).SQL("SELECT reltuples AS estimate FROM pg_class WHERE relname = ?;", tablename).Get(&rows) + // the table can live in multiple schemas of a postgres database + // See https://wiki.postgresql.org/wiki/Count_estimate + tablename = x.TableName(bean, true) + _, err = e.Context(ctx).SQL("SELECT reltuples::bigint AS estimate FROM pg_class WHERE oid = ?::regclass;", tablename).Get(&rows) case schemas.MSSQL: _, err = e.Context(ctx).SQL("sp_spaceused ?;", tablename).Get(&rows) default: diff --git a/models/migrations/v1_19/v233.go b/models/migrations/v1_19/v233.go index fe568b64eb..ba4cd8e20b 100644 --- a/models/migrations/v1_19/v233.go +++ b/models/migrations/v1_19/v233.go @@ -6,7 +6,6 @@ package v1_19 //nolint import ( "fmt" - "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/secret" "code.gitea.io/gitea/modules/setting" @@ -56,9 +55,9 @@ func batchProcess[T any](x *xorm.Engine, buf []T, query func(limit, start int) * func AddHeaderAuthorizationEncryptedColWebhook(x *xorm.Engine) error { // Add the column to the table type Webhook struct { - ID int64 `xorm:"pk autoincr"` - Type webhook.HookType `xorm:"VARCHAR(16) 'type'"` - Meta string `xorm:"TEXT"` // store hook-specific attributes + ID int64 `xorm:"pk autoincr"` + Type string `xorm:"VARCHAR(16) 'type'"` + Meta string `xorm:"TEXT"` // store hook-specific attributes // HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization() HeaderAuthorizationEncrypted string `xorm:"TEXT"` diff --git a/models/migrations/v1_19/v233_test.go b/models/migrations/v1_19/v233_test.go index 9902b7e4ae..83558da334 100644 --- a/models/migrations/v1_19/v233_test.go +++ b/models/migrations/v1_19/v233_test.go @@ -7,10 +7,10 @@ import ( "testing" "code.gitea.io/gitea/models/migrations/base" - "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/secret" "code.gitea.io/gitea/modules/setting" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" ) @@ -18,9 +18,9 @@ import ( func Test_AddHeaderAuthorizationEncryptedColWebhook(t *testing.T) { // Create Webhook table type Webhook struct { - ID int64 `xorm:"pk autoincr"` - Type webhook.HookType `xorm:"VARCHAR(16) 'type'"` - Meta string `xorm:"TEXT"` // store hook-specific attributes + ID int64 `xorm:"pk autoincr"` + Type webhook_module.HookType `xorm:"VARCHAR(16) 'type'"` + Meta string `xorm:"TEXT"` // store hook-specific attributes // HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization() HeaderAuthorizationEncrypted string `xorm:"TEXT"` diff --git a/models/org_team.go b/models/org_team.go index a5a2575eec..b3ee842c1f 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -6,7 +6,6 @@ package models import ( "context" - "errors" "fmt" "strings" @@ -235,7 +234,7 @@ func RemoveRepository(t *organization.Team, repoID int64) error { // It's caller's responsibility to assign organization ID. func NewTeam(t *organization.Team) (err error) { if len(t.Name) == 0 { - return errors.New("empty team name") + return util.NewInvalidArgumentErrorf("empty team name") } if err = organization.IsUsableTeamName(t.Name); err != nil { @@ -300,7 +299,7 @@ func NewTeam(t *organization.Team) (err error) { // UpdateTeam updates information of team. func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err error) { if len(t.Name) == 0 { - return errors.New("empty team name") + return util.NewInvalidArgumentErrorf("empty team name") } if len(t.Description) > 255 { diff --git a/models/packages/conan/references.go b/models/packages/conan/references.go index 06e828e8fa..0d888a1ec8 100644 --- a/models/packages/conan/references.go +++ b/models/packages/conan/references.go @@ -5,7 +5,6 @@ package conan import ( "context" - "errors" "strconv" "strings" @@ -13,13 +12,14 @@ import ( "code.gitea.io/gitea/models/packages" conan_module "code.gitea.io/gitea/modules/packages/conan" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) var ( - ErrRecipeReferenceNotExist = errors.New("Recipe reference does not exist") - ErrPackageReferenceNotExist = errors.New("Package reference does not exist") + ErrRecipeReferenceNotExist = util.NewNotExistErrorf("recipe reference does not exist") + ErrPackageReferenceNotExist = util.NewNotExistErrorf("package reference does not exist") ) // RecipeExists checks if a recipe exists diff --git a/models/packages/container/search.go b/models/packages/container/search.go index dfd5e244ba..2e35c44766 100644 --- a/models/packages/container/search.go +++ b/models/packages/container/search.go @@ -5,7 +5,6 @@ package container import ( "context" - "errors" "strings" "time" @@ -13,11 +12,12 @@ import ( "code.gitea.io/gitea/models/packages" user_model "code.gitea.io/gitea/models/user" container_module "code.gitea.io/gitea/modules/packages/container" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) -var ErrContainerBlobNotExist = errors.New("Container blob does not exist") +var ErrContainerBlobNotExist = util.NewNotExistErrorf("container blob does not exist") type BlobSearchOptions struct { OwnerID int64 diff --git a/models/packages/package.go b/models/packages/package.go index 5c4837d98b..a804f35de3 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -5,11 +5,11 @@ package packages import ( "context" - "errors" "fmt" "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -20,9 +20,9 @@ func init() { var ( // ErrDuplicatePackage indicates a duplicated package error - ErrDuplicatePackage = errors.New("Package does exist already") + ErrDuplicatePackage = util.NewAlreadyExistErrorf("package already exists") // ErrPackageNotExist indicates a package not exist error - ErrPackageNotExist = errors.New("Package does not exist") + ErrPackageNotExist = util.NewNotExistErrorf("package does not exist") ) // Type of a package diff --git a/models/packages/package_blob.go b/models/packages/package_blob.go index 36ad745312..3b4a1ecf18 100644 --- a/models/packages/package_blob.go +++ b/models/packages/package_blob.go @@ -5,15 +5,15 @@ package packages import ( "context" - "errors" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) // ErrPackageBlobNotExist indicates a package blob not exist error -var ErrPackageBlobNotExist = errors.New("Package blob does not exist") +var ErrPackageBlobNotExist = util.NewNotExistErrorf("package blob does not exist") func init() { db.RegisterModel(new(PackageBlob)) diff --git a/models/packages/package_blob_upload.go b/models/packages/package_blob_upload.go index 64d1f9d473..4b0e789221 100644 --- a/models/packages/package_blob_upload.go +++ b/models/packages/package_blob_upload.go @@ -5,7 +5,6 @@ package packages import ( "context" - "errors" "strings" "time" @@ -15,7 +14,7 @@ import ( ) // ErrPackageBlobUploadNotExist indicates a package blob upload not exist error -var ErrPackageBlobUploadNotExist = errors.New("Package blob upload does not exist") +var ErrPackageBlobUploadNotExist = util.NewNotExistErrorf("package blob upload does not exist") func init() { db.RegisterModel(new(PackageBlobUpload)) diff --git a/models/packages/package_cleanup_rule.go b/models/packages/package_cleanup_rule.go index 9bd512755d..fa12dec406 100644 --- a/models/packages/package_cleanup_rule.go +++ b/models/packages/package_cleanup_rule.go @@ -5,17 +5,17 @@ package packages import ( "context" - "errors" "fmt" "regexp" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) -var ErrPackageCleanupRuleNotExist = errors.New("Package blob does not exist") +var ErrPackageCleanupRuleNotExist = util.NewNotExistErrorf("package blob does not exist") func init() { db.RegisterModel(new(PackageCleanupRule)) diff --git a/models/packages/package_file.go b/models/packages/package_file.go index 6d0fd185a0..7f794836dc 100644 --- a/models/packages/package_file.go +++ b/models/packages/package_file.go @@ -5,13 +5,13 @@ package packages import ( "context" - "errors" "strconv" "strings" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) @@ -22,9 +22,9 @@ func init() { var ( // ErrDuplicatePackageFile indicates a duplicated package file error - ErrDuplicatePackageFile = errors.New("Package file does exist already") + ErrDuplicatePackageFile = util.NewAlreadyExistErrorf("package file already exists") // ErrPackageFileNotExist indicates a package file not exist error - ErrPackageFileNotExist = errors.New("Package file does not exist") + ErrPackageFileNotExist = util.NewNotExistErrorf("package file does not exist") ) // EmptyFileKey is a named constant for an empty file key diff --git a/models/packages/package_version.go b/models/packages/package_version.go index 928f9d47d6..759c20abed 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -5,7 +5,6 @@ package packages import ( "context" - "errors" "strconv" "strings" @@ -17,7 +16,7 @@ import ( ) // ErrDuplicatePackageVersion indicates a duplicated package version error -var ErrDuplicatePackageVersion = errors.New("Package version already exists") +var ErrDuplicatePackageVersion = util.NewAlreadyExistErrorf("package version already exists") func init() { db.RegisterModel(new(PackageVersion)) diff --git a/models/project/project.go b/models/project/project.go index bcf1166408..0a07cfe22a 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -5,7 +5,6 @@ package project import ( "context" - "errors" "fmt" "code.gitea.io/gitea/models/db" @@ -176,7 +175,7 @@ func NewProject(p *Project) error { } if !IsTypeValid(p.Type) { - return errors.New("project type is not valid") + return util.NewInvalidArgumentErrorf("project type is not valid") } ctx, committer, err := db.TxContext(db.DefaultContext) diff --git a/models/repo/mirror.go b/models/repo/mirror.go index 2f59b85331..c1d24a4886 100644 --- a/models/repo/mirror.go +++ b/models/repo/mirror.go @@ -6,16 +6,16 @@ package repo import ( "context" - "errors" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) // ErrMirrorNotExist mirror does not exist error -var ErrMirrorNotExist = errors.New("Mirror does not exist") +var ErrMirrorNotExist = util.NewNotExistErrorf("Mirror does not exist") // Mirror represents mirror information of a repository. type Mirror struct { diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go index f79ce59ee2..642020bb5e 100644 --- a/models/repo/pushmirror.go +++ b/models/repo/pushmirror.go @@ -5,18 +5,18 @@ package repo import ( "context" - "errors" "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) // ErrPushMirrorNotExist mirror does not exist error -var ErrPushMirrorNotExist = errors.New("PushMirror does not exist") +var ErrPushMirrorNotExist = util.NewNotExistErrorf("PushMirror does not exist") // PushMirror represents mirror information of a repository. type PushMirror struct { @@ -90,7 +90,7 @@ func DeletePushMirrors(ctx context.Context, opts PushMirrorOptions) error { _, err := db.GetEngine(ctx).Where(opts.toConds()).Delete(&PushMirror{}) return err } - return errors.New("repoID required and must be set") + return util.NewInvalidArgumentErrorf("repoID required and must be set") } func GetPushMirror(ctx context.Context, opts PushMirrorOptions) (*PushMirror, error) { diff --git a/models/repo/release.go b/models/repo/release.go index 25eba10e05..08b429f5e1 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -6,7 +6,6 @@ package repo import ( "context" - "errors" "fmt" "sort" "strconv" @@ -156,7 +155,7 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs for i := range attachments { if attachments[i].ReleaseID != 0 { - return errors.New("release permission denied") + return util.NewPermissionDeniedErrorf("release permission denied") } attachments[i].ReleaseID = releaseID // No assign value could be 0, so ignore AllCols(). diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 6d9dd9ec65..9922ff25a2 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -5,7 +5,6 @@ package repo import ( "context" - "errors" "fmt" "strings" @@ -708,7 +707,7 @@ func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error) cond := builder.NewCond() if opts.Actor == nil { - return nil, 0, errors.New("GetUserRepositories: Actor is needed but not given") + return nil, 0, util.NewInvalidArgumentErrorf("GetUserRepositories: Actor is needed but not given") } cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID}) if !opts.Private { diff --git a/models/system/setting.go b/models/system/setting.go index dc6145b417..8e16547d92 100644 --- a/models/system/setting.go +++ b/models/system/setting.go @@ -92,13 +92,13 @@ func GetSettingNoCache(key string) (*Setting, error) { } // GetSetting returns the setting value via the key -func GetSetting(key string) (*Setting, error) { - return cache.Get(genSettingCacheKey(key), func() (*Setting, error) { +func GetSetting(key string) (string, error) { + return cache.GetString(genSettingCacheKey(key), func() (string, error) { res, err := GetSettingNoCache(key) if err != nil { - return nil, err + return "", err } - return res, nil + return res.SettingValue, nil }) } @@ -106,7 +106,8 @@ func GetSetting(key string) (*Setting, error) { // none existing keys and errors are ignored and result in false func GetSettingBool(key string) bool { s, _ := GetSetting(key) - return s.GetValueBool() + v, _ := strconv.ParseBool(s) + return v } // GetSettings returns specific settings @@ -183,8 +184,8 @@ func SetSettingNoVersion(key, value string) error { // SetSetting updates a users' setting for a specific key func SetSetting(setting *Setting) error { - _, err := cache.Set(genSettingCacheKey(setting.SettingKey), func() (*Setting, error) { - return setting, upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version) + _, err := cache.GetString(genSettingCacheKey(setting.SettingKey), func() (string, error) { + return setting.SettingValue, upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version) }) if err != nil { return err @@ -266,7 +267,7 @@ func Init() error { enableFederatedAvatar = false } - if disableGravatar || !enableFederatedAvatar { + if enableFederatedAvatar || !disableGravatar { var err error GravatarSourceURL, err = url.Parse(setting.GravatarSource) if err != nil { diff --git a/models/unittest/fscopy.go b/models/unittest/fscopy.go index 631da49f2d..74b12d5057 100644 --- a/models/unittest/fscopy.go +++ b/models/unittest/fscopy.go @@ -64,7 +64,7 @@ func Copy(src, dest string) error { func CopyDir(srcPath, destPath string, filters ...func(filePath string) bool) error { // Check if target directory exists. if _, err := os.Stat(destPath); !errors.Is(err, os.ErrNotExist) { - return errors.New("file or directory already exists: " + destPath) + return util.NewAlreadyExistErrorf("file or directory already exists: %s", destPath) } err := os.MkdirAll(destPath, os.ModePerm) diff --git a/models/user/avatar.go b/models/user/avatar.go index ce25139b5f..e6ca49efd0 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -67,9 +67,7 @@ func (u *User) AvatarLinkWithSize(size int) string { useLocalAvatar := false autoGenerateAvatar := false - disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar) - - disableGravatar := disableGravatarSetting.GetValueBool() + disableGravatar := system_model.GetSettingBool(system_model.KeyPictureDisableGravatar) switch { case u.UseCustomAvatar: diff --git a/models/user/email_address.go b/models/user/email_address.go index 69e94f8bb6..e310858f92 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -6,7 +6,6 @@ package user import ( "context" - "errors" "fmt" "net/mail" "regexp" @@ -22,7 +21,7 @@ import ( ) // ErrEmailNotActivated e-mail address has not been activated error -var ErrEmailNotActivated = errors.New("e-mail address has not been activated") +var ErrEmailNotActivated = util.NewInvalidArgumentErrorf("e-mail address has not been activated") // ErrEmailCharIsNotSupported e-mail address contains unsupported character type ErrEmailCharIsNotSupported struct { diff --git a/models/user/openid.go b/models/user/openid.go index 1946705048..596ff182bc 100644 --- a/models/user/openid.go +++ b/models/user/openid.go @@ -5,7 +5,6 @@ package user import ( "context" - "errors" "fmt" "code.gitea.io/gitea/models/db" @@ -13,7 +12,7 @@ import ( ) // ErrOpenIDNotExist openid is not known -var ErrOpenIDNotExist = errors.New("OpenID is unknown") +var ErrOpenIDNotExist = util.NewNotExistErrorf("OpenID is unknown") // UserOpenID is the list of all OpenID identities of a user. // Since this is a middle table, name it OpenID is not suitable, so we ignore the lint here diff --git a/models/user/setting.go b/models/user/setting.go index a17483f9af..f5cfef5b33 100644 --- a/models/user/setting.go +++ b/models/user/setting.go @@ -53,13 +53,13 @@ func genSettingCacheKey(userID int64, key string) string { } // GetSetting returns the setting value via the key -func GetSetting(uid int64, key string) (*Setting, error) { - return cache.Get(genSettingCacheKey(uid, key), func() (*Setting, error) { +func GetSetting(uid int64, key string) (string, error) { + return cache.GetString(genSettingCacheKey(uid, key), func() (string, error) { res, err := GetSettingNoCache(uid, key) if err != nil { - return nil, err + return "", err } - return res, nil + return res.SettingValue, nil }) } @@ -154,7 +154,7 @@ func SetUserSetting(userID int64, key, value string) error { return err } - _, err := cache.Set(genSettingCacheKey(userID, key), func() (string, error) { + _, err := cache.GetString(genSettingCacheKey(userID, key), func() (string, error) { return value, upsertUserSettingValue(userID, key, value) }) diff --git a/models/webhook/hooktask.go b/models/webhook/hooktask.go index 2a37ff31d8..ccce1447bc 100644 --- a/models/webhook/hooktask.go +++ b/models/webhook/hooktask.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" gouuid "github.com/google/uuid" ) @@ -107,7 +108,7 @@ type HookTask struct { UUID string `xorm:"unique"` api.Payloader `xorm:"-"` PayloadContent string `xorm:"LONGTEXT"` - EventType HookEventType + EventType webhook_module.HookEventType IsDelivered bool Delivered int64 DeliveredString string `xorm:"-"` diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 5defc67fd7..c24404c42c 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" "xorm.io/builder" ) @@ -46,7 +47,7 @@ type ErrHookTaskNotExist struct { UUID string } -// IsErrWebhookNotExist checks if an error is a ErrWebhookNotExist. +// IsErrHookTaskNotExist checks if an error is a ErrHookTaskNotExist. func IsErrHookTaskNotExist(err error) bool { _, ok := err.(ErrHookTaskNotExist) return ok @@ -117,84 +118,22 @@ func IsValidHookContentType(name string) bool { return ok } -// HookEvents is a set of web hook events -type HookEvents struct { - Create bool `json:"create"` - Delete bool `json:"delete"` - Fork bool `json:"fork"` - Issues bool `json:"issues"` - IssueAssign bool `json:"issue_assign"` - IssueLabel bool `json:"issue_label"` - IssueMilestone bool `json:"issue_milestone"` - IssueComment bool `json:"issue_comment"` - Push bool `json:"push"` - PullRequest bool `json:"pull_request"` - PullRequestAssign bool `json:"pull_request_assign"` - PullRequestLabel bool `json:"pull_request_label"` - PullRequestMilestone bool `json:"pull_request_milestone"` - PullRequestComment bool `json:"pull_request_comment"` - PullRequestReview bool `json:"pull_request_review"` - PullRequestSync bool `json:"pull_request_sync"` - Wiki bool `json:"wiki"` - Repository bool `json:"repository"` - Release bool `json:"release"` - Package bool `json:"package"` -} - -// HookEvent represents events that will delivery hook. -type HookEvent struct { - PushOnly bool `json:"push_only"` - SendEverything bool `json:"send_everything"` - ChooseEvents bool `json:"choose_events"` - BranchFilter string `json:"branch_filter"` - - HookEvents `json:"events"` -} - -// HookType is the type of a webhook -type HookType = string - -// Types of webhooks -const ( - GITEA HookType = "gitea" - GOGS HookType = "gogs" - SLACK HookType = "slack" - DISCORD HookType = "discord" - DINGTALK HookType = "dingtalk" - TELEGRAM HookType = "telegram" - MSTEAMS HookType = "msteams" - FEISHU HookType = "feishu" - MATRIX HookType = "matrix" - WECHATWORK HookType = "wechatwork" - PACKAGIST HookType = "packagist" -) - -// HookStatus is the status of a web hook -type HookStatus int - -// Possible statuses of a web hook -const ( - HookStatusNone = iota - HookStatusSucceed - HookStatusFail -) - // Webhook represents a web hook object. 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"` - IsSystemWebhook bool - URL string `xorm:"url TEXT"` - HTTPMethod string `xorm:"http_method"` - ContentType HookContentType - Secret string `xorm:"TEXT"` - Events string `xorm:"TEXT"` - *HookEvent `xorm:"-"` - IsActive bool `xorm:"INDEX"` - Type HookType `xorm:"VARCHAR(16) 'type'"` - Meta string `xorm:"TEXT"` // store hook-specific attributes - LastStatus HookStatus // Last delivery status + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook + OrgID int64 `xorm:"INDEX"` + IsSystemWebhook bool + URL string `xorm:"url TEXT"` + HTTPMethod string `xorm:"http_method"` + ContentType HookContentType + Secret string `xorm:"TEXT"` + Events string `xorm:"TEXT"` + *webhook_module.HookEvent `xorm:"-"` + IsActive bool `xorm:"INDEX"` + Type webhook_module.HookType `xorm:"VARCHAR(16) 'type'"` + Meta string `xorm:"TEXT"` // store hook-specific attributes + LastStatus webhook_module.HookStatus // Last delivery status // HeaderAuthorizationEncrypted should be accessed using HeaderAuthorization() and SetHeaderAuthorization() HeaderAuthorizationEncrypted string `xorm:"TEXT"` @@ -209,7 +148,7 @@ func init() { // AfterLoad updates the webhook object upon setting a column func (w *Webhook) AfterLoad() { - w.HookEvent = &HookEvent{} + w.HookEvent = &webhook_module.HookEvent{} if err := json.Unmarshal([]byte(w.Events), w.HookEvent); err != nil { log.Error("Unmarshal[%d]: %v", w.ID, err) } @@ -362,34 +301,34 @@ func (w *Webhook) HasPackageEvent() bool { // EventCheckers returns event checkers func (w *Webhook) EventCheckers() []struct { Has func() bool - Type HookEventType + Type webhook_module.HookEventType } { return []struct { Has func() bool - Type HookEventType + Type webhook_module.HookEventType }{ - {w.HasCreateEvent, HookEventCreate}, - {w.HasDeleteEvent, HookEventDelete}, - {w.HasForkEvent, HookEventFork}, - {w.HasPushEvent, HookEventPush}, - {w.HasIssuesEvent, HookEventIssues}, - {w.HasIssuesAssignEvent, HookEventIssueAssign}, - {w.HasIssuesLabelEvent, HookEventIssueLabel}, - {w.HasIssuesMilestoneEvent, HookEventIssueMilestone}, - {w.HasIssueCommentEvent, HookEventIssueComment}, - {w.HasPullRequestEvent, HookEventPullRequest}, - {w.HasPullRequestAssignEvent, HookEventPullRequestAssign}, - {w.HasPullRequestLabelEvent, HookEventPullRequestLabel}, - {w.HasPullRequestMilestoneEvent, HookEventPullRequestMilestone}, - {w.HasPullRequestCommentEvent, HookEventPullRequestComment}, - {w.HasPullRequestApprovedEvent, HookEventPullRequestReviewApproved}, - {w.HasPullRequestRejectedEvent, HookEventPullRequestReviewRejected}, - {w.HasPullRequestCommentEvent, HookEventPullRequestReviewComment}, - {w.HasPullRequestSyncEvent, HookEventPullRequestSync}, - {w.HasWikiEvent, HookEventWiki}, - {w.HasRepositoryEvent, HookEventRepository}, - {w.HasReleaseEvent, HookEventRelease}, - {w.HasPackageEvent, HookEventPackage}, + {w.HasCreateEvent, webhook_module.HookEventCreate}, + {w.HasDeleteEvent, webhook_module.HookEventDelete}, + {w.HasForkEvent, webhook_module.HookEventFork}, + {w.HasPushEvent, webhook_module.HookEventPush}, + {w.HasIssuesEvent, webhook_module.HookEventIssues}, + {w.HasIssuesAssignEvent, webhook_module.HookEventIssueAssign}, + {w.HasIssuesLabelEvent, webhook_module.HookEventIssueLabel}, + {w.HasIssuesMilestoneEvent, webhook_module.HookEventIssueMilestone}, + {w.HasIssueCommentEvent, webhook_module.HookEventIssueComment}, + {w.HasPullRequestEvent, webhook_module.HookEventPullRequest}, + {w.HasPullRequestAssignEvent, webhook_module.HookEventPullRequestAssign}, + {w.HasPullRequestLabelEvent, webhook_module.HookEventPullRequestLabel}, + {w.HasPullRequestMilestoneEvent, webhook_module.HookEventPullRequestMilestone}, + {w.HasPullRequestCommentEvent, webhook_module.HookEventPullRequestComment}, + {w.HasPullRequestApprovedEvent, webhook_module.HookEventPullRequestReviewApproved}, + {w.HasPullRequestRejectedEvent, webhook_module.HookEventPullRequestReviewRejected}, + {w.HasPullRequestCommentEvent, webhook_module.HookEventPullRequestReviewComment}, + {w.HasPullRequestSyncEvent, webhook_module.HookEventPullRequestSync}, + {w.HasWikiEvent, webhook_module.HookEventWiki}, + {w.HasRepositoryEvent, webhook_module.HookEventRepository}, + {w.HasReleaseEvent, webhook_module.HookEventRelease}, + {w.HasPackageEvent, webhook_module.HookEventPackage}, } } @@ -453,7 +392,7 @@ func getWebhook(bean *Webhook) (*Webhook, error) { if err != nil { return nil, err } else if !has { - return nil, ErrWebhookNotExist{bean.ID} + return nil, ErrWebhookNotExist{ID: bean.ID} } return bean, nil } @@ -541,7 +480,7 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) { if err != nil { return nil, err } else if !has { - return nil, ErrWebhookNotExist{id} + return nil, ErrWebhookNotExist{ID: id} } return webhook, nil } diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index 2bdafb61b6..c368fc620e 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" ) @@ -46,11 +47,11 @@ func TestWebhook_History(t *testing.T) { func TestWebhook_UpdateEvent(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) webhook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 1}) - hookEvent := &HookEvent{ + hookEvent := &webhook_module.HookEvent{ PushOnly: true, SendEverything: false, ChooseEvents: false, - HookEvents: HookEvents{ + HookEvents: webhook_module.HookEvents{ Create: false, Push: true, PullRequest: false, @@ -59,7 +60,7 @@ func TestWebhook_UpdateEvent(t *testing.T) { webhook.HookEvent = hookEvent assert.NoError(t, webhook.UpdateEvent()) assert.NotEmpty(t, webhook.Events) - actualHookEvent := &HookEvent{} + actualHookEvent := &webhook_module.HookEvent{} assert.NoError(t, json.Unmarshal([]byte(webhook.Events), actualHookEvent)) assert.Equal(t, *hookEvent, *actualHookEvent) } @@ -74,13 +75,13 @@ func TestWebhook_EventsArray(t *testing.T) { "package", }, (&Webhook{ - HookEvent: &HookEvent{SendEverything: true}, + HookEvent: &webhook_module.HookEvent{SendEverything: true}, }).EventsArray(), ) assert.Equal(t, []string{"push"}, (&Webhook{ - HookEvent: &HookEvent{PushOnly: true}, + HookEvent: &webhook_module.HookEvent{PushOnly: true}, }).EventsArray(), ) } diff --git a/modules/avatar/hash.go b/modules/avatar/hash.go new file mode 100644 index 0000000000..50db9c1943 --- /dev/null +++ b/modules/avatar/hash.go @@ -0,0 +1,28 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package avatar + +import ( + "crypto/sha256" + "encoding/hex" + "strconv" +) + +// HashAvatar will generate a unique string, which ensures that when there's a +// different unique ID while the data is the same, it will generate a different +// output. It will generate the output according to: +// HEX(HASH(uniqueID || - || data)) +// The hash being used is SHA256. +// The sole purpose of the unique ID is to generate a distinct hash Such that +// two unique IDs with the same data will have a different hash output. +// The "-" byte is important to ensure that data cannot be modified such that +// the first byte is a number, which could lead to a "collision" with the hash +// of another unique ID. +func HashAvatar(uniqueID int64, data []byte) string { + h := sha256.New() + h.Write([]byte(strconv.FormatInt(uniqueID, 10))) + h.Write([]byte{'-'}) + h.Write(data) + return hex.EncodeToString(h.Sum(nil)) +} diff --git a/modules/cache/cache.go b/modules/cache/cache.go index 2e7d5bb603..edaf483135 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -45,39 +45,6 @@ func GetCache() mc.Cache { return conn } -// Get returns the key value from cache with callback when no key exists in cache -func Get[V interface{}](key string, getFunc func() (V, error)) (V, error) { - if conn == nil || setting.CacheService.TTL == 0 { - return getFunc() - } - - cached := conn.Get(key) - if value, ok := cached.(V); ok { - return value, nil - } - - value, err := getFunc() - if err != nil { - return value, err - } - - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) -} - -// Set updates and returns the key value in the cache with callback. The old value is only removed if the updateFunc() is successful -func Set[V interface{}](key string, valueFunc func() (V, error)) (V, error) { - if conn == nil || setting.CacheService.TTL == 0 { - return valueFunc() - } - - value, err := valueFunc() - if err != nil { - return value, err - } - - return value, conn.Put(key, value, setting.CacheService.TTLSeconds()) -} - // GetString returns the key value from cache with callback when no key exists in cache func GetString(key string, getFunc func() (string, error)) (string, error) { if conn == nil || setting.CacheService.TTL == 0 { diff --git a/modules/notification/notification.go b/modules/notification/notification.go index 7ffe223561..b2ccc765f3 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/modules/notification/mail" "code.gitea.io/gitea/modules/notification/mirror" "code.gitea.io/gitea/modules/notification/ui" - "code.gitea.io/gitea/modules/notification/webhook" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" ) @@ -37,7 +36,6 @@ func NewContext() { RegisterNotifier(mail.NewNotifier()) } RegisterNotifier(indexer.NewNotifier()) - RegisterNotifier(webhook.NewNotifier()) RegisterNotifier(action.NewNotifier()) RegisterNotifier(mirror.NewNotifier()) } diff --git a/modules/packages/composer/metadata.go b/modules/packages/composer/metadata.go index b98294001c..36b0b8e421 100644 --- a/modules/packages/composer/metadata.go +++ b/modules/packages/composer/metadata.go @@ -5,12 +5,12 @@ package composer import ( "archive/zip" - "errors" "io" "regexp" "strings" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" @@ -21,11 +21,11 @@ const TypeProperty = "composer.type" var ( // ErrMissingComposerFile indicates a missing composer.json file - ErrMissingComposerFile = errors.New("composer.json file is missing") + ErrMissingComposerFile = util.NewInvalidArgumentErrorf("composer.json file is missing") // ErrInvalidName indicates an invalid package name - ErrInvalidName = errors.New("package name is invalid") + ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid") // ErrInvalidVersion indicates an invalid package version - ErrInvalidVersion = errors.New("package version is invalid") + ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid") ) // Package represents a Composer package diff --git a/modules/packages/conan/conaninfo_parser.go b/modules/packages/conan/conaninfo_parser.go index 5bb3fb8930..de11dbee45 100644 --- a/modules/packages/conan/conaninfo_parser.go +++ b/modules/packages/conan/conaninfo_parser.go @@ -5,9 +5,10 @@ package conan import ( "bufio" - "errors" "io" "strings" + + "code.gitea.io/gitea/modules/util" ) // Conaninfo represents infos of a Conan package @@ -79,7 +80,7 @@ func readSections(r io.Reader) (map[string][]string, error) { continue } if line != "" { - return nil, errors.New("Invalid conaninfo.txt") + return nil, util.NewInvalidArgumentErrorf("invalid conaninfo.txt") } } if err := scanner.Err(); err != nil { diff --git a/modules/packages/conan/reference.go b/modules/packages/conan/reference.go index 37a5170dd3..58f268bd48 100644 --- a/modules/packages/conan/reference.go +++ b/modules/packages/conan/reference.go @@ -4,12 +4,12 @@ package conan import ( - "errors" "fmt" "regexp" "strings" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) const ( @@ -25,7 +25,7 @@ var ( namePattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9_][a-zA-Z0-9_\+\.-]{%d,%d}$`, minChars-1, maxChars-1)) revisionPattern = regexp.MustCompile(fmt.Sprintf(`^[a-zA-Z0-9]{1,%d}$`, maxChars)) - ErrValidation = errors.New("Could not validate one or more reference fields") + ErrValidation = util.NewInvalidArgumentErrorf("could not validate one or more reference fields") ) // RecipeReference represents a recipe /@/# diff --git a/modules/packages/helm/metadata.go b/modules/packages/helm/metadata.go index 98b5919a73..fdbd9003b8 100644 --- a/modules/packages/helm/metadata.go +++ b/modules/packages/helm/metadata.go @@ -6,10 +6,10 @@ package helm import ( "archive/tar" "compress/gzip" - "errors" "io" "strings" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" @@ -18,13 +18,13 @@ import ( var ( // ErrMissingChartFile indicates a missing Chart.yaml file - ErrMissingChartFile = errors.New("Chart.yaml file is missing") + ErrMissingChartFile = util.NewInvalidArgumentErrorf("Chart.yaml file is missing") // ErrInvalidName indicates an invalid package name - ErrInvalidName = errors.New("package name is invalid") + ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid") // ErrInvalidVersion indicates an invalid package version - ErrInvalidVersion = errors.New("package version is invalid") + ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid") // ErrInvalidChart indicates an invalid chart - ErrInvalidChart = errors.New("chart is invalid") + ErrInvalidChart = util.NewInvalidArgumentErrorf("chart is invalid") ) // Metadata for a Chart file. This models the structure of a Chart.yaml file. diff --git a/modules/packages/npm/creator.go b/modules/packages/npm/creator.go index 02f6724812..548d7ed9e5 100644 --- a/modules/packages/npm/creator.go +++ b/modules/packages/npm/creator.go @@ -8,7 +8,6 @@ import ( "crypto/sha1" "crypto/sha512" "encoding/base64" - "errors" "fmt" "io" "regexp" @@ -16,6 +15,7 @@ import ( "time" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" @@ -23,15 +23,15 @@ import ( var ( // ErrInvalidPackage indicates an invalid package - ErrInvalidPackage = errors.New("The package is invalid") + ErrInvalidPackage = util.NewInvalidArgumentErrorf("package is invalid") // ErrInvalidPackageName indicates an invalid name - ErrInvalidPackageName = errors.New("The package name is invalid") + ErrInvalidPackageName = util.NewInvalidArgumentErrorf("package name is invalid") // ErrInvalidPackageVersion indicates an invalid version - ErrInvalidPackageVersion = errors.New("The package version is invalid") + ErrInvalidPackageVersion = util.NewInvalidArgumentErrorf("package version is invalid") // ErrInvalidAttachment indicates a invalid attachment - ErrInvalidAttachment = errors.New("The package attachment is invalid") + ErrInvalidAttachment = util.NewInvalidArgumentErrorf("package attachment is invalid") // ErrInvalidIntegrity indicates an integrity validation error - ErrInvalidIntegrity = errors.New("Failed to validate integrity") + ErrInvalidIntegrity = util.NewInvalidArgumentErrorf("failed to validate integrity") ) var nameMatch = regexp.MustCompile(`\A((@[^\s\/~'!\(\)\*]+?)[\/])?([^_.][^\s\/~'!\(\)\*]+)\z`) diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index 033421af96..3c478b1c02 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -7,13 +7,13 @@ import ( "archive/zip" "bytes" "encoding/xml" - "errors" "fmt" "io" "path/filepath" "regexp" "strings" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" @@ -21,13 +21,13 @@ import ( var ( // ErrMissingNuspecFile indicates a missing Nuspec file - ErrMissingNuspecFile = errors.New("Nuspec file is missing") + ErrMissingNuspecFile = util.NewInvalidArgumentErrorf("Nuspec file is missing") // ErrNuspecFileTooLarge indicates a Nuspec file which is too large - ErrNuspecFileTooLarge = errors.New("Nuspec file is too large") + ErrNuspecFileTooLarge = util.NewInvalidArgumentErrorf("Nuspec file is too large") // ErrNuspecInvalidID indicates an invalid id in the Nuspec file - ErrNuspecInvalidID = errors.New("Nuspec file contains an invalid id") + ErrNuspecInvalidID = util.NewInvalidArgumentErrorf("Nuspec file contains an invalid id") // ErrNuspecInvalidVersion indicates an invalid version in the Nuspec file - ErrNuspecInvalidVersion = errors.New("Nuspec file contains an invalid version") + ErrNuspecInvalidVersion = util.NewInvalidArgumentErrorf("Nuspec file contains an invalid version") ) // PackageType specifies the package type the metadata describes diff --git a/modules/packages/nuget/symbol_extractor.go b/modules/packages/nuget/symbol_extractor.go index 634bbb17e6..b709eac4c1 100644 --- a/modules/packages/nuget/symbol_extractor.go +++ b/modules/packages/nuget/symbol_extractor.go @@ -7,7 +7,6 @@ import ( "archive/zip" "bytes" "encoding/binary" - "errors" "fmt" "io" "path" @@ -15,13 +14,14 @@ import ( "strings" "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/util" ) var ( - ErrMissingPdbFiles = errors.New("Package does not contain PDB files") - ErrInvalidFiles = errors.New("Package contains invalid files") - ErrInvalidPdbMagicNumber = errors.New("Invalid Portable PDB magic number") - ErrMissingPdbStream = errors.New("Missing PDB stream") + ErrMissingPdbFiles = util.NewInvalidArgumentErrorf("package does not contain PDB files") + ErrInvalidFiles = util.NewInvalidArgumentErrorf("package contains invalid files") + ErrInvalidPdbMagicNumber = util.NewInvalidArgumentErrorf("invalid Portable PDB magic number") + ErrMissingPdbStream = util.NewInvalidArgumentErrorf("missing PDB stream") ) type PortablePdb struct { diff --git a/modules/packages/pub/metadata.go b/modules/packages/pub/metadata.go index 36fe665707..13a066afac 100644 --- a/modules/packages/pub/metadata.go +++ b/modules/packages/pub/metadata.go @@ -6,11 +6,11 @@ package pub import ( "archive/tar" "compress/gzip" - "errors" "io" "regexp" "strings" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "github.com/hashicorp/go-version" @@ -18,10 +18,10 @@ import ( ) var ( - ErrMissingPubspecFile = errors.New("Pubspec file is missing") - ErrPubspecFileTooLarge = errors.New("Pubspec file is too large") - ErrInvalidName = errors.New("Package name is invalid") - ErrInvalidVersion = errors.New("Package version is invalid") + ErrMissingPubspecFile = util.NewInvalidArgumentErrorf("Pubspec file is missing") + ErrPubspecFileTooLarge = util.NewInvalidArgumentErrorf("Pubspec file is too large") + ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid") + ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid") ) var namePattern = regexp.MustCompile(`\A[a-zA-Z_][a-zA-Z0-9_]*\z`) diff --git a/modules/packages/rubygems/marshal.go b/modules/packages/rubygems/marshal.go index 14fb755606..efb2ba34a4 100644 --- a/modules/packages/rubygems/marshal.go +++ b/modules/packages/rubygems/marshal.go @@ -6,9 +6,10 @@ package rubygems import ( "bufio" "bytes" - "errors" "io" "reflect" + + "code.gitea.io/gitea/modules/util" ) const ( @@ -31,9 +32,9 @@ const ( var ( // ErrUnsupportedType indicates an unsupported type - ErrUnsupportedType = errors.New("Type is unsupported") + ErrUnsupportedType = util.NewInvalidArgumentErrorf("type is unsupported") // ErrInvalidIntRange indicates an invalid number range - ErrInvalidIntRange = errors.New("Number is not in valid range") + ErrInvalidIntRange = util.NewInvalidArgumentErrorf("number is not in valid range") ) // RubyUserMarshal is a Ruby object that has a marshal_load function. diff --git a/modules/packages/rubygems/metadata.go b/modules/packages/rubygems/metadata.go index e2c73c8f3a..adc1c05808 100644 --- a/modules/packages/rubygems/metadata.go +++ b/modules/packages/rubygems/metadata.go @@ -6,11 +6,11 @@ package rubygems import ( "archive/tar" "compress/gzip" - "errors" "io" "regexp" "strings" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/validation" "gopkg.in/yaml.v3" @@ -18,11 +18,11 @@ import ( var ( // ErrMissingMetadataFile indicates a missing metadata.gz file - ErrMissingMetadataFile = errors.New("Metadata file is missing") + ErrMissingMetadataFile = util.NewInvalidArgumentErrorf("metadata.gz file is missing") // ErrInvalidName indicates an invalid id in the metadata.gz file - ErrInvalidName = errors.New("Metadata file contains an invalid name") + ErrInvalidName = util.NewInvalidArgumentErrorf("package name is invalid") // ErrInvalidVersion indicates an invalid version in the metadata.gz file - ErrInvalidVersion = errors.New("Metadata file contains an invalid version") + ErrInvalidVersion = util.NewInvalidArgumentErrorf("package version is invalid") ) var versionMatcher = regexp.MustCompile(`\A[0-9]+(?:\.[0-9a-zA-Z]+)*(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?\z`) diff --git a/modules/setting/log.go b/modules/setting/log.go index 7372fc998d..8a2d47eda7 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -284,8 +284,6 @@ func newRouterLogService() { } func newLogService() { - log.Info("Gitea v%s%s", AppVer, AppBuiltWith) - options := newDefaultLogOptions() options.bufferLength = Cfg.Section("log").Key("BUFFER_LEN").MustInt64(10000) EnableSSHLog = Cfg.Section("log").Key("ENABLE_SSH_LOG").MustBool(false) @@ -297,24 +295,14 @@ func newLogService() { sections := strings.Split(Cfg.Section("log").Key("MODE").MustString("console"), ",") useConsole := false - for i := 0; i < len(sections); i++ { - sections[i] = strings.TrimSpace(sections[i]) - if sections[i] == "console" { - useConsole = true - } - } - - if !useConsole { - err := log.DelLogger("console") - if err != nil { - log.Fatal("DelLogger: %v", err) - } - } - for _, name := range sections { - if len(name) == 0 { + name = strings.TrimSpace(name) + if name == "" { continue } + if name == "console" { + useConsole = true + } sec, err := Cfg.GetSection("log." + name + ".default") if err != nil { @@ -336,6 +324,13 @@ func newLogService() { AddLogDescription(log.DEFAULT, &description) + if !useConsole { + log.Info("According to the configuration, subsequent logs will not be printed to the console") + if err := log.DelLogger("console"); err != nil { + log.Fatal("Cannot delete console logger: %v", err) + } + } + // Finally redirect the default golog to here golog.SetFlags(0) golog.SetPrefix("") diff --git a/modules/setting/picture.go b/modules/setting/picture.go index 9d16a2360b..a814af822f 100644 --- a/modules/setting/picture.go +++ b/modules/setting/picture.go @@ -68,7 +68,7 @@ func newPictureService() { } func GetDefaultDisableGravatar() bool { - return !OfflineMode + return OfflineMode } func GetDefaultEnableFederatedAvatar(disableGravatar bool) bool { diff --git a/modules/sitemap/sitemap.go b/modules/sitemap/sitemap.go index ceb65c1c8d..280ca1d710 100644 --- a/modules/sitemap/sitemap.go +++ b/modules/sitemap/sitemap.go @@ -11,48 +11,62 @@ import ( "time" ) -// sitemapFileLimit contains the maximum size of a sitemap file -const sitemapFileLimit = 50 * 1024 * 1024 +const ( + sitemapFileLimit = 50 * 1024 * 1024 // the maximum size of a sitemap file + urlsLimit = 50000 -// Url represents a single sitemap entry + schemaURL = "http://www.sitemaps.org/schemas/sitemap/0.9" + urlsetName = "urlset" + sitemapindexName = "sitemapindex" +) + +// URL represents a single sitemap entry type URL struct { URL string `xml:"loc"` LastMod *time.Time `xml:"lastmod,omitempty"` } -// SitemapUrl represents a sitemap +// Sitemap represents a sitemap type Sitemap struct { XMLName xml.Name Namespace string `xml:"xmlns,attr"` - URLs []URL `xml:"url"` + URLs []URL `xml:"url"` + Sitemaps []URL `xml:"sitemap"` } // NewSitemap creates a sitemap func NewSitemap() *Sitemap { return &Sitemap{ - XMLName: xml.Name{Local: "urlset"}, - Namespace: "http://www.sitemaps.org/schemas/sitemap/0.9", + XMLName: xml.Name{Local: urlsetName}, + Namespace: schemaURL, } } -// NewSitemap creates a sitemap index. +// NewSitemapIndex creates a sitemap index. func NewSitemapIndex() *Sitemap { return &Sitemap{ - XMLName: xml.Name{Local: "sitemapindex"}, - Namespace: "http://www.sitemaps.org/schemas/sitemap/0.9", + XMLName: xml.Name{Local: sitemapindexName}, + Namespace: schemaURL, } } // Add adds a URL to the sitemap func (s *Sitemap) Add(u URL) { - s.URLs = append(s.URLs, u) + if s.XMLName.Local == sitemapindexName { + s.Sitemaps = append(s.Sitemaps, u) + } else { + s.URLs = append(s.URLs, u) + } } -// Write writes the sitemap to a response +// WriteTo writes the sitemap to a response func (s *Sitemap) WriteTo(w io.Writer) (int64, error) { - if len(s.URLs) > 50000 { - return 0, fmt.Errorf("The sitemap contains too many URLs: %d", len(s.URLs)) + if l := len(s.URLs); l > urlsLimit { + return 0, fmt.Errorf("The sitemap contains %d URLs, but only %d are allowed", l, urlsLimit) + } + if l := len(s.Sitemaps); l > urlsLimit { + return 0, fmt.Errorf("The sitemap contains %d sub-sitemaps, but only %d are allowed", l, urlsLimit) } buf := bytes.NewBufferString(xml.Header) if err := xml.NewEncoder(buf).Encode(s); err != nil { @@ -62,7 +76,7 @@ func (s *Sitemap) WriteTo(w io.Writer) (int64, error) { return 0, err } if buf.Len() > sitemapFileLimit { - return 0, fmt.Errorf("The sitemap is too big: %d", buf.Len()) + return 0, fmt.Errorf("The sitemap has %d bytes, but only %d are allowed", buf.Len(), sitemapFileLimit) } return buf.WriteTo(w) } diff --git a/modules/sitemap/sitemap_test.go b/modules/sitemap/sitemap_test.go index ab879b272e..1180463cd7 100644 --- a/modules/sitemap/sitemap_test.go +++ b/modules/sitemap/sitemap_test.go @@ -6,7 +6,6 @@ package sitemap import ( "bytes" "encoding/xml" - "fmt" "strings" "testing" "time" @@ -14,63 +13,154 @@ import ( "github.com/stretchr/testify/assert" ) -func TestOk(t *testing.T) { - testReal := func(s *Sitemap, name string, urls []URL, expected string) { - for _, url := range urls { - s.Add(url) - } - buf := &bytes.Buffer{} - _, err := s.WriteTo(buf) - assert.NoError(t, nil, err) - assert.Equal(t, xml.Header+"<"+name+" xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">"+expected+"\n", buf.String()) - } - test := func(urls []URL, expected string) { - testReal(NewSitemap(), "urlset", urls, expected) - testReal(NewSitemapIndex(), "sitemapindex", urls, expected) - } - +func TestNewSitemap(t *testing.T) { ts := time.Unix(1651322008, 0).UTC() - test( - []URL{}, - "", - ) - test( - []URL{ - {URL: "https://gitea.io/test1", LastMod: &ts}, + tests := []struct { + name string + urls []URL + want string + wantErr string + }{ + { + name: "empty", + urls: []URL{}, + want: xml.Header + `` + + "" + + "\n", }, - "https://gitea.io/test12022-04-30T12:33:28Z", - ) - test( - []URL{ - {URL: "https://gitea.io/test2", LastMod: nil}, + { + name: "regular", + urls: []URL{ + {URL: "https://gitea.io/test1", LastMod: &ts}, + }, + want: xml.Header + `` + + "https://gitea.io/test12022-04-30T12:33:28Z" + + "\n", }, - "https://gitea.io/test2", - ) - test( - []URL{ - {URL: "https://gitea.io/test1", LastMod: &ts}, - {URL: "https://gitea.io/test2", LastMod: nil}, + { + name: "without lastmod", + urls: []URL{ + {URL: "https://gitea.io/test1"}, + }, + want: xml.Header + `` + + "https://gitea.io/test1" + + "\n", + }, + { + name: "multiple", + urls: []URL{ + {URL: "https://gitea.io/test1", LastMod: &ts}, + {URL: "https://gitea.io/test2", LastMod: nil}, + }, + want: xml.Header + `` + + "https://gitea.io/test12022-04-30T12:33:28Z" + + "https://gitea.io/test2" + + "\n", + }, + { + name: "too many urls", + urls: make([]URL, 50001), + wantErr: "The sitemap contains 50001 URLs, but only 50000 are allowed", + }, + { + name: "too big file", + urls: []URL{ + {URL: strings.Repeat("b", 50*1024*1024+1)}, + }, + wantErr: "The sitemap has 52428932 bytes, but only 52428800 are allowed", }, - "https://gitea.io/test12022-04-30T12:33:28Z"+ - "https://gitea.io/test2", - ) -} - -func TestTooManyURLs(t *testing.T) { - s := NewSitemap() - for i := 0; i < 50001; i++ { - s.Add(URL{URL: fmt.Sprintf("https://gitea.io/test%d", i)}) } - buf := &bytes.Buffer{} - _, err := s.WriteTo(buf) - assert.EqualError(t, err, "The sitemap contains too many URLs: 50001") + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewSitemap() + for _, url := range tt.urls { + s.Add(url) + } + buf := &bytes.Buffer{} + _, err := s.WriteTo(buf) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + assert.Equalf(t, tt.want, buf.String(), "NewSitemap()") + } + }) + } } -func TestSitemapTooBig(t *testing.T) { - s := NewSitemap() - s.Add(URL{URL: strings.Repeat("b", sitemapFileLimit)}) - buf := &bytes.Buffer{} - _, err := s.WriteTo(buf) - assert.EqualError(t, err, "The sitemap is too big: 52428931") +func TestNewSitemapIndex(t *testing.T) { + ts := time.Unix(1651322008, 0).UTC() + + tests := []struct { + name string + urls []URL + want string + wantErr string + }{ + { + name: "empty", + urls: []URL{}, + want: xml.Header + `` + + "" + + "\n", + }, + { + name: "regular", + urls: []URL{ + {URL: "https://gitea.io/test1", LastMod: &ts}, + }, + want: xml.Header + `` + + "https://gitea.io/test12022-04-30T12:33:28Z" + + "\n", + }, + { + name: "without lastmod", + urls: []URL{ + {URL: "https://gitea.io/test1"}, + }, + want: xml.Header + `` + + "https://gitea.io/test1" + + "\n", + }, + { + name: "multiple", + urls: []URL{ + {URL: "https://gitea.io/test1", LastMod: &ts}, + {URL: "https://gitea.io/test2", LastMod: nil}, + }, + want: xml.Header + `` + + "https://gitea.io/test12022-04-30T12:33:28Z" + + "https://gitea.io/test2" + + "\n", + }, + { + name: "too many sitemaps", + urls: make([]URL, 50001), + wantErr: "The sitemap contains 50001 sub-sitemaps, but only 50000 are allowed", + }, + { + name: "too big file", + urls: []URL{ + {URL: strings.Repeat("b", 50*1024*1024+1)}, + }, + wantErr: "The sitemap has 52428952 bytes, but only 52428800 are allowed", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := NewSitemapIndex() + for _, url := range tt.urls { + s.Add(url) + } + buf := &bytes.Buffer{} + _, err := s.WriteTo(buf) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + } else { + assert.NoError(t, err) + assert.Equalf(t, tt.want, buf.String(), "NewSitemapIndex()") + } + }) + } } diff --git a/modules/structs/mirror.go b/modules/structs/mirror.go index 21e7751f76..55cd133a4f 100644 --- a/modules/structs/mirror.go +++ b/modules/structs/mirror.go @@ -9,6 +9,7 @@ type CreatePushMirrorOption struct { RemoteUsername string `json:"remote_username"` RemotePassword string `json:"remote_password"` Interval string `json:"interval"` + SyncOnCommit bool `json:"sync_on_commit"` } // PushMirror represents information of a push mirror @@ -21,4 +22,5 @@ type PushMirror struct { LastUpdateUnix string `json:"last_update"` LastError string `json:"last_error"` Interval string `json:"interval"` + SyncOnCommit bool `json:"sync_on_commit"` } diff --git a/modules/util/error.go b/modules/util/error.go index 63bd447bf3..e67b9977f0 100644 --- a/modules/util/error.go +++ b/modules/util/error.go @@ -5,6 +5,7 @@ package util import ( "errors" + "fmt" ) // Common Errors forming the base of our error system @@ -34,3 +35,31 @@ func (w SilentWrap) Error() string { func (w SilentWrap) Unwrap() error { return w.Err } + +// NewSilentWrapErrorf returns an error that formats as the given text but unwraps as the provided error +func NewSilentWrapErrorf(unwrap error, message string, args ...interface{}) error { + if len(args) == 0 { + return SilentWrap{Message: message, Err: unwrap} + } + return SilentWrap{Message: fmt.Sprintf(message, args...), Err: unwrap} +} + +// NewInvalidArgumentErrorf returns an error that formats as the given text but unwraps as an ErrInvalidArgument +func NewInvalidArgumentErrorf(message string, args ...interface{}) error { + return NewSilentWrapErrorf(ErrInvalidArgument, message, args...) +} + +// NewPermissionDeniedErrorf returns an error that formats as the given text but unwraps as an ErrPermissionDenied +func NewPermissionDeniedErrorf(message string, args ...interface{}) error { + return NewSilentWrapErrorf(ErrPermissionDenied, message, args...) +} + +// NewAlreadyExistErrorf returns an error that formats as the given text but unwraps as an ErrAlreadyExist +func NewAlreadyExistErrorf(message string, args ...interface{}) error { + return NewSilentWrapErrorf(ErrAlreadyExist, message, args...) +} + +// NewNotExistErrorf returns an error that formats as the given text but unwraps as an ErrNotExist +func NewNotExistErrorf(message string, args ...interface{}) error { + return NewSilentWrapErrorf(ErrNotExist, message, args...) +} diff --git a/modules/webhook/structs.go b/modules/webhook/structs.go new file mode 100644 index 0000000000..96012de352 --- /dev/null +++ b/modules/webhook/structs.go @@ -0,0 +1,38 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package webhook + +// HookEvents is a set of web hook events +type HookEvents struct { + Create bool `json:"create"` + Delete bool `json:"delete"` + Fork bool `json:"fork"` + Issues bool `json:"issues"` + IssueAssign bool `json:"issue_assign"` + IssueLabel bool `json:"issue_label"` + IssueMilestone bool `json:"issue_milestone"` + IssueComment bool `json:"issue_comment"` + Push bool `json:"push"` + PullRequest bool `json:"pull_request"` + PullRequestAssign bool `json:"pull_request_assign"` + PullRequestLabel bool `json:"pull_request_label"` + PullRequestMilestone bool `json:"pull_request_milestone"` + PullRequestComment bool `json:"pull_request_comment"` + PullRequestReview bool `json:"pull_request_review"` + PullRequestSync bool `json:"pull_request_sync"` + Wiki bool `json:"wiki"` + Repository bool `json:"repository"` + Release bool `json:"release"` + Package bool `json:"package"` +} + +// HookEvent represents events that will delivery hook. +type HookEvent struct { + PushOnly bool `json:"push_only"` + SendEverything bool `json:"send_everything"` + ChooseEvents bool `json:"choose_events"` + BranchFilter string `json:"branch_filter"` + + HookEvents `json:"events"` +} diff --git a/modules/webhook/type.go b/modules/webhook/type.go new file mode 100644 index 0000000000..db4ab17931 --- /dev/null +++ b/modules/webhook/type.go @@ -0,0 +1,95 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package webhook + +// HookEventType is the type of a hook event +type HookEventType string + +// Types of hook events +const ( + HookEventCreate HookEventType = "create" + HookEventDelete HookEventType = "delete" + HookEventFork HookEventType = "fork" + HookEventPush HookEventType = "push" + HookEventIssues HookEventType = "issues" + HookEventIssueAssign HookEventType = "issue_assign" + HookEventIssueLabel HookEventType = "issue_label" + HookEventIssueMilestone HookEventType = "issue_milestone" + HookEventIssueComment HookEventType = "issue_comment" + HookEventPullRequest HookEventType = "pull_request" + HookEventPullRequestAssign HookEventType = "pull_request_assign" + HookEventPullRequestLabel HookEventType = "pull_request_label" + HookEventPullRequestMilestone HookEventType = "pull_request_milestone" + HookEventPullRequestComment HookEventType = "pull_request_comment" + HookEventPullRequestReviewApproved HookEventType = "pull_request_review_approved" + HookEventPullRequestReviewRejected HookEventType = "pull_request_review_rejected" + HookEventPullRequestReviewComment HookEventType = "pull_request_review_comment" + HookEventPullRequestSync HookEventType = "pull_request_sync" + HookEventWiki HookEventType = "wiki" + HookEventRepository HookEventType = "repository" + HookEventRelease HookEventType = "release" + HookEventPackage HookEventType = "package" +) + +// Event returns the HookEventType as an event string +func (h HookEventType) Event() string { + switch h { + case HookEventCreate: + return "create" + case HookEventDelete: + return "delete" + case HookEventFork: + return "fork" + case HookEventPush: + return "push" + case HookEventIssues, HookEventIssueAssign, HookEventIssueLabel, HookEventIssueMilestone: + return "issues" + case HookEventPullRequest, HookEventPullRequestAssign, HookEventPullRequestLabel, HookEventPullRequestMilestone, + HookEventPullRequestSync: + return "pull_request" + case HookEventIssueComment, HookEventPullRequestComment: + return "issue_comment" + case HookEventPullRequestReviewApproved: + return "pull_request_approved" + case HookEventPullRequestReviewRejected: + return "pull_request_rejected" + case HookEventPullRequestReviewComment: + return "pull_request_comment" + case HookEventWiki: + return "wiki" + case HookEventRepository: + return "repository" + case HookEventRelease: + return "release" + } + return "" +} + +// HookType is the type of a webhook +type HookType = string + +// Types of webhooks +const ( + GITEA HookType = "gitea" + GOGS HookType = "gogs" + SLACK HookType = "slack" + DISCORD HookType = "discord" + DINGTALK HookType = "dingtalk" + TELEGRAM HookType = "telegram" + MSTEAMS HookType = "msteams" + FEISHU HookType = "feishu" + MATRIX HookType = "matrix" + WECHATWORK HookType = "wechatwork" + PACKAGIST HookType = "packagist" +) + +// HookStatus is the status of a web hook +type HookStatus int + +// Possible statuses of a web hook +const ( + HookStatusNone HookStatus = iota + HookStatusSucceed + HookStatusFail +) diff --git a/options/license/HPND-export-US b/options/license/HPND-export-US new file mode 100644 index 0000000000..b0cd393969 --- /dev/null +++ b/options/license/HPND-export-US @@ -0,0 +1,5 @@ +Copyright (C) 1990 by the Massachusetts Institute of Technology + +Export of this software from the United States of America may require a specific license from the United States Government. It is the responsibility of any person or organization contemplating export to obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 58571fff14..a623952aa7 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -4,6 +4,7 @@ package composer import ( + "errors" "fmt" "io" "net/http" @@ -200,7 +201,11 @@ func UploadPackage(ctx *context.Context) { cp, err := composer_module.ParsePackage(buf, buf.Size()) if err != nil { - apiError(ctx, http.StatusBadRequest, err) + if errors.Is(err, util.ErrInvalidArgument) { + apiError(ctx, http.StatusBadRequest, err) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } return } diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go index af863bc4b9..3bcce6bdf5 100644 --- a/routers/api/packages/helm/helm.go +++ b/routers/api/packages/helm/helm.go @@ -4,6 +4,7 @@ package helm import ( + "errors" "fmt" "io" "net/http" @@ -163,7 +164,11 @@ func UploadPackage(ctx *context.Context) { metadata, err := helm_module.ParseChartArchive(buf) if err != nil { - apiError(ctx, http.StatusBadRequest, err) + if errors.Is(err, util.ErrInvalidArgument) { + apiError(ctx, http.StatusBadRequest, err) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } return } diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 1a09cb6f36..0d25f173e9 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -158,7 +158,11 @@ func DownloadPackageFileByName(ctx *context.Context) { func UploadPackage(ctx *context.Context) { npmPackage, err := npm_module.ParsePackage(ctx.Req.Body) if err != nil { - apiError(ctx, http.StatusBadRequest, err) + if errors.Is(err, util.ErrInvalidArgument) { + apiError(ctx, http.StatusBadRequest, err) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } return } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index d6f7d1d7f6..6423db7d3a 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -411,7 +411,11 @@ func UploadSymbolPackage(ctx *context.Context) { pdbs, err := nuget_module.ExtractPortablePdb(buf, buf.Size()) if err != nil { - apiError(ctx, http.StatusBadRequest, err) + if errors.Is(err, util.ErrInvalidArgument) { + apiError(ctx, http.StatusBadRequest, err) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } return } defer pdbs.Close() @@ -507,7 +511,7 @@ func processUploadedFile(ctx *context.Context, expectedType nuget_module.Package np, err := nuget_module.ParsePackageMetaData(buf, buf.Size()) if err != nil { - if err == nuget_module.ErrMissingNuspecFile || err == nuget_module.ErrNuspecFileTooLarge || err == nuget_module.ErrNuspecInvalidID || err == nuget_module.ErrNuspecInvalidVersion { + if errors.Is(err, util.ErrInvalidArgument) { apiError(ctx, http.StatusBadRequest, err) } else { apiError(ctx, http.StatusInternalServerError, err) diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go index 247950a214..1ece4e18ed 100644 --- a/routers/api/packages/pub/pub.go +++ b/routers/api/packages/pub/pub.go @@ -4,6 +4,7 @@ package pub import ( + "errors" "fmt" "io" "net/http" @@ -19,6 +20,7 @@ import ( packages_module "code.gitea.io/gitea/modules/packages" pub_module "code.gitea.io/gitea/modules/packages/pub" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" packages_service "code.gitea.io/gitea/services/packages" ) @@ -173,7 +175,11 @@ func UploadPackageFile(ctx *context.Context) { pck, err := pub_module.ParsePackage(buf) if err != nil { - apiError(ctx, http.StatusInternalServerError, err) + if errors.Is(err, util.ErrInvalidArgument) { + apiError(ctx, http.StatusBadRequest, err) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } return } diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index c1a10b5e78..af358fb82f 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -6,6 +6,7 @@ package rubygems import ( "compress/gzip" "compress/zlib" + "errors" "fmt" "io" "net/http" @@ -217,7 +218,11 @@ func UploadPackageFile(ctx *context.Context) { rp, err := rubygems_module.ParsePackageMetaData(buf) if err != nil { - apiError(ctx, http.StatusInternalServerError, err) + if errors.Is(err, util.ErrInvalidArgument) { + apiError(ctx, http.StatusBadRequest, err) + } else { + apiError(ctx, http.StatusInternalServerError, err) + } return } if _, err := buf.Seek(0, io.SeekStart); err != nil { diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go index ef08a08be0..4e435c9599 100644 --- a/routers/api/v1/org/hook.go +++ b/routers/api/v1/org/hook.go @@ -6,12 +6,12 @@ package org import ( "net/http" - "code.gitea.io/gitea/models/webhook" + webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" - "code.gitea.io/gitea/services/convert" + webhook_service "code.gitea.io/gitea/services/webhook" ) // ListHooks list an organziation's webhooks @@ -39,18 +39,18 @@ func ListHooks(ctx *context.APIContext) { // "200": // "$ref": "#/responses/HookList" - opts := &webhook.ListWebhookOptions{ + opts := &webhook_model.ListWebhookOptions{ ListOptions: utils.GetListOptions(ctx), OrgID: ctx.Org.Organization.ID, } - count, err := webhook.CountWebhooksByOpts(opts) + count, err := webhook_model.CountWebhooksByOpts(opts) if err != nil { ctx.InternalServerError(err) return } - orgHooks, err := webhook.ListWebhooksByOpts(ctx, opts) + orgHooks, err := webhook_model.ListWebhooksByOpts(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -58,7 +58,7 @@ func ListHooks(ctx *context.APIContext) { hooks := make([]*api.Hook, len(orgHooks)) for i, hook := range orgHooks { - hooks[i], err = convert.ToHook(ctx.Org.Organization.AsUser().HomeLink(), hook) + hooks[i], err = webhook_service.ToHook(ctx.Org.Organization.AsUser().HomeLink(), hook) if err != nil { ctx.InternalServerError(err) return @@ -99,7 +99,7 @@ func GetHook(ctx *context.APIContext) { return } - apiHook, err := convert.ToHook(org.AsUser().HomeLink(), hook) + apiHook, err := webhook_service.ToHook(org.AsUser().HomeLink(), hook) if err != nil { ctx.InternalServerError(err) return @@ -200,8 +200,8 @@ func DeleteHook(ctx *context.APIContext) { org := ctx.Org.Organization hookID := ctx.ParamsInt64(":id") - if err := webhook.DeleteWebhookByOrgID(org.ID, hookID); err != nil { - if webhook.IsErrWebhookNotExist(err) { + if err := webhook_model.DeleteWebhookByOrgID(org.ID, hookID); err != nil { + if webhook_model.IsErrWebhookNotExist(err) { ctx.NotFound() } else { ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOrgID", err) diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 757ae7247b..100a28d7f6 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/convert" webhook_service "code.gitea.io/gitea/services/webhook" @@ -68,7 +69,7 @@ func ListHooks(ctx *context.APIContext) { apiHooks := make([]*api.Hook, len(hooks)) for i := range hooks { - apiHooks[i], err = convert.ToHook(ctx.Repo.RepoLink, hooks[i]) + apiHooks[i], err = webhook_service.ToHook(ctx.Repo.RepoLink, hooks[i]) if err != nil { ctx.InternalServerError(err) return @@ -115,7 +116,7 @@ func GetHook(ctx *context.APIContext) { if err != nil { return } - apiHook, err := convert.ToHook(repo.RepoLink, hook) + apiHook, err := webhook_service.ToHook(repo.RepoLink, hook) if err != nil { ctx.InternalServerError(err) return @@ -176,7 +177,7 @@ func TestHook(ctx *context.APIContext) { commit := convert.ToPayloadCommit(ctx.Repo.Repository, ctx.Repo.Commit) commitID := ctx.Repo.Commit.ID.String() - if err := webhook_service.PrepareWebhook(ctx, hook, webhook.HookEventPush, &api.PushPayload{ + if err := webhook_service.PrepareWebhook(ctx, hook, webhook_module.HookEventPush, &api.PushPayload{ Ref: ref, Before: commitID, After: commitID, diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 5fce5a4a80..06bfabe3d2 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -345,10 +345,11 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro } pushMirror := &repo_model.PushMirror{ - RepoID: repo.ID, - Repo: repo, - RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix), - Interval: interval, + RepoID: repo.ID, + Repo: repo, + RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix), + Interval: interval, + SyncOnCommit: mirrorOption.SyncOnCommit, } if err = repo_model.InsertPushMirror(ctx, pushMirror); err != nil { diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index 1a27ececfe..fc202f51cf 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -13,7 +13,7 @@ import ( "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/services/convert" + webhook_module "code.gitea.io/gitea/modules/webhook" webhook_service "code.gitea.io/gitea/services/webhook" ) @@ -98,7 +98,7 @@ func AddRepoHook(ctx *context.APIContext, form *api.CreateHookOption) { // toAPIHook converts the hook to its API representation. // If there is an error, write to `ctx` accordingly. Return (hook, ok) func toAPIHook(ctx *context.APIContext, repoLink string, hook *webhook.Webhook) (*api.Hook, bool) { - apiHook, err := convert.ToHook(repoLink, hook) + apiHook, err := webhook_service.ToHook(repoLink, hook) if err != nil { ctx.Error(http.StatusInternalServerError, "ToHook", err) return nil, false @@ -127,9 +127,9 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID ContentType: webhook.ToHookContentType(form.Config["content_type"]), Secret: form.Config["secret"], HTTPMethod: "POST", - HookEvent: &webhook.HookEvent{ + HookEvent: &webhook_module.HookEvent{ ChooseEvents: true, - HookEvents: webhook.HookEvents{ + HookEvents: webhook_module.HookEvents{ Create: util.IsStringInSlice(string(webhook.HookEventCreate), form.Events, true), Delete: util.IsStringInSlice(string(webhook.HookEventDelete), form.Events, true), Fork: util.IsStringInSlice(string(webhook.HookEventFork), form.Events, true), @@ -160,7 +160,7 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID ctx.Error(http.StatusInternalServerError, "SetHeaderAuthorization", err) return nil, false } - if w.Type == webhook.SLACK { + if w.Type == webhook_module.SLACK { channel, ok := form.Config["channel"] if !ok { ctx.Error(http.StatusUnprocessableEntity, "", "Missing config option: channel") @@ -253,7 +253,7 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh w.ContentType = webhook.ToHookContentType(ct) } - if w.Type == webhook.SLACK { + if w.Type == webhook_module.SLACK { if channel, ok := form.Config["channel"]; ok { meta, err := json.Marshal(&webhook_service.SlackMeta{ Channel: channel, diff --git a/routers/init.go b/routers/init.go index a13dc13aac..cab3bcc4a5 100644 --- a/routers/init.go +++ b/routers/init.go @@ -121,6 +121,7 @@ func GlobalInitInstalled(ctx context.Context) { log.Info("Log path: %s", setting.LogRootPath) log.Info("Configuration file: %s", setting.CustomConf) log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode)) + log.Info("Gitea v%s%s", setting.AppVer, setting.AppBuiltWith) // Setup i18n translation.InitLocales(ctx) diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index 2b6f107faf..bf56e3d0bd 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -23,6 +23,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" webhook_service "code.gitea.io/gitea/services/webhook" @@ -119,7 +120,7 @@ func checkHookType(ctx *context.Context) string { // WebhooksNew render creating webhook page func WebhooksNew(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} + ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}} orCtx, err := getOrgRepoCtx(ctx) if err != nil { @@ -154,12 +155,12 @@ func WebhooksNew(ctx *context.Context) { } // ParseHookEvent convert web form content to webhook.HookEvent -func ParseHookEvent(form forms.WebhookForm) *webhook.HookEvent { - return &webhook.HookEvent{ +func ParseHookEvent(form forms.WebhookForm) *webhook_module.HookEvent { + return &webhook_module.HookEvent{ PushOnly: form.PushOnly(), SendEverything: form.SendEverything(), ChooseEvents: form.ChooseEvents(), - HookEvents: webhook.HookEvents{ + HookEvents: webhook_module.HookEvents{ Create: form.Create, Delete: form.Delete, Fork: form.Fork, @@ -201,7 +202,7 @@ func createWebhook(ctx *context.Context, params webhookParams) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} + ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}} ctx.Data["HookType"] = params.Type orCtx, err := getOrgRepoCtx(ctx) @@ -326,7 +327,7 @@ func giteaHookParams(ctx *context.Context) webhookParams { } return webhookParams{ - Type: webhook.GITEA, + Type: webhook_module.GITEA, URL: form.PayloadURL, ContentType: contentType, Secret: form.Secret, @@ -354,7 +355,7 @@ func gogsHookParams(ctx *context.Context) webhookParams { } return webhookParams{ - Type: webhook.GOGS, + Type: webhook_module.GOGS, URL: form.PayloadURL, ContentType: contentType, Secret: form.Secret, @@ -376,7 +377,7 @@ func discordHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewDiscordHookForm) return webhookParams{ - Type: webhook.DISCORD, + Type: webhook_module.DISCORD, URL: form.PayloadURL, ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -401,7 +402,7 @@ func dingtalkHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewDingtalkHookForm) return webhookParams{ - Type: webhook.DINGTALK, + Type: webhook_module.DINGTALK, URL: form.PayloadURL, ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -422,7 +423,7 @@ func telegramHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewTelegramHookForm) return webhookParams{ - Type: webhook.TELEGRAM, + Type: webhook_module.TELEGRAM, URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", url.PathEscape(form.BotToken), url.QueryEscape(form.ChatID)), ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -447,7 +448,7 @@ func matrixHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewMatrixHookForm) return webhookParams{ - Type: webhook.MATRIX, + Type: webhook_module.MATRIX, URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, url.PathEscape(form.RoomID)), ContentType: webhook.ContentTypeJSON, HTTPMethod: http.MethodPut, @@ -474,7 +475,7 @@ func mSTeamsHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm) return webhookParams{ - Type: webhook.MSTEAMS, + Type: webhook_module.MSTEAMS, URL: form.PayloadURL, ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -495,7 +496,7 @@ func slackHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewSlackHookForm) return webhookParams{ - Type: webhook.SLACK, + Type: webhook_module.SLACK, URL: form.PayloadURL, ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -522,7 +523,7 @@ func feishuHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewFeishuHookForm) return webhookParams{ - Type: webhook.FEISHU, + Type: webhook_module.FEISHU, URL: form.PayloadURL, ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -543,7 +544,7 @@ func wechatworkHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm) return webhookParams{ - Type: webhook.WECHATWORK, + Type: webhook_module.WECHATWORK, URL: form.PayloadURL, ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -564,7 +565,7 @@ func packagistHookParams(ctx *context.Context) webhookParams { form := web.GetForm(ctx).(*forms.NewPackagistHookForm) return webhookParams{ - Type: webhook.PACKAGIST, + Type: webhook_module.PACKAGIST, URL: fmt.Sprintf("https://packagist.org/api/update-package?username=%s&apiToken=%s", url.QueryEscape(form.Username), url.QueryEscape(form.APIToken)), ContentType: webhook.ContentTypeJSON, WebhookForm: form.WebhookForm, @@ -603,15 +604,15 @@ func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) { ctx.Data["HookType"] = w.Type switch w.Type { - case webhook.SLACK: + case webhook_module.SLACK: ctx.Data["SlackHook"] = webhook_service.GetSlackHook(w) - case webhook.DISCORD: + case webhook_module.DISCORD: ctx.Data["DiscordHook"] = webhook_service.GetDiscordHook(w) - case webhook.TELEGRAM: + case webhook_module.TELEGRAM: ctx.Data["TelegramHook"] = webhook_service.GetTelegramHook(w) - case webhook.MATRIX: + case webhook_module.MATRIX: ctx.Data["MatrixHook"] = webhook_service.GetMatrixHook(w) - case webhook.PACKAGIST: + case webhook_module.PACKAGIST: ctx.Data["PackagistHook"] = webhook_service.GetPackagistHook(w) } @@ -688,7 +689,7 @@ func TestWebhook(ctx *context.Context) { Pusher: apiUser, Sender: apiUser, } - if err := webhook_service.PrepareWebhook(ctx, w, webhook.HookEventPush, p); err != nil { + if err := webhook_service.PrepareWebhook(ctx, w, webhook_module.HookEventPush, p); err != nil { ctx.Flash.Error("PrepareWebhook: " + err.Error()) ctx.Status(http.StatusInternalServerError) } else { diff --git a/routers/web/user/code.go b/routers/web/user/code.go index 0f95932061..81e3e65b4b 100644 --- a/routers/web/user/code.go +++ b/routers/web/user/code.go @@ -26,7 +26,7 @@ func CodeSearch(ctx *context.Context) { ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled - ctx.Data["Title"] = ctx.Tr("code.title") + ctx.Data["Title"] = ctx.Tr("explore.code") ctx.Data["ContextUser"] = ctx.ContextUser language := ctx.FormTrim("l") diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go index 89be795599..ec50eef9c1 100644 --- a/routers/web/user/setting/keys.go +++ b/routers/web/user/setting/keys.go @@ -99,14 +99,18 @@ func KeysPost(ctx *context.Context) { loadKeysData(ctx) ctx.Data["Err_Content"] = true ctx.Data["Err_Signature"] = true - ctx.Data["KeyID"] = err.(asymkey_model.ErrGPGInvalidTokenSignature).ID + keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID + ctx.Data["KeyID"] = keyID + ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID) ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form) case asymkey_model.IsErrGPGNoEmailFound(err): loadKeysData(ctx) ctx.Data["Err_Content"] = true ctx.Data["Err_Signature"] = true - ctx.Data["KeyID"] = err.(asymkey_model.ErrGPGNoEmailFound).ID + keyID := err.(asymkey_model.ErrGPGNoEmailFound).ID + ctx.Data["KeyID"] = keyID + ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID) ctx.RenderWithErr(ctx.Tr("settings.gpg_no_key_email_found"), tplSettingsKeys, &form) default: ctx.ServerError("AddPublicKey", err) @@ -138,7 +142,9 @@ func KeysPost(ctx *context.Context) { loadKeysData(ctx) ctx.Data["VerifyingID"] = form.KeyID ctx.Data["Err_Signature"] = true - ctx.Data["KeyID"] = err.(asymkey_model.ErrGPGInvalidTokenSignature).ID + keyID := err.(asymkey_model.ErrGPGInvalidTokenSignature).ID + ctx.Data["KeyID"] = keyID + ctx.Data["PaddedKeyID"] = asymkey_model.PaddedKeyID(keyID) ctx.RenderWithErr(ctx.Tr("settings.gpg_invalid_token_signature"), tplSettingsKeys, &form) default: ctx.ServerError("VerifyGPG", err) diff --git a/services/convert/convert.go b/services/convert/convert.go index 756a1f95d9..a8329f5285 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -22,13 +22,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/gitdiff" - webhook_service "code.gitea.io/gitea/services/webhook" ) // ToEmail convert models.EmailAddress to api.Email @@ -242,38 +240,6 @@ func ToGPGKeyEmail(email *user_model.EmailAddress) *api.GPGKeyEmail { } } -// ToHook convert models.Webhook to api.Hook -func ToHook(repoLink string, w *webhook.Webhook) (*api.Hook, error) { - config := map[string]string{ - "url": w.URL, - "content_type": w.ContentType.Name(), - } - if w.Type == webhook.SLACK { - s := webhook_service.GetSlackHook(w) - config["channel"] = s.Channel - config["username"] = s.Username - config["icon_url"] = s.IconURL - config["color"] = s.Color - } - - authorizationHeader, err := w.HeaderAuthorization() - if err != nil { - return nil, err - } - - return &api.Hook{ - ID: w.ID, - Type: w.Type, - URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), - Active: w.IsActive, - Config: config, - Events: w.EventsArray(), - AuthorizationHeader: authorizationHeader, - Updated: w.UpdatedUnix.AsTime(), - Created: w.CreatedUnix.AsTime(), - }, nil -} - // ToGitHook convert git.Hook to api.GitHook func ToGitHook(h *git.Hook) *api.GitHook { return &api.GitHook{ diff --git a/services/repository/avatar.go b/services/repository/avatar.go index a829a1000a..5fe8bd2c72 100644 --- a/services/repository/avatar.go +++ b/services/repository/avatar.go @@ -5,7 +5,6 @@ package repository import ( "context" - "crypto/md5" "fmt" "image/png" "io" @@ -27,7 +26,7 @@ func UploadAvatar(repo *repo_model.Repository, data []byte) error { return err } - newAvatar := fmt.Sprintf("%d-%x", repo.ID, md5.Sum(data)) + newAvatar := avatar.HashAvatar(repo.ID, data) if repo.Avatar == newAvatar { // upload the same picture return nil } diff --git a/services/repository/avatar_test.go b/services/repository/avatar_test.go index 3875302696..5ec899ec3f 100644 --- a/services/repository/avatar_test.go +++ b/services/repository/avatar_test.go @@ -5,14 +5,13 @@ package repository import ( "bytes" - "crypto/md5" - "fmt" "image" "image/png" "testing" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/avatar" "github.com/stretchr/testify/assert" ) @@ -28,7 +27,7 @@ func TestUploadAvatar(t *testing.T) { err := UploadAvatar(repo, buff.Bytes()) assert.NoError(t, err) - assert.Equal(t, fmt.Sprintf("%d-%x", 10, md5.Sum(buff.Bytes())), repo.Avatar) + assert.Equal(t, avatar.HashAvatar(10, buff.Bytes()), repo.Avatar) } func TestUploadBigAvatar(t *testing.T) { diff --git a/services/user/user.go b/services/user/user.go index 65db732bf9..c95eb67a85 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -5,7 +5,6 @@ package user import ( "context" - "crypto/md5" "fmt" "image/png" "io" @@ -241,11 +240,7 @@ func UploadAvatar(u *user_model.User, data []byte) error { defer committer.Close() u.UseCustomAvatar = true - // Different users can upload same image as avatar - // If we prefix it with u.ID, it will be separated - // Otherwise, if any of the users delete his avatar - // Other users will lose their avatars too. - u.Avatar = fmt.Sprintf("%x", md5.Sum([]byte(fmt.Sprintf("%d-%x", u.ID, md5.Sum(data))))) + u.Avatar = avatar.HashAvatar(u.ID, data) if err = user_model.UpdateUserCols(ctx, u, "use_custom_avatar", "avatar"); err != nil { return fmt.Errorf("updateUser: %w", err) } diff --git a/services/webhook/deliver.go b/services/webhook/deliver.go index eed711c580..effbe45e56 100644 --- a/services/webhook/deliver.go +++ b/services/webhook/deliver.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/proxy" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/gobwas/glob" ) @@ -89,7 +90,7 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error { } case http.MethodPut: switch w.Type { - case webhook_model.MATRIX: + case webhook_module.MATRIX: txnID, err := getMatrixTxnID([]byte(t.PayloadContent)) if err != nil { return err @@ -189,9 +190,9 @@ func Deliver(ctx context.Context, t *webhook_model.HookTask) error { // Update webhook last delivery status. if t.IsSucceed { - w.LastStatus = webhook_model.HookStatusSucceed + w.LastStatus = webhook_module.HookStatusSucceed } else { - w.LastStatus = webhook_model.HookStatusFail + w.LastStatus = webhook_module.HookStatusFail } if err = webhook_model.UpdateWebhookLastStatus(w); err != nil { log.Error("UpdateWebhookLastStatus: %v", err) diff --git a/services/webhook/deliver_test.go b/services/webhook/deliver_test.go index e7a042f4d2..ee63975ad3 100644 --- a/services/webhook/deliver_test.go +++ b/services/webhook/deliver_test.go @@ -16,6 +16,7 @@ import ( webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" ) @@ -62,14 +63,14 @@ func TestWebhookDeliverAuthorizationHeader(t *testing.T) { URL: s.URL + "/webhook", ContentType: webhook_model.ContentTypeJSON, IsActive: true, - Type: webhook_model.GITEA, + Type: webhook_module.GITEA, } err := hook.SetHeaderAuthorization("Bearer s3cr3t-t0ken") assert.NoError(t, err) assert.NoError(t, webhook_model.CreateWebhook(db.DefaultContext, hook)) db.GetEngine(db.DefaultContext).NoAutoTime().DB().Logger.ShowSQL(true) - hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_model.HookEventPush, Payloader: &api.PushPayload{}} + hookTask := &webhook_model.HookTask{HookID: hook.ID, EventType: webhook_module.HookEventPush, Payloader: &api.PushPayload{}} hookTask, err = webhook_model.CreateHookTask(db.DefaultContext, hookTask) assert.NoError(t, err) diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index 7cb1fb75fc..99ee6e4d19 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -8,11 +8,11 @@ import ( "net/url" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" dingtalk "gitea.com/lunny/dingtalk_webhook" ) @@ -129,7 +129,7 @@ func (d *DingtalkPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, } // Review implements PayloadConvertor Review method -func (d *DingtalkPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (d *DingtalkPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { var text, title string switch p.Action { case api.HookIssueReviewed: @@ -190,6 +190,6 @@ func createDingtalkPayload(title, text, singleTitle, singleURL string) *Dingtalk } // GetDingtalkPayload converts a ding talk webhook into a DingtalkPayload -func GetDingtalkPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetDingtalkPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) { return convertPayloader(new(DingtalkPayload), p, event) } diff --git a/services/webhook/dingtalk_test.go b/services/webhook/dingtalk_test.go index 89b5f9d219..e3122d2f36 100644 --- a/services/webhook/dingtalk_test.go +++ b/services/webhook/dingtalk_test.go @@ -7,8 +7,8 @@ import ( "net/url" "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -162,7 +162,7 @@ func TestDingTalkPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(DingtalkPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &DingtalkPayload{}, pl) diff --git a/services/webhook/discord.go b/services/webhook/discord.go index c9fdc95320..ed44fef404 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type ( @@ -190,7 +191,7 @@ func (d *DiscordPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, } // Review implements PayloadConvertor Review method -func (d *DiscordPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (d *DiscordPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { var text, title string var color int switch p.Action { @@ -204,11 +205,11 @@ func (d *DiscordPayload) Review(p *api.PullRequestPayload, event webhook_model.H text = p.Review.Content switch event { - case webhook_model.HookEventPullRequestReviewApproved: + case webhook_module.HookEventPullRequestReviewApproved: color = greenColor - case webhook_model.HookEventPullRequestReviewRejected: + case webhook_module.HookEventPullRequestReviewRejected: color = redColor - case webhook_model.HookEventPullRequestComment: + case webhook_module.HookEventPullRequestComment: color = greyColor default: color = yellowColor @@ -256,7 +257,7 @@ func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { } // GetDiscordPayload converts a discord webhook into a DiscordPayload -func GetDiscordPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetDiscordPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) { s := new(DiscordPayload) discord := &DiscordMeta{} @@ -269,14 +270,14 @@ func GetDiscordPayload(p api.Payloader, event webhook_model.HookEventType, meta return convertPayloader(s, p, event) } -func parseHookPullRequestEventType(event webhook_model.HookEventType) (string, error) { +func parseHookPullRequestEventType(event webhook_module.HookEventType) (string, error) { switch event { - case webhook_model.HookEventPullRequestReviewApproved: + case webhook_module.HookEventPullRequestReviewApproved: return "approved", nil - case webhook_model.HookEventPullRequestReviewRejected: + case webhook_module.HookEventPullRequestReviewRejected: return "rejected", nil - case webhook_model.HookEventPullRequestComment: + case webhook_module.HookEventPullRequestComment: return "comment", nil default: diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index df3cdc15bd..624d53446a 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -6,9 +6,9 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -179,7 +179,7 @@ func TestDiscordPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(DiscordPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &DiscordPayload{}, pl) diff --git a/services/webhook/feishu.go b/services/webhook/feishu.go index 58b6fff331..4fbf8f76a9 100644 --- a/services/webhook/feishu.go +++ b/services/webhook/feishu.go @@ -7,10 +7,10 @@ import ( "fmt" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type ( @@ -117,7 +117,7 @@ func (f *FeishuPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, e } // Review implements PayloadConvertor Review method -func (f *FeishuPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (f *FeishuPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { action, err := parseHookPullRequestEventType(event) if err != nil { return nil, err @@ -159,6 +159,6 @@ func (f *FeishuPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { } // GetFeishuPayload converts a ding talk webhook into a FeishuPayload -func GetFeishuPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetFeishuPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) { return convertPayloader(new(FeishuPayload), p, event) } diff --git a/services/webhook/feishu_test.go b/services/webhook/feishu_test.go index df44fd1f72..84549c1fa5 100644 --- a/services/webhook/feishu_test.go +++ b/services/webhook/feishu_test.go @@ -6,8 +6,8 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -124,7 +124,7 @@ func TestFeishuPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(FeishuPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &FeishuPayload{}, pl) diff --git a/services/webhook/general.go b/services/webhook/general.go index bec752cffe..1f7d204d1f 100644 --- a/services/webhook/general.go +++ b/services/webhook/general.go @@ -9,9 +9,11 @@ import ( "net/url" "strings" + webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type linkFormatter = func(string, string) string @@ -223,3 +225,36 @@ func getIssueCommentPayloadInfo(p *api.IssueCommentPayload, linkFormatter linkFo return text, issueTitle, color } + +// ToHook convert models.Webhook to api.Hook +// This function is not part of the convert package to prevent an import cycle +func ToHook(repoLink string, w *webhook_model.Webhook) (*api.Hook, error) { + config := map[string]string{ + "url": w.URL, + "content_type": w.ContentType.Name(), + } + if w.Type == webhook_module.SLACK { + s := GetSlackHook(w) + config["channel"] = s.Channel + config["username"] = s.Username + config["icon_url"] = s.IconURL + config["color"] = s.Color + } + + authorizationHeader, err := w.HeaderAuthorization() + if err != nil { + return nil, err + } + + return &api.Hook{ + ID: w.ID, + Type: w.Type, + URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), + Active: w.IsActive, + Config: config, + Events: w.EventsArray(), + AuthorizationHeader: authorizationHeader, + Updated: w.UpdatedUnix.AsTime(), + Created: w.CreatedUnix.AsTime(), + }, nil +} diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index bd3efd46b2..cf2b503cdc 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" ) const matrixPayloadSizeLimit = 1024 * 64 @@ -173,7 +174,7 @@ func (m *MatrixPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, e } // Review implements PayloadConvertor Review method -func (m *MatrixPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (m *MatrixPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { senderLink := MatrixLinkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName) title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) titleLink := MatrixLinkFormatter(p.PullRequest.URL, title) @@ -210,7 +211,7 @@ func (m *MatrixPayload) Repository(p *api.RepositoryPayload) (api.Payloader, err } // GetMatrixPayload converts a Matrix webhook into a MatrixPayload -func GetMatrixPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetMatrixPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) { s := new(MatrixPayload) matrix := &MatrixMeta{} diff --git a/services/webhook/matrix_test.go b/services/webhook/matrix_test.go index 754234eccf..8c71094228 100644 --- a/services/webhook/matrix_test.go +++ b/services/webhook/matrix_test.go @@ -6,8 +6,8 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -133,7 +133,7 @@ func TestMatrixPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(MatrixPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &MatrixPayload{}, pl) diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index ef8366f8d5..03d92821b9 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -8,11 +8,11 @@ import ( "net/url" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type ( @@ -205,7 +205,7 @@ func (m *MSTeamsPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, } // Review implements PayloadConvertor Review method -func (m *MSTeamsPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (m *MSTeamsPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { var text, title string var color int switch p.Action { @@ -219,11 +219,11 @@ func (m *MSTeamsPayload) Review(p *api.PullRequestPayload, event webhook_model.H text = p.Review.Content switch event { - case webhook_model.HookEventPullRequestReviewApproved: + case webhook_module.HookEventPullRequestReviewApproved: color = greenColor - case webhook_model.HookEventPullRequestReviewRejected: + case webhook_module.HookEventPullRequestReviewRejected: color = redColor - case webhook_model.HookEventPullRequestComment: + case webhook_module.HookEventPullRequestComment: color = greyColor default: color = yellowColor @@ -297,7 +297,7 @@ func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { } // GetMSTeamsPayload converts a MSTeams webhook into a MSTeamsPayload -func GetMSTeamsPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetMSTeamsPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) { return convertPayloader(new(MSTeamsPayload), p, event) } diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go index 8daf99f867..4f378713cc 100644 --- a/services/webhook/msteams_test.go +++ b/services/webhook/msteams_test.go @@ -6,8 +6,8 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -277,7 +277,7 @@ func TestMSTeamsPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(MSTeamsPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &MSTeamsPayload{}, pl) diff --git a/modules/notification/webhook/webhook.go b/services/webhook/notifier.go similarity index 80% rename from modules/notification/webhook/webhook.go rename to services/webhook/notifier.go index 97d5e04340..ee80766032 100644 --- a/modules/notification/webhook/webhook.go +++ b/services/webhook/notifier.go @@ -13,17 +13,21 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "code.gitea.io/gitea/services/convert" - webhook_services "code.gitea.io/gitea/services/webhook" ) +func init() { + notification.RegisterNotifier(&webhookNotifier{}) +} + type webhookNotifier struct { base.NullNotifier } @@ -54,7 +58,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user return } - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestLabel, &api.PullRequestPayload{ Action: api.HookIssueLabelCleared, Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), @@ -62,7 +66,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user Sender: convert.ToUser(doer, nil), }) } else { - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueLabel, &api.IssuePayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelCleared, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), @@ -80,7 +84,7 @@ func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_m mode, _ := access_model.AccessLevel(ctx, doer, repo) // forked webhook - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: oldRepo}, webhook.HookEventFork, &api.ForkPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: oldRepo}, webhook_module.HookEventFork, &api.ForkPayload{ Forkee: convert.ToRepo(ctx, oldRepo, oldMode), Repo: convert.ToRepo(ctx, repo, mode), Sender: convert.ToUser(doer, nil), @@ -92,7 +96,7 @@ func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_m // Add to hook queue for created repo after session commit. if u.IsOrganization() { - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), @@ -105,7 +109,7 @@ func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_m func (m *webhookNotifier) NotifyCreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { // Add to hook queue for created repo after session commit. - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), @@ -116,7 +120,7 @@ func (m *webhookNotifier) NotifyCreateRepository(ctx context.Context, doer, u *u } func (m *webhookNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoDeleted, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(repo.MustOwner(ctx), nil), @@ -128,7 +132,7 @@ func (m *webhookNotifier) NotifyDeleteRepository(ctx context.Context, doer *user func (m *webhookNotifier) NotifyMigrateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_model.Repository) { // Add to hook queue for created repo after session commit. - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), @@ -159,7 +163,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *u apiPullRequest.Action = api.HookIssueAssigned } // Assignee comment triggers a webhook - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestAssign, apiPullRequest); err != nil { + if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestAssign, apiPullRequest); err != nil { log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err) return } @@ -177,7 +181,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *u apiIssue.Action = api.HookIssueAssigned } // Assignee comment triggers a webhook - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueAssign, apiIssue); err != nil { + if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueAssign, apiIssue); err != nil { log.Error("PrepareWebhooks [is_pull: %v, remove_assignee: %v]: %v", issue.IsPull, removed, err) return } @@ -193,7 +197,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user return } issue.PullRequest.Issue = issue - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueEdited, Index: issue.Index, Changes: &api.ChangesPayload{ @@ -206,7 +210,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user Sender: convert.ToUser(doer, nil), }) } else { - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueEdited, Index: issue.Index, Changes: &api.ChangesPayload{ @@ -245,7 +249,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use } else { apiPullRequest.Action = api.HookIssueReOpened } - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, apiPullRequest) + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, apiPullRequest) } else { apiIssue := &api.IssuePayload{ Index: issue.Index, @@ -258,7 +262,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use } else { apiIssue.Action = api.HookIssueReOpened } - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, apiIssue) + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, apiIssue) } if err != nil { log.Error("PrepareWebhooks [is_pull: %v, is_closed: %v]: %v", issue.IsPull, isClosed, err) @@ -276,7 +280,7 @@ func (m *webhookNotifier) NotifyNewIssue(ctx context.Context, issue *issues_mode } mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), @@ -302,7 +306,7 @@ func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues } mode, _ := access_model.AccessLevel(ctx, pull.Issue.Poster, pull.Issue.Repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pull.Issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: pull.Issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueOpened, Index: pull.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pull, nil), @@ -323,7 +327,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *us var err error if issue.IsPull { issue.PullRequest.Issue = issue - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueEdited, Index: issue.Index, Changes: &api.ChangesPayload{ @@ -336,7 +340,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *us Sender: convert.ToUser(doer, nil), }) } else { - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssues, &api.IssuePayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueEdited, Index: issue.Index, Changes: &api.ChangesPayload{ @@ -369,15 +373,15 @@ func (m *webhookNotifier) NotifyUpdateComment(ctx context.Context, doer *user_mo return } - var eventType webhook.HookEventType + var eventType webhook_module.HookEventType if c.Issue.IsPull { - eventType = webhook.HookEventPullRequestComment + eventType = webhook_module.HookEventPullRequestComment } else { - eventType = webhook.HookEventIssueComment + eventType = webhook_module.HookEventIssueComment } mode, _ := access_model.AccessLevel(ctx, doer, c.Issue.Repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentEdited, Issue: convert.ToAPIIssue(ctx, c.Issue), Comment: convert.ToComment(c), @@ -397,15 +401,15 @@ func (m *webhookNotifier) NotifyUpdateComment(ctx context.Context, doer *user_mo func (m *webhookNotifier) NotifyCreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { - var eventType webhook.HookEventType + var eventType webhook_module.HookEventType if issue.IsPull { - eventType = webhook.HookEventPullRequestComment + eventType = webhook_module.HookEventPullRequestComment } else { - eventType = webhook.HookEventIssueComment + eventType = webhook_module.HookEventIssueComment } mode, _ := access_model.AccessLevel(ctx, doer, repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentCreated, Issue: convert.ToAPIIssue(ctx, issue), Comment: convert.ToComment(comment), @@ -434,15 +438,15 @@ func (m *webhookNotifier) NotifyDeleteComment(ctx context.Context, doer *user_mo return } - var eventType webhook.HookEventType + var eventType webhook_module.HookEventType if comment.Issue.IsPull { - eventType = webhook.HookEventPullRequestComment + eventType = webhook_module.HookEventPullRequestComment } else { - eventType = webhook.HookEventIssueComment + eventType = webhook_module.HookEventIssueComment } mode, _ := access_model.AccessLevel(ctx, doer, comment.Issue.Repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ Action: api.HookIssueCommentDeleted, Issue: convert.ToAPIIssue(ctx, comment.Issue), Comment: convert.ToComment(comment), @@ -456,7 +460,7 @@ func (m *webhookNotifier) NotifyDeleteComment(ctx context.Context, doer *user_mo func (m *webhookNotifier) NotifyNewWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { // Add to hook queue for created wiki page. - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiCreated, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), @@ -469,7 +473,7 @@ func (m *webhookNotifier) NotifyNewWikiPage(ctx context.Context, doer *user_mode func (m *webhookNotifier) NotifyEditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page, comment string) { // Add to hook queue for edit wiki page. - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiEdited, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), @@ -482,7 +486,7 @@ func (m *webhookNotifier) NotifyEditWikiPage(ctx context.Context, doer *user_mod func (m *webhookNotifier) NotifyDeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, page string) { // Add to hook queue for edit wiki page. - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiDeleted, Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), @@ -517,7 +521,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *use log.Error("LoadIssue: %v", err) return } - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestLabel, &api.PullRequestPayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestLabel, &api.PullRequestPayload{ Action: api.HookIssueLabelUpdated, Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), @@ -525,7 +529,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *use Sender: convert.ToUser(doer, nil), }) } else { - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueLabel, &api.IssuePayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueLabel, &api.IssuePayload{ Action: api.HookIssueLabelUpdated, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), @@ -559,7 +563,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer * log.Error("LoadIssue: %v", err) return } - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequestMilestone, &api.PullRequestPayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestMilestone, &api.PullRequestPayload{ Action: hookAction, Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), @@ -567,7 +571,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer * Sender: convert.ToUser(doer, nil), }) } else { - err = webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventIssueMilestone, &api.IssuePayload{ + err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventIssueMilestone, &api.IssuePayload{ Action: hookAction, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), @@ -588,7 +592,7 @@ func (m *webhookNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mo return } - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventPush, &api.PushPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{ Ref: opts.RefFullName, Before: opts.OldCommitID, After: opts.NewCommitID, @@ -641,7 +645,7 @@ func (*webhookNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_m Action: api.HookIssueClosed, } - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pr.Issue.Repo}, webhook.HookEventPullRequest, apiPullRequest); err != nil { + if err := PrepareWebhooks(ctx, EventSource{Repository: pr.Issue.Repo}, webhook_module.HookEventPullRequest, apiPullRequest); err != nil { log.Error("PrepareWebhooks: %v", err) } } @@ -655,7 +659,7 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(ctx context.Contex issue := pr.Issue mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: issue.Repo}, webhook.HookEventPullRequest, &api.PullRequestPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueEdited, Index: issue.Index, Changes: &api.ChangesPayload{ @@ -672,15 +676,15 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(ctx context.Contex } func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issues_model.PullRequest, review *issues_model.Review, comment *issues_model.Comment, mentions []*user_model.User) { - var reviewHookType webhook.HookEventType + var reviewHookType webhook_module.HookEventType switch review.Type { case issues_model.ReviewTypeApprove: - reviewHookType = webhook.HookEventPullRequestReviewApproved + reviewHookType = webhook_module.HookEventPullRequestReviewApproved case issues_model.ReviewTypeComment: - reviewHookType = webhook.HookEventPullRequestComment + reviewHookType = webhook_module.HookEventPullRequestComment case issues_model.ReviewTypeReject: - reviewHookType = webhook.HookEventPullRequestReviewRejected + reviewHookType = webhook_module.HookEventPullRequestReviewRejected default: // unsupported review webhook type here log.Error("Unsupported review webhook type") @@ -697,7 +701,7 @@ func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issue log.Error("models.AccessLevel: %v", err) return } - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: review.Issue.Repo}, reviewHookType, &api.PullRequestPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: review.Issue.Repo}, reviewHookType, &api.PullRequestPayload{ Action: api.HookIssueReviewed, Index: review.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), @@ -717,7 +721,7 @@ func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_mode apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) refName := git.RefEndName(refFullName) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventCreate, &api.CreatePayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventCreate, &api.CreatePayload{ Ref: refName, Sha: refID, RefType: refType, @@ -738,7 +742,7 @@ func (m *webhookNotifier) NotifyPullRequestSynchronized(ctx context.Context, doe return } - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: pr.Issue.Repo}, webhook.HookEventPullRequestSync, &api.PullRequestPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: pr.Issue.Repo}, webhook_module.HookEventPullRequestSync, &api.PullRequestPayload{ Action: api.HookIssueSynchronized, Index: pr.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), @@ -754,7 +758,7 @@ func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_mode apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) refName := git.RefEndName(refFullName) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventDelete, &api.DeletePayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventDelete, &api.DeletePayload{ Ref: refName, RefType: refType, PusherType: api.PusherTypeUser, @@ -772,7 +776,7 @@ func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model } mode, _ := access_model.AccessLevel(ctx, doer, rel.Repo) - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: rel.Repo}, webhook.HookEventRelease, &api.ReleasePayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: rel.Repo}, webhook_module.HookEventRelease, &api.ReleasePayload{ Action: action, Release: convert.ToRelease(rel), Repository: convert.ToRepo(ctx, rel.Repo, mode), @@ -802,7 +806,7 @@ func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *use return } - if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventPush, &api.PushPayload{ + if err := PrepareWebhooks(ctx, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{ Ref: opts.RefFullName, Before: opts.OldCommitID, After: opts.NewCommitID, @@ -835,7 +839,7 @@ func (m *webhookNotifier) NotifyPackageDelete(ctx context.Context, doer *user_mo } func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_model.PackageDescriptor, action api.HookPackageAction) { - source := webhook_services.EventSource{ + source := EventSource{ Repository: pd.Repository, Owner: pd.Owner, } @@ -846,7 +850,7 @@ func notifyPackage(ctx context.Context, sender *user_model.User, pd *packages_mo return } - if err := webhook_services.PrepareWebhooks(ctx, source, webhook.HookEventPackage, &api.PackagePayload{ + if err := PrepareWebhooks(ctx, source, webhook_module.HookEventPackage, &api.PackagePayload{ Action: action, Package: apiPackage, Sender: convert.ToUser(sender, nil), diff --git a/services/webhook/packagist.go b/services/webhook/packagist.go index 815e1a93e9..e47e7d3285 100644 --- a/services/webhook/packagist.go +++ b/services/webhook/packagist.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type ( @@ -20,7 +21,7 @@ type ( } `json:"repository"` } - // PackagistMeta contains the meta data for the webhook + // PackagistMeta contains the metadata for the webhook PackagistMeta struct { Username string `json:"username"` APIToken string `json:"api_token"` @@ -49,62 +50,62 @@ func (f *PackagistPayload) JSONPayload() ([]byte, error) { var _ PayloadConvertor = &PackagistPayload{} // Create implements PayloadConvertor Create method -func (f *PackagistPayload) Create(p *api.CreatePayload) (api.Payloader, error) { +func (f *PackagistPayload) Create(_ *api.CreatePayload) (api.Payloader, error) { return nil, nil } // Delete implements PayloadConvertor Delete method -func (f *PackagistPayload) Delete(p *api.DeletePayload) (api.Payloader, error) { +func (f *PackagistPayload) Delete(_ *api.DeletePayload) (api.Payloader, error) { return nil, nil } // Fork implements PayloadConvertor Fork method -func (f *PackagistPayload) Fork(p *api.ForkPayload) (api.Payloader, error) { +func (f *PackagistPayload) Fork(_ *api.ForkPayload) (api.Payloader, error) { return nil, nil } // Push implements PayloadConvertor Push method -func (f *PackagistPayload) Push(p *api.PushPayload) (api.Payloader, error) { +func (f *PackagistPayload) Push(_ *api.PushPayload) (api.Payloader, error) { return f, nil } // Issue implements PayloadConvertor Issue method -func (f *PackagistPayload) Issue(p *api.IssuePayload) (api.Payloader, error) { +func (f *PackagistPayload) Issue(_ *api.IssuePayload) (api.Payloader, error) { return nil, nil } // IssueComment implements PayloadConvertor IssueComment method -func (f *PackagistPayload) IssueComment(p *api.IssueCommentPayload) (api.Payloader, error) { +func (f *PackagistPayload) IssueComment(_ *api.IssueCommentPayload) (api.Payloader, error) { return nil, nil } // PullRequest implements PayloadConvertor PullRequest method -func (f *PackagistPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, error) { +func (f *PackagistPayload) PullRequest(_ *api.PullRequestPayload) (api.Payloader, error) { return nil, nil } // Review implements PayloadConvertor Review method -func (f *PackagistPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (f *PackagistPayload) Review(_ *api.PullRequestPayload, _ webhook_module.HookEventType) (api.Payloader, error) { return nil, nil } // Repository implements PayloadConvertor Repository method -func (f *PackagistPayload) Repository(p *api.RepositoryPayload) (api.Payloader, error) { +func (f *PackagistPayload) Repository(_ *api.RepositoryPayload) (api.Payloader, error) { return nil, nil } // Wiki implements PayloadConvertor Wiki method -func (f *PackagistPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { +func (f *PackagistPayload) Wiki(_ *api.WikiPayload) (api.Payloader, error) { return nil, nil } // Release implements PayloadConvertor Release method -func (f *PackagistPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { +func (f *PackagistPayload) Release(_ *api.ReleasePayload) (api.Payloader, error) { return nil, nil } // GetPackagistPayload converts a packagist webhook into a PackagistPayload -func GetPackagistPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetPackagistPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) { s := new(PackagistPayload) packagist := &PackagistMeta{} diff --git a/services/webhook/packagist_test.go b/services/webhook/packagist_test.go index 4941ae3f01..932b56fe9b 100644 --- a/services/webhook/packagist_test.go +++ b/services/webhook/packagist_test.go @@ -6,8 +6,8 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -101,7 +101,7 @@ func TestPackagistPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(PackagistPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.Nil(t, pl) }) diff --git a/services/webhook/payloader.go b/services/webhook/payloader.go index 7b04f1dd36..9eff25628b 100644 --- a/services/webhook/payloader.go +++ b/services/webhook/payloader.go @@ -4,8 +4,8 @@ package webhook import ( - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" ) // PayloadConvertor defines the interface to convert system webhook payload to external payload @@ -18,40 +18,40 @@ type PayloadConvertor interface { IssueComment(*api.IssueCommentPayload) (api.Payloader, error) Push(*api.PushPayload) (api.Payloader, error) PullRequest(*api.PullRequestPayload) (api.Payloader, error) - Review(*api.PullRequestPayload, webhook_model.HookEventType) (api.Payloader, error) + Review(*api.PullRequestPayload, webhook_module.HookEventType) (api.Payloader, error) Repository(*api.RepositoryPayload) (api.Payloader, error) Release(*api.ReleasePayload) (api.Payloader, error) Wiki(*api.WikiPayload) (api.Payloader, error) } -func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_model.HookEventType) (api.Payloader, error) { +func convertPayloader(s PayloadConvertor, p api.Payloader, event webhook_module.HookEventType) (api.Payloader, error) { switch event { - case webhook_model.HookEventCreate: + case webhook_module.HookEventCreate: return s.Create(p.(*api.CreatePayload)) - case webhook_model.HookEventDelete: + case webhook_module.HookEventDelete: return s.Delete(p.(*api.DeletePayload)) - case webhook_model.HookEventFork: + case webhook_module.HookEventFork: return s.Fork(p.(*api.ForkPayload)) - case webhook_model.HookEventIssues, webhook_model.HookEventIssueAssign, webhook_model.HookEventIssueLabel, webhook_model.HookEventIssueMilestone: + case webhook_module.HookEventIssues, webhook_module.HookEventIssueAssign, webhook_module.HookEventIssueLabel, webhook_module.HookEventIssueMilestone: return s.Issue(p.(*api.IssuePayload)) - case webhook_model.HookEventIssueComment, webhook_model.HookEventPullRequestComment: + case webhook_module.HookEventIssueComment, webhook_module.HookEventPullRequestComment: pl, ok := p.(*api.IssueCommentPayload) if ok { return s.IssueComment(pl) } return s.PullRequest(p.(*api.PullRequestPayload)) - case webhook_model.HookEventPush: + case webhook_module.HookEventPush: return s.Push(p.(*api.PushPayload)) - case webhook_model.HookEventPullRequest, webhook_model.HookEventPullRequestAssign, webhook_model.HookEventPullRequestLabel, - webhook_model.HookEventPullRequestMilestone, webhook_model.HookEventPullRequestSync: + case webhook_module.HookEventPullRequest, webhook_module.HookEventPullRequestAssign, webhook_module.HookEventPullRequestLabel, + webhook_module.HookEventPullRequestMilestone, webhook_module.HookEventPullRequestSync: return s.PullRequest(p.(*api.PullRequestPayload)) - case webhook_model.HookEventPullRequestReviewApproved, webhook_model.HookEventPullRequestReviewRejected, webhook_model.HookEventPullRequestReviewComment: + case webhook_module.HookEventPullRequestReviewApproved, webhook_module.HookEventPullRequestReviewRejected, webhook_module.HookEventPullRequestReviewComment: return s.Review(p.(*api.PullRequestPayload), event) - case webhook_model.HookEventRepository: + case webhook_module.HookEventRepository: return s.Repository(p.(*api.RepositoryPayload)) - case webhook_model.HookEventRelease: + case webhook_module.HookEventRelease: return s.Release(p.(*api.ReleasePayload)) - case webhook_model.HookEventWiki: + case webhook_module.HookEventWiki: return s.Wiki(p.(*api.WikiPayload)) } return s, nil diff --git a/services/webhook/slack.go b/services/webhook/slack.go index 1814361a1c..c2d4a7731e 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" ) // SlackMeta contains the slack metadata @@ -231,7 +232,7 @@ func (s *SlackPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, er } // Review implements PayloadConvertor Review method -func (s *SlackPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (s *SlackPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { senderLink := SlackLinkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName) title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) titleLink := fmt.Sprintf("%s/pulls/%d", p.Repository.HTMLURL, p.Index) @@ -278,7 +279,7 @@ func (s *SlackPayload) createPayload(text string, attachments []SlackAttachment) } // GetSlackPayload converts a slack webhook into a SlackPayload -func GetSlackPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetSlackPayload(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) { s := new(SlackPayload) slack := &SlackMeta{} diff --git a/services/webhook/slack_test.go b/services/webhook/slack_test.go index db97b351c5..d9828f374f 100644 --- a/services/webhook/slack_test.go +++ b/services/webhook/slack_test.go @@ -6,8 +6,8 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -124,7 +124,7 @@ func TestSlackPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(SlackPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &SlackPayload{}, pl) diff --git a/services/webhook/telegram.go b/services/webhook/telegram.go index 8bc68490e5..e5c731fc92 100644 --- a/services/webhook/telegram.go +++ b/services/webhook/telegram.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type ( @@ -140,7 +141,7 @@ func (t *TelegramPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, } // Review implements PayloadConvertor Review method -func (t *TelegramPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (t *TelegramPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { var text, attachmentText string switch p.Action { case api.HookIssueReviewed: @@ -185,7 +186,7 @@ func (t *TelegramPayload) Release(p *api.ReleasePayload) (api.Payloader, error) } // GetTelegramPayload converts a telegram webhook into a TelegramPayload -func GetTelegramPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetTelegramPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) { return convertPayloader(new(TelegramPayload), p, event) } diff --git a/services/webhook/telegram_test.go b/services/webhook/telegram_test.go index b092f7e732..b42b0ccda8 100644 --- a/services/webhook/telegram_test.go +++ b/services/webhook/telegram_test.go @@ -6,8 +6,8 @@ package webhook import ( "testing" - webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -124,7 +124,7 @@ func TestTelegramPayload(t *testing.T) { p.Action = api.HookIssueReviewed d := new(TelegramPayload) - pl, err := d.Review(p, webhook_model.HookEventPullRequestReviewApproved) + pl, err := d.Review(p, webhook_module.HookEventPullRequestReviewApproved) require.NoError(t, err) require.NotNil(t, pl) require.IsType(t, &TelegramPayload{}, pl) diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index 21173e7cd8..afd8e3c105 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -18,62 +18,58 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/gobwas/glob" ) type webhook struct { - name webhook_model.HookType - payloadCreator func(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) + name webhook_module.HookType + payloadCreator func(p api.Payloader, event webhook_module.HookEventType, meta string) (api.Payloader, error) } -var webhooks = map[webhook_model.HookType]*webhook{ - webhook_model.SLACK: { - name: webhook_model.SLACK, +var webhooks = map[webhook_module.HookType]*webhook{ + webhook_module.SLACK: { + name: webhook_module.SLACK, payloadCreator: GetSlackPayload, }, - webhook_model.DISCORD: { - name: webhook_model.DISCORD, + webhook_module.DISCORD: { + name: webhook_module.DISCORD, payloadCreator: GetDiscordPayload, }, - webhook_model.DINGTALK: { - name: webhook_model.DINGTALK, + webhook_module.DINGTALK: { + name: webhook_module.DINGTALK, payloadCreator: GetDingtalkPayload, }, - webhook_model.TELEGRAM: { - name: webhook_model.TELEGRAM, + webhook_module.TELEGRAM: { + name: webhook_module.TELEGRAM, payloadCreator: GetTelegramPayload, }, - webhook_model.MSTEAMS: { - name: webhook_model.MSTEAMS, + webhook_module.MSTEAMS: { + name: webhook_module.MSTEAMS, payloadCreator: GetMSTeamsPayload, }, - webhook_model.FEISHU: { - name: webhook_model.FEISHU, + webhook_module.FEISHU: { + name: webhook_module.FEISHU, payloadCreator: GetFeishuPayload, }, - webhook_model.MATRIX: { - name: webhook_model.MATRIX, + webhook_module.MATRIX: { + name: webhook_module.MATRIX, payloadCreator: GetMatrixPayload, }, - webhook_model.WECHATWORK: { - name: webhook_model.WECHATWORK, + webhook_module.WECHATWORK: { + name: webhook_module.WECHATWORK, payloadCreator: GetWechatworkPayload, }, - webhook_model.PACKAGIST: { - name: webhook_model.PACKAGIST, + webhook_module.PACKAGIST: { + name: webhook_module.PACKAGIST, payloadCreator: GetPackagistPayload, }, } -// RegisterWebhook registers a webhook -func RegisterWebhook(name string, webhook *webhook) { - webhooks[name] = webhook -} - // IsValidHookTaskType returns true if a webhook registered func IsValidHookTaskType(name string) bool { - if name == webhook_model.GITEA || name == webhook_model.GOGS { + if name == webhook_module.GITEA || name == webhook_module.GOGS { return true } _, ok := webhooks[name] @@ -157,7 +153,7 @@ func checkBranch(w *webhook_model.Webhook, branch string) bool { } // PrepareWebhook creates a hook task and enqueues it for processing -func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook_model.HookEventType, p api.Payloader) error { +func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook_module.HookEventType, p api.Payloader) error { // Skip sending if webhooks are disabled. if setting.DisableWebhooks { return nil @@ -176,7 +172,7 @@ func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook // Avoid sending "0 new commits" to non-integration relevant webhooks (e.g. slack, discord, etc.). // Integration webhooks (e.g. drone) still receive the required data. if pushEvent, ok := p.(*api.PushPayload); ok && - w.Type != webhook_model.GITEA && w.Type != webhook_model.GOGS && + w.Type != webhook_module.GITEA && w.Type != webhook_module.GOGS && len(pushEvent.Commits) == 0 { return nil } @@ -215,7 +211,7 @@ func PrepareWebhook(ctx context.Context, w *webhook_model.Webhook, event webhook } // PrepareWebhooks adds new webhooks to task queue for given payload. -func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_model.HookEventType, p api.Payloader) error { +func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_module.HookEventType, p api.Payloader) error { owner := source.Owner var ws []*webhook_model.Webhook diff --git a/services/webhook/webhook_test.go b/services/webhook/webhook_test.go index a1f197d809..338b94360b 100644 --- a/services/webhook/webhook_test.go +++ b/services/webhook/webhook_test.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/unittest" webhook_model "code.gitea.io/gitea/models/webhook" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" "github.com/stretchr/testify/assert" ) @@ -32,12 +33,12 @@ func TestPrepareWebhooks(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) hookTasks := []*webhook_model.HookTask{ - {HookID: 1, EventType: webhook_model.HookEventPush}, + {HookID: 1, EventType: webhook_module.HookEventPush}, } for _, hookTask := range hookTasks { unittest.AssertNotExistsBean(t, hookTask) } - assert.NoError(t, PrepareWebhooks(db.DefaultContext, EventSource{Repository: repo}, webhook_model.HookEventPush, &api.PushPayload{Commits: []*api.PayloadCommit{{}}})) + assert.NoError(t, PrepareWebhooks(db.DefaultContext, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Commits: []*api.PayloadCommit{{}}})) for _, hookTask := range hookTasks { unittest.AssertExistsAndLoadBean(t, hookTask) } @@ -48,13 +49,13 @@ func TestPrepareWebhooksBranchFilterMatch(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) hookTasks := []*webhook_model.HookTask{ - {HookID: 4, EventType: webhook_model.HookEventPush}, + {HookID: 4, EventType: webhook_module.HookEventPush}, } for _, hookTask := range hookTasks { unittest.AssertNotExistsBean(t, hookTask) } // this test also ensures that * doesn't handle / in any special way (like shell would) - assert.NoError(t, PrepareWebhooks(db.DefaultContext, EventSource{Repository: repo}, webhook_model.HookEventPush, &api.PushPayload{Ref: "refs/heads/feature/7791", Commits: []*api.PayloadCommit{{}}})) + assert.NoError(t, PrepareWebhooks(db.DefaultContext, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Ref: "refs/heads/feature/7791", Commits: []*api.PayloadCommit{{}}})) for _, hookTask := range hookTasks { unittest.AssertExistsAndLoadBean(t, hookTask) } @@ -65,12 +66,12 @@ func TestPrepareWebhooksBranchFilterNoMatch(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) hookTasks := []*webhook_model.HookTask{ - {HookID: 4, EventType: webhook_model.HookEventPush}, + {HookID: 4, EventType: webhook_module.HookEventPush}, } for _, hookTask := range hookTasks { unittest.AssertNotExistsBean(t, hookTask) } - assert.NoError(t, PrepareWebhooks(db.DefaultContext, EventSource{Repository: repo}, webhook_model.HookEventPush, &api.PushPayload{Ref: "refs/heads/fix_weird_bug"})) + assert.NoError(t, PrepareWebhooks(db.DefaultContext, EventSource{Repository: repo}, webhook_module.HookEventPush, &api.PushPayload{Ref: "refs/heads/fix_weird_bug"})) for _, hookTask := range hookTasks { unittest.AssertNotExistsBean(t, hookTask) diff --git a/services/webhook/wechatwork.go b/services/webhook/wechatwork.go index a77d871dd7..dc8810c4a6 100644 --- a/services/webhook/wechatwork.go +++ b/services/webhook/wechatwork.go @@ -7,10 +7,10 @@ import ( "fmt" "strings" - webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" + webhook_module "code.gitea.io/gitea/modules/webhook" ) type ( @@ -135,7 +135,7 @@ func (f *WechatworkPayload) PullRequest(p *api.PullRequestPayload) (api.Payloade } // Review implements PayloadConvertor Review method -func (f *WechatworkPayload) Review(p *api.PullRequestPayload, event webhook_model.HookEventType) (api.Payloader, error) { +func (f *WechatworkPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { var text, title string switch p.Action { case api.HookIssueReviewed: @@ -180,6 +180,6 @@ func (f *WechatworkPayload) Release(p *api.ReleasePayload) (api.Payloader, error } // GetWechatworkPayload GetWechatworkPayload converts a ding talk webhook into a WechatworkPayload -func GetWechatworkPayload(p api.Payloader, event webhook_model.HookEventType, meta string) (api.Payloader, error) { +func GetWechatworkPayload(p api.Payloader, event webhook_module.HookEventType, _ string) (api.Payloader, error) { return convertPayloader(new(WechatworkPayload), p, event) } diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 63b99136a8..6cb00fdd1d 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -413,7 +413,7 @@
{{svg "octicon-calendar" 16 "mr-3"}} - +
{{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index c86c6744de..c223282596 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -15376,6 +15376,10 @@ "remote_username": { "type": "string", "x-go-name": "RemoteUsername" + }, + "sync_on_commit": { + "type": "boolean", + "x-go-name": "SyncOnCommit" } }, "x-go-package": "code.gitea.io/gitea/modules/structs" @@ -18576,6 +18580,10 @@ "repo_name": { "type": "string", "x-go-name": "RepoName" + }, + "sync_on_commit": { + "type": "boolean", + "x-go-name": "SyncOnCommit" } }, "x-go-package": "code.gitea.io/gitea/modules/structs" diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index fe6c0bbeb1..0968069c3a 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -18,7 +18,7 @@

{{.locale.Tr "settings.gpg_token_required"}}

-