Compare commits

..

1 Commits

Author SHA1 Message Date
techknowlogick
49a4e4555a [skip ci] Updated translations via Crowdin 2022-10-26 00:20:58 +00:00
193 changed files with 1113 additions and 2365 deletions

View File

@@ -5,6 +5,6 @@ tmp_dir = ".air"
cmd = "make backend"
bin = "gitea"
include_ext = ["go", "tmpl"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services"]
exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"]
include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"]
exclude_regex = ["_test.go$", "_gen.go$"]

View File

@@ -941,8 +941,7 @@ steps:
image: plugins/hugo:latest
pull: always
commands:
# https://github.com/drone-plugins/drone-hugo/issues/36
- apk upgrade --no-cache libcurl && apk add --no-cache make bash curl
- apk add --no-cache make bash curl
- cd docs
- make trans-copy clean build

View File

@@ -4,256 +4,6 @@ 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.18.0](https://github.com/go-gitea/gitea/releases/tag/1.18.0) - 2022-12-22
* 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/1.17.4) - 2022-12-21
* SECURITY
* Do not allow Ghost access to limited visible user/org (#21849) (#21875)
* Fix package access for admins and inactive users (#21580) (#21592)
* ENHANCEMENTS
* Fix button in branch list, avoid unexpected page jump before restore branch actually done (#21562) (#21927)
* Fix vertical align of committer avatar rendered by email address (#21884) (#21919)
* Fix setting HTTP headers after write (#21833) (#21874)
* Ignore line anchor links with leading zeroes (#21728) (#21777)
* Enable Monaco automaticLayout (#21516)
* BUGFIXES
* Do not list active repositories as unadopted (#22034) (#22167)
* Correctly handle moved files in apply patch (#22118) (#22136)
* Fix condition for is_internal (#22095) (#22131)
* Fix permission check on issue/pull lock (#22114)
* Fix sorting admin user list by last login (#22081) (#22106)
* Workaround for container registry push/pull errors (#21862) (#22069)
* Fix issue/PR numbers (#22037) (#22045)
* Handle empty author names (#21902) (#22028)
* Fix ListBranches to handle empty case (#21921) (#22025)
* Fix enabling partial clones on 1.17 (#21809)
* Prevent panic in doctor command when running default checks (#21791) (#21808)
* Upgrade golang.org/x/crypto (#21792) (#21794)
* Init git module before database migration (#21764) (#21766)
* Set last login when activating account (#21731) (#21754)
* Add HEAD fix to gitea doctor (#21352) (#21751)
* Fix UI language switching bug (#21597) (#21748)
* Remove semver compatible flag and change pypi to an array of test cases (#21708) (#21729)
* Allow local package identifiers for PyPI packages (#21690) (#21726)
* Fix repository adoption on Windows (#21646) (#21651)
* Sync git hooks when config file path changed (#21619) (#21625)
* Added check for disabled Packages (#21540) (#21614)
* Fix `Timestamp.IsZero` (#21593) (#21604)
* Fix issues count bug (#21600)
* Support binary deploy in npm packages (#21589)
* Update milestone counters when issue is deleted (#21459) (#21586)
* SessionUser protection against nil pointer dereference (#21581)
* Case-insensitive NuGet symbol file GUID (#21409) (#21575)
* Suppress `ExternalLoginUserNotExist` error (#21504) (#21572)
* Prevent Authorization header for presigned LFS urls (#21531) (#21569)
* Update binding to fix bugs (#21560)
* Fix generating compare link (#21519) (#21530)
* Ignore error when retrieving changed PR review files (#21487) (#21524)
* Fix incorrect notification commit url (#21479) (#21483)
* Display total commit count in hook message (#21400) (#21481)
* Enforce grouped NuGet search results (#21442) (#21480)
* Return 404 when user is not found on avatar (#21476) (#21477)
* Normalize NuGet package version on upload (#22186) (#22201)
* MISC
* Check for zero time instant in TimeStamp.IsZero() (#22171) (#22173)
* Fix warn in database structs sync (#22111)
* Allow for resolution of NPM registry paths that match upstream (#21568) (#21723)
## [1.17.3](https://github.com/go-gitea/gitea/releases/tag/v1.17.3) - 2022-10-15
* SECURITY

View File

@@ -31,7 +31,6 @@ EXPOSE 2222 3000
RUN apk --no-cache add \
bash \
ca-certificates \
dumb-init \
gettext \
git \
curl \
@@ -69,6 +68,6 @@ ENV HOME "/var/lib/gitea/git"
VOLUME ["/var/lib/gitea", "/etc/gitea"]
WORKDIR /var/lib/gitea
ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"]
ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"]
CMD []

View File

@@ -358,7 +358,7 @@ watch-frontend: node-check node_modules
.PHONY: watch-backend
watch-backend: go-check
GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml
$(GO) run $(AIR_PACKAGE) -c .air.toml
.PHONY: test
test: test-frontend test-backend

View File

@@ -413,9 +413,9 @@ var (
Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN",
},
cli.StringFlag{
Name: "host",
Name: "addr",
Value: "",
Usage: "SMTP Host",
Usage: "SMTP Addr",
},
cli.IntFlag{
Name: "port",
@@ -955,8 +955,8 @@ func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error {
}
conf.Auth = c.String("auth-type")
}
if c.IsSet("host") {
conf.Host = c.String("host")
if c.IsSet("addr") {
conf.Addr = c.String("addr")
}
if c.IsSet("port") {
conf.Port = c.Int("port")

View File

@@ -996,9 +996,6 @@ ROUTER = console
;;
;; Add co-authored-by and co-committed-by trailers if committer does not match author
;ADD_CO_COMMITTER_TRAILERS = true
;;
;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply
;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = true
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1553,7 +1550,7 @@ ROUTER = console
;; Prefix displayed before subject in mail
;SUBJECT_PREFIX =
;;
;; Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy".
;; Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy".
;; - sendmail: use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
;; - dummy: send email messages to the log as a testing phase.
;; If your provider does not explicitly say which protocol it uses but does provide a port,

View File

@@ -101,7 +101,6 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
- `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review.
- `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request.
- `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author.
- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **true**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required.
### Repository - Issue (`repository.issue`)
@@ -673,7 +672,7 @@ and
[Gitea 1.17 configuration document](https://github.com/go-gitea/gitea/blob/release/v1.17/docs/content/doc/advanced/config-cheat-sheet.en-us.md)
- `ENABLED`: **false**: Enable to use a mail service.
- `PROTOCOL`: **\<empty\>**: Mail server protocol. One of "smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy". _Before 1.18, this was inferred from a combination of `MAILER_TYPE` and `IS_TLS_ENABLED`._
- `PROTOCOL`: **\<empty\>**: Mail server protocol. One of "smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy". _Before 1.18, this was inferred from a combination of `MAILER_TYPE` and `IS_TLS_ENABLED`._
- SMTP family, if your provider does not explicitly say which protocol it uses but does provide a port, you can set SMTP_PORT instead and this will be inferred.
- **sendmail** Use the operating system's `sendmail` command instead of SMTP. This is common on Linux systems.
- **dummy** Send email messages to the log as a testing phase.

32
go.mod
View File

@@ -15,8 +15,8 @@ require (
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
github.com/NYTimes/gziphandler v1.1.1
github.com/PuerkitoBio/goquery v1.8.0
github.com/alecthomas/chroma/v2 v2.4.0
github.com/blevesearch/bleve/v2 v2.3.5
github.com/alecthomas/chroma/v2 v2.3.0
github.com/blevesearch/bleve/v2 v2.3.4
github.com/buildkite/terminal-to-html/v3 v3.7.0
github.com/caddyserver/certmagic v0.17.2
github.com/chi-middleware/proxy v1.1.1
@@ -94,11 +94,11 @@ require (
github.com/yuin/goldmark-meta v1.1.0
go.jolheiser.com/hcaptcha v0.0.4
go.jolheiser.com/pwn v0.0.3
golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891
golang.org/x/net v0.2.0
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
golang.org/x/net v0.0.0-20220927171203-f486391704dc
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
golang.org/x/sys v0.2.0
golang.org/x/text v0.4.0
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec
golang.org/x/text v0.3.8
golang.org/x/tools v0.1.12
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/ini.v1 v1.67.0
@@ -129,21 +129,21 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bgentry/speakeasy v0.1.0 // indirect
github.com/bits-and-blooms/bitset v1.3.3 // indirect
github.com/blevesearch/bleve_index_api v1.0.4 // indirect
github.com/blevesearch/geo v0.1.15 // indirect
github.com/blevesearch/bleve_index_api v1.0.3 // indirect
github.com/blevesearch/geo v0.1.14 // indirect
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
github.com/blevesearch/gtreap v0.1.1 // indirect
github.com/blevesearch/mmap-go v1.0.4 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.1.3 // indirect
github.com/blevesearch/scorch_segment_api/v2 v2.1.2 // indirect
github.com/blevesearch/segment v0.9.0 // indirect
github.com/blevesearch/snowballstem v0.9.0 // indirect
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
github.com/blevesearch/vellum v1.0.9 // indirect
github.com/blevesearch/zapx/v11 v11.3.6 // indirect
github.com/blevesearch/zapx/v12 v12.3.6 // indirect
github.com/blevesearch/zapx/v13 v13.3.6 // indirect
github.com/blevesearch/zapx/v14 v14.3.6 // indirect
github.com/blevesearch/zapx/v15 v15.3.6 // indirect
github.com/blevesearch/vellum v1.0.8 // indirect
github.com/blevesearch/zapx/v11 v11.3.5 // indirect
github.com/blevesearch/zapx/v12 v12.3.5 // indirect
github.com/blevesearch/zapx/v13 v13.3.5 // indirect
github.com/blevesearch/zapx/v14 v14.3.5 // indirect
github.com/blevesearch/zapx/v15 v15.3.5 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
@@ -302,8 +302,6 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142
replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible
replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix
exclude github.com/gofrs/uuid v3.2.0+incompatible
exclude github.com/gofrs/uuid v4.0.0+incompatible

69
go.sum
View File

@@ -149,6 +149,7 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I=
github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/RoaringBitmap/roaring v1.2.1 h1:58/LJlg/81wfEHd5L9qsHduznOIhyv4qb1yWcSvVq9A=
github.com/RoaringBitmap/roaring v1.2.1/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
@@ -159,10 +160,9 @@ github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw=
github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs=
github.com/alecthomas/chroma/v2 v2.4.0 h1:Loe2ZjT5x3q1bcWwemqyqEi8p11/IV/ncFCeLYDpWC4=
github.com/alecthomas/chroma/v2 v2.4.0/go.mod h1:6kHzqF5O6FUSJzBXW7fXELjb+e+7OXW4UpoPqMO7IBQ=
github.com/alecthomas/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U=
github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
@@ -225,47 +225,52 @@ github.com/bits-and-blooms/bitset v1.3.3/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edY
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM=
github.com/blevesearch/bleve/v2 v2.3.5 h1:1wuR7eB8Fk9UaCaBUfnQt5V7zIpi4VDok9ExN7Rl+/8=
github.com/blevesearch/bleve/v2 v2.3.5/go.mod h1:FneKGHMRrCLrp4X9+iy3wlBqgM2ALucg7bp8jUuAi/s=
github.com/blevesearch/bleve/v2 v2.3.4 h1:SSb7/cwGzo85LWX1jchIsXM8ZiNNMX3shT5lROM63ew=
github.com/blevesearch/bleve/v2 v2.3.4/go.mod h1:Ot0zYum8XQRfPcwhae8bZmNyYubynsoMjVvl1jPqL30=
github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/bleve_index_api v1.0.3 h1:DDSWaPXOZZJ2BB73ZTWjKxydAugjwywcqU+91AAqcAg=
github.com/blevesearch/bleve_index_api v1.0.3/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4=
github.com/blevesearch/bleve_index_api v1.0.4 h1:mtlzsyJjMIlDngqqB1mq8kPryUMIuEVVbRbJHOWEexU=
github.com/blevesearch/bleve_index_api v1.0.4/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms=
github.com/blevesearch/geo v0.1.15 h1:0NybEduqE5fduFRYiUKF0uqybAIFKXYjkBdXKYn7oA4=
github.com/blevesearch/geo v0.1.15/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc=
github.com/blevesearch/geo v0.1.13/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc=
github.com/blevesearch/geo v0.1.14 h1:TTDpJN6l9ck/cUYbXSn4aCElNls0Whe44rcQKsB7EfU=
github.com/blevesearch/geo v0.1.14/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc=
github.com/blevesearch/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:9eJDeqxJ3E7WnLebQUlPD7ZjSce7AnDb9vjGmMCbD0A=
github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo=
github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M=
github.com/blevesearch/goleveldb v1.0.1/go.mod h1:WrU8ltZbIp0wAoig/MHbrPCXSOLpe79nz5lv5nqfYrQ=
github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y=
github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk=
github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA=
github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc=
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU=
github.com/blevesearch/scorch_segment_api/v2 v2.1.3 h1:2UzpR2dR5DvSZk8tVJkcQ7D5xhoK/UBelYw8ttBHrRQ=
github.com/blevesearch/scorch_segment_api/v2 v2.1.3/go.mod h1:eZrfp1y+lUh+DzFjUcTBUSnKGuunyFIpBIvqYVzJfvc=
github.com/blevesearch/scorch_segment_api/v2 v2.1.2 h1:TAte9VZLWda5WAVlZTTZ+GCzEHqGJb4iB2aiZSA6Iv8=
github.com/blevesearch/scorch_segment_api/v2 v2.1.2/go.mod h1:rvoQXZGq8drq7vXbNeyiRzdEOwZkjkiYGf1822i6CRA=
github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac=
github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ=
github.com/blevesearch/snowball v0.6.1/go.mod h1:ZF0IBg5vgpeoUhnMza2v0A/z8m1cWPlwhke08LpNusg=
github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s=
github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs=
github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15amfX2pXlYbFOnF8zNU=
github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q=
github.com/blevesearch/vellum v1.0.3/go.mod h1:2u5ax02KeDuNWu4/C+hVQMD6uLN4txH1JbtpaDNLJRo=
github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRvNBlNMrEVgY=
github.com/blevesearch/vellum v1.0.9 h1:PL+NWVk3dDGPCV0hoDu9XLLJgqU4E5s/dOeEJByQ2uQ=
github.com/blevesearch/vellum v1.0.9/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k=
github.com/blevesearch/vellum v1.0.8 h1:iMGh4lfxza4BnWO/UJTMPlI3HsK9YawjPv+TteVa9ck=
github.com/blevesearch/vellum v1.0.8/go.mod h1:+cpRi/tqq49xUYSQN2P7A5zNSNrS+MscLeeaZ3J46UA=
github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM=
github.com/blevesearch/zapx/v11 v11.3.6 h1:50jET4HUJ6eCqGxdhUt+mjybMvEX2MWyqLGtCx3yUgc=
github.com/blevesearch/zapx/v11 v11.3.6/go.mod h1:B0CzJRj/pS7hJIroflRtFsa9mRHpMSucSgre0FVINns=
github.com/blevesearch/zapx/v11 v11.3.5 h1:eBQWQ7huA+mzm0sAGnZDwgGGli7S45EO+N+ObFWssbI=
github.com/blevesearch/zapx/v11 v11.3.5/go.mod h1:5UdIa/HRMdeRCiLQOyFESsnqBGiip7vQmYReA9toevU=
github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A=
github.com/blevesearch/zapx/v12 v12.3.6 h1:G304NHBLgQeZ+IHK/XRCM0nhHqAts8MEvHI6LhoDNM4=
github.com/blevesearch/zapx/v12 v12.3.6/go.mod h1:iYi7tIKpauwU5os5wTxJITixr5Km21Hl365otMwdaP0=
github.com/blevesearch/zapx/v12 v12.3.5 h1:5pX2hU+R1aZihT7ac1dNWh1n4wqkIM9pZzWp0ANED9s=
github.com/blevesearch/zapx/v12 v12.3.5/go.mod h1:ANcthYRZQycpbRut/6ArF5gP5HxQyJqiFcuJCBju/ss=
github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ=
github.com/blevesearch/zapx/v13 v13.3.6 h1:vavltQHNdjQezhLZs5nIakf+w/uOa1oqZxB58Jy/3Ig=
github.com/blevesearch/zapx/v13 v13.3.6/go.mod h1:X+FsTwCU8qOHtK0d/ArvbOH7qiIgViSQ1GQvcR6LSkI=
github.com/blevesearch/zapx/v13 v13.3.5 h1:eJ3gbD+Nu8p36/O6lhfdvWQ4pxsGYSuTOBrLLPVWJ74=
github.com/blevesearch/zapx/v13 v13.3.5/go.mod h1:FV+dRnScFgKnRDIp08RQL4JhVXt1x2HE3AOzqYa6fjo=
github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g=
github.com/blevesearch/zapx/v14 v14.3.6 h1:b9lub7TvcwUyJxK/cQtnN79abngKxsI7zMZnICU0WhE=
github.com/blevesearch/zapx/v14 v14.3.6/go.mod h1:9X8W3XoikagU0rwcTqwZho7p9cC7m7zhPZO94S4wUvM=
github.com/blevesearch/zapx/v14 v14.3.5 h1:hEvVjZaagFCvOUJrlFQ6/Z6Jjy0opM3g7TMEo58TwP4=
github.com/blevesearch/zapx/v14 v14.3.5/go.mod h1:954A/eKFb+pg/ncIYWLWCKY+mIjReM9FGTGIO2Wu1cU=
github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A=
github.com/blevesearch/zapx/v15 v15.3.5 h1:NVD0qq8vRk66ImJn1KloXT5ckqPDUZT7VbVJs9jKlac=
github.com/blevesearch/zapx/v15 v15.3.5/go.mod h1:QMUh2hXCaYIWFKPYGavq/Iga2zbHWZ9DZAa9uFbWyvg=
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs=
github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
@@ -356,6 +361,7 @@ github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67/go.mod h1:BQwMFl
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 h1:4KDlx3vjalrHD/EfsjCpV91HNX3JPaIqRtt83zZ7x+Y=
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
@@ -824,7 +830,6 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo=
github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4=
@@ -1482,8 +1487,6 @@ github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87/go.m
github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc=
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/zeripath/zapx/v15 v15.3.6-alignment-fix h1:fKZ9OxEDoJKgM0KBXRbSb5IgKUEXis6C3zEIiMtzzQ0=
github.com/zeripath/zapx/v15 v15.3.6-alignment-fix/go.mod h1:5DbhhDTGtuQSns1tS2aJxJLPc91boXCvjOMeCLD1saM=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE=
github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is=
@@ -1605,8 +1608,8 @@ golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891 h1:WhEPFM1Ck5gaKybeSWvzI7Y/cd8K9K5tJGRxXMACOBA=
golang.org/x/crypto v0.2.1-0.20221112162523-6fad3dfc1891/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be h1:fmw3UbQh+nxngCAHrDCCztao/kbYFnWjoqop8dHx05A=
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1718,8 +1721,8 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.0.0-20220927171203-f486391704dc h1:FxpXZdoBqT8RjqTy6i1E8nXHhW21wK7ptQ/EPIGxzPQ=
golang.org/x/net v0.0.0-20220927171203-f486391704dc/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1873,13 +1876,13 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI=
golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1889,8 +1892,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@@ -272,7 +272,7 @@ func (a *Action) GetRefLink() string {
return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix))
case strings.HasPrefix(a.RefName, git.TagPrefix):
return a.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.TagPrefix))
case len(a.RefName) == git.SHAFullLength && git.IsValidSHAPattern(a.RefName):
case len(a.RefName) == 40 && git.IsValidSHAPattern(a.RefName):
return a.GetRepoLink() + "/src/commit/" + a.RefName
default:
// FIXME: we will just assume it's a branch - this was the old way - at some point we may want to enforce that there is always a ref here.

View File

@@ -20,12 +20,8 @@ import (
"code.gitea.io/gitea/modules/setting"
)
const (
// DefaultAvatarClass is the default class of a rendered avatar
DefaultAvatarClass = "ui avatar vm"
// DefaultAvatarPixelSize is the default size in pixels of a rendered avatar
DefaultAvatarPixelSize = 28
)
// DefaultAvatarPixelSize is the default size in pixels of a rendered avatar
const DefaultAvatarPixelSize = 28
// EmailHash represents a pre-generated hash map (mainly used by LibravatarURL, it queries email server's DNS records)
type EmailHash struct {
@@ -154,11 +150,10 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
return DefaultAvatarLink()
}
enableFederatedAvatarSetting, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
enableFederatedAvatar := enableFederatedAvatarSetting.GetValueBool()
enableFederatedAvatar, _ := system_model.GetSetting(system_model.KeyPictureEnableFederatedAvatar)
var err error
if enableFederatedAvatar && system_model.LibravatarService != nil {
if enableFederatedAvatar != nil && enableFederatedAvatar.GetValueBool() && system_model.LibravatarService != nil {
emailHash := saveEmailHash(email)
if final {
// for final link, we can spend more time on slow external query
@@ -176,10 +171,8 @@ func generateEmailAvatarLink(email string, size int, final bool) string {
return urlStr
}
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
disableGravatar := disableGravatarSetting.GetValueBool()
if !disableGravatar {
disableGravatar, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
if disableGravatar != nil && !disableGravatar.GetValueBool() {
// copy GravatarSourceURL, because we will modify its Path.
avatarURLCopy := *system_model.GravatarSourceURL
avatarURLCopy.Path = path.Join(avatarURLCopy.Path, HashEmail(email))

View File

@@ -8,9 +8,6 @@ import (
"context"
"errors"
"fmt"
"strconv"
"code.gitea.io/gitea/modules/setting"
)
// ResourceIndex represents a resource index which could be used as issue/release and others
@@ -27,6 +24,11 @@ var (
ErrGetResourceIndexFailed = errors.New("get resource index failed")
)
const (
// MaxDupIndexAttempts max retry times to create index
MaxDupIndexAttempts = 3
)
// SyncMaxResourceIndex sync the max index with the resource
func SyncMaxResourceIndex(ctx context.Context, tableName string, groupID, maxIndex int64) (err error) {
e := GetEngine(ctx)
@@ -59,25 +61,8 @@ func SyncMaxResourceIndex(ctx context.Context, tableName string, groupID, maxInd
return nil
}
func postgresGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) {
res, err := GetEngine(ctx).Query(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+
"VALUES (?,1) ON CONFLICT (group_id) DO UPDATE SET max_index = %s.max_index+1 RETURNING max_index",
tableName, tableName), groupID)
if err != nil {
return 0, err
}
if len(res) == 0 {
return 0, ErrGetResourceIndexFailed
}
return strconv.ParseInt(string(res[0]["max_index"]), 10, 64)
}
// GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created
func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) {
if setting.Database.UsePostgreSQL {
return postgresGetNextResourceIndex(ctx, tableName, groupID)
}
e := GetEngine(ctx)
// try to update the max_index to next value, and acquire the write-lock for the record

View File

@@ -7,10 +7,8 @@ package git
import (
"context"
"crypto/sha1"
"errors"
"fmt"
"net/url"
"strconv"
"strings"
"time"
@@ -51,67 +49,79 @@ func init() {
db.RegisterModel(new(CommitStatusIndex))
}
func postgresGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) {
res, err := db.GetEngine(ctx).Query("INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+
"VALUES (?,?,1) ON CONFLICT (repo_id, sha) DO UPDATE SET max_index = `commit_status_index`.max_index+1 RETURNING max_index",
repoID, sha)
if err != nil {
return 0, err
// upsertCommitStatusIndex the function will not return until it acquires the lock or receives an error.
func upsertCommitStatusIndex(ctx context.Context, repoID int64, sha string) (err error) {
// An atomic UPSERT operation (INSERT/UPDATE) is the only operation
// that ensures that the key is actually locked.
switch {
case setting.Database.UseSQLite3 || setting.Database.UsePostgreSQL:
_, err = db.Exec(ctx, "INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+
"VALUES (?,?,1) ON CONFLICT (repo_id,sha) DO UPDATE SET max_index = `commit_status_index`.max_index+1",
repoID, sha)
case setting.Database.UseMySQL:
_, err = db.Exec(ctx, "INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+
"VALUES (?,?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1",
repoID, sha)
case setting.Database.UseMSSQL:
// https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/
_, err = db.Exec(ctx, "MERGE `commit_status_index` WITH (HOLDLOCK) as target "+
"USING (SELECT ? AS repo_id, ? AS sha) AS src "+
"ON src.repo_id = target.repo_id AND src.sha = target.sha "+
"WHEN MATCHED THEN UPDATE SET target.max_index = target.max_index+1 "+
"WHEN NOT MATCHED THEN INSERT (repo_id, sha, max_index) "+
"VALUES (src.repo_id, src.sha, 1);",
repoID, sha)
default:
return fmt.Errorf("database type not supported")
}
if len(res) == 0 {
return 0, db.ErrGetResourceIndexFailed
}
return strconv.ParseInt(string(res[0]["max_index"]), 10, 64)
return err
}
// GetNextCommitStatusIndex retried 3 times to generate a resource index
func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) {
if setting.Database.UsePostgreSQL {
return postgresGetCommitStatusIndex(ctx, repoID, sha)
}
e := db.GetEngine(ctx)
// try to update the max_index to next value, and acquire the write-lock for the record
res, err := e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha)
if err != nil {
return 0, err
}
affected, err := res.RowsAffected()
if err != nil {
return 0, err
}
if affected == 0 {
// this slow path is only for the first time of creating a resource index
_, errIns := e.Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) VALUES (?, ?, 0)", repoID, sha)
res, err = e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha)
func GetNextCommitStatusIndex(repoID int64, sha string) (int64, error) {
for i := 0; i < db.MaxDupIndexAttempts; i++ {
idx, err := getNextCommitStatusIndex(repoID, sha)
if err == db.ErrResouceOutdated {
continue
}
if err != nil {
return 0, err
}
return idx, nil
}
return 0, db.ErrGetResourceIndexFailed
}
affected, err = res.RowsAffected()
if err != nil {
return 0, err
}
// if the update still can not update any records, the record must not exist and there must be some errors (insert error)
if affected == 0 {
if errIns == nil {
return 0, errors.New("impossible error when GetNextCommitStatusIndex, insert and update both succeeded but no record is updated")
}
return 0, errIns
}
// getNextCommitStatusIndex return the next index
func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) {
ctx, commiter, err := db.TxContext()
if err != nil {
return 0, err
}
defer commiter.Close()
var preIdx int64
_, err = db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", repoID, sha).Get(&preIdx)
if err != nil {
return 0, err
}
// now, the new index is in database (protected by the transaction and write-lock)
var newIdx int64
has, err := e.SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id=? AND sha=?", repoID, sha).Get(&newIdx)
if err := upsertCommitStatusIndex(ctx, repoID, sha); err != nil {
return 0, err
}
var curIdx int64
has, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ? AND max_index=?", repoID, sha, preIdx+1).Get(&curIdx)
if err != nil {
return 0, err
}
if !has {
return 0, errors.New("impossible error when GetNextCommitStatusIndex, upsert succeeded but no record can be selected")
return 0, db.ErrResouceOutdated
}
return newIdx, nil
if err := commiter.Commit(); err != nil {
return 0, err
}
return curIdx, nil
}
func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) {
@@ -281,8 +291,10 @@ func NewCommitStatus(opts NewCommitStatusOptions) error {
return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA)
}
if _, err := git.NewIDFromString(opts.SHA); err != nil {
return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err)
// Get the next Status Index
idx, err := GetNextCommitStatusIndex(opts.Repo.ID, opts.SHA)
if err != nil {
return fmt.Errorf("generate commit status index failed: %w", err)
}
ctx, committer, err := db.TxContext()
@@ -291,12 +303,6 @@ func NewCommitStatus(opts NewCommitStatusOptions) error {
}
defer committer.Close()
// Get the next Status Index
idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA)
if err != nil {
return fmt.Errorf("generate commit status index failed: %w", err)
}
opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description)
opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context)
opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL)
@@ -310,7 +316,7 @@ func NewCommitStatus(opts NewCommitStatusOptions) error {
// Insert new CommitStatus
if _, err = db.GetEngine(ctx).Insert(opts.CommitStatus); err != nil {
return fmt.Errorf("insert CommitStatus[%s, %s]: %w", repoPath, opts.SHA, err)
return fmt.Errorf("Insert CommitStatus[%s, %s]: %w", repoPath, opts.SHA, err)
}
return committer.Commit()

View File

@@ -1010,7 +1010,12 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue
}
}
if err := repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.IsPull, false); err != nil {
if opts.IsPull {
_, err = e.Exec("UPDATE `repository` SET num_pulls = num_pulls + 1 WHERE id = ?", opts.Issue.RepoID)
} else {
_, err = e.Exec("UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?", opts.Issue.RepoID)
}
if err != nil {
return err
}

View File

@@ -6,7 +6,6 @@ package issues
import (
"context"
"errors"
"time"
"code.gitea.io/gitea/models/db"
@@ -48,42 +47,33 @@ func (t *TrackedTime) LoadAttributes() (err error) {
}
func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) {
// Load the issue
if t.Issue == nil {
t.Issue, err = GetIssueByID(ctx, t.IssueID)
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
if err != nil {
return
}
}
// Now load the repo for the issue (which we may have just loaded)
if t.Issue != nil {
err = t.Issue.LoadRepo(ctx)
if err != nil && !errors.Is(err, util.ErrNotExist) {
return err
if err != nil {
return
}
}
// Load the user
if t.User == nil {
t.User, err = user_model.GetUserByIDCtx(ctx, t.UserID)
if err != nil {
if !errors.Is(err, util.ErrNotExist) {
return err
}
t.User = user_model.NewGhostUser()
return
}
}
return nil
return err
}
// LoadAttributes load Issue, User
func (tl TrackedTimeList) LoadAttributes() error {
func (tl TrackedTimeList) LoadAttributes() (err error) {
for _, t := range tl {
if err := t.LoadAttributes(); err != nil {
if err = t.LoadAttributes(); err != nil {
return err
}
}
return nil
return err
}
// FindTrackedTimesOptions represent the filters for tracked times. If an ID is 0 it will be ignored.

View File

@@ -14,7 +14,6 @@ import (
"regexp"
"strings"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -514,13 +513,6 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
return nil
}
// Some migration tasks depend on the git command
if git.DefaultContext == nil {
if err = git.InitSimple(context.Background()); err != nil {
return err
}
}
// Migrate
for i, m := range migrations[v-minDBVersion:] {
log.Info("Migration[%d]: %s", v+int64(i), m.Description())

View File

@@ -458,9 +458,8 @@ func CountOrgs(opts FindOrgOptions) (int64, error) {
// HasOrgOrUserVisible tells if the given user can see the given org or user
func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) bool {
// If user is nil, it's an anonymous user/request.
// The Ghost user is handled like an anonymous user.
if user == nil || user.IsGhost() {
// Not SignedUser
if user == nil {
return orgOrUser.Visibility == structs.VisibleTypePublic
}

View File

@@ -305,7 +305,7 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P
sess := db.GetEngine(ctx).
Table("package_version").
Join("LEFT", "package_version pv2", "package_version.package_id = pv2.package_id AND pv2.is_internal = ? AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))", false).
Join("LEFT", "package_version pv2", "package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))").
Join("INNER", "package", "package.id = package_version.package_id").
Where(cond)

View File

@@ -444,7 +444,7 @@ func CheckRepoStats(ctx context.Context) error {
},
// Repository.NumIssues
{
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=?)", false),
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, false),
repoStatsCorrectNumIssues,
"repository count 'num_issues'",
},
@@ -456,7 +456,7 @@ func CheckRepoStats(ctx context.Context) error {
},
// Repository.NumPulls
{
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=?)", true),
statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, true),
repoStatsCorrectNumPulls,
"repository count 'num_pulls'",
},

View File

@@ -12,7 +12,6 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
@@ -36,10 +35,6 @@ func (s *Setting) TableName() string {
}
func (s *Setting) GetValueBool() bool {
if s == nil {
return false
}
b, _ := strconv.ParseBool(s.SettingValue)
return b
}
@@ -80,8 +75,8 @@ func IsErrDataExpired(err error) bool {
return ok
}
// GetSettingNoCache returns specific setting without using the cache
func GetSettingNoCache(key string) (*Setting, error) {
// GetSetting returns specific setting
func GetSetting(key string) (*Setting, error) {
v, err := GetSettings([]string{key})
if err != nil {
return nil, err
@@ -92,24 +87,6 @@ func GetSettingNoCache(key string) (*Setting, error) {
return v[key], nil
}
// GetSetting returns the setting value via the key
func GetSetting(key string) (*Setting, error) {
return cache.Get(genSettingCacheKey(key), func() (*Setting, error) {
res, err := GetSettingNoCache(key)
if err != nil {
return nil, err
}
return res, nil
})
}
// GetSettingBool return bool value of setting,
// none existing keys and errors are ignored and result in false
func GetSettingBool(key string) bool {
s, _ := GetSetting(key)
return s.GetValueBool()
}
// GetSettings returns specific settings
func GetSettings(keys []string) (map[string]*Setting, error) {
for i := 0; i < len(keys); i++ {
@@ -162,13 +139,12 @@ func GetAllSettings() (AllSettings, error) {
// DeleteSetting deletes a specific setting for a user
func DeleteSetting(setting *Setting) error {
cache.Remove(genSettingCacheKey(setting.SettingKey))
_, err := db.GetEngine(db.DefaultContext).Delete(setting)
return err
}
func SetSettingNoVersion(key, value string) error {
s, err := GetSettingNoCache(key)
s, err := GetSetting(key)
if IsErrSettingIsNotExist(err) {
return SetSetting(&Setting{
SettingKey: key,
@@ -184,13 +160,9 @@ 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)
})
if err != nil {
if err := upsertSettingValue(strings.ToLower(setting.SettingKey), setting.SettingValue, setting.Version); err != nil {
return err
}
setting.Version++
return nil
}
@@ -241,7 +213,7 @@ var (
func Init() error {
var disableGravatar bool
disableGravatarSetting, err := GetSettingNoCache(KeyPictureDisableGravatar)
disableGravatarSetting, err := GetSetting(KeyPictureDisableGravatar)
if IsErrSettingIsNotExist(err) {
disableGravatar = setting.GetDefaultDisableGravatar()
disableGravatarSetting = &Setting{SettingValue: strconv.FormatBool(disableGravatar)}
@@ -252,7 +224,7 @@ func Init() error {
}
var enableFederatedAvatar bool
enableFederatedAvatarSetting, err := GetSettingNoCache(KeyPictureEnableFederatedAvatar)
enableFederatedAvatarSetting, err := GetSetting(KeyPictureEnableFederatedAvatar)
if IsErrSettingIsNotExist(err) {
enableFederatedAvatar = setting.GetDefaultEnableFederatedAvatar(disableGravatar)
enableFederatedAvatarSetting = &Setting{SettingValue: strconv.FormatBool(enableFederatedAvatar)}

View File

@@ -9,8 +9,3 @@ const (
KeyPictureDisableGravatar = "picture.disable_gravatar"
KeyPictureEnableFederatedAvatar = "picture.enable_federated_avatar"
)
// genSettingCacheKey returns the cache key for some configuration
func genSettingCacheKey(key string) string {
return "system.setting." + key
}

View File

@@ -89,7 +89,6 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error)
&user_model.UserBadge{UserID: u.ID},
&pull_model.AutoMerge{DoerID: u.ID},
&pull_model.ReviewState{UserID: u.ID},
&user_model.Redirect{RedirectUserID: u.ID},
); err != nil {
return fmt.Errorf("deleteBeans: %w", err)
}

View File

@@ -68,9 +68,11 @@ func (u *User) AvatarLinkWithSize(size int) string {
useLocalAvatar := false
autoGenerateAvatar := false
var disableGravatar bool
disableGravatarSetting, _ := system_model.GetSetting(system_model.KeyPictureDisableGravatar)
disableGravatar := disableGravatarSetting.GetValueBool()
if disableGravatarSetting != nil {
disableGravatar = disableGravatarSetting.GetValueBool()
}
switch {
case u.UseCustomAvatar:

View File

@@ -10,7 +10,6 @@ import (
"strings"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/cache"
"xorm.io/builder"
)
@@ -48,25 +47,9 @@ func IsErrUserSettingIsNotExist(err error) bool {
return ok
}
// genSettingCacheKey returns the cache key for some configuration
func genSettingCacheKey(userID int64, key string) string {
return fmt.Sprintf("user_%d.setting.%s", userID, key)
}
// GetSetting returns the setting value via the key
// GetSetting returns specific setting
func GetSetting(uid int64, key string) (*Setting, error) {
return cache.Get(genSettingCacheKey(uid, key), func() (*Setting, error) {
res, err := GetSettingNoCache(uid, key)
if err != nil {
return nil, err
}
return res, nil
})
}
// GetSettingNoCache returns specific setting without using the cache
func GetSettingNoCache(uid int64, key string) (*Setting, error) {
v, err := GetSettings(uid, []string{key})
v, err := GetUserSettings(uid, []string{key})
if err != nil {
return nil, err
}
@@ -76,8 +59,8 @@ func GetSettingNoCache(uid int64, key string) (*Setting, error) {
return v[key], nil
}
// GetSettings returns specific settings from user
func GetSettings(uid int64, keys []string) (map[string]*Setting, error) {
// GetUserSettings returns specific settings from user
func GetUserSettings(uid int64, keys []string) (map[string]*Setting, error) {
settings := make([]*Setting, 0, len(keys))
if err := db.GetEngine(db.DefaultContext).
Where("user_id=?", uid).
@@ -122,7 +105,6 @@ func GetUserSetting(userID int64, key string, def ...string) (string, error) {
if err := validateUserSettingKey(key); err != nil {
return "", err
}
setting := &Setting{UserID: userID, SettingKey: key}
has, err := db.GetEngine(db.DefaultContext).Get(setting)
if err != nil {
@@ -142,10 +124,7 @@ func DeleteUserSetting(userID int64, key string) error {
if err := validateUserSettingKey(key); err != nil {
return err
}
cache.Remove(genSettingCacheKey(userID, key))
_, err := db.GetEngine(db.DefaultContext).Delete(&Setting{UserID: userID, SettingKey: key})
return err
}
@@ -154,12 +133,7 @@ func SetUserSetting(userID int64, key, value string) error {
if err := validateUserSettingKey(key); err != nil {
return err
}
_, err := cache.Set(genSettingCacheKey(userID, key), func() (string, error) {
return value, upsertUserSettingValue(userID, key, value)
})
return err
return upsertUserSettingValue(userID, key, value)
}
func upsertUserSettingValue(userID int64, key, value string) error {

View File

@@ -27,7 +27,7 @@ func TestSettings(t *testing.T) {
assert.NoError(t, err)
// get specific setting
settings, err := user_model.GetSettings(99, []string{keyName})
settings, err := user_model.GetUserSettings(99, []string{keyName})
assert.NoError(t, err)
assert.Len(t, settings, 1)
assert.EqualValues(t, newSetting.SettingValue, settings[keyName].SettingValue)

View File

@@ -11,7 +11,7 @@ import (
// GetKeyPair function returns a user's private and public keys
func GetKeyPair(user *user_model.User) (pub, priv string, err error) {
var settings map[string]*user_model.Setting
settings, err = user_model.GetSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem})
settings, err = user_model.GetUserSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem})
if err != nil {
return
} else if len(settings) == 0 {

135
modules/cache/cache.go vendored
View File

@@ -46,64 +46,32 @@ 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 {
return getFunc()
}
cached := conn.Get(key)
if cached == nil {
value, err := getFunc()
if err != nil {
if !conn.IsExist(key) {
var (
value string
err error
)
if value, err = getFunc(); err != nil {
return value, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
err = conn.Put(key, value, setting.CacheService.TTLSeconds())
if err != nil {
return "", err
}
}
if value, ok := cached.(string); ok {
return value, nil
value := conn.Get(key)
if v, ok := value.(string); ok {
return v, nil
}
if stringer, ok := cached.(fmt.Stringer); ok {
return stringer.String(), nil
if v, ok := value.(fmt.Stringer); ok {
return v.String(), nil
}
return fmt.Sprintf("%s", cached), nil
return fmt.Sprintf("%s", conn.Get(key)), nil
}
// GetInt returns key value from cache with callback when no key exists in cache
@@ -111,33 +79,30 @@ func GetInt(key string, getFunc func() (int, error)) (int, error) {
if conn == nil || setting.CacheService.TTL == 0 {
return getFunc()
}
cached := conn.Get(key)
if cached == nil {
value, err := getFunc()
if err != nil {
if !conn.IsExist(key) {
var (
value int
err error
)
if value, err = getFunc(); err != nil {
return value, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
}
switch v := cached.(type) {
case int:
return v, nil
case string:
value, err := strconv.Atoi(v)
err = conn.Put(key, value, setting.CacheService.TTLSeconds())
if err != nil {
return 0, err
}
}
switch value := conn.Get(key).(type) {
case int:
return value, nil
default:
value, err := getFunc()
case string:
v, err := strconv.Atoi(value)
if err != nil {
return value, err
return 0, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
return v, nil
default:
return 0, fmt.Errorf("Unsupported cached value type: %v", value)
}
}
@@ -146,34 +111,30 @@ func GetInt64(key string, getFunc func() (int64, error)) (int64, error) {
if conn == nil || setting.CacheService.TTL == 0 {
return getFunc()
}
cached := conn.Get(key)
if cached == nil {
value, err := getFunc()
if err != nil {
if !conn.IsExist(key) {
var (
value int64
err error
)
if value, err = getFunc(); err != nil {
return value, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
}
switch v := conn.Get(key).(type) {
case int64:
return v, nil
case string:
value, err := strconv.ParseInt(v, 10, 64)
err = conn.Put(key, value, setting.CacheService.TTLSeconds())
if err != nil {
return 0, err
}
}
switch value := conn.Get(key).(type) {
case int64:
return value, nil
default:
value, err := getFunc()
case string:
v, err := strconv.ParseInt(value, 10, 64)
if err != nil {
return value, err
return 0, err
}
return value, conn.Put(key, value, setting.CacheService.TTLSeconds())
return v, nil
default:
return 0, fmt.Errorf("Unsupported cached value type: %v", value)
}
}

View File

@@ -29,12 +29,6 @@ func AmbiguousTablesForLocale(locale translation.Locale) []*AmbiguousTable {
key = key[:idx]
}
}
if table == nil && (locale.Language() == "zh-CN" || locale.Language() == "zh_CN") {
table = AmbiguousCharacters["zh-hans"]
}
if table == nil && strings.HasPrefix(locale.Language(), "zh") {
table = AmbiguousCharacters["zh-hant"]
}
if table == nil {
table = AmbiguousCharacters["_default"]
}

View File

@@ -9,7 +9,6 @@
package charset
import (
"bufio"
"io"
"strings"
@@ -33,7 +32,7 @@ func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune)
return streamer.escaped, sb.String()
}
// EscapeControlReaders escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
// EscapeControlReaders escapes the unicode control sequences in a provider reader and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
outputStream := &HTMLStreamerWriter{Writer: writer}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
@@ -45,35 +44,6 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.
return streamer.escaped, err
}
// EscapeControlStringReader escapes the unicode control sequences in a provided reader of string content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte
func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) {
bufRd := bufio.NewReader(reader)
outputStream := &HTMLStreamerWriter{Writer: writer}
streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer)
for {
line, rdErr := bufRd.ReadString('\n')
if len(line) > 0 {
if err := streamer.Text(line); err != nil {
streamer.escaped.HasError = true
log.Error("Error whilst escaping: %v", err)
return streamer.escaped, err
}
}
if rdErr != nil {
if rdErr != io.EOF {
err = rdErr
}
break
}
if err := streamer.SelfClosingTag("br"); err != nil {
streamer.escaped.HasError = true
return streamer.escaped, err
}
}
return streamer.escaped, err
}
// EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string
func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) {
sb := &strings.Builder{}

View File

@@ -220,13 +220,7 @@ func (ctx *APIContext) CheckForOTP() {
func APIAuth(authMethod auth_service.Method) func(*APIContext) {
return func(ctx *APIContext) {
// Get user from session if logged in.
var err error
ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
ctx.Error(http.StatusUnauthorized, "APIAuth", err)
return
}
ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if ctx.Doer != nil {
if ctx.Locale.Language() != ctx.Doer.Language {
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)
@@ -394,7 +388,7 @@ func RepoRefForAPI(next http.Handler) http.Handler {
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if len(refName) == git.SHAFullLength {
} else if len(refName) == 40 {
ctx.Repo.CommitID = refName
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
if err != nil {

View File

@@ -34,7 +34,6 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/auth"
@@ -323,9 +322,9 @@ func (ctx *Context) plainTextInternal(skip, status int, bs []byte) {
if statusPrefix == 4 || statusPrefix == 5 {
log.Log(skip, log.TRACE, "plainTextInternal (status=%d): %s", status, string(bs))
}
ctx.Resp.WriteHeader(status)
ctx.Resp.Header().Set("Content-Type", "text/plain;charset=utf-8")
ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff")
ctx.Resp.WriteHeader(status)
if _, err := ctx.Resp.Write(bs); err != nil {
log.ErrorWithSkip(skip, "plainTextInternal (status=%d): write bytes failed: %v", status, err)
}
@@ -346,61 +345,34 @@ func (ctx *Context) RespHeader() http.Header {
return ctx.Resp.Header()
}
type ServeHeaderOptions struct {
ContentType string // defaults to "application/octet-stream"
ContentTypeCharset string
ContentLength *int64
Disposition string // defaults to "attachment"
Filename string
CacheDuration time.Duration // defaults to 5 minutes
LastModified time.Time
}
// SetServeHeaders sets necessary content serve headers
func (ctx *Context) SetServeHeaders(opts *ServeHeaderOptions) {
header := ctx.Resp.Header()
contentType := typesniffer.ApplicationOctetStream
if opts.ContentType != "" {
if opts.ContentTypeCharset != "" {
contentType = opts.ContentType + "; charset=" + strings.ToLower(opts.ContentTypeCharset)
} else {
contentType = opts.ContentType
}
}
header.Set("Content-Type", contentType)
header.Set("X-Content-Type-Options", "nosniff")
if opts.ContentLength != nil {
header.Set("Content-Length", strconv.FormatInt(*opts.ContentLength, 10))
}
if opts.Filename != "" {
disposition := opts.Disposition
if disposition == "" {
disposition = "attachment"
}
backslashEscapedName := strings.ReplaceAll(strings.ReplaceAll(opts.Filename, `\`, `\\`), `"`, `\"`) // \ -> \\, " -> \"
header.Set("Content-Disposition", fmt.Sprintf(`%s; filename="%s"; filename*=UTF-8''%s`, disposition, backslashEscapedName, url.PathEscape(opts.Filename)))
header.Set("Access-Control-Expose-Headers", "Content-Disposition")
}
duration := opts.CacheDuration
if duration == 0 {
duration = 5 * time.Minute
}
httpcache.AddCacheControlToHeader(header, duration)
if !opts.LastModified.IsZero() {
header.Set("Last-Modified", opts.LastModified.UTC().Format(http.TimeFormat))
}
func (ctx *Context) SetServeHeaders(filename string) {
ctx.Resp.Header().Set("Content-Description", "File Transfer")
ctx.Resp.Header().Set("Content-Type", "application/octet-stream")
ctx.Resp.Header().Set("Content-Disposition", "attachment; filename="+filename)
ctx.Resp.Header().Set("Content-Transfer-Encoding", "binary")
ctx.Resp.Header().Set("Expires", "0")
ctx.Resp.Header().Set("Cache-Control", "must-revalidate")
ctx.Resp.Header().Set("Pragma", "public")
ctx.Resp.Header().Set("Access-Control-Expose-Headers", "Content-Disposition")
}
// ServeContent serves content to http request
func (ctx *Context) ServeContent(r io.ReadSeeker, opts *ServeHeaderOptions) {
ctx.SetServeHeaders(opts)
http.ServeContent(ctx.Resp, ctx.Req, opts.Filename, opts.LastModified, r)
func (ctx *Context) ServeContent(name string, r io.ReadSeeker, modTime time.Time) {
ctx.SetServeHeaders(name)
http.ServeContent(ctx.Resp, ctx.Req, name, modTime, r)
}
// ServeFile serves given file to response.
func (ctx *Context) ServeFile(file string, names ...string) {
var name string
if len(names) > 0 {
name = names[0]
} else {
name = path.Base(file)
}
ctx.SetServeHeaders(name)
http.ServeFile(ctx.Resp, ctx.Req, file)
}
// UploadStream returns the request body or the first form file
@@ -663,13 +635,7 @@ func getCsrfOpts() CsrfOptions {
// Auth converts auth.Auth as a middleware
func Auth(authMethod auth.Method) func(*Context) {
return func(ctx *Context) {
var err error
ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
log.Error("Failed to verify user %v: %v", ctx.Req.RemoteAddr, err)
ctx.Error(http.StatusUnauthorized, "Verify")
return
}
ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if ctx.Doer != nil {
if ctx.Locale.Language() != ctx.Doer.Language {
ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req)

View File

@@ -816,7 +816,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
}
// For legacy and API support only full commit sha
parts := strings.Split(path, "/")
if len(parts) > 0 && len(parts[0]) == git.SHAFullLength {
if len(parts) > 0 && len(parts[0]) == 40 {
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
return parts[0]
}
@@ -852,7 +852,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string {
return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist)
case RepoRefCommit:
parts := strings.Split(path, "/")
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength {
if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= 40 {
ctx.Repo.TreePath = strings.Join(parts[1:], "/")
return parts[0]
}
@@ -961,7 +961,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if len(refName) >= 7 && len(refName) <= git.SHAFullLength {
} else if len(refName) >= 7 && len(refName) <= 40 {
ctx.Repo.IsViewCommit = true
ctx.Repo.CommitID = refName
@@ -971,7 +971,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context
return
}
// If short commit ID add canonical link header
if len(refName) < git.SHAFullLength {
if len(refName) < 40 {
ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"",
util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1))))
}

View File

@@ -110,11 +110,12 @@ func ToAPIIssueList(il issues_model.IssueList) []*api.Issue {
// ToTrackedTime converts TrackedTime to API format
func ToTrackedTime(t *issues_model.TrackedTime) (apiT *api.TrackedTime) {
apiT = &api.TrackedTime{
ID: t.ID,
IssueID: t.IssueID,
UserID: t.UserID,
Time: t.Time,
Created: t.Created,
ID: t.ID,
IssueID: t.IssueID,
UserID: t.UserID,
UserName: t.User.Name,
Time: t.Time,
Created: t.Created,
}
if t.Issue != nil {
apiT.Issue = ToAPIIssue(t.Issue)

View File

@@ -205,9 +205,6 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er
// find stopwatches without existing issue
genericOrphanCheck("Orphaned Stopwatches without existing Issue",
"stopwatch", "issue", "stopwatch.issue_id=`issue`.id"),
// find redirects without existing user.
genericOrphanCheck("Orphaned Redirects without existing redirect user",
"user_redirect", "user", "user_redirect.redirect_user_id=`user`.id"),
)
for _, c := range consistencyChecks {

View File

@@ -19,9 +19,11 @@ func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool)
numReposUpdated := 0
err := iterateRepositories(ctx, func(repo *repo_model.Repository) error {
numRepos++
_, _, defaultBranchErr := git.NewCommand(ctx, "rev-parse").AddDashesAndList(repo.DefaultBranch).RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
runOpts := &git.RunOpts{Dir: repo.RepoPath()}
head, _, headErr := git.NewCommand(ctx, "symbolic-ref", "--short", "HEAD").RunStdString(&git.RunOpts{Dir: repo.RepoPath()})
_, _, defaultBranchErr := git.NewCommand(ctx, "rev-parse").AddDashesAndList(repo.DefaultBranch).RunStdString(runOpts)
head, _, headErr := git.NewCommand(ctx, "symbolic-ref", "--short", "HEAD").RunStdString(runOpts)
// what we expect: default branch is valid, and HEAD points to it
if headErr == nil && defaultBranchErr == nil && head == repo.DefaultBranch {
@@ -47,7 +49,7 @@ func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool)
}
// otherwise, let's try fixing HEAD
err := git.NewCommand(ctx, "symbolic-ref").AddDashesAndList("HEAD", git.BranchPrefix+repo.DefaultBranch).Run(&git.RunOpts{Dir: repo.RepoPath()})
err := git.NewCommand(ctx, "symbolic-ref").AddDashesAndList("HEAD", repo.DefaultBranch).Run(runOpts)
if err != nil {
logger.Warn("Failed to fix HEAD for %s/%s: %v", repo.OwnerName, repo.Name, err)
return nil
@@ -63,7 +65,7 @@ func synchronizeRepoHeads(ctx context.Context, logger log.Logger, autofix bool)
logger.Info("Out of %d repos, HEADs for %d are now fixed and HEADS for %d are still broken", numRepos, numReposUpdated, numDefaultBranchesBroken+numHeadsBroken-numReposUpdated)
} else {
if numHeadsBroken == 0 && numDefaultBranchesBroken == 0 {
logger.Info("All %d repos have their HEADs in the correct state", numRepos)
logger.Info("All %d repos have their HEADs in the correct state")
} else {
if numHeadsBroken == 0 && numDefaultBranchesBroken != 0 {
logger.Critical("Default branches are broken for %d/%d repos", numDefaultBranchesBroken, numRepos)

View File

@@ -202,11 +202,8 @@ func (c *Command) Run(opts *RunOpts) error {
if opts == nil {
opts = &RunOpts{}
}
// We must not change the provided options
timeout := opts.Timeout
if timeout <= 0 {
timeout = defaultCommandExecutionTimeout
if opts.Timeout <= 0 {
opts.Timeout = defaultCommandExecutionTimeout
}
if len(opts.Dir) == 0 {
@@ -241,7 +238,7 @@ func (c *Command) Run(opts *RunOpts) error {
if opts.UseContextTimeout {
ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc)
} else {
ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, timeout, desc)
ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc)
}
defer finished()
@@ -342,20 +339,9 @@ func (c *Command) RunStdBytes(opts *RunOpts) (stdout, stderr []byte, runErr RunS
}
stdoutBuf := &bytes.Buffer{}
stderrBuf := &bytes.Buffer{}
// We must not change the provided options as it could break future calls - therefore make a copy.
newOpts := &RunOpts{
Env: opts.Env,
Timeout: opts.Timeout,
UseContextTimeout: opts.UseContextTimeout,
Dir: opts.Dir,
Stdout: stdoutBuf,
Stderr: stderrBuf,
Stdin: opts.Stdin,
PipelineFunc: opts.PipelineFunc,
}
err := c.Run(newOpts)
opts.Stdout = stdoutBuf
opts.Stderr = stderrBuf
err := c.Run(opts)
stderr = stderrBuf.Bytes()
if err != nil {
return nil, stderr, &runStdError{err: err, stderr: bytesToString(stderr)}

View File

@@ -53,7 +53,7 @@ func (repo *Repository) IsReferenceExist(name string) bool {
// IsBranchExist returns true if given branch exists in current repository.
func (repo *Repository) IsBranchExist(name string) bool {
if repo == nil || name == "" {
if name == "" {
return false
}

View File

@@ -42,7 +42,7 @@ func (repo *Repository) RemoveReference(name string) error {
// ConvertToSHA1 returns a Hash object from a potential ID string
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
if len(commitID) == SHAFullLength {
if len(commitID) == 40 {
sha1, err := NewIDFromString(commitID)
if err == nil {
return sha1, nil

View File

@@ -138,7 +138,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co
// ConvertToSHA1 returns a Hash object from a potential ID string
func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) {
if len(commitID) == SHAFullLength && IsValidSHAPattern(commitID) {
if len(commitID) == 40 && IsValidSHAPattern(commitID) {
sha1, err := NewIDFromString(commitID)
if err == nil {
return sha1, nil

View File

@@ -17,7 +17,7 @@ import (
// ReadTreeToIndex reads a treeish to the index
func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error {
if len(treeish) != SHAFullLength {
if len(treeish) != 40 {
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return err

View File

@@ -16,7 +16,7 @@ import (
// IsTagExist returns true if given tag exists in the repository.
func (repo *Repository) IsTagExist(name string) bool {
if repo == nil || name == "" {
if name == "" {
return false
}

View File

@@ -20,7 +20,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != SHAFullLength {
if len(idStr) != 40 {
res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(&RunOpts{Dir: repo.Path})
if err != nil {
return nil, err

View File

@@ -67,7 +67,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) {
// GetTree find the tree object in the repository.
func (repo *Repository) GetTree(idStr string) (*Tree, error) {
if len(idStr) != SHAFullLength {
if len(idStr) != 40 {
res, err := repo.GetRefCommitID(idStr)
if err != nil {
return nil, err

View File

@@ -18,9 +18,6 @@ const EmptySHA = "0000000000000000000000000000000000000000"
// EmptyTreeSHA is the SHA of an empty tree
const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"
// SHAFullLength is the full length of a git SHA
const SHAFullLength = 40
// SHAPattern can be used to determine if a string is an valid sha
var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`)
@@ -54,7 +51,7 @@ func MustIDFromString(s string) SHA1 {
func NewIDFromString(s string) (SHA1, error) {
var id SHA1
s = strings.TrimSpace(s)
if len(s) != SHAFullLength {
if len(s) != 40 {
return id, fmt.Errorf("Length must be 40: %s", s)
}
b, err := hex.DecodeString(s)

View File

@@ -10,7 +10,6 @@ package git
import (
"bytes"
"strconv"
"strings"
"time"
"github.com/go-git/go-git/v5/plumbing/object"
@@ -31,9 +30,7 @@ type Signature = object.Signature
func newSignatureFromCommitline(line []byte) (_ *Signature, err error) {
sig := new(Signature)
emailStart := bytes.IndexByte(line, '<')
if emailStart > 0 { // Empty name has already occurred, even if it shouldn't
sig.Name = strings.TrimSpace(string(line[:emailStart-1]))
}
sig.Name = string(line[:emailStart-1])
emailEnd := bytes.IndexByte(line, '>')
sig.Email = string(line[emailStart+1 : emailEnd])

View File

@@ -11,7 +11,6 @@ import (
"bytes"
"fmt"
"strconv"
"strings"
"time"
)
@@ -52,9 +51,7 @@ func newSignatureFromCommitline(line []byte) (sig *Signature, err error) {
return
}
if emailStart > 0 { // Empty name has already occurred, even if it shouldn't
sig.Name = strings.TrimSpace(string(line[:emailStart-1]))
}
sig.Name = string(line[:emailStart-1])
sig.Email = string(line[emailStart+1 : emailEnd])
hasTime := emailEnd+2 < len(line)

View File

@@ -165,7 +165,7 @@ func validateOptions(field *api.IssueFormField, idx int) error {
return position.Errorf("should be a string")
}
case api.IssueFormFieldTypeCheckboxes:
opt, ok := option.(map[string]interface{})
opt, ok := option.(map[interface{}]interface{})
if !ok {
return position.Errorf("should be a dictionary")
}
@@ -351,7 +351,7 @@ func (o *valuedOption) Label() string {
return label
}
case api.IssueFormFieldTypeCheckboxes:
if vs, ok := o.data.(map[string]interface{}); ok {
if vs, ok := o.data.(map[interface{}]interface{}); ok {
if v, ok := vs["label"].(string); ok {
return v
}

View File

@@ -6,21 +6,18 @@ package template
import (
"net/url"
"reflect"
"testing"
"code.gitea.io/gitea/modules/json"
api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/require"
)
func TestValidate(t *testing.T) {
tests := []struct {
name string
filename string
content string
want *api.IssueTemplate
wantErr string
name string
content string
wantErr string
}{
{
name: "miss name",
@@ -319,9 +316,21 @@ body:
`,
wantErr: "body[0](checkboxes), option[0]: 'required' should be a bool",
},
{
name: "valid",
content: `
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tmpl, err := unmarshal("test.yaml", []byte(tt.content))
if err != nil {
t.Fatal(err)
}
if err := Validate(tmpl); (err == nil) != (tt.wantErr == "") || err != nil && err.Error() != tt.wantErr {
t.Errorf("Validate() error = %v, wantErr %q", err, tt.wantErr)
}
})
}
t.Run("valid", func(t *testing.T) {
content := `
name: Name
title: Title
about: About
@@ -377,227 +386,96 @@ body:
required: false
- label: Option 3 of checkboxes
required: true
`,
want: &api.IssueTemplate{
Name: "Name",
Title: "Title",
About: "About",
Labels: []string{"label1", "label2"},
Ref: "Ref",
Fields: []*api.IssueFormField{
{
Type: "markdown",
ID: "id1",
Attributes: map[string]interface{}{
"value": "Value of the markdown",
`
want := &api.IssueTemplate{
Name: "Name",
Title: "Title",
About: "About",
Labels: []string{"label1", "label2"},
Ref: "Ref",
Fields: []*api.IssueFormField{
{
Type: "markdown",
ID: "id1",
Attributes: map[string]interface{}{
"value": "Value of the markdown",
},
},
{
Type: "textarea",
ID: "id2",
Attributes: map[string]interface{}{
"label": "Label of textarea",
"description": "Description of textarea",
"placeholder": "Placeholder of textarea",
"value": "Value of textarea",
"render": "bash",
},
Validations: map[string]interface{}{
"required": true,
},
},
{
Type: "input",
ID: "id3",
Attributes: map[string]interface{}{
"label": "Label of input",
"description": "Description of input",
"placeholder": "Placeholder of input",
"value": "Value of input",
},
Validations: map[string]interface{}{
"required": true,
"is_number": true,
"regex": "[a-zA-Z0-9]+",
},
},
{
Type: "dropdown",
ID: "id4",
Attributes: map[string]interface{}{
"label": "Label of dropdown",
"description": "Description of dropdown",
"multiple": true,
"options": []interface{}{
"Option 1 of dropdown",
"Option 2 of dropdown",
"Option 3 of dropdown",
},
},
{
Type: "textarea",
ID: "id2",
Attributes: map[string]interface{}{
"label": "Label of textarea",
"description": "Description of textarea",
"placeholder": "Placeholder of textarea",
"value": "Value of textarea",
"render": "bash",
},
Validations: map[string]interface{}{
"required": true,
},
Validations: map[string]interface{}{
"required": true,
},
{
Type: "input",
ID: "id3",
Attributes: map[string]interface{}{
"label": "Label of input",
"description": "Description of input",
"placeholder": "Placeholder of input",
"value": "Value of input",
},
Validations: map[string]interface{}{
"required": true,
"is_number": true,
"regex": "[a-zA-Z0-9]+",
},
},
{
Type: "dropdown",
ID: "id4",
Attributes: map[string]interface{}{
"label": "Label of dropdown",
"description": "Description of dropdown",
"multiple": true,
"options": []interface{}{
"Option 1 of dropdown",
"Option 2 of dropdown",
"Option 3 of dropdown",
},
},
Validations: map[string]interface{}{
"required": true,
},
},
{
Type: "checkboxes",
ID: "id5",
Attributes: map[string]interface{}{
"label": "Label of checkboxes",
"description": "Description of checkboxes",
"options": []interface{}{
map[string]interface{}{"label": "Option 1 of checkboxes", "required": true},
map[string]interface{}{"label": "Option 2 of checkboxes", "required": false},
map[string]interface{}{"label": "Option 3 of checkboxes", "required": true},
},
},
{
Type: "checkboxes",
ID: "id5",
Attributes: map[string]interface{}{
"label": "Label of checkboxes",
"description": "Description of checkboxes",
"options": []interface{}{
map[interface{}]interface{}{"label": "Option 1 of checkboxes", "required": true},
map[interface{}]interface{}{"label": "Option 2 of checkboxes", "required": false},
map[interface{}]interface{}{"label": "Option 3 of checkboxes", "required": true},
},
},
},
FileName: "test.yaml",
},
wantErr: "",
},
{
name: "single label",
content: `
name: Name
title: Title
about: About
labels: label1
ref: Ref
body:
- type: markdown
id: id1
attributes:
value: Value of the markdown
`,
want: &api.IssueTemplate{
Name: "Name",
Title: "Title",
About: "About",
Labels: []string{"label1"},
Ref: "Ref",
Fields: []*api.IssueFormField{
{
Type: "markdown",
ID: "id1",
Attributes: map[string]interface{}{
"value": "Value of the markdown",
},
},
},
FileName: "test.yaml",
},
wantErr: "",
},
{
name: "comma-delimited labels",
content: `
name: Name
title: Title
about: About
labels: label1,label2,,label3 ,,
ref: Ref
body:
- type: markdown
id: id1
attributes:
value: Value of the markdown
`,
want: &api.IssueTemplate{
Name: "Name",
Title: "Title",
About: "About",
Labels: []string{"label1", "label2", "label3"},
Ref: "Ref",
Fields: []*api.IssueFormField{
{
Type: "markdown",
ID: "id1",
Attributes: map[string]interface{}{
"value": "Value of the markdown",
},
},
},
FileName: "test.yaml",
},
wantErr: "",
},
{
name: "empty string as labels",
content: `
name: Name
title: Title
about: About
labels: ''
ref: Ref
body:
- type: markdown
id: id1
attributes:
value: Value of the markdown
`,
want: &api.IssueTemplate{
Name: "Name",
Title: "Title",
About: "About",
Labels: nil,
Ref: "Ref",
Fields: []*api.IssueFormField{
{
Type: "markdown",
ID: "id1",
Attributes: map[string]interface{}{
"value": "Value of the markdown",
},
},
},
FileName: "test.yaml",
},
wantErr: "",
},
{
name: "comma delimited labels in markdown",
filename: "test.md",
content: `---
name: Name
title: Title
about: About
labels: label1,label2,,label3 ,,
ref: Ref
---
Content
`,
want: &api.IssueTemplate{
Name: "Name",
Title: "Title",
About: "About",
Labels: []string{"label1", "label2", "label3"},
Ref: "Ref",
Fields: nil,
Content: "Content\n",
FileName: "test.md",
},
wantErr: "",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
filename := "test.yaml"
if tt.filename != "" {
filename = tt.filename
}
tmpl, err := unmarshal(filename, []byte(tt.content))
require.NoError(t, err)
if tt.wantErr != "" {
require.EqualError(t, Validate(tmpl), tt.wantErr)
} else {
require.NoError(t, Validate(tmpl))
want, _ := json.Marshal(tt.want)
got, _ := json.Marshal(tmpl)
require.JSONEq(t, string(want), string(got))
}
})
}
FileName: "test.yaml",
}
got, err := unmarshal("test.yaml", []byte(content))
if err != nil {
t.Fatal(err)
}
if err := Validate(got); err != nil {
t.Errorf("Validate() error = %v", err)
}
if !reflect.DeepEqual(want, got) {
jsonWant, _ := json.Marshal(want)
jsonGot, _ := json.Marshal(got)
t.Errorf("want:\n%s\ngot:\n%s", jsonWant, jsonGot)
}
})
}
func TestRenderToMarkdown(t *testing.T) {

View File

@@ -7,16 +7,15 @@ package template
import (
"fmt"
"io"
"path"
"path/filepath"
"strconv"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/util"
"gopkg.in/yaml.v3"
"gopkg.in/yaml.v2"
)
// CouldBe indicates a file with the filename could be a template,
@@ -44,7 +43,7 @@ func Unmarshal(filename string, content []byte) (*api.IssueTemplate, error) {
// UnmarshalFromEntry parses out a valid template from the blob in entry
func UnmarshalFromEntry(entry *git.TreeEntry, dir string) (*api.IssueTemplate, error) {
return unmarshalFromEntry(entry, path.Join(dir, entry.Name())) // Filepaths in Git are ALWAYS '/' separated do not use filepath here
return unmarshalFromEntry(entry, filepath.Join(dir, entry.Name()))
}
// UnmarshalFromCommit parses out a valid template from the commit
@@ -96,27 +95,14 @@ func unmarshal(filename string, content []byte) (*api.IssueTemplate, error) {
}{}
if typ := it.Type(); typ == api.IssueTemplateTypeMarkdown {
if templateBody, err := markdown.ExtractMetadata(string(content), it); err != nil {
// The only thing we know here is that we can't extract metadata from the content,
// it's hard to tell if metadata doesn't exist or metadata isn't valid.
// There's an example template:
//
// ---
// # Title
// ---
// Content
//
// It could be a valid markdown with two horizontal lines, or an invalid markdown with wrong metadata.
it.Content = string(content)
it.Name = path.Base(it.FileName) // paths in Git are always '/' separated - do not use filepath!
it.About, _ = util.SplitStringAtByteN(it.Content, 80)
} else {
it.Content = templateBody
if it.About == "" {
if _, err := markdown.ExtractMetadata(string(content), compatibleTemplate); err == nil && compatibleTemplate.About != "" {
it.About = compatibleTemplate.About
}
templateBody, err := markdown.ExtractMetadata(string(content), it)
if err != nil {
return nil, err
}
it.Content = templateBody
if it.About == "" {
if _, err := markdown.ExtractMetadata(string(content), compatibleTemplate); err == nil && compatibleTemplate.About != "" {
it.About = compatibleTemplate.About
}
}
} else if typ == api.IssueTemplateTypeYaml {

View File

@@ -9,86 +9,82 @@ import (
"strings"
"testing"
"code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
)
/*
IssueTemplate is a legacy to keep the unit tests working.
Copied from structs.IssueTemplate, the original type has been changed a lot to support yaml template.
*/
type IssueTemplate struct {
Name string `json:"name" yaml:"name"`
Title string `json:"title" yaml:"title"`
About string `json:"about" yaml:"about"`
Labels []string `json:"labels" yaml:"labels"`
Ref string `json:"ref" yaml:"ref"`
}
func (it *IssueTemplate) Valid() bool {
func validateMetadata(it structs.IssueTemplate) bool {
/*
A legacy to keep the unit tests working.
Copied from the method "func (it IssueTemplate) Valid() bool", the original method has been removed.
Because it becomes quite complicated to validate an issue template which is support yaml form now.
The new way to validate an issue template is to call the Validate in modules/issue/template,
*/
return strings.TrimSpace(it.Name) != "" && strings.TrimSpace(it.About) != ""
}
func TestExtractMetadata(t *testing.T) {
t.Run("ValidFrontAndBody", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest), &meta)
assert.NoError(t, err)
assert.Equal(t, bodyTest, body)
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
assert.True(t, validateMetadata(meta))
})
t.Run("NoFirstSeparator", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoLastSeparator", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
_, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest), &meta)
assert.Error(t, err)
})
t.Run("NoBody", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
body, err := ExtractMetadata(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest), &meta)
assert.NoError(t, err)
assert.Equal(t, "", body)
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
assert.True(t, validateMetadata(meta))
})
}
func TestExtractMetadataBytes(t *testing.T) {
t.Run("ValidFrontAndBody", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s\n%s", sepTest, frontTest, sepTest, bodyTest)), &meta)
assert.NoError(t, err)
assert.Equal(t, bodyTest, string(body))
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
assert.True(t, validateMetadata(meta))
})
t.Run("NoFirstSeparator", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
_, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", frontTest, sepTest, bodyTest)), &meta)
assert.Error(t, err)
})
t.Run("NoLastSeparator", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
_, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, bodyTest)), &meta)
assert.Error(t, err)
})
t.Run("NoBody", func(t *testing.T) {
var meta IssueTemplate
var meta structs.IssueTemplate
body, err := ExtractMetadataBytes([]byte(fmt.Sprintf("%s\n%s\n%s", sepTest, frontTest, sepTest)), &meta)
assert.NoError(t, err)
assert.Equal(t, "", string(body))
assert.Equal(t, metaTest, meta)
assert.True(t, meta.Valid())
assert.True(t, validateMetadata(meta))
})
}
@@ -101,7 +97,7 @@ labels:
- bug
- "test label"`
bodyTest = "This is the body"
metaTest = IssueTemplate{
metaTest = structs.IssueTemplate{
Name: "Test",
About: "A Test",
Title: "Test Title",

View File

@@ -30,13 +30,6 @@ func (s *ContentStore) Get(key BlobHash256Key) (storage.Object, error) {
return s.store.Open(KeyToRelativePath(key))
}
// FIXME: Workaround to be removed in v1.20
// https://github.com/go-gitea/gitea/issues/19586
func (s *ContentStore) Has(key BlobHash256Key) error {
_, err := s.store.Stat(KeyToRelativePath(key))
return err
}
// Save stores a package blob
func (s *ContentStore) Save(key BlobHash256Key, r io.Reader, size int64) error {
_, err := s.store.Save(KeyToRelativePath(key), r, size)

View File

@@ -6,10 +6,8 @@ package nuget
import (
"archive/zip"
"bytes"
"encoding/xml"
"errors"
"fmt"
"io"
"path/filepath"
"regexp"
@@ -185,23 +183,7 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) {
return &Package{
PackageType: packageType,
ID: p.Metadata.ID,
Version: toNormalizedVersion(v),
Version: v.String(),
Metadata: m,
}, nil
}
// https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#normalized-version-numbers
// https://github.com/NuGet/NuGet.Client/blob/dccbd304b11103e08b97abf4cf4bcc1499d9235a/src/NuGet.Core/NuGet.Versioning/VersionFormatter.cs#L121
func toNormalizedVersion(v *version.Version) string {
var buf bytes.Buffer
segments := v.Segments64()
fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2])
if len(segments) > 3 && segments[3] > 0 {
fmt.Fprintf(&buf, ".%d", segments[3])
}
pre := v.Prerelease()
if pre != "" {
fmt.Fprint(&buf, "-", pre)
}
return buf.String()
}

View File

@@ -147,19 +147,6 @@ func TestParseNuspecMetaData(t *testing.T) {
assert.Len(t, deps, 1)
assert.Equal(t, dependencyID, deps[0].ID)
assert.Equal(t, dependencyVersion, deps[0].Version)
t.Run("NormalizedVersion", func(t *testing.T) {
np, err := ParseNuspecMetaData(strings.NewReader(`<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata>
<id>test</id>
<version>1.04.5.2.5-rc.1+metadata</version>
</metadata>
</package>`))
assert.NoError(t, err)
assert.NotNil(t, np)
assert.Equal(t, "1.4.5.2-rc.1", np.Version)
})
})
t.Run("Symbols Package", func(t *testing.T) {

View File

@@ -18,33 +18,32 @@ import (
// Mailer represents mail service.
type Mailer struct {
// Mailer
Name string `ini:"NAME"`
From string `ini:"FROM"`
EnvelopeFrom string `ini:"ENVELOPE_FROM"`
OverrideEnvelopeFrom bool `ini:"-"`
FromName string `ini:"-"`
FromEmail string `ini:"-"`
SendAsPlainText bool `ini:"SEND_AS_PLAIN_TEXT"`
SubjectPrefix string `ini:"SUBJECT_PREFIX"`
Name string
From string
EnvelopeFrom string
OverrideEnvelopeFrom bool `ini:"-"`
FromName string
FromEmail string
SendAsPlainText bool
SubjectPrefix string
// SMTP sender
Protocol string `ini:"PROTOCOL"`
SMTPAddr string `ini:"SMTP_ADDR"`
SMTPPort string `ini:"SMTP_PORT"`
User string `ini:"USER"`
Passwd string `ini:"PASSWD"`
EnableHelo bool `ini:"ENABLE_HELO"`
HeloHostname string `ini:"HELO_HOSTNAME"`
ForceTrustServerCert bool `ini:"FORCE_TRUST_SERVER_CERT"`
UseClientCert bool `ini:"USE_CLIENT_CERT"`
ClientCertFile string `ini:"CLIENT_CERT_FILE"`
ClientKeyFile string `ini:"CLIENT_KEY_FILE"`
Protocol string
SMTPAddr string
SMTPPort string
User, Passwd string
EnableHelo bool
HeloHostname string
ForceTrustServerCert bool
UseClientCert bool
ClientCertFile string
ClientKeyFile string
// Sendmail sender
SendmailPath string `ini:"SENDMAIL_PATH"`
SendmailArgs []string `ini:"-"`
SendmailTimeout time.Duration `ini:"SENDMAIL_TIMEOUT"`
SendmailConvertCRLF bool `ini:"SENDMAIL_CONVERT_CRLF"`
SendmailPath string
SendmailArgs []string
SendmailTimeout time.Duration
SendmailConvertCRLF bool
}
// MailService the global mailer
@@ -57,12 +56,35 @@ func newMailService() {
return
}
// Handle Deprecations and map on to new configuration
MailService = &Mailer{
Name: sec.Key("NAME").MustString(AppName),
SendAsPlainText: sec.Key("SEND_AS_PLAIN_TEXT").MustBool(false),
Protocol: sec.Key("PROTOCOL").In("", []string{"smtp", "smtps", "smtp+startls", "smtp+unix", "sendmail", "dummy"}),
SMTPAddr: sec.Key("SMTP_ADDR").String(),
SMTPPort: sec.Key("SMTP_PORT").String(),
User: sec.Key("USER").String(),
Passwd: sec.Key("PASSWD").String(),
EnableHelo: sec.Key("ENABLE_HELO").MustBool(true),
HeloHostname: sec.Key("HELO_HOSTNAME").String(),
ForceTrustServerCert: sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(false),
UseClientCert: sec.Key("USE_CLIENT_CERT").MustBool(false),
ClientCertFile: sec.Key("CLIENT_CERT_FILE").String(),
ClientKeyFile: sec.Key("CLIENT_KEY_FILE").String(),
SubjectPrefix: sec.Key("SUBJECT_PREFIX").MustString(""),
SendmailPath: sec.Key("SENDMAIL_PATH").MustString("sendmail"),
SendmailTimeout: sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute),
SendmailConvertCRLF: sec.Key("SENDMAIL_CONVERT_CRLF").MustBool(true),
}
MailService.From = sec.Key("FROM").MustString(MailService.User)
MailService.EnvelopeFrom = sec.Key("ENVELOPE_FROM").MustString("")
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "MAILER_TYPE", "mailer", "PROTOCOL")
if sec.HasKey("MAILER_TYPE") && !sec.HasKey("PROTOCOL") {
if sec.Key("MAILER_TYPE").String() == "sendmail" {
sec.Key("PROTOCOL").MustString("sendmail")
MailService.Protocol = "sendmail"
}
}
@@ -74,91 +96,31 @@ func newMailService() {
if err != nil {
log.Fatal("Invalid mailer.HOST (%s): %v", givenHost, err)
}
sec.Key("SMTP_ADDR").MustString(addr)
sec.Key("SMTP_PORT").MustString(port)
MailService.SMTPAddr = addr
MailService.SMTPPort = port
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "IS_TLS_ENABLED", "mailer", "PROTOCOL")
if sec.HasKey("IS_TLS_ENABLED") && !sec.HasKey("PROTOCOL") {
if sec.Key("IS_TLS_ENABLED").MustBool() {
sec.Key("PROTOCOL").MustString("smtps")
MailService.Protocol = "smtps"
} else {
sec.Key("PROTOCOL").MustString("smtp+starttls")
MailService.Protocol = "smtp+startls"
}
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
sec.Key("ENABLE_HELO").MustBool(!sec.Key("DISABLE_HELO").MustBool())
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(sec.Key("SKIP_VERIFY").MustBool())
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
sec.Key("USE_CLIENT_CERT").MustBool(sec.Key("USE_CERTIFICATE").MustBool())
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
sec.Key("CERT_FILE").MustString(sec.Key("CERT_FILE").String())
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
sec.Key("KEY_FILE").MustString(sec.Key("KEY_FILE").String())
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
sec.Key("SEND_AS_PLAIN_TEXT").MustBool(!sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false))
}
if sec.HasKey("PROTOCOL") && sec.Key("PROTOCOL").String() == "smtp+startls" {
log.Error("Deprecated fallback `[mailer]` `PROTOCOL = smtp+startls` present. Use `[mailer]` `PROTOCOL = smtp+starttls`` instead. This fallback will be removed in v1.19.0")
sec.Key("PROTOCOL").SetValue("smtp+starttls")
}
// Set default values & validate
sec.Key("NAME").MustString(AppName)
sec.Key("PROTOCOL").In("", []string{"smtp", "smtps", "smtp+starttls", "smtp+unix", "sendmail", "dummy"})
sec.Key("ENABLE_HELO").MustBool(true)
sec.Key("FORCE_TRUST_SERVER_CERT").MustBool(false)
sec.Key("USE_CLIENT_CERT").MustBool(false)
sec.Key("SENDMAIL_PATH").MustString("sendmail")
sec.Key("SENDMAIL_TIMEOUT").MustDuration(5 * time.Minute)
sec.Key("SENDMAIL_CONVERT_CRLF").MustBool(true)
sec.Key("FROM").MustString(sec.Key("USER").String())
// Now map the values on to the MailService
MailService = &Mailer{}
if err := sec.MapTo(MailService); err != nil {
log.Fatal("Unable to map [mailer] section on to MailService. Error: %v", err)
}
// Infer SMTPPort if not set
if MailService.SMTPPort == "" {
switch MailService.Protocol {
case "smtp":
MailService.SMTPPort = "25"
case "smtps":
MailService.SMTPPort = "465"
case "smtp+starttls":
case "smtp+startls":
MailService.SMTPPort = "587"
}
}
// Infer Protocol
if MailService.Protocol == "" {
if strings.ContainsAny(MailService.SMTPAddr, "/\\") {
MailService.Protocol = "smtp+unix"
@@ -169,7 +131,7 @@ func newMailService() {
case "465":
MailService.Protocol = "smtps"
case "587":
MailService.Protocol = "smtp+starttls"
MailService.Protocol = "smtp+startls"
default:
log.Error("unable to infer unspecified mailer.PROTOCOL from mailer.SMTP_PORT = %q, assume using smtps", MailService.SMTPPort)
MailService.Protocol = "smtps"
@@ -189,6 +151,42 @@ func newMailService() {
}
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "DISABLE_HELO", "mailer", "ENABLE_HELO")
if sec.HasKey("DISABLE_HELO") && !sec.HasKey("ENABLE_HELO") {
MailService.EnableHelo = !sec.Key("DISABLE_HELO").MustBool()
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "SKIP_VERIFY", "mailer", "FORCE_TRUST_SERVER_CERT")
if sec.HasKey("SKIP_VERIFY") && !sec.HasKey("FORCE_TRUST_SERVER_CERT") {
MailService.ForceTrustServerCert = sec.Key("SKIP_VERIFY").MustBool()
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "USE_CERTIFICATE", "mailer", "USE_CLIENT_CERT")
if sec.HasKey("USE_CERTIFICATE") && !sec.HasKey("USE_CLIENT_CERT") {
MailService.UseClientCert = sec.Key("USE_CLIENT_CERT").MustBool()
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "CERT_FILE", "mailer", "CLIENT_CERT_FILE")
if sec.HasKey("CERT_FILE") && !sec.HasKey("CLIENT_CERT_FILE") {
MailService.ClientCertFile = sec.Key("CERT_FILE").String()
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "KEY_FILE", "mailer", "CLIENT_KEY_FILE")
if sec.HasKey("KEY_FILE") && !sec.HasKey("CLIENT_KEY_FILE") {
MailService.ClientKeyFile = sec.Key("KEY_FILE").String()
}
// FIXME: DEPRECATED to be removed in v1.19.0
deprecatedSetting("mailer", "ENABLE_HTML_ALTERNATIVE", "mailer", "SEND_AS_PLAIN_TEXT")
if sec.HasKey("ENABLE_HTML_ALTERNATIVE") && !sec.HasKey("SEND_AS_PLAIN_TEXT") {
MailService.SendAsPlainText = !sec.Key("ENABLE_HTML_ALTERNATIVE").MustBool(false)
}
if MailService.From != "" {
parsed, err := mail.ParseAddress(MailService.From)
if err != nil {

View File

@@ -83,7 +83,6 @@ var (
DefaultMergeMessageOfficialApproversOnly bool
PopulateSquashCommentWithCommitMessages bool
AddCoCommitterTrailers bool
TestConflictingPatchesWithGitApply bool
} `ini:"repository.pull-request"`
// Issue Setting
@@ -206,7 +205,6 @@ var (
DefaultMergeMessageOfficialApproversOnly bool
PopulateSquashCommentWithCommitMessages bool
AddCoCommitterTrailers bool
TestConflictingPatchesWithGitApply bool
}{
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"},
// Same as GitHub. See
@@ -221,7 +219,6 @@ var (
DefaultMergeMessageOfficialApproversOnly: true,
PopulateSquashCommentWithCommitMessages: false,
AddCoCommitterTrailers: true,
TestConflictingPatchesWithGitApply: true,
},
// Issue settings

View File

@@ -22,7 +22,6 @@ import (
"time"
"code.gitea.io/gitea/modules/container"
"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/user"
@@ -464,13 +463,6 @@ func getAppPath() (string, error) {
appPath, err = exec.LookPath(os.Args[0])
}
if err != nil {
// FIXME: Once we switch to go 1.19 use !errors.Is(err, exec.ErrDot)
if !strings.Contains(err.Error(), "cannot run executable found relative to current directory") {
return "", err
}
appPath, err = filepath.Abs(os.Args[0])
}
if err != nil {
return "", err
}
@@ -610,7 +602,7 @@ func LoadForTest(extraConfigs ...string) {
func deprecatedSetting(oldSection, oldKey, newSection, newKey string) {
if Cfg.Section(oldSection).HasKey(oldKey) {
log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.19.0", oldSection, oldKey, newSection, newKey)
log.Error("Deprecated fallback `[%s]` `%s` present. Use `[%s]` `%s` instead. This fallback will be removed in v1.18.0", oldSection, oldKey, newSection, newKey)
}
}
@@ -970,11 +962,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)
InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN")
if InstallLock && InternalToken == "" {
// if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate
// some users do cluster deployment, they still depend on this auto-generating behavior.
generateSaveInternalToken()
}
cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",")
if len(cfgdata) == 0 {
@@ -1039,10 +1026,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
// The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches.
// Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly.
unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false)
RunMode = os.Getenv("GITEA_RUN_MODE")
if RunMode == "" {
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
}
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
IsProd = strings.EqualFold(RunMode, "prod")
// Does not check run user when the install lock is off.
if InstallLock {
@@ -1166,8 +1150,6 @@ func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
return authorizedPrincipalsAllow, true
}
// loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set
// If the secret is loaded from uriKey (file), the file should be non-empty, to guarantee the behavior stable and clear.
func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string {
// don't allow setting both URI and verbatim string
uri := sec.Key(uriKey).String()
@@ -1191,15 +1173,7 @@ func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string {
if err != nil {
log.Fatal("Failed to read %s (%s): %v", uriKey, tempURI.RequestURI(), err)
}
val := strings.TrimSpace(string(buf))
if val == "" {
// The file shouldn't be empty, otherwise we can not know whether the user has ever set the KEY or KEY_URI
// For example: if INTERNAL_TOKEN_URI=file:///empty-file,
// Then if the token is re-generated during installation and saved to INTERNAL_TOKEN
// Then INTERNAL_TOKEN and INTERNAL_TOKEN_URI both exist, that's a fatal error (they shouldn't)
log.Fatal("Failed to read %s (%s): the file is empty", uriKey, tempURI.RequestURI())
}
return val
return strings.TrimSpace(string(buf))
// only file URIs are allowed
default:
@@ -1208,19 +1182,6 @@ func loadSecret(sec *ini.Section, uriKey, verbatimKey string) string {
}
}
// generateSaveInternalToken generates and saves the internal token to app.ini
func generateSaveInternalToken() {
token, err := generate.NewInternalToken()
if err != nil {
log.Fatal("Error generate internal token: %v", err)
}
InternalToken = token
CreateOrAppendToCustomConf("security.INTERNAL_TOKEN", func(cfg *ini.File) {
cfg.Section("security").Key("INTERNAL_TOKEN").SetValue(token)
})
}
// MakeAbsoluteAssetURL returns the absolute asset url prefix without a trailing slash
func MakeAbsoluteAssetURL(appURL, staticURLPrefix string) string {
parsedPrefix, err := url.Parse(strings.TrimSuffix(staticURLPrefix, "/"))

View File

@@ -103,8 +103,7 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)
return 0, err
}
// Golang's tmp file (os.CreateTemp) always have 0o600 mode, so we need to change the file to follow the umask (as what Create/MkDir does)
// but we don't want to make these files executable - so ensure that we mask out the executable bits
if err := util.ApplyUmask(p, os.ModePerm&0o666); err != nil {
if err := util.ApplyUmask(p, os.ModePerm); err != nil {
return 0, err
}

View File

@@ -5,12 +5,8 @@
package structs
import (
"fmt"
"path"
"strings"
"path/filepath"
"time"
"gopkg.in/yaml.v3"
)
// StateType issue state type
@@ -147,47 +143,14 @@ type IssueFormField struct {
// IssueTemplate represents an issue template for a repository
// swagger:model
type IssueTemplate struct {
Name string `json:"name" yaml:"name"`
Title string `json:"title" yaml:"title"`
About string `json:"about" yaml:"about"` // Using "description" in a template file is compatible
Labels IssueTemplateLabels `json:"labels" yaml:"labels"`
Ref string `json:"ref" yaml:"ref"`
Content string `json:"content" yaml:"-"`
Fields []*IssueFormField `json:"body" yaml:"body"`
FileName string `json:"file_name" yaml:"-"`
}
type IssueTemplateLabels []string
func (l *IssueTemplateLabels) UnmarshalYAML(value *yaml.Node) error {
var labels []string
if value.IsZero() {
*l = labels
return nil
}
switch value.Kind {
case yaml.ScalarNode:
str := ""
err := value.Decode(&str)
if err != nil {
return err
}
for _, v := range strings.Split(str, ",") {
if v = strings.TrimSpace(v); v == "" {
continue
}
labels = append(labels, v)
}
*l = labels
return nil
case yaml.SequenceNode:
if err := value.Decode(&labels); err != nil {
return err
}
*l = labels
return nil
}
return fmt.Errorf("line %d: cannot unmarshal %s into IssueTemplateLabels", value.Line, value.ShortTag())
Name string `json:"name" yaml:"name"`
Title string `json:"title" yaml:"title"`
About string `json:"about" yaml:"about"` // Using "description" in a template file is compatible
Labels []string `json:"labels" yaml:"labels"`
Ref string `json:"ref" yaml:"ref"`
Content string `json:"content" yaml:"-"`
Fields []*IssueFormField `json:"body" yaml:"body"`
FileName string `json:"file_name" yaml:"-"`
}
// IssueTemplateType defines issue template type
@@ -200,14 +163,14 @@ const (
// Type returns the type of IssueTemplate, can be "md", "yaml" or empty for known
func (it IssueTemplate) Type() IssueTemplateType {
if base := path.Base(it.FileName); base == "config.yaml" || base == "config.yml" {
if it.Name == "config.yaml" || it.Name == "config.yml" {
// ignore config.yaml which is a special configuration file
return ""
}
if ext := path.Ext(it.FileName); ext == ".md" {
if ext := filepath.Ext(it.FileName); ext == ".md" {
return IssueTemplateTypeMarkdown
} else if ext == ".yaml" || ext == ".yml" {
return IssueTemplateTypeYaml
return "yaml"
}
return ""
return IssueTemplateTypeYaml
}

View File

@@ -1,106 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package structs
import (
"testing"
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v3"
)
func TestIssueTemplate_Type(t *testing.T) {
tests := []struct {
fileName string
want IssueTemplateType
}{
{
fileName: ".gitea/ISSUE_TEMPLATE/bug_report.yaml",
want: IssueTemplateTypeYaml,
},
{
fileName: ".gitea/ISSUE_TEMPLATE/bug_report.md",
want: IssueTemplateTypeMarkdown,
},
{
fileName: ".gitea/ISSUE_TEMPLATE/bug_report.txt",
want: "",
},
{
fileName: ".gitea/ISSUE_TEMPLATE/config.yaml",
want: "",
},
}
for _, tt := range tests {
t.Run(tt.fileName, func(t *testing.T) {
it := IssueTemplate{
FileName: tt.fileName,
}
assert.Equal(t, tt.want, it.Type())
})
}
}
func TestIssueTemplateLabels_UnmarshalYAML(t *testing.T) {
tests := []struct {
name string
content string
tmpl *IssueTemplate
want *IssueTemplate
wantErr string
}{
{
name: "array",
content: `labels: ["a", "b", "c"]`,
tmpl: &IssueTemplate{
Labels: []string{"should_be_overwrote"},
},
want: &IssueTemplate{
Labels: []string{"a", "b", "c"},
},
},
{
name: "string",
content: `labels: "a,b,c"`,
tmpl: &IssueTemplate{
Labels: []string{"should_be_overwrote"},
},
want: &IssueTemplate{
Labels: []string{"a", "b", "c"},
},
},
{
name: "empty",
content: `labels:`,
tmpl: &IssueTemplate{
Labels: []string{"should_be_overwrote"},
},
want: &IssueTemplate{
Labels: nil,
},
},
{
name: "error",
content: `
labels:
a: aa
b: bb
`,
tmpl: &IssueTemplate{},
wantErr: "line 3: cannot unmarshal !!map into IssueTemplateLabels",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := yaml.Unmarshal([]byte(tt.content), tt.tmpl)
if tt.wantErr != "" {
assert.EqualError(t, err, tt.wantErr)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, tt.tmpl)
}
})
}
}

View File

@@ -6,8 +6,7 @@ package system
// RuntimeState contains app state for runtime, and we can save remote version for update checker here in future
type RuntimeState struct {
LastAppPath string `json:"last_app_path"`
LastCustomConf string `json:"last_custom_conf"`
LastAppPath string `json:"last_app_path"`
}
// Name returns the item name

46
modules/system/setting.go Normal file
View File

@@ -0,0 +1,46 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package system
import (
"strconv"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/cache"
)
func genKey(key string) string {
return "system.setting." + key
}
// GetSetting returns the setting value via the key
func GetSetting(key string) (string, error) {
return cache.GetString(genKey(key), func() (string, error) {
res, err := system.GetSetting(key)
if err != nil {
return "", err
}
return res.SettingValue, nil
})
}
// GetSettingBool return bool value of setting,
// none existing keys and errors are ignored and result in false
func GetSettingBool(key string) bool {
s, _ := GetSetting(key)
b, _ := strconv.ParseBool(s)
return b
}
// SetSetting sets the setting value
func SetSetting(key, value string, version int) error {
cache.Remove(genKey(key))
return system.SetSetting(&system.Setting{
SettingKey: key,
SettingValue: value,
Version: version,
})
}

View File

@@ -0,0 +1,34 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package system
import (
"fmt"
"code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/cache"
)
func genUserKey(userID int64, key string) string {
return fmt.Sprintf("user_%d.setting.%s", userID, key)
}
// GetUserSetting returns the user setting value via the key
func GetUserSetting(userID int64, key string) (string, error) {
return cache.GetString(genUserKey(userID, key), func() (string, error) {
res, err := user.GetSetting(userID, key)
if err != nil {
return "", err
}
return res.SettingValue, nil
})
}
// SetUserSetting sets the user setting value
func SetUserSetting(userID int64, key, value string) error {
cache.Remove(genUserKey(userID, key))
return user.SetUserSetting(userID, key, value)
}

View File

@@ -42,6 +42,7 @@ import (
"code.gitea.io/gitea/modules/repository"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/svg"
system_module "code.gitea.io/gitea/modules/system"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
@@ -86,7 +87,7 @@ func NewFuncMap() []template.FuncMap {
return setting.AssetVersion
},
"DisableGravatar": func() bool {
return system_model.GetSettingBool(system_model.KeyPictureDisableGravatar)
return system_module.GetSettingBool(system_model.KeyPictureDisableGravatar)
},
"DefaultShowFullName": func() bool {
return setting.UI.DefaultShowFullName
@@ -646,7 +647,7 @@ func SVG(icon string, others ...interface{}) template.HTML {
// Avatar renders user avatars. args: user, size (int), class (string)
func Avatar(item interface{}, others ...interface{}) template.HTML {
size, class := parseOthers(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)
size, class := parseOthers(avatars.DefaultAvatarPixelSize, "ui avatar vm", others...)
switch t := item.(type) {
case *user_model.User:
@@ -677,7 +678,7 @@ func AvatarByAction(action *activities_model.Action, others ...interface{}) temp
// RepoAvatar renders repo avatars. args: repo, size(int), class (string)
func RepoAvatar(repo *repo_model.Repository, others ...interface{}) template.HTML {
size, class := parseOthers(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)
size, class := parseOthers(avatars.DefaultAvatarPixelSize, "ui avatar", others...)
src := repo.RelAvatarLink()
if src != "" {
@@ -688,7 +689,7 @@ func RepoAvatar(repo *repo_model.Repository, others ...interface{}) template.HTM
// AvatarByEmail renders avatars by email address. args: email, name, size (int), class (string)
func AvatarByEmail(email, name string, others ...interface{}) template.HTML {
size, class := parseOthers(avatars.DefaultAvatarPixelSize, avatars.DefaultAvatarClass, others...)
size, class := parseOthers(avatars.DefaultAvatarPixelSize, "ui avatar", others...)
src := avatars.GenerateEmailAvatarFastLink(email, size*setting.Avatar.RenderedSizeFactor)
if src != "" {

View File

@@ -13,13 +13,8 @@ import (
// TimeStamp defines a timestamp
type TimeStamp int64
var (
// mock is NOT concurrency-safe!!
mock time.Time
// Used for IsZero, to check if timestamp is the zero time instant.
timeZeroUnix = time.Time{}.Unix()
)
// mock is NOT concurrency-safe!!
var mock time.Time
// Set sets the time to a mocked time.Time
func Set(now time.Time) {
@@ -108,5 +103,5 @@ func (ts TimeStamp) FormatDate() string {
// IsZero is zero time
func (ts TimeStamp) IsZero() bool {
return int64(ts) == 0 || int64(ts) == timeZeroUnix
return ts.AsTimeInLocation(time.Local).IsZero()
}

View File

@@ -742,9 +742,6 @@ create_oauth2_application_button=Vytvořit aplikaci
create_oauth2_application_success=Úspěšně jste vytvořili novou OAuth2 aplikaci.
update_oauth2_application_success=Úspěšně jste aktualizovali OAuth2 aplikaci.
oauth2_application_name=Název aplikace
oauth2_select_type=Jaký typ aplikace se hodí?
oauth2_type_web=Webová (např. Node.JS, Tomcat, Go)
oauth2_type_native=Nativní (např. Mobil, Desktop, Prohlížeč)
oauth2_redirect_uri=URI přesměrování
save_application=Uložit
oauth2_client_id=ID klienta

View File

@@ -736,9 +736,6 @@ create_oauth2_application_button=Anwendung erstellen
create_oauth2_application_success=Du hast erfolgreich eine neue OAuth2 Anwendung erstellt.
update_oauth2_application_success=Du hast erfolgreich eine neue OAuth2 Anwendung bearbeitet.
oauth2_application_name=Name der Anwendung
oauth2_select_type=Welcher Anwendungstyp passt?
oauth2_type_web=Web (z.B. Node.JS, Tomcat, Go)
oauth2_type_native=Native (z.B. Mobile, Desktop, Browser)
oauth2_redirect_uri=Weiterleitungs-URI
save_application=Speichern
oauth2_client_id=Client-ID

View File

@@ -738,9 +738,6 @@ create_oauth2_application_button=Δημιουργία Εφαρμογής
create_oauth2_application_success=Δημιουργήσατε επιτυχώς μια νέα εφαρμογή OAuth2.
update_oauth2_application_success=Ενημερώσατε επιτυχώς την εφαρμογή OAuth2.
oauth2_application_name=Όνομα Εφαρμογής
oauth2_select_type=Ποιος τύπος εφαρμογής ταιριάζει;
oauth2_type_web=Web (πχ Node.JS, Tomcat, Go)
oauth2_type_native=Εγγενές (π.χ. Κινητό, Επιφάνεια Εργασίας, Πρόγραμμα Περιήγησης)
oauth2_redirect_uri=URI Ανακατεύθυνσης
save_application=Αποθήκευση
oauth2_client_id=Ταυτότητα Πελάτη

View File

@@ -749,9 +749,6 @@ create_oauth2_application_button=Crear Aplicación
create_oauth2_application_success=Ha creado una nueva aplicación OAuth2 con éxito.
update_oauth2_application_success=Ha actualizado correctamente la aplicación OAuth2.
oauth2_application_name=Nombre de la Aplicación
oauth2_select_type=¿Qué tipo de aplicación es?
oauth2_type_web=Web (por ejemplo: Node.JS, Tomcat, Go)
oauth2_type_native=Nativa (por ejemplo, móvil, escritorio, navegador)
oauth2_redirect_uri=URI de redireccionado
save_application=Guardar
oauth2_client_id=ID de cliente

View File

@@ -675,9 +675,6 @@ create_oauth2_application_button=ایجاد برنامه
create_oauth2_application_success=برنامه OAuth2 جدید شما با موفقیت ساخته شد.
update_oauth2_application_success=برنامه OAuth2 با موفقیت به‎روزرسانی شد.
oauth2_application_name=نام برنامه
oauth2_select_type=کدام نوع برنامه متناسب است؟
oauth2_type_web=وب (مثلا Node.JS, Tomcat, Go)
oauth2_type_native=بومی (مثلا، Mobile, Desktop, Browser)
oauth2_redirect_uri=تغییر مسیر به نشانی اینترنتی
save_application=ذخيره
oauth2_client_id=شناسه کلاینت

View File

@@ -742,9 +742,6 @@ create_oauth2_application_button=Créer une application
create_oauth2_application_success=Vous avez créé avec succès une nouvelle application OAuth2.
update_oauth2_application_success=Vous avez mis à jour l'application OAuth2 avec succès.
oauth2_application_name=Nom de l'Application
oauth2_select_type=De quel type d'application s'agit-il ?
oauth2_type_web=Web (par exemple Node.JS, Tomcat, Go)
oauth2_type_native=Native (par exemple Mobile, Bureau, Navigateur)
oauth2_redirect_uri=URL de redirection
save_application=Enregistrer
oauth2_client_id=ID du client

View File

@@ -526,9 +526,6 @@ create_oauth2_application_button=Alkalmazás létrehozása
create_oauth2_application_success=Sikerült létrehozni egy új OAuth2 alkalmazást.
update_oauth2_application_success=Sikerült módosítani az OAuth2 alkalmazást.
oauth2_application_name=Alkalmazásnév
oauth2_select_type=Melyik típus felelne meg?
oauth2_type_web=Web (pl. Node.JS, Tomcat, Go)
oauth2_type_native=Natív (pl. Mobil, PC, Böngésző)
oauth2_redirect_uri=Átirányítási URI
save_application=Mentés
oauth2_client_id=Ügyfélazonosító

View File

@@ -519,9 +519,6 @@ create_oauth2_application_button=Buat Aplikasi
create_oauth2_application_success=Anda berhasil membuat aplikasi OAuth2 baru.
update_oauth2_application_success=Anda berhasil memperbarui aplikasi OAuth2.
oauth2_application_name=Nama Aplikasi
oauth2_select_type=Aplikasi tipe apa yang cocok?
oauth2_type_web=Web (contohnya Node.JS, Tomcat, Go)
oauth2_type_native=Asli (contohnya perangkat genggaman, desktop, peramban)
oauth2_redirect_uri=URI Pengalihan
save_application=Simpan
oauth2_client_id=ID Klien

View File

@@ -553,9 +553,6 @@ access_token_deletion=Eyða Aðgangslykli
create_oauth2_application_button=Skapa Forrit
update_oauth2_application_success=Þú hefur uppfært OAuth2 forritið.
oauth2_application_name=Forritsheiti
oauth2_select_type=Hvaða forritsgerð passar?
oauth2_type_web=Net (t.d. Node.JS, Tomcat, Go)
oauth2_type_native=Á kerfi (t.d. síma, tölvu, vafra)
oauth2_redirect_uri=Áframsendingar Vefslóð
save_application=Vista
oauth2_client_id=Auðkenni Notanda

View File

@@ -736,9 +736,6 @@ create_oauth2_application_button=Crea applicazione
create_oauth2_application_success=Hai creato con successo una nuova applicazione OAuth2.
update_oauth2_application_success=Hai aggiornato con successo l'applicazione OAuth2.
oauth2_application_name=Nome applicazione
oauth2_select_type=Quale tipo di applicazione é adatto?
oauth2_type_web=Web (es: Node.JS, Tomcat, Go)
oauth2_type_native=Nativo (es. Mobile, Desktop, Browser)
oauth2_redirect_uri=URI di reindirizzamento
save_application=Salva
oauth2_client_id=Client ID

View File

@@ -742,9 +742,6 @@ create_oauth2_application_button=アプリケーション作成
create_oauth2_application_success=新しいOAuth2アプリケーションを作成しました。
update_oauth2_application_success=OAuth2アプリケーションを更新しました。
oauth2_application_name=アプリケーション名
oauth2_select_type=アプリケーションタイプを選択
oauth2_type_web=Web (Node.JS, Tomcat, Go など)
oauth2_type_native=Native (モバイル, デスクトップ, ブラウザーなど)
oauth2_redirect_uri=リダイレクトURI
save_application=保存
oauth2_client_id=クライアントID

View File

@@ -736,9 +736,6 @@ create_oauth2_application_button=Izveidot lietotni
create_oauth2_application_success=OAuth2 lietotne veiksmīgi izveidota.
update_oauth2_application_success=OAuth2 lietotne veiksmīgi atjaunināta.
oauth2_application_name=Lietotnes nosaukums
oauth2_select_type=Kāds lietotnes veids visvairāk atbilst?
oauth2_type_web=Tīmekļa (piemēram, Node.JS, Tomcat, Go)
oauth2_type_native=Specializētā (piemēram, mobilā, darbvirsmas, tīmekļa pārlūks)
oauth2_redirect_uri=Novirzīšanas URI
save_application=Saglabāt
oauth2_client_id=Klienta ID

View File

@@ -489,9 +489,6 @@ create_oauth2_application_button=അപ്ലിക്കേഷൻ സൃഷ്
create_oauth2_application_success=നിങ്ങൾ വിജയകരമായി ഒരു പുതിയ OAuth2 അപ്ലിക്കേഷൻ സൃഷ്ടിച്ചു.
update_oauth2_application_success=നിങ്ങൾ വിജയകരമായി ഒരു പുതിയ OAuth2 അപ്ലിക്കേഷൻ പുതുക്കി.
oauth2_application_name=അപ്ലിക്കേഷന്റെ പേര്
oauth2_select_type=ഏത് തരം അപ്ലിക്കേഷനാണ് ഇതു്?
oauth2_type_web=വെബ് (e.g. Node.JS, Tomcat, Go)
oauth2_type_native=നേറ്റീവ് (ഉദാ. മൊബൈൽ, ഡെസ്ക്ടോപ്പ്, ബ്രൌസർ)
oauth2_redirect_uri=URI റീഡയറക്‌ട് ചെയ്യുക
save_application=സംരക്ഷിയ്ക്കുക
oauth2_client_id=ക്ലൈന്റ് ഐഡി

View File

@@ -736,9 +736,6 @@ create_oauth2_application_button=Maak applicatie
create_oauth2_application_success=Je hebt met succes een nieuwe OAuth2-applicatie aangemaakt.
update_oauth2_application_success=Je hebt de OAuth2-applicatie succesvol bijgewerkt.
oauth2_application_name=Applicatie naam
oauth2_select_type=Welk type toepassing past?
oauth2_type_web=Web (bijv. Node.JS, Tomcat, Go)
oauth2_type_native=Native (bijv. Mobiel, Desktop, Browser)
oauth2_redirect_uri=Omleidings URL
save_application=Opslaan
oauth2_client_id=Client-ID

View File

@@ -688,9 +688,6 @@ create_oauth2_application_button=Stwórz aplikację
create_oauth2_application_success=Udało Ci się stworzyć nową aplikację OAuth2.
update_oauth2_application_success=Udało Ci się zaktualizować aplikację OAuth2.
oauth2_application_name=Nazwa aplikacji
oauth2_select_type=Który typ aplikacji jest dla niej właściwy?
oauth2_type_web=Webowa (np. Node.JS, Tomcat, Go)
oauth2_type_native=Natywna (np. mobilna, pulpitowa, przeglądarkowa)
oauth2_redirect_uri=URI przekierowania
save_application=Zapisz
oauth2_client_id=ID klienta

View File

@@ -738,9 +738,6 @@ create_oauth2_application_button=Criar aplicativo
create_oauth2_application_success=Você criou com sucesso um novo aplicativo OAuth2.
update_oauth2_application_success=Você alterou com sucesso o aplicativo OAuth2.
oauth2_application_name=Nome do aplicativo
oauth2_select_type=Que tipo de aplicativo se encaixa?
oauth2_type_web=Web (exemplo: Node.JS, Tomcat, Go)
oauth2_type_native=Nativo (exemplo: Celular, Computador, Navegador)
oauth2_redirect_uri=Redirecionar URI
save_application=Salvar
oauth2_client_id=Client ID

View File

@@ -749,9 +749,7 @@ create_oauth2_application_button=Criar aplicação
create_oauth2_application_success=Criou com sucesso uma nova aplicação OAuth2.
update_oauth2_application_success=Modificou com sucesso a aplicação OAuth2.
oauth2_application_name=Nome da aplicação
oauth2_select_type=Que tipo de aplicaçãoo se encaixa?
oauth2_type_web=Web (por exemplo: Node.JS, Tomcat, Go)
oauth2_type_native=Nativa (por exemplo: Telemóvel, Computador, Navegador)
oauth2_confidential_client=Cliente confidencial. Escolha para aplicações que mantêm o segredo confidencial, tais como aplicações web. Não escolha para aplicações nativas, incluindo aplicações para computador e aplicações móveis.
oauth2_redirect_uri=URI de reencaminhamento
save_application=Guardar
oauth2_client_id=ID do cliente

View File

@@ -725,9 +725,6 @@ create_oauth2_application_button=Создать приложение
create_oauth2_application_success=Вы успешно создали новое приложение OAuth2.
update_oauth2_application_success=Изменения настроек приложения OAuth2 успешно применены.
oauth2_application_name=Имя приложения
oauth2_select_type=Какой тип приложения подходит?
oauth2_type_web=Веб (например: Node.JS, Tomcat, Go)
oauth2_type_native=Нативный (например: телефон, ПК, браузер)
oauth2_redirect_uri=URI переадресации
save_application=Сохранить
oauth2_client_id=ID клиента

View File

@@ -657,9 +657,6 @@ create_oauth2_application_button=යෙදුම සාදන්න
create_oauth2_application_success=ඔබ නව Oauth2 යෙදුමක් සාර්ථකව නිර්මාණය කර ඇත.
update_oauth2_application_success=ඔබ Oauth2 යෙදුම සාර්ථකව යාවත්කාලීන කර ඇත.
oauth2_application_name=යෙදුමේ නම
oauth2_select_type=කුමන යෙදුම් වර්ගය ගැලපේද?
oauth2_type_web=වෙබ් (උදා: Node.JS, ටොම්කැට්, යන්න)
oauth2_type_native=දේශීය (උදා: ජංගම, පරිගණක, බ්රව්සරය)
oauth2_redirect_uri=නැවත හරවා යැවීමේ URI
save_application=සුරකින්න
oauth2_client_id=අනුග්‍රාහකයේ හැඳු.

View File

@@ -738,7 +738,6 @@ create_oauth2_application_button=Vytvoriť aplikáciu
create_oauth2_application_success=Úspešne ste vytvorili novú aplikáciu OAuth2.
update_oauth2_application_success=Úspešne ste aktualizovali aplikáciu OAuth2.
oauth2_application_name=Názov aplikácie
oauth2_select_type=Ktorý typ aplikácie sa hodí?
oauth2_redirect_uri=Presmerovanie URI
save_application=Uložiť
oauth2_client_id=ID klienta

View File

@@ -561,9 +561,6 @@ create_oauth2_application_button=Skapa applikation
create_oauth2_application_success=Du har lyckats med att skapa en ny OAuth2-applikation.
update_oauth2_application_success=Du har lyckats uppdatera OAuth2-applikationen.
oauth2_application_name=Applikationsnamn
oauth2_select_type=Vilken typ av applikation passar?
oauth2_type_web=Webb (t.ex. Node.JS, Tomcat, Go)
oauth2_type_native=Native (ex. Mobil, Desktop, Webbläsare)
oauth2_redirect_uri=Omdirigerings-URI
save_application=Spara
oauth2_client_id=Klient-ID

View File

@@ -742,9 +742,6 @@ create_oauth2_application_button=Uygulama Oluştur
create_oauth2_application_success=Başarıyla yeni bir OAuth2 uygulaması oluşturdunuz.
update_oauth2_application_success=OAuth2 uygulamasını başarıyla güncellediniz.
oauth2_application_name=Uygulama Adı
oauth2_select_type=Hangi uygulama türü uyuyor?
oauth2_type_web=Web (ör. Node.JS, Tomcat, Go)
oauth2_type_native=Yerel (ör. Mobil, Masaüstü, Tarayıcı)
oauth2_redirect_uri=Yönlendirme URI'si
save_application=Kaydet
oauth2_client_id=İstemci Kimliği

View File

@@ -683,9 +683,6 @@ create_oauth2_application_button=Створити програму
create_oauth2_application_success=Ви успішно створили нову програму OAuth2.
update_oauth2_application_success=Ви успішно оновили програму OAuth2.
oauth2_application_name=Назва програми
oauth2_select_type=Який тип програми підходить?
oauth2_type_web=Веб (напр. Node.JS, Tomcat, Go)
oauth2_type_native=Рідний (напр. мобільний, робочий стіл, веб-переглядач)
oauth2_redirect_uri=URI перенаправлення
save_application=Зберегти
oauth2_client_id=ID Клієнта

View File

@@ -749,9 +749,6 @@ create_oauth2_application_button=创建应用
create_oauth2_application_success=您已成功创建了一个新的 OAuth2 应用。
update_oauth2_application_success=您已成功更新了此 OAuth2 应用。
oauth2_application_name=应用名称
oauth2_select_type=哪种应用类型合适?
oauth2_type_web=Web (例如 Node.JS, Tomacat, Go)
oauth2_type_native=原生 (例如移动,桌面,浏览器)
oauth2_redirect_uri=重定向 URI
save_application=保存
oauth2_client_id=客户端ID

View File

@@ -740,9 +740,6 @@ create_oauth2_application_button=建立應用程式
create_oauth2_application_success=您已成功新增一個 OAuth2 應用程式。
update_oauth2_application_success=您已成功更新了 OAuth2 應用程式。
oauth2_application_name=應用程式名稱
oauth2_select_type=適用哪種程式類別?
oauth2_type_web=Web (例如 Node.JS, Tomacat, Go)
oauth2_type_native=原生應用程式 (Mobile, Desktop, Browser)
oauth2_redirect_uri=重新導向 URI
save_application=儲存
oauth2_client_id=客戶端 ID

View File

@@ -12,7 +12,6 @@ import (
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/packages/composer"
@@ -58,13 +57,7 @@ func Routes(ctx gocontext.Context) *web.Route {
authGroup := auth.NewGroup(authMethods...)
r.Use(func(ctx *context.Context) {
var err error
ctx.Doer, err = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
log.Error("Verify: %v", err)
ctx.Error(http.StatusUnauthorized, "authGroup.Verify")
return
}
ctx.Doer = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
ctx.IsSigned = ctx.Doer != nil
})
@@ -186,7 +179,6 @@ func Routes(ctx gocontext.Context) *web.Route {
r.Group("/maven", func() {
r.Put("/*", reqPackageAccess(perm.AccessModeWrite), maven.UploadPackageFile)
r.Get("/*", maven.DownloadPackageFile)
r.Head("/*", maven.ProvidePackageFileHeader)
}, reqPackageAccess(perm.AccessModeRead))
r.Group("/nuget", func() {
r.Group("", func() { // Needs to be unauthenticated for the NuGet client.
@@ -324,13 +316,7 @@ func ContainerRoutes(ctx gocontext.Context) *web.Route {
authGroup := auth.NewGroup(authMethods...)
r.Use(func(ctx *context.Context) {
var err error
ctx.Doer, err = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
if err != nil {
log.Error("Failed to verify user: %v", err)
ctx.Error(http.StatusUnauthorized, "Verify")
return
}
ctx.Doer = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session)
ctx.IsSigned = ctx.Doer != nil
})

View File

@@ -184,10 +184,7 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
ctx.ServeContent(s, &context.ServeHeaderOptions{
Filename: pf.Name,
LastModified: pf.CreatedUnix.AsLocalTime(),
})
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
}
// UploadPackage creates a new package

View File

@@ -20,22 +20,22 @@ func (a *Auth) Name() string {
}
// Verify extracts the user from the Bearer token
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) *user_model.User {
uid, err := packages.ParseAuthorizationToken(req)
if err != nil {
log.Trace("ParseAuthorizationToken: %v", err)
return nil, err
return nil
}
if uid == 0 {
return nil, nil
return nil
}
u, err := user_model.GetUserByID(uid)
if err != nil {
log.Error("GetUserByID: %v", err)
return nil, err
return nil
}
return u, nil
return u
}

View File

@@ -473,10 +473,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
}
defer s.Close()
ctx.ServeContent(s, &context.ServeHeaderOptions{
Filename: pf.Name,
LastModified: pf.CreatedUnix.AsLocalTime(),
})
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
}
// DeleteRecipeV1 deletes the requested recipe(s)

View File

@@ -21,25 +21,25 @@ func (a *Auth) Name() string {
// Verify extracts the user from the Bearer token
// If it's an anonymous session a ghost user is returned
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) *user_model.User {
uid, err := packages.ParseAuthorizationToken(req)
if err != nil {
log.Trace("ParseAuthorizationToken: %v", err)
return nil, err
return nil
}
if uid == 0 {
return nil, nil
return nil
}
if uid == -1 {
return user_model.NewGhostUser(), nil
return user_model.NewGhostUser()
}
u, err := user_model.GetUserByID(uid)
if err != nil {
log.Error("GetUserByID: %v", err)
return nil, err
return nil
}
return u, nil
return u
}

View File

@@ -7,11 +7,8 @@ package container
import (
"context"
"encoding/hex"
"errors"
"fmt"
"os"
"strings"
"sync"
"code.gitea.io/gitea/models/db"
packages_model "code.gitea.io/gitea/models/packages"
@@ -19,12 +16,9 @@ import (
"code.gitea.io/gitea/modules/log"
packages_module "code.gitea.io/gitea/modules/packages"
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
)
var uploadVersionMutex sync.Mutex
// saveAsPackageBlob creates a package blob from an upload
// The uploaded blob gets stored in a special upload version to link them to the package/image
func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_service.PackageInfo) (*packages_model.PackageBlob, error) {
@@ -34,11 +28,6 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic
contentStore := packages_module.NewContentStore()
var uploadVersion *packages_model.PackageVersion
// FIXME: Replace usage of mutex with database transaction
// https://github.com/go-gitea/gitea/pull/21862
uploadVersionMutex.Lock()
err := db.WithTx(func(ctx context.Context) error {
created := true
p := &packages_model.Package{
@@ -79,30 +68,11 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic
}
}
uploadVersion = pv
return nil
})
uploadVersionMutex.Unlock()
if err != nil {
return nil, err
}
err = db.WithTx(func(ctx context.Context) error {
pb, exists, err = packages_model.GetOrInsertBlob(ctx, pb)
if err != nil {
log.Error("Error inserting package blob: %v", err)
return err
}
// FIXME: Workaround to be removed in v1.20
// https://github.com/go-gitea/gitea/issues/19586
if exists {
err = contentStore.Has(packages_module.BlobHash256Key(pb.HashSHA256))
if err != nil && (errors.Is(err, util.ErrNotExist) || errors.Is(err, os.ErrNotExist)) {
log.Debug("Package registry inconsistent: blob %s does not exist on file system", pb.HashSHA256)
exists = false
}
}
if !exists {
if err := contentStore.Save(packages_module.BlobHash256Key(pb.HashSHA256), hsr, hsr.Size()); err != nil {
log.Error("Error saving package blob in content store: %v", err)
@@ -113,7 +83,7 @@ func saveAsPackageBlob(hsr packages_module.HashedSizeReader, pi *packages_servic
filename := strings.ToLower(fmt.Sprintf("sha256_%s", pb.HashSHA256))
pf := &packages_model.PackageFile{
VersionID: uploadVersion.ID,
VersionID: pv.ID,
BlobID: pb.ID,
Name: filename,
LowerName: filename,

View File

@@ -10,7 +10,6 @@ import (
"io"
"net/http"
"net/url"
"os"
"regexp"
"strconv"
"strings"
@@ -25,7 +24,6 @@ import (
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/packages/container/oci"
"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"
container_service "code.gitea.io/gitea/services/packages/container"
@@ -195,7 +193,7 @@ func InitiateUploadBlob(ctx *context.Context) {
mount := ctx.FormTrim("mount")
from := ctx.FormTrim("from")
if mount != "" {
blob, _ := workaroundGetContainerBlob(ctx, &container_model.BlobSearchOptions{
blob, _ := container_model.GetContainerBlob(ctx, &container_model.BlobSearchOptions{
Image: from,
Digest: mount,
})
@@ -408,7 +406,7 @@ func getBlobFromContext(ctx *context.Context) (*packages_model.PackageFileDescri
return nil, container_model.ErrContainerBlobNotExist
}
return workaroundGetContainerBlob(ctx, &container_model.BlobSearchOptions{
return container_model.GetContainerBlob(ctx, &container_model.BlobSearchOptions{
OwnerID: ctx.Package.Owner.ID,
Image: ctx.Params("image"),
Digest: digest,
@@ -550,7 +548,7 @@ func getManifestFromContext(ctx *context.Context) (*packages_model.PackageFileDe
return nil, container_model.ErrContainerBlobNotExist
}
return workaroundGetContainerBlob(ctx, opts)
return container_model.GetContainerBlob(ctx, opts)
}
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#checking-if-content-exists-in-the-registry
@@ -690,23 +688,3 @@ func GetTagList(ctx *context.Context) {
Tags: tags,
})
}
// FIXME: Workaround to be removed in v1.20
// https://github.com/go-gitea/gitea/issues/19586
func workaroundGetContainerBlob(ctx *context.Context, opts *container_model.BlobSearchOptions) (*packages_model.PackageFileDescriptor, error) {
blob, err := container_model.GetContainerBlob(ctx, opts)
if err != nil {
return nil, err
}
err = packages_module.NewContentStore().Has(packages_module.BlobHash256Key(blob.Blob.HashSHA256))
if err != nil {
if errors.Is(err, util.ErrNotExist) || errors.Is(err, os.ErrNotExist) {
log.Debug("Package registry inconsistent: blob %s does not exist on file system", blob.Blob.HashSHA256)
return nil, container_model.ErrContainerBlobNotExist
}
return nil, err
}
return blob, nil
}

View File

@@ -6,10 +6,8 @@ package container
import (
"context"
"errors"
"fmt"
"io"
"os"
"strings"
"code.gitea.io/gitea/models/db"
@@ -21,7 +19,6 @@ import (
packages_module "code.gitea.io/gitea/modules/packages"
container_module "code.gitea.io/gitea/modules/packages/container"
"code.gitea.io/gitea/modules/packages/container/oci"
"code.gitea.io/gitea/modules/util"
packages_service "code.gitea.io/gitea/services/packages"
)
@@ -406,15 +403,6 @@ func createManifestBlob(ctx context.Context, mci *manifestCreationInfo, pv *pack
log.Error("Error inserting package blob: %v", err)
return nil, false, "", err
}
// FIXME: Workaround to be removed in v1.20
// https://github.com/go-gitea/gitea/issues/19586
if exists {
err = packages_module.NewContentStore().Has(packages_module.BlobHash256Key(pb.HashSHA256))
if err != nil && (errors.Is(err, util.ErrNotExist) || errors.Is(err, os.ErrNotExist)) {
log.Debug("Package registry inconsistent: blob %s does not exist on file system", pb.HashSHA256)
exists = false
}
}
if !exists {
contentStore := packages_module.NewContentStore()
if err := contentStore.Save(packages_module.BlobHash256Key(pb.HashSHA256), buf, buf.Size()); err != nil {

View File

@@ -53,10 +53,7 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
ctx.ServeContent(s, &context.ServeHeaderOptions{
Filename: pf.Name,
LastModified: pf.CreatedUnix.AsLocalTime(),
})
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
}
// UploadPackage uploads the specific generic package.

View File

@@ -138,10 +138,7 @@ func DownloadPackageFile(ctx *context.Context) {
}
defer s.Close()
ctx.ServeContent(s, &context.ServeHeaderOptions{
Filename: pf.Name,
LastModified: pf.CreatedUnix.AsLocalTime(),
})
ctx.ServeContent(pf.Name, s, pf.CreatedUnix.AsLocalTime())
}
// UploadPackage creates a new package

Some files were not shown because too many files have changed in this diff Show More