diff --git a/CHANGELOG.md b/CHANGELOG.md index e9ba23b4c493f..e82430e2ce5b8 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 b80602cb61c3d..fbd7d8d81004c 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 3ccef3130cac3..3b2ff4cbbf1f0 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 3f75f26a53d0a..c9df0d21be5fe 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 05cc19c13452c..6d6b18786ccbc 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 2c53867e1e98d..64c293bc25cdc 100644 --- a/go.mod +++ b/go.mod @@ -33,7 +33,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 6388c2b183221..bde61a8c5b154 100644 --- a/go.sum +++ b/go.sum @@ -475,8 +475,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 ecd9041e65612..be019184eb5bb 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 ca0334cc0b1aa..8a8d4fce153d0 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 b3eecb2c9bfe0..1df6db6fa7219 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 f00c3f3e9e675..6d43437ec106a 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 7ccb782fa62f1..4386142861fcb 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 c8ad0c1aa2739..3db8b16528da4 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 fe568b64eb572..ba4cd8e20b995 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 9902b7e4ae371..83558da334e8d 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 a5a2575eec180..b3ee842c1f297 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 06e828e8fa476..0d888a1ec88cb 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 dfd5e244ba28b..2e35c44766ae3 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 5c4837d98b0c8..a804f35de3526 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 36ad745312d26..3b4a1ecf1859a 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 64d1f9d473db1..4b0e789221bd2 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 9bd512755de51..fa12dec40602c 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 6d0fd185a04eb..7f794836dc94e 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 928f9d47d6cdc..759c20abed22b 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 bcf1166408f85..0a07cfe22ad1b 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 2f59b85331d0b..c1d24a4886375 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 f79ce59ee2270..642020bb5e6d8 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 25eba10e05dff..08b429f5e1ec6 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 6d9dd9ec65ac4..9922ff25a2f0e 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 dc6145b417e49..8e16547d929ec 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 631da49f2d5b5..74b12d5057791 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 ce25139b5f743..e6ca49efd0485 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 69e94f8bb6bee..e310858f92ee9 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 194670504896b..596ff182bc751 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 a17483f9af735..f5cfef5b33945 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 2a37ff31d88d3..ccce1447bcf8f 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 5defc67fd7219..c24404c42cf04 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 2bdafb61b698e..c368fc620e2f2 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 0000000000000..50db9c1943a30 --- /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 2e7d5bb603d95..edaf483135b86 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 c3e09bb8a9151..10581eb87f7c6 100644 --- a/modules/notification/notification.go +++ b/modules/notification/notification.go @@ -16,7 +16,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" ) @@ -36,7 +35,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 b98294001c287..36b0b8e421974 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 5bb3fb8930c9e..de11dbee45bf8 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 37a5170dd3b8b..58f268bd48277 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 98b5919a73f2e..fdbd9003b84c2 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 02f67248129de..548d7ed9e56fa 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 033421af96a86..3c478b1c0288c 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 634bbb17e6214..b709eac4c1965 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 36fe665707695..13a066afacc9d 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 14fb755606e97..efb2ba34a4921 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 e2c73c8f3a0de..adc1c05808740 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 7372fc998d99d..8a2d47eda7670 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 9d16a2360bc6b..a814af822fba2 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 ceb65c1c8d24d..280ca1d710070 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 ab879b272e70f..1180463cd79e2 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()) +func TestNewSitemap(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 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", + }, } - test := func(urls []URL, expected string) { - testReal(NewSitemap(), "urlset", urls, expected) - testReal(NewSitemapIndex(), "sitemapindex", urls, expected) + 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 TestNewSitemapIndex(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 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", }, - "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") -} - -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") + 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 21e7751f765e5..55cd133a4fc7b 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 63bd447bf3e6d..e67b9977f080c 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 0000000000000..96012de352002 --- /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 0000000000000..db4ab17931e9c --- /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 0000000000000..b0cd39396978a --- /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 58571fff14d02..a623952aa7387 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 af863bc4b91d0..3bcce6bdf5855 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 1a09cb6f3663b..0d25f173e922b 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 d6f7d1d7f66ca..6423db7d3a214 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 247950a214ae9..1ece4e18ed6d4 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 c1a10b5e78f34..af358fb82fbad 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 ef08a08be0e40..4e435c9599a16 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 757ae7247bf71..100a28d7f6621 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 5fce5a4a803f9..06bfabe3d2d29 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 1a27ececfe1ce..fc202f51cfea3 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 670191debc664..61af512220506 100644 --- a/routers/init.go +++ b/routers/init.go @@ -119,6 +119,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 2b6f107fafd11..bf56e3d0bdc83 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 0f959320615c0..81e3e65b4b67a 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 89be795599bda..ec50eef9c18de 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 756a1f95d9054..a8329f528584f 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 a829a1000ae3d..5fe8bd2c72f88 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 3875302696d03..5ec899ec3f9a7 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 65db732bf917a..c95eb67a851e9 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 eed711c580060..effbe45e56910 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 e7a042f4d2de2..ee63975ad37d1 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 7cb1fb75fc30e..99ee6e4d192b8 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 89b5f9d219dcd..e3122d2f36fca 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 c9fdc95320429..ed44fef404801 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 df3cdc15bddaa..624d53446a981 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 58b6fff3318ef..4fbf8f76a90ae 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 df44fd1f724ab..84549c1fa5764 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 bec752cffe581..1f7d204d1f74c 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 bd3efd46b273a..cf2b503cdc2df 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 754234eccf96f..8c710942280fa 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 ef8366f8d5c77..03d92821b9eb3 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 8daf99f86700b..4f378713cc7c6 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 97d5e04340d93..ee80766032ff1 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 815e1a93e9f1f..e47e7d32850f4 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 4941ae3f01ca9..932b56fe9b9a1 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 7b04f1dd36a94..9eff25628bce8 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 1814361a1cd3c..c2d4a7731e0a4 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 db97b351c5758..d9828f374f0dd 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 8bc68490e5040..e5c731fc9291c 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 b092f7e732069..b42b0ccda8847 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 21173e7cd8255..afd8e3c105cb1 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 a1f197d80935c..338b94360bbff 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 a77d871dd7f6b..dc8810c4a6ae2 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 f6d63639a8295..3e7cbb0c4a04b 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 c86c6744deec2..c2232825966d3 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 fe6c0bbeb1f79..0968069c3a0af 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"}}

-