diff --git a/.air.toml b/.air.toml index 4b3297fc1a77..061008830317 100644 --- a/.air.toml +++ b/.air.toml @@ -7,4 +7,4 @@ bin = "gitea" include_ext = ["go", "tmpl"] exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"] include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"] -exclude_regex = ["_test.go$"] +exclude_regex = ["_test.go$", "_gen.go$"] diff --git a/.drone.yml b/.drone.yml index 3c1cf2a02f51..57c888a7d985 100644 --- a/.drone.yml +++ b/.drone.yml @@ -25,7 +25,7 @@ steps: - make deps-frontend - name: deps-backend - image: golang:1.18 + image: golang:1.19 pull: always commands: - make deps-backend @@ -88,7 +88,7 @@ steps: depends_on: [deps-frontend] - name: checks-backend - image: golang:1.18 + image: golang:1.19 commands: - make checks-backend depends_on: [deps-backend] @@ -122,7 +122,7 @@ steps: path: /go - name: build-backend-arm64 - image: golang:1.18 + image: golang:1.19 environment: GO111MODULE: on GOPROXY: https://goproxy.io @@ -138,7 +138,7 @@ steps: path: /go - name: build-backend-windows - image: golang:1.18 + image: golang:1.19 environment: GO111MODULE: on GOPROXY: https://goproxy.io @@ -153,7 +153,7 @@ steps: path: /go - name: build-backend-386 - image: golang:1.18 + image: golang:1.19 environment: GO111MODULE: on GOPROXY: https://goproxy.io @@ -243,7 +243,7 @@ steps: - pull_request - name: deps-backend - image: golang:1.18 + image: golang:1.19 pull: always commands: - make deps-backend @@ -360,7 +360,7 @@ steps: path: /go - name: generate-coverage - image: golang:1.18 + image: golang:1.19 commands: - make coverage environment: @@ -436,7 +436,7 @@ steps: - pull_request - name: deps-backend - image: golang:1.18 + image: golang:1.19 pull: always commands: - make deps-backend @@ -578,7 +578,7 @@ trigger: steps: - name: download - image: golang:1.18 + image: golang:1.19 pull: always commands: - timeout -s ABRT 40m make generate-license generate-gitignore @@ -640,7 +640,7 @@ steps: - make deps-frontend - name: deps-backend - image: golang:1.18 + image: golang:1.19 pull: always commands: - make deps-backend @@ -649,7 +649,7 @@ steps: path: /go - name: static - image: techknowlogick/xgo:go-1.18.x + image: techknowlogick/xgo:go-1.19.x pull: always commands: # Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved @@ -760,7 +760,7 @@ steps: - make deps-frontend - name: deps-backend - image: golang:1.18 + image: golang:1.19 pull: always commands: - make deps-backend @@ -769,7 +769,7 @@ steps: path: /go - name: static - image: techknowlogick/xgo:go-1.18.x + image: techknowlogick/xgo:go-1.19.x pull: always commands: # Upgrade to node 18 once https://github.com/techknowlogick/xgo/issues/163 is resolved diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 86f886b4b4d5..4cc4060c5837 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -30,7 +30,7 @@ overrides: env: worker: true rules: - no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top] + no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, status, statusbar, stop, toolbar, top] - files: ["build/generate-images.js"] rules: import/no-unresolved: [0] @@ -109,7 +109,7 @@ rules: import/no-extraneous-dependencies: [2] import/no-import-module-exports: [0] import/no-internal-modules: [0] - import/no-mutable-exports: [2] + import/no-mutable-exports: [0] import/no-named-as-default-member: [0] import/no-named-as-default: [2] import/no-named-default: [0] @@ -121,7 +121,7 @@ rules: import/no-restricted-paths: [0] import/no-self-import: [2] import/no-unassigned-import: [0] - import/no-unresolved: [2, {commonjs: true}] + import/no-unresolved: [2, {commonjs: true, ignore: ["\\?.+$"]}] import/no-unused-modules: [2, {unusedExports: true}] import/no-useless-path-segments: [2, {commonjs: true}] import/no-webpack-loader-syntax: [2] @@ -211,7 +211,7 @@ rules: no-compare-neg-zero: [2] no-cond-assign: [2, except-parens] no-confusing-arrow: [0] - no-console: [1, {allow: [info, warn, error]}] + no-console: [1, {allow: [debug, info, warn, error]}] no-const-assign: [2] no-constant-binary-expression: [2] no-constant-condition: [0] @@ -287,7 +287,7 @@ rules: no-redeclare: [2] no-regex-spaces: [2] no-restricted-exports: [0] - no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top] + no-restricted-globals: [2, addEventListener, blur, close, closed, confirm, defaultStatus, defaultstatus, error, event, external, find, focus, frameElement, frames, history, innerHeight, innerWidth, isFinite, isNaN, length, location, locationbar, menubar, moveBy, moveTo, name, onblur, onerror, onfocus, onload, onresize, onunload, open, opener, opera, outerHeight, outerWidth, pageXOffset, pageYOffset, parent, print, removeEventListener, resizeBy, resizeTo, screen, screenLeft, screenTop, screenX, screenY, scroll, scrollbars, scrollBy, scrollTo, scrollX, scrollY, self, status, statusbar, stop, toolbar, top, __dirname, __filename] no-restricted-imports: [0] no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement] no-return-assign: [0] @@ -321,7 +321,7 @@ rules: no-unused-labels: [2] no-unused-private-class-members: [2] no-unused-vars: [2, {args: all, argsIgnorePattern: ^_, varsIgnorePattern: ^_, caughtErrorsIgnorePattern: ^_, destructuredArrayIgnorePattern: ^_, ignoreRestSiblings: false}] - no-use-before-define: [2, nofunc] + no-use-before-define: [2, {functions: false, classes: true, variables: true, allowNamedExports: true}] no-useless-backreference: [0] no-useless-call: [2] no-useless-catch: [2] @@ -347,7 +347,7 @@ rules: padded-blocks: [2, never] padding-line-between-statements: [0] prefer-arrow-callback: [2, {allowNamedFunctions: true, allowUnboundThis: true}] - prefer-const: [2, {destructuring: all}] + prefer-const: [2, {destructuring: all, ignoreReadBeforeAssign: true}] prefer-destructuring: [0] prefer-exponentiation-operator: [2] prefer-named-capture-group: [0] @@ -449,7 +449,7 @@ rules: unicorn/no-new-array: [0] unicorn/no-new-buffer: [0] unicorn/no-null: [0] - unicorn/no-object-as-default-parameter: [2] + unicorn/no-object-as-default-parameter: [0] unicorn/no-process-exit: [0] unicorn/no-reduce: [2] unicorn/no-static-only-class: [2] @@ -475,7 +475,7 @@ rules: unicorn/prefer-array-index-of: [2] unicorn/prefer-array-some: [2] unicorn/prefer-at: [0] - unicorn/prefer-code-point: [2] + unicorn/prefer-code-point: [0] unicorn/prefer-dataset: [2] unicorn/prefer-date-now: [2] unicorn/prefer-default-parameters: [0] diff --git a/.golangci.yml b/.golangci.yml index 11c58454a007..982ab06f0b44 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -29,7 +29,7 @@ linters: fast: false run: - go: 1.18 + go: 1.19 timeout: 10m skip-dirs: - node_modules @@ -75,7 +75,7 @@ linters-settings: - name: modifies-value-receiver gofumpt: extra-rules: true - lang-version: "1.18" + lang-version: "1.19" depguard: # TODO: use depguard to replace import checks in gitea-vet list-type: denylist @@ -171,3 +171,7 @@ issues: - path: models/user/openid.go linters: - golint + - path: models/user/badge.go + linters: + - revive + text: "exported: type name will be used as user.UserBadge by other packages, and that stutters; consider calling this Badge" diff --git a/CHANGELOG.md b/CHANGELOG.md index ea2380d9b1ad..50e8394a992a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,314 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.17.0](https://github.com/go-gitea/gitea/releases/tag/v1.17.0) - 2022-07-30 + +* BREAKING + * Require go1.18 for Gitea 1.17 (#19918) + * Make AppDataPath absolute against the AppWorkPath if it is not (#19815) + * Nuke the incorrect permission report on /api/v1/notifications (#19761) + * Refactor git module, make Gitea use internal git config (#19732) + * Remove `RequireHighlightJS` field, update plantuml example. (#19615) + * Increase minimal required git version to 2.0 (#19577) + * Add a directory prefix `gitea-src-VERSION` to release-tar-file (#19396) + * Use "main" as default branch name (#19354) + * Make cron task no notice on success (#19221) + * Add pam account authorization check (#19040) + * Show messages for users if the ROOT_URL is wrong, show JavaScript errors (#18971) + * Refactor mirror code & fix StartToMirror (#18904) + * Remove deprecated SSH ciphers from default (#18697) + * Add the possibility to allow the user to have a favicon which differs from the main logo (#18542) + * Update reserved usernames list (#18438) + * Support custom ACME provider (#18340) + * Change initial TrustModel to committer (#18335) + * Update HTTP status codes (#18063) + * Upgrade Alpine from 3.13 to 3.15 (#18050) + * Restrict email address validation (#17688) + * Refactor Router Logger (#17308) +* SECURITY + * Use git.HOME_PATH for Git HOME directory (#20114) (#20293) + * Add write check for creating Commit Statuses (#20332) (#20333) + * Remove deprecated SSH ciphers from default (#18697) +* FEDERATION + * Return statistic information for nodeinfo (#19561) + * Add Webfinger endpoint (#19462) + * Store the foreign ID of issues during migration (#18446) +* FEATURES + * Automatically render wiki TOC (#19873) + * Adding button to link accounts from user settings (#19792) + * Allow set default merge style while creating repo (#19751) + * Auto merge pull requests when all checks succeeded (#9307 & #19648) + * Improve reviewing PR UX (#19612) + * Add support for rendering console output with colors (#19497) + * Add Helm Chart registry (#19406) + * Add Goroutine stack inspector to admin/monitor (#19207) + * RSS/Atom support for Orgs & Repos (#17714 & #19055) + * Add button for issue deletion (#19032) + * Allow to mark files in a PR as viewed (#19007) + * Add Index to comment for migrations and mirroring (#18806) + * Add health check endpoint (#18465) + * Add packagist webhook (#18224) + * Add "Allow edits from maintainer" feature (#18002) + * Add apply-patch, basic revert and cherry-pick functionality (#17902) + * Add Package Registry (#16510) + * Add LDAP group sync to Teams (#16299) + * Pause queues (#15928) + * Added auto-save whitespace behavior if it changed manually (#15566) + * Find files in repo (#15028) + * Provide configuration to allow camo-media proxying (#12802) +* API + * Add endpoint to serve blob or LFS file content (#19689) + * Add endpoint to check if team has repo access (#19540) + * More commit info (#19252) + * Allow to create file on empty repo (#19224) + * Allow removing issues (#18879) + * Add endpoint to query collaborators permission for a repository (#18761) + * Return primary language and repository language stats API URL (#18396) + * Implement http signatures support for the API (#17565) +* ENHANCEMENTS + * Make notification bell more prominent on mobile (#20108, #20236, #20251) (#20269) + * Adjust max-widths for the repository file table (#20243) (#20247) + * Display full name (#20171) (#20246) + * Add dbconsistency checks for Stopwatches (#20010) + * Add fetch.writeCommitGraph to gitconfig (#20006) + * Add fgprof pprof profiler (#20005) + * Move agit dependency (#19998) + * Empty log queue on flush and close (#19994) + * Remove tab/TabName usage where it's not needed (#19973) + * Improve file header on mobile (#19945) + * Move issues related files into models/issues (#19931) + * Add breaking email restrictions checker in doctor (#19903) + * Improve UX on modal for deleting an access token (#19894) + * Add alt text to logo (#19892) + * Move some code into models/git (#19879) + * Remove customized (unmaintained) dropdown, improve aria a11y for dropdown (#19861) + * Make user profile image show full image on mobile (#19840) + * Replace blue button and label classes with primary (#19763) + * Remove fomantic progress module (#19760) + * Allows repo search to match against "owner/repo" pattern strings (#19754) + * Move org functions (#19753) + * Move almost all functions' parameter db.Engine to context.Context (#19748) + * Show source/target branches on PR's list (#19747) + * Use http.StatusTemporaryRedirect(307) when serve avatar directly (#19739) + * Add doctor orphan check for orphaned pull requests without an existing base repo (#19731) + * Make Ctrl+Enter (quick submit) work for issue comment and wiki editor (#19729) + * Update go-chi/cache to utilize Ping() (#19719) + * Improve commit list/view on mobile (#19712) + * Move some repository related code into sub package (#19711) + * Use a better OlderThan for DeleteInactiveUsers (#19693) + * Introduce eslint-plugin-jquery (#19690) + * Tidy up `` template (#19678) + * Calculate filename hash only once (#19654) + * Simplify `IsVendor` (#19626) + * Add "Reference" section to Issue view sidebar (#19609) + * Only set CanColorStdout / CanColorStderr to true if the stdout/stderr is a terminal (#19581) + * Use for a repo action one database transaction (#19576) + * Simplify loops to copy (#19569) + * Added X-Mailer header to outgoing emails (#19562) + * use middleware to open gitRepo (#19559) + * Mute link in diff header (#19556) + * Improve UI on mobile (#19546) + * Fix Pull Request comment filename word breaks (#19535) + * Permalink files In PR diff (#19534) + * PullService lock via pullID (#19520) + * Make repository file list useable on mobile (#19515) + * more context for models (#19511) + * Refactor readme file renderer (#19502) + * By default force vertical tabs on mobile (#19486) + * Github style following followers (#19482) + * Improve action table indices (#19472) + * Use horizontal tabs for repo header on mobile (#19468) + * pass gitRepo down since its used for main repo and wiki (#19461) + * Admin should not delete himself (#19423) + * Use queue instead of memory queue in webhook send service (#19390) + * Simplify the code to get issue count (#19380) + * Add commit status popup to issuelist (#19375) + * Add RSS Feed buttons to Repo, User and Org pages (#19370) + * Add logic to switch between source/rendered on Markdown (#19356) + * Move some helper files out of models (#19355) + * Move access and repo permission to models/perm/access (#19350) + * Disallow selecting the text of buttons (#19330) + * Allow custom redirect for landing page (#19324) + * Remove dependent on session auth for api/v1 routers (#19321) + * Never use /api/v1 from Gitea UI Pages (#19318) + * Remove legacy unmaintained packages, refactor to support change default locale (#19308) + * Move milestone to models/issues/ (#19278) + * Configure OpenSSH log level via Environment in Docker (#19274) + * Move reaction to models/issues/ (#19264) + * Make git.OpenRepository accept Context (#19260) + * Move some issue methods as functions (#19255) + * Show last cron messages on monitor page (#19223) + * New cron task: delete old system notices (#19219) + * Add Redis Sentinel Authentication Support (#19213) + * Add auto logging of goroutine pid label (#19212) + * Set OpenGraph title to DisplayName in profile pages (#19206) + * Add pprof labels in processes and for lifecycles (#19202) + * Let web and API routes have different auth methods group (#19168) + * Move init repository related functions to modules (#19159) + * Feeds: render markdown to html (#19058) + * Allow users to self-request a PR review (#19030) + * Allow render HTML with css/js external links (#19017) + * Fix script compatiable with OpenWrt (#19000) + * Support ignore all santize for external renderer (#18984) + * Add note to GPG key response if user has no keys (#18961) + * Improve Stopwatch behavior (#18930) + * Improve mirror iterator (#18928) + * Uncapitalize errors (#18915) + * Prevent Stats Indexer reporting error if repo dir missing (#18870) + * Refactor SecToTime() function (#18863) + * Replace deprecated String.prototype.substr() with String.prototype.slice() (#18796) + * Move deletebeans into models/db (#18781) + * Fix display time of milestones (#18753) + * Add config option to disable "Update branch by rebase" (#18745) + * Display template path of current page in dev mode (#18717) + * Add number in queue status to monitor page (#18712) + * Change git.cmd to RunWithContext (#18693) + * Refactor i18n, use Locale to provide i18n/translation related functions (#18648) + * Delete old git.NewCommand() and use it as git.NewCommandContext() (#18552) + * Move organization related structs into sub package (#18518) + * Warn at startup if the provided `SCRIPT_TYPE` is not on the PATH (#18467) + * Use `CryptoRandomBytes` instead of `CryptoRandomString` (#18439) + * Use explicit jQuery import, remove unused eslint globals (#18435) + * Allow to filter repositories by language in explore, user and organization repositories lists (#18430) + * Use base32 for 2FA scratch token (#18384) + * Unexport var git.GlobalCommandArgs (#18376) + * Don't underline commit status icon on hover (#18372) + * Always use git command but not os.Command (#18363) + * Switch to non-deprecation setting (#18358) + * Set the LastModified header for raw files (#18356) + * Refactor jwt.StandardClaims to RegisteredClaims (#18344) + * Enable deprecation error for v1.17.0 (#18341) + * Refactor httplib (#18338) + * Limit max-height of CodeMirror editors for issue comment and wiki (#18271) + * Validate migration files (#18203) + * Format with gofumpt (#18184) + * Allow custom default merge message with .gitea/default_merge_message/_TEMPLATE.md (#18177) + * Prettify number of issues (#17760) + * Add a "admin user generate-access-token" subcommand (#17722) + * Custom regexp external issues (#17624) + * Add smtp password to install page (#17564) + * Add config options to hide issue events (#17414) + * Prevent double click new issue/pull/comment button (#16157) + * Show issue assignee on project board (#15232) +* BUGFIXES + * WebAuthn CredentialID field needs to be increased in size (#20530) (#20555) + * Ensure that all unmerged files are merged when conflict checking (#20528) (#20536) + * Stop logging EOFs and exit(1)s in ssh handler (#20476) (#20529) + * Add labels to two buttons that were missing them (#20419) (#20524) + * Fix ROOT_URL detection for URLs without trailing slash (#20502) (#20503) + * Dismiss prior pull reviews if done via web in review dismiss (#20197) (#20407) + * Allow RSA 2047 bit keys (#20272) (#20396) + * Add missing return for when topic isn't found (#20351) (#20395) + * Fix commit status icon when in subdirectory (#20285) (#20385) + * Initialize cron last (#20373) (#20384) + * Set target on create release with existing tag (#20381) (#20382) + * Update xorm.io/xorm to fix a interpreting db column sizes issue on 32bit systems (#20371) (#20372) + * Make sure `repo_dir` is an empty directory or doesn't exist before 'dump-repo' (#20205) (#20370) + * Prevent context deadline error propagation in GetCommitsInfo (#20346) (#20361) + * Correctly handle draft releases without a tag (#20314) (#20335) + * Prevent "empty" scrollbars on Firefox (#20294) (#20308) + * Refactor SSH init code, fix directory creation for TrustedUserCAKeys file (#20299) (#20306) + * Bump goldmark to v1.4.13 (#20300) (#20301) + * Do not create empty ".ssh" directory when loading config (#20289) (#20298) + * Fix NPE when using non-numeric (#20277) (#20278) + * Store read access in access for team repositories (#20275) (#20276) + * EscapeFilter the group dn membership (#20200) (#20254) + * Only show Followers that current user can access (#20220) (#20252) + * Update Bluemonday to v1.0.19 (#20199) (#20209) + * Refix indices on actions table (#20158) (#20198) + * Check if project has the same repository id with issue when assign project to issue (#20133) (#20188) + * Fix remove file on initial comment (#20127) (#20128) + * Catch the error before the response is processed by goth (#20000) (#20102) + * Dashboard feed respect setting.UI.FeedPagingNum again (#20094) (#20099) + * Alter hook_task TEXT fields to LONGTEXT (#20038) (#20041) + * Respond with a 401 on git push when password isn't changed yet (#20026) (#20027) + * Return 404 when tag is broken (#20017) (#20024) + * Alter hook_task TEXT fields to LONGTEXT (#20038) (#20041) + * Respond with a 401 on git push when password isn't changed yet (#20026) (#20027) + * Return 404 when tag is broken (#20017) (#20024) + * Write Commit-Graphs in RepositoryDumper (#20004) + * Use DisplayName() instead of FullName in Oauth Provider (#19991) + * Don't buffer doctor logger (#19982) + * Always try to fetch repo for mirrors (#19975) + * Uppercase first languages letters (#19965) + * Fix cli command restore-repo: "units" should be parsed as StringSlice (#19953) + * Ensure minimum mirror interval is reported on settings page (#19895) + * Exclude Archived repos from Dashboard Milestones (#19882) + * gitconfig: set safe.directory = * (#19870) + * Prevent NPE on update mirror settings (#19864) + * Only return valid stopwatches to the EventSource (#19863) + * Prevent NPE whilst migrating if there is a team request review (#19855) + * Fix inconsistency in doctor output (#19836) + * Fix release tag for webhook (#19830) + * Add title attribute to dependencies in sidebar (#19807) + * Estimate Action Count in Statistics (#19775) + * Do not update user stars numbers unless fix is specified (#19750) + * Improved ref comment link when origin is body/title (#19741) + * Fix nodeinfo caching and prevent NPE if cache non-existent (#19721) + * Fix duplicate entry error when add team member (#19702) + * Fix sending empty notifications (#19589) + * Update image URL for Discord webhook (#19536) + * Don't let repo clone URL overflow (#19517) + * Allow commit status popup on /pulls page (#19507) + * Fix two UI bugs: JS error in imagediff.js, 500 error in diff/compare.tmpl (#19494) + * Fix logging of Transfer API (#19456) + * Fix panic in teams API when requesting members (#19360) + * Refactor CSRF protection modules, make sure CSRF tokens can be up-to-date. (#19337) + * An attempt to sync a non-mirror repo must give 400 (Bad Request) (#19300) + * Move checks for pulls before merge into own function (#19271) + * Fix `contrib/upgrade.sh` (#19222) + * Set the default branch for repositories generated from templates (#19136) + * Fix EasyMDE error when input Enter (#19004) + * Don't clean up hardcoded `tmp` (#18983) + * Delete related notifications on issue deletion too (#18953) + * Fix trace log to show value instead of pointers (#18926) + * Fix behavior or checkbox submission. (#18851) + * Add `ContextUser` (#18798) + * Fix some mirror bugs (#18649) + * Quote MAKE to prevent path expansion with space error (#18622) + * Preserve users if restoring a repository on the same Gitea instance (#18604) + * Fix non-ASCII search on database (#18437) + * Automatically pause queue if index service is unavailable (#15066) +* TESTING + * Allow postgres integration tests to run over unix pipe (#19875) + * Prevent intermittent NPE in queue tests (#19301) + * Add test for importing pull requests in gitea uploader for migrations (#18752) + * Remove redundant comparison in repo dump/restore (#18660) + * More repo dump/restore tests, including pull requests (#18621) + * Add test coverage for original author conversion during migrations (#18506) +* TRANSLATION + * Update issue_no_dependencies description (#19112) + * Refactor webhooks i18n (#18380) +* BUILD + * Use alpine 3.16 (#19797) + * Require node 14.0 (#19451) +* DOCS + * Update documents (git/fomantic/db, etc) (#19868) + * Update the ROOT documentation and error messages (#19832) + * Update document to use FHS `/usr/local/bin/gitea` instead of `/app/...` for Docker (#19794) + * Update documentation to disable duration settings with -1 instead of 0 (#19647) + * Add warning to set SENDMAIL_ARGS to -- (#19102) + * Update nginx reverse proxy docs (#18922) + * Add example to render html files (#18736) + * Make SSH passtrough documentation better (#18687) + * Changelog 1.16.0 & 1.15.11 (#18468 & #18455) (#18470) + * Update the SSH passthrough documentation (#18366) + * Add `contrib/upgrade.sh` (#18286) +* MISC + * Fix aria for logo (#19955) + * In code search, get code unit accessible repos in one (main) query (#19764) + * Add tooltip to pending PR comments (#19662) + * Improve sync performance for pull-mirrors (#19125) + * Improve dashboard's repo list performance (#18963) + * Avoid database lookups for `DescriptionHTML` (#18924) + * Remove CodeMirror dependencies (#18911) + * Disable unnecessary mirroring elements (#18527) + * Disable unnecessary OpenID/OAuth2 elements (#18491) + * Disable unnecessary GitHooks elements (#18485) + * Change some logging levels (#18421) + * Prevent showing webauthn error for every time visiting `/user/settings/security` (#18385) + * Use correct translation key for errors (#18342) + ## [1.16.9](https://github.com/go-gitea/gitea/releases/tag/v1.16.9) - 2022-07-12 * SECURITY @@ -160,7 +468,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). ## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02 * SECURITY -* Git backend ignore replace objects (#18979) (#18980) + * Git backend ignore replace objects (#18979) (#18980) * ENHANCEMENTS * Adjust error for already locked db and prevent level db lock on malformed connstr (#18923) (#18938) * BUGFIXES diff --git a/Dockerfile b/Dockerfile index e092b5813be4..d5d98e69a83c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ #Build stage -FROM golang:1.18-alpine3.16 AS build-env +FROM golang:1.19-alpine3.16 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} diff --git a/Dockerfile.rootless b/Dockerfile.rootless index c597fb29c856..8c2b8e98c95a 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ #Build stage -FROM golang:1.18-alpine3.16 AS build-env +FROM golang:1.19-alpine3.16 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} diff --git a/MAINTAINERS b/MAINTAINERS index ec49f3f140cd..802f04cd933e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -47,3 +47,4 @@ Leon Hofmeister (@delvh) Gusted (@silentcodeg) Wim (@42wim) +xinyu (@penlinux) diff --git a/Makefile b/Makefile index 812d5f4d5a47..44e245d22524 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ SHASUM ?= shasum -a 256 HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" ) COMMA := , -XGO_VERSION := go-1.18.x +XGO_VERSION := go-1.19.x AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.5.0 @@ -364,7 +364,7 @@ test\#%: coverage: grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' coverage.out > coverage-bodged.out grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' integration.coverage.out > integration.coverage-bodged.out - $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all || (echo "gocovmerge failed"; echo "integration.coverage.out"; cat integration.coverage.out; echo "coverage.out"; cat coverage.out; exit 1) + $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all .PHONY: unit-test-coverage unit-test-coverage: diff --git a/cmd/doctor.go b/cmd/doctor.go index 3f16c6e2a600..67a4ecc9c8eb 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -124,13 +124,13 @@ func runRecreateTable(ctx *cli.Context) error { } func runDoctor(ctx *cli.Context) error { + stdCtx, cancel := installSignals() + defer cancel() + // Silence the default loggers log.DelNamedLogger("console") log.DelNamedLogger(log.DEFAULT) - stdCtx, cancel := installSignals() - defer cancel() - // Now setup our own logFile := ctx.String("log-file") if !ctx.IsSet("log-file") { diff --git a/cmd/main_test.go b/cmd/main_test.go new file mode 100644 index 000000000000..9cce0ef0360b --- /dev/null +++ b/cmd/main_test.go @@ -0,0 +1,23 @@ +// 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 cmd + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" +) + +func init() { + setting.SetCustomPathAndConf("", "", "") + setting.LoadForTest() +} + +func TestMain(m *testing.M) { + unittest.MainTest(m, &unittest.TestOptions{ + GiteaRootPath: "..", + }) +} diff --git a/cmd/migrate_storage.go b/cmd/migrate_storage.go index 93fb64a4d3a5..f11cf9b11f37 100644 --- a/cmd/migrate_storage.go +++ b/cmd/migrate_storage.go @@ -12,9 +12,11 @@ import ( "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/models/migrations" + packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" + packages_module "code.gitea.io/gitea/modules/packages" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" @@ -25,13 +27,13 @@ import ( var CmdMigrateStorage = cli.Command{ Name: "migrate-storage", Usage: "Migrate the storage", - Description: "This is a command for migrating storage.", + Description: "Copies stored files from storage configured in app.ini to parameter-configured storage", Action: runMigrateStorage, Flags: []cli.Flag{ cli.StringFlag{ Name: "type, t", Value: "", - Usage: "Kinds of files to migrate, currently only 'attachments' is supported", + Usage: "Type of stored files to copy. Allowed types: 'attachments', 'lfs', 'avatars', 'repo-avatars', 'repo-archivers', 'packages'", }, cli.StringFlag{ Name: "storage, s", @@ -80,34 +82,53 @@ var CmdMigrateStorage = cli.Command{ }, } -func migrateAttachments(dstStorage storage.ObjectStorage) error { - return repo_model.IterateAttachment(func(attach *repo_model.Attachment) error { +func migrateAttachments(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.IterateObjects(ctx, func(attach *repo_model.Attachment) error { _, err := storage.Copy(dstStorage, attach.RelativePath(), storage.Attachments, attach.RelativePath()) return err }) } -func migrateLFS(dstStorage storage.ObjectStorage) error { - return git_model.IterateLFS(func(mo *git_model.LFSMetaObject) error { +func migrateLFS(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.IterateObjects(ctx, func(mo *git_model.LFSMetaObject) error { _, err := storage.Copy(dstStorage, mo.RelativePath(), storage.LFS, mo.RelativePath()) return err }) } -func migrateAvatars(dstStorage storage.ObjectStorage) error { - return user_model.IterateUser(func(user *user_model.User) error { +func migrateAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.IterateObjects(ctx, func(user *user_model.User) error { _, err := storage.Copy(dstStorage, user.CustomAvatarRelativePath(), storage.Avatars, user.CustomAvatarRelativePath()) return err }) } -func migrateRepoAvatars(dstStorage storage.ObjectStorage) error { - return repo_model.IterateRepository(func(repo *repo_model.Repository) error { +func migrateRepoAvatars(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.IterateObjects(ctx, func(repo *repo_model.Repository) error { _, err := storage.Copy(dstStorage, repo.CustomAvatarRelativePath(), storage.RepoAvatars, repo.CustomAvatarRelativePath()) return err }) } +func migrateRepoArchivers(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.IterateObjects(ctx, func(archiver *repo_model.RepoArchiver) error { + p, err := archiver.RelativePath() + if err != nil { + return err + } + _, err = storage.Copy(dstStorage, p, storage.RepoArchives, p) + return err + }) +} + +func migratePackages(ctx context.Context, dstStorage storage.ObjectStorage) error { + return db.IterateObjects(ctx, func(pb *packages_model.PackageBlob) error { + p := packages_module.KeyToRelativePath(packages_module.BlobHash256Key(pb.HashSHA256)) + _, err := storage.Copy(dstStorage, p, storage.Packages, p) + return err + }) +} + func runMigrateStorage(ctx *cli.Context) error { stdCtx, cancel := installSignals() defer cancel() @@ -127,8 +148,6 @@ func runMigrateStorage(ctx *cli.Context) error { return err } - goCtx := context.Background() - if err := storage.Init(); err != nil { return err } @@ -145,13 +164,13 @@ func runMigrateStorage(ctx *cli.Context) error { return nil } dstStorage, err = storage.NewLocalStorage( - goCtx, + stdCtx, storage.LocalStorageConfig{ Path: p, }) case string(storage.MinioStorageType): dstStorage, err = storage.NewMinioStorage( - goCtx, + stdCtx, storage.MinioStorageConfig{ Endpoint: ctx.String("minio-endpoint"), AccessKeyID: ctx.String("minio-access-key-id"), @@ -162,35 +181,29 @@ func runMigrateStorage(ctx *cli.Context) error { UseSSL: ctx.Bool("minio-use-ssl"), }) default: - return fmt.Errorf("Unsupported storage type: %s", ctx.String("storage")) + return fmt.Errorf("unsupported storage type: %s", ctx.String("storage")) } if err != nil { return err } + migratedMethods := map[string]func(context.Context, storage.ObjectStorage) error{ + "attachments": migrateAttachments, + "lfs": migrateLFS, + "avatars": migrateAvatars, + "repo-avatars": migrateRepoAvatars, + "repo-archivers": migrateRepoArchivers, + "packages": migratePackages, + } + tp := strings.ToLower(ctx.String("type")) - switch tp { - case "attachments": - if err := migrateAttachments(dstStorage); err != nil { - return err - } - case "lfs": - if err := migrateLFS(dstStorage); err != nil { - return err - } - case "avatars": - if err := migrateAvatars(dstStorage); err != nil { - return err - } - case "repo-avatars": - if err := migrateRepoAvatars(dstStorage); err != nil { + if m, ok := migratedMethods[tp]; ok { + if err := m(stdCtx, dstStorage); err != nil { return err } - default: - return fmt.Errorf("Unsupported storage: %s", ctx.String("type")) + log.Info("%s files have successfully been copied to the new storage.", tp) + return nil } - log.Warn("All files have been copied to the new placement but old files are still on the original placement.") - - return nil + return fmt.Errorf("unsupported storage: %s", ctx.String("type")) } diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go new file mode 100644 index 000000000000..e6d205e4109d --- /dev/null +++ b/cmd/migrate_storage_test.go @@ -0,0 +1,74 @@ +// 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 cmd + +import ( + "context" + "os" + "strings" + "testing" + + "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + packages_module "code.gitea.io/gitea/modules/packages" + "code.gitea.io/gitea/modules/storage" + packages_service "code.gitea.io/gitea/services/packages" + + "github.com/stretchr/testify/assert" +) + +func TestMigratePackages(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + creator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + + content := "package main\n\nfunc main() {\nfmt.Println(\"hi\")\n}\n" + buf, err := packages_module.CreateHashedBufferFromReader(strings.NewReader(content), 1024) + assert.NoError(t, err) + defer buf.Close() + + v, f, err := packages_service.CreatePackageAndAddFile(&packages_service.PackageCreationInfo{ + PackageInfo: packages_service.PackageInfo{ + Owner: creator, + PackageType: packages.TypeGeneric, + Name: "test", + Version: "1.0.0", + }, + Creator: creator, + SemverCompatible: true, + VersionProperties: map[string]string{}, + }, &packages_service.PackageFileCreationInfo{ + PackageFileInfo: packages_service.PackageFileInfo{ + Filename: "a.go", + }, + Data: buf, + IsLead: true, + }) + assert.NoError(t, err) + assert.NotNil(t, v) + assert.NotNil(t, f) + + ctx := context.Background() + + p, err := os.MkdirTemp(os.TempDir(), "migrated_packages") + assert.NoError(t, err) + + dstStorage, err := storage.NewLocalStorage( + ctx, + storage.LocalStorageConfig{ + Path: p, + }) + assert.NoError(t, err) + + err = migratePackages(ctx, dstStorage) + assert.NoError(t, err) + + entries, err := os.ReadDir(p) + assert.NoError(t, err) + assert.EqualValues(t, 2, len(entries)) + assert.EqualValues(t, "01", entries[0].Name()) + assert.EqualValues(t, "tmp", entries[1].Name()) +} diff --git a/contrib/pr/checkout.go b/contrib/pr/checkout.go index f6d29f3c5b57..65762a91e3b8 100644 --- a/contrib/pr/checkout.go +++ b/contrib/pr/checkout.go @@ -80,7 +80,6 @@ func runPR() { setting.RunUser = curUser.Username log.Printf("[PR] Loading fixtures data ...\n") - gitea_git.CheckLFSVersion() //models.LoadConfigs() /* setting.Database.Type = "sqlite3" diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 367553f1fa44..5e612fb42860 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -377,9 +377,10 @@ INTERNAL_TOKEN= ;; Name of cookie used to store authentication information. ;COOKIE_REMEMBER_NAME = gitea_incredible ;; -;; Reverse proxy authentication header name of user name and email +;; Reverse proxy authentication header name of user name, email, and full name ;REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER ;REVERSE_PROXY_AUTHENTICATION_EMAIL = X-WEBAUTH-EMAIL +;REVERSE_PROXY_AUTHENTICATION_FULL_NAME = X-WEBAUTH-FULLNAME ;; ;; Interpret X-Forwarded-For header or the X-Real-IP header and set this as the remote IP for the request ;REVERSE_PROXY_LIMIT = 1 @@ -632,6 +633,7 @@ ROUTER = console ;GC_ARGS = ;; ;; If use git wire protocol version 2 when git version >= 2.18, default is true, set to false when you always want git wire protocol version 1 +;; To enable this for Git over SSH when using a OpenSSH server, add `AcceptEnv GIT_PROTOCOL` to your sshd_config file. ;ENABLE_AUTO_GIT_WIRE_PROTOCOL = true ;; ;; Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled) @@ -693,13 +695,16 @@ ROUTER = console ;ENABLE_REVERSE_PROXY_AUTHENTICATION = false ;ENABLE_REVERSE_PROXY_AUTO_REGISTRATION = false ;ENABLE_REVERSE_PROXY_EMAIL = false +;ENABLE_REVERSE_PROXY_FULL_NAME = false ;; ;; Enable captcha validation for registration ;ENABLE_CAPTCHA = false ;; -;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha +;; Type of captcha you want to use. Options: image, recaptcha, hcaptcha, mcaptcha. ;CAPTCHA_TYPE = image ;; +;; Change this to use recaptcha.net or other recaptcha service +;RECAPTCHA_URL = https://www.google.com/recaptcha/ ;; Enable recaptcha to use Google's recaptcha service ;; Go to https://www.google.com/recaptcha/admin to sign up for a key ;RECAPTCHA_SECRET = @@ -709,8 +714,13 @@ ROUTER = console ;HCAPTCHA_SECRET = ;HCAPTCHA_SITEKEY = ;; -;; Change this to use recaptcha.net or other recaptcha service -;RECAPTCHA_URL = https://www.google.com/recaptcha/ +;; Change this to use demo.mcaptcha.org or your self-hosted mcaptcha.org instance. +;MCAPTCHA_URL = https://demo.mcaptcha.org +;; +;; Go to your configured mCaptcha instance and register a sitekey +;; and use your account's secret. +;MCAPTCHA_SECRET = +;MCAPTCHA_SITEKEY = ;; ;; Default value for KeepEmailPrivate ;; Each new user will get the value of this setting copied into their profile @@ -1082,7 +1092,7 @@ ROUTER = console ;EXPLORE_PAGING_NUM = 20 ;; ;; Number of issues that are displayed on one page -;ISSUE_PAGING_NUM = 10 +;ISSUE_PAGING_NUM = 20 ;; ;; Number of maximum commits displayed in one activity feed ;FEED_MAX_COMMIT_NUM = 5 @@ -1495,6 +1505,11 @@ ROUTER = console ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; +;; NOTICE: this section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older, +;; please refer to +;; https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini +;; https://github.com/go-gitea/gitea/blob/release/v1.17/docs/content/doc/advanced/config-cheat-sheet.en-us.md +;; ;ENABLED = false ;; ;; Buffer length of channel, keep it as it is if you don't know what it is. @@ -1508,12 +1523,12 @@ ROUTER = console ;; - 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, ;; you can set SMTP_PORT instead and this will be inferred. -;; (Before 1.18, this was controlled via MAILER_TYPE and IS_TLS_ENABLED.) +;; (Before 1.18, see the notice, this was controlled via MAILER_TYPE and IS_TLS_ENABLED.) ;PROTOCOL = ;; ;; Mail server address, e.g. smtp.gmail.com. ;; For smtp+unix, this should be a path to a unix socket instead. -;; (Before 1.18, this was combined with SMTP_PORT as HOST.) +;; (Before 1.18, see the notice, this was combined with SMTP_PORT as HOST.) ;SMTP_ADDR = ;; ;; Mail server port. Common ports are: diff --git a/docs/config.yaml b/docs/config.yaml index 2d15e774eb7f..d9544bd30177 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -20,8 +20,9 @@ params: website: https://docs.gitea.io version: 1.16.9 minGoVersion: 1.18 - goVersion: 1.18 + goVersion: 1.19 minNodeVersion: 14 + search: nav outputs: home: diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index c6a4d989a6f6..37f887d4aa3d 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -172,7 +172,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a ## UI (`ui`) - `EXPLORE_PAGING_NUM`: **20**: Number of repositories that are shown in one explore page. -- `ISSUE_PAGING_NUM`: **10**: Number of issues that are shown in one page (for all pages that list issues). +- `ISSUE_PAGING_NUM`: **20**: Number of issues that are shown in one page (for all pages that list issues, milestones, projects). - `MEMBERS_PAGING_NUM`: **20**: Number of members that are shown in organization members. - `FEED_MAX_COMMIT_NUM`: **5**: Number of maximum commits shown in one activity feed. - `FEED_PAGING_NUM`: **20**: Number of items that are displayed in home feed. @@ -296,8 +296,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `MINIMUM_KEY_SIZE_CHECK`: **true**: Indicate whether to check minimum key size with corresponding type. - `OFFLINE_MODE`: **false**: Disables use of CDN for static files and Gravatar for profile pictures. -- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`. -- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. From 1.11 paths are relative to `CUSTOM_PATH`. +- `CERT_FILE`: **https/cert.pem**: Cert file path used for HTTPS. When chaining, the server certificate must come first, then intermediate CA certificates (if any). This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`. +- `KEY_FILE`: **https/key.pem**: Key file path used for HTTPS. This is ignored if `ENABLE_ACME=true`. Paths are relative to `CUSTOM_PATH`. - `STATIC_ROOT_PATH`: **./**: Upper level of template and static files path. - `APP_DATA_PATH`: **data** (**/data/gitea** on docker): Default path for application data. - `STATIC_CACHE_TIME`: **6h**: Web browser cache time for static resources on `custom/`, `public/` and all uploaded avatars. Note that this cache is disabled when `RUN_MODE` is "dev". @@ -438,11 +438,11 @@ Configuration at `[queue]` will set defaults for queues with overrides for indiv - `MAX_ATTEMPTS`: **10**: Maximum number of attempts to create the wrapped queue - `TIMEOUT`: **GRACEFUL_HAMMER_TIME + 30s**: Timeout the creation of the wrapped queue if it takes longer than this to create. - Queues by default come with a dynamically scaling worker pool. The following settings configure this: -- `WORKERS`: **0** (v1.14 and before: **1**): Number of initial workers for the queue. +- `WORKERS`: **0**: Number of initial workers for the queue. - `MAX_WORKERS`: **10**: Maximum number of worker go-routines for the queue. - `BLOCK_TIMEOUT`: **1s**: If the queue blocks for this time, boost the number of workers - the `BLOCK_TIMEOUT` will then be doubled before boosting again whilst the boost is ongoing. - `BOOST_TIMEOUT`: **5m**: Boost workers will timeout after this long. -- `BOOST_WORKERS`: **1** (v1.14 and before: **5**): This many workers will be added to the worker pool if there is a boost. +- `BOOST_WORKERS`: **1**: This many workers will be added to the worker pool if there is a boost. Gitea creates the following non-unique queues: @@ -492,6 +492,8 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o authentication. - `REVERSE_PROXY_AUTHENTICATION_EMAIL`: **X-WEBAUTH-EMAIL**: Header name for reverse proxy authentication provided email. +- `REVERSE_PROXY_AUTHENTICATION_FULL_NAME`: **X-WEBAUTH-FULLNAME**: Header name for reverse proxy + authentication provided full name. - `REVERSE_PROXY_LIMIT`: **1**: Interpret X-Forwarded-For header or the X-Real-IP header and set this as the remote IP for the request. Number of trusted proxy count. Set to zero to not use these headers. - `REVERSE_PROXY_TRUSTED_PROXIES`: **127.0.0.0/8,::1/128**: List of IP addresses and networks separated by comma of trusted proxy servers. Use `*` to trust all. @@ -577,15 +579,20 @@ Certain queues have defaults that override the defaults set in `[queue]` (this o for reverse authentication. - `ENABLE_REVERSE_PROXY_EMAIL`: **false**: Enable this to allow to auto-registration with a provided email rather than a generated email. +- `ENABLE_REVERSE_PROXY_FULL_NAME`: **false**: Enable this to allow to auto-registration with a + provided full name for the user. - `ENABLE_CAPTCHA`: **false**: Enable this to use captcha validation for registration. - `REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA`: **false**: Enable this to force captcha validation - even for External Accounts (i.e. GitHub, OpenID Connect, etc). You must `ENABLE_CAPTCHA` also. -- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha\] + even for External Accounts (i.e. GitHub, OpenID Connect, etc). You also must enable `ENABLE_CAPTCHA`. +- `CAPTCHA_TYPE`: **image**: \[image, recaptcha, hcaptcha, mcaptcha\] - `RECAPTCHA_SECRET`: **""**: Go to https://www.google.com/recaptcha/admin to get a secret for recaptcha. - `RECAPTCHA_SITEKEY`: **""**: Go to https://www.google.com/recaptcha/admin to get a sitekey for recaptcha. - `RECAPTCHA_URL`: **https://www.google.com/recaptcha/**: Set the recaptcha url - allows the use of recaptcha net. - `HCAPTCHA_SECRET`: **""**: Sign up at https://www.hcaptcha.com/ to get a secret for hcaptcha. - `HCAPTCHA_SITEKEY`: **""**: Sign up at https://www.hcaptcha.com/ to get a sitekey for hcaptcha. +- `MCAPTCHA_SECRET`: **""**: Go to your mCaptcha instance to get a secret for mCaptcha. +- `MCAPTCHA_SITEKEY`: **""**: Go to your mCaptcha instance to get a sitekey for mCaptcha. +- `MCAPTCHA_URL` **https://demo.mcaptcha.org/**: Set the mCaptcha URL. - `DEFAULT_KEEP_EMAIL_PRIVATE`: **false**: By default set users to keep their email address private. - `DEFAULT_ALLOW_CREATE_ORGANIZATION`: **true**: Allow new users to create organizations by default. - `DEFAULT_USER_IS_RESTRICTED`: **false**: Give new users restricted permissions by default @@ -631,7 +638,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type - `QUEUE_LENGTH`: **1000**: Hook task queue length. Use caution when editing this value. - `DELIVER_TIMEOUT`: **5**: Delivery timeout (sec) for shooting webhooks. -- `ALLOWED_HOST_LIST`: **external**: Since 1.15.7. Default to `*` for 1.15.x, `external` for 1.16 and later. Webhook can only call allowed hosts for security reasons. Comma separated list. +- `ALLOWED_HOST_LIST`: **external**: Webhook can only call allowed hosts for security reasons. Comma separated list. - Built-in networks: - `loopback`: 127.0.0.0/8 for IPv4 and ::1/128 for IPv6, localhost is included. - `private`: RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) and RFC 4193 (FC00::/7). Also called LAN/Intranet. @@ -646,6 +653,12 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type ## Mailer (`mailer`) +⚠️ This section is for Gitea 1.18 and later. If you are using Gitea 1.17 or older, +please refer to +[Gitea 1.17 app.ini example](https://github.com/go-gitea/gitea/blob/release/v1.17/custom/conf/app.example.ini) +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`: **\**: 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. @@ -964,7 +977,8 @@ Default templates for project boards: - `COMMITS_RANGE_SIZE`: **50**: Set the default commits range size - `BRANCHES_RANGE_SIZE`: **20**: Set the default branches range size - `GC_ARGS`: **\**: Arguments for command `git gc`, e.g. `--aggressive --auto`. See more on http://git-scm.com/docs/git-gc/ -- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use Git wire protocol version 2 when Git version >= 2.18, default is true, set to false when you always want Git wire protocol version 1 +- `ENABLE_AUTO_GIT_WIRE_PROTOCOL`: **true**: If use Git wire protocol version 2 when Git version >= 2.18, default is true, set to false when you always want Git wire protocol version 1. + To enable this for Git over SSH when using a OpenSSH server, add `AcceptEnv GIT_PROTOCOL` to your sshd_config file. - `PULL_REQUEST_PUSH_MESSAGE`: **true**: Respond to pushes to a non-default branch with a URL for creating a Pull Request (if the repository has them enabled) - `VERBOSE_PUSH`: **true**: Print status information about pushes as they are being processed. - `VERBOSE_PUSH_DELAY`: **5s**: Only print verbose information if push takes longer than this delay. diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index c2dff2aeca37..34de3c0324f1 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -15,7 +15,14 @@ menu: # 配置说明 -这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。所有默认值可以通过 [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) 查看到。如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 +这是针对Gitea配置文件的说明,你可以了解Gitea的强大配置。需要说明的是,你的所有改变请修改 `custom/conf/app.ini` 文件而不是源文件。 +所有默认值可以通过 [app.example.ini](https://github.com/go-gitea/gitea/blob/master/custom/conf/app.example.ini) 查看到。 +如果你发现 `%(X)s` 这样的内容,请查看 [ini](https://github.com/go-ini/ini/#recursive-values) 这里的说明。 +标注了 :exclamation: 的配置项表明除非你真的理解这个配置项的意义,否则最好使用默认值。 + +## ⚠️时效性警告⚠️ + +此文档的内容可能过于陈旧或者错误,请参考英文文档。 {{< toc >}} diff --git a/docs/content/doc/developers/api-usage.en-us.md b/docs/content/doc/developers/api-usage.en-us.md index dd2822e9f136..1ff912353fed 100644 --- a/docs/content/doc/developers/api-usage.en-us.md +++ b/docs/content/doc/developers/api-usage.en-us.md @@ -105,6 +105,18 @@ curl -X POST "http://localhost:4000/api/v1/repos/test1/test1/issues" \ As mentioned above, the token used is the same one you would use in the `token=` string in a GET request. +## Pagination + +The API supports pagination. The `page` and `limit` parameters are used to specify the page number and the number of items per page. As well, the `Link` header is returned with the next, previous, and last page links if there are more than one pages. The `x-total-count` is also returned to indicate the total number of items. + +```sh +curl -v "http://localhost/api/v1/repos/search?limit=1" +... +< link: ; rel="next",; rel="last" +... +< x-total-count: 5252 +``` + ## API Guide: API Reference guide is auto-generated by swagger and available on: diff --git a/docs/content/doc/features/comparison.en-us.md b/docs/content/doc/features/comparison.en-us.md index 36180e3f5b4b..db13c87d5f0d 100644 --- a/docs/content/doc/features/comparison.en-us.md +++ b/docs/content/doc/features/comparison.en-us.md @@ -122,6 +122,7 @@ _Symbols used in table:_ | AD / LDAP integration | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | Multiple LDAP / AD server support | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | | LDAP user synchronization | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | +| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | [✘](https://github.com/gogs/gogs/issues/1221) | ✓ | ✓ | ✓ | ✓ | ✘ | | OpenId Connect support | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | | OAuth 2.0 integration (external authorization) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✓ | | Act as OAuth 2.0 provider | [✓](https://github.com/go-gitea/gitea/pull/5378) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | diff --git a/docs/content/doc/features/comparison.zh-cn.md b/docs/content/doc/features/comparison.zh-cn.md index 990a78aec0d5..f0eac22a262b 100644 --- a/docs/content/doc/features/comparison.zh-cn.md +++ b/docs/content/doc/features/comparison.zh-cn.md @@ -46,7 +46,7 @@ _表格中的符号含义:_ | Git 驱动的集成化 wiki | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | | 部署令牌 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | 仓库写权限令牌 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ | -| 内置容器 Registry | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | +| 内置容器 Registry | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | | 外部 Git 镜像 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | | WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ? | | 内置 CI/CD | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | @@ -62,7 +62,7 @@ _表格中的符号含义:_ | Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ⁄ | ✓ | | 组织里程碑 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | | 细粒度用户角色 (例如 Code, Issues, Wiki) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| 提交人的身份验证 | ✘ | ✘ | ? | ✓ | ✓ | ✓ | ✘ | +| 提交人的身份验证 | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ | | GPG 签名的提交 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | | SSH 签名的提交 | ✓ | ✘ | ✘ | ✘ | ✘ | ? | ? | | 拒绝未用通过验证的提交 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ | @@ -71,6 +71,7 @@ _表格中的符号含义:_ | 建立新分支 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | | 在线代码编辑 | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | 提交的统计图表 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | +| 模板仓库 | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ | #### Issue 管理 @@ -84,9 +85,9 @@ _表格中的符号含义:_ | 关联的 issues | ✘ | ✘ | ⁄ | ✘ | ✓ | ✘ | ✘ | | 私密 issues | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | | 评论反馈 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| 锁定讨论 | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | +| 锁定讨论 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | | Issue 批量处理 | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Issue 看板 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | +| Issue 看板 | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | | 从 issues 创建分支 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | | Issue 搜索 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | | 全局 Issue 搜索 | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | @@ -108,6 +109,7 @@ _表格中的符号含义:_ | 回退某些 commits 或 merge request | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | | Pull/Merge requests 模板 | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | | 查看 Cherry-picking 的更改 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | +| 下载 Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✘ | #### 第三方集成 @@ -118,10 +120,12 @@ _表格中的符号含义:_ | 集成 AD / LDAP | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | 支持多个 LDAP / AD 服务 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | | LDAP 用户同步 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | +| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | [✘](https://github.com/gogs/gogs/issues/1221) | ✓ | ✓ | ✓ | ✓ | ✘ | | 支持 OpenId 连接 | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | | 集成 OAuth 2.0(外部授权) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✓ | | 作为 OAuth 2.0 provider | [✓](https://github.com/go-gitea/gitea/pull/5378) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | | 二次验证 (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | | 集成 Mattermost/Slack | ✓ | ✓ | ⁄ | ✓ | ✓ | ⁄ | ✓ | | 集成 Discord | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| 集成 Microsoft Teams | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | | 显示外部 CI/CD 的状态 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | diff --git a/docs/content/doc/features/comparison.zh-tw.md b/docs/content/doc/features/comparison.zh-tw.md index a2604c9052e1..015955f0a852 100644 --- a/docs/content/doc/features/comparison.zh-tw.md +++ b/docs/content/doc/features/comparison.zh-tw.md @@ -121,6 +121,7 @@ menu: | 整合 AD / LDAP | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | 支援多重 LDAP / AD 伺服器 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | | 同步 LDAP 使用者 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | +| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | [✘](https://github.com/gogs/gogs/issues/1221) | ✓ | ✓ | ✓ | ✓ | ✘ | | 支援 OpenId Connect | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | | 整合 OAuth 2.0 (外部驗證) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✓ | | 成為 OAuth 2.0 提供者 | [✓](https://github.com/go-gitea/gitea/pull/5378) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | diff --git a/docs/content/doc/help/search.de-de.md b/docs/content/doc/help/search.de-de.md new file mode 100644 index 000000000000..cfacfe737e0f --- /dev/null +++ b/docs/content/doc/help/search.de-de.md @@ -0,0 +1,18 @@ +--- +date: "2019-11-12T16:00:00+02:00" +title: "Search" +slug: "search" +weight: 4 +toc: false +draft: false +sitemap: + priority : 0.1 +layout: "search" +--- + + +This file exists solely to respond to /search URL with the related `search` layout template. + +No content shown here is rendered, all content is based in the template layouts/doc/search.html + +Setting a very low sitemap priority will tell search engines this is not important content. diff --git a/docs/content/doc/help/search.en-us.md b/docs/content/doc/help/search.en-us.md index 8d4b0d20cbfd..cfacfe737e0f 100644 --- a/docs/content/doc/help/search.en-us.md +++ b/docs/content/doc/help/search.en-us.md @@ -5,12 +5,6 @@ slug: "search" weight: 4 toc: false draft: false -menu: - sidebar: - parent: "help" - name: "Search" - weight: 4 - identifier: "search" sitemap: priority : 0.1 layout: "search" diff --git a/docs/content/doc/help/search.fr-fr.md b/docs/content/doc/help/search.fr-fr.md index 16fff85a98cf..bfcd6f3c440a 100644 --- a/docs/content/doc/help/search.fr-fr.md +++ b/docs/content/doc/help/search.fr-fr.md @@ -5,12 +5,6 @@ slug: "search" weight: 4 toc: false draft: false -menu: - sidebar: - parent: "help" - name: "Chercher" - weight: 4 - identifier: "search" sitemap: priority : 0.1 layout: "search" diff --git a/docs/content/doc/help/search.nl-nl.md b/docs/content/doc/help/search.nl-nl.md new file mode 100644 index 000000000000..cfacfe737e0f --- /dev/null +++ b/docs/content/doc/help/search.nl-nl.md @@ -0,0 +1,18 @@ +--- +date: "2019-11-12T16:00:00+02:00" +title: "Search" +slug: "search" +weight: 4 +toc: false +draft: false +sitemap: + priority : 0.1 +layout: "search" +--- + + +This file exists solely to respond to /search URL with the related `search` layout template. + +No content shown here is rendered, all content is based in the template layouts/doc/search.html + +Setting a very low sitemap priority will tell search engines this is not important content. diff --git a/docs/content/doc/help/search.pt-br.md b/docs/content/doc/help/search.pt-br.md new file mode 100644 index 000000000000..cfacfe737e0f --- /dev/null +++ b/docs/content/doc/help/search.pt-br.md @@ -0,0 +1,18 @@ +--- +date: "2019-11-12T16:00:00+02:00" +title: "Search" +slug: "search" +weight: 4 +toc: false +draft: false +sitemap: + priority : 0.1 +layout: "search" +--- + + +This file exists solely to respond to /search URL with the related `search` layout template. + +No content shown here is rendered, all content is based in the template layouts/doc/search.html + +Setting a very low sitemap priority will tell search engines this is not important content. diff --git a/docs/content/doc/help/search.zh-cn.md b/docs/content/doc/help/search.zh-cn.md index 52fae9defb8f..f6243d1e8f47 100644 --- a/docs/content/doc/help/search.zh-cn.md +++ b/docs/content/doc/help/search.zh-cn.md @@ -5,12 +5,6 @@ slug: "search" weight: 4 toc: false draft: false -menu: - sidebar: - parent: "help" - name: "搜索" - weight: 4 - identifier: "search" sitemap: priority : 0.1 layout: "search" diff --git a/docs/content/doc/help/search.zh-tw.md b/docs/content/doc/help/search.zh-tw.md index ef3c74a90d40..335f95571372 100644 --- a/docs/content/doc/help/search.zh-tw.md +++ b/docs/content/doc/help/search.zh-tw.md @@ -5,12 +5,6 @@ slug: "search" weight: 4 toc: false draft: false -menu: - sidebar: - parent: "help" - name: "搜尋" - weight: 4 - identifier: "search" sitemap: priority : 0.1 layout: "search" diff --git a/docs/content/doc/installation/from-source.zh-cn.md b/docs/content/doc/installation/from-source.zh-cn.md index 275b0c2f7479..008566e57db5 100644 --- a/docs/content/doc/installation/from-source.zh-cn.md +++ b/docs/content/doc/installation/from-source.zh-cn.md @@ -15,29 +15,35 @@ menu: # 从源代码安装 -首先你需要安装Golang,关于Golang的安装,参见官方文档 [install instructions](https://golang.org/doc/install)。 +首先你需要安装Golang,关于Golang的安装,参见[官方文档](https://golang.google.cn/doc/install)。 + +其次你需要[安装Node.js](https://nodejs.org/zh-cn/download/),Node.js 和 npm 将用于构建 Gitea 前端。 + +**目录** + +{{< toc >}} ## 下载 -你需要获取Gitea的源码,最方便的方式是使用 go 命令。执行以下命令: +你需要获取Gitea的源码,最方便的方式是使用 `git` 命令。执行以下命令: ``` -go get -d -u code.gitea.io/gitea -cd $GOPATH/src/code.gitea.io/gitea +git clone https://github.com/go-gitea/gitea +cd gitea ``` -然后你可以选择编译和安装的版本,当前你有多个选择。如果你想编译 `master` 版本,你可以直接跳到 [编译](#编译) 部分,这是我们的开发分支,虽然也很稳定但不建议您在正式产品中使用。 +然后你可以选择编译和安装的版本,当前你有多个选择。如果你想编译 `main` 版本,你可以直接跳到 [编译](#编译) 部分,这是我们的开发分支,虽然也很稳定但不建议您在正式产品中使用。 如果你想编译最新稳定分支,你可以执行以下命令签出源码: -``` +```bash git branch -a git checkout v{{< version >}} ``` 最后,你也可以直接使用标签版本如 `v{{< version >}}`。你可以执行以下命令列出可用的版本并选择某个版本签出: -``` +```bash git tag -l git checkout v{{< version >}} ``` @@ -46,11 +52,11 @@ git checkout v{{< version >}} 要从源代码进行编译,以下依赖程序必须事先安装好: -- `go` {{< min-go-version >}} 或以上版本, 详见 [here](https://golang.org/dl/) -- `node` {{< min-node-version >}} 或以上版本,并且安装 `npm`, 详见 [here](https://nodejs.org/en/download/) -- `make`, 详见 这里 +- `go` {{< min-go-version >}} 或以上版本, 详见[这里](https://golang.google.cn/doc/install) +- `node` {{< min-node-version >}} 或以上版本,并且安装 `npm`, 详见[这里](https://nodejs.org/zh-cn/download/) +- `make`, 详见[这里]({{< relref "make.zh-cn.md" >}}) -各种可用的 [make 任务](https://github.com/go-gitea/gitea/blob/master/Makefile) +各种可用的 [make 任务](https://github.com/go-gitea/gitea/blob/main/Makefile) 可以用来使编译过程更方便。 按照您的编译需求,以下 tags 可以使用: @@ -76,10 +82,26 @@ TAGS="bindata sqlite sqlite_unlock_notify" make build 在执行了以上步骤之后,你将会获得 `gitea` 的二进制文件,在你复制到部署的机器之前可以先测试一下。在命令行执行完后,你可以 `Ctrl + C` 关掉程序。 -``` +```bash ./gitea web ``` +## 交叉编译 + +Go 编译器支持交叉编译到不同的目标架构。有关 Go 支持的目标架构列表,请参见 [Optional environment variables](https://go.dev/doc/install/source#environment)。 + +交叉构建适用于 Linux ARM64 的 Gitea: + +```bash +GOOS=linux GOARCH=arm64 make build +``` + +交叉构建适用于 Linux ARM64 的 Gitea,并且带上 Gitea 发行版采用的编译选项: + +```bash +CC=aarch64-unknown-linux-gnu-gcc GOOS=linux GOARCH=arm64 TAGS="bindata sqlite sqlite_unlock_notify" make build +``` + ## 需要帮助? 如果从本页中没有找到你需要的内容,请访问 [帮助页面]({{< relref "seek-help.zh-cn.md" >}}) diff --git a/docs/content/doc/installation/with-docker.zh-cn.md b/docs/content/doc/installation/with-docker.zh-cn.md index 91892fdaf95c..2c63c9d4e1e4 100644 --- a/docs/content/doc/installation/with-docker.zh-cn.md +++ b/docs/content/doc/installation/with-docker.zh-cn.md @@ -23,7 +23,7 @@ Gitea 在其 Docker Hub 组织内提供自动更新的 Docker 镜像。可以始 ## 基本 -最简单的设置只是创建一个卷和一个网络,然后将 `gitea/gitea:latest` 镜像作为服务启动。由于没有可用的数据库,因此可以使用 SQLite3 初始化数据库。创建一个类似 `gitea` 的目录,并将以下内容粘贴到名为 `docker-compose.yml` 的文件中。请注意,该卷应由配置文件中指定的 UID/GID 的用户/组拥有。如果您不授予卷正确的权限,则容器可能无法启动。另请注意,标签 `:latest` 将安装当前的开发版本。对于稳定的发行版,您可以使用 `:1` 或指定某个发行版,例如 `:1.13.0`。 +最简单的设置只是创建一个卷和一个网络,然后将 `gitea/gitea:latest` 镜像作为服务启动。由于没有可用的数据库,因此可以使用 SQLite3 初始化数据库。创建一个类似 `gitea` 的目录,并将以下内容粘贴到名为 `docker-compose.yml` 的文件中。请注意,该卷应由配置文件中指定的 UID/GID 的用户/组拥有。如果您不授予卷正确的权限,则容器可能无法启动。另请注意,标签 `:latest` 将安装当前的开发版本。对于稳定的发行版,您可以使用 `:1` 或指定某个发行版,例如 `{{< version >}}`。 ```yaml version: "3" @@ -103,11 +103,11 @@ services: environment: - USER_UID=1000 - USER_GID=1000 -+ - DB_TYPE=mysql -+ - DB_HOST=db:3306 -+ - DB_NAME=gitea -+ - DB_USER=gitea -+ - DB_PASSWD=gitea ++ - GITEA__database__DB_TYPE=mysql ++ - GITEA__database__HOST=db:3306 ++ - GITEA__database__NAME=gitea ++ - GITEA__database__USER=gitea ++ - GITEA__database__PASSWD=gitea restart: always networks: - gitea @@ -153,11 +153,11 @@ services: environment: - USER_UID=1000 - USER_GID=1000 -+ - DB_TYPE=postgres -+ - DB_HOST=db:5432 -+ - DB_NAME=gitea -+ - DB_USER=gitea -+ - DB_PASSWD=gitea ++ - GITEA__database__DB_TYPE=postgres ++ - GITEA__database__HOST=db:5432 ++ - GITEA__database__NAME=gitea ++ - GITEA__database__USER=gitea ++ - GITEA__database__PASSWD=gitea restart: always networks: - gitea @@ -276,6 +276,42 @@ docker-compose pull docker-compose up -d ``` +## 使用环境变量管理部署 + +除了上面的环境变量之外,`app.ini` 中的任何设置都可以使用以下形式的环境变量进行设置或覆盖:`GITEA__SECTION_NAME__KEY_NAME`。 每次 docker 容器启动时都会应用这些设置。 完整信息在[这里](https://github.com/go-gitea/gitea/tree/master/contrib/environment-to-ini)。 + +```bash +... +services: + server: + environment: + - GITEA__mailer__ENABLED=true + - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} + - GITEA__mailer__MAILER_TYPE=smtp + - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} + - GITEA__mailer__IS_TLS_ENABLED=true + - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} + - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" +``` + +Gitea 将为每次新安装自动生成新的 `SECRET_KEY` 并将它们写入 `app.ini`。 如果您想手动设置 `SECRET_KEY`,您可以使用以下 docker 命令来使用 Gitea 内置的[方法](https://docs.gitea.io/en-us/command-line/#generate)生成 `SECRET_KEY`。 安装后请妥善保管您的 `SECRET_KEY`,如若丢失则无法解密已加密的数据。 + +以下命令将向 `stdout` 输出一个新的 `SECRET_KEY` 和 `INTERNAL_TOKEN`,然后您可以将其放入环境变量中。 + +```bash +docker run -it --rm gitea/gitea:1 gitea generate secret SECRET_KEY +docker run -it --rm gitea/gitea:1 gitea generate secret INTERNAL_TOKEN +``` + +```yaml +... +services: + server: + environment: + - GITEA__security__SECRET_KEY=[value returned by generate secret SECRET_KEY] + - GITEA__security__INTERNAL_TOKEN=[value returned by generate secret INTERNAL_TOKEN] +``` + ## SSH 容器直通 由于 SSH 在容器内运行,因此,如果需要 SSH 支持,则需要将 SSH 从主机传递到容器。一种选择是在非标准端口上运行容器 SSH(或将主机端口移至非标准端口)。另一个可能更直接的选择是将 SSH 连接从主机转发到容器。下面将说明此设置。 diff --git a/docs/content/doc/packages/generic.en-us.md b/docs/content/doc/packages/generic.en-us.md index a82058da8ac5..dd0f5653fff8 100644 --- a/docs/content/doc/packages/generic.en-us.md +++ b/docs/content/doc/packages/generic.en-us.md @@ -27,7 +27,7 @@ To authenticate to the Package Registry, you need to provide [custom HTTP header ## Publish a package To publish a generic package perform a HTTP PUT operation with the package content in the request body. -You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first. +You cannot publish a file with the same name twice to a package. You must delete the existing package version first. ``` PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{file_name} @@ -36,9 +36,9 @@ PUT https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{packa | Parameter | Description | | ----------------- | ----------- | | `owner` | The owner of the package. | -| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). | -| `package_version` | The package version, a non-empty string. | -| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), or underscores (`_`). | +| `package_name` | The package name. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), pluses (`+`), or underscores (`_`). | +| `package_version` | The package version, a non-empty string without trailing or leading whitespaces. | +| `file_name` | The filename. It can contain only lowercase letters (`a-z`), uppercase letter (`A-Z`), numbers (`0-9`), dots (`.`), hyphens (`-`), pluses (`+`), or underscores (`_`). | Example request using HTTP Basic authentication: @@ -55,7 +55,8 @@ The server reponds with the following HTTP Status codes. | HTTP Status Code | Meaning | | ----------------- | ------- | | `201 Created` | The package has been published. | -| `400 Bad Request` | The package name and/or version are invalid or a package with the same name and version already exist. | +| `400 Bad Request` | The package name and/or version and/or file name are invalid. | +| `409 Conflict` | A file with the same name exist already in the package. | ## Download a package @@ -80,3 +81,67 @@ Example request using HTTP Basic authentication: curl --user your_username:your_token_or_password \ https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin ``` + +The server reponds with the following HTTP Status codes. + +| HTTP Status Code | Meaning | +| ----------------- | ------- | +| `200 OK` | Success | +| `404 Not Found` | The package or file was not found. | + +## Delete a package + +To delete a generic package perform a HTTP DELETE operation. This will delete all files of this version. + +``` +DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version} +``` + +| Parameter | Description | +| ----------------- | ----------- | +| `owner` | The owner of the package. | +| `package_name` | The package name. | +| `package_version` | The package version. | + +Example request using HTTP Basic authentication: + +```shell +curl --user your_username:your_token_or_password -X DELETE \ + https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0 +``` + +The server reponds with the following HTTP Status codes. + +| HTTP Status Code | Meaning | +| ----------------- | ------- | +| `204 No Content` | Success | +| `404 Not Found` | The package was not found. | + +## Delete a package file + +To delete a file of a generic package perform a HTTP DELETE operation. This will delete the package version too if there is no file left. + +``` +DELETE https://gitea.example.com/api/packages/{owner}/generic/{package_name}/{package_version}/{filename} +``` + +| Parameter | Description | +| ----------------- | ----------- | +| `owner` | The owner of the package. | +| `package_name` | The package name. | +| `package_version` | The package version. | +| `filename` | The filename. | + +Example request using HTTP Basic authentication: + +```shell +curl --user your_username:your_token_or_password -X DELETE \ + https://gitea.example.com/api/packages/testuser/generic/test_package/1.0.0/file.bin +``` + +The server reponds with the following HTTP Status codes. + +| HTTP Status Code | Meaning | +| ----------------- | ------- | +| `204 No Content` | Success | +| `404 Not Found` | The package or file was not found. | diff --git a/docs/content/doc/packages/maven.en-us.md b/docs/content/doc/packages/maven.en-us.md index 04ee488e4993..22da3c16d294 100644 --- a/docs/content/doc/packages/maven.en-us.md +++ b/docs/content/doc/packages/maven.en-us.md @@ -81,6 +81,16 @@ To publish a package simply run: mvn deploy ``` +If you want to publish a prebuild package to the registry, you can use [`mvn deploy:deploy-file`](https://maven.apache.org/plugins/maven-deploy-plugin/deploy-file-mojo.html): + +```shell +mvn deploy:deploy-file -Durl=https://gitea.example.com/api/packages/{owner}/maven -DrepositoryId=gitea -Dfile=/path/to/package.jar +``` + +| Parameter | Description | +| -------------- | ----------- | +| `owner` | The owner of the package. | + You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first. ## Install a package diff --git a/docs/content/doc/packages/npm.en-us.md b/docs/content/doc/packages/npm.en-us.md index 9ab4ac900cfb..122f306ee5e3 100644 --- a/docs/content/doc/packages/npm.en-us.md +++ b/docs/content/doc/packages/npm.en-us.md @@ -67,6 +67,26 @@ npm publish You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first. +## Unpublish a package + +Delete a package by running the following command: + +```shell +npm unpublish {package_name}[@{package_version}] +``` + +| Parameter | Description | +| ----------------- | ----------- | +| `package_name` | The package name. | +| `package_version` | The package version. | + +For example: + +```shell +npm unpublish @test/test_package +npm unpublish @test/test_package@1.0.0 +``` + ## Install a package To install a package from the package registry, execute the following command: @@ -113,6 +133,7 @@ The tag name must not be a valid version. All tag names which are parsable as a npm install npm ci npm publish +npm unpublish npm dist-tag npm view ``` diff --git a/docs/content/doc/packages/nuget.en-us.md b/docs/content/doc/packages/nuget.en-us.md index a4435fa99f01..6c8aaa70af1d 100644 --- a/docs/content/doc/packages/nuget.en-us.md +++ b/docs/content/doc/packages/nuget.en-us.md @@ -47,6 +47,8 @@ For example: dotnet nuget add source --name gitea --username testuser --password password123 https://gitea.example.com/api/packages/testuser/nuget/index.json ``` +You can add the source without credentials and use the [`--api-key`](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-nuget-push) parameter when publishing packages. In this case you need to provide a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). + ## Publish a package Publish a package by running the following command: diff --git a/docs/content/doc/packages/overview.en-us.md b/docs/content/doc/packages/overview.en-us.md index 81575b9ade7c..5e03b710170f 100644 --- a/docs/content/doc/packages/overview.en-us.md +++ b/docs/content/doc/packages/overview.en-us.md @@ -34,6 +34,7 @@ The following package managers are currently supported: | [Maven]({{< relref "doc/packages/maven.en-us.md" >}}) | Java | `mvn`, `gradle` | | [npm]({{< relref "doc/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn` | | [NuGet]({{< relref "doc/packages/nuget.en-us.md" >}}) | .NET | `nuget` | +| [Pub]({{< relref "doc/packages/pub.en-us.md" >}}) | Dart | `dart`, `flutter` | | [PyPI]({{< relref "doc/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` | | [RubyGems]({{< relref "doc/packages/rubygems.en-us.md" >}}) | Ruby | `gem`, `Bundler` | diff --git a/docs/content/doc/packages/pub.en-us.md b/docs/content/doc/packages/pub.en-us.md new file mode 100644 index 000000000000..4d3766220833 --- /dev/null +++ b/docs/content/doc/packages/pub.en-us.md @@ -0,0 +1,83 @@ +--- +date: "2022-07-31T00:00:00+00:00" +title: "Pub Packages Repository" +slug: "packages/pub" +draft: false +toc: false +menu: + sidebar: + parent: "packages" + name: "Pub" + weight: 90 + identifier: "pub" +--- + +# Pub Packages Repository + +Publish [Pub](https://dart.dev/guides/packages) packages for your user or organization. + +**Table of Contents** + +{{< toc >}} + +## Requirements + +To work with the Pub package registry, you need to use the tools [dart](https://dart.dev/tools/dart-tool) and/or [flutter](https://docs.flutter.dev/reference/flutter-cli). + +The following examples use dart. + +## Configuring the package registry + +To register the package registry and provide credentials, execute: + +```shell +dart pub token add https://gitea.example.com/api/packages/{owner}/pub +``` + +| Placeholder | Description | +| ------------ | ----------- | +| `owner` | The owner of the package. | + +You need to provide your [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}). + +## Publish a package + +To publish a package, edit the `pubspec.yaml` and add the following line: + +```yaml +publish_to: https://gitea.example.com/api/packages/{owner}/pub +``` + +| Placeholder | Description | +| ------------ | ----------- | +| `owner` | The owner of the package. | + +Now you can publish the package by running the following command: + +```shell +dart pub publish +``` + +You cannot publish a package if a package of the same name and version already exists. You must delete the existing package first. + +## Install a package + +To install a Pub package from the package registry, execute the following command: + +```shell +dart pub add {package_name} --hosted-url=https://gitea.example.com/api/packages/{owner}/pub/ +``` + +| Parameter | Description | +| ----------------- | ----------- | +| `owner` | The owner of the package. | +| `package_name` | The package name. | + +For example: + +```shell +# use latest version +dart pub add mypackage --hosted-url=https://gitea.example.com/api/packages/testuser/pub/ +# specify version +dart pub add mypackage:1.0.8 --hosted-url=https://gitea.example.com/api/packages/testuser/pub/ +``` diff --git a/docs/content/doc/packages/pypi.en-us.md b/docs/content/doc/packages/pypi.en-us.md index af17fe83101c..588df71d60c2 100644 --- a/docs/content/doc/packages/pypi.en-us.md +++ b/docs/content/doc/packages/pypi.en-us.md @@ -8,7 +8,7 @@ menu: sidebar: parent: "packages" name: "PyPI" - weight: 90 + weight: 100 identifier: "pypi" --- diff --git a/docs/content/doc/packages/rubygems.en-us.md b/docs/content/doc/packages/rubygems.en-us.md index dd7ac9ee7ed0..d4ae30bbcecc 100644 --- a/docs/content/doc/packages/rubygems.en-us.md +++ b/docs/content/doc/packages/rubygems.en-us.md @@ -8,7 +8,7 @@ menu: sidebar: parent: "packages" name: "RubyGems" - weight: 100 + weight: 110 identifier: "rubygems" --- diff --git a/docs/content/doc/upgrade/from-gitea.en-us.md b/docs/content/doc/upgrade/from-gitea.en-us.md index f5c9551f31d2..0d22a32439c8 100644 --- a/docs/content/doc/upgrade/from-gitea.en-us.md +++ b/docs/content/doc/upgrade/from-gitea.en-us.md @@ -23,6 +23,12 @@ To update Gitea, download a newer version, stop the old one, perform a backup, a Every time a Gitea instance starts up, it checks whether a database migration should be run. If a database migration is required, Gitea will take some time to complete the upgrade and then serve. +## Check the Changelog for breaking changes + +To make Gitea better, some breaking changes are unavoidable, especially for big milestone releases. +Before upgrade, please read the [Changelog on Gitea blog](https://blog.gitea.io/) +and check whether the breaking changes affect your Gitea instance. + ## Backup for downgrade Gitea keeps compatibility for patch versions whose first two fields are the same (`a.b.x` -> `a.b.y`), diff --git a/docs/layouts/doc/search.html b/docs/layouts/doc/search.html index 736fcaee106f..90fe96fe5d9c 100644 --- a/docs/layouts/doc/search.html +++ b/docs/layouts/doc/search.html @@ -11,12 +11,6 @@
-
- -
-
diff --git a/go.mod b/go.mod index 6d41af507d35..fa6fb911db1a 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b code.gitea.io/sdk/gitea v0.15.1 + codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222 gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb gitea.com/go-chi/cache v0.2.0 gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 diff --git a/go.sum b/go.sum index 124e65a727ad..7f7ed7fe2d3e 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,8 @@ code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b/go.mod h1:zcNbT/aJE code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= +codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222 h1:PCW4i+gnQ9XxF8V+nBch3KWdGe4MiP3xXUCA/z0jhHk= +codeberg.org/gusted/mcaptcha v0.0.0-20220722211632-55c1ffff1222/go.mod h1:IIAjsijsd8q1isWX8MACefDEgTQslQ4stk2AeeTt3kM= contrib.go.opencensus.io/exporter/aws v0.0.0-20181029163544-2befc13012d0/go.mod h1:uu1P0UCM/6RbsMrgPa98ll8ZcHM858i/AD06a9aLRCA= contrib.go.opencensus.io/exporter/ocagent v0.5.0/go.mod h1:ImxhfLRpxoYiSq891pBrLVhN+qmP8BTVvdH2YLs7Gl0= contrib.go.opencensus.io/exporter/stackdriver v0.12.1/go.mod h1:iwB6wGarfphGGe/e5CWqyUk/cLzKnWsOKPVW3no6OTw= diff --git a/integrations/admin_user_test.go b/integrations/admin_user_test.go index a2020652b747..2225c903df9c 100644 --- a/integrations/admin_user_test.go +++ b/integrations/admin_user_test.go @@ -61,7 +61,7 @@ func makeRequest(t *testing.T, formData user_model.User, headerCode int) { }) session.MakeRequest(t, req, headerCode) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: formData.ID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: formData.ID}) assert.Equal(t, formData.Name, user.Name) assert.Equal(t, formData.LoginName, user.LoginName) assert.Equal(t, formData.Email, user.Email) diff --git a/integrations/api_admin_test.go b/integrations/api_admin_test.go index 62c7d7eaf7d3..e32b86684472 100644 --- a/integrations/api_admin_test.go +++ b/integrations/api_admin_test.go @@ -22,7 +22,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) { defer prepareTestEnv(t)() // user1 is an admin user session := loginUser(t, "user1") - keyOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}).(*user_model.User) + keyOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}) token := getTokenForLoggedInUser(t, session) urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token) @@ -194,7 +194,7 @@ func TestAPIEditUser(t *testing.T) { json.Unmarshal(resp.Body.Bytes(), &errMap) assert.EqualValues(t, "email is not allowed to be empty string", errMap["message"].(string)) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) assert.False(t, user2.IsRestricted) bTrue := true req = NewRequestWithJSON(t, "PATCH", urlStr, api.EditUserOption{ @@ -205,6 +205,6 @@ func TestAPIEditUser(t *testing.T) { Restricted: &bTrue, }) session.MakeRequest(t, req, http.StatusOK) - user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}).(*user_model.User) + user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{LoginName: "user2"}) assert.True(t, user2.IsRestricted) } diff --git a/integrations/api_comment_test.go b/integrations/api_comment_test.go index 7dcc0279fc2f..ac1079b02de0 100644 --- a/integrations/api_comment_test.go +++ b/integrations/api_comment_test.go @@ -24,10 +24,10 @@ func TestAPIListRepoComments(t *testing.T) { defer prepareTestEnv(t)() comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{}, - unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + unittest.Cond("type = ?", issues_model.CommentTypeComment)) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments", repoOwner.Name, repo.Name)) @@ -70,10 +70,10 @@ func TestAPIListIssueComments(t *testing.T) { defer prepareTestEnv(t)() comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{}, - unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + unittest.Cond("type = ?", issues_model.CommentTypeComment)) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues/%d/comments", @@ -91,9 +91,9 @@ func TestAPICreateComment(t *testing.T) { defer prepareTestEnv(t)() const commentBody = "Comment body" - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -113,10 +113,10 @@ func TestAPICreateComment(t *testing.T) { func TestAPIGetComment(t *testing.T) { defer prepareTestEnv(t)() - comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}).(*issues_model.Comment) + comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}) assert.NoError(t, comment.LoadIssue()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: comment.Issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -142,10 +142,10 @@ func TestAPIEditComment(t *testing.T) { const newCommentBody = "This is the new comment body" comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{}, - unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + unittest.Cond("type = ?", issues_model.CommentTypeComment)) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -167,10 +167,10 @@ func TestAPIDeleteComment(t *testing.T) { defer prepareTestEnv(t)() comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{}, - unittest.Cond("type = ?", issues_model.CommentTypeComment)).(*issues_model.Comment) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + unittest.Cond("type = ?", issues_model.CommentTypeComment)) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: comment.IssueID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -185,9 +185,9 @@ func TestAPIListIssueTimeline(t *testing.T) { defer prepareTestEnv(t)() // load comment - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) // make request session := loginUser(t, repoOwner.Name) diff --git a/integrations/api_issue_label_test.go b/integrations/api_issue_label_test.go index 9b6333b2a268..9d9fdcfbc30c 100644 --- a/integrations/api_issue_label_test.go +++ b/integrations/api_issue_label_test.go @@ -22,8 +22,8 @@ import ( func TestAPIModifyLabels(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/labels?token=%s", owner.Name, repo.Name, token) @@ -37,7 +37,7 @@ func TestAPIModifyLabels(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusCreated) apiLabel := new(api.Label) DecodeJSON(t, resp, &apiLabel) - dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, RepoID: repo.ID}).(*issues_model.Label) + dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, RepoID: repo.ID}) assert.EqualValues(t, dbLabel.Name, apiLabel.Name) assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color) @@ -91,10 +91,10 @@ func TestAPIModifyLabels(t *testing.T) { func TestAPIAddIssueLabels(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}).(*issues_model.Issue) - _ = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID, ID: 2}).(*issues_model.Label) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}) + _ = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID, ID: 2}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -114,10 +114,10 @@ func TestAPIAddIssueLabels(t *testing.T) { func TestAPIReplaceIssueLabels(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}).(*issues_model.Issue) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID}).(*issues_model.Label) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repo.ID}) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{RepoID: repo.ID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -140,8 +140,8 @@ func TestAPIReplaceIssueLabels(t *testing.T) { func TestAPIModifyOrgLabels(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) user := "user1" session := loginUser(t, user) token := getTokenForLoggedInUser(t, session) @@ -156,7 +156,7 @@ func TestAPIModifyOrgLabels(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusCreated) apiLabel := new(api.Label) DecodeJSON(t, resp, &apiLabel) - dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, OrgID: owner.ID}).(*issues_model.Label) + dbLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: apiLabel.ID, OrgID: owner.ID}) assert.EqualValues(t, dbLabel.Name, apiLabel.Name) assert.EqualValues(t, strings.TrimLeft(dbLabel.Color, "#"), apiLabel.Color) diff --git a/integrations/api_issue_milestone_test.go b/integrations/api_issue_milestone_test.go index a7f89721a5e8..ba97c99b9dd8 100644 --- a/integrations/api_issue_milestone_test.go +++ b/integrations/api_issue_milestone_test.go @@ -21,9 +21,9 @@ import ( func TestAPIIssuesMilestone(t *testing.T) { defer prepareTestEnv(t)() - milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: milestone.RepoID}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: milestone.RepoID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) assert.Equal(t, int64(1), int64(milestone.NumIssues)) assert.Equal(t, structs.StateOpen, milestone.State()) diff --git a/integrations/api_issue_reaction_test.go b/integrations/api_issue_reaction_test.go index 3834af213097..ca6b69721ce2 100644 --- a/integrations/api_issue_reaction_test.go +++ b/integrations/api_issue_reaction_test.go @@ -23,14 +23,14 @@ import ( func TestAPIIssuesReactions(t *testing.T) { defer prepareTestEnv(t)() - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) _ = issue.LoadRepo(db.DefaultContext) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/reactions?token=%s", owner.Name, issue.Repo.Name, issue.Index, token) @@ -80,17 +80,17 @@ func TestAPIIssuesReactions(t *testing.T) { func TestAPICommentReactions(t *testing.T) { defer prepareTestEnv(t)() - comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}).(*issues_model.Comment) + comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2}) _ = comment.LoadIssue() issue := comment.Issue _ = issue.LoadRepo(db.DefaultContext) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d/reactions?token=%s", owner.Name, issue.Repo.Name, comment.ID, token) diff --git a/integrations/api_issue_stopwatch_test.go b/integrations/api_issue_stopwatch_test.go index b4e5f90543a3..052a1ad9fc9b 100644 --- a/integrations/api_issue_stopwatch_test.go +++ b/integrations/api_issue_stopwatch_test.go @@ -21,8 +21,8 @@ import ( func TestAPIListStopWatches(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -30,8 +30,8 @@ func TestAPIListStopWatches(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) var apiWatches []*api.StopWatch DecodeJSON(t, resp, &apiWatches) - stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID}).(*issues_model.Stopwatch) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID}).(*issues_model.Issue) + stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID}) if assert.Len(t, apiWatches, 1) { assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix()) assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex) @@ -45,10 +45,10 @@ func TestAPIListStopWatches(t *testing.T) { func TestAPIStopStopWatches(t *testing.T) { defer prepareTestEnv(t)() - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) _ = issue.LoadRepo(db.DefaultContext) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -61,10 +61,10 @@ func TestAPIStopStopWatches(t *testing.T) { func TestAPICancelStopWatches(t *testing.T) { defer prepareTestEnv(t)() - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) _ = issue.LoadRepo(db.DefaultContext) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -77,10 +77,10 @@ func TestAPICancelStopWatches(t *testing.T) { func TestAPIStartStopWatches(t *testing.T) { defer prepareTestEnv(t)() - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) _ = issue.LoadRepo(db.DefaultContext) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_issue_subscription_test.go b/integrations/api_issue_subscription_test.go index 2c6cddcab9e7..db3d1694d650 100644 --- a/integrations/api_issue_subscription_test.go +++ b/integrations/api_issue_subscription_test.go @@ -21,19 +21,19 @@ import ( func TestAPIIssueSubscriptions(t *testing.T) { defer prepareTestEnv(t)() - issue1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) - issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) - issue3 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue) - issue4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue) - issue5 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 8}).(*issues_model.Issue) + issue1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + issue3 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) + issue4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}) + issue5 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 8}) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue1.PosterID}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue1.PosterID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) testSubscription := func(issue *issues_model.Issue, isWatching bool) { - issueRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) + issueRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/check?token=%s", issueRepo.OwnerName, issueRepo.Name, issue.Index, token) req := NewRequest(t, "GET", urlStr) @@ -54,7 +54,7 @@ func TestAPIIssueSubscriptions(t *testing.T) { testSubscription(issue4, false) testSubscription(issue5, false) - issue1Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue1.RepoID}).(*repo_model.Repository) + issue1Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue1.RepoID}) urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/%s?token=%s", issue1Repo.OwnerName, issue1Repo.Name, issue1.Index, owner.Name, token) req := NewRequest(t, "DELETE", urlStr) session.MakeRequest(t, req, http.StatusCreated) @@ -64,7 +64,7 @@ func TestAPIIssueSubscriptions(t *testing.T) { session.MakeRequest(t, req, http.StatusOK) testSubscription(issue1, false) - issue5Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue5.RepoID}).(*repo_model.Repository) + issue5Repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue5.RepoID}) urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/subscriptions/%s?token=%s", issue5Repo.OwnerName, issue5Repo.Name, issue5.Index, owner.Name, token) req = NewRequest(t, "PUT", urlStr) session.MakeRequest(t, req, http.StatusCreated) diff --git a/integrations/api_issue_test.go b/integrations/api_issue_test.go index 5c802e8d20df..afb2f75c15fb 100644 --- a/integrations/api_issue_test.go +++ b/integrations/api_issue_test.go @@ -16,6 +16,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -24,8 +25,8 @@ import ( func TestAPIListIssues(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -75,8 +76,8 @@ func TestAPICreateIssue(t *testing.T) { defer prepareTestEnv(t)() const body, title = "apiTestBody", "apiTestTitle" - repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -99,7 +100,7 @@ func TestAPICreateIssue(t *testing.T) { Title: title, }) - repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Equal(t, repoBefore.NumIssues+1, repoAfter.NumIssues) assert.Equal(t, repoBefore.NumClosedIssues, repoAfter.NumClosedIssues) } @@ -107,9 +108,9 @@ func TestAPICreateIssue(t *testing.T) { func TestAPIEditIssue(t *testing.T) { defer prepareTestEnv(t)() - issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue) - repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext)) assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) assert.Equal(t, api.StateOpen, issueBefore.State()) @@ -138,8 +139,8 @@ func TestAPIEditIssue(t *testing.T) { var apiIssue api.Issue DecodeJSON(t, resp, &apiIssue) - issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue) - repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository) + issueAfter := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) + repoAfter := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) // check deleted user assert.Equal(t, int64(500), issueAfter.PosterID) @@ -171,19 +172,21 @@ func TestAPISearchIssues(t *testing.T) { token := getUserToken(t, "user2") + // as this API was used in the frontend, it uses UI page size + expectedIssueCount := 15 // from the fixtures + if expectedIssueCount > setting.UI.IssuePagingNum { + expectedIssueCount = setting.UI.IssuePagingNum + } + link, _ := url.Parse("/api/v1/repos/issues/search") - req := NewRequest(t, "GET", link.String()+"?token="+token) - resp := MakeRequest(t, req, http.StatusOK) + query := url.Values{"token": {getUserToken(t, "user1")}} var apiIssues []*api.Issue - DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 10) - query := url.Values{"token": {token}} link.RawQuery = query.Encode() - req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + req := NewRequest(t, "GET", link.String()) + resp := MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 10) + assert.Len(t, apiIssues, expectedIssueCount) since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801 before := time.Unix(999307200, 0).Format(time.RFC3339) @@ -211,14 +214,15 @@ func TestAPISearchIssues(t *testing.T) { resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count")) - assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit + assert.Len(t, apiIssues, 17) - query.Add("limit", "20") + query.Add("limit", "10") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 17) + assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count")) + assert.Len(t, apiIssues, 10) query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}} link.RawQuery = query.Encode() @@ -266,23 +270,21 @@ func TestAPISearchIssues(t *testing.T) { func TestAPISearchIssuesWithLabels(t *testing.T) { defer prepareTestEnv(t)() - token := getUserToken(t, "user1") + // as this API was used in the frontend, it uses UI page size + expectedIssueCount := 15 // from the fixtures + if expectedIssueCount > setting.UI.IssuePagingNum { + expectedIssueCount = setting.UI.IssuePagingNum + } link, _ := url.Parse("/api/v1/repos/issues/search") - req := NewRequest(t, "GET", link.String()+"?token="+token) - resp := MakeRequest(t, req, http.StatusOK) + query := url.Values{"token": {getUserToken(t, "user1")}} var apiIssues []*api.Issue - DecodeJSON(t, resp, &apiIssues) - - assert.Len(t, apiIssues, 10) - query := url.Values{} - query.Add("token", token) link.RawQuery = query.Encode() - req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + req := NewRequest(t, "GET", link.String()) + resp := MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 10) + assert.Len(t, apiIssues, expectedIssueCount) query.Add("labels", "label1") link.RawQuery = query.Encode() diff --git a/integrations/api_issue_tracked_time_test.go b/integrations/api_issue_tracked_time_test.go index a6846cb78651..504aacf000d7 100644 --- a/integrations/api_issue_tracked_time_test.go +++ b/integrations/api_issue_tracked_time_test.go @@ -22,8 +22,8 @@ import ( func TestAPIGetTrackedTimes(t *testing.T) { defer prepareTestEnv(t)() - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) assert.NoError(t, issue2.LoadRepo(db.DefaultContext)) session := loginUser(t, user2.Name) @@ -64,10 +64,10 @@ func TestAPIGetTrackedTimes(t *testing.T) { func TestAPIDeleteTrackedTime(t *testing.T) { defer prepareTestEnv(t)() - time6 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 6}).(*issues_model.TrackedTime) - issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) + time6 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 6}) + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) assert.NoError(t, issue2.LoadRepo(db.DefaultContext)) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) @@ -76,7 +76,7 @@ func TestAPIDeleteTrackedTime(t *testing.T) { req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time6.ID, token) session.MakeRequest(t, req, http.StatusForbidden) - time3 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 3}).(*issues_model.TrackedTime) + time3 := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{ID: 3}) req = NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/%d/times/%d?token=%s", user2.Name, issue2.Repo.Name, issue2.Index, time3.ID, token) session.MakeRequest(t, req, http.StatusNoContent) // Delete non existing time @@ -99,10 +99,10 @@ func TestAPIDeleteTrackedTime(t *testing.T) { func TestAPIAddTrackedTimes(t *testing.T) { defer prepareTestEnv(t)() - issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) + issue2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) assert.NoError(t, issue2.LoadRepo(db.DefaultContext)) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session := loginUser(t, admin.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_keys_test.go b/integrations/api_keys_test.go index 198da29b8a10..76d1122086b1 100644 --- a/integrations/api_keys_test.go +++ b/integrations/api_keys_test.go @@ -49,8 +49,8 @@ func TestDeleteDeployKeyNoLogin(t *testing.T) { func TestCreateReadOnlyDeployKey(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -75,8 +75,8 @@ func TestCreateReadOnlyDeployKey(t *testing.T) { func TestCreateReadWriteDeployKey(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: "repo1"}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -100,7 +100,7 @@ func TestCreateReadWriteDeployKey(t *testing.T) { func TestCreateUserKey(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}) session := loginUser(t, "user1") token := url.QueryEscape(getTokenForLoggedInUser(t, session)) diff --git a/integrations/api_notification_test.go b/integrations/api_notification_test.go index 4bf18632ca07..ad6a8af0a54e 100644 --- a/integrations/api_notification_test.go +++ b/integrations/api_notification_test.go @@ -21,9 +21,9 @@ import ( func TestAPINotification(t *testing.T) { defer prepareTestEnv(t)() - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - thread5 := unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + thread5 := unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}) assert.NoError(t, thread5.LoadAttributes()) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) @@ -127,7 +127,7 @@ func TestAPINotification(t *testing.T) { session.MakeRequest(t, req, http.StatusResetContent) assert.Equal(t, models.NotificationStatusUnread, thread5.Status) - thread5 = unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification) + thread5 = unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}) assert.Equal(t, models.NotificationStatusRead, thread5.Status) // -- check notifications -- @@ -140,8 +140,8 @@ func TestAPINotification(t *testing.T) { func TestAPINotificationPUT(t *testing.T) { defer prepareTestEnv(t)() - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - thread5 := unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + thread5 := unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}) assert.NoError(t, thread5.LoadAttributes()) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_oauth2_apps_test.go b/integrations/api_oauth2_apps_test.go index 2c08338b25b9..4eead582d148 100644 --- a/integrations/api_oauth2_apps_test.go +++ b/integrations/api_oauth2_apps_test.go @@ -27,7 +27,7 @@ func TestOAuth2Application(t *testing.T) { } func testAPICreateOAuth2Application(t *testing.T) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) appBody := api.CreateOAuth2ApplicationOptions{ Name: "test-app-1", RedirectURIs: []string{ @@ -51,7 +51,7 @@ func testAPICreateOAuth2Application(t *testing.T) { } func testAPIListOAuth2Applications(t *testing.T) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -61,7 +61,7 @@ func testAPIListOAuth2Applications(t *testing.T) { RedirectURIs: []string{ "http://www.google.com", }, - }).(*auth.OAuth2Application) + }) urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2?token=%s", token) req := NewRequest(t, "GET", urlStr) @@ -80,14 +80,14 @@ func testAPIListOAuth2Applications(t *testing.T) { } func testAPIDeleteOAuth2Application(t *testing.T) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) oldApp := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ UID: user.ID, Name: "test-app-1", - }).(*auth.OAuth2Application) + }) urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", oldApp.ID, token) req := NewRequest(t, "DELETE", urlStr) @@ -101,7 +101,7 @@ func testAPIDeleteOAuth2Application(t *testing.T) { } func testAPIGetOAuth2Application(t *testing.T) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -111,7 +111,7 @@ func testAPIGetOAuth2Application(t *testing.T) { RedirectURIs: []string{ "http://www.google.com", }, - }).(*auth.OAuth2Application) + }) urlStr := fmt.Sprintf("/api/v1/user/applications/oauth2/%d?token=%s", existApp.ID, token) req := NewRequest(t, "GET", urlStr) @@ -131,7 +131,7 @@ func testAPIGetOAuth2Application(t *testing.T) { } func testAPIUpdateOAuth2Application(t *testing.T) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) existApp := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ UID: user.ID, @@ -139,7 +139,7 @@ func testAPIUpdateOAuth2Application(t *testing.T) { RedirectURIs: []string{ "http://www.google.com", }, - }).(*auth.OAuth2Application) + }) appBody := api.CreateOAuth2ApplicationOptions{ Name: "test-app-1", diff --git a/integrations/api_packages_composer_test.go b/integrations/api_packages_composer_test.go index 59b975408dfb..7c58ae62be6a 100644 --- a/integrations/api_packages_composer_test.go +++ b/integrations/api_packages_composer_test.go @@ -25,7 +25,7 @@ import ( func TestPackageComposer(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) vendorName := "gitea" projectName := "composer-package" diff --git a/integrations/api_packages_conan_test.go b/integrations/api_packages_conan_test.go index 65d16801fc59..e14555d1d03d 100644 --- a/integrations/api_packages_conan_test.go +++ b/integrations/api_packages_conan_test.go @@ -205,7 +205,7 @@ func uploadConanPackageV2(t *testing.T, baseURL, token, name, version, user, cha func TestPackageConan(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) name := "ConanPackage" version1 := "1.2" diff --git a/integrations/api_packages_container_test.go b/integrations/api_packages_container_test.go index 5e073f313f7a..c62ab5dbb882 100644 --- a/integrations/api_packages_container_test.go +++ b/integrations/api_packages_container_test.go @@ -28,7 +28,7 @@ import ( func TestPackageContainer(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) has := func(l packages_model.PackagePropertyList, name string) bool { for _, pp := range l { @@ -276,11 +276,23 @@ func TestPackageContainer(t *testing.T) { } } - // Overwrite existing tag + req = NewRequest(t, "GET", fmt.Sprintf("%s/manifests/%s", url, tag)) + addTokenAuthHeader(req, userToken) + MakeRequest(t, req, http.StatusOK) + + pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag) + assert.NoError(t, err) + assert.EqualValues(t, 1, pv.DownloadCount) + + // Overwrite existing tag should keep the download count req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/manifests/%s", url, tag), strings.NewReader(manifestContent)) addTokenAuthHeader(req, userToken) req.Header.Set("Content-Type", oci.MediaTypeDockerManifest) MakeRequest(t, req, http.StatusCreated) + + pv, err = packages_model.GetVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, image, tag) + assert.NoError(t, err) + assert.EqualValues(t, 1, pv.DownloadCount) }) t.Run("HeadManifest", func(t *testing.T) { diff --git a/integrations/api_packages_generic_test.go b/integrations/api_packages_generic_test.go index adaf99e981ae..f2aff8ed240c 100644 --- a/integrations/api_packages_generic_test.go +++ b/integrations/api_packages_generic_test.go @@ -20,19 +20,19 @@ import ( func TestPackageGeneric(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) packageName := "te-st_pac.kage" - packageVersion := "1.0.3" + packageVersion := "1.0.3-te st" filename := "fi-le_na.me" content := []byte{1, 2, 3} - url := fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, filename) + url := fmt.Sprintf("/api/packages/%s/generic/%s/%s", user.Name, packageName, packageVersion) t.Run("Upload", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) + req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) AddBasicAuthHeader(req, user.Name) MakeRequest(t, req, http.StatusCreated) @@ -55,54 +55,139 @@ func TestPackageGeneric(t *testing.T) { pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID) assert.NoError(t, err) assert.Equal(t, int64(len(content)), pb.Size) - }) - t.Run("UploadExists", func(t *testing.T) { - defer PrintCurrentTest(t)() + t.Run("Exists", func(t *testing.T) { + defer PrintCurrentTest(t)() - req := NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusBadRequest) + req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusConflict) + }) + + t.Run("Additional", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "PUT", url+"/dummy.bin", bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusCreated) + + // Check deduplication + pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) + assert.NoError(t, err) + assert.Len(t, pfs, 2) + assert.Equal(t, pfs[0].BlobID, pfs[1].BlobID) + }) + + t.Run("InvalidParameter", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, "invalid+package name", packageVersion, filename), bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, "%20test ", filename), bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + + req = NewRequestWithBody(t, "PUT", fmt.Sprintf("/api/packages/%s/generic/%s/%s/%s", user.Name, packageName, packageVersion, "inval+id.na me"), bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusBadRequest) + }) }) t.Run("Download", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequest(t, "GET", url) + checkDownloadCount := func(count int64) { + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + assert.Equal(t, count, pvs[0].DownloadCount) + } + + checkDownloadCount(0) + + req := NewRequest(t, "GET", url+"/"+filename) resp := MakeRequest(t, req, http.StatusOK) assert.Equal(t, content, resp.Body.Bytes()) - pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) - assert.NoError(t, err) - assert.Len(t, pvs, 1) - assert.Equal(t, int64(1), pvs[0].DownloadCount) + checkDownloadCount(1) + + req = NewRequest(t, "GET", url+"/dummy.bin") + MakeRequest(t, req, http.StatusOK) + + checkDownloadCount(2) + + t.Run("NotExists", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequest(t, "GET", url+"/not.found") + MakeRequest(t, req, http.StatusNotFound) + }) }) t.Run("Delete", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequest(t, "DELETE", url) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusOK) + t.Run("File", func(t *testing.T) { + defer PrintCurrentTest(t)() - pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) - assert.NoError(t, err) - assert.Empty(t, pvs) - }) + req := NewRequest(t, "DELETE", url+"/"+filename) + MakeRequest(t, req, http.StatusUnauthorized) - t.Run("DownloadNotExists", func(t *testing.T) { - defer PrintCurrentTest(t)() + req = NewRequest(t, "DELETE", url+"/"+filename) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNoContent) - req := NewRequest(t, "GET", url) - MakeRequest(t, req, http.StatusNotFound) - }) + req = NewRequest(t, "GET", url+"/"+filename) + MakeRequest(t, req, http.StatusNotFound) - t.Run("DeleteNotExists", func(t *testing.T) { - defer PrintCurrentTest(t)() + req = NewRequest(t, "DELETE", url+"/"+filename) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNotFound) - req := NewRequest(t, "DELETE", url) - AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusNotFound) + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + + t.Run("RemovesVersion", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req = NewRequest(t, "DELETE", url+"/dummy.bin") + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNoContent) + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Empty(t, pvs) + }) + }) + + t.Run("Version", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "PUT", url+"/"+filename, bytes.NewReader(content)) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusCreated) + + req = NewRequest(t, "DELETE", url) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequest(t, "DELETE", url) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNoContent) + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeGeneric) + assert.NoError(t, err) + assert.Empty(t, pvs) + + req = NewRequest(t, "GET", url+"/"+filename) + MakeRequest(t, req, http.StatusNotFound) + + req = NewRequest(t, "DELETE", url) + AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusNotFound) + }) }) } diff --git a/integrations/api_packages_helm_test.go b/integrations/api_packages_helm_test.go index fcf5d2f7622c..8ea5e8a7b09f 100644 --- a/integrations/api_packages_helm_test.go +++ b/integrations/api_packages_helm_test.go @@ -26,7 +26,7 @@ import ( func TestPackageHelm(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) packageName := "test-chart" packageVersion := "1.0.3" diff --git a/integrations/api_packages_maven_test.go b/integrations/api_packages_maven_test.go index c7c45426859e..512039b6a567 100644 --- a/integrations/api_packages_maven_test.go +++ b/integrations/api_packages_maven_test.go @@ -21,7 +21,7 @@ import ( func TestPackageMaven(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) groupID := "com.gitea" artifactID := "test-project" @@ -42,6 +42,7 @@ func TestPackageMaven(t *testing.T) { defer PrintCurrentTest(t)() putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusCreated) + putFile(t, fmt.Sprintf("/%s/%s", packageVersion, filename), "test", http.StatusBadRequest) putFile(t, "/maven-metadata.xml", "test", http.StatusOK) pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeMaven) @@ -135,12 +136,14 @@ func TestPackageMaven(t *testing.T) { pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) assert.NoError(t, err) assert.Len(t, pfs, 2) - i := 0 - if strings.HasSuffix(pfs[1].Name, ".pom") { - i = 1 + for _, pf := range pfs { + if strings.HasSuffix(pf.Name, ".pom") { + assert.Equal(t, filename+".pom", pf.Name) + assert.True(t, pf.IsLead) + } else { + assert.False(t, pf.IsLead) + } } - assert.Equal(t, filename+".pom", pfs[i].Name) - assert.True(t, pfs[i].IsLead) }) t.Run("DownloadPOM", func(t *testing.T) { @@ -202,4 +205,13 @@ func TestPackageMaven(t *testing.T) { assert.Equal(t, checksum, resp.Body.String()) } }) + + t.Run("UploadSnapshot", func(t *testing.T) { + snapshotVersion := packageVersion + "-SNAPSHOT" + + putFile(t, fmt.Sprintf("/%s/%s", snapshotVersion, filename), "test", http.StatusCreated) + putFile(t, "/maven-metadata.xml", "test", http.StatusOK) + putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test", http.StatusCreated) + putFile(t, fmt.Sprintf("/%s/maven-metadata.xml", snapshotVersion), "test-overwrite", http.StatusCreated) + }) } diff --git a/integrations/api_packages_npm_test.go b/integrations/api_packages_npm_test.go index ad88ac5da676..8b22ead6d99f 100644 --- a/integrations/api_packages_npm_test.go +++ b/integrations/api_packages_npm_test.go @@ -24,7 +24,7 @@ import ( func TestPackageNpm(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) token := fmt.Sprintf("Bearer %s", getTokenForLoggedInUser(t, loginUser(t, user.Name))) @@ -36,33 +36,36 @@ func TestPackageNpm(t *testing.T) { packageDescription := "Test Description" data := "H4sIAAAAAAAA/ytITM5OTE/VL4DQelnF+XkMVAYGBgZmJiYK2MRBwNDcSIHB2NTMwNDQzMwAqA7IMDUxA9LUdgg2UFpcklgEdAql5kD8ogCnhwio5lJQUMpLzE1VslJQcihOzi9I1S9JLS7RhSYIJR2QgrLUouLM/DyQGkM9Az1D3YIiqExKanFyUWZBCVQ2BKhVwQVJDKwosbQkI78IJO/tZ+LsbRykxFXLNdA+HwWjYBSMgpENACgAbtAACAAA" - upload := `{ - "_id": "` + packageName + `", - "name": "` + packageName + `", - "description": "` + packageDescription + `", - "dist-tags": { - "` + packageTag + `": "` + packageVersion + `" - }, - "versions": { - "` + packageVersion + `": { + + buildUpload := func(version string) string { + return `{ + "_id": "` + packageName + `", "name": "` + packageName + `", - "version": "` + packageVersion + `", "description": "` + packageDescription + `", - "author": { - "name": "` + packageAuthor + `" + "dist-tags": { + "` + packageTag + `": "` + version + `" + }, + "versions": { + "` + version + `": { + "name": "` + packageName + `", + "version": "` + version + `", + "description": "` + packageDescription + `", + "author": { + "name": "` + packageAuthor + `" + }, + "dist": { + "integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==", + "shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90" + } + } }, - "dist": { - "integrity": "sha512-yA4FJsVhetynGfOC1jFf79BuS+jrHbm0fhh+aHzCQkOaOBXKf9oBnC4a6DnLLnEsHQDRLYd00cwj8sCXpC+wIg==", - "shasum": "aaa7eaf852a948b0aa05afeda35b1badca155d90" + "_attachments": { + "` + packageName + `-` + version + `.tgz": { + "data": "` + data + `" + } } - } - }, - "_attachments": { - "` + packageName + `-` + packageVersion + `.tgz": { - "data": "` + data + `" - } - } - }` + }` + } root := fmt.Sprintf("/api/packages/%s/npm/%s", user.Name, url.QueryEscape(packageName)) tagsRoot := fmt.Sprintf("/api/packages/%s/npm/-/package/%s/dist-tags", user.Name, url.QueryEscape(packageName)) @@ -71,7 +74,7 @@ func TestPackageNpm(t *testing.T) { t.Run("Upload", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload)) + req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion))) req = addTokenAuthHeader(req, token) MakeRequest(t, req, http.StatusCreated) @@ -103,7 +106,7 @@ func TestPackageNpm(t *testing.T) { t.Run("UploadExists", func(t *testing.T) { defer PrintCurrentTest(t)() - req := NewRequestWithBody(t, "PUT", root, strings.NewReader(upload)) + req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion))) req = addTokenAuthHeader(req, token) MakeRequest(t, req, http.StatusBadRequest) }) @@ -219,4 +222,57 @@ func TestPackageNpm(t *testing.T) { test(t, http.StatusOK, "dummy") test(t, http.StatusOK, packageTag2) }) + + t.Run("Delete", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequestWithBody(t, "PUT", root, strings.NewReader(buildUpload(packageVersion+"-dummy"))) + req = addTokenAuthHeader(req, token) + MakeRequest(t, req, http.StatusCreated) + + req = NewRequest(t, "PUT", root+"/-rev/dummy") + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequest(t, "PUT", root+"/-rev/dummy") + req = addTokenAuthHeader(req, token) + MakeRequest(t, req, http.StatusOK) + + t.Run("Version", func(t *testing.T) { + defer PrintCurrentTest(t)() + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm) + assert.NoError(t, err) + assert.Len(t, pvs, 2) + + req := NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename)) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequest(t, "DELETE", fmt.Sprintf("%s/-/%s/%s/-rev/dummy", root, packageVersion, filename)) + req = addTokenAuthHeader(req, token) + MakeRequest(t, req, http.StatusOK) + + pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + }) + + t.Run("Full", func(t *testing.T) { + defer PrintCurrentTest(t)() + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + + req := NewRequest(t, "DELETE", root+"/-rev/dummy") + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequest(t, "DELETE", root+"/-rev/dummy") + req = addTokenAuthHeader(req, token) + MakeRequest(t, req, http.StatusOK) + + pvs, err = packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNpm) + assert.NoError(t, err) + assert.Len(t, pvs, 0) + }) + }) } diff --git a/integrations/api_packages_nuget_test.go b/integrations/api_packages_nuget_test.go index e69dd0ff9b66..5b662309ea1f 100644 --- a/integrations/api_packages_nuget_test.go +++ b/integrations/api_packages_nuget_test.go @@ -24,9 +24,16 @@ import ( "github.com/stretchr/testify/assert" ) +func addNuGetAPIKeyHeader(request *http.Request, token string) *http.Request { + request.Header.Set("X-NuGet-ApiKey", token) + return request +} + func TestPackageNuGet(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + token := getUserToken(t, user.Name) packageName := "test.package" packageVersion := "1.0.3" @@ -60,6 +67,10 @@ func TestPackageNuGet(t *testing.T) { req := NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url)) req = AddBasicAuthHeader(req, user.Name) + MakeRequest(t, req, http.StatusOK) + + req = NewRequest(t, "GET", fmt.Sprintf("%s/index.json", url)) + req = addNuGetAPIKeyHeader(req, token) resp := MakeRequest(t, req, http.StatusOK) var result nuget.ServiceIndexResponse @@ -122,7 +133,7 @@ func TestPackageNuGet(t *testing.T) { req = NewRequestWithBody(t, "PUT", url, bytes.NewReader(content)) req = AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusBadRequest) + MakeRequest(t, req, http.StatusConflict) }) t.Run("SymbolPackage", func(t *testing.T) { @@ -208,7 +219,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) req = NewRequestWithBody(t, "PUT", fmt.Sprintf("%s/symbolpackage", url), createPackage(packageName, "SymbolsPackage")) req = AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusBadRequest) + MakeRequest(t, req, http.StatusConflict) }) }) @@ -352,7 +363,7 @@ AAAjQmxvYgAAAGm7ENm9SGxMtAFVvPUsPJTF6PbtAAAAAFcVogEJAAAAAQAAAA==`) req := NewRequest(t, "DELETE", fmt.Sprintf("%s/%s/%s", url, packageName, packageVersion)) req = AddBasicAuthHeader(req, user.Name) - MakeRequest(t, req, http.StatusOK) + MakeRequest(t, req, http.StatusNoContent) pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypeNuGet) assert.NoError(t, err) diff --git a/integrations/api_packages_pub_test.go b/integrations/api_packages_pub_test.go new file mode 100644 index 000000000000..76d5116158e3 --- /dev/null +++ b/integrations/api_packages_pub_test.go @@ -0,0 +1,179 @@ +// 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 integrations + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/http/httptest" + "testing" + "time" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" + pub_module "code.gitea.io/gitea/modules/packages/pub" + + "github.com/stretchr/testify/assert" +) + +func TestPackagePub(t *testing.T) { + defer prepareTestEnv(t)() + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + + token := "Bearer " + getUserToken(t, user.Name) + + packageName := "test_package" + packageVersion := "1.0.1" + packageDescription := "Test Description" + + filename := fmt.Sprintf("%s.tar.gz", packageVersion) + + pubspecContent := `name: ` + packageName + ` +version: ` + packageVersion + ` +description: ` + packageDescription + + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + archive := tar.NewWriter(zw) + archive.WriteHeader(&tar.Header{ + Name: "pubspec.yaml", + Mode: 0o600, + Size: int64(len(pubspecContent)), + }) + archive.Write([]byte(pubspecContent)) + archive.Close() + zw.Close() + content := buf.Bytes() + + root := fmt.Sprintf("/api/packages/%s/pub", user.Name) + + t.Run("Upload", func(t *testing.T) { + defer PrintCurrentTest(t)() + + uploadURL := root + "/api/packages/versions/new" + + req := NewRequest(t, "GET", uploadURL) + MakeRequest(t, req, http.StatusUnauthorized) + + req = NewRequest(t, "GET", uploadURL) + addTokenAuthHeader(req, token) + resp := MakeRequest(t, req, http.StatusOK) + + type UploadRequest struct { + URL string `json:"url"` + Fields map[string]string `json:"fields"` + } + + var result UploadRequest + DecodeJSON(t, resp, &result) + + assert.Empty(t, result.Fields) + + uploadFile := func(t *testing.T, url string, content []byte, expectedStatus int) *httptest.ResponseRecorder { + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, _ := writer.CreateFormFile("file", "dummy.tar.gz") + _, _ = io.Copy(part, bytes.NewReader(content)) + + _ = writer.Close() + + req := NewRequestWithBody(t, "POST", url, body) + req.Header.Add("Content-Type", writer.FormDataContentType()) + addTokenAuthHeader(req, token) + return MakeRequest(t, req, expectedStatus) + } + + resp = uploadFile(t, result.URL, content, http.StatusNoContent) + + req = NewRequest(t, "GET", resp.Header().Get("Location")) + addTokenAuthHeader(req, token) + MakeRequest(t, req, http.StatusOK) + + pvs, err := packages.GetVersionsByPackageType(db.DefaultContext, user.ID, packages.TypePub) + assert.NoError(t, err) + assert.Len(t, pvs, 1) + + pd, err := packages.GetPackageDescriptor(db.DefaultContext, pvs[0]) + assert.NoError(t, err) + assert.NotNil(t, pd.SemVer) + assert.IsType(t, &pub_module.Metadata{}, pd.Metadata) + assert.Equal(t, packageName, pd.Package.Name) + assert.Equal(t, packageVersion, pd.Version.Version) + + pfs, err := packages.GetFilesByVersionID(db.DefaultContext, pvs[0].ID) + assert.NoError(t, err) + assert.Len(t, pfs, 1) + assert.Equal(t, filename, pfs[0].Name) + assert.True(t, pfs[0].IsLead) + + pb, err := packages.GetBlobByID(db.DefaultContext, pfs[0].BlobID) + assert.NoError(t, err) + assert.Equal(t, int64(len(content)), pb.Size) + + resp = uploadFile(t, result.URL, content, http.StatusBadRequest) + }) + + t.Run("Download", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s/%s", root, packageName, packageVersion)) + resp := MakeRequest(t, req, http.StatusOK) + + type VersionMetadata struct { + Version string `json:"version"` + ArchiveURL string `json:"archive_url"` + Published time.Time `json:"published"` + Pubspec interface{} `json:"pubspec,omitempty"` + } + + var result VersionMetadata + DecodeJSON(t, resp, &result) + + assert.Equal(t, packageVersion, result.Version) + assert.NotNil(t, result.Pubspec) + + req = NewRequest(t, "GET", result.ArchiveURL) + resp = MakeRequest(t, req, http.StatusOK) + + assert.Equal(t, content, resp.Body.Bytes()) + }) + + t.Run("EnumeratePackageVersions", func(t *testing.T) { + defer PrintCurrentTest(t)() + + req := NewRequest(t, "GET", fmt.Sprintf("%s/api/packages/%s", root, packageName)) + resp := MakeRequest(t, req, http.StatusOK) + + type VersionMetadata struct { + Version string `json:"version"` + ArchiveURL string `json:"archive_url"` + Published time.Time `json:"published"` + Pubspec interface{} `json:"pubspec,omitempty"` + } + + type PackageVersions struct { + Name string `json:"name"` + Latest *VersionMetadata `json:"latest"` + Versions []*VersionMetadata `json:"versions"` + } + + var result PackageVersions + DecodeJSON(t, resp, &result) + + assert.Equal(t, packageName, result.Name) + assert.NotNil(t, result.Latest) + assert.Len(t, result.Versions, 1) + assert.Equal(t, result.Latest.Version, result.Versions[0].Version) + assert.Equal(t, packageVersion, result.Latest.Version) + assert.NotNil(t, result.Latest.Pubspec) + }) +} diff --git a/integrations/api_packages_pypi_test.go b/integrations/api_packages_pypi_test.go index 5d610df39da9..a4c49ef1013b 100644 --- a/integrations/api_packages_pypi_test.go +++ b/integrations/api_packages_pypi_test.go @@ -25,7 +25,7 @@ import ( func TestPackagePyPI(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) packageName := "test-package" packageVersion := "1.0.1" diff --git a/integrations/api_packages_rubygems_test.go b/integrations/api_packages_rubygems_test.go index 269bc953b418..2228d3d0c19e 100644 --- a/integrations/api_packages_rubygems_test.go +++ b/integrations/api_packages_rubygems_test.go @@ -23,7 +23,7 @@ import ( func TestPackageRubyGems(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) packageName := "gitea" packageVersion := "1.0.5" diff --git a/integrations/api_packages_test.go b/integrations/api_packages_test.go index 1f24807060df..fcdacacea09d 100644 --- a/integrations/api_packages_test.go +++ b/integrations/api_packages_test.go @@ -24,7 +24,7 @@ import ( func TestPackageAPI(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_pull_commits_test.go b/integrations/api_pull_commits_test.go index 3b75fbcb4a28..693011c2350e 100644 --- a/integrations/api_pull_commits_test.go +++ b/integrations/api_pull_commits_test.go @@ -18,9 +18,9 @@ import ( func TestAPIPullCommits(t *testing.T) { defer prepareTestEnv(t)() - pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) assert.NoError(t, pullIssue.LoadIssue()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.HeadRepoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.HeadRepoID}) session := loginUser(t, "user2") req := NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/commits", repo.OwnerName, repo.Name, pullIssue.Index) diff --git a/integrations/api_pull_review_test.go b/integrations/api_pull_review_test.go index b601ca1d41fe..024ead905062 100644 --- a/integrations/api_pull_review_test.go +++ b/integrations/api_pull_review_test.go @@ -21,9 +21,9 @@ import ( func TestAPIPullReview(t *testing.T) { defer prepareTestEnv(t)() - pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue) + pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext)) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}) // test ListPullReviews session := loginUser(t, "user2") @@ -65,7 +65,7 @@ func TestAPIPullReview(t *testing.T) { assert.EqualValues(t, *reviews[5], review) // test GetPullReviewComments - comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7}).(*issues_model.Comment) + comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 7}) req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews/%d/comments?token=%s", repo.OwnerName, repo.Name, pullIssue.Index, 10, token) resp = session.MakeRequest(t, req, http.StatusOK) var reviewComments []*api.PullReviewComment @@ -200,9 +200,9 @@ func TestAPIPullReview(t *testing.T) { // test get review requests // to make it simple, use same api with get review - pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}).(*issues_model.Issue) + pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}) assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext)) - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}).(*repo_model.Repository) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}) req = NewRequestf(t, http.MethodGet, "/api/v1/repos/%s/%s/pulls/%d/reviews?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token) resp = session.MakeRequest(t, req, http.StatusOK) @@ -224,9 +224,9 @@ func TestAPIPullReview(t *testing.T) { func TestAPIPullReviewRequest(t *testing.T) { defer prepareTestEnv(t)() - pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue) + pullIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) assert.NoError(t, pullIssue.LoadAttributes(db.DefaultContext)) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue.RepoID}) // Test add Review Request session := loginUser(t, "user2") @@ -269,9 +269,9 @@ func TestAPIPullReviewRequest(t *testing.T) { session.MakeRequest(t, req, http.StatusNoContent) // Test team review request - pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}).(*issues_model.Issue) + pullIssue12 := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 12}) assert.NoError(t, pullIssue12.LoadAttributes(db.DefaultContext)) - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}).(*repo_model.Repository) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: pullIssue12.RepoID}) // Test add Team Review Request req = NewRequestWithJSON(t, http.MethodPost, fmt.Sprintf("/api/v1/repos/%s/%s/pulls/%d/requested_reviewers?token=%s", repo3.OwnerName, repo3.Name, pullIssue12.Index, token), &api.PullReviewRequestOptions{ diff --git a/integrations/api_pull_test.go b/integrations/api_pull_test.go index 0c63ec2c0065..4cb1b43cbbc2 100644 --- a/integrations/api_pull_test.go +++ b/integrations/api_pull_test.go @@ -23,8 +23,8 @@ import ( func TestAPIViewPulls(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, "user2") token := getTokenForLoggedInUser(t, session) @@ -40,9 +40,9 @@ func TestAPIViewPulls(t *testing.T) { // TestAPIMergePullWIP ensures that we can't merge a WIP pull request func TestAPIMergePullWIP(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{Status: issues_model.PullRequestStatusMergeable}, unittest.Cond("has_merged = ?", false)).(*issues_model.PullRequest) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{Status: issues_model.PullRequestStatusMergeable}, unittest.Cond("has_merged = ?", false)) pr.LoadIssue() issue_service.ChangeTitle(pr.Issue, owner, setting.Repository.PullRequest.WorkInProgressPrefixes[0]+" "+pr.Issue.Title) @@ -63,12 +63,12 @@ func TestAPIMergePullWIP(t *testing.T) { func TestAPICreatePullSuccess(t *testing.T) { defer prepareTestEnv(t)() - repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) // repo10 have code, pulls units. - repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}).(*repo_model.Repository) + repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}) // repo11 only have code unit but should still create pulls - owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}).(*user_model.User) - owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}).(*user_model.User) + owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}) + owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}) session := loginUser(t, owner11.Name) token := getTokenForLoggedInUser(t, session) @@ -84,11 +84,11 @@ func TestAPICreatePullSuccess(t *testing.T) { func TestAPICreatePullWithFieldsSuccess(t *testing.T) { defer prepareTestEnv(t)() // repo10 have code, pulls units. - repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) - owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}).(*user_model.User) + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) + owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}) // repo11 only have code unit but should still create pulls - repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}).(*repo_model.Repository) - owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}).(*user_model.User) + repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}) + owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}) session := loginUser(t, owner11.Name) token := getTokenForLoggedInUser(t, session) @@ -121,11 +121,11 @@ func TestAPICreatePullWithFieldsSuccess(t *testing.T) { func TestAPICreatePullWithFieldsFailure(t *testing.T) { defer prepareTestEnv(t)() // repo10 have code, pulls units. - repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) - owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}).(*user_model.User) + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) + owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}) // repo11 only have code unit but should still create pulls - repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}).(*repo_model.Repository) - owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}).(*user_model.User) + repo11 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 11}) + owner11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo11.OwnerID}) session := loginUser(t, owner11.Name) token := getTokenForLoggedInUser(t, session) @@ -154,8 +154,8 @@ func TestAPICreatePullWithFieldsFailure(t *testing.T) { func TestAPIEditPull(t *testing.T) { defer prepareTestEnv(t)() - repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) - owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}).(*user_model.User) + repo10 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) + owner10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo10.OwnerID}) session := loginUser(t, owner10.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_releases_test.go b/integrations/api_releases_test.go index 74639e900739..9561e3f48800 100644 --- a/integrations/api_releases_test.go +++ b/integrations/api_releases_test.go @@ -23,8 +23,8 @@ import ( func TestAPIListReleases(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) token := getUserToken(t, user2.LowerName) link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/releases", user2.Name, repo.Name)) @@ -98,8 +98,8 @@ func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, func TestAPICreateAndUpdateRelease(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session) @@ -150,8 +150,8 @@ func TestAPICreateAndUpdateRelease(t *testing.T) { func TestAPICreateReleaseToDefaultBranch(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session) @@ -161,8 +161,8 @@ func TestAPICreateReleaseToDefaultBranch(t *testing.T) { func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session) @@ -179,8 +179,8 @@ func TestAPICreateReleaseToDefaultBranchOnExistingTag(t *testing.T) { func TestAPIGetReleaseByTag(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.LowerName) tag := "v1.1" @@ -212,8 +212,8 @@ func TestAPIGetReleaseByTag(t *testing.T) { func TestAPIDeleteReleaseByTagName(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_archive_test.go b/integrations/api_repo_archive_test.go index 7778b7ff697a..ca959a12874f 100644 --- a/integrations/api_repo_archive_test.go +++ b/integrations/api_repo_archive_test.go @@ -21,8 +21,8 @@ import ( func TestAPIDownloadArchive(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user2.LowerName) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_collaborator_test.go b/integrations/api_repo_collaborator_test.go index fdca1d915024..f2e5bf648d80 100644 --- a/integrations/api_repo_collaborator_test.go +++ b/integrations/api_repo_collaborator_test.go @@ -20,13 +20,13 @@ import ( func TestAPIRepoCollaboratorPermission(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}).(*user_model.User) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + repo2Owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}) - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}).(*user_model.User) - user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11}).(*user_model.User) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) + user10 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) + user11 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 11}) session := loginUser(t, repo2Owner.Name) testCtx := NewAPITestContext(t, repo2Owner.Name, repo2.Name) diff --git a/integrations/api_repo_edit_test.go b/integrations/api_repo_edit_test.go index f3f0139d9538..677fc0beff50 100644 --- a/integrations/api_repo_edit_test.go +++ b/integrations/api_repo_edit_test.go @@ -135,13 +135,13 @@ func TestAPIRepoEdit(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { bFalse, bTrue := false, true - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3, is an org - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo15 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}).(*repo_model.Repository) // empty repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo15 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}) // empty repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo // Get user2's token session := loginUser(t, user2.Name) @@ -166,7 +166,7 @@ func TestAPIRepoEdit(t *testing.T) { assert.Equal(t, *repoEditOption.Website, repo.Website) assert.Equal(t, *repoEditOption.Archived, repo.Archived) // check repo1 from database - repo1edited := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1edited := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo1editedOption := getRepoEditOptionFromRepo(repo1edited) assert.Equal(t, *repoEditOption.Name, *repo1editedOption.Name) assert.Equal(t, *repoEditOption.Description, *repo1editedOption.Description) @@ -191,7 +191,7 @@ func TestAPIRepoEdit(t *testing.T) { DecodeJSON(t, resp, &repo) assert.NotNil(t, repo) // check repo1 was written to database - repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo1editedOption = getRepoEditOptionFromRepo(repo1edited) assert.Equal(t, *repo1editedOption.HasIssues, true) assert.Nil(t, repo1editedOption.ExternalTracker) @@ -213,7 +213,7 @@ func TestAPIRepoEdit(t *testing.T) { DecodeJSON(t, resp, &repo) assert.NotNil(t, repo) // check repo1 was written to database - repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo1editedOption = getRepoEditOptionFromRepo(repo1edited) assert.Equal(t, *repo1editedOption.HasIssues, true) assert.Equal(t, *repo1editedOption.ExternalTracker, *repoEditOption.ExternalTracker) @@ -244,7 +244,7 @@ func TestAPIRepoEdit(t *testing.T) { DecodeJSON(t, resp, &repo) assert.NotNil(t, repo) // check repo1 was written to database - repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1edited = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo1editedOption = getRepoEditOptionFromRepo(repo1edited) assert.Equal(t, *repo1editedOption.Description, *repoEditOption.Description) assert.Equal(t, *repo1editedOption.HasIssues, true) @@ -289,7 +289,7 @@ func TestAPIRepoEdit(t *testing.T) { _ = session.MakeRequest(t, req, http.StatusOK) // Test making a repo public that is private - repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) + repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) assert.True(t, repo16.IsPrivate) repoEditOption = &api.EditRepoOption{ Private: &bFalse, @@ -297,7 +297,7 @@ func TestAPIRepoEdit(t *testing.T) { url = fmt.Sprintf("/api/v1/repos/%s/%s?token=%s", user2.Name, repo16.Name, token2) req = NewRequestWithJSON(t, "PATCH", url, &repoEditOption) _ = session.MakeRequest(t, req, http.StatusOK) - repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) + repo16 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) assert.False(t, repo16.IsPrivate) // Make it private again repoEditOption.Private = &bTrue @@ -311,7 +311,7 @@ func TestAPIRepoEdit(t *testing.T) { Archived: &bTrue, }) _ = session.MakeRequest(t, req, http.StatusOK) - repo15 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}).(*repo_model.Repository) + repo15 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}) assert.True(t, repo15.IsArchived) req = NewRequestWithJSON(t, "PATCH", url, &api.EditRepoOption{ Archived: &bFalse, diff --git a/integrations/api_repo_file_create_test.go b/integrations/api_repo_file_create_test.go index fd460ce5643f..f9ed479ca20e 100644 --- a/integrations/api_repo_file_create_test.go +++ b/integrations/api_repo_file_create_test.go @@ -112,8 +112,8 @@ func getExpectedFileResponseForCreate(repoFullName, commitID, treePath, latestCo func BenchmarkAPICreateFileSmall(b *testing.B) { onGiteaRunTB(b, func(t testing.TB, u *url.URL) { b := t.(*testing.B) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo for n := 0; n < b.N; n++ { treePath := fmt.Sprintf("update/file%d.txt", n) @@ -127,8 +127,8 @@ func BenchmarkAPICreateFileMedium(b *testing.B) { onGiteaRunTB(b, func(t testing.TB, u *url.URL) { b := t.(*testing.B) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo b.ResetTimer() for n := 0; n < b.N; n++ { @@ -141,12 +141,12 @@ func BenchmarkAPICreateFileMedium(b *testing.B) { func TestAPICreateFile(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3, is an org - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo fileID := 0 // Get user2's token @@ -288,7 +288,7 @@ func TestAPICreateFile(t *testing.T) { url = fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s?token=%s", user2.Name, "empty-repo", treePath, token2) req = NewRequestWithJSON(t, "POST", url, &createFileOptions) resp = session.MakeRequest(t, req, http.StatusCreated) - emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}).(*repo_model.Repository) // public repo + emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "empty-repo"}) // public repo gitRepo, _ := git.OpenRepository(stdCtx.Background(), emptyRepo.RepoPath()) commitID, _ := gitRepo.GetBranchCommitID(createFileOptions.NewBranchName) latestCommit, _ := gitRepo.GetCommitByPath(treePath) diff --git a/integrations/api_repo_file_delete_test.go b/integrations/api_repo_file_delete_test.go index 42df869d692c..340ffe362e8d 100644 --- a/integrations/api_repo_file_delete_test.go +++ b/integrations/api_repo_file_delete_test.go @@ -39,12 +39,12 @@ func getDeleteFileOptions() *api.DeleteFileOptions { func TestAPIDeleteFile(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3, is an org - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo fileID := 0 // Get user2's token diff --git a/integrations/api_repo_file_update_test.go b/integrations/api_repo_file_update_test.go index e39d83e49e13..3044f0384417 100644 --- a/integrations/api_repo_file_update_test.go +++ b/integrations/api_repo_file_update_test.go @@ -107,12 +107,12 @@ func getExpectedFileResponseForUpdate(commitID, treePath, lastCommitSHA string) func TestAPIUpdateFile(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3, is an org - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo fileID := 0 // Get user2's token diff --git a/integrations/api_repo_get_contents_list_test.go b/integrations/api_repo_get_contents_list_test.go index 97b152bf1b34..18231a2cafc5 100644 --- a/integrations/api_repo_get_contents_list_test.go +++ b/integrations/api_repo_get_contents_list_test.go @@ -55,13 +55,13 @@ func TestAPIGetContentsList(t *testing.T) { func testAPIGetContentsList(t *testing.T, u *url.URL) { /*** SETUP ***/ - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3, is an org - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo - treePath := "" // root dir + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo + treePath := "" // root dir // Get user2's token session := loginUser(t, user2.Name) diff --git a/integrations/api_repo_get_contents_test.go b/integrations/api_repo_get_contents_test.go index 56f5336b7bd9..1fb8b9bf0dc3 100644 --- a/integrations/api_repo_get_contents_test.go +++ b/integrations/api_repo_get_contents_test.go @@ -56,12 +56,12 @@ func TestAPIGetContents(t *testing.T) { func testAPIGetContents(t *testing.T, u *url.URL) { /*** SETUP ***/ - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3, is an org - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3, is an org + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo treePath := "README.md" // Get user2's token diff --git a/integrations/api_repo_git_blobs_test.go b/integrations/api_repo_git_blobs_test.go index 0a3cf632cccd..7b990450d893 100644 --- a/integrations/api_repo_git_blobs_test.go +++ b/integrations/api_repo_git_blobs_test.go @@ -18,12 +18,12 @@ import ( func TestAPIReposGitBlobs(t *testing.T) { defer prepareTestEnv(t)() - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3 - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3 + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo repo1ReadmeSHA := "65f1bf27bc3bf70f64657658635e66094edbcb4d" repo3ReadmeSHA := "d56a3073c1dbb7b15963110a049d50cdb5db99fc" repo16ReadmeSHA := "f90451c72ef61a7645293d17b47be7a8e983da57" diff --git a/integrations/api_repo_git_commits_test.go b/integrations/api_repo_git_commits_test.go index f5a64490b9ed..7eba5bd22362 100644 --- a/integrations/api_repo_git_commits_test.go +++ b/integrations/api_repo_git_commits_test.go @@ -25,7 +25,7 @@ func compareCommitFiles(t *testing.T, expect []string, files []*api.CommitAffect func TestAPIReposGitCommits(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -53,7 +53,7 @@ func TestAPIReposGitCommits(t *testing.T) { func TestAPIReposGitCommitList(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -76,7 +76,7 @@ func TestAPIReposGitCommitList(t *testing.T) { func TestAPIReposGitCommitListPage2Empty(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -93,7 +93,7 @@ func TestAPIReposGitCommitListPage2Empty(t *testing.T) { func TestAPIReposGitCommitListDifferentBranch(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -112,7 +112,7 @@ func TestAPIReposGitCommitListDifferentBranch(t *testing.T) { func TestDownloadCommitDiffOrPatch(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -134,7 +134,7 @@ func TestDownloadCommitDiffOrPatch(t *testing.T) { func TestGetFileHistory(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_git_hook_test.go b/integrations/api_repo_git_hook_test.go index a31b27c45649..b90d66c175f8 100644 --- a/integrations/api_repo_git_hook_test.go +++ b/integrations/api_repo_git_hook_test.go @@ -25,8 +25,8 @@ echo Hello, World! func TestAPIListGitHooks(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) // user1 is an admin user session := loginUser(t, "user1") @@ -51,8 +51,8 @@ func TestAPIListGitHooks(t *testing.T) { func TestAPIListGitHooksNoHooks(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) // user1 is an admin user session := loginUser(t, "user1") @@ -72,8 +72,8 @@ func TestAPIListGitHooksNoHooks(t *testing.T) { func TestAPIListGitHooksNoAccess(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -85,8 +85,8 @@ func TestAPIListGitHooksNoAccess(t *testing.T) { func TestAPIGetGitHook(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) // user1 is an admin user session := loginUser(t, "user1") @@ -103,8 +103,8 @@ func TestAPIGetGitHook(t *testing.T) { func TestAPIGetGitHookNoAccess(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -116,8 +116,8 @@ func TestAPIGetGitHookNoAccess(t *testing.T) { func TestAPIEditGitHook(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) // user1 is an admin user session := loginUser(t, "user1") @@ -146,8 +146,8 @@ func TestAPIEditGitHook(t *testing.T) { func TestAPIEditGitHookNoAccess(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) @@ -162,8 +162,8 @@ func TestAPIEditGitHookNoAccess(t *testing.T) { func TestAPIDeleteGitHook(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 37}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) // user1 is an admin user session := loginUser(t, "user1") @@ -185,8 +185,8 @@ func TestAPIDeleteGitHook(t *testing.T) { func TestAPIDeleteGitHookNoAccess(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_git_notes_test.go b/integrations/api_repo_git_notes_test.go index 08b885bd2fc9..733e0575dce7 100644 --- a/integrations/api_repo_git_notes_test.go +++ b/integrations/api_repo_git_notes_test.go @@ -18,7 +18,7 @@ import ( func TestAPIReposGitNotes(t *testing.T) { onGiteaRun(t, func(*testing.T, *url.URL) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_git_ref_test.go b/integrations/api_repo_git_ref_test.go index f0fc3c81fa2a..7ff16eb1c5a5 100644 --- a/integrations/api_repo_git_ref_test.go +++ b/integrations/api_repo_git_ref_test.go @@ -14,7 +14,7 @@ import ( func TestAPIReposGitRefs(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_git_tags_test.go b/integrations/api_repo_git_tags_test.go index 9e870d248913..45551a4d7b5c 100644 --- a/integrations/api_repo_git_tags_test.go +++ b/integrations/api_repo_git_tags_test.go @@ -21,8 +21,8 @@ import ( func TestAPIGitTags(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -66,8 +66,8 @@ func TestAPIGitTags(t *testing.T) { func TestAPIDeleteTagByName(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.LowerName) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_git_trees_test.go b/integrations/api_repo_git_trees_test.go index 03e065645bb1..d80bcadb692f 100644 --- a/integrations/api_repo_git_trees_test.go +++ b/integrations/api_repo_git_trees_test.go @@ -15,12 +15,12 @@ import ( func TestAPIReposGitTrees(t *testing.T) { defer prepareTestEnv(t)() - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo1 & repo16 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of the repo3 - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // owner of neither repos - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) // public repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // public repo - repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) // private repo + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo1 & repo16 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of the repo3 + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // owner of neither repos + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) // public repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // public repo + repo16 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) // private repo repo1TreeSHA := "65f1bf27bc3bf70f64657658635e66094edbcb4d" repo3TreeSHA := "2a47ca4b614a9f5a43abbd5ad851a54a616ffee6" repo16TreeSHA := "69554a64c1e6030f051e5c3f94bfbd773cd6a324" diff --git a/integrations/api_repo_lfs_locks_test.go b/integrations/api_repo_lfs_locks_test.go index ca7bd35001e5..3fd8f48f9751 100644 --- a/integrations/api_repo_lfs_locks_test.go +++ b/integrations/api_repo_lfs_locks_test.go @@ -23,8 +23,8 @@ import ( func TestAPILFSLocksNotStarted(t *testing.T) { defer prepareTestEnv(t)() setting.LFS.StartServer = false - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) req := NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name) MakeRequest(t, req, http.StatusNotFound) @@ -39,8 +39,8 @@ func TestAPILFSLocksNotStarted(t *testing.T) { func TestAPILFSLocksNotLogin(t *testing.T) { defer prepareTestEnv(t)() setting.LFS.StartServer = true - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) req := NewRequestf(t, "GET", "/%s/%s.git/info/lfs/locks", user.Name, repo.Name) req.Header.Set("Accept", lfs.MediaType) @@ -53,11 +53,11 @@ func TestAPILFSLocksNotLogin(t *testing.T) { func TestAPILFSLocksLogged(t *testing.T) { defer prepareTestEnv(t)() setting.LFS.StartServer = true - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // in org 3 - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // in org 3 + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // in org 3 + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // in org 3 - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) // own by org 3 + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // own by org 3 tests := []struct { user *user_model.User diff --git a/integrations/api_repo_lfs_migrate_test.go b/integrations/api_repo_lfs_migrate_test.go index 6d41a48529ce..1f6893f32a1f 100644 --- a/integrations/api_repo_lfs_migrate_test.go +++ b/integrations/api_repo_lfs_migrate_test.go @@ -28,7 +28,7 @@ func TestAPIRepoLFSMigrateLocal(t *testing.T) { setting.Migrations.AllowLocalNetworks = true assert.NoError(t, migrations.Init()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_lfs_test.go b/integrations/api_repo_lfs_test.go index 6a2fccebb508..8bbc01995306 100644 --- a/integrations/api_repo_lfs_test.go +++ b/integrations/api_repo_lfs_test.go @@ -28,8 +28,8 @@ func TestAPILFSNotStarted(t *testing.T) { setting.LFS.StartServer = false - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) req := NewRequestf(t, "POST", "/%s/%s.git/info/lfs/objects/batch", user.Name, repo.Name) MakeRequest(t, req, http.StatusNotFound) @@ -48,8 +48,8 @@ func TestAPILFSMediaType(t *testing.T) { setting.LFS.StartServer = true - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) req := NewRequestf(t, "POST", "/%s/%s.git/info/lfs/objects/batch", user.Name, repo.Name) MakeRequest(t, req, http.StatusUnsupportedMediaType) diff --git a/integrations/api_repo_raw_test.go b/integrations/api_repo_raw_test.go index 258b409befb8..8e8cc750dde4 100644 --- a/integrations/api_repo_raw_test.go +++ b/integrations/api_repo_raw_test.go @@ -16,7 +16,7 @@ import ( func TestAPIReposRaw(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_tags_test.go b/integrations/api_repo_tags_test.go index 14a24cf5eb75..4b87093cdf3d 100644 --- a/integrations/api_repo_tags_test.go +++ b/integrations/api_repo_tags_test.go @@ -19,7 +19,7 @@ import ( func TestAPIRepoTags(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Login as User2. session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/api_repo_teams_test.go b/integrations/api_repo_teams_test.go index efd6ddb457fa..2ec69582865f 100644 --- a/integrations/api_repo_teams_test.go +++ b/integrations/api_repo_teams_test.go @@ -23,9 +23,9 @@ func TestAPIRepoTeams(t *testing.T) { defer prepareTestEnv(t)() // publicOrgRepo = user3/repo21 - publicOrgRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}).(*repo_model.Repository) + publicOrgRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}) // user4 - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -65,7 +65,7 @@ func TestAPIRepoTeams(t *testing.T) { session.MakeRequest(t, req, http.StatusForbidden) // AddTeam with user2 - user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session = loginUser(t, user.Name) token = getTokenForLoggedInUser(t, session) url = fmt.Sprintf("/api/v1/repos/%s/teams/%s?token=%s", publicOrgRepo.FullName(), "team1", token) diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index 57fe65f4bf90..5631df323a46 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -26,7 +26,7 @@ import ( func TestAPIUserReposNotLogin(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) req := NewRequestf(t, "GET", "/api/v1/users/%s/repos", user.Name) resp := MakeRequest(t, req, http.StatusOK) @@ -57,11 +57,11 @@ func TestAPISearchRepo(t *testing.T) { assert.False(t, repo.Private) } - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 16}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 18}).(*user_model.User) - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}).(*user_model.User) - orgUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 16}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 18}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}) + orgUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 17}) oldAPIDefaultNum := setting.API.DefaultPagingNum defer func() { @@ -241,7 +241,7 @@ var repoCache = make(map[int64]*repo_model.Repository) func getRepo(t *testing.T, repoID int64) *repo_model.Repository { if _, ok := repoCache[repoID]; !ok { - repoCache[repoID] = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repoCache[repoID] = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) } return repoCache[repoID] } @@ -278,11 +278,11 @@ func TestAPIViewRepo(t *testing.T) { func TestAPIOrgRepos(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) // User3 is an Org. Check their repos. - sourceOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + sourceOrg := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) expectedResults := map[*user_model.User]struct { count int @@ -324,7 +324,7 @@ func TestAPIOrgRepos(t *testing.T) { func TestAPIGetRepoByIDUnauthorized(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token) @@ -348,7 +348,7 @@ func TestAPIRepoMigrate(t *testing.T) { defer prepareTestEnv(t)() for _, testCase := range testCases { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOptions{ @@ -448,7 +448,7 @@ func TestAPIOrgRepoCreate(t *testing.T) { defer prepareTestEnv(t)() for _, testCase := range testCases { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/org/%s/repos?token="+token, testCase.orgName), &api.CreateRepoOption{ @@ -515,7 +515,7 @@ func TestAPIRepoTransfer(t *testing.T) { defer prepareTestEnv(t)() // create repo to move - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) repoName := "moveME" @@ -532,8 +532,8 @@ func TestAPIRepoTransfer(t *testing.T) { // start testing for _, testCase := range testCases { - user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}).(*repo_model.Repository) + user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: testCase.ctxUserID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) session = loginUser(t, user.Name) token = getTokenForLoggedInUser(t, session) req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer?token=%s", repo.OwnerName, repo.Name, token), &api.TransferRepoOption{ @@ -544,13 +544,13 @@ func TestAPIRepoTransfer(t *testing.T) { } // cleanup - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) _ = models.DeleteRepository(user, repo.OwnerID, repo.ID) } func transfer(t *testing.T) *repo_model.Repository { // create repo to move - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) repoName := "moveME" @@ -566,7 +566,7 @@ func transfer(t *testing.T) *repo_model.Repository { resp := session.MakeRequest(t, req, http.StatusCreated) DecodeJSON(t, resp, apiRepo) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: apiRepo.ID}) req = NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer?token=%s", repo.OwnerName, repo.Name, token), &api.TransferRepoOption{ NewOwner: "user4", }) @@ -630,11 +630,11 @@ func TestAPIRejectTransfer(t *testing.T) { func TestAPIGenerateRepo(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) - templateRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 44}).(*repo_model.Repository) + templateRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 44}) // user repo := new(api.Repository) @@ -666,10 +666,10 @@ func TestAPIGenerateRepo(t *testing.T) { func TestAPIRepoGetReviewers(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/reviewers?token=%s", user.Name, repo.Name, token) resp := session.MakeRequest(t, req, http.StatusOK) @@ -680,10 +680,10 @@ func TestAPIRepoGetReviewers(t *testing.T) { func TestAPIRepoGetAssignees(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/assignees?token=%s", user.Name, repo.Name, token) resp := session.MakeRequest(t, req, http.StatusOK) diff --git a/integrations/api_repo_topic_test.go b/integrations/api_repo_topic_test.go index 04295724a75b..e99c682e211f 100644 --- a/integrations/api_repo_topic_test.go +++ b/integrations/api_repo_topic_test.go @@ -52,11 +52,11 @@ func TestAPITopicSearch(t *testing.T) { func TestAPIRepoTopic(t *testing.T) { defer prepareTestEnv(t)() - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of repo2 - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) // owner of repo3 - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) // write access to repo 3 - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of repo2 + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) // owner of repo3 + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) // write access to repo 3 + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // Get user2's token token2 := getUserToken(t, user2.Name) diff --git a/integrations/api_team_test.go b/integrations/api_team_test.go index d571342c3d61..82824d610bd6 100644 --- a/integrations/api_team_test.go +++ b/integrations/api_team_test.go @@ -24,9 +24,9 @@ import ( func TestAPITeam(t *testing.T) { defer prepareTestEnv(t)() - teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{}).(*organization.TeamUser) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID}).(*organization.Team) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID}).(*user_model.User) + teamUser := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{}) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamUser.TeamID}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser.UID}) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session) @@ -39,8 +39,8 @@ func TestAPITeam(t *testing.T) { assert.Equal(t, team.Name, apiTeam.Name) // non team member user will not access the teams details - teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3}).(*organization.TeamUser) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID}).(*user_model.User) + teamUser2 := unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{ID: 3}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: teamUser2.UID}) session = loginUser(t, user2.Name) token = getTokenForLoggedInUser(t, session) @@ -51,11 +51,11 @@ func TestAPITeam(t *testing.T) { _ = session.MakeRequest(t, req, http.StatusUnauthorized) // Get an admin user able to create, update and delete teams. - user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session = loginUser(t, user.Name) token = getTokenForLoggedInUser(t, session) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 6}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 6}) // Create team. teamToCreate := &api.CreateTeamOption{ @@ -108,7 +108,7 @@ func TestAPITeam(t *testing.T) { teamToEdit.Permission, unit.AllUnitKeyNames(), nil) // Read team. - teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + teamRead := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, teamRead.GetUnits()) req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID) resp = session.MakeRequest(t, req, http.StatusOK) @@ -174,7 +174,7 @@ func TestAPITeam(t *testing.T) { "read", nil, teamToEdit.UnitsMap) // Read team. - teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + teamRead = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) req = NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamID) resp = session.MakeRequest(t, req, http.StatusOK) apiTeam = api.Team{} @@ -207,7 +207,7 @@ func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, d } func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id}) assert.NoError(t, team.GetUnits(), "GetUnits") apiTeam, err := convert.ToTeam(team) assert.NoError(t, err) @@ -222,8 +222,8 @@ type TeamSearchResults struct { func TestAPITeamSearch(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) var results TeamSearchResults @@ -236,7 +236,7 @@ func TestAPITeamSearch(t *testing.T) { assert.Equal(t, "test_team", results.Data[0].Name) // no access if not organization member - user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) token5 := getUserToken(t, user5.Name) req = NewRequestf(t, "GET", "/api/v1/orgs/%s/teams/search?q=%s&token=%s", org.Name, "team", token5) @@ -246,9 +246,9 @@ func TestAPITeamSearch(t *testing.T) { func TestAPIGetTeamRepo(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) - teamRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 24}).(*repo.Repository) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) + teamRepo := unittest.AssertExistsAndLoadBean(t, &repo.Repository{ID: 24}) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}) var results api.Repository @@ -259,7 +259,7 @@ func TestAPIGetTeamRepo(t *testing.T) { assert.Equal(t, "big_test_private_4", teamRepo.Name) // no access if not organization member - user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) token5 := getUserToken(t, user5.Name) req = NewRequestf(t, "GET", "/api/v1/teams/%d/repos/%s/?token=%s", team.ID, teamRepo.FullName(), token5) diff --git a/integrations/api_team_user_test.go b/integrations/api_team_user_test.go index 7263408bee56..9b3364b5b185 100644 --- a/integrations/api_team_user_test.go +++ b/integrations/api_team_user_test.go @@ -31,7 +31,7 @@ func TestAPITeamUser(t *testing.T) { var user2 *api.User DecodeJSON(t, resp, &user2) user2.Created = user2.Created.In(time.Local) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}) expectedUser := convert.ToUser(user, user) diff --git a/integrations/api_token_test.go b/integrations/api_token_test.go index aca4768503c9..17e8fb5e2580 100644 --- a/integrations/api_token_test.go +++ b/integrations/api_token_test.go @@ -17,7 +17,7 @@ import ( // TestAPICreateAndDeleteToken tests that token that was just created can be deleted func TestAPICreateAndDeleteToken(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) req := NewRequestWithJSON(t, "POST", "/api/v1/users/user1/tokens", map[string]string{ "name": "test-key-1", @@ -57,7 +57,7 @@ func TestAPICreateAndDeleteToken(t *testing.T) { // TestAPIDeleteMissingToken ensures that error is thrown when token not found func TestAPIDeleteMissingToken(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) req := NewRequestf(t, "DELETE", "/api/v1/users/user1/tokens/%d", unittest.NonexistentID) req = AddBasicAuthHeader(req, user.Name) diff --git a/integrations/api_user_orgs_test.go b/integrations/api_user_orgs_test.go index 219bd273c99c..9f3487cb7fb6 100644 --- a/integrations/api_user_orgs_test.go +++ b/integrations/api_user_orgs_test.go @@ -25,7 +25,7 @@ func TestUserOrgs(t *testing.T) { orgs := getUserOrgs(t, adminUsername, normalUsername) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}).(*user_model.User) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}) assert.Equal(t, []*api.Organization{ { @@ -81,7 +81,7 @@ func TestMyOrgs(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) var orgs []*api.Organization DecodeJSON(t, resp, &orgs) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}).(*user_model.User) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user3"}) assert.Equal(t, []*api.Organization{ { diff --git a/integrations/api_user_search_test.go b/integrations/api_user_search_test.go index 41f14cf944f3..dbaca24981a7 100644 --- a/integrations/api_user_search_test.go +++ b/integrations/api_user_search_test.go @@ -52,7 +52,7 @@ func TestAPIUserSearchNotLoggedIn(t *testing.T) { var modelUser *user_model.User for _, user := range results.Data { assert.Contains(t, user.UserName, query) - modelUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: user.ID}).(*user_model.User) + modelUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: user.ID}) if modelUser.KeepEmailPrivate { assert.EqualValues(t, fmt.Sprintf("%s@%s", modelUser.LowerName, setting.Service.NoReplyAddress), user.Email) } else { diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go index 492a4fdadf3f..892ff3813401 100644 --- a/integrations/auth_ldap_test.go +++ b/integrations/auth_ldap_test.go @@ -326,7 +326,7 @@ func TestLDAPGroupTeamSyncAddMember(t *testing.T) { for _, gitLDAPUser := range gitLDAPUsers { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ Name: gitLDAPUser.UserName, - }).(*user_model.User) + }) usersOrgs, err := organization.FindOrgs(organization.FindOrgOptions{ UserID: user.ID, IncludePrivate: true, @@ -370,7 +370,7 @@ func TestLDAPGroupTeamSyncRemoveMember(t *testing.T) { loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ Name: gitLDAPUsers[0].UserName, - }).(*user_model.User) + }) err = organization.AddOrgUser(org.ID, user.ID) assert.NoError(t, err) err = models.AddTeamMember(team, user.ID) diff --git a/integrations/benchmarks_test.go b/integrations/benchmarks_test.go index ffae471307d2..a63c36368330 100644 --- a/integrations/benchmarks_test.go +++ b/integrations/benchmarks_test.go @@ -33,7 +33,7 @@ func BenchmarkRepoBranchCommit(b *testing.B) { for _, repoID := range samples { b.StopTimer() - repo := unittest.AssertExistsAndLoadBean(b, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(b, &repo_model.Repository{ID: repoID}) b.StartTimer() b.Run(repo.Name, func(b *testing.B) { session := loginUser(b, "user2") diff --git a/integrations/change_default_branch_test.go b/integrations/change_default_branch_test.go index 096afa28f46f..6fe7305d4563 100644 --- a/integrations/change_default_branch_test.go +++ b/integrations/change_default_branch_test.go @@ -16,8 +16,8 @@ import ( func TestChangeDefaultBranch(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) branchesURL := fmt.Sprintf("/%s/%s/settings/branches", owner.Name, repo.Name) diff --git a/integrations/csrf_test.go b/integrations/csrf_test.go index 5bfc97bbd136..2c61f954269c 100644 --- a/integrations/csrf_test.go +++ b/integrations/csrf_test.go @@ -20,7 +20,7 @@ func TestCsrfProtection(t *testing.T) { defer prepareTestEnv(t)() // test web form csrf via form - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user.Name) req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ "_csrf": "fake_csrf", diff --git a/integrations/dump_restore_test.go b/integrations/dump_restore_test.go index ef869c4ddabc..7395bd5bd9a7 100644 --- a/integrations/dump_restore_test.go +++ b/integrations/dump_restore_test.go @@ -48,8 +48,8 @@ func TestDumpRestore(t *testing.T) { assert.NoError(t, err) defer util.RemoveAll(basePath) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, repoOwner.Name) token := getTokenForLoggedInUser(t, session) @@ -90,7 +90,7 @@ func TestDumpRestore(t *testing.T) { }, false) assert.NoError(t, err) - newrepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: newreponame}).(*repo_model.Repository) + newrepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: newreponame}) // // Phase 3: dump restored from the Gitea instance to the filesystem diff --git a/integrations/empty_repo_test.go b/integrations/empty_repo_test.go index abc28b74c8af..daf153a183b7 100644 --- a/integrations/empty_repo_test.go +++ b/integrations/empty_repo_test.go @@ -21,8 +21,8 @@ func TestEmptyRepo(t *testing.T) { "commit/1ae57b34ccf7e18373", "graph", } - emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}, unittest.Cond("is_empty = ?", true)).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID}).(*user_model.User) + emptyRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}, unittest.Cond("is_empty = ?", true)) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: emptyRepo.OwnerID}) for _, subpath := range subpaths { req := NewRequestf(t, "GET", "/%s/%s/%s", owner.Name, emptyRepo.Name, subpath) MakeRequest(t, req, http.StatusNotFound) diff --git a/integrations/eventsource_test.go b/integrations/eventsource_test.go index ff3298863485..e2465e9e5659 100644 --- a/integrations/eventsource_test.go +++ b/integrations/eventsource_test.go @@ -53,9 +53,9 @@ func TestEventSourceManagerRun(t *testing.T) { } } - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - thread5 := unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}).(*models.Notification) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + thread5 := unittest.AssertExistsAndLoadBean(t, &models.Notification{ID: 5}) assert.NoError(t, thread5.LoadAttributes()) session := loginUser(t, user2.Name) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/git_test.go b/integrations/git_test.go index d6bd673822ba..9018374514c6 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -156,11 +156,6 @@ func standardCommitAndPushTest(t *testing.T, dstPath string) (little, big string func lfsCommitAndPushTest(t *testing.T, dstPath string) (littleLFS, bigLFS string) { t.Run("LFS", func(t *testing.T) { defer PrintCurrentTest(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } prefix := "lfs-data-file-" err := git.NewCommand(git.DefaultContext, "lfs").AddArguments("install").Run(&git.RunOpts{Dir: dstPath}) assert.NoError(t, err) @@ -226,7 +221,6 @@ func rawTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS s resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - git.CheckLFSVersion() if setting.LFS.StartServer { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/raw/branch/master/", littleLFS)) resp := session.MakeRequest(t, req, http.StatusOK) @@ -268,12 +262,9 @@ func mediaTest(t *testing.T, ctx *APITestContext, little, big, littleLFS, bigLFS resp := session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) assert.Equal(t, littleSize, resp.Length) - git.CheckLFSVersion() - if setting.LFS.StartServer { - req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) - resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) - assert.Equal(t, littleSize, resp.Length) - } + req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", littleLFS)) + resp = session.MakeRequestNilResponseRecorder(t, req, http.StatusOK) + assert.Equal(t, littleSize, resp.Length) if !testing.Short() { req = NewRequest(t, "GET", path.Join("/", username, reponame, "/media/branch/master/", big)) @@ -763,7 +754,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB pr1 = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ HeadRepoID: repo.ID, Flow: issues_model.PullRequestFlowAGit, - }).(*issues_model.PullRequest) + }) if !assert.NotEmpty(t, pr1) { return } @@ -785,7 +776,7 @@ func doCreateAgitFlowPull(dstPath string, ctx *APITestContext, baseBranch, headB HeadRepoID: repo.ID, Index: pr1.Index + 1, Flow: issues_model.PullRequestFlowAGit, - }).(*issues_model.PullRequest) + }) if !assert.NotEmpty(t, pr2) { return } diff --git a/integrations/gpg_git_test.go b/integrations/gpg_git_test.go index 461f3c503d55..6edce606f2ba 100644 --- a/integrations/gpg_git_test.go +++ b/integrations/gpg_git_test.go @@ -61,7 +61,7 @@ func TestGPGGit(t *testing.T) { setting.Repository.Signing.SigningKey = rootKeyID setting.Repository.Signing.SigningName = "gitea" setting.Repository.Signing.SigningEmail = "gitea@fake.local" - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: username}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: username}) setting.Repository.Signing.InitialCommit = []string{"never"} setting.Repository.Signing.CRUDActions = []string{"never"} diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 230f780175c9..3c379f5c84ef 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -175,10 +175,9 @@ func initIntegrationTest() { setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master" _ = util.RemoveAll(repo_module.LocalCopyPath()) - if err := git.InitOnceWithSync(context.Background()); err != nil { + if err := git.InitFull(context.Background()); err != nil { log.Fatal("git.InitOnceWithSync: %v", err) } - git.CheckLFSVersion() setting.InitDBConfig() if err := storage.Init(); err != nil { @@ -285,7 +284,6 @@ func prepareTestEnv(t testing.TB, skip ...int) func() { assert.NoError(t, unittest.LoadFixtures()) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) - assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) @@ -586,7 +584,6 @@ func resetFixtures(t *testing.T) { assert.NoError(t, unittest.LoadFixtures()) assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) - assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 7d30d657f558..4bbb4744eae9 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -41,7 +41,7 @@ func getIssue(t *testing.T, repoID int64, issueSelection *goquery.Selection) *is indexStr := href[strings.LastIndexByte(href, '/')+1:] index, err := strconv.Atoi(indexStr) assert.NoError(t, err, "Invalid issue href: %s", href) - return unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repoID, Index: int64(index)}).(*issues_model.Issue) + return unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: repoID, Index: int64(index)}) } func assertMatch(t testing.TB, issue *issues_model.Issue, keyword string) { @@ -66,8 +66,8 @@ func TestNoLoginViewIssues(t *testing.T) { func TestViewIssuesSortByType(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) session := loginUser(t, user.Name) req := NewRequest(t, "GET", repo.Link()+"/issues?type=created_by") @@ -94,11 +94,11 @@ func TestViewIssuesSortByType(t *testing.T) { func TestViewIssuesKeyword(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ RepoID: repo.ID, Index: 1, - }).(*issues_model.Issue) + }) issues.UpdateIssueIndexer(issue) time.Sleep(time.Second * 1) const keyword = "first" @@ -356,17 +356,17 @@ func TestSearchIssues(t *testing.T) { session := loginUser(t, "user2") + expectedIssueCount := 15 // from the fixtures + if expectedIssueCount > setting.UI.IssuePagingNum { + expectedIssueCount = setting.UI.IssuePagingNum + } + link, _ := url.Parse("/issues/search") req := NewRequest(t, "GET", link.String()) resp := session.MakeRequest(t, req, http.StatusOK) var apiIssues []*api.Issue DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 10) - - req = NewRequest(t, "GET", link.String()) - resp = session.MakeRequest(t, req, http.StatusOK) - DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 10) + assert.Len(t, apiIssues, expectedIssueCount) since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801 before := time.Unix(999307200, 0).Format(time.RFC3339) @@ -394,14 +394,15 @@ func TestSearchIssues(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count")) - assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit + assert.Len(t, apiIssues, 17) - query.Add("limit", "20") + query.Add("limit", "5") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 17) + assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count")) + assert.Len(t, apiIssues, 5) query = url.Values{"assigned": {"true"}, "state": {"all"}} link.RawQuery = query.Encode() @@ -449,29 +450,26 @@ func TestSearchIssues(t *testing.T) { func TestSearchIssuesWithLabels(t *testing.T) { defer prepareTestEnv(t)() - token := getUserToken(t, "user1") + expectedIssueCount := 15 // from the fixtures + if expectedIssueCount > setting.UI.IssuePagingNum { + expectedIssueCount = setting.UI.IssuePagingNum + } - link, _ := url.Parse("/api/v1/repos/issues/search?token=" + token) - req := NewRequest(t, "GET", link.String()) - resp := MakeRequest(t, req, http.StatusOK) + session := loginUser(t, "user1") + link, _ := url.Parse("/issues/search") + query := url.Values{} var apiIssues []*api.Issue - DecodeJSON(t, resp, &apiIssues) - - assert.Len(t, apiIssues, 10) - query := url.Values{ - "token": []string{token}, - } link.RawQuery = query.Encode() - req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + req := NewRequest(t, "GET", link.String()) + resp := session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 10) + assert.Len(t, apiIssues, expectedIssueCount) query.Add("labels", "label1") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.Len(t, apiIssues, 2) @@ -479,7 +477,7 @@ func TestSearchIssuesWithLabels(t *testing.T) { query.Set("labels", "label1,label2") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.Len(t, apiIssues, 2) @@ -487,7 +485,7 @@ func TestSearchIssuesWithLabels(t *testing.T) { query.Set("labels", "orglabel4") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.Len(t, apiIssues, 1) @@ -496,7 +494,7 @@ func TestSearchIssuesWithLabels(t *testing.T) { query.Add("state", "all") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.Len(t, apiIssues, 2) @@ -504,7 +502,7 @@ func TestSearchIssuesWithLabels(t *testing.T) { query.Set("labels", "label1,orglabel4") link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) - resp = MakeRequest(t, req, http.StatusOK) + resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) assert.Len(t, apiIssues, 2) } @@ -512,9 +510,9 @@ func TestSearchIssuesWithLabels(t *testing.T) { func TestGetIssueInfo(t *testing.T) { defer prepareTestEnv(t)() - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) assert.NoError(t, issue.LoadAttributes(db.DefaultContext)) assert.Equal(t, int64(1019307200), int64(issue.DeadlineUnix)) assert.Equal(t, api.StateOpen, issue.State()) @@ -533,9 +531,9 @@ func TestGetIssueInfo(t *testing.T) { func TestUpdateIssueDeadline(t *testing.T) { defer prepareTestEnv(t)() - issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}).(*issues_model.Issue) - repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + issueBefore := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 10}) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) assert.NoError(t, issueBefore.LoadAttributes(db.DefaultContext)) assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) assert.Equal(t, api.StateOpen, issueBefore.State()) diff --git a/integrations/lfs_getobject_test.go b/integrations/lfs_getobject_test.go index 4b6bb140d3ad..14a8ac253e2c 100644 --- a/integrations/lfs_getobject_test.go +++ b/integrations/lfs_getobject_test.go @@ -14,7 +14,6 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/setting" @@ -83,11 +82,6 @@ func checkResponseTestContentEncoding(t *testing.T, content *[]byte, resp *httpt func TestGetLFSSmall(t *testing.T) { defer prepareTestEnv(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } content := []byte("A very small file\n") resp := storeAndGetLfs(t, &content, nil, http.StatusOK) @@ -96,11 +90,6 @@ func TestGetLFSSmall(t *testing.T) { func TestGetLFSLarge(t *testing.T) { defer prepareTestEnv(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } content := make([]byte, web.GzipMinSize*10) for i := range content { content[i] = byte(i % 256) @@ -112,11 +101,6 @@ func TestGetLFSLarge(t *testing.T) { func TestGetLFSGzip(t *testing.T) { defer prepareTestEnv(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } b := make([]byte, web.GzipMinSize*10) for i := range b { b[i] = byte(i % 256) @@ -133,11 +117,6 @@ func TestGetLFSGzip(t *testing.T) { func TestGetLFSZip(t *testing.T) { defer prepareTestEnv(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } b := make([]byte, web.GzipMinSize*10) for i := range b { b[i] = byte(i % 256) @@ -156,11 +135,6 @@ func TestGetLFSZip(t *testing.T) { func TestGetLFSRangeNo(t *testing.T) { defer prepareTestEnv(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } content := []byte("123456789\n") resp := storeAndGetLfs(t, &content, nil, http.StatusOK) @@ -169,11 +143,6 @@ func TestGetLFSRangeNo(t *testing.T) { func TestGetLFSRange(t *testing.T) { defer prepareTestEnv(t)() - git.CheckLFSVersion() - if !setting.LFS.StartServer { - t.Skip() - return - } content := []byte("123456789\n") tests := []struct { diff --git a/integrations/migrate_test.go b/integrations/migrate_test.go index f67e4ed2297d..d16f74ab6df2 100644 --- a/integrations/migrate_test.go +++ b/integrations/migrate_test.go @@ -24,7 +24,7 @@ import ( func TestMigrateLocalPath(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}).(*user_model.User) + adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}) old := setting.ImportLocalPaths setting.ImportLocalPaths = true @@ -62,7 +62,7 @@ func TestMigrateGiteaForm(t *testing.T) { ownerName := "user2" repoName := "repo1" - repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: ownerName}).(*user_model.User) + repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: ownerName}) session := loginUser(t, ownerName) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index 20a5c903a92c..80093d66f1ed 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -82,8 +82,7 @@ func initMigrationTest(t *testing.T) func() { } } - assert.NoError(t, git.InitOnceWithSync(context.Background())) - git.CheckLFSVersion() + assert.NoError(t, git.InitFull(context.Background())) setting.InitDBConfig() setting.NewLogServices(true) return deferFn diff --git a/integrations/mirror_pull_test.go b/integrations/mirror_pull_test.go index 8f74d5fe16d6..3a45fa7cc20f 100644 --- a/integrations/mirror_pull_test.go +++ b/integrations/mirror_pull_test.go @@ -24,8 +24,8 @@ import ( func TestMirrorPull(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repoPath := repo_model.RepoPath(user.Name, repo.Name) opts := migration.MigrateOptions{ diff --git a/integrations/mirror_push_test.go b/integrations/mirror_push_test.go index 3a22b0075423..5a226c5a92f9 100644 --- a/integrations/mirror_push_test.go +++ b/integrations/mirror_push_test.go @@ -36,8 +36,8 @@ func testMirrorPush(t *testing.T, u *url.URL) { setting.Migrations.AllowLocalNetworks = true assert.NoError(t, migrations.Init()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - srcRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + srcRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) mirrorRepo, err := repository.CreateRepository(user, user, models.CreateRepoOptions{ Name: "test-push-mirror", diff --git a/integrations/org_count_test.go b/integrations/org_count_test.go index eca51eb0f622..2bffa90034a8 100644 --- a/integrations/org_count_test.go +++ b/integrations/org_count_test.go @@ -115,7 +115,7 @@ func doCheckOrgCounts(username string, orgCounts map[string]int, strict bool, ca return func(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ Name: username, - }).(*user_model.User) + }) orgs, err := organization.FindOrgs(organization.FindOrgOptions{ UserID: user.ID, diff --git a/integrations/org_test.go b/integrations/org_test.go index d787e6f79100..e4677f58de76 100644 --- a/integrations/org_test.go +++ b/integrations/org_test.go @@ -197,8 +197,8 @@ func TestOrgRestrictedUser(t *testing.T) { func TestTeamSearch(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) var results TeamSearchResults @@ -213,7 +213,7 @@ func TestTeamSearch(t *testing.T) { assert.Equal(t, "test_team", results.Data[0].Name) // no access if not organization member - user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) session = loginUser(t, user5.Name) csrf = GetCSRF(t, session, "/"+org.Name) req = NewRequestf(t, "GET", "/org/%s/teams/-/search?q=%s", org.Name, "team") diff --git a/integrations/privateactivity_test.go b/integrations/privateactivity_test.go index c5cdc27d6e07..8e6a538c59ab 100644 --- a/integrations/privateactivity_test.go +++ b/integrations/privateactivity_test.go @@ -29,8 +29,8 @@ const privateActivityTestOtherUser = "user4" // activity helpers func testPrivateActivityDoSomethingForActionEntries(t *testing.T) { - repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}) session := loginUser(t, privateActivityTestUser) token := getTokenForLoggedInUser(t, session) diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index 2a3a461efd12..13c2ff973a13 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -228,18 +228,18 @@ func TestCantMergeConflict(t *testing.T) { // Now this PR will be marked conflict - or at least a race will do - so drop down to pure code at this point... user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ Name: "user1", - }).(*user_model.User) + }) repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ OwnerID: user1.ID, Name: "repo1", - }).(*repo_model.Repository) + }) pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ HeadRepoID: repo1.ID, BaseRepoID: repo1.ID, HeadBranch: "conflict", BaseBranch: "base", - }).(*issues_model.PullRequest) + }) gitRepo, err := git.OpenRepository(git.DefaultContext, repo_model.RepoPath(user1.Name, repo1.Name)) assert.NoError(t, err) @@ -265,11 +265,11 @@ func TestCantMergeUnrelated(t *testing.T) { // Drop down to pure code at this point user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ Name: "user1", - }).(*user_model.User) + }) repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ OwnerID: user1.ID, Name: "repo1", - }).(*repo_model.Repository) + }) path := repo_model.RepoPath(user1.Name, repo1.Name) err := git.NewCommand(git.DefaultContext, "read-tree", "--empty").Run(&git.RunOpts{Dir: path}) @@ -341,7 +341,7 @@ func TestCantMergeUnrelated(t *testing.T) { BaseRepoID: repo1.ID, HeadBranch: "unrelated", BaseBranch: "base", - }).(*issues_model.PullRequest) + }) err = pull.Merge(context.Background(), pr, user1, gitRepo, repo_model.MergeStyleMerge, "", "UNRELATED") assert.Error(t, err, "Merge should return an error due to unrelated") @@ -352,7 +352,7 @@ func TestCantMergeUnrelated(t *testing.T) { func TestConflictChecking(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Create new clean repo to test conflict checking. baseRepo, err := repo_service.CreateRepository(user, user, models.CreateRepoOptions{ @@ -408,7 +408,7 @@ func TestConflictChecking(t *testing.T) { err = pull.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil) assert.NoError(t, err) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "PR with conflict!"}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "PR with conflict!"}) conflictingPR, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) diff --git a/integrations/pull_status_test.go b/integrations/pull_status_test.go index 33a27cd81275..d38d90169bff 100644 --- a/integrations/pull_status_test.go +++ b/integrations/pull_status_test.go @@ -56,11 +56,11 @@ func TestPullCreate_CommitStatus(t *testing.T) { } statesIcons := map[api.CommitStatusState]string{ - api.CommitStatusPending: "circle icon yellow", - api.CommitStatusSuccess: "check icon green", - api.CommitStatusError: "warning icon red", - api.CommitStatusFailure: "remove icon red", - api.CommitStatusWarning: "warning sign icon yellow", + api.CommitStatusPending: "octicon-dot-fill", + api.CommitStatusSuccess: "octicon-check", + api.CommitStatusError: "gitea-exclamation", + api.CommitStatusFailure: "octicon-x", + api.CommitStatusWarning: "gitea-exclamation", } testCtx := NewAPITestContext(t, "user1", "repo1") @@ -80,9 +80,9 @@ func TestPullCreate_CommitStatus(t *testing.T) { assert.NotEmpty(t, commitURL) assert.EqualValues(t, commitID, path.Base(commitURL)) - cls, ok := doc.doc.Find("#commits-table tbody tr td.message i.commit-status").Last().Attr("class") + cls, ok := doc.doc.Find("#commits-table tbody tr td.message .commit-status").Last().Attr("class") assert.True(t, ok) - assert.EqualValues(t, "commit-status "+statesIcons[status], cls) + assert.Contains(t, cls, statesIcons[status]) } }) } diff --git a/integrations/pull_update_test.go b/integrations/pull_update_test.go index 47ada91e1a08..056d06189a79 100644 --- a/integrations/pull_update_test.go +++ b/integrations/pull_update_test.go @@ -26,8 +26,8 @@ import ( func TestAPIPullUpdate(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { // Create PR to test - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}) pr := createOutdatedPR(t, user, org26) // Test GetDiverging @@ -54,8 +54,8 @@ func TestAPIPullUpdate(t *testing.T) { func TestAPIPullUpdateByRebase(t *testing.T) { onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) { // Create PR to test - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + org26 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 26}) pr := createOutdatedPR(t, user, org26) // Test GetDiverging @@ -166,7 +166,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *issues_mod err = pull_service.NewPullRequest(git.DefaultContext, baseRepo, pullIssue, nil, nil, pullRequest, nil) assert.NoError(t, err) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "Test Pull -to-update-"}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: "Test Pull -to-update-"}) pr, err := issues_model.GetPullRequestByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) diff --git a/integrations/release_test.go b/integrations/release_test.go index dd32a64ed5c7..5c6290422d40 100644 --- a/integrations/release_test.go +++ b/integrations/release_test.go @@ -134,7 +134,7 @@ func TestCreateReleasePaging(t *testing.T) { func TestViewReleaseListNoLogin(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) link := repo.Link() + "/releases" @@ -160,7 +160,7 @@ func TestViewReleaseListNoLogin(t *testing.T) { func TestViewReleaseListLogin(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) link := repo.Link() + "/releases" @@ -191,7 +191,7 @@ func TestViewReleaseListLogin(t *testing.T) { func TestViewTagsList(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) link := repo.Link() + "/tags" diff --git a/integrations/rename_branch_test.go b/integrations/rename_branch_test.go index 7760a2d946c4..ad27869cde04 100644 --- a/integrations/rename_branch_test.go +++ b/integrations/rename_branch_test.go @@ -40,6 +40,6 @@ func TestRenameBranch(t *testing.T) { assert.Equal(t, "/user2/repo1/src/branch/main/README.md", location) // check db - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Equal(t, "main", repo1.DefaultBranch) } diff --git a/integrations/repo_commits_test.go b/integrations/repo_commits_test.go index 7107f43b0fed..b18b35da1e65 100644 --- a/integrations/repo_commits_test.go +++ b/integrations/repo_commits_test.go @@ -55,7 +55,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) { doc = NewHTMLParser(t, resp.Body) // Check if commit status is displayed in message column - sel := doc.doc.Find("#commits-table tbody tr td.message a.commit-statuses-trigger i.commit-status") + sel := doc.doc.Find("#commits-table tbody tr td.message a.commit-statuses-trigger .commit-status") assert.Equal(t, 1, sel.Length()) for _, class := range classes { assert.True(t, sel.HasClass(class)) @@ -96,21 +96,21 @@ func testRepoCommitsWithStatus(t *testing.T, resp, respOne *httptest.ResponseRec } func TestRepoCommitsWithStatusPending(t *testing.T) { - doTestRepoCommitWithStatus(t, "pending", "circle", "yellow") + doTestRepoCommitWithStatus(t, "pending", "octicon-dot-fill", "yellow") } func TestRepoCommitsWithStatusSuccess(t *testing.T) { - doTestRepoCommitWithStatus(t, "success", "check", "green") + doTestRepoCommitWithStatus(t, "success", "octicon-check", "green") } func TestRepoCommitsWithStatusError(t *testing.T) { - doTestRepoCommitWithStatus(t, "error", "warning", "red") + doTestRepoCommitWithStatus(t, "error", "gitea-exclamation", "red") } func TestRepoCommitsWithStatusFailure(t *testing.T) { - doTestRepoCommitWithStatus(t, "failure", "remove", "red") + doTestRepoCommitWithStatus(t, "failure", "octicon-x", "red") } func TestRepoCommitsWithStatusWarning(t *testing.T) { - doTestRepoCommitWithStatus(t, "warning", "warning", "sign", "yellow") + doTestRepoCommitWithStatus(t, "warning", "gitea-exclamation", "yellow") } diff --git a/integrations/repo_fork_test.go b/integrations/repo_fork_test.go index 5f28e66ac8ba..17133621d650 100644 --- a/integrations/repo_fork_test.go +++ b/integrations/repo_fork_test.go @@ -17,7 +17,7 @@ import ( ) func testRepoFork(t *testing.T, session *TestSession, ownerName, repoName, forkOwnerName, forkRepoName string) *httptest.ResponseRecorder { - forkOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: forkOwnerName}).(*user_model.User) + forkOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: forkOwnerName}) // Step0: check the existence of the to-fork repo req := NewRequestf(t, "GET", "/%s/%s", forkOwnerName, forkRepoName) diff --git a/integrations/repo_generate_test.go b/integrations/repo_generate_test.go index 0123932a749b..d34983f528df 100644 --- a/integrations/repo_generate_test.go +++ b/integrations/repo_generate_test.go @@ -17,7 +17,7 @@ import ( ) func testRepoGenerate(t *testing.T, session *TestSession, templateOwnerName, templateRepoName, generateOwnerName, generateRepoName string) *httptest.ResponseRecorder { - generateOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: generateOwnerName}).(*user_model.User) + generateOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: generateOwnerName}) // Step0: check the existence of the generated repo req := NewRequestf(t, "GET", "/%s/%s", generateOwnerName, generateRepoName) diff --git a/integrations/repo_tag_test.go b/integrations/repo_tag_test.go index 793cf724ebff..1b3e30106bf8 100644 --- a/integrations/repo_tag_test.go +++ b/integrations/repo_tag_test.go @@ -24,8 +24,8 @@ import ( func TestCreateNewTagProtected(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) t.Run("API", func(t *testing.T) { defer PrintCurrentTest(t)() diff --git a/integrations/repo_test.go b/integrations/repo_test.go index 872d3f24d1f7..c2ac6183f045 100644 --- a/integrations/repo_test.go +++ b/integrations/repo_test.go @@ -64,7 +64,7 @@ func testViewRepo(t *testing.T) { } }) - f.commitTime, _ = s.Find("span.time-since").Attr("title") + f.commitTime, _ = s.Find("span.time-since").Attr("data-content") items = append(items, f) }) diff --git a/integrations/signin_test.go b/integrations/signin_test.go index 952efcfdd9d6..568ceb40ca5d 100644 --- a/integrations/signin_test.go +++ b/integrations/signin_test.go @@ -34,7 +34,7 @@ func testLoginFailed(t *testing.T, username, password, message string) { func TestSignin(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // add new user with user2's email user.Name = "testuser" diff --git a/integrations/signup_test.go b/integrations/signup_test.go index b34e40f28699..071ece9fa16c 100644 --- a/integrations/signup_test.go +++ b/integrations/signup_test.go @@ -54,7 +54,7 @@ func TestSignupAsRestricted(t *testing.T) { req = NewRequest(t, "GET", "/restrictedUser") MakeRequest(t, req, http.StatusOK) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "restrictedUser"}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "restrictedUser"}) assert.True(t, user2.IsRestricted) } diff --git a/integrations/user_avatar_test.go b/integrations/user_avatar_test.go index 2bf6fde5ff1d..ee532bb64a27 100644 --- a/integrations/user_avatar_test.go +++ b/integrations/user_avatar_test.go @@ -22,7 +22,7 @@ import ( func TestUserAvatar(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo3, is an org + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org seed := user2.Email if len(seed) == 0 { @@ -72,7 +72,7 @@ func TestUserAvatar(t *testing.T) { session.MakeRequest(t, req, http.StatusSeeOther) - user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) // owner of the repo3, is an org + user2 = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // owner of the repo3, is an org req = NewRequest(t, "GET", user2.AvatarLinkWithSize(0)) _ = session.MakeRequest(t, req, http.StatusOK) diff --git a/integrations/user_test.go b/integrations/user_test.go index 33113369a749..b0c1cd42ebe3 100644 --- a/integrations/user_test.go +++ b/integrations/user_test.go @@ -229,16 +229,16 @@ func testExportUserGPGKeys(t *testing.T, user, expected string) { func TestListStopWatches(t *testing.T) { defer prepareTestEnv(t)() - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) session := loginUser(t, owner.Name) req := NewRequestf(t, "GET", "/user/stopwatches") resp := session.MakeRequest(t, req, http.StatusOK) var apiWatches []*api.StopWatch DecodeJSON(t, resp, &apiWatches) - stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID}).(*issues_model.Stopwatch) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID}).(*issues_model.Issue) + stopwatch := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: owner.ID}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: stopwatch.IssueID}) if assert.Len(t, apiWatches, 1) { assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix()) assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex) diff --git a/integrations/webfinger_test.go b/integrations/webfinger_test.go index 07bf58b509fe..3574941e4216 100644 --- a/integrations/webfinger_test.go +++ b/integrations/webfinger_test.go @@ -25,7 +25,7 @@ func TestWebfinger(t *testing.T) { setting.Federation.Enabled = false }() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) appURL, _ := url.Parse(setting.AppURL) diff --git a/integrations/xss_test.go b/integrations/xss_test.go index 1ce25e1bf5c3..d5ce94b0c6cc 100644 --- a/integrations/xss_test.go +++ b/integrations/xss_test.go @@ -16,7 +16,7 @@ import ( func TestXSSUserFullName(t *testing.T) { defer prepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) const fullName = `name & ` session := loginUser(t, user.Name) diff --git a/main.go b/main.go index ac60f85a6680..0e550f05ebca 100644 --- a/main.go +++ b/main.go @@ -171,9 +171,9 @@ func setAppHelpTemplates() { } func adjustHelpTemplate(originalTemplate string) string { - overrided := "" + overridden := "" if _, ok := os.LookupEnv("GITEA_CUSTOM"); ok { - overrided = "(GITEA_CUSTOM)" + overridden = "(GITEA_CUSTOM)" } return fmt.Sprintf(`%s @@ -183,7 +183,7 @@ DEFAULT CONFIGURATION: AppPath: %s AppWorkPath: %s -`, originalTemplate, setting.CustomPath, overrided, setting.CustomConf, setting.AppPath, setting.AppWorkPath) +`, originalTemplate, setting.CustomPath, overridden, setting.CustomConf, setting.AppPath, setting.AppWorkPath) } func formatBuiltWith() string { diff --git a/models/action_test.go b/models/action_test.go index 2d46bd3e80e1..5c61736a6150 100644 --- a/models/action_test.go +++ b/models/action_test.go @@ -19,16 +19,16 @@ import ( func TestAction_GetRepoPath(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) action := &Action{RepoID: repo.ID} assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath()) } func TestAction_GetRepoLink(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) action := &Action{RepoID: repo.ID} setting.AppSubURL = "/suburl" expected := path.Join(setting.AppSubURL, owner.Name, repo.Name) @@ -38,7 +38,7 @@ func TestAction_GetRepoLink(t *testing.T) { func TestGetFeeds(t *testing.T) { // test with an individual user assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: user, @@ -65,9 +65,9 @@ func TestGetFeeds(t *testing.T) { func TestGetFeedsForRepos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}) // private repo & no login actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ @@ -107,8 +107,8 @@ func TestGetFeedsForRepos(t *testing.T) { func TestGetFeeds2(t *testing.T) { // test with an organization user assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{ RequestedUser: org, @@ -214,7 +214,7 @@ func TestNotifyWatchers(t *testing.T) { func TestGetFeedsCorrupted(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) unittest.AssertExistsAndLoadBean(t, &Action{ ID: 8, RepoID: 1700, diff --git a/models/asymkey/gpg_key_test.go b/models/asymkey/gpg_key_test.go index 07bb77bdf468..2cee45d98f75 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -196,7 +196,7 @@ Unknown GPG key with good email func TestCheckGPGUserEmail(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) testEmailWithUpperCaseLetters := `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index 5a58ec62b7d1..ad1d80e25a85 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -512,10 +512,14 @@ func GetActiveOAuth2ProviderSources() ([]*Source, error) { func GetActiveOAuth2SourceByName(name string) (*Source, error) { authSource := new(Source) has, err := db.GetEngine(db.DefaultContext).Where("name = ? and type = ? and is_active = ?", name, OAuth2, true).Get(authSource) - if !has || err != nil { + if err != nil { return nil, err } + if !has { + return nil, fmt.Errorf("oauth2 source not found, name: %q", name) + } + return authSource, nil } diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go index cb8c4aeb6aa5..2a74f3999801 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -17,7 +17,7 @@ import ( func TestOAuth2Application_GenerateClientSecret(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application) + app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}) secret, err := app.GenerateClientSecret() assert.NoError(t, err) assert.True(t, len(secret) > 0) @@ -26,7 +26,7 @@ func TestOAuth2Application_GenerateClientSecret(t *testing.T) { func BenchmarkOAuth2Application_GenerateClientSecret(b *testing.B) { assert.NoError(b, unittest.PrepareTestDatabase()) - app := unittest.AssertExistsAndLoadBean(b, &OAuth2Application{ID: 1}).(*OAuth2Application) + app := unittest.AssertExistsAndLoadBean(b, &OAuth2Application{ID: 1}) for i := 0; i < b.N; i++ { _, _ = app.GenerateClientSecret() } @@ -44,7 +44,7 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) { func TestOAuth2Application_ValidateClientSecret(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application) + app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}) secret, err := app.GenerateClientSecret() assert.NoError(t, err) assert.True(t, app.ValidateClientSecret([]byte(secret))) @@ -77,7 +77,7 @@ func TestOAuth2Application_TableName(t *testing.T) { func TestOAuth2Application_GetGrantByUserID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application) + app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}) grant, err := app.GetGrantByUserID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, int64(1), grant.UserID) @@ -89,7 +89,7 @@ func TestOAuth2Application_GetGrantByUserID(t *testing.T) { func TestOAuth2Application_CreateGrant(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application) + app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}) grant, err := app.CreateGrant(db.DefaultContext, 2, "") assert.NoError(t, err) assert.NotNil(t, grant) @@ -113,7 +113,7 @@ func TestGetOAuth2GrantByID(t *testing.T) { func TestOAuth2Grant_IncreaseCounter(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 1}).(*OAuth2Grant) + grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 1}) assert.NoError(t, grant.IncreaseCounter(db.DefaultContext)) assert.Equal(t, int64(2), grant.Counter) unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 2}) @@ -121,7 +121,7 @@ func TestOAuth2Grant_IncreaseCounter(t *testing.T) { func TestOAuth2Grant_ScopeContains(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Scope: "openid profile"}).(*OAuth2Grant) + grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Scope: "openid profile"}) assert.True(t, grant.ScopeContains("openid")) assert.True(t, grant.ScopeContains("profile")) assert.False(t, grant.ScopeContains("profil")) @@ -130,7 +130,7 @@ func TestOAuth2Grant_ScopeContains(t *testing.T) { func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1}).(*OAuth2Grant) + grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1}) code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256") assert.NoError(t, err) assert.NotNil(t, code) @@ -224,7 +224,7 @@ func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) { func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - code := unittest.AssertExistsAndLoadBean(t, &OAuth2AuthorizationCode{Code: "authcode"}).(*OAuth2AuthorizationCode) + code := unittest.AssertExistsAndLoadBean(t, &OAuth2AuthorizationCode{Code: "authcode"}) assert.NoError(t, code.Invalidate(db.DefaultContext)) unittest.AssertNotExistsBean(t, &OAuth2AuthorizationCode{Code: "authcode"}) } diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go index cc39691ce2d3..edbb7ecd5b4e 100644 --- a/models/auth/webauthn_test.go +++ b/models/auth/webauthn_test.go @@ -40,7 +40,7 @@ func TestWebAuthnCredential_TableName(t *testing.T) { func TestWebAuthnCredential_UpdateSignCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1}).(*WebAuthnCredential) + cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1}) cred.SignCount = 1 assert.NoError(t, cred.UpdateSignCount()) unittest.AssertExistsIf(t, true, &WebAuthnCredential{ID: 1, SignCount: 1}) @@ -48,7 +48,7 @@ func TestWebAuthnCredential_UpdateSignCount(t *testing.T) { func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1}).(*WebAuthnCredential) + cred := unittest.AssertExistsAndLoadBean(t, &WebAuthnCredential{ID: 1}) cred.SignCount = 0xffffffff assert.NoError(t, cred.UpdateSignCount()) unittest.AssertExistsIf(t, true, &WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) diff --git a/models/db/iterate.go b/models/db/iterate.go new file mode 100644 index 000000000000..3d4fa06eeb96 --- /dev/null +++ b/models/db/iterate.go @@ -0,0 +1,34 @@ +// 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 db + +import ( + "context" + + "code.gitea.io/gitea/modules/setting" +) + +// IterateObjects iterate all the Bean object +func IterateObjects[Object any](ctx context.Context, f func(repo *Object) error) error { + var start int + batchSize := setting.Database.IterateBufferSize + sess := GetEngine(ctx) + for { + repos := make([]*Object, 0, batchSize) + if err := sess.Limit(batchSize, start).Find(&repos); err != nil { + return err + } + if len(repos) == 0 { + return nil + } + start += len(repos) + + for _, repo := range repos { + if err := f(repo); err != nil { + return err + } + } + } +} diff --git a/models/git/branches_test.go b/models/git/branches_test.go index 8102d28d484b..58c4ad027be1 100644 --- a/models/git/branches_test.go +++ b/models/git/branches_test.go @@ -18,8 +18,8 @@ import ( func TestAddDeletedBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}).(*git_model.DeletedBranch) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}) assert.Error(t, git_model.AddDeletedBranch(repo.ID, firstBranch.Name, firstBranch.Commit, firstBranch.DeletedByID)) assert.NoError(t, git_model.AddDeletedBranch(repo.ID, "test", "5655464564554545466464656", int64(1))) @@ -27,7 +27,7 @@ func TestAddDeletedBranch(t *testing.T) { func TestGetDeletedBranches(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) branches, err := git_model.GetDeletedBranches(repo.ID) assert.NoError(t, err) @@ -36,7 +36,7 @@ func TestGetDeletedBranches(t *testing.T) { func TestGetDeletedBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}).(*git_model.DeletedBranch) + firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}) assert.NotNil(t, getDeletedBranch(t, firstBranch)) } @@ -44,8 +44,8 @@ func TestGetDeletedBranch(t *testing.T) { func TestDeletedBranchLoadUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}).(*git_model.DeletedBranch) - secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 2}).(*git_model.DeletedBranch) + firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}) + secondBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 2}) branch := getDeletedBranch(t, firstBranch) assert.Nil(t, branch.DeletedBy) @@ -62,9 +62,9 @@ func TestDeletedBranchLoadUser(t *testing.T) { func TestRemoveDeletedBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}).(*git_model.DeletedBranch) + firstBranch := unittest.AssertExistsAndLoadBean(t, &git_model.DeletedBranch{ID: 1}) err := git_model.RemoveDeletedBranchByID(repo.ID, 1) assert.NoError(t, err) @@ -73,7 +73,7 @@ func TestRemoveDeletedBranch(t *testing.T) { } func getDeletedBranch(t *testing.T, branch *git_model.DeletedBranch) *git_model.DeletedBranch { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) deletedBranch, err := git_model.GetDeletedBranchByID(repo.ID, branch.ID) assert.NoError(t, err) @@ -99,7 +99,7 @@ func TestFindRenamedBranch(t *testing.T) { func TestRenameBranch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) _isDefault := false ctx, committer, err := db.TxContext() @@ -117,16 +117,16 @@ func TestRenameBranch(t *testing.T) { })) assert.Equal(t, true, _isDefault) - repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Equal(t, "main", repo1.DefaultBranch) - pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) // merged + pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) // merged assert.Equal(t, "master", pull.BaseBranch) - pull = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) // open + pull = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) // open assert.Equal(t, "main", pull.BaseBranch) - renamedBranch := unittest.AssertExistsAndLoadBean(t, &git_model.RenamedBranch{ID: 2}).(*git_model.RenamedBranch) + renamedBranch := unittest.AssertExistsAndLoadBean(t, &git_model.RenamedBranch{ID: 2}) assert.Equal(t, "master", renamedBranch.From) assert.Equal(t, "main", renamedBranch.To) assert.Equal(t, int64(1), renamedBranch.RepoID) @@ -143,7 +143,7 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) { // Get deletedBranch with ID of 1 on repo with ID 2. // This should return a nil branch as this deleted branch // is actually on repo with ID 1. - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) deletedBranch, err := git_model.GetDeletedBranchByID(repo2.ID, 1) @@ -153,7 +153,7 @@ func TestOnlyGetDeletedBranchOnCorrectRepo(t *testing.T) { // Now get the deletedBranch with ID of 1 on repo with ID 1. // This should return the deletedBranch. - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) deletedBranch, err = git_model.GetDeletedBranchByID(repo1.ID, 1) diff --git a/models/git/commit_status_test.go b/models/git/commit_status_test.go index 991929743006..7b81b1549c22 100644 --- a/models/git/commit_status_test.go +++ b/models/git/commit_status_test.go @@ -19,7 +19,7 @@ import ( func TestGetCommitStatuses(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) sha1 := "1234123412341234123412341234123412341234" diff --git a/models/git/lfs.go b/models/git/lfs.go index ec963cf59358..179da3120ae1 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -278,29 +278,6 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6 return committer.Commit() } -// IterateLFS iterates lfs object -func IterateLFS(f func(mo *LFSMetaObject) error) error { - var start int - const batchSize = 100 - e := db.GetEngine(db.DefaultContext) - for { - mos := make([]*LFSMetaObject, 0, batchSize) - if err := e.Limit(batchSize, start).Find(&mos); err != nil { - return err - } - if len(mos) == 0 { - return nil - } - start += len(mos) - - for _, mo := range mos { - if err := f(mo); err != nil { - return err - } - } - } -} - // CopyLFS copies LFS data from one repo to another func CopyLFS(ctx context.Context, newRepo, oldRepo *repo_model.Repository) error { var lfsObjects []*LFSMetaObject diff --git a/models/issues/assignees_test.go b/models/issues/assignees_test.go index 37d966f140f7..291bb673da84 100644 --- a/models/issues/assignees_test.go +++ b/models/issues/assignees_test.go @@ -68,8 +68,8 @@ func TestUpdateAssignee(t *testing.T) { func TestMakeIDsFromAPIAssigneesToAdd(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + _ = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) IDs, err := issues_model.MakeIDsFromAPIAssigneesToAdd("", []string{""}) assert.NoError(t, err) diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index 06b0b85e3cff..f12da0177f86 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -20,9 +20,9 @@ import ( func TestCreateComment(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) now := time.Now().Unix() comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{ @@ -42,15 +42,15 @@ func TestCreateComment(t *testing.T) { unittest.AssertInt64InRange(t, now, then, int64(comment.CreatedUnix)) unittest.AssertExistsAndLoadBean(t, comment) // assert actually added to DB - updatedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID}).(*issues_model.Issue) + updatedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID}) unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix)) } func TestFetchCodeComments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) res, err := issues_model.FetchCodeComments(db.DefaultContext, issue, user) assert.NoError(t, err) assert.Contains(t, res, "README.md") @@ -58,7 +58,7 @@ func TestFetchCodeComments(t *testing.T) { assert.Len(t, res["README.md"][4], 1) assert.Equal(t, int64(4), res["README.md"][4][0].ID) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) res, err = issues_model.FetchCodeComments(db.DefaultContext, issue, user2) assert.NoError(t, err) assert.Len(t, res, 1) diff --git a/models/issues/issue_list_test.go b/models/issues/issue_list_test.go index 6b978f9ae602..f2cfca9bc0af 100644 --- a/models/issues/issue_list_test.go +++ b/models/issues/issue_list_test.go @@ -18,9 +18,9 @@ func TestIssueList_LoadRepositories(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) issueList := issues_model.IssueList{ - unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue), - unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue), - unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue), + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}), + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}), + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}), } repos, err := issueList.LoadRepositories() @@ -35,8 +35,8 @@ func TestIssueList_LoadAttributes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) setting.Service.EnableTimetracking = true issueList := issues_model.IssueList{ - unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue), - unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue), + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}), + unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}), } assert.NoError(t, issueList.LoadAttributes()) diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 019e578da874..bef5d03e8afa 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -29,13 +29,13 @@ func TestIssue_ReplaceLabels(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(issueID int64, labelIDs []int64) { - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID}).(*issues_model.Issue) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) labels := make([]*issues_model.Label, len(labelIDs)) for i, labelID := range labelIDs { - labels[i] = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID, RepoID: repo.ID}).(*issues_model.Label) + labels[i] = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID, RepoID: repo.ID}) } assert.NoError(t, issues_model.ReplaceIssueLabels(issue, labels, doer)) unittest.AssertCount(t, &issues_model.IssueLabel{IssueID: issueID}, len(labelIDs)) @@ -59,7 +59,7 @@ func Test_GetIssueIDsByRepoID(t *testing.T) { func TestIssueAPIURL(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) err := issue.LoadAttributes(db.DefaultContext) assert.NoError(t, err) @@ -117,8 +117,8 @@ func TestIssue_ClearLabels(t *testing.T) { } for _, test := range tests { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}).(*issues_model.Issue) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}) assert.NoError(t, issues_model.ClearIssueLabels(issue, doer)) unittest.AssertNotExistsBean(t, &issues_model.IssueLabel{IssueID: test.issueID}) } @@ -126,7 +126,7 @@ func TestIssue_ClearLabels(t *testing.T) { func TestUpdateIssueCols(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{}) const newTitle = "New Title for unit test" issue.Title = newTitle @@ -138,7 +138,7 @@ func TestUpdateIssueCols(t *testing.T) { assert.NoError(t, issues_model.UpdateIssueCols(db.DefaultContext, issue, "name")) then := time.Now().Unix() - updatedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID}).(*issues_model.Issue) + updatedIssue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue.ID}) assert.EqualValues(t, newTitle, updatedIssue.Title) assert.EqualValues(t, prevContent, updatedIssue.Content) unittest.AssertInt64InRange(t, now, then, int64(updatedIssue.UpdatedUnix)) @@ -291,8 +291,8 @@ func TestGetUserIssueStats(t *testing.T) { { issues_model.UserIssueStatsOptions{ UserID: 2, - Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization), - Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}).(*organization.Team), + Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}), + Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}), FilterMode: issues_model.FilterModeAll, }, issues_model.IssueStats{ @@ -347,7 +347,7 @@ func TestIssue_SearchIssueIDsByKeyword(t *testing.T) { func TestGetRepoIDsForIssuesOptions(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) for _, test := range []struct { Opts issues_model.IssuesOptions ExpectedRepoIDs []int64 @@ -378,8 +378,8 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) { func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *issues_model.Issue { var newIssue issues_model.Issue t.Run(title, func(t *testing.T) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) issue := issues_model.Issue{ RepoID: repo.ID, @@ -420,10 +420,10 @@ func TestIssue_ResolveMentions(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(owner, repo, doer string, mentions []string, expected []int64) { - o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}).(*user_model.User) - r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: o.ID, LowerName: repo}).(*repo_model.Repository) + o := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: owner}) + r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: o.ID, LowerName: repo}) issue := &issues_model.Issue{RepoID: r.ID} - d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}).(*user_model.User) + d := unittest.AssertExistsAndLoadBean(t, &user_model.User{LowerName: doer}) resolved, err := issues_model.ResolveIssueMentionsByVisibility(db.DefaultContext, issue, d, mentions) assert.NoError(t, err) ids := make([]int64, len(resolved)) @@ -504,7 +504,7 @@ func TestCorrectIssueStats(t *testing.T) { func TestIssueForeignReference(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}) assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive // it is fine for an issue to not have a foreign reference @@ -537,7 +537,7 @@ func TestIssueForeignReference(t *testing.T) { func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) miles := issues_model.MilestoneList{ - unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone), + unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}), } assert.NoError(t, miles.LoadTotalTrackedTimes()) @@ -547,7 +547,7 @@ func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) { func TestLoadTotalTrackedTime(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone) + milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) assert.NoError(t, milestone.LoadTotalTrackedTime()) diff --git a/models/issues/issue_user_test.go b/models/issues/issue_user_test.go index 33e9f98ecc43..7dd84ed68cdf 100644 --- a/models/issues/issue_user_test.go +++ b/models/issues/issue_user_test.go @@ -18,7 +18,7 @@ import ( func Test_NewIssueUsers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) newIssue := &issues_model.Issue{ RepoID: repo.ID, PosterID: 4, @@ -39,7 +39,7 @@ func Test_NewIssueUsers(t *testing.T) { func TestUpdateIssueUserByRead(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) assert.NoError(t, issues_model.UpdateIssueUserByRead(4, issue.ID)) unittest.AssertExistsAndLoadBean(t, &issues_model.IssueUser{IssueID: issue.ID, UID: 4}, "is_read=1") @@ -52,7 +52,7 @@ func TestUpdateIssueUserByRead(t *testing.T) { func TestUpdateIssueUsersByMentions(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) uids := []int64{2, 5} assert.NoError(t, issues_model.UpdateIssueUsersByMentions(db.DefaultContext, issue.ID, uids)) diff --git a/models/issues/issue_watch_test.go b/models/issues/issue_watch_test.go index c6b6416d9b32..7aaf9f7f5da5 100644 --- a/models/issues/issue_watch_test.go +++ b/models/issues/issue_watch_test.go @@ -18,11 +18,11 @@ func TestCreateOrUpdateIssueWatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(3, 1, true)) - iw := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 3, IssueID: 1}).(*issues_model.IssueWatch) + iw := unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 3, IssueID: 1}) assert.True(t, iw.IsWatching) assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(1, 1, false)) - iw = unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 1, IssueID: 1}).(*issues_model.IssueWatch) + iw = unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 1, IssueID: 1}) assert.False(t, iw.IsWatching) } diff --git a/models/issues/issue_xref_test.go b/models/issues/issue_xref_test.go index 6bb19d5328d5..af1c8bc68506 100644 --- a/models/issues/issue_xref_test.go +++ b/models/issues/issue_xref_test.go @@ -27,7 +27,7 @@ func TestXRef_AddCrossReferences(t *testing.T) { // PR to close issue #1 content := fmt.Sprintf("content2, closes #%d", itarget.Index) pr := testCreateIssue(t, 1, 2, "title2", content, true) - ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: 0}).(*issues_model.Comment) + ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: 0}) assert.Equal(t, issues_model.CommentTypePullRef, ref.Type) assert.Equal(t, pr.RepoID, ref.RefRepoID) assert.True(t, ref.RefIsPull) @@ -36,7 +36,7 @@ func TestXRef_AddCrossReferences(t *testing.T) { // Comment on PR to reopen issue #1 content = fmt.Sprintf("content2, reopens #%d", itarget.Index) c := testCreateComment(t, 1, 2, pr.ID, content) - ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID}).(*issues_model.Comment) + ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: pr.ID, RefCommentID: c.ID}) assert.Equal(t, issues_model.CommentTypeCommentRef, ref.Type) assert.Equal(t, pr.RepoID, ref.RefRepoID) assert.True(t, ref.RefIsPull) @@ -45,7 +45,7 @@ func TestXRef_AddCrossReferences(t *testing.T) { // Issue mentioning issue #1 content = fmt.Sprintf("content3, mentions #%d", itarget.Index) i := testCreateIssue(t, 1, 2, "title3", content, false) - ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment) + ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}) assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type) assert.Equal(t, pr.RepoID, ref.RefRepoID) assert.False(t, ref.RefIsPull) @@ -57,7 +57,7 @@ func TestXRef_AddCrossReferences(t *testing.T) { // Cross-reference to issue #4 by admin content = fmt.Sprintf("content5, mentions user3/repo3#%d", itarget.Index) i = testCreateIssue(t, 2, 1, "title5", content, false) - ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment) + ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}) assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type) assert.Equal(t, i.RepoID, ref.RefRepoID) assert.False(t, ref.RefIsPull) @@ -78,15 +78,15 @@ func TestXRef_NeuterCrossReferences(t *testing.T) { // Issue mentioning issue #1 title := fmt.Sprintf("title2, mentions #%d", itarget.Index) i := testCreateIssue(t, 1, 2, title, "content2", false) - ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment) + ref := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}) assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type) assert.Equal(t, references.XRefActionNone, ref.RefAction) - d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) i.Title = "title2, no mentions" assert.NoError(t, issues_model.ChangeIssueTitle(i, d, title)) - ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}).(*issues_model.Comment) + ref = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: itarget.ID, RefIssueID: i.ID, RefCommentID: 0}) assert.Equal(t, issues_model.CommentTypeIssueRef, ref.Type) assert.Equal(t, references.XRefActionNeutered, ref.RefAction) } @@ -94,7 +94,7 @@ func TestXRef_NeuterCrossReferences(t *testing.T) { func TestXRef_ResolveCrossReferences(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) i1 := testCreateIssue(t, 1, 2, "title1", "content1", false) i2 := testCreateIssue(t, 1, 2, "title2", "content2", false) @@ -103,10 +103,10 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { assert.NoError(t, err) pr := testCreatePR(t, 1, 2, "titlepr", fmt.Sprintf("closes #%d", i1.Index)) - rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0}).(*issues_model.Comment) + rp := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i1.ID, RefIssueID: pr.Issue.ID, RefCommentID: 0}) c1 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i2.Index)) - r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID}).(*issues_model.Comment) + r1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i2.ID, RefIssueID: pr.Issue.ID, RefCommentID: c1.ID}) // Must be ignored c2 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("mentions #%d", i2.Index)) @@ -117,7 +117,7 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c3.ID}) c4 := testCreateComment(t, 1, 2, pr.Issue.ID, fmt.Sprintf("closes #%d", i3.Index)) - r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID}).(*issues_model.Comment) + r4 := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{IssueID: i3.ID, RefIssueID: pr.Issue.ID, RefCommentID: c4.ID}) refs, err := pr.ResolveCrossReferences(db.DefaultContext) assert.NoError(t, err) @@ -128,8 +128,8 @@ func TestXRef_ResolveCrossReferences(t *testing.T) { } func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispull bool) *issues_model.Issue { - r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository) - d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User) + r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}) + d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}) idx, err := db.GetNextResourceIndex("issue_index", r.ID) assert.NoError(t, err) @@ -159,8 +159,8 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu } func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues_model.PullRequest { - r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}).(*repo_model.Repository) - d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User) + r := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo}) + d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}) i := &issues_model.Issue{RepoID: r.ID, PosterID: d.ID, Poster: d, Title: title, Content: content, IsPull: true} pr := &issues_model.PullRequest{HeadRepoID: repo, BaseRepoID: repo, HeadBranch: "head", BaseBranch: "base", Status: issues_model.PullRequestStatusMergeable} assert.NoError(t, issues_model.NewPullRequest(db.DefaultContext, r, i, nil, nil, pr)) @@ -169,8 +169,8 @@ func testCreatePR(t *testing.T, repo, doer int64, title, content string) *issues } func testCreateComment(t *testing.T, repo, doer, issue int64, content string) *issues_model.Comment { - d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}).(*user_model.User) - i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue}).(*issues_model.Issue) + d := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doer}) + i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issue}) c := &issues_model.Comment{Type: issues_model.CommentTypeComment, PosterID: doer, Poster: d, IssueID: issue, Issue: i, Content: content} ctx, committer, err := db.TxContext() diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 33f114b5fe09..9ad6fd427b92 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -21,17 +21,17 @@ import ( func TestLabel_CalOpenIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) label.CalOpenIssues() assert.EqualValues(t, 2, label.NumOpenIssues) } func TestLabel_ForegroundColor(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) assert.Equal(t, template.CSS("#000"), label.ForegroundColor()) - label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label) + label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}) assert.Equal(t, template.CSS("#fff"), label.ForegroundColor()) } @@ -260,7 +260,7 @@ func TestGetLabelsByIssueID(t *testing.T) { func TestUpdateLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) // make sure update wont overwrite it update := &issues_model.Label{ ID: label.ID, @@ -271,7 +271,7 @@ func TestUpdateLabel(t *testing.T) { label.Color = update.Color label.Name = update.Name assert.NoError(t, issues_model.UpdateLabel(update)) - newLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) + newLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) assert.EqualValues(t, label.ID, newLabel.ID) assert.EqualValues(t, label.Color, newLabel.Color) assert.EqualValues(t, label.Name, newLabel.Name) @@ -281,7 +281,7 @@ func TestUpdateLabel(t *testing.T) { func TestDeleteLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) assert.NoError(t, issues_model.DeleteLabel(label.RepoID, label.ID)) unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID, RepoID: label.RepoID}) @@ -301,9 +301,9 @@ func TestHasIssueLabel(t *testing.T) { func TestNewIssueLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // add new IssueLabel prevNumIssues := label.NumIssues @@ -316,7 +316,7 @@ func TestNewIssueLabel(t *testing.T) { LabelID: label.ID, Content: "1", }) - label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label) + label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}) assert.EqualValues(t, prevNumIssues+1, label.NumIssues) // re-add existing IssueLabel @@ -326,10 +326,10 @@ func TestNewIssueLabel(t *testing.T) { func TestNewIssueLabels(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) - label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 5}).(*issues_model.Issue) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + label1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) + label2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 5}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.NoError(t, issues_model.NewIssueLabels(issue, []*issues_model.Label{label1, label2}, doer)) unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label1.ID}) @@ -341,10 +341,10 @@ func TestNewIssueLabels(t *testing.T) { Content: "1", }) unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: issue.ID, LabelID: label1.ID}) - label1 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) + label1 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) assert.EqualValues(t, 3, label1.NumIssues) assert.EqualValues(t, 1, label1.NumClosedIssues) - label2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}).(*issues_model.Label) + label2 = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 2}) assert.EqualValues(t, 1, label2.NumIssues) assert.EqualValues(t, 1, label2.NumClosedIssues) @@ -357,9 +357,9 @@ func TestNewIssueLabels(t *testing.T) { func TestDeleteIssueLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(labelID, issueID, doerID int64) { - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}).(*issues_model.Label) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID}).(*issues_model.Issue) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doerID}).(*user_model.User) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: issueID}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: doerID}) expectedNumIssues := label.NumIssues expectedNumClosedIssues := label.NumClosedIssues @@ -383,7 +383,7 @@ func TestDeleteIssueLabel(t *testing.T) { IssueID: issueID, LabelID: labelID, }, `content=""`) - label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}).(*issues_model.Label) + label = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}) assert.EqualValues(t, expectedNumIssues, label.NumIssues) assert.EqualValues(t, expectedNumClosedIssues, label.NumClosedIssues) } diff --git a/models/issues/milestone_test.go b/models/issues/milestone_test.go index a6fbf9c23b53..f04a2b2b3bef 100644 --- a/models/issues/milestone_test.go +++ b/models/issues/milestone_test.go @@ -40,7 +40,7 @@ func TestGetMilestoneByRepoID(t *testing.T) { func TestGetMilestonesByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64, state api.StateType) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{ RepoID: repo.ID, State: state, @@ -88,7 +88,7 @@ func TestGetMilestonesByRepoID(t *testing.T) { func TestGetMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) test := func(sortType string, sortCond func(*issues_model.Milestone) int) { for _, page := range []int{0, 1} { milestones, _, err := issues_model.GetMilestones(issues_model.GetMilestonesOption{ @@ -150,7 +150,7 @@ func TestGetMilestones(t *testing.T) { func TestCountRepoMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) count, err := issues_model.CountMilestones(db.DefaultContext, issues_model.GetMilestonesOption{ RepoID: repoID, State: api.StateAll, @@ -173,7 +173,7 @@ func TestCountRepoMilestones(t *testing.T) { func TestCountRepoClosedMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) count, err := issues_model.CountMilestones(db.DefaultContext, issues_model.GetMilestonesOption{ RepoID: repoID, State: api.StateClosed, @@ -196,7 +196,7 @@ func TestCountRepoClosedMilestones(t *testing.T) { func TestCountMilestonesByRepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) milestonesCount := func(repoID int64) (int, int) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) return repo.NumOpenMilestones, repo.NumClosedMilestones } repo1OpenCount, repo1ClosedCount := milestonesCount(1) @@ -215,8 +215,8 @@ func TestCountMilestonesByRepoIDs(t *testing.T) { func TestGetMilestonesByRepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) test := func(sortType string, sortCond func(*issues_model.Milestone) int) { for _, page := range []int{0, 1} { openMilestones, err := issues_model.GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, false, sortType) @@ -262,7 +262,7 @@ func TestGetMilestonesStats(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": repoID})) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, stats.OpenCount) @@ -277,8 +277,8 @@ func TestGetMilestonesStats(t *testing.T) { assert.EqualValues(t, 0, stats.OpenCount) assert.EqualValues(t, 0, stats.ClosedCount) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) milestoneStats, err := issues_model.GetMilestonesStatsByRepoCond(builder.In("repo_id", []int64{repo1.ID, repo2.ID})) assert.NoError(t, err) @@ -301,7 +301,7 @@ func TestNewMilestone(t *testing.T) { func TestChangeMilestoneStatus(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone) + milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, true)) unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=1") @@ -324,11 +324,11 @@ func TestDeleteMilestoneByRepoID(t *testing.T) { func TestUpdateMilestone(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone) + milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) milestone.Name = " newMilestoneName " milestone.Content = "newMilestoneContent" assert.NoError(t, issues_model.UpdateMilestone(milestone, milestone.IsClosed)) - milestone = unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone) + milestone = unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) assert.EqualValues(t, "newMilestoneName", milestone.Name) unittest.CheckConsistencyFor(t, &issues_model.Milestone{}) } @@ -336,7 +336,7 @@ func TestUpdateMilestone(t *testing.T) { func TestUpdateMilestoneCounters(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{MilestoneID: 1}, - "is_closed=0").(*issues_model.Issue) + "is_closed=0") issue.IsClosed = true issue.ClosedUnix = timeutil.TimeStampNow() diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go index 0d1991383d31..fb46e3071e39 100644 --- a/models/issues/pull_test.go +++ b/models/issues/pull_test.go @@ -16,7 +16,7 @@ import ( func TestPullRequest_LoadAttributes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.NoError(t, pr.LoadAttributes()) assert.NotNil(t, pr.Merger) assert.Equal(t, pr.MergerID, pr.Merger.ID) @@ -24,7 +24,7 @@ func TestPullRequest_LoadAttributes(t *testing.T) { func TestPullRequest_LoadIssue(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.NoError(t, pr.LoadIssue()) assert.NotNil(t, pr.Issue) assert.Equal(t, int64(2), pr.Issue.ID) @@ -35,7 +35,7 @@ func TestPullRequest_LoadIssue(t *testing.T) { func TestPullRequest_LoadBaseRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.NoError(t, pr.LoadBaseRepo()) assert.NotNil(t, pr.BaseRepo) assert.Equal(t, pr.BaseRepoID, pr.BaseRepo.ID) @@ -46,7 +46,7 @@ func TestPullRequest_LoadBaseRepo(t *testing.T) { func TestPullRequest_LoadHeadRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.NoError(t, pr.LoadHeadRepo()) assert.NotNil(t, pr.HeadRepo) assert.Equal(t, pr.HeadRepoID, pr.HeadRepo.ID) @@ -180,12 +180,12 @@ func TestGetPullRequestByIssueID(t *testing.T) { func TestPullRequest_Update(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) pr.BaseBranch = "baseBranch" pr.HeadBranch = "headBranch" pr.Update() - pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}).(*issues_model.PullRequest) + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: pr.ID}) assert.Equal(t, "baseBranch", pr.BaseBranch) assert.Equal(t, "headBranch", pr.HeadBranch) unittest.CheckConsistencyFor(t, pr) @@ -200,7 +200,7 @@ func TestPullRequest_UpdateCols(t *testing.T) { } assert.NoError(t, pr.UpdateCols("head_branch")) - pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.Equal(t, "master", pr.BaseBranch) assert.Equal(t, "headBranch", pr.HeadBranch) unittest.CheckConsistencyFor(t, pr) @@ -210,8 +210,8 @@ func TestPullRequestList_LoadAttributes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) prs := []*issues_model.PullRequest{ - unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest), - unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest), + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}), + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}), } assert.NoError(t, issues_model.PullRequestList(prs).LoadAttributes()) for _, pr := range prs { @@ -227,7 +227,7 @@ func TestPullRequestList_LoadAttributes(t *testing.T) { func TestPullRequest_IsWorkInProgress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) pr.LoadIssue() assert.False(t, pr.IsWorkInProgress()) @@ -242,7 +242,7 @@ func TestPullRequest_IsWorkInProgress(t *testing.T) { func TestPullRequest_GetWorkInProgressPrefixWorkInProgress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) pr.LoadIssue() assert.Empty(t, pr.GetWorkInProgressPrefix()) diff --git a/models/issues/reaction_test.go b/models/issues/reaction_test.go index ee1b6687a264..835a667619cb 100644 --- a/models/issues/reaction_test.go +++ b/models/issues/reaction_test.go @@ -32,7 +32,7 @@ func addReaction(t *testing.T, doerID, issueID, commentID int64, content string) func TestIssueAddReaction(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var issue1ID int64 = 1 @@ -44,7 +44,7 @@ func TestIssueAddReaction(t *testing.T) { func TestIssueAddDuplicateReaction(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var issue1ID int64 = 1 @@ -58,14 +58,14 @@ func TestIssueAddDuplicateReaction(t *testing.T) { assert.Error(t, err) assert.Equal(t, issues_model.ErrReactionAlreadyExist{Reaction: "heart"}, err) - existingR := unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}).(*issues_model.Reaction) + existingR := unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}) assert.Equal(t, existingR.ID, reaction.ID) } func TestIssueDeleteReaction(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var issue1ID int64 = 1 @@ -82,14 +82,14 @@ func TestIssueReactionCount(t *testing.T) { setting.UI.ReactionMaxUserNum = 2 - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) ghost := user_model.NewGhostUser() var issueID int64 = 2 - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) addReaction(t, user1.ID, issueID, 0, "heart") addReaction(t, user2.ID, issueID, 0, "heart") @@ -122,7 +122,7 @@ func TestIssueReactionCount(t *testing.T) { func TestIssueCommentAddReaction(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var issue1ID int64 = 1 var comment1ID int64 = 1 @@ -135,10 +135,10 @@ func TestIssueCommentAddReaction(t *testing.T) { func TestIssueCommentDeleteReaction(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) var issue1ID int64 = 1 var comment1ID int64 = 1 @@ -163,7 +163,7 @@ func TestIssueCommentDeleteReaction(t *testing.T) { func TestIssueCommentReactionCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var issue1ID int64 = 1 var comment1ID int64 = 1 diff --git a/models/issues/review_test.go b/models/issues/review_test.go index 3506604b46db..46d1cc777b65 100644 --- a/models/issues/review_test.go +++ b/models/issues/review_test.go @@ -29,22 +29,22 @@ func TestGetReviewByID(t *testing.T) { func TestReview_LoadAttributes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 1}).(*issues_model.Review) + review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 1}) assert.NoError(t, review.LoadAttributes(db.DefaultContext)) assert.NotNil(t, review.Issue) assert.NotNil(t, review.Reviewer) - invalidReview1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 2}).(*issues_model.Review) + invalidReview1 := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 2}) assert.Error(t, invalidReview1.LoadAttributes(db.DefaultContext)) - invalidReview2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 3}).(*issues_model.Review) + invalidReview2 := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 3}) assert.Error(t, invalidReview2.LoadAttributes(db.DefaultContext)) } func TestReview_LoadCodeComments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 4}).(*issues_model.Review) + review := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 4}) assert.NoError(t, review.LoadAttributes(db.DefaultContext)) assert.NoError(t, review.LoadCodeComments(db.DefaultContext)) assert.Len(t, review.CodeComments, 1) @@ -74,8 +74,8 @@ func TestFindReviews(t *testing.T) { func TestGetCurrentReview(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) review, err := issues_model.GetCurrentReview(db.DefaultContext, user, issue) assert.NoError(t, err) @@ -83,7 +83,7 @@ func TestGetCurrentReview(t *testing.T) { assert.Equal(t, issues_model.ReviewTypePending, review.Type) assert.Equal(t, "Pending Review", review.Content) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 7}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 7}) review2, err := issues_model.GetCurrentReview(db.DefaultContext, user2, issue) assert.Error(t, err) assert.True(t, issues_model.IsErrReviewNotExist(err)) @@ -93,8 +93,8 @@ func TestGetCurrentReview(t *testing.T) { func TestCreateReview(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) review, err := issues_model.CreateReview(db.DefaultContext, issues_model.CreateReviewOptions{ Content: "New Review", @@ -110,10 +110,10 @@ func TestCreateReview(t *testing.T) { func TestGetReviewersByIssueID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}).(*issues_model.Issue) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 3}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) + user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) expectedReviews := []*issues_model.Review{} expectedReviews = append(expectedReviews, @@ -150,43 +150,43 @@ func TestGetReviewersByIssueID(t *testing.T) { func TestDismissReview(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - rejectReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review) - requestReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review) - approveReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 8}).(*issues_model.Review) + rejectReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}) + requestReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}) + approveReviewExample := unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 8}) assert.False(t, rejectReviewExample.Dismissed) assert.False(t, requestReviewExample.Dismissed) assert.False(t, approveReviewExample.Dismissed) assert.NoError(t, issues_model.DismissReview(rejectReviewExample, true)) - rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review) - requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review) + rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}) + requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}) assert.True(t, rejectReviewExample.Dismissed) assert.False(t, requestReviewExample.Dismissed) assert.NoError(t, issues_model.DismissReview(requestReviewExample, true)) - rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review) - requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review) + rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}) + requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}) assert.True(t, rejectReviewExample.Dismissed) assert.False(t, requestReviewExample.Dismissed) assert.False(t, approveReviewExample.Dismissed) assert.NoError(t, issues_model.DismissReview(requestReviewExample, true)) - rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review) - requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review) + rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}) + requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}) assert.True(t, rejectReviewExample.Dismissed) assert.False(t, requestReviewExample.Dismissed) assert.False(t, approveReviewExample.Dismissed) assert.NoError(t, issues_model.DismissReview(requestReviewExample, false)) - rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review) - requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review) + rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}) + requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}) assert.True(t, rejectReviewExample.Dismissed) assert.False(t, requestReviewExample.Dismissed) assert.False(t, approveReviewExample.Dismissed) assert.NoError(t, issues_model.DismissReview(requestReviewExample, false)) - rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}).(*issues_model.Review) - requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}).(*issues_model.Review) + rejectReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 9}) + requestReviewExample = unittest.AssertExistsAndLoadBean(t, &issues_model.Review{ID: 11}) assert.True(t, rejectReviewExample.Dismissed) assert.False(t, requestReviewExample.Dismissed) assert.False(t, approveReviewExample.Dismissed) diff --git a/models/issues/stopwatch_test.go b/models/issues/stopwatch_test.go index c0573964d5c4..a5e33f1cf6e2 100644 --- a/models/issues/stopwatch_test.go +++ b/models/issues/stopwatch_test.go @@ -70,7 +70,7 @@ func TestCreateOrStopIssueStopwatch(t *testing.T) { assert.NoError(t, err) assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(user3, issue1)) - sw := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: 3, IssueID: 1}).(*issues_model.Stopwatch) + sw := unittest.AssertExistsAndLoadBean(t, &issues_model.Stopwatch{UserID: 3, IssueID: 1}) assert.LessOrEqual(t, sw.CreatedUnix, timeutil.TimeStampNow()) assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(user2, issue2)) diff --git a/models/issues/tracked_time_test.go b/models/issues/tracked_time_test.go index 787ba9b701e1..ba8b242d9991 100644 --- a/models/issues/tracked_time_test.go +++ b/models/issues/tracked_time_test.go @@ -32,10 +32,10 @@ func TestAddTime(t *testing.T) { assert.Equal(t, int64(1), trackedTime.IssueID) assert.Equal(t, int64(3661), trackedTime.Time) - tt := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{UserID: 3, IssueID: 1}).(*issues_model.TrackedTime) + tt := unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{UserID: 3, IssueID: 1}) assert.Equal(t, int64(3661), tt.Time) - comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddTimeManual, PosterID: 3, IssueID: 1}).(*issues_model.Comment) + comment := unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeAddTimeManual, PosterID: 3, IssueID: 1}) assert.Equal(t, comment.Content, "1 hour 1 minute") } diff --git a/models/migrate_test.go b/models/migrate_test.go index b6525278ecfa..627fb1ae737d 100644 --- a/models/migrate_test.go +++ b/models/migrate_test.go @@ -21,7 +21,7 @@ import ( func TestMigrate_InsertMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) reponame := "repo1" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}) name := "milestonetest1" ms := &issues_model.Milestone{ RepoID: repo.ID, @@ -30,7 +30,7 @@ func TestMigrate_InsertMilestones(t *testing.T) { err := InsertMilestones(ms) assert.NoError(t, err) unittest.AssertExistsAndLoadBean(t, ms) - repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}).(*repo_model.Repository) + repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) assert.EqualValues(t, repo.NumMilestones+1, repoModified.NumMilestones) unittest.CheckConsistencyFor(t, &issues_model.Milestone{}) @@ -39,10 +39,10 @@ func TestMigrate_InsertMilestones(t *testing.T) { func assertCreateIssues(t *testing.T, isPull bool) { assert.NoError(t, unittest.PrepareTestDatabase()) reponame := "repo1" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) - milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}).(*issues_model.Milestone) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) + milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) assert.EqualValues(t, milestone.ID, 1) reaction := &issues_model.Reaction{ Type: "heart", @@ -72,7 +72,7 @@ func assertCreateIssues(t *testing.T, isPull bool) { err := InsertIssues(is) assert.NoError(t, err) - i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title}).(*issues_model.Issue) + i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title}) assert.Nil(t, i.ForeignReference) err = i.LoadAttributes(db.DefaultContext) assert.NoError(t, err) @@ -90,9 +90,9 @@ func TestMigrate_CreateIssuesIsPullTrue(t *testing.T) { func TestMigrate_InsertIssueComments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) _ = issue.LoadRepo(db.DefaultContext) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: issue.Repo.OwnerID}) reaction := &issues_model.Reaction{ Type: "heart", UserID: owner.ID, @@ -109,7 +109,7 @@ func TestMigrate_InsertIssueComments(t *testing.T) { err := InsertIssueComments([]*issues_model.Comment{comment}) assert.NoError(t, err) - issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) assert.EqualValues(t, issue.NumComments+1, issueModified.NumComments) unittest.CheckConsistencyFor(t, &issues_model.Issue{}) @@ -118,8 +118,8 @@ func TestMigrate_InsertIssueComments(t *testing.T) { func TestMigrate_InsertPullRequests(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) reponame := "repo1" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}).(*repo_model.Repository) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: reponame}) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) i := &issues_model.Issue{ RepoID: repo.ID, @@ -138,7 +138,7 @@ func TestMigrate_InsertPullRequests(t *testing.T) { err := InsertPullRequests(p) assert.NoError(t, err) - _ = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{IssueID: i.ID}).(*issues_model.PullRequest) + _ = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{IssueID: i.ID}) unittest.CheckConsistencyFor(t, &issues_model.Issue{}, &issues_model.PullRequest{}) } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 2719f45efbbb..30c4ad250c08 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -406,6 +406,8 @@ var migrations = []Migration{ NewMigration("Drop old CredentialID column", dropOldCredentialIDColumn), // v223 -> v224 NewMigration("Rename CredentialIDBytes column to CredentialID", renameCredentialIDBytes), + // v224 -> v225 + NewMigration("Add badges to users", creatUserBadgesTable), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go index 46782f24a100..53e4f3539564 100644 --- a/models/migrations/migrations_test.go +++ b/models/migrations/migrations_test.go @@ -66,11 +66,10 @@ func TestMain(m *testing.M) { setting.SetCustomPathAndConf("", "", "") setting.LoadForTest() - if err = git.InitOnceWithSync(context.Background()); err != nil { - fmt.Printf("Unable to InitOnceWithSync: %v\n", err) + if err = git.InitFull(context.Background()); err != nil { + fmt.Printf("Unable to InitFull: %v\n", err) os.Exit(1) } - git.CheckLFSVersion() setting.InitDBConfig() setting.NewLogServices(true) @@ -207,7 +206,6 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En deferFn := PrintCurrentTest(t, ourSkip) assert.NoError(t, os.RemoveAll(setting.RepoRootPath)) assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath)) - assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { assert.NoError(t, err, "unable to read the new repo root: %v\n", err) diff --git a/models/migrations/v220.go b/models/migrations/v220.go index f5983582a30f..8138bc5bb149 100644 --- a/models/migrations/v220.go +++ b/models/migrations/v220.go @@ -12,18 +12,17 @@ import ( "xorm.io/xorm/schemas" ) -func addContainerRepositoryProperty(x *xorm.Engine) error { +func addContainerRepositoryProperty(x *xorm.Engine) (err error) { switch x.Dialect().URI().DBType { case schemas.SQLITE: - _, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer) - if err != nil { - return err - } + _, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name || '/' || p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", + packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer) + case schemas.MSSQL: + _, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, u.lower_name + '/' + p.lower_name FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", + packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer) default: - _, err := x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer) - if err != nil { - return err - } + _, err = x.Exec("INSERT INTO package_property (ref_type, ref_id, name, value) SELECT ?, p.id, ?, CONCAT(u.lower_name, '/', p.lower_name) FROM package p JOIN `user` u ON p.owner_id = u.id WHERE p.type = ?", + packages_model.PropertyTypePackage, container_module.PropertyRepository, packages_model.TypeContainer) } - return nil + return err } diff --git a/models/migrations/v224.go b/models/migrations/v224.go new file mode 100644 index 000000000000..d684d538df22 --- /dev/null +++ b/models/migrations/v224.go @@ -0,0 +1,28 @@ +// 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 migrations + +import ( + "xorm.io/xorm" +) + +func creatUserBadgesTable(x *xorm.Engine) error { + type Badge struct { + ID int64 `xorm:"pk autoincr"` + Description string + ImageURL string + } + + type userBadge struct { + ID int64 `xorm:"pk autoincr"` + BadgeID int64 + UserID int64 `xorm:"INDEX"` + } + + if err := x.Sync2(new(Badge)); err != nil { + return err + } + return x.Sync2(new(userBadge)) +} diff --git a/models/notification_test.go b/models/notification_test.go index 16ff02d6c05b..340fb4337ae5 100644 --- a/models/notification_test.go +++ b/models/notification_test.go @@ -17,22 +17,22 @@ import ( func TestCreateOrUpdateIssueNotifications(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) assert.NoError(t, CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0)) // User 9 is inactive, thus notifications for user 1 and 4 are created - notf := unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 1, IssueID: issue.ID}).(*Notification) + notf := unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 1, IssueID: issue.ID}) assert.Equal(t, NotificationStatusUnread, notf.Status) unittest.CheckConsistencyFor(t, &issues_model.Issue{ID: issue.ID}) - notf = unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 4, IssueID: issue.ID}).(*Notification) + notf = unittest.AssertExistsAndLoadBean(t, &Notification{UserID: 4, IssueID: issue.ID}) assert.Equal(t, NotificationStatusUnread, notf.Status) } func TestNotificationsForUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread} notfs, err := NotificationsForUser(db.DefaultContext, user, statuses, 1, 10) assert.NoError(t, err) @@ -48,7 +48,7 @@ func TestNotificationsForUser(t *testing.T) { func TestNotification_GetRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - notf := unittest.AssertExistsAndLoadBean(t, &Notification{RepoID: 1}).(*Notification) + notf := unittest.AssertExistsAndLoadBean(t, &Notification{RepoID: 1}) repo, err := notf.GetRepo() assert.NoError(t, err) assert.Equal(t, repo, notf.Repository) @@ -57,7 +57,7 @@ func TestNotification_GetRepo(t *testing.T) { func TestNotification_GetIssue(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - notf := unittest.AssertExistsAndLoadBean(t, &Notification{RepoID: 1}).(*Notification) + notf := unittest.AssertExistsAndLoadBean(t, &Notification{RepoID: 1}) issue, err := notf.GetIssue() assert.NoError(t, err) assert.Equal(t, issue, notf.Issue) @@ -66,7 +66,7 @@ func TestNotification_GetIssue(t *testing.T) { func TestGetNotificationCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) cnt, err := GetNotificationCount(db.DefaultContext, user, NotificationStatusRead) assert.NoError(t, err) assert.EqualValues(t, 0, cnt) @@ -78,9 +78,9 @@ func TestGetNotificationCount(t *testing.T) { func TestSetNotificationStatus(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) notf := unittest.AssertExistsAndLoadBean(t, - &Notification{UserID: user.ID, Status: NotificationStatusRead}).(*Notification) + &Notification{UserID: user.ID, Status: NotificationStatusRead}) _, err := SetNotificationStatus(notf.ID, user, NotificationStatusPinned) assert.NoError(t, err) unittest.AssertExistsAndLoadBean(t, @@ -94,13 +94,13 @@ func TestSetNotificationStatus(t *testing.T) { func TestUpdateNotificationStatuses(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) notfUnread := unittest.AssertExistsAndLoadBean(t, - &Notification{UserID: user.ID, Status: NotificationStatusUnread}).(*Notification) + &Notification{UserID: user.ID, Status: NotificationStatusUnread}) notfRead := unittest.AssertExistsAndLoadBean(t, - &Notification{UserID: user.ID, Status: NotificationStatusRead}).(*Notification) + &Notification{UserID: user.ID, Status: NotificationStatusRead}) notfPinned := unittest.AssertExistsAndLoadBean(t, - &Notification{UserID: user.ID, Status: NotificationStatusPinned}).(*Notification) + &Notification{UserID: user.ID, Status: NotificationStatusPinned}) assert.NoError(t, UpdateNotificationStatuses(user, NotificationStatusUnread, NotificationStatusRead)) unittest.AssertExistsAndLoadBean(t, &Notification{ID: notfUnread.ID, Status: NotificationStatusRead}) diff --git a/models/org_team_test.go b/models/org_team_test.go index 35ee9af85a8e..a0de6d73f1f6 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -23,7 +23,7 @@ func TestTeam_AddMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID, userID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, AddTeamMember(team, userID)) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID}) @@ -37,7 +37,7 @@ func TestTeam_RemoveMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(teamID, userID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, RemoveTeamMember(team, userID)) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}) @@ -47,7 +47,7 @@ func TestTeam_RemoveMember(t *testing.T) { testSuccess(3, 2) testSuccess(3, unittest.NonexistentID) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) err := RemoveTeamMember(team, 2) assert.True(t, organization.IsErrLastOrgOwner(err)) } @@ -56,7 +56,7 @@ func TestTeam_HasRepository(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID, repoID int64, expected bool) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.Equal(t, expected, HasRepository(team, repoID)) } test(1, 1, false) @@ -72,8 +72,8 @@ func TestTeam_AddRepository(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(teamID, repoID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) assert.NoError(t, AddRepository(team, repo)) unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID}) @@ -81,8 +81,8 @@ func TestTeam_AddRepository(t *testing.T) { testSuccess(2, 3) testSuccess(2, 5) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.Error(t, AddRepository(team, repo)) unittest.CheckConsistencyFor(t, &organization.Team{ID: 1}, &repo_model.Repository{ID: 1}) } @@ -91,7 +91,7 @@ func TestTeam_RemoveRepository(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(teamID, repoID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, RemoveRepository(team, repoID)) unittest.AssertNotExistsBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID}) @@ -120,17 +120,17 @@ func TestUpdateTeam(t *testing.T) { // successful update assert.NoError(t, unittest.PrepareTestDatabase()) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) team.LowerName = "newname" team.Name = "newName" team.Description = strings.Repeat("A long description!", 100) team.AccessMode = perm.AccessModeAdmin assert.NoError(t, UpdateTeam(team, true, false)) - team = unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: "newName"}).(*organization.Team) + team = unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: "newName"}) assert.True(t, strings.HasPrefix(team.Description, "A long description!")) - access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: 3}).(*access_model.Access) + access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: 3}) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) unittest.CheckConsistencyFor(t, &organization.Team{ID: team.ID}) @@ -140,7 +140,7 @@ func TestUpdateTeam2(t *testing.T) { // update to already-existing team assert.NoError(t, unittest.PrepareTestDatabase()) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) team.LowerName = "owners" team.Name = "Owners" team.Description = strings.Repeat("A long description!", 100) @@ -153,15 +153,15 @@ func TestUpdateTeam2(t *testing.T) { func TestDeleteTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) assert.NoError(t, DeleteTeam(team)) unittest.AssertNotExistsBean(t, &organization.Team{ID: team.ID}) unittest.AssertNotExistsBean(t, &organization.TeamRepo{TeamID: team.ID}) unittest.AssertNotExistsBean(t, &organization.TeamUser{TeamID: team.ID}) // check that team members don't have "leftover" access to repos - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) accessMode, err := access_model.AccessLevel(user, repo) assert.NoError(t, err) assert.True(t, accessMode < perm.AccessModeWrite) @@ -171,7 +171,7 @@ func TestAddTeamMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID, userID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, AddTeamMember(team, userID)) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID}) @@ -185,7 +185,7 @@ func TestRemoveTeamMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(teamID, userID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, RemoveTeamMember(team, userID)) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}) @@ -195,15 +195,15 @@ func TestRemoveTeamMember(t *testing.T) { testSuccess(3, 2) testSuccess(3, unittest.NonexistentID) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) err := RemoveTeamMember(team, 2) assert.True(t, organization.IsErrLastOrgOwner(err)) } func TestRepository_RecalculateAccesses3(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - team5 := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) - user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User) + team5 := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}) + user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) has, err := db.GetEngine(db.DefaultContext).Get(&access_model.Access{UserID: 29, RepoID: 23}) assert.NoError(t, err) diff --git a/models/org_test.go b/models/org_test.go index af11bed280f4..23b417119ede 100644 --- a/models/org_test.go +++ b/models/org_test.go @@ -16,14 +16,14 @@ import ( func TestUser_RemoveMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) // remove a user that is a member unittest.AssertExistsAndLoadBean(t, &organization.OrgUser{UID: 4, OrgID: 3}) prevNumMembers := org.NumMembers assert.NoError(t, RemoveOrgUser(org.ID, 4)) unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 4, OrgID: 3}) - org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) assert.Equal(t, prevNumMembers-1, org.NumMembers) // remove a user that is not a member @@ -31,7 +31,7 @@ func TestUser_RemoveMember(t *testing.T) { prevNumMembers = org.NumMembers assert.NoError(t, RemoveOrgUser(org.ID, 5)) unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: 5, OrgID: 3}) - org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) assert.Equal(t, prevNumMembers, org.NumMembers) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) @@ -40,14 +40,14 @@ func TestUser_RemoveMember(t *testing.T) { func TestRemoveOrgUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(orgID, userID int64) { - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}) expectedNumMembers := org.NumMembers if unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) { expectedNumMembers-- } assert.NoError(t, RemoveOrgUser(orgID, userID)) unittest.AssertNotExistsBean(t, &organization.OrgUser{OrgID: orgID, UID: userID}) - org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User) + org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}) assert.EqualValues(t, expectedNumMembers, org.NumMembers) } testSuccess(3, 4) diff --git a/models/organization/org_test.go b/models/organization/org_test.go index 3a135498a337..0fba6e25925c 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -31,7 +31,7 @@ func TestUser_IsOwnedBy(t *testing.T) { {2, 2, false}, // user2 is not an organization {2, 3, false}, } { - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: testCase.OrgID}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: testCase.OrgID}) isOwner, err := org.IsOwnedBy(testCase.UserID) assert.NoError(t, err) assert.Equal(t, testCase.ExpectedOwner, isOwner) @@ -52,7 +52,7 @@ func TestUser_IsOrgMember(t *testing.T) { {2, 2, false}, // user2 is not an organization {2, 3, false}, } { - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: testCase.OrgID}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: testCase.OrgID}) isMember, err := org.IsOrgMember(testCase.UserID) assert.NoError(t, err) assert.Equal(t, testCase.ExpectedMember, isMember) @@ -61,7 +61,7 @@ func TestUser_IsOrgMember(t *testing.T) { func TestUser_GetTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) team, err := org.GetTeam("team1") assert.NoError(t, err) assert.Equal(t, org.ID, team.OrgID) @@ -70,26 +70,26 @@ func TestUser_GetTeam(t *testing.T) { _, err = org.GetTeam("does not exist") assert.True(t, organization.IsErrTeamNotExist(err)) - nonOrg := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 2}).(*organization.Organization) + nonOrg := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 2}) _, err = nonOrg.GetTeam("team") assert.True(t, organization.IsErrTeamNotExist(err)) } func TestUser_GetOwnerTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) team, err := org.GetOwnerTeam() assert.NoError(t, err) assert.Equal(t, org.ID, team.OrgID) - nonOrg := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 2}).(*organization.Organization) + nonOrg := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 2}) _, err = nonOrg.GetOwnerTeam() assert.True(t, organization.IsErrTeamNotExist(err)) } func TestUser_GetTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) teams, err := org.LoadTeams() assert.NoError(t, err) if assert.Len(t, teams, 4) { @@ -102,7 +102,7 @@ func TestUser_GetTeams(t *testing.T) { func TestUser_GetMembers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) members, _, err := org.GetMembers() assert.NoError(t, err) if assert.Len(t, members, 3) { @@ -275,7 +275,7 @@ func TestChangeOrgUserStatus(t *testing.T) { testSuccess := func(orgID, userID int64, public bool) { assert.NoError(t, organization.ChangeOrgUserStatus(orgID, userID, public)) - orgUser := unittest.AssertExistsAndLoadBean(t, &organization.OrgUser{OrgID: orgID, UID: userID}).(*organization.OrgUser) + orgUser := unittest.AssertExistsAndLoadBean(t, &organization.OrgUser{OrgID: orgID, UID: userID}) assert.Equal(t, public, orgUser.IsPublic) } @@ -287,7 +287,7 @@ func TestChangeOrgUserStatus(t *testing.T) { func TestUser_GetUserTeamIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expected []int64) { teamIDs, err := org.GetUserTeamIDs(userID) assert.NoError(t, err) @@ -300,7 +300,7 @@ func TestUser_GetUserTeamIDs(t *testing.T) { func TestAccessibleReposEnv_CountRepos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID, expectedCount int64) { env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) @@ -314,7 +314,7 @@ func TestAccessibleReposEnv_CountRepos(t *testing.T) { func TestAccessibleReposEnv_RepoIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID, _, pageSize int64, expectedRepoIDs []int64) { env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) @@ -328,7 +328,7 @@ func TestAccessibleReposEnv_RepoIDs(t *testing.T) { func TestAccessibleReposEnv_Repos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expectedRepoIDs []int64) { env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) @@ -337,7 +337,7 @@ func TestAccessibleReposEnv_Repos(t *testing.T) { expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs)) for i, repoID := range expectedRepoIDs { expectedRepos[i] = unittest.AssertExistsAndLoadBean(t, - &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + &repo_model.Repository{ID: repoID}) } assert.Equal(t, expectedRepos, repos) } @@ -347,7 +347,7 @@ func TestAccessibleReposEnv_Repos(t *testing.T) { func TestAccessibleReposEnv_MirrorRepos(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expectedRepoIDs []int64) { env, err := organization.AccessibleReposEnv(db.DefaultContext, org, userID) assert.NoError(t, err) @@ -356,7 +356,7 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) { expectedRepos := make([]*repo_model.Repository, len(expectedRepoIDs)) for i, repoID := range expectedRepoIDs { expectedRepos[i] = unittest.AssertExistsAndLoadBean(t, - &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + &repo_model.Repository{ID: repoID}) } assert.Equal(t, expectedRepos, repos) } @@ -366,8 +366,8 @@ func TestAccessibleReposEnv_MirrorRepos(t *testing.T) { func TestHasOrgVisibleTypePublic(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) const newOrgName = "test-org-public" org := &organization.Organization{ @@ -378,7 +378,7 @@ func TestHasOrgVisibleTypePublic(t *testing.T) { unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization}) assert.NoError(t, organization.CreateOrganization(org, owner)) org = unittest.AssertExistsAndLoadBean(t, - &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*organization.Organization) + &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}) test1 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner) test2 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user3) test3 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), nil) @@ -389,8 +389,8 @@ func TestHasOrgVisibleTypePublic(t *testing.T) { func TestHasOrgVisibleTypeLimited(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) const newOrgName = "test-org-limited" org := &organization.Organization{ @@ -401,7 +401,7 @@ func TestHasOrgVisibleTypeLimited(t *testing.T) { unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization}) assert.NoError(t, organization.CreateOrganization(org, owner)) org = unittest.AssertExistsAndLoadBean(t, - &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*organization.Organization) + &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}) test1 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner) test2 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user3) test3 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), nil) @@ -412,8 +412,8 @@ func TestHasOrgVisibleTypeLimited(t *testing.T) { func TestHasOrgVisibleTypePrivate(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) const newOrgName = "test-org-private" org := &organization.Organization{ @@ -424,7 +424,7 @@ func TestHasOrgVisibleTypePrivate(t *testing.T) { unittest.AssertNotExistsBean(t, &user_model.User{Name: org.Name, Type: user_model.UserTypeOrganization}) assert.NoError(t, organization.CreateOrganization(org, owner)) org = unittest.AssertExistsAndLoadBean(t, - &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}).(*organization.Organization) + &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}) test1 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner) test2 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user3) test3 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), nil) @@ -453,8 +453,8 @@ func TestGetUsersWhoCanCreateOrgRepo(t *testing.T) { func TestUser_RemoveOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: org.ID}).(*repo_model.Repository) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: org.ID}) // remove a repo that does belong to org unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{RepoID: repo.ID, OrgID: org.ID}) @@ -478,7 +478,7 @@ func TestCreateOrganization(t *testing.T) { // successful creation of org assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) const newOrgName = "neworg" org := &organization.Organization{ Name: newOrgName, @@ -487,9 +487,9 @@ func TestCreateOrganization(t *testing.T) { unittest.AssertNotExistsBean(t, &user_model.User{Name: newOrgName, Type: user_model.UserTypeOrganization}) assert.NoError(t, organization.CreateOrganization(org, owner)) org = unittest.AssertExistsAndLoadBean(t, - &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}).(*organization.Organization) + &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}) ownerTeam := unittest.AssertExistsAndLoadBean(t, - &organization.Team{Name: organization.OwnerTeamName, OrgID: org.ID}).(*organization.Team) + &organization.Team{Name: organization.OwnerTeamName, OrgID: org.ID}) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: owner.ID, TeamID: ownerTeam.ID}) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) } @@ -498,7 +498,7 @@ func TestCreateOrganization2(t *testing.T) { // unauthorized creation of org assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) const newOrgName = "neworg" org := &organization.Organization{ Name: newOrgName, @@ -516,7 +516,7 @@ func TestCreateOrganization3(t *testing.T) { // create org with same name as existent org assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org := &organization.Organization{Name: "user3"} // should already exist unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: org.Name}) // sanity check err := organization.CreateOrganization(org, owner) @@ -529,7 +529,7 @@ func TestCreateOrganization4(t *testing.T) { // create org with unusable name assert.NoError(t, unittest.PrepareTestDatabase()) - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) err := organization.CreateOrganization(&organization.Organization{Name: "assets"}, owner) assert.Error(t, err) assert.True(t, db.IsErrNameReserved(err)) diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go index 22ee5217f95e..aed3ea23cf8c 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -130,7 +130,7 @@ func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bo func TestAddOrgUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(orgID, userID int64, isPublic bool) { - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}) expectedNumMembers := org.NumMembers if !unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) { expectedNumMembers++ @@ -139,7 +139,7 @@ func TestAddOrgUser(t *testing.T) { ou := &organization.OrgUser{OrgID: orgID, UID: userID} unittest.AssertExistsAndLoadBean(t, ou) assert.Equal(t, isPublic, ou.IsPublic) - org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}).(*user_model.User) + org = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: orgID}) assert.EqualValues(t, expectedNumMembers, org.NumMembers) } diff --git a/models/organization/team_test.go b/models/organization/team_test.go index 829c440c2938..c8d58a0eb7a8 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -17,22 +17,22 @@ import ( func TestTeam_IsOwnerTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) assert.True(t, team.IsOwnerTeam()) - team = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team) + team = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) assert.False(t, team.IsOwnerTeam()) } func TestTeam_IsMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) assert.True(t, team.IsMember(2)) assert.False(t, team.IsMember(4)) assert.False(t, team.IsMember(unittest.NonexistentID)) - team = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}).(*organization.Team) + team = unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) assert.True(t, team.IsMember(2)) assert.True(t, team.IsMember(4)) assert.False(t, team.IsMember(unittest.NonexistentID)) @@ -42,7 +42,7 @@ func TestTeam_GetRepositories(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, team.GetRepositoriesCtx(db.DefaultContext)) assert.Len(t, team.Repos, team.NumRepos) for _, repo := range team.Repos { @@ -57,7 +57,7 @@ func TestTeam_GetMembers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, team.GetMembersCtx(db.DefaultContext)) assert.Len(t, team.Members, team.NumMembers) for _, member := range team.Members { @@ -126,7 +126,7 @@ func TestGetTeamMembers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) members, err := organization.GetTeamMembers(db.DefaultContext, &organization.SearchMembersOptions{ TeamID: teamID, }) @@ -173,7 +173,7 @@ func TestHasTeamRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamID, repoID int64, expected bool) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.Equal(t, expected, organization.HasTeamRepo(db.DefaultContext, team.OrgID, teamID, repoID)) } test(1, 1, false) diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go index 31819ccca1ab..dc753421d021 100644 --- a/models/packages/descriptor.go +++ b/models/packages/descriptor.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/modules/packages/maven" "code.gitea.io/gitea/modules/packages/npm" "code.gitea.io/gitea/modules/packages/nuget" + "code.gitea.io/gitea/modules/packages/pub" "code.gitea.io/gitea/modules/packages/pypi" "code.gitea.io/gitea/modules/packages/rubygems" @@ -143,6 +144,8 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc metadata = &npm.Metadata{} case TypeMaven: metadata = &maven.Metadata{} + case TypePub: + metadata = &pub.Metadata{} case TypePyPI: metadata = &pypi.Metadata{} case TypeRubyGems: diff --git a/models/packages/package.go b/models/packages/package.go index 97cfbc6cad20..39b1c83cfabf 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -39,6 +39,7 @@ const ( TypeMaven Type = "maven" TypeNpm Type = "npm" TypeNuGet Type = "nuget" + TypePub Type = "pub" TypePyPI Type = "pypi" TypeRubyGems Type = "rubygems" ) @@ -62,6 +63,8 @@ func (pt Type) Name() string { return "npm" case TypeNuGet: return "NuGet" + case TypePub: + return "Pub" case TypePyPI: return "PyPI" case TypeRubyGems: @@ -89,6 +92,8 @@ func (pt Type) SVGName() string { return "gitea-npm" case TypeNuGet: return "gitea-nuget" + case TypePub: + return "gitea-pub" case TypePyPI: return "gitea-python" case TypeRubyGems: diff --git a/models/perm/access/access_test.go b/models/perm/access/access_test.go index a5e0448d3db8..8e75792e0c79 100644 --- a/models/perm/access/access_test.go +++ b/models/perm/access/access_test.go @@ -23,21 +23,21 @@ import ( func TestAccessLevel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) + user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}) // A public repository owned by User 2 - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.False(t, repo1.IsPrivate) // A private repository owned by Org 3 - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.True(t, repo3.IsPrivate) // Another public repository - repo4 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + repo4 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) assert.False(t, repo4.IsPrivate) // org. owned private repo - repo24 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}).(*repo_model.Repository) + repo24 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}) level, err := access_model.AccessLevel(user2, repo1) assert.NoError(t, err) @@ -74,13 +74,13 @@ func TestAccessLevel(t *testing.T) { func TestHasAccess(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) // A public repository owned by User 2 - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.False(t, repo1.IsPrivate) // A private repository owned by Org 3 - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.True(t, repo2.IsPrivate) has, err := access_model.HasAccess(db.DefaultContext, user1.ID, repo1) @@ -100,7 +100,7 @@ func TestHasAccess(t *testing.T) { func TestRepository_RecalculateAccesses(t *testing.T) { // test with organization repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.NoError(t, repo1.GetOwner(db.DefaultContext)) _, err := db.GetEngine(db.DefaultContext).Delete(&repo_model.Collaboration{UserID: 2, RepoID: 3}) @@ -117,7 +117,7 @@ func TestRepository_RecalculateAccesses(t *testing.T) { func TestRepository_RecalculateAccesses2(t *testing.T) { // test with non-organization repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) assert.NoError(t, repo1.GetOwner(db.DefaultContext)) _, err := db.GetEngine(db.DefaultContext).Delete(&repo_model.Collaboration{UserID: 4, RepoID: 4}) @@ -133,11 +133,11 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // public non-organization repo - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -155,7 +155,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } // collaborator - collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, collaborator) assert.NoError(t, err) for _, unit := range repo.Units { @@ -164,7 +164,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } // owner - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { @@ -173,7 +173,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } // admin - admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { @@ -186,11 +186,11 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // private non-organization repo - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -216,7 +216,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } // owner - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { @@ -225,7 +225,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } // admin - admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { @@ -238,11 +238,11 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // public organization repo - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 32}) assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -268,7 +268,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } // org member team owner - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { @@ -277,7 +277,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } // org member team tester - member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) + member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, member) assert.NoError(t, err) for _, unit := range repo.Units { @@ -287,7 +287,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { assert.False(t, perm.CanWrite(unit.TypeCode)) // admin - admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { @@ -300,11 +300,11 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // private organization repo - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 24}) assert.NoError(t, repo.LoadUnits(db.DefaultContext)) // plain user - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -330,7 +330,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } // org member team owner - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { @@ -339,7 +339,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } // update team information and then check permission - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}) err = organization.UpdateTeamUnits(team, nil) assert.NoError(t, err) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) @@ -350,7 +350,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } // org member team tester - tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, tester) assert.NoError(t, err) assert.True(t, perm.CanWrite(unit.TypeIssues)) @@ -358,7 +358,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.False(t, perm.CanRead(unit.TypeCode)) // org member team reviewer - reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}).(*user_model.User) + reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, reviewer) assert.NoError(t, err) assert.False(t, perm.CanRead(unit.TypeIssues)) @@ -366,7 +366,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.True(t, perm.CanRead(unit.TypeCode)) // admin - admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { diff --git a/models/repo/attachment.go b/models/repo/attachment.go index ddddac2c3dcf..afec78a4254b 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -226,28 +226,6 @@ func DeleteAttachmentsByRelease(releaseID int64) error { return err } -// IterateAttachment iterates attachments; it should not be used when Gitea is servicing users. -func IterateAttachment(f func(attach *Attachment) error) error { - var start int - const batchSize = 100 - for { - attachments := make([]*Attachment, 0, batchSize) - if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&attachments); err != nil { - return err - } - if len(attachments) == 0 { - return nil - } - start += len(attachments) - - for _, attach := range attachments { - if err := f(attach); err != nil { - return err - } - } - } -} - // CountOrphanedAttachments returns the number of bad attachments func CountOrphanedAttachments() (int64, error) { return db.GetEngine(db.DefaultContext).Where("(issue_id > 0 and issue_id not in (select id from issue)) or (release_id > 0 and release_id not in (select id from `release`))"). diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go index 2e6253d5610b..cbf46dd286d0 100644 --- a/models/repo/collaboration_test.go +++ b/models/repo/collaboration_test.go @@ -19,7 +19,7 @@ import ( func TestRepository_GetCollaborators(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) collaborators, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{}) assert.NoError(t, err) expectedLen, err := db.GetEngine(db.DefaultContext).Count(&repo_model.Collaboration{RepoID: repoID}) @@ -40,7 +40,7 @@ func TestRepository_IsCollaborator(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID, userID int64, expected bool) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) actual, err := repo_model.IsCollaborator(db.DefaultContext, repo.ID, userID) assert.NoError(t, err) assert.Equal(t, expected, actual) @@ -54,13 +54,13 @@ func TestRepository_IsCollaborator(t *testing.T) { func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) - collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}).(*repo_model.Collaboration) + collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode) - access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID}).(*access_model.Access) + access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID}) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) diff --git a/models/repo/mirror.go b/models/repo/mirror.go index 8f96e8cee185..e94bbda2c181 100644 --- a/models/repo/mirror.go +++ b/models/repo/mirror.go @@ -153,7 +153,9 @@ func (repos MirrorRepositoryList) loadAttributes(ctx context.Context) error { } for i := range repos { repos[i].Mirror = set[repos[i].ID] - repos[i].Mirror.Repo = repos[i] + if repos[i].Mirror != nil { + repos[i].Mirror.Repo = repos[i] + } } return nil } diff --git a/models/repo/redirect_test.go b/models/repo/redirect_test.go index 05b105cf63ff..90114667e599 100644 --- a/models/repo/redirect_test.go +++ b/models/repo/redirect_test.go @@ -29,7 +29,7 @@ func TestNewRedirect(t *testing.T) { // redirect to a completely new name assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame")) unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ @@ -48,7 +48,7 @@ func TestNewRedirect2(t *testing.T) { // redirect to previously used name assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "oldrepo1")) unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ @@ -67,7 +67,7 @@ func TestNewRedirect3(t *testing.T) { // redirect for a previously-unredirected repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame")) unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 9de76fa5ffa1..1fa469fcfeb3 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -15,36 +15,12 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) -// IterateRepository iterate repositories -func IterateRepository(f func(repo *Repository) error) error { - var start int - batchSize := setting.Database.IterateBufferSize - sess := db.GetEngine(db.DefaultContext) - for { - repos := make([]*Repository, 0, batchSize) - if err := sess.Limit(batchSize, start).Find(&repos); err != nil { - return err - } - if len(repos) == 0 { - return nil - } - start += len(repos) - - for _, repo := range repos { - if err := f(repo); err != nil { - return err - } - } - } -} - // FindReposMapByIDs find repos as map func FindReposMapByIDs(repoIDs []int64, res map[int64]*Repository) error { return db.GetEngine(db.DefaultContext).In("id", repoIDs).Find(&res) diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go index 6f8b282a66aa..617ec12798d4 100644 --- a/models/repo/repo_test.go +++ b/models/repo/repo_test.go @@ -56,7 +56,7 @@ func TestGetPrivateRepositoryCount(t *testing.T) { func TestRepoAPIURL(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL()) } diff --git a/models/repo/star_test.go b/models/repo/star_test.go index aa72b1dac8c0..1b53e17d2732 100644 --- a/models/repo/star_test.go +++ b/models/repo/star_test.go @@ -36,7 +36,7 @@ func TestIsStaring(t *testing.T) { func TestRepository_GetStargazers(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) assert.NoError(t, err) if assert.Len(t, gazers, 1) { @@ -47,7 +47,7 @@ func TestRepository_GetStargazers(t *testing.T) { func TestRepository_GetStargazers2(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) assert.NoError(t, err) assert.Len(t, gazers, 0) diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 71e0c57550c5..6c0a241dc562 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -170,3 +170,15 @@ func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64) users := make([]*user_model.User, 0, 8) return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users) } + +// GetIssuePosters returns all users that have authored an issue/pull request for the given repository +func GetIssuePosters(ctx context.Context, repo *Repository, isPull bool) ([]*user_model.User, error) { + users := make([]*user_model.User, 0, 8) + cond := builder.In("`user`.id", + builder.Select("poster_id").From("issue").Where( + builder.Eq{"repo_id": repo.ID}. + And(builder.Eq{"is_pull": isPull}), + ).GroupBy("poster_id"), + ) + return users, db.GetEngine(ctx).Where(cond).OrderBy(user_model.GetOrderByName()).Find(&users) +} diff --git a/models/repo/user_repo_test.go b/models/repo/user_repo_test.go index d024729b9cde..640914592090 100644 --- a/models/repo/user_repo_test.go +++ b/models/repo/user_repo_test.go @@ -17,13 +17,13 @@ import ( func TestRepoAssignees(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) users, err := repo_model.GetRepoAssignees(db.DefaultContext, repo2) assert.NoError(t, err) assert.Len(t, users, 1) assert.Equal(t, users[0].ID, int64(2)) - repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository) + repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}) users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21) assert.NoError(t, err) assert.Len(t, users, 3) @@ -36,7 +36,7 @@ func TestRepoGetReviewers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // test public repo - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) ctx := db.DefaultContext reviewers, err := repo_model.GetReviewers(ctx, repo1, 2, 2) @@ -54,7 +54,7 @@ func TestRepoGetReviewers(t *testing.T) { assert.Len(t, reviewers, 3) // test private user repo - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) reviewers, err = repo_model.GetReviewers(ctx, repo2, 2, 4) assert.NoError(t, err) @@ -62,7 +62,7 @@ func TestRepoGetReviewers(t *testing.T) { assert.EqualValues(t, reviewers[0].ID, 2) // test private org repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) reviewers, err = repo_model.GetReviewers(ctx, repo3, 2, 1) assert.NoError(t, err) diff --git a/models/repo/watch_test.go b/models/repo/watch_test.go index 3875e63fd873..18a2d5d5fdf3 100644 --- a/models/repo/watch_test.go +++ b/models/repo/watch_test.go @@ -30,7 +30,7 @@ func TestIsWatching(t *testing.T) { func TestGetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) watches, err := repo_model.GetWatchers(db.DefaultContext, repo.ID) assert.NoError(t, err) // One watchers are inactive, thus minus 1 @@ -47,7 +47,7 @@ func TestGetWatchers(t *testing.T) { func TestRepository_GetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) @@ -55,7 +55,7 @@ func TestRepository_GetWatchers(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID}) } - repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}).(*repo_model.Repository) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}) watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, 0) @@ -64,7 +64,7 @@ func TestRepository_GetWatchers(t *testing.T) { func TestWatchIfAuto(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) diff --git a/models/repo/wiki_test.go b/models/repo/wiki_test.go index 339289e05d86..863173627628 100644 --- a/models/repo/wiki_test.go +++ b/models/repo/wiki_test.go @@ -18,7 +18,7 @@ import ( func TestRepository_WikiCloneLink(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) cloneLink := repo.WikiCloneLink() assert.Equal(t, "ssh://sshuser@try.gitea.io:3000/user2/repo1.wiki.git", cloneLink.SSH) assert.Equal(t, "https://try.gitea.io/user2/repo1.wiki.git", cloneLink.HTTPS) @@ -32,15 +32,15 @@ func TestWikiPath(t *testing.T) { func TestRepository_WikiPath(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) expected := filepath.Join(setting.RepoRootPath, "user2/repo1.wiki.git") assert.Equal(t, expected, repo.WikiPath()) } func TestRepository_HasWiki(t *testing.T) { unittest.PrepareTestEnv(t) - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.True(t, repo1.HasWiki()) - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.False(t, repo2.HasWiki()) } diff --git a/models/repo_collaboration_test.go b/models/repo_collaboration_test.go index 4cf4d612184c..72b354f1a5db 100644 --- a/models/repo_collaboration_test.go +++ b/models/repo_collaboration_test.go @@ -19,9 +19,9 @@ func TestRepository_AddCollaborator(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(repoID, userID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) assert.NoError(t, repo.GetOwner(db.DefaultContext)) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) assert.NoError(t, AddCollaborator(repo, user)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) } @@ -33,7 +33,7 @@ func TestRepository_AddCollaborator(t *testing.T) { func TestRepository_DeleteCollaboration(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) assert.NoError(t, repo.GetOwner(db.DefaultContext)) assert.NoError(t, DeleteCollaboration(repo, 4)) unittest.AssertNotExistsBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go index 9125bb8c8dfe..7904b04e98c3 100644 --- a/models/repo_transfer_test.go +++ b/models/repo_transfer_test.go @@ -17,8 +17,8 @@ import ( func TestRepositoryTransfer(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) transfer, err := GetPendingRepositoryTransfer(repo) assert.NoError(t, err) @@ -32,7 +32,7 @@ func TestRepositoryTransfer(t *testing.T) { assert.Nil(t, transfer) assert.True(t, IsErrNoPendingTransfer(err)) - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.NoError(t, CreatePendingRepositoryTransfer(doer, user2, repo.ID, nil)) @@ -41,7 +41,7 @@ func TestRepositoryTransfer(t *testing.T) { assert.NoError(t, transfer.LoadAttributes()) assert.Equal(t, "user2", transfer.Recipient.Name) - user6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Only transfer can be started at any given time err = CreatePendingRepositoryTransfer(doer, user6, repo.ID, nil) diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 7f9af553747c..58656f781f13 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -120,11 +120,9 @@ func MainTest(m *testing.M, testOpts *TestOptions) { fatalTestError("util.CopyDir: %v\n", err) } - if err = git.InitOnceWithSync(context.Background()); err != nil { + if err = git.InitFull(context.Background()); err != nil { fatalTestError("git.Init: %v\n", err) } - git.CheckLFSVersion() - ownerDirs, err := os.ReadDir(setting.RepoRootPath) if err != nil { fatalTestError("unable to read the new repo root: %v\n", err) @@ -206,8 +204,6 @@ func PrepareTestEnv(t testing.TB) { assert.NoError(t, util.RemoveAll(setting.RepoRootPath)) metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta") assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath)) - assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again - ownerDirs, err := os.ReadDir(setting.RepoRootPath) assert.NoError(t, err) for _, ownerDir := range ownerDirs { diff --git a/models/unittest/unit_tests.go b/models/unittest/unit_tests.go index 6c20c2781bb4..c8673debed02 100644 --- a/models/unittest/unit_tests.go +++ b/models/unittest/unit_tests.go @@ -55,7 +55,7 @@ func BeanExists(t assert.TestingT, bean interface{}, conditions ...interface{}) } // AssertExistsAndLoadBean assert that a bean exists and load it from the test database -func AssertExistsAndLoadBean(t assert.TestingT, bean interface{}, conditions ...interface{}) interface{} { +func AssertExistsAndLoadBean[T any](t assert.TestingT, bean T, conditions ...interface{}) T { exists, err := LoadBeanIfExists(bean, conditions...) assert.NoError(t, err) assert.True(t, exists, diff --git a/models/user.go b/models/user.go index 86a714e746bb..4afbb9bea5c7 100644 --- a/models/user.go +++ b/models/user.go @@ -85,6 +85,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) (err error) &organization.TeamUser{UID: u.ID}, &issues_model.Stopwatch{UserID: u.ID}, &user_model.Setting{UserID: u.ID}, + &user_model.UserBadge{UserID: u.ID}, &pull_model.AutoMerge{DoerID: u.ID}, &pull_model.ReviewState{UserID: u.ID}, ); err != nil { diff --git a/models/user/badge.go b/models/user/badge.go new file mode 100644 index 000000000000..5ff840cb8c35 --- /dev/null +++ b/models/user/badge.go @@ -0,0 +1,42 @@ +// 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 user + +import ( + "context" + + "code.gitea.io/gitea/models/db" +) + +// Badge represents a user badge +type Badge struct { + ID int64 `xorm:"pk autoincr"` + Description string + ImageURL string +} + +// UserBadge represents a user badge +type UserBadge struct { + ID int64 `xorm:"pk autoincr"` + BadgeID int64 + UserID int64 `xorm:"INDEX"` +} + +func init() { + db.RegisterModel(new(Badge)) + db.RegisterModel(new(UserBadge)) +} + +// GetUserBadges returns the user's badges. +func GetUserBadges(ctx context.Context, u *User) ([]*Badge, int64, error) { + sess := db.GetEngine(ctx). + Select("`badge`.*"). + Join("INNER", "user_badge", "`user_badge`.badge_id=badge.id"). + Where("user_badge.user_id=?", u.ID) + + badges := make([]*Badge, 0, 8) + count, err := sess.FindAndCount(&badges) + return badges, count, err +} diff --git a/models/user/search.go b/models/user/search.go index f8e6c89f0680..0aa9949367af 100644 --- a/models/user/search.go +++ b/models/user/search.go @@ -9,7 +9,6 @@ import ( "strings" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -125,28 +124,6 @@ func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) { return users, count, sessQuery.Find(&users) } -// IterateUser iterate users -func IterateUser(f func(user *User) error) error { - var start int - batchSize := setting.Database.IterateBufferSize - for { - users := make([]*User, 0, batchSize) - if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&users); err != nil { - return err - } - if len(users) == 0 { - return nil - } - start += len(users) - - for _, user := range users { - if err := f(user); err != nil { - return err - } - } - } -} - // BuildCanSeeUserCondition creates a condition which can be used to restrict results to users/orgs the actor can see func BuildCanSeeUserCondition(actor *User) builder.Cond { if actor != nil { diff --git a/models/user/user_test.go b/models/user/user_test.go index 489ee3b05da3..940382cdafa2 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -22,7 +22,7 @@ import ( func TestOAuth2Application_LoadUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: 1}).(*auth.OAuth2Application) + app := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: 1}) user, err := user_model.GetUserByID(app.UID) assert.NoError(t, err) assert.NotNil(t, user) @@ -41,10 +41,10 @@ func TestGetUserEmailsByNames(t *testing.T) { func TestCanCreateOrganization(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) assert.True(t, admin.CanCreateOrganization()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.True(t, user.CanCreateOrganization()) // Disable user create organization permission. user.AllowCreateOrganization = false @@ -141,7 +141,7 @@ func TestEmailNotificationPreferences(t *testing.T) { {user_model.EmailNotificationsEnabled, 8}, {user_model.EmailNotificationsOnMention, 9}, } { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.userID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.userID}) assert.Equal(t, test.expected, user.EmailNotifications()) // Try all possible settings @@ -242,7 +242,7 @@ func TestCreateUserInvalidEmail(t *testing.T) { func TestCreateUserEmailAlreadyUsed(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // add new user with user2's email user.Name = "testuser" @@ -288,18 +288,18 @@ func TestGetMaileableUsersByIDs(t *testing.T) { func TestUpdateUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) user.KeepActivityPrivate = true assert.NoError(t, user_model.UpdateUser(db.DefaultContext, user, false)) - user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.True(t, user.KeepActivityPrivate) setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false} user.KeepActivityPrivate = false user.Visibility = structs.VisibleTypePrivate assert.Error(t, user_model.UpdateUser(db.DefaultContext, user, false)) - user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.True(t, user.KeepActivityPrivate) user.Email = "no mail@mail.org" @@ -310,7 +310,7 @@ func TestNewUserRedirect(t *testing.T) { // redirect to a completely new name assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername")) unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{ @@ -327,7 +327,7 @@ func TestNewUserRedirect2(t *testing.T) { // redirect to previously used name assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "olduser1")) unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{ @@ -344,7 +344,7 @@ func TestNewUserRedirect3(t *testing.T) { // redirect for a previously-unredirected user assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.NoError(t, user_model.NewUserRedirect(db.DefaultContext, user.ID, user.Name, "newusername")) unittest.AssertExistsAndLoadBean(t, &user_model.Redirect{ diff --git a/models/user_heatmap_test.go b/models/user_heatmap_test.go index 9361cb3452fa..1ff7bc6ed213 100644 --- a/models/user_heatmap_test.go +++ b/models/user_heatmap_test.go @@ -63,7 +63,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { defer timeutil.Unset() for _, tc := range testCases { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: tc.userID}) doer := &user_model.User{ID: tc.doerID} _, err := unittest.LoadBeanIfExists(doer) diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 1b79a414ade5..478a6a29ff23 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -399,6 +399,10 @@ func CreateWebhook(ctx context.Context, w *Webhook) error { // CreateWebhooks creates multiple web hooks func CreateWebhooks(ctx context.Context, ws []*Webhook) error { + // xorm returns err "no element on slice when insert" for empty slices. + if len(ws) == 0 { + return nil + } for i := 0; i < len(ws); i++ { ws[i].Type = strings.TrimSpace(ws[i].Type) } diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index 4bc811586d9a..1d77ee2a41ad 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -31,14 +31,14 @@ func TestIsValidHookContentType(t *testing.T) { func TestWebhook_History(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - webhook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 1}).(*Webhook) + webhook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 1}) tasks, err := webhook.History(0) assert.NoError(t, err) if assert.Len(t, tasks, 1) { assert.Equal(t, int64(1), tasks[0].ID) } - webhook = unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 2}).(*Webhook) + webhook = unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 2}) tasks, err = webhook.History(0) assert.NoError(t, err) assert.Len(t, tasks, 0) @@ -46,7 +46,7 @@ func TestWebhook_History(t *testing.T) { func TestWebhook_UpdateEvent(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - webhook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 1}).(*Webhook) + webhook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 1}) hookEvent := &HookEvent{ PushOnly: true, SendEverything: false, @@ -162,7 +162,7 @@ func TestGetWebhooksByOrgID(t *testing.T) { func TestUpdateWebhook(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 2}).(*Webhook) + hook := unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 2}) hook.IsActive = true hook.ContentType = ContentTypeForm unittest.AssertNotExistsBean(t, hook) @@ -220,7 +220,7 @@ func TestCreateHookTask(t *testing.T) { func TestUpdateHookTask(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hook := unittest.AssertExistsAndLoadBean(t, &HookTask{ID: 1}).(*HookTask) + hook := unittest.AssertExistsAndLoadBean(t, &HookTask{ID: 1}) hook.PayloadContent = "new payload content" hook.DeliveredString = "new delivered string" hook.IsDelivered = true diff --git a/modules/activitypub/client_test.go b/modules/activitypub/client_test.go index b93ef5ac988a..62068d53b3df 100644 --- a/modules/activitypub/client_test.go +++ b/modules/activitypub/client_test.go @@ -23,7 +23,7 @@ import ( func TestActivityPubSignedPost(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) pubID := "https://example.com/pubID" c, err := NewClient(user, pubID) assert.NoError(t, err) diff --git a/modules/activitypub/user_settings_test.go b/modules/activitypub/user_settings_test.go index 90c6f680f993..beefde232f56 100644 --- a/modules/activitypub/user_settings_test.go +++ b/modules/activitypub/user_settings_test.go @@ -17,7 +17,7 @@ import ( func TestUserSettings(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) pub, priv, err := GetKeyPair(user1) assert.NoError(t, err) pub1, err := GetPublicKey(user1) diff --git a/modules/charset/ambiguous.go b/modules/charset/ambiguous.go new file mode 100644 index 000000000000..9dab3b0951bf --- /dev/null +++ b/modules/charset/ambiguous.go @@ -0,0 +1,54 @@ +// This file is generated by modules/charset/ambiguous/generate.go DO NOT EDIT +// 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 charset + +import ( + "sort" + "strings" + "unicode" + + "code.gitea.io/gitea/modules/translation" +) + +// AmbiguousTablesForLocale provides the table of ambiguous characters for this locale. +func AmbiguousTablesForLocale(locale translation.Locale) []*AmbiguousTable { + key := locale.Language() + var table *AmbiguousTable + var ok bool + for len(key) > 0 { + if table, ok = AmbiguousCharacters[key]; ok { + break + } + idx := strings.LastIndexAny(key, "-_") + if idx < 0 { + key = "" + } else { + key = key[:idx] + } + } + if table == nil { + table = AmbiguousCharacters["_default"] + } + + return []*AmbiguousTable{ + table, + AmbiguousCharacters["_common"], + } +} + +func isAmbiguous(r rune, confusableTo *rune, tables ...*AmbiguousTable) bool { + for _, table := range tables { + if !unicode.Is(table.RangeTable, r) { + continue + } + i := sort.Search(len(table.Confusable), func(i int) bool { + return table.Confusable[i] >= r + }) + (*confusableTo) = table.With[i] + return true + } + return false +} diff --git a/modules/charset/ambiguous/ambiguous.json b/modules/charset/ambiguous/ambiguous.json new file mode 100644 index 000000000000..d0f69f6ae2b1 --- /dev/null +++ b/modules/charset/ambiguous/ambiguous.json @@ -0,0 +1 @@ +"{\"_common\":[8232,32,8233,32,5760,32,8192,32,8193,32,8194,32,8195,32,8196,32,8197,32,8198,32,8200,32,8201,32,8202,32,8287,32,8199,32,8239,32,2042,95,65101,95,65102,95,65103,95,8208,45,8209,45,8210,45,65112,45,1748,45,8259,45,727,45,8722,45,10134,45,11450,45,1549,44,1643,44,8218,44,184,44,42233,44,894,59,2307,58,2691,58,1417,58,1795,58,1796,58,5868,58,65072,58,6147,58,6153,58,8282,58,1475,58,760,58,42889,58,8758,58,720,58,42237,58,451,33,11601,33,660,63,577,63,2429,63,5038,63,42731,63,119149,46,8228,46,1793,46,1794,46,42510,46,68176,46,1632,46,1776,46,42232,46,1373,96,65287,96,8219,96,8242,96,1370,96,1523,96,8175,96,65344,96,900,96,8189,96,8125,96,8127,96,8190,96,697,96,884,96,712,96,714,96,715,96,756,96,699,96,701,96,700,96,702,96,42892,96,1497,96,2036,96,2037,96,5194,96,5836,96,94033,96,94034,96,65339,91,10088,40,10098,40,12308,40,64830,40,65341,93,10089,41,10099,41,12309,41,64831,41,10100,123,119060,123,10101,125,65342,94,8270,42,1645,42,8727,42,66335,42,5941,47,8257,47,8725,47,8260,47,9585,47,10187,47,10744,47,119354,47,12755,47,12339,47,11462,47,20031,47,12035,47,65340,92,65128,92,8726,92,10189,92,10741,92,10745,92,119311,92,119355,92,12756,92,20022,92,12034,92,42872,38,708,94,710,94,5869,43,10133,43,66203,43,8249,60,10094,60,706,60,119350,60,5176,60,5810,60,5120,61,11840,61,12448,61,42239,61,8250,62,10095,62,707,62,119351,62,5171,62,94015,62,8275,126,732,126,8128,126,8764,126,65372,124,65293,45,120784,50,120794,50,120804,50,120814,50,120824,50,130034,50,42842,50,423,50,1000,50,42564,50,5311,50,42735,50,119302,51,120785,51,120795,51,120805,51,120815,51,120825,51,130035,51,42923,51,540,51,439,51,42858,51,11468,51,1248,51,94011,51,71882,51,120786,52,120796,52,120806,52,120816,52,120826,52,130036,52,5070,52,71855,52,120787,53,120797,53,120807,53,120817,53,120827,53,130037,53,444,53,71867,53,120788,54,120798,54,120808,54,120818,54,120828,54,130038,54,11474,54,5102,54,71893,54,119314,55,120789,55,120799,55,120809,55,120819,55,120829,55,130039,55,66770,55,71878,55,2819,56,2538,56,2666,56,125131,56,120790,56,120800,56,120810,56,120820,56,120830,56,130040,56,547,56,546,56,66330,56,2663,57,2920,57,2541,57,3437,57,120791,57,120801,57,120811,57,120821,57,120831,57,130041,57,42862,57,11466,57,71884,57,71852,57,71894,57,9082,97,65345,97,119834,97,119886,97,119938,97,119990,97,120042,97,120094,97,120146,97,120198,97,120250,97,120302,97,120354,97,120406,97,120458,97,593,97,945,97,120514,97,120572,97,120630,97,120688,97,120746,97,65313,65,119808,65,119860,65,119912,65,119964,65,120016,65,120068,65,120120,65,120172,65,120224,65,120276,65,120328,65,120380,65,120432,65,913,65,120488,65,120546,65,120604,65,120662,65,120720,65,5034,65,5573,65,42222,65,94016,65,66208,65,119835,98,119887,98,119939,98,119991,98,120043,98,120095,98,120147,98,120199,98,120251,98,120303,98,120355,98,120407,98,120459,98,388,98,5071,98,5234,98,5551,98,65314,66,8492,66,119809,66,119861,66,119913,66,120017,66,120069,66,120121,66,120173,66,120225,66,120277,66,120329,66,120381,66,120433,66,42932,66,914,66,120489,66,120547,66,120605,66,120663,66,120721,66,5108,66,5623,66,42192,66,66178,66,66209,66,66305,66,65347,99,8573,99,119836,99,119888,99,119940,99,119992,99,120044,99,120096,99,120148,99,120200,99,120252,99,120304,99,120356,99,120408,99,120460,99,7428,99,1010,99,11429,99,43951,99,66621,99,128844,67,71922,67,71913,67,65315,67,8557,67,8450,67,8493,67,119810,67,119862,67,119914,67,119966,67,120018,67,120174,67,120226,67,120278,67,120330,67,120382,67,120434,67,1017,67,11428,67,5087,67,42202,67,66210,67,66306,67,66581,67,66844,67,8574,100,8518,100,119837,100,119889,100,119941,100,119993,100,120045,100,120097,100,120149,100,120201,100,120253,100,120305,100,120357,100,120409,100,120461,100,1281,100,5095,100,5231,100,42194,100,8558,68,8517,68,119811,68,119863,68,119915,68,119967,68,120019,68,120071,68,120123,68,120175,68,120227,68,120279,68,120331,68,120383,68,120435,68,5024,68,5598,68,5610,68,42195,68,8494,101,65349,101,8495,101,8519,101,119838,101,119890,101,119942,101,120046,101,120098,101,120150,101,120202,101,120254,101,120306,101,120358,101,120410,101,120462,101,43826,101,1213,101,8959,69,65317,69,8496,69,119812,69,119864,69,119916,69,120020,69,120072,69,120124,69,120176,69,120228,69,120280,69,120332,69,120384,69,120436,69,917,69,120492,69,120550,69,120608,69,120666,69,120724,69,11577,69,5036,69,42224,69,71846,69,71854,69,66182,69,119839,102,119891,102,119943,102,119995,102,120047,102,120099,102,120151,102,120203,102,120255,102,120307,102,120359,102,120411,102,120463,102,43829,102,42905,102,383,102,7837,102,1412,102,119315,70,8497,70,119813,70,119865,70,119917,70,120021,70,120073,70,120125,70,120177,70,120229,70,120281,70,120333,70,120385,70,120437,70,42904,70,988,70,120778,70,5556,70,42205,70,71874,70,71842,70,66183,70,66213,70,66853,70,65351,103,8458,103,119840,103,119892,103,119944,103,120048,103,120100,103,120152,103,120204,103,120256,103,120308,103,120360,103,120412,103,120464,103,609,103,7555,103,397,103,1409,103,119814,71,119866,71,119918,71,119970,71,120022,71,120074,71,120126,71,120178,71,120230,71,120282,71,120334,71,120386,71,120438,71,1292,71,5056,71,5107,71,42198,71,65352,104,8462,104,119841,104,119945,104,119997,104,120049,104,120101,104,120153,104,120205,104,120257,104,120309,104,120361,104,120413,104,120465,104,1211,104,1392,104,5058,104,65320,72,8459,72,8460,72,8461,72,119815,72,119867,72,119919,72,120023,72,120179,72,120231,72,120283,72,120335,72,120387,72,120439,72,919,72,120494,72,120552,72,120610,72,120668,72,120726,72,11406,72,5051,72,5500,72,42215,72,66255,72,731,105,9075,105,65353,105,8560,105,8505,105,8520,105,119842,105,119894,105,119946,105,119998,105,120050,105,120102,105,120154,105,120206,105,120258,105,120310,105,120362,105,120414,105,120466,105,120484,105,618,105,617,105,953,105,8126,105,890,105,120522,105,120580,105,120638,105,120696,105,120754,105,1110,105,42567,105,1231,105,43893,105,5029,105,71875,105,65354,106,8521,106,119843,106,119895,106,119947,106,119999,106,120051,106,120103,106,120155,106,120207,106,120259,106,120311,106,120363,106,120415,106,120467,106,1011,106,1112,106,65322,74,119817,74,119869,74,119921,74,119973,74,120025,74,120077,74,120129,74,120181,74,120233,74,120285,74,120337,74,120389,74,120441,74,42930,74,895,74,1032,74,5035,74,5261,74,42201,74,119844,107,119896,107,119948,107,120000,107,120052,107,120104,107,120156,107,120208,107,120260,107,120312,107,120364,107,120416,107,120468,107,8490,75,65323,75,119818,75,119870,75,119922,75,119974,75,120026,75,120078,75,120130,75,120182,75,120234,75,120286,75,120338,75,120390,75,120442,75,922,75,120497,75,120555,75,120613,75,120671,75,120729,75,11412,75,5094,75,5845,75,42199,75,66840,75,1472,108,8739,73,9213,73,65512,73,1633,108,1777,73,66336,108,125127,108,120783,73,120793,73,120803,73,120813,73,120823,73,130033,73,65321,73,8544,73,8464,73,8465,73,119816,73,119868,73,119920,73,120024,73,120128,73,120180,73,120232,73,120284,73,120336,73,120388,73,120440,73,65356,108,8572,73,8467,108,119845,108,119897,108,119949,108,120001,108,120053,108,120105,73,120157,73,120209,73,120261,73,120313,73,120365,73,120417,73,120469,73,448,73,120496,73,120554,73,120612,73,120670,73,120728,73,11410,73,1030,73,1216,73,1493,108,1503,108,1575,108,126464,108,126592,108,65166,108,65165,108,1994,108,11599,73,5825,73,42226,73,93992,73,66186,124,66313,124,119338,76,8556,76,8466,76,119819,76,119871,76,119923,76,120027,76,120079,76,120131,76,120183,76,120235,76,120287,76,120339,76,120391,76,120443,76,11472,76,5086,76,5290,76,42209,76,93974,76,71843,76,71858,76,66587,76,66854,76,65325,77,8559,77,8499,77,119820,77,119872,77,119924,77,120028,77,120080,77,120132,77,120184,77,120236,77,120288,77,120340,77,120392,77,120444,77,924,77,120499,77,120557,77,120615,77,120673,77,120731,77,1018,77,11416,77,5047,77,5616,77,5846,77,42207,77,66224,77,66321,77,119847,110,119899,110,119951,110,120003,110,120055,110,120107,110,120159,110,120211,110,120263,110,120315,110,120367,110,120419,110,120471,110,1400,110,1404,110,65326,78,8469,78,119821,78,119873,78,119925,78,119977,78,120029,78,120081,78,120185,78,120237,78,120289,78,120341,78,120393,78,120445,78,925,78,120500,78,120558,78,120616,78,120674,78,120732,78,11418,78,42208,78,66835,78,3074,111,3202,111,3330,111,3458,111,2406,111,2662,111,2790,111,3046,111,3174,111,3302,111,3430,111,3664,111,3792,111,4160,111,1637,111,1781,111,65359,111,8500,111,119848,111,119900,111,119952,111,120056,111,120108,111,120160,111,120212,111,120264,111,120316,111,120368,111,120420,111,120472,111,7439,111,7441,111,43837,111,959,111,120528,111,120586,111,120644,111,120702,111,120760,111,963,111,120532,111,120590,111,120648,111,120706,111,120764,111,11423,111,4351,111,1413,111,1505,111,1607,111,126500,111,126564,111,126596,111,65259,111,65260,111,65258,111,65257,111,1726,111,64428,111,64429,111,64427,111,64426,111,1729,111,64424,111,64425,111,64423,111,64422,111,1749,111,3360,111,4125,111,66794,111,71880,111,71895,111,66604,111,1984,79,2534,79,2918,79,12295,79,70864,79,71904,79,120782,79,120792,79,120802,79,120812,79,120822,79,130032,79,65327,79,119822,79,119874,79,119926,79,119978,79,120030,79,120082,79,120134,79,120186,79,120238,79,120290,79,120342,79,120394,79,120446,79,927,79,120502,79,120560,79,120618,79,120676,79,120734,79,11422,79,1365,79,11604,79,4816,79,2848,79,66754,79,42227,79,71861,79,66194,79,66219,79,66564,79,66838,79,9076,112,65360,112,119849,112,119901,112,119953,112,120005,112,120057,112,120109,112,120161,112,120213,112,120265,112,120317,112,120369,112,120421,112,120473,112,961,112,120530,112,120544,112,120588,112,120602,112,120646,112,120660,112,120704,112,120718,112,120762,112,120776,112,11427,112,65328,80,8473,80,119823,80,119875,80,119927,80,119979,80,120031,80,120083,80,120187,80,120239,80,120291,80,120343,80,120395,80,120447,80,929,80,120504,80,120562,80,120620,80,120678,80,120736,80,11426,80,5090,80,5229,80,42193,80,66197,80,119850,113,119902,113,119954,113,120006,113,120058,113,120110,113,120162,113,120214,113,120266,113,120318,113,120370,113,120422,113,120474,113,1307,113,1379,113,1382,113,8474,81,119824,81,119876,81,119928,81,119980,81,120032,81,120084,81,120188,81,120240,81,120292,81,120344,81,120396,81,120448,81,11605,81,119851,114,119903,114,119955,114,120007,114,120059,114,120111,114,120163,114,120215,114,120267,114,120319,114,120371,114,120423,114,120475,114,43847,114,43848,114,7462,114,11397,114,43905,114,119318,82,8475,82,8476,82,8477,82,119825,82,119877,82,119929,82,120033,82,120189,82,120241,82,120293,82,120345,82,120397,82,120449,82,422,82,5025,82,5074,82,66740,82,5511,82,42211,82,94005,82,65363,115,119852,115,119904,115,119956,115,120008,115,120060,115,120112,115,120164,115,120216,115,120268,115,120320,115,120372,115,120424,115,120476,115,42801,115,445,115,1109,115,43946,115,71873,115,66632,115,65331,83,119826,83,119878,83,119930,83,119982,83,120034,83,120086,83,120138,83,120190,83,120242,83,120294,83,120346,83,120398,83,120450,83,1029,83,1359,83,5077,83,5082,83,42210,83,94010,83,66198,83,66592,83,119853,116,119905,116,119957,116,120009,116,120061,116,120113,116,120165,116,120217,116,120269,116,120321,116,120373,116,120425,116,120477,116,8868,84,10201,84,128872,84,65332,84,119827,84,119879,84,119931,84,119983,84,120035,84,120087,84,120139,84,120191,84,120243,84,120295,84,120347,84,120399,84,120451,84,932,84,120507,84,120565,84,120623,84,120681,84,120739,84,11430,84,5026,84,42196,84,93962,84,71868,84,66199,84,66225,84,66325,84,119854,117,119906,117,119958,117,120010,117,120062,117,120114,117,120166,117,120218,117,120270,117,120322,117,120374,117,120426,117,120478,117,42911,117,7452,117,43854,117,43858,117,651,117,965,117,120534,117,120592,117,120650,117,120708,117,120766,117,1405,117,66806,117,71896,117,8746,85,8899,85,119828,85,119880,85,119932,85,119984,85,120036,85,120088,85,120140,85,120192,85,120244,85,120296,85,120348,85,120400,85,120452,85,1357,85,4608,85,66766,85,5196,85,42228,85,94018,85,71864,85,8744,118,8897,118,65366,118,8564,118,119855,118,119907,118,119959,118,120011,118,120063,118,120115,118,120167,118,120219,118,120271,118,120323,118,120375,118,120427,118,120479,118,7456,118,957,118,120526,118,120584,118,120642,118,120700,118,120758,118,1141,118,1496,118,71430,118,43945,118,71872,118,119309,86,1639,86,1783,86,8548,86,119829,86,119881,86,119933,86,119985,86,120037,86,120089,86,120141,86,120193,86,120245,86,120297,86,120349,86,120401,86,120453,86,1140,86,11576,86,5081,86,5167,86,42719,86,42214,86,93960,86,71840,86,66845,86,623,119,119856,119,119908,119,119960,119,120012,119,120064,119,120116,119,120168,119,120220,119,120272,119,120324,119,120376,119,120428,119,120480,119,7457,119,1121,119,1309,119,1377,119,71434,119,71438,119,71439,119,43907,119,71919,87,71910,87,119830,87,119882,87,119934,87,119986,87,120038,87,120090,87,120142,87,120194,87,120246,87,120298,87,120350,87,120402,87,120454,87,1308,87,5043,87,5076,87,42218,87,5742,120,10539,120,10540,120,10799,120,65368,120,8569,120,119857,120,119909,120,119961,120,120013,120,120065,120,120117,120,120169,120,120221,120,120273,120,120325,120,120377,120,120429,120,120481,120,5441,120,5501,120,5741,88,9587,88,66338,88,71916,88,65336,88,8553,88,119831,88,119883,88,119935,88,119987,88,120039,88,120091,88,120143,88,120195,88,120247,88,120299,88,120351,88,120403,88,120455,88,42931,88,935,88,120510,88,120568,88,120626,88,120684,88,120742,88,11436,88,11613,88,5815,88,42219,88,66192,88,66228,88,66327,88,66855,88,611,121,7564,121,65369,121,119858,121,119910,121,119962,121,120014,121,120066,121,120118,121,120170,121,120222,121,120274,121,120326,121,120378,121,120430,121,120482,121,655,121,7935,121,43866,121,947,121,8509,121,120516,121,120574,121,120632,121,120690,121,120748,121,1199,121,4327,121,71900,121,65337,89,119832,89,119884,89,119936,89,119988,89,120040,89,120092,89,120144,89,120196,89,120248,89,120300,89,120352,89,120404,89,120456,89,933,89,978,89,120508,89,120566,89,120624,89,120682,89,120740,89,11432,89,1198,89,5033,89,5053,89,42220,89,94019,89,71844,89,66226,89,119859,122,119911,122,119963,122,120015,122,120067,122,120119,122,120171,122,120223,122,120275,122,120327,122,120379,122,120431,122,120483,122,7458,122,43923,122,71876,122,66293,90,71909,90,65338,90,8484,90,8488,90,119833,90,119885,90,119937,90,119989,90,120041,90,120197,90,120249,90,120301,90,120353,90,120405,90,120457,90,918,90,120493,90,120551,90,120609,90,120667,90,120725,90,5059,90,42204,90,71849,90,65282,34,65284,36,65285,37,65286,38,65290,42,65291,43,65294,46,65295,47,65296,48,65297,49,65298,50,65299,51,65300,52,65301,53,65302,54,65303,55,65304,56,65305,57,65308,60,65309,61,65310,62,65312,64,65316,68,65318,70,65319,71,65324,76,65329,81,65330,82,65333,85,65334,86,65335,87,65343,95,65346,98,65348,100,65350,102,65355,107,65357,109,65358,110,65361,113,65362,114,65364,116,65365,117,65367,119,65370,122,65371,123,65373,125],\"_default\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"cs\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"de\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"es\":[8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"fr\":[65374,126,65306,58,65281,33,8216,96,8245,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"it\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"ja\":[8211,45,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65292,44,65307,59],\"ko\":[8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"pl\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"pt-BR\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"qps-ploc\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"ru\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,305,105,921,73,1009,112,215,120,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"tr\":[160,32,8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"zh-hans\":[65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41],\"zh-hant\":[8211,45,65374,126,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65307,59]}" \ No newline at end of file diff --git a/modules/charset/ambiguous/generate.go b/modules/charset/ambiguous/generate.go new file mode 100644 index 000000000000..43cdb217a79a --- /dev/null +++ b/modules/charset/ambiguous/generate.go @@ -0,0 +1,178 @@ +// 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 main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "os" + "sort" + "text/template" + "unicode" + + "code.gitea.io/gitea/modules/json" + + "golang.org/x/text/unicode/rangetable" +) + +// ambiguous.json provides a one to one mapping of ambiguous characters to other characters +// See https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json + +type AmbiguousTable struct { + Confusable []rune + With []rune + Locale string + RangeTable *unicode.RangeTable +} + +type RunePair struct { + Confusable rune + With rune +} + +var verbose bool + +func main() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, `%s: Generate AmbiguousCharacter + +Usage: %[1]s [-v] [-o output.go] ambiguous.json +`, os.Args[0]) + flag.PrintDefaults() + } + + output := "" + flag.BoolVar(&verbose, "v", false, "verbose output") + flag.StringVar(&output, "o", "ambiguous_gen.go", "file to output to") + flag.Parse() + input := flag.Arg(0) + if input == "" { + input = "ambiguous.json" + } + + bs, err := os.ReadFile(input) + if err != nil { + fatalf("Unable to read: %s Err: %v", input, err) + } + + var unwrapped string + if err := json.Unmarshal(bs, &unwrapped); err != nil { + fatalf("Unable to unwrap content in: %s Err: %v", input, err) + } + + fromJSON := map[string][]uint32{} + if err := json.Unmarshal([]byte(unwrapped), &fromJSON); err != nil { + fatalf("Unable to unmarshal content in: %s Err: %v", input, err) + } + + tables := make([]*AmbiguousTable, 0, len(fromJSON)) + for locale, chars := range fromJSON { + table := &AmbiguousTable{Locale: locale} + table.Confusable = make([]rune, 0, len(chars)/2) + table.With = make([]rune, 0, len(chars)/2) + pairs := make([]RunePair, len(chars)/2) + for i := 0; i < len(chars); i += 2 { + pairs[i/2].Confusable, pairs[i/2].With = rune(chars[i]), rune(chars[i+1]) + } + sort.Slice(pairs, func(i, j int) bool { + return pairs[i].Confusable < pairs[j].Confusable + }) + for _, pair := range pairs { + table.Confusable = append(table.Confusable, pair.Confusable) + table.With = append(table.With, pair.With) + } + table.RangeTable = rangetable.New(table.Confusable...) + tables = append(tables, table) + } + sort.Slice(tables, func(i, j int) bool { + return tables[i].Locale < tables[j].Locale + }) + data := map[string]interface{}{ + "Tables": tables, + } + + if err := runTemplate(generatorTemplate, output, &data); err != nil { + fatalf("Unable to run template: %v", err) + } +} + +func runTemplate(t *template.Template, filename string, data interface{}) error { + buf := bytes.NewBuffer(nil) + if err := t.Execute(buf, data); err != nil { + return fmt.Errorf("unable to execute template: %w", err) + } + bs, err := format.Source(buf.Bytes()) + if err != nil { + verbosef("Bad source:\n%s", buf.String()) + return fmt.Errorf("unable to format source: %w", err) + } + file, err := os.Create(filename) + if err != nil { + return fmt.Errorf("failed to create file %s because %w", filename, err) + } + defer file.Close() + _, err = file.Write(bs) + if err != nil { + return fmt.Errorf("unable to write generated source: %w", err) + } + return nil +} + +var generatorTemplate = template.Must(template.New("ambiguousTemplate").Parse(`// This file is generated by modules/charset/ambiguous/generate.go DO NOT EDIT +// 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 charset + +import "unicode" + +// This file is generated from https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json + +// AmbiguousTable matches a confusable rune with its partner for the Locale +type AmbiguousTable struct { + Confusable []rune + With []rune + Locale string + RangeTable *unicode.RangeTable +} + +// AmbiguousCharacters provides a map by locale name to the confusable characters in that locale +var AmbiguousCharacters = map[string]*AmbiguousTable{ + {{range .Tables}}{{printf "%q:" .Locale}} { + Confusable: []rune{ {{range .Confusable}}{{.}},{{end}} }, + With: []rune{ {{range .With}}{{.}},{{end}} }, + Locale: {{printf "%q" .Locale}}, + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {{range .RangeTable.R16 }} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}}, + {{end}} }, + R32: []unicode.Range32{ + {{range .RangeTable.R32}} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}}, + {{end}} }, + LatinOffset: {{.RangeTable.LatinOffset}}, + }, + }, + {{end}} +} + +`)) + +func logf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, format+"\n", args...) +} + +func verbosef(format string, args ...interface{}) { + if verbose { + logf(format, args...) + } +} + +func fatalf(format string, args ...interface{}) { + logf("fatal: "+format+"\n", args...) + os.Exit(1) +} diff --git a/modules/charset/ambiguous_gen.go b/modules/charset/ambiguous_gen.go new file mode 100644 index 000000000000..cc270affac52 --- /dev/null +++ b/modules/charset/ambiguous_gen.go @@ -0,0 +1,837 @@ +// This file is generated by modules/charset/ambiguous/generate.go DO NOT EDIT +// 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 charset + +import "unicode" + +// This file is generated from https://github.com/hediet/vscode-unicode-data/blob/main/out/ambiguous.json + +// AmbiguousTable matches a confusable rune with its partner for the Locale +type AmbiguousTable struct { + Confusable []rune + With []rune + Locale string + RangeTable *unicode.RangeTable +} + +// AmbiguousCharacters provides a map by locale name to the confusable characters in that locale +var AmbiguousCharacters = map[string]*AmbiguousTable{ + "_common": { + Confusable: []rune{184, 383, 388, 397, 422, 423, 439, 444, 445, 448, 451, 540, 546, 547, 577, 593, 609, 611, 617, 618, 623, 651, 655, 660, 697, 699, 700, 701, 702, 706, 707, 708, 710, 712, 714, 715, 720, 727, 731, 732, 756, 760, 884, 890, 894, 895, 900, 913, 914, 917, 918, 919, 922, 924, 925, 927, 929, 932, 933, 935, 945, 947, 953, 957, 959, 961, 963, 965, 978, 988, 1000, 1010, 1011, 1017, 1018, 1029, 1030, 1032, 1109, 1110, 1112, 1121, 1140, 1141, 1198, 1199, 1211, 1213, 1216, 1231, 1248, 1281, 1292, 1307, 1308, 1309, 1357, 1359, 1365, 1370, 1373, 1377, 1379, 1382, 1392, 1400, 1404, 1405, 1409, 1412, 1413, 1417, 1472, 1475, 1493, 1496, 1497, 1503, 1505, 1523, 1549, 1575, 1607, 1632, 1633, 1637, 1639, 1643, 1645, 1726, 1729, 1748, 1749, 1776, 1777, 1781, 1783, 1793, 1794, 1795, 1796, 1984, 1994, 2036, 2037, 2042, 2307, 2406, 2429, 2534, 2538, 2541, 2662, 2663, 2666, 2691, 2790, 2819, 2848, 2918, 2920, 3046, 3074, 3174, 3202, 3302, 3330, 3360, 3430, 3437, 3458, 3664, 3792, 4125, 4160, 4327, 4351, 4608, 4816, 5024, 5025, 5026, 5029, 5033, 5034, 5035, 5036, 5038, 5043, 5047, 5051, 5053, 5056, 5058, 5059, 5070, 5071, 5074, 5076, 5077, 5081, 5082, 5086, 5087, 5090, 5094, 5095, 5102, 5107, 5108, 5120, 5167, 5171, 5176, 5194, 5196, 5229, 5231, 5234, 5261, 5290, 5311, 5441, 5500, 5501, 5511, 5551, 5556, 5573, 5598, 5610, 5616, 5623, 5741, 5742, 5760, 5810, 5815, 5825, 5836, 5845, 5846, 5868, 5869, 5941, 6147, 6153, 7428, 7439, 7441, 7452, 7456, 7457, 7458, 7462, 7555, 7564, 7837, 7935, 8125, 8126, 8127, 8128, 8175, 8189, 8190, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8208, 8209, 8210, 8218, 8219, 8228, 8232, 8233, 8239, 8242, 8249, 8250, 8257, 8259, 8260, 8270, 8275, 8282, 8287, 8450, 8458, 8459, 8460, 8461, 8462, 8464, 8465, 8466, 8467, 8469, 8473, 8474, 8475, 8476, 8477, 8484, 8488, 8490, 8492, 8493, 8494, 8495, 8496, 8497, 8499, 8500, 8505, 8509, 8517, 8518, 8519, 8520, 8521, 8544, 8548, 8553, 8556, 8557, 8558, 8559, 8560, 8564, 8569, 8572, 8573, 8574, 8722, 8725, 8726, 8727, 8739, 8744, 8746, 8758, 8764, 8868, 8897, 8899, 8959, 9075, 9076, 9082, 9213, 9585, 9587, 10088, 10089, 10094, 10095, 10098, 10099, 10100, 10101, 10133, 10134, 10187, 10189, 10201, 10539, 10540, 10741, 10744, 10745, 10799, 11397, 11406, 11410, 11412, 11416, 11418, 11422, 11423, 11426, 11427, 11428, 11429, 11430, 11432, 11436, 11450, 11462, 11466, 11468, 11472, 11474, 11576, 11577, 11599, 11601, 11604, 11605, 11613, 11840, 12034, 12035, 12295, 12308, 12309, 12339, 12448, 12755, 12756, 20022, 20031, 42192, 42193, 42194, 42195, 42196, 42198, 42199, 42201, 42202, 42204, 42205, 42207, 42208, 42209, 42210, 42211, 42214, 42215, 42218, 42219, 42220, 42222, 42224, 42226, 42227, 42228, 42232, 42233, 42237, 42239, 42510, 42564, 42567, 42719, 42731, 42735, 42801, 42842, 42858, 42862, 42872, 42889, 42892, 42904, 42905, 42911, 42923, 42930, 42931, 42932, 43826, 43829, 43837, 43847, 43848, 43854, 43858, 43866, 43893, 43905, 43907, 43923, 43945, 43946, 43951, 64422, 64423, 64424, 64425, 64426, 64427, 64428, 64429, 64830, 64831, 65072, 65101, 65102, 65103, 65112, 65128, 65165, 65166, 65257, 65258, 65259, 65260, 65282, 65284, 65285, 65286, 65287, 65290, 65291, 65293, 65294, 65295, 65296, 65297, 65298, 65299, 65300, 65301, 65302, 65303, 65304, 65305, 65308, 65309, 65310, 65312, 65313, 65314, 65315, 65316, 65317, 65318, 65319, 65320, 65321, 65322, 65323, 65324, 65325, 65326, 65327, 65328, 65329, 65330, 65331, 65332, 65333, 65334, 65335, 65336, 65337, 65338, 65339, 65340, 65341, 65342, 65343, 65344, 65345, 65346, 65347, 65348, 65349, 65350, 65351, 65352, 65353, 65354, 65355, 65356, 65357, 65358, 65359, 65360, 65361, 65362, 65363, 65364, 65365, 65366, 65367, 65368, 65369, 65370, 65371, 65372, 65373, 65512, 66178, 66182, 66183, 66186, 66192, 66194, 66197, 66198, 66199, 66203, 66208, 66209, 66210, 66213, 66219, 66224, 66225, 66226, 66228, 66255, 66293, 66305, 66306, 66313, 66321, 66325, 66327, 66330, 66335, 66336, 66338, 66564, 66581, 66587, 66592, 66604, 66621, 66632, 66740, 66754, 66766, 66770, 66794, 66806, 66835, 66838, 66840, 66844, 66845, 66853, 66854, 66855, 68176, 70864, 71430, 71434, 71438, 71439, 71840, 71842, 71843, 71844, 71846, 71849, 71852, 71854, 71855, 71858, 71861, 71864, 71867, 71868, 71872, 71873, 71874, 71875, 71876, 71878, 71880, 71882, 71884, 71893, 71894, 71895, 71896, 71900, 71904, 71909, 71910, 71913, 71916, 71919, 71922, 93960, 93962, 93974, 93992, 94005, 94010, 94011, 94015, 94016, 94018, 94019, 94033, 94034, 119060, 119149, 119302, 119309, 119311, 119314, 119315, 119318, 119338, 119350, 119351, 119354, 119355, 119808, 119809, 119810, 119811, 119812, 119813, 119814, 119815, 119816, 119817, 119818, 119819, 119820, 119821, 119822, 119823, 119824, 119825, 119826, 119827, 119828, 119829, 119830, 119831, 119832, 119833, 119834, 119835, 119836, 119837, 119838, 119839, 119840, 119841, 119842, 119843, 119844, 119845, 119847, 119848, 119849, 119850, 119851, 119852, 119853, 119854, 119855, 119856, 119857, 119858, 119859, 119860, 119861, 119862, 119863, 119864, 119865, 119866, 119867, 119868, 119869, 119870, 119871, 119872, 119873, 119874, 119875, 119876, 119877, 119878, 119879, 119880, 119881, 119882, 119883, 119884, 119885, 119886, 119887, 119888, 119889, 119890, 119891, 119892, 119894, 119895, 119896, 119897, 119899, 119900, 119901, 119902, 119903, 119904, 119905, 119906, 119907, 119908, 119909, 119910, 119911, 119912, 119913, 119914, 119915, 119916, 119917, 119918, 119919, 119920, 119921, 119922, 119923, 119924, 119925, 119926, 119927, 119928, 119929, 119930, 119931, 119932, 119933, 119934, 119935, 119936, 119937, 119938, 119939, 119940, 119941, 119942, 119943, 119944, 119945, 119946, 119947, 119948, 119949, 119951, 119952, 119953, 119954, 119955, 119956, 119957, 119958, 119959, 119960, 119961, 119962, 119963, 119964, 119966, 119967, 119970, 119973, 119974, 119977, 119978, 119979, 119980, 119982, 119983, 119984, 119985, 119986, 119987, 119988, 119989, 119990, 119991, 119992, 119993, 119995, 119997, 119998, 119999, 120000, 120001, 120003, 120005, 120006, 120007, 120008, 120009, 120010, 120011, 120012, 120013, 120014, 120015, 120016, 120017, 120018, 120019, 120020, 120021, 120022, 120023, 120024, 120025, 120026, 120027, 120028, 120029, 120030, 120031, 120032, 120033, 120034, 120035, 120036, 120037, 120038, 120039, 120040, 120041, 120042, 120043, 120044, 120045, 120046, 120047, 120048, 120049, 120050, 120051, 120052, 120053, 120055, 120056, 120057, 120058, 120059, 120060, 120061, 120062, 120063, 120064, 120065, 120066, 120067, 120068, 120069, 120071, 120072, 120073, 120074, 120077, 120078, 120079, 120080, 120081, 120082, 120083, 120084, 120086, 120087, 120088, 120089, 120090, 120091, 120092, 120094, 120095, 120096, 120097, 120098, 120099, 120100, 120101, 120102, 120103, 120104, 120105, 120107, 120108, 120109, 120110, 120111, 120112, 120113, 120114, 120115, 120116, 120117, 120118, 120119, 120120, 120121, 120123, 120124, 120125, 120126, 120128, 120129, 120130, 120131, 120132, 120134, 120138, 120139, 120140, 120141, 120142, 120143, 120144, 120146, 120147, 120148, 120149, 120150, 120151, 120152, 120153, 120154, 120155, 120156, 120157, 120159, 120160, 120161, 120162, 120163, 120164, 120165, 120166, 120167, 120168, 120169, 120170, 120171, 120172, 120173, 120174, 120175, 120176, 120177, 120178, 120179, 120180, 120181, 120182, 120183, 120184, 120185, 120186, 120187, 120188, 120189, 120190, 120191, 120192, 120193, 120194, 120195, 120196, 120197, 120198, 120199, 120200, 120201, 120202, 120203, 120204, 120205, 120206, 120207, 120208, 120209, 120211, 120212, 120213, 120214, 120215, 120216, 120217, 120218, 120219, 120220, 120221, 120222, 120223, 120224, 120225, 120226, 120227, 120228, 120229, 120230, 120231, 120232, 120233, 120234, 120235, 120236, 120237, 120238, 120239, 120240, 120241, 120242, 120243, 120244, 120245, 120246, 120247, 120248, 120249, 120250, 120251, 120252, 120253, 120254, 120255, 120256, 120257, 120258, 120259, 120260, 120261, 120263, 120264, 120265, 120266, 120267, 120268, 120269, 120270, 120271, 120272, 120273, 120274, 120275, 120276, 120277, 120278, 120279, 120280, 120281, 120282, 120283, 120284, 120285, 120286, 120287, 120288, 120289, 120290, 120291, 120292, 120293, 120294, 120295, 120296, 120297, 120298, 120299, 120300, 120301, 120302, 120303, 120304, 120305, 120306, 120307, 120308, 120309, 120310, 120311, 120312, 120313, 120315, 120316, 120317, 120318, 120319, 120320, 120321, 120322, 120323, 120324, 120325, 120326, 120327, 120328, 120329, 120330, 120331, 120332, 120333, 120334, 120335, 120336, 120337, 120338, 120339, 120340, 120341, 120342, 120343, 120344, 120345, 120346, 120347, 120348, 120349, 120350, 120351, 120352, 120353, 120354, 120355, 120356, 120357, 120358, 120359, 120360, 120361, 120362, 120363, 120364, 120365, 120367, 120368, 120369, 120370, 120371, 120372, 120373, 120374, 120375, 120376, 120377, 120378, 120379, 120380, 120381, 120382, 120383, 120384, 120385, 120386, 120387, 120388, 120389, 120390, 120391, 120392, 120393, 120394, 120395, 120396, 120397, 120398, 120399, 120400, 120401, 120402, 120403, 120404, 120405, 120406, 120407, 120408, 120409, 120410, 120411, 120412, 120413, 120414, 120415, 120416, 120417, 120419, 120420, 120421, 120422, 120423, 120424, 120425, 120426, 120427, 120428, 120429, 120430, 120431, 120432, 120433, 120434, 120435, 120436, 120437, 120438, 120439, 120440, 120441, 120442, 120443, 120444, 120445, 120446, 120447, 120448, 120449, 120450, 120451, 120452, 120453, 120454, 120455, 120456, 120457, 120458, 120459, 120460, 120461, 120462, 120463, 120464, 120465, 120466, 120467, 120468, 120469, 120471, 120472, 120473, 120474, 120475, 120476, 120477, 120478, 120479, 120480, 120481, 120482, 120483, 120484, 120488, 120489, 120492, 120493, 120494, 120496, 120497, 120499, 120500, 120502, 120504, 120507, 120508, 120510, 120514, 120516, 120522, 120526, 120528, 120530, 120532, 120534, 120544, 120546, 120547, 120550, 120551, 120552, 120554, 120555, 120557, 120558, 120560, 120562, 120565, 120566, 120568, 120572, 120574, 120580, 120584, 120586, 120588, 120590, 120592, 120602, 120604, 120605, 120608, 120609, 120610, 120612, 120613, 120615, 120616, 120618, 120620, 120623, 120624, 120626, 120630, 120632, 120638, 120642, 120644, 120646, 120648, 120650, 120660, 120662, 120663, 120666, 120667, 120668, 120670, 120671, 120673, 120674, 120676, 120678, 120681, 120682, 120684, 120688, 120690, 120696, 120700, 120702, 120704, 120706, 120708, 120718, 120720, 120721, 120724, 120725, 120726, 120728, 120729, 120731, 120732, 120734, 120736, 120739, 120740, 120742, 120746, 120748, 120754, 120758, 120760, 120762, 120764, 120766, 120776, 120778, 120782, 120783, 120784, 120785, 120786, 120787, 120788, 120789, 120790, 120791, 120792, 120793, 120794, 120795, 120796, 120797, 120798, 120799, 120800, 120801, 120802, 120803, 120804, 120805, 120806, 120807, 120808, 120809, 120810, 120811, 120812, 120813, 120814, 120815, 120816, 120817, 120818, 120819, 120820, 120821, 120822, 120823, 120824, 120825, 120826, 120827, 120828, 120829, 120830, 120831, 125127, 125131, 126464, 126500, 126564, 126592, 126596, 128844, 128872, 130032, 130033, 130034, 130035, 130036, 130037, 130038, 130039, 130040, 130041}, + With: []rune{44, 102, 98, 103, 82, 50, 51, 53, 115, 73, 33, 51, 56, 56, 63, 97, 103, 121, 105, 105, 119, 117, 121, 63, 96, 96, 96, 96, 96, 60, 62, 94, 94, 96, 96, 96, 58, 45, 105, 126, 96, 58, 96, 105, 59, 74, 96, 65, 66, 69, 90, 72, 75, 77, 78, 79, 80, 84, 89, 88, 97, 121, 105, 118, 111, 112, 111, 117, 89, 70, 50, 99, 106, 67, 77, 83, 73, 74, 115, 105, 106, 119, 86, 118, 89, 121, 104, 101, 73, 105, 51, 100, 71, 113, 87, 119, 85, 83, 79, 96, 96, 119, 113, 113, 104, 110, 110, 117, 103, 102, 111, 58, 108, 58, 108, 118, 96, 108, 111, 96, 44, 108, 111, 46, 108, 111, 86, 44, 42, 111, 111, 45, 111, 46, 73, 111, 86, 46, 46, 58, 58, 79, 108, 96, 96, 95, 58, 111, 63, 79, 56, 57, 111, 57, 56, 58, 111, 56, 79, 79, 57, 111, 111, 111, 111, 111, 111, 111, 111, 57, 111, 111, 111, 111, 111, 121, 111, 85, 79, 68, 82, 84, 105, 89, 65, 74, 69, 63, 87, 77, 72, 89, 71, 104, 90, 52, 98, 82, 87, 83, 86, 83, 76, 67, 80, 75, 100, 54, 71, 66, 61, 86, 62, 60, 96, 85, 80, 100, 98, 74, 76, 50, 120, 72, 120, 82, 98, 70, 65, 68, 68, 77, 66, 88, 120, 32, 60, 88, 73, 96, 75, 77, 58, 43, 47, 58, 58, 99, 111, 111, 117, 118, 119, 122, 114, 103, 121, 102, 121, 96, 105, 96, 126, 96, 96, 96, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 45, 44, 96, 46, 32, 32, 32, 96, 60, 62, 47, 45, 47, 42, 126, 58, 32, 67, 103, 72, 72, 72, 104, 73, 73, 76, 108, 78, 80, 81, 82, 82, 82, 90, 90, 75, 66, 67, 101, 101, 69, 70, 77, 111, 105, 121, 68, 100, 101, 105, 106, 73, 86, 88, 76, 67, 68, 77, 105, 118, 120, 73, 99, 100, 45, 47, 92, 42, 73, 118, 85, 58, 126, 84, 118, 85, 69, 105, 112, 97, 73, 47, 88, 40, 41, 60, 62, 40, 41, 123, 125, 43, 45, 47, 92, 84, 120, 120, 92, 47, 92, 120, 114, 72, 73, 75, 77, 78, 79, 111, 80, 112, 67, 99, 84, 89, 88, 45, 47, 57, 51, 76, 54, 86, 69, 73, 33, 79, 81, 88, 61, 92, 47, 79, 40, 41, 47, 61, 47, 92, 92, 47, 66, 80, 100, 68, 84, 71, 75, 74, 67, 90, 70, 77, 78, 76, 83, 82, 86, 72, 87, 88, 89, 65, 69, 73, 79, 85, 46, 44, 58, 61, 46, 50, 105, 86, 63, 50, 115, 50, 51, 57, 38, 58, 96, 70, 102, 117, 51, 74, 88, 66, 101, 102, 111, 114, 114, 117, 117, 121, 105, 114, 119, 122, 118, 115, 99, 111, 111, 111, 111, 111, 111, 111, 111, 40, 41, 58, 95, 95, 95, 45, 92, 108, 108, 111, 111, 111, 111, 34, 36, 37, 38, 96, 42, 43, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 60, 61, 62, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 73, 66, 69, 70, 124, 88, 79, 80, 83, 84, 43, 65, 66, 67, 70, 79, 77, 84, 89, 88, 72, 90, 66, 67, 124, 77, 84, 88, 56, 42, 108, 88, 79, 67, 76, 83, 111, 99, 115, 82, 79, 85, 55, 111, 117, 78, 79, 75, 67, 86, 70, 76, 88, 46, 79, 118, 119, 119, 119, 86, 70, 76, 89, 69, 90, 57, 69, 52, 76, 79, 85, 53, 84, 118, 115, 70, 105, 122, 55, 111, 51, 57, 54, 57, 111, 117, 121, 79, 90, 87, 67, 88, 87, 67, 86, 84, 76, 73, 82, 83, 51, 62, 65, 85, 89, 96, 96, 123, 46, 51, 86, 92, 55, 70, 82, 76, 60, 62, 47, 92, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 67, 68, 71, 74, 75, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 102, 104, 105, 106, 107, 108, 110, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 68, 69, 70, 71, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 87, 88, 89, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 77, 79, 83, 84, 85, 86, 87, 88, 89, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 73, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 105, 65, 66, 69, 90, 72, 73, 75, 77, 78, 79, 80, 84, 89, 88, 97, 121, 105, 118, 111, 112, 111, 117, 112, 65, 66, 69, 90, 72, 73, 75, 77, 78, 79, 80, 84, 89, 88, 97, 121, 105, 118, 111, 112, 111, 117, 112, 65, 66, 69, 90, 72, 73, 75, 77, 78, 79, 80, 84, 89, 88, 97, 121, 105, 118, 111, 112, 111, 117, 112, 65, 66, 69, 90, 72, 73, 75, 77, 78, 79, 80, 84, 89, 88, 97, 121, 105, 118, 111, 112, 111, 117, 112, 65, 66, 69, 90, 72, 73, 75, 77, 78, 79, 80, 84, 89, 88, 97, 121, 105, 118, 111, 112, 111, 117, 112, 70, 79, 73, 50, 51, 52, 53, 54, 55, 56, 57, 79, 73, 50, 51, 52, 53, 54, 55, 56, 57, 79, 73, 50, 51, 52, 53, 54, 55, 56, 57, 79, 73, 50, 51, 52, 53, 54, 55, 56, 57, 79, 73, 50, 51, 52, 53, 54, 55, 56, 57, 108, 56, 108, 111, 111, 108, 111, 67, 84, 79, 73, 50, 51, 52, 53, 54, 55, 56, 57}, + Locale: "_common", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 184, Hi: 383, Stride: 199}, + {Lo: 388, Hi: 397, Stride: 9}, + {Lo: 422, Hi: 423, Stride: 1}, + {Lo: 439, Hi: 444, Stride: 5}, + {Lo: 445, Hi: 451, Stride: 3}, + {Lo: 540, Hi: 546, Stride: 6}, + {Lo: 547, Hi: 577, Stride: 30}, + {Lo: 593, Hi: 609, Stride: 16}, + {Lo: 611, Hi: 617, Stride: 6}, + {Lo: 618, Hi: 623, Stride: 5}, + {Lo: 651, Hi: 655, Stride: 4}, + {Lo: 660, Hi: 697, Stride: 37}, + {Lo: 699, Hi: 702, Stride: 1}, + {Lo: 706, Hi: 708, Stride: 1}, + {Lo: 710, Hi: 714, Stride: 2}, + {Lo: 715, Hi: 720, Stride: 5}, + {Lo: 727, Hi: 731, Stride: 4}, + {Lo: 732, Hi: 756, Stride: 24}, + {Lo: 760, Hi: 884, Stride: 124}, + {Lo: 890, Hi: 894, Stride: 4}, + {Lo: 895, Hi: 900, Stride: 5}, + {Lo: 913, Hi: 914, Stride: 1}, + {Lo: 917, Hi: 919, Stride: 1}, + {Lo: 922, Hi: 924, Stride: 2}, + {Lo: 925, Hi: 929, Stride: 2}, + {Lo: 932, Hi: 933, Stride: 1}, + {Lo: 935, Hi: 945, Stride: 10}, + {Lo: 947, Hi: 953, Stride: 6}, + {Lo: 957, Hi: 965, Stride: 2}, + {Lo: 978, Hi: 988, Stride: 10}, + {Lo: 1000, Hi: 1010, Stride: 10}, + {Lo: 1011, Hi: 1017, Stride: 6}, + {Lo: 1018, Hi: 1029, Stride: 11}, + {Lo: 1030, Hi: 1032, Stride: 2}, + {Lo: 1109, Hi: 1110, Stride: 1}, + {Lo: 1112, Hi: 1121, Stride: 9}, + {Lo: 1140, Hi: 1141, Stride: 1}, + {Lo: 1198, Hi: 1199, Stride: 1}, + {Lo: 1211, Hi: 1213, Stride: 2}, + {Lo: 1216, Hi: 1231, Stride: 15}, + {Lo: 1248, Hi: 1281, Stride: 33}, + {Lo: 1292, Hi: 1307, Stride: 15}, + {Lo: 1308, Hi: 1309, Stride: 1}, + {Lo: 1357, Hi: 1359, Stride: 2}, + {Lo: 1365, Hi: 1370, Stride: 5}, + {Lo: 1373, Hi: 1377, Stride: 4}, + {Lo: 1379, Hi: 1382, Stride: 3}, + {Lo: 1392, Hi: 1400, Stride: 8}, + {Lo: 1404, Hi: 1405, Stride: 1}, + {Lo: 1409, Hi: 1412, Stride: 3}, + {Lo: 1413, Hi: 1417, Stride: 4}, + {Lo: 1472, Hi: 1475, Stride: 3}, + {Lo: 1493, Hi: 1496, Stride: 3}, + {Lo: 1497, Hi: 1503, Stride: 6}, + {Lo: 1505, Hi: 1523, Stride: 18}, + {Lo: 1549, Hi: 1575, Stride: 26}, + {Lo: 1607, Hi: 1632, Stride: 25}, + {Lo: 1633, Hi: 1637, Stride: 4}, + {Lo: 1639, Hi: 1643, Stride: 4}, + {Lo: 1645, Hi: 1726, Stride: 81}, + {Lo: 1729, Hi: 1748, Stride: 19}, + {Lo: 1749, Hi: 1776, Stride: 27}, + {Lo: 1777, Hi: 1781, Stride: 4}, + {Lo: 1783, Hi: 1793, Stride: 10}, + {Lo: 1794, Hi: 1796, Stride: 1}, + {Lo: 1984, Hi: 1994, Stride: 10}, + {Lo: 2036, Hi: 2037, Stride: 1}, + {Lo: 2042, Hi: 2307, Stride: 265}, + {Lo: 2406, Hi: 2429, Stride: 23}, + {Lo: 2534, Hi: 2538, Stride: 4}, + {Lo: 2541, Hi: 2662, Stride: 121}, + {Lo: 2663, Hi: 2666, Stride: 3}, + {Lo: 2691, Hi: 2790, Stride: 99}, + {Lo: 2819, Hi: 2848, Stride: 29}, + {Lo: 2918, Hi: 2920, Stride: 2}, + {Lo: 3046, Hi: 3074, Stride: 28}, + {Lo: 3174, Hi: 3202, Stride: 28}, + {Lo: 3302, Hi: 3330, Stride: 28}, + {Lo: 3360, Hi: 3430, Stride: 70}, + {Lo: 3437, Hi: 3458, Stride: 21}, + {Lo: 3664, Hi: 3792, Stride: 128}, + {Lo: 4125, Hi: 4160, Stride: 35}, + {Lo: 4327, Hi: 4351, Stride: 24}, + {Lo: 4608, Hi: 5024, Stride: 208}, + {Lo: 5025, Hi: 5026, Stride: 1}, + {Lo: 5029, Hi: 5033, Stride: 4}, + {Lo: 5034, Hi: 5036, Stride: 1}, + {Lo: 5038, Hi: 5043, Stride: 5}, + {Lo: 5047, Hi: 5051, Stride: 4}, + {Lo: 5053, Hi: 5056, Stride: 3}, + {Lo: 5058, Hi: 5059, Stride: 1}, + {Lo: 5070, Hi: 5071, Stride: 1}, + {Lo: 5074, Hi: 5076, Stride: 2}, + {Lo: 5077, Hi: 5081, Stride: 4}, + {Lo: 5082, Hi: 5086, Stride: 4}, + {Lo: 5087, Hi: 5090, Stride: 3}, + {Lo: 5094, Hi: 5095, Stride: 1}, + {Lo: 5102, Hi: 5107, Stride: 5}, + {Lo: 5108, Hi: 5120, Stride: 12}, + {Lo: 5167, Hi: 5171, Stride: 4}, + {Lo: 5176, Hi: 5194, Stride: 18}, + {Lo: 5196, Hi: 5229, Stride: 33}, + {Lo: 5231, Hi: 5234, Stride: 3}, + {Lo: 5261, Hi: 5290, Stride: 29}, + {Lo: 5311, Hi: 5441, Stride: 130}, + {Lo: 5500, Hi: 5501, Stride: 1}, + {Lo: 5511, Hi: 5551, Stride: 40}, + {Lo: 5556, Hi: 5573, Stride: 17}, + {Lo: 5598, Hi: 5610, Stride: 12}, + {Lo: 5616, Hi: 5623, Stride: 7}, + {Lo: 5741, Hi: 5742, Stride: 1}, + {Lo: 5760, Hi: 5810, Stride: 50}, + {Lo: 5815, Hi: 5825, Stride: 10}, + {Lo: 5836, Hi: 5845, Stride: 9}, + {Lo: 5846, Hi: 5868, Stride: 22}, + {Lo: 5869, Hi: 5941, Stride: 72}, + {Lo: 6147, Hi: 6153, Stride: 6}, + {Lo: 7428, Hi: 7439, Stride: 11}, + {Lo: 7441, Hi: 7452, Stride: 11}, + {Lo: 7456, Hi: 7458, Stride: 1}, + {Lo: 7462, Hi: 7555, Stride: 93}, + {Lo: 7564, Hi: 7837, Stride: 273}, + {Lo: 7935, Hi: 8125, Stride: 190}, + {Lo: 8126, Hi: 8128, Stride: 1}, + {Lo: 8175, Hi: 8189, Stride: 14}, + {Lo: 8190, Hi: 8192, Stride: 2}, + {Lo: 8193, Hi: 8202, Stride: 1}, + {Lo: 8208, Hi: 8210, Stride: 1}, + {Lo: 8218, Hi: 8219, Stride: 1}, + {Lo: 8228, Hi: 8232, Stride: 4}, + {Lo: 8233, Hi: 8239, Stride: 6}, + {Lo: 8242, Hi: 8249, Stride: 7}, + {Lo: 8250, Hi: 8257, Stride: 7}, + {Lo: 8259, Hi: 8260, Stride: 1}, + {Lo: 8270, Hi: 8275, Stride: 5}, + {Lo: 8282, Hi: 8287, Stride: 5}, + {Lo: 8450, Hi: 8458, Stride: 8}, + {Lo: 8459, Hi: 8462, Stride: 1}, + {Lo: 8464, Hi: 8467, Stride: 1}, + {Lo: 8469, Hi: 8473, Stride: 4}, + {Lo: 8474, Hi: 8477, Stride: 1}, + {Lo: 8484, Hi: 8488, Stride: 4}, + {Lo: 8490, Hi: 8492, Stride: 2}, + {Lo: 8493, Hi: 8497, Stride: 1}, + {Lo: 8499, Hi: 8500, Stride: 1}, + {Lo: 8505, Hi: 8509, Stride: 4}, + {Lo: 8517, Hi: 8521, Stride: 1}, + {Lo: 8544, Hi: 8548, Stride: 4}, + {Lo: 8553, Hi: 8556, Stride: 3}, + {Lo: 8557, Hi: 8560, Stride: 1}, + {Lo: 8564, Hi: 8569, Stride: 5}, + {Lo: 8572, Hi: 8574, Stride: 1}, + {Lo: 8722, Hi: 8725, Stride: 3}, + {Lo: 8726, Hi: 8727, Stride: 1}, + {Lo: 8739, Hi: 8744, Stride: 5}, + {Lo: 8746, Hi: 8758, Stride: 12}, + {Lo: 8764, Hi: 8868, Stride: 104}, + {Lo: 8897, Hi: 8899, Stride: 2}, + {Lo: 8959, Hi: 9075, Stride: 116}, + {Lo: 9076, Hi: 9082, Stride: 6}, + {Lo: 9213, Hi: 9585, Stride: 372}, + {Lo: 9587, Hi: 10088, Stride: 501}, + {Lo: 10089, Hi: 10094, Stride: 5}, + {Lo: 10095, Hi: 10098, Stride: 3}, + {Lo: 10099, Hi: 10101, Stride: 1}, + {Lo: 10133, Hi: 10134, Stride: 1}, + {Lo: 10187, Hi: 10189, Stride: 2}, + {Lo: 10201, Hi: 10539, Stride: 338}, + {Lo: 10540, Hi: 10741, Stride: 201}, + {Lo: 10744, Hi: 10745, Stride: 1}, + {Lo: 10799, Hi: 11397, Stride: 598}, + {Lo: 11406, Hi: 11410, Stride: 4}, + {Lo: 11412, Hi: 11416, Stride: 4}, + {Lo: 11418, Hi: 11422, Stride: 4}, + {Lo: 11423, Hi: 11426, Stride: 3}, + {Lo: 11427, Hi: 11430, Stride: 1}, + {Lo: 11432, Hi: 11436, Stride: 4}, + {Lo: 11450, Hi: 11462, Stride: 12}, + {Lo: 11466, Hi: 11468, Stride: 2}, + {Lo: 11472, Hi: 11474, Stride: 2}, + {Lo: 11576, Hi: 11577, Stride: 1}, + {Lo: 11599, Hi: 11601, Stride: 2}, + {Lo: 11604, Hi: 11605, Stride: 1}, + {Lo: 11613, Hi: 11840, Stride: 227}, + {Lo: 12034, Hi: 12035, Stride: 1}, + {Lo: 12295, Hi: 12308, Stride: 13}, + {Lo: 12309, Hi: 12339, Stride: 30}, + {Lo: 12448, Hi: 12755, Stride: 307}, + {Lo: 12756, Hi: 20022, Stride: 7266}, + {Lo: 20031, Hi: 42192, Stride: 22161}, + {Lo: 42193, Hi: 42196, Stride: 1}, + {Lo: 42198, Hi: 42199, Stride: 1}, + {Lo: 42201, Hi: 42202, Stride: 1}, + {Lo: 42204, Hi: 42205, Stride: 1}, + {Lo: 42207, Hi: 42211, Stride: 1}, + {Lo: 42214, Hi: 42215, Stride: 1}, + {Lo: 42218, Hi: 42220, Stride: 1}, + {Lo: 42222, Hi: 42226, Stride: 2}, + {Lo: 42227, Hi: 42228, Stride: 1}, + {Lo: 42232, Hi: 42233, Stride: 1}, + {Lo: 42237, Hi: 42239, Stride: 2}, + {Lo: 42510, Hi: 42564, Stride: 54}, + {Lo: 42567, Hi: 42719, Stride: 152}, + {Lo: 42731, Hi: 42735, Stride: 4}, + {Lo: 42801, Hi: 42842, Stride: 41}, + {Lo: 42858, Hi: 42862, Stride: 4}, + {Lo: 42872, Hi: 42889, Stride: 17}, + {Lo: 42892, Hi: 42904, Stride: 12}, + {Lo: 42905, Hi: 42911, Stride: 6}, + {Lo: 42923, Hi: 42930, Stride: 7}, + {Lo: 42931, Hi: 42932, Stride: 1}, + {Lo: 43826, Hi: 43829, Stride: 3}, + {Lo: 43837, Hi: 43847, Stride: 10}, + {Lo: 43848, Hi: 43854, Stride: 6}, + {Lo: 43858, Hi: 43866, Stride: 8}, + {Lo: 43893, Hi: 43905, Stride: 12}, + {Lo: 43907, Hi: 43923, Stride: 16}, + {Lo: 43945, Hi: 43946, Stride: 1}, + {Lo: 43951, Hi: 64422, Stride: 20471}, + {Lo: 64423, Hi: 64429, Stride: 1}, + {Lo: 64830, Hi: 64831, Stride: 1}, + {Lo: 65072, Hi: 65101, Stride: 29}, + {Lo: 65102, Hi: 65103, Stride: 1}, + {Lo: 65112, Hi: 65128, Stride: 16}, + {Lo: 65165, Hi: 65166, Stride: 1}, + {Lo: 65257, Hi: 65260, Stride: 1}, + {Lo: 65282, Hi: 65284, Stride: 2}, + {Lo: 65285, Hi: 65287, Stride: 1}, + {Lo: 65290, Hi: 65291, Stride: 1}, + {Lo: 65293, Hi: 65305, Stride: 1}, + {Lo: 65308, Hi: 65310, Stride: 1}, + {Lo: 65312, Hi: 65373, Stride: 1}, + {Lo: 65512, Hi: 65512, Stride: 1}, + }, + R32: []unicode.Range32{ + {Lo: 66178, Hi: 66182, Stride: 4}, + {Lo: 66183, Hi: 66186, Stride: 3}, + {Lo: 66192, Hi: 66194, Stride: 2}, + {Lo: 66197, Hi: 66199, Stride: 1}, + {Lo: 66203, Hi: 66208, Stride: 5}, + {Lo: 66209, Hi: 66210, Stride: 1}, + {Lo: 66213, Hi: 66219, Stride: 6}, + {Lo: 66224, Hi: 66226, Stride: 1}, + {Lo: 66228, Hi: 66255, Stride: 27}, + {Lo: 66293, Hi: 66305, Stride: 12}, + {Lo: 66306, Hi: 66313, Stride: 7}, + {Lo: 66321, Hi: 66325, Stride: 4}, + {Lo: 66327, Hi: 66330, Stride: 3}, + {Lo: 66335, Hi: 66336, Stride: 1}, + {Lo: 66338, Hi: 66564, Stride: 226}, + {Lo: 66581, Hi: 66587, Stride: 6}, + {Lo: 66592, Hi: 66604, Stride: 12}, + {Lo: 66621, Hi: 66632, Stride: 11}, + {Lo: 66740, Hi: 66754, Stride: 14}, + {Lo: 66766, Hi: 66770, Stride: 4}, + {Lo: 66794, Hi: 66806, Stride: 12}, + {Lo: 66835, Hi: 66838, Stride: 3}, + {Lo: 66840, Hi: 66844, Stride: 4}, + {Lo: 66845, Hi: 66853, Stride: 8}, + {Lo: 66854, Hi: 66855, Stride: 1}, + {Lo: 68176, Hi: 70864, Stride: 2688}, + {Lo: 71430, Hi: 71438, Stride: 4}, + {Lo: 71439, Hi: 71840, Stride: 401}, + {Lo: 71842, Hi: 71844, Stride: 1}, + {Lo: 71846, Hi: 71852, Stride: 3}, + {Lo: 71854, Hi: 71855, Stride: 1}, + {Lo: 71858, Hi: 71867, Stride: 3}, + {Lo: 71868, Hi: 71872, Stride: 4}, + {Lo: 71873, Hi: 71876, Stride: 1}, + {Lo: 71878, Hi: 71884, Stride: 2}, + {Lo: 71893, Hi: 71896, Stride: 1}, + {Lo: 71900, Hi: 71904, Stride: 4}, + {Lo: 71909, Hi: 71910, Stride: 1}, + {Lo: 71913, Hi: 71922, Stride: 3}, + {Lo: 93960, Hi: 93962, Stride: 2}, + {Lo: 93974, Hi: 93992, Stride: 18}, + {Lo: 94005, Hi: 94010, Stride: 5}, + {Lo: 94011, Hi: 94015, Stride: 4}, + {Lo: 94016, Hi: 94018, Stride: 2}, + {Lo: 94019, Hi: 94033, Stride: 14}, + {Lo: 94034, Hi: 119060, Stride: 25026}, + {Lo: 119149, Hi: 119302, Stride: 153}, + {Lo: 119309, Hi: 119311, Stride: 2}, + {Lo: 119314, Hi: 119315, Stride: 1}, + {Lo: 119318, Hi: 119338, Stride: 20}, + {Lo: 119350, Hi: 119351, Stride: 1}, + {Lo: 119354, Hi: 119355, Stride: 1}, + {Lo: 119808, Hi: 119845, Stride: 1}, + {Lo: 119847, Hi: 119892, Stride: 1}, + {Lo: 119894, Hi: 119897, Stride: 1}, + {Lo: 119899, Hi: 119949, Stride: 1}, + {Lo: 119951, Hi: 119964, Stride: 1}, + {Lo: 119966, Hi: 119967, Stride: 1}, + {Lo: 119970, Hi: 119973, Stride: 3}, + {Lo: 119974, Hi: 119977, Stride: 3}, + {Lo: 119978, Hi: 119980, Stride: 1}, + {Lo: 119982, Hi: 119993, Stride: 1}, + {Lo: 119995, Hi: 119997, Stride: 2}, + {Lo: 119998, Hi: 120001, Stride: 1}, + {Lo: 120003, Hi: 120005, Stride: 2}, + {Lo: 120006, Hi: 120053, Stride: 1}, + {Lo: 120055, Hi: 120069, Stride: 1}, + {Lo: 120071, Hi: 120074, Stride: 1}, + {Lo: 120077, Hi: 120084, Stride: 1}, + {Lo: 120086, Hi: 120092, Stride: 1}, + {Lo: 120094, Hi: 120105, Stride: 1}, + {Lo: 120107, Hi: 120121, Stride: 1}, + {Lo: 120123, Hi: 120126, Stride: 1}, + {Lo: 120128, Hi: 120132, Stride: 1}, + {Lo: 120134, Hi: 120138, Stride: 4}, + {Lo: 120139, Hi: 120144, Stride: 1}, + {Lo: 120146, Hi: 120157, Stride: 1}, + {Lo: 120159, Hi: 120209, Stride: 1}, + {Lo: 120211, Hi: 120261, Stride: 1}, + {Lo: 120263, Hi: 120313, Stride: 1}, + {Lo: 120315, Hi: 120365, Stride: 1}, + {Lo: 120367, Hi: 120417, Stride: 1}, + {Lo: 120419, Hi: 120469, Stride: 1}, + {Lo: 120471, Hi: 120484, Stride: 1}, + {Lo: 120488, Hi: 120489, Stride: 1}, + {Lo: 120492, Hi: 120494, Stride: 1}, + {Lo: 120496, Hi: 120497, Stride: 1}, + {Lo: 120499, Hi: 120500, Stride: 1}, + {Lo: 120502, Hi: 120504, Stride: 2}, + {Lo: 120507, Hi: 120508, Stride: 1}, + {Lo: 120510, Hi: 120514, Stride: 4}, + {Lo: 120516, Hi: 120522, Stride: 6}, + {Lo: 120526, Hi: 120534, Stride: 2}, + {Lo: 120544, Hi: 120546, Stride: 2}, + {Lo: 120547, Hi: 120550, Stride: 3}, + {Lo: 120551, Hi: 120552, Stride: 1}, + {Lo: 120554, Hi: 120555, Stride: 1}, + {Lo: 120557, Hi: 120558, Stride: 1}, + {Lo: 120560, Hi: 120562, Stride: 2}, + {Lo: 120565, Hi: 120566, Stride: 1}, + {Lo: 120568, Hi: 120572, Stride: 4}, + {Lo: 120574, Hi: 120580, Stride: 6}, + {Lo: 120584, Hi: 120592, Stride: 2}, + {Lo: 120602, Hi: 120604, Stride: 2}, + {Lo: 120605, Hi: 120608, Stride: 3}, + {Lo: 120609, Hi: 120610, Stride: 1}, + {Lo: 120612, Hi: 120613, Stride: 1}, + {Lo: 120615, Hi: 120616, Stride: 1}, + {Lo: 120618, Hi: 120620, Stride: 2}, + {Lo: 120623, Hi: 120624, Stride: 1}, + {Lo: 120626, Hi: 120630, Stride: 4}, + {Lo: 120632, Hi: 120638, Stride: 6}, + {Lo: 120642, Hi: 120650, Stride: 2}, + {Lo: 120660, Hi: 120662, Stride: 2}, + {Lo: 120663, Hi: 120666, Stride: 3}, + {Lo: 120667, Hi: 120668, Stride: 1}, + {Lo: 120670, Hi: 120671, Stride: 1}, + {Lo: 120673, Hi: 120674, Stride: 1}, + {Lo: 120676, Hi: 120678, Stride: 2}, + {Lo: 120681, Hi: 120682, Stride: 1}, + {Lo: 120684, Hi: 120688, Stride: 4}, + {Lo: 120690, Hi: 120696, Stride: 6}, + {Lo: 120700, Hi: 120708, Stride: 2}, + {Lo: 120718, Hi: 120720, Stride: 2}, + {Lo: 120721, Hi: 120724, Stride: 3}, + {Lo: 120725, Hi: 120726, Stride: 1}, + {Lo: 120728, Hi: 120729, Stride: 1}, + {Lo: 120731, Hi: 120732, Stride: 1}, + {Lo: 120734, Hi: 120736, Stride: 2}, + {Lo: 120739, Hi: 120740, Stride: 1}, + {Lo: 120742, Hi: 120746, Stride: 4}, + {Lo: 120748, Hi: 120754, Stride: 6}, + {Lo: 120758, Hi: 120766, Stride: 2}, + {Lo: 120776, Hi: 120778, Stride: 2}, + {Lo: 120782, Hi: 120831, Stride: 1}, + {Lo: 125127, Hi: 125131, Stride: 4}, + {Lo: 126464, Hi: 126500, Stride: 36}, + {Lo: 126564, Hi: 126592, Stride: 28}, + {Lo: 126596, Hi: 128844, Stride: 2248}, + {Lo: 128872, Hi: 130032, Stride: 1160}, + {Lo: 130033, Hi: 130041, Stride: 1}, + }, + LatinOffset: 0, + }, + }, + "_default": { + Confusable: []rune{160, 180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{32, 96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "_default", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 160, Hi: 180, Stride: 20}, + {Lo: 215, Hi: 305, Stride: 90}, + {Lo: 921, Hi: 1009, Stride: 88}, + {Lo: 1040, Hi: 1042, Stride: 2}, + {Lo: 1045, Hi: 1047, Stride: 2}, + {Lo: 1050, Hi: 1052, Stride: 2}, + {Lo: 1053, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8216, Stride: 5}, + {Lo: 8217, Hi: 8245, Stride: 28}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "cs": { + Confusable: []rune{180, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "cs", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 305, Stride: 125}, + {Lo: 921, Hi: 1009, Stride: 88}, + {Lo: 1040, Hi: 1042, Stride: 2}, + {Lo: 1045, Hi: 1047, Stride: 2}, + {Lo: 1050, Hi: 1052, Stride: 2}, + {Lo: 1053, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8216, Hi: 8217, Stride: 1}, + {Lo: 8245, Hi: 12494, Stride: 4249}, + {Lo: 65281, Hi: 65283, Stride: 2}, + {Lo: 65288, Hi: 65289, Stride: 1}, + {Lo: 65292, Hi: 65306, Stride: 14}, + {Lo: 65307, Hi: 65311, Stride: 4}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 0, + }, + }, + "de": { + Confusable: []rune{180, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "de", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 305, Stride: 125}, + {Lo: 921, Hi: 1009, Stride: 88}, + {Lo: 1040, Hi: 1042, Stride: 2}, + {Lo: 1045, Hi: 1047, Stride: 2}, + {Lo: 1050, Hi: 1052, Stride: 2}, + {Lo: 1053, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8216, Hi: 8217, Stride: 1}, + {Lo: 8245, Hi: 12494, Stride: 4249}, + {Lo: 65281, Hi: 65283, Stride: 2}, + {Lo: 65288, Hi: 65289, Stride: 1}, + {Lo: 65292, Hi: 65306, Stride: 14}, + {Lo: 65307, Hi: 65311, Stride: 4}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 0, + }, + }, + "es": { + Confusable: []rune{180, 215, 305, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 120, 105, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "es", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 1009, Stride: 704}, + {Lo: 1040, Hi: 1042, Stride: 2}, + {Lo: 1045, Hi: 1047, Stride: 2}, + {Lo: 1050, Hi: 1052, Stride: 2}, + {Lo: 1053, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8245, Stride: 34}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "fr": { + Confusable: []rune{215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8216, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "fr", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 215, Hi: 305, Stride: 90}, + {Lo: 921, Hi: 1009, Stride: 88}, + {Lo: 1040, Hi: 1042, Stride: 2}, + {Lo: 1045, Hi: 1047, Stride: 2}, + {Lo: 1050, Hi: 1052, Stride: 2}, + {Lo: 1053, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8216, Hi: 8245, Stride: 29}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 0, + }, + }, + "it": { + Confusable: []rune{160, 180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8216, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{32, 96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "it", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 160, Hi: 180, Stride: 20}, + {Lo: 215, Hi: 305, Stride: 90}, + {Lo: 921, Hi: 1009, Stride: 88}, + {Lo: 1040, Hi: 1042, Stride: 2}, + {Lo: 1045, Hi: 1047, Stride: 2}, + {Lo: 1050, Hi: 1052, Stride: 2}, + {Lo: 1053, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8216, Stride: 5}, + {Lo: 8245, Hi: 12494, Stride: 4249}, + {Lo: 65281, Hi: 65283, Stride: 2}, + {Lo: 65288, Hi: 65289, Stride: 1}, + {Lo: 65292, Hi: 65306, Stride: 14}, + {Lo: 65307, Hi: 65311, Stride: 4}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "ja": { + Confusable: []rune{180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8216, 8217, 8245, 65281, 65283, 65292, 65306, 65307}, + With: []rune{96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 96, 96, 33, 35, 44, 58, 59}, + Locale: "ja", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8216, Stride: 5}, + {Lo: 8217, Hi: 8245, Stride: 28}, + {Lo: 65281, Hi: 65283, Stride: 2}, + {Lo: 65292, Hi: 65306, Stride: 14}, + {Lo: 65307, Hi: 65307, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "ko": { + Confusable: []rune{180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "ko", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8245, Stride: 34}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "pl": { + Confusable: []rune{180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "pl", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8216, Hi: 8217, Stride: 1}, + {Lo: 8245, Hi: 12494, Stride: 4249}, + {Lo: 65281, Hi: 65283, Stride: 2}, + {Lo: 65288, Hi: 65289, Stride: 1}, + {Lo: 65292, Hi: 65306, Stride: 14}, + {Lo: 65307, Hi: 65311, Stride: 4}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "pt-BR": { + Confusable: []rune{180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "pt-BR", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8216, Hi: 8217, Stride: 1}, + {Lo: 8245, Hi: 12494, Stride: 4249}, + {Lo: 65281, Hi: 65283, Stride: 2}, + {Lo: 65288, Hi: 65289, Stride: 1}, + {Lo: 65292, Hi: 65306, Stride: 14}, + {Lo: 65307, Hi: 65311, Stride: 4}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "qps-ploc": { + Confusable: []rune{160, 180, 215, 305, 921, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{32, 96, 120, 105, 73, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "qps-ploc", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 160, Hi: 180, Stride: 20}, + {Lo: 215, Hi: 305, Stride: 90}, + {Lo: 921, Hi: 1040, Stride: 119}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8216, Stride: 5}, + {Lo: 8217, Hi: 8245, Stride: 28}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "ru": { + Confusable: []rune{180, 215, 305, 921, 1009, 8216, 8217, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{96, 120, 105, 73, 112, 96, 96, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "ru", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 8216, Stride: 7207}, + {Lo: 8217, Hi: 8245, Stride: 28}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "tr": { + Confusable: []rune{160, 180, 215, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 8245, 12494, 65281, 65283, 65288, 65289, 65292, 65306, 65307, 65311, 65374}, + With: []rune{32, 96, 120, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 96, 47, 33, 35, 40, 41, 44, 58, 59, 63, 126}, + Locale: "tr", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 160, Hi: 180, Stride: 20}, + {Lo: 215, Hi: 921, Stride: 706}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 8245, Stride: 34}, + {Lo: 12494, Hi: 65281, Stride: 52787}, + {Lo: 65283, Hi: 65288, Stride: 5}, + {Lo: 65289, Hi: 65292, Stride: 3}, + {Lo: 65306, Hi: 65307, Stride: 1}, + {Lo: 65311, Hi: 65374, Stride: 63}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "zh-hans": { + Confusable: []rune{180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8245, 12494, 65281, 65288, 65289, 65306, 65374}, + With: []rune{96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 96, 47, 33, 40, 41, 58, 126}, + Locale: "zh-hans", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8245, Hi: 12494, Stride: 4249}, + {Lo: 65281, Hi: 65288, Stride: 7}, + {Lo: 65289, Hi: 65306, Stride: 17}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, + "zh-hant": { + Confusable: []rune{180, 215, 305, 921, 1009, 1040, 1042, 1045, 1047, 1050, 1052, 1053, 1054, 1056, 1057, 1058, 1059, 1061, 1068, 1072, 1073, 1075, 1077, 1086, 1088, 1089, 1091, 1093, 8211, 12494, 65283, 65307, 65374}, + With: []rune{96, 120, 105, 73, 112, 65, 66, 69, 51, 75, 77, 72, 79, 80, 67, 84, 89, 88, 98, 97, 54, 114, 101, 111, 112, 99, 121, 120, 45, 47, 35, 59, 126}, + Locale: "zh-hant", + RangeTable: &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 180, Hi: 215, Stride: 35}, + {Lo: 305, Hi: 921, Stride: 616}, + {Lo: 1009, Hi: 1040, Stride: 31}, + {Lo: 1042, Hi: 1045, Stride: 3}, + {Lo: 1047, Hi: 1050, Stride: 3}, + {Lo: 1052, Hi: 1054, Stride: 1}, + {Lo: 1056, Hi: 1059, Stride: 1}, + {Lo: 1061, Hi: 1068, Stride: 7}, + {Lo: 1072, Hi: 1073, Stride: 1}, + {Lo: 1075, Hi: 1077, Stride: 2}, + {Lo: 1086, Hi: 1088, Stride: 2}, + {Lo: 1089, Hi: 1093, Stride: 2}, + {Lo: 8211, Hi: 12494, Stride: 4283}, + {Lo: 65283, Hi: 65307, Stride: 24}, + {Lo: 65374, Hi: 65374, Stride: 1}, + }, + R32: []unicode.Range32{}, + LatinOffset: 1, + }, + }, +} diff --git a/modules/charset/ambiguous_gen_test.go b/modules/charset/ambiguous_gen_test.go new file mode 100644 index 000000000000..bd64e1c5b1c9 --- /dev/null +++ b/modules/charset/ambiguous_gen_test.go @@ -0,0 +1,32 @@ +// 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 charset + +import ( + "sort" + "testing" + "unicode" + + "github.com/stretchr/testify/assert" +) + +func TestAmbiguousCharacters(t *testing.T) { + for locale, ambiguous := range AmbiguousCharacters { + assert.Equal(t, locale, ambiguous.Locale) + assert.Equal(t, len(ambiguous.Confusable), len(ambiguous.With)) + assert.True(t, sort.SliceIsSorted(ambiguous.Confusable, func(i, j int) bool { + return ambiguous.Confusable[i] < ambiguous.Confusable[j] + })) + + for _, confusable := range ambiguous.Confusable { + assert.True(t, unicode.Is(ambiguous.RangeTable, confusable)) + i := sort.Search(len(ambiguous.Confusable), func(j int) bool { + return ambiguous.Confusable[j] >= confusable + }) + found := i < len(ambiguous.Confusable) && ambiguous.Confusable[i] == confusable + assert.True(t, found, "%c is not in %d", confusable, i) + } + } +} diff --git a/modules/charset/breakwriter.go b/modules/charset/breakwriter.go new file mode 100644 index 000000000000..619826ff21b1 --- /dev/null +++ b/modules/charset/breakwriter.go @@ -0,0 +1,44 @@ +// 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 charset + +import ( + "bytes" + "io" +) + +// BreakWriter wraps an io.Writer to always write '\n' as '
' +type BreakWriter struct { + io.Writer +} + +// Write writes the provided byte slice transparently replacing '\n' with '
' +func (b *BreakWriter) Write(bs []byte) (n int, err error) { + pos := 0 + for pos < len(bs) { + idx := bytes.IndexByte(bs[pos:], '\n') + if idx < 0 { + wn, err := b.Writer.Write(bs[pos:]) + return n + wn, err + } + + if idx > 0 { + wn, err := b.Writer.Write(bs[pos : pos+idx]) + n += wn + if err != nil { + return n, err + } + } + + if _, err = b.Writer.Write([]byte("
")); err != nil { + return n, err + } + pos += idx + 1 + + n++ + } + + return n, err +} diff --git a/modules/charset/breakwriter_test.go b/modules/charset/breakwriter_test.go new file mode 100644 index 000000000000..6bbed42ea54c --- /dev/null +++ b/modules/charset/breakwriter_test.go @@ -0,0 +1,69 @@ +// 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 charset + +import ( + "strings" + "testing" +) + +func TestBreakWriter_Write(t *testing.T) { + tests := []struct { + name string + kase string + expect string + wantErr bool + }{ + { + name: "noline", + kase: "abcdefghijklmnopqrstuvwxyz", + expect: "abcdefghijklmnopqrstuvwxyz", + }, + { + name: "endline", + kase: "abcdefghijklmnopqrstuvwxyz\n", + expect: "abcdefghijklmnopqrstuvwxyz
", + }, + { + name: "startline", + kase: "\nabcdefghijklmnopqrstuvwxyz", + expect: "
abcdefghijklmnopqrstuvwxyz", + }, + { + name: "onlyline", + kase: "\n\n\n", + expect: "


", + }, + { + name: "empty", + kase: "", + expect: "", + }, + { + name: "midline", + kase: "\nabc\ndefghijkl\nmnopqrstuvwxy\nz", + expect: "
abc
defghijkl
mnopqrstuvwxy
z", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + buf := &strings.Builder{} + b := &BreakWriter{ + Writer: buf, + } + n, err := b.Write([]byte(tt.kase)) + if (err != nil) != tt.wantErr { + t.Errorf("BreakWriter.Write() error = %v, wantErr %v", err, tt.wantErr) + return + } + if n != len(tt.kase) { + t.Errorf("BreakWriter.Write() = %v, want %v", n, len(tt.kase)) + } + if buf.String() != tt.expect { + t.Errorf("BreakWriter.Write() wrote %q, want %v", buf.String(), tt.expect) + } + }) + } +} diff --git a/modules/charset/escape.go b/modules/charset/escape.go index 9c1baafba326..b264a569ff5e 100644 --- a/modules/charset/escape.go +++ b/modules/charset/escape.go @@ -1,236 +1,58 @@ -// Copyright 2021 The Gitea Authors. All rights reserved. +// 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. +//go:generate go run invisible/generate.go -v -o ./invisible_gen.go + +//go:generate go run ambiguous/generate.go -v -o ./ambiguous_gen.go ambiguous/ambiguous.json + package charset import ( - "bytes" - "fmt" "io" "strings" - "unicode" - "unicode/utf8" - "golang.org/x/text/unicode/bidi" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/translation" ) -// EscapeStatus represents the findings of the unicode escaper -type EscapeStatus struct { - Escaped bool - HasError bool - HasBadRunes bool - HasControls bool - HasSpaces bool - HasMarks bool - HasBIDI bool - BadBIDI bool - HasRTLScript bool - HasLTRScript bool -} - -// Or combines two EscapeStatus structs into one representing the conjunction of the two -func (status EscapeStatus) Or(other EscapeStatus) EscapeStatus { - st := status - st.Escaped = st.Escaped || other.Escaped - st.HasError = st.HasError || other.HasError - st.HasBadRunes = st.HasBadRunes || other.HasBadRunes - st.HasControls = st.HasControls || other.HasControls - st.HasSpaces = st.HasSpaces || other.HasSpaces - st.HasMarks = st.HasMarks || other.HasMarks - st.HasBIDI = st.HasBIDI || other.HasBIDI - st.BadBIDI = st.BadBIDI || other.BadBIDI - st.HasRTLScript = st.HasRTLScript || other.HasRTLScript - st.HasLTRScript = st.HasLTRScript || other.HasLTRScript - return st -} +// RuneNBSP is the codepoint for NBSP +const RuneNBSP = 0xa0 -// 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) (EscapeStatus, string) { +// EscapeControlHTML escapes the unicode control sequences in a provided html document +func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) { sb := &strings.Builder{} - escaped, _ := EscapeControlReader(strings.NewReader(text), sb) - return escaped, sb.String() -} + outputStream := &HTMLStreamerWriter{Writer: sb} + streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) -// EscapeControlBytes escapes the unicode control sequences a provided []byte and returns the findings as an EscapeStatus and the escaped []byte -func EscapeControlBytes(text []byte) (EscapeStatus, []byte) { - buf := &bytes.Buffer{} - escaped, _ := EscapeControlReader(bytes.NewReader(text), buf) - return escaped, buf.Bytes() + if err := StreamHTML(strings.NewReader(text), streamer); err != nil { + streamer.escaped.HasError = true + log.Error("Error whilst escaping: %v", err) + } + return streamer.escaped, sb.String() } -// EscapeControlReader escapes the unicode control sequences a provided Reader writing the escaped output to the output and returns the findings as an EscapeStatus and an error -func EscapeControlReader(text io.Reader, output io.Writer) (escaped EscapeStatus, err error) { - buf := make([]byte, 4096) - readStart := 0 - runeCount := 0 - var n int - var writePos int - - lineHasBIDI := false - lineHasRTLScript := false - lineHasLTRScript := false - -readingloop: - for err == nil { - n, err = text.Read(buf[readStart:]) - bs := buf[:n+readStart] - n = len(bs) - i := 0 +// 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) - for i < len(bs) { - r, size := utf8.DecodeRune(bs[i:]) - runeCount++ - - // Now handle the codepoints - switch { - case r == utf8.RuneError: - if writePos < i { - if _, err = output.Write(bs[writePos:i]); err != nil { - escaped.HasError = true - return - } - writePos = i - } - // runes can be at most 4 bytes - so... - if len(bs)-i <= 3 { - // if not request more data - copy(buf, bs[i:]) - readStart = n - i - writePos = 0 - continue readingloop - } - // this is a real broken rune - escaped.HasBadRunes = true - escaped.Escaped = true - if err = writeBroken(output, bs[i:i+size]); err != nil { - escaped.HasError = true - return - } - writePos += size - case r == '\n': - if lineHasBIDI && !lineHasRTLScript && lineHasLTRScript { - escaped.BadBIDI = true - } - lineHasBIDI = false - lineHasRTLScript = false - lineHasLTRScript = false - - case runeCount == 1 && r == 0xFEFF: // UTF BOM - // the first BOM is safe - case r == '\r' || r == '\t' || r == ' ': - // These are acceptable control characters and space characters - case unicode.IsSpace(r): - escaped.HasSpaces = true - escaped.Escaped = true - if writePos < i { - if _, err = output.Write(bs[writePos:i]); err != nil { - escaped.HasError = true - return - } - } - if err = writeEscaped(output, r); err != nil { - escaped.HasError = true - return - } - writePos = i + size - case unicode.Is(unicode.Bidi_Control, r): - escaped.Escaped = true - escaped.HasBIDI = true - if writePos < i { - if _, err = output.Write(bs[writePos:i]); err != nil { - escaped.HasError = true - return - } - } - lineHasBIDI = true - if err = writeEscaped(output, r); err != nil { - escaped.HasError = true - return - } - writePos = i + size - case unicode.Is(unicode.C, r): - escaped.Escaped = true - escaped.HasControls = true - if writePos < i { - if _, err = output.Write(bs[writePos:i]); err != nil { - escaped.HasError = true - return - } - } - if err = writeEscaped(output, r); err != nil { - escaped.HasError = true - return - } - writePos = i + size - case unicode.Is(unicode.M, r): - escaped.Escaped = true - escaped.HasMarks = true - if writePos < i { - if _, err = output.Write(bs[writePos:i]); err != nil { - escaped.HasError = true - return - } - } - if err = writeEscaped(output, r); err != nil { - escaped.HasError = true - return - } - writePos = i + size - default: - p, _ := bidi.Lookup(bs[i : i+size]) - c := p.Class() - if c == bidi.R || c == bidi.AL { - lineHasRTLScript = true - escaped.HasRTLScript = true - } else if c == bidi.L { - lineHasLTRScript = true - escaped.HasLTRScript = true - } - } - i += size - } - if n > 0 { - // we read something... - // write everything unwritten - if writePos < i { - if _, err = output.Write(bs[writePos:i]); err != nil { - escaped.HasError = true - return - } - } - - // reset the starting positions for the next read - readStart = 0 - writePos = 0 - } - } - if readStart > 0 { - // this means that there is an incomplete or broken rune at 0-readStart and we read nothing on the last go round - escaped.Escaped = true - escaped.HasBadRunes = true - if err = writeBroken(output, buf[:readStart]); err != nil { - escaped.HasError = true - return - } - } - if err == io.EOF { - if lineHasBIDI && !lineHasRTLScript && lineHasLTRScript { - escaped.BadBIDI = true - } - err = nil - return + if err = StreamHTML(reader, streamer); err != nil { + streamer.escaped.HasError = true + log.Error("Error whilst escaping: %v", err) } - escaped.HasError = true - return escaped, err + return streamer.escaped, err } -func writeBroken(output io.Writer, bs []byte) (err error) { - _, err = fmt.Fprintf(output, `<%X>`, bs) - return 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{} + outputStream := &HTMLStreamerWriter{Writer: sb} + streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) -func writeEscaped(output io.Writer, r rune) (err error) { - _, err = fmt.Fprintf(output, `%c`, r, r) - return err + if err := streamer.Text(text); err != nil { + streamer.escaped.HasError = true + log.Error("Error whilst escaping: %v", err) + } + return streamer.escaped, sb.String() } diff --git a/modules/charset/escape_status.go b/modules/charset/escape_status.go new file mode 100644 index 000000000000..7ff0ef112bb2 --- /dev/null +++ b/modules/charset/escape_status.go @@ -0,0 +1,28 @@ +// 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 charset + +// EscapeStatus represents the findings of the unicode escaper +type EscapeStatus struct { + Escaped bool + HasError bool + HasBadRunes bool + HasInvisible bool + HasAmbiguous bool +} + +// Or combines two EscapeStatus structs into one representing the conjunction of the two +func (status *EscapeStatus) Or(other *EscapeStatus) *EscapeStatus { + st := status + if status == nil { + st = &EscapeStatus{} + } + st.Escaped = st.Escaped || other.Escaped + st.HasError = st.HasError || other.HasError + st.HasBadRunes = st.HasBadRunes || other.HasBadRunes + st.HasAmbiguous = st.HasAmbiguous || other.HasAmbiguous + st.HasInvisible = st.HasInvisible || other.HasInvisible + return st +} diff --git a/modules/charset/escape_stream.go b/modules/charset/escape_stream.go new file mode 100644 index 000000000000..8c17136c9dc6 --- /dev/null +++ b/modules/charset/escape_stream.go @@ -0,0 +1,297 @@ +// 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 charset + +import ( + "fmt" + "regexp" + "sort" + "strings" + "unicode" + "unicode/utf8" + + "code.gitea.io/gitea/modules/translation" + + "golang.org/x/net/html" +) + +// VScode defaultWordRegexp +var defaultWordRegexp = regexp.MustCompile(`(-?\d*\.\d\w*)|([^\` + "`" + `\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s\x00-\x1f]+)`) + +func NewEscapeStreamer(locale translation.Locale, next HTMLStreamer, allowed ...rune) HTMLStreamer { + return &escapeStreamer{ + escaped: &EscapeStatus{}, + PassthroughHTMLStreamer: *NewPassthroughStreamer(next), + locale: locale, + ambiguousTables: AmbiguousTablesForLocale(locale), + allowed: allowed, + } +} + +type escapeStreamer struct { + PassthroughHTMLStreamer + escaped *EscapeStatus + locale translation.Locale + ambiguousTables []*AmbiguousTable + allowed []rune +} + +func (e *escapeStreamer) EscapeStatus() *EscapeStatus { + return e.escaped +} + +// Text tells the next streamer there is a text +func (e *escapeStreamer) Text(data string) error { + sb := &strings.Builder{} + pos, until, next := 0, 0, 0 + if len(data) > len(UTF8BOM) && data[:len(UTF8BOM)] == string(UTF8BOM) { + _, _ = sb.WriteString(data[:len(UTF8BOM)]) + pos = len(UTF8BOM) + } + for pos < len(data) { + nextIdxs := defaultWordRegexp.FindStringIndex(data[pos:]) + if nextIdxs == nil { + until = len(data) + next = until + } else { + until, next = nextIdxs[0]+pos, nextIdxs[1]+pos + } + + // from pos until until we know that the runes are not \r\t\n or even ' ' + runes := make([]rune, 0, next-until) + positions := make([]int, 0, next-until+1) + + for pos < until { + r, sz := utf8.DecodeRune([]byte(data)[pos:]) + positions = positions[:0] + positions = append(positions, pos, pos+sz) + types, confusables, _ := e.runeTypes(r) + if err := e.handleRunes(data, []rune{r}, positions, types, confusables, sb); err != nil { + return err + } + pos += sz + } + + for i := pos; i < next; { + r, sz := utf8.DecodeRune([]byte(data)[i:]) + runes = append(runes, r) + positions = append(positions, i) + i += sz + } + positions = append(positions, next) + types, confusables, runeCounts := e.runeTypes(runes...) + if runeCounts.needsEscape() { + if err := e.handleRunes(data, runes, positions, types, confusables, sb); err != nil { + return err + } + } else { + _, _ = sb.Write([]byte(data)[pos:next]) + } + pos = next + } + if sb.Len() > 0 { + if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil { + return err + } + } + return nil +} + +func (e *escapeStreamer) handleRunes(data string, runes []rune, positions []int, types []runeType, confusables []rune, sb *strings.Builder) error { + for i, r := range runes { + switch types[i] { + case brokenRuneType: + if sb.Len() > 0 { + if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil { + return err + } + sb.Reset() + } + end := positions[i+1] + start := positions[i] + if err := e.brokenRune([]byte(data)[start:end]); err != nil { + return err + } + case ambiguousRuneType: + if sb.Len() > 0 { + if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil { + return err + } + sb.Reset() + } + if err := e.ambiguousRune(r, confusables[0]); err != nil { + return err + } + confusables = confusables[1:] + case invisibleRuneType: + if sb.Len() > 0 { + if err := e.PassthroughHTMLStreamer.Text(sb.String()); err != nil { + return err + } + sb.Reset() + } + if err := e.invisibleRune(r); err != nil { + return err + } + default: + _, _ = sb.WriteRune(r) + } + } + return nil +} + +func (e *escapeStreamer) brokenRune(bs []byte) error { + e.escaped.Escaped = true + e.escaped.HasBadRunes = true + + if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{ + Key: "class", + Val: "broken-code-point", + }); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.Text(fmt.Sprintf("<%X>", bs)); err != nil { + return err + } + + return e.PassthroughHTMLStreamer.EndTag("span") +} + +func (e *escapeStreamer) ambiguousRune(r, c rune) error { + e.escaped.Escaped = true + e.escaped.HasAmbiguous = true + + if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{ + Key: "class", + Val: "ambiguous-code-point tooltip", + }, html.Attribute{ + Key: "data-content", + Val: e.locale.Tr("repo.ambiguous_character", r, c), + }); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{ + Key: "class", + Val: "char", + }); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.Text(string(r)); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.EndTag("span"); err != nil { + return err + } + + return e.PassthroughHTMLStreamer.EndTag("span") +} + +func (e *escapeStreamer) invisibleRune(r rune) error { + e.escaped.Escaped = true + e.escaped.HasInvisible = true + + if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{ + Key: "class", + Val: "escaped-code-point", + }, html.Attribute{ + Key: "data-escaped", + Val: fmt.Sprintf("[U+%04X]", r), + }); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{ + Key: "class", + Val: "char", + }); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.Text(string(r)); err != nil { + return err + } + if err := e.PassthroughHTMLStreamer.EndTag("span"); err != nil { + return err + } + + return e.PassthroughHTMLStreamer.EndTag("span") +} + +type runeCountType struct { + numBasicRunes int + numNonConfusingNonBasicRunes int + numAmbiguousRunes int + numInvisibleRunes int + numBrokenRunes int +} + +func (counts runeCountType) needsEscape() bool { + if counts.numBrokenRunes > 0 { + return true + } + if counts.numBasicRunes == 0 && + counts.numNonConfusingNonBasicRunes > 0 { + return false + } + return counts.numAmbiguousRunes > 0 || counts.numInvisibleRunes > 0 +} + +type runeType int + +const ( + basicASCIIRuneType runeType = iota //nolint // <- This is technically deadcode but its self-documenting so it should stay + brokenRuneType + nonBasicASCIIRuneType + ambiguousRuneType + invisibleRuneType +) + +func (e *escapeStreamer) runeTypes(runes ...rune) (types []runeType, confusables []rune, runeCounts runeCountType) { + types = make([]runeType, len(runes)) + for i, r := range runes { + var confusable rune + switch { + case r == utf8.RuneError: + types[i] = brokenRuneType + runeCounts.numBrokenRunes++ + case r == ' ' || r == '\t' || r == '\n': + runeCounts.numBasicRunes++ + case e.isAllowed(r): + if r > 0x7e || r < 0x20 { + types[i] = nonBasicASCIIRuneType + runeCounts.numNonConfusingNonBasicRunes++ + } else { + runeCounts.numBasicRunes++ + } + case unicode.Is(InvisibleRanges, r): + types[i] = invisibleRuneType + runeCounts.numInvisibleRunes++ + case unicode.IsControl(r): + types[i] = invisibleRuneType + runeCounts.numInvisibleRunes++ + case isAmbiguous(r, &confusable, e.ambiguousTables...): + confusables = append(confusables, confusable) + types[i] = ambiguousRuneType + runeCounts.numAmbiguousRunes++ + case r > 0x7e || r < 0x20: + types[i] = nonBasicASCIIRuneType + runeCounts.numNonConfusingNonBasicRunes++ + default: + runeCounts.numBasicRunes++ + } + } + return types, confusables, runeCounts +} + +func (e *escapeStreamer) isAllowed(r rune) bool { + if len(e.allowed) == 0 { + return false + } + if len(e.allowed) == 1 { + return e.allowed[0] == r + } + + return sort.Search(len(e.allowed), func(i int) bool { + return e.allowed[i] >= r + }) >= 0 +} diff --git a/modules/charset/escape_test.go b/modules/charset/escape_test.go index 01ccca77249b..8063e115424c 100644 --- a/modules/charset/escape_test.go +++ b/modules/charset/escape_test.go @@ -8,6 +8,8 @@ import ( "reflect" "strings" "testing" + + "code.gitea.io/gitea/modules/translation" ) type escapeControlTest struct { @@ -25,37 +27,37 @@ var escapeControlTests = []escapeControlTest{ name: "single line western", text: "single line western", result: "single line western", - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, { name: "multi line western", text: "single line western\nmulti line western\n", result: "single line western\nmulti line western\n", - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, { name: "multi line western non-breaking space", text: "single line western\nmulti line western\n", result: `single line western` + "\n" + `multi line western` + "\n", - status: EscapeStatus{Escaped: true, HasLTRScript: true, HasSpaces: true}, + status: EscapeStatus{Escaped: true, HasInvisible: true}, }, { name: "mixed scripts: western + japanese", text: "日属秘ぞしちゅ。Then some western.", result: "日属秘ぞしちゅ。Then some western.", - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, { name: "japanese", text: "日属秘ぞしちゅ。", result: "日属秘ぞしちゅ。", - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, { name: "hebrew", text: "עד תקופת יוון העתיקה היה העיסוק במתמטיקה תכליתי בלבד: היא שימשה כאוסף של נוסחאות לחישוב קרקע, אוכלוסין וכו'. פריצת הדרך של היוונים, פרט לתרומותיהם הגדולות לידע המתמטי, הייתה בלימוד המתמטיקה כשלעצמה, מתוקף ערכה הרוחני. יחסם של חלק מהיוונים הקדמונים למתמטיקה היה דתי - למשל, הכת שאסף סביבו פיתגורס האמינה כי המתמטיקה היא הבסיס לכל הדברים. היוונים נחשבים ליוצרי מושג ההוכחה המתמטית, וכן לראשונים שעסקו במתמטיקה לשם עצמה, כלומר כתחום מחקרי עיוני ומופשט ולא רק כעזר שימושי. עם זאת, לצדה", - result: "עד תקופת יוון העתיקה היה העיסוק במתמטיקה תכליתי בלבד: היא שימשה כאוסף של נוסחאות לחישוב קרקע, אוכלוסין וכו'. פריצת הדרך של היוונים, פרט לתרומותיהם הגדולות לידע המתמטי, הייתה בלימוד המתמטיקה כשלעצמה, מתוקף ערכה הרוחני. יחסם של חלק מהיוונים הקדמונים למתמטיקה היה דתי - למשל, הכת שאסף סביבו פיתגורס האמינה כי המתמטיקה היא הבסיס לכל הדברים. היוונים נחשבים ליוצרי מושג ההוכחה המתמטית, וכן לראשונים שעסקו במתמטיקה לשם עצמה, כלומר כתחום מחקרי עיוני ומופשט ולא רק כעזר שימושי. עם זאת, לצדה", - status: EscapeStatus{HasRTLScript: true}, + result: `עד תקופת יוון העתיקה היה העיסוק במתמטיקה תכליתי בלבד: היא שימשה כאוסף של נוסחאות לחישוב קרקע, אוכלוסין וכו'. פריצת הדרך של היוונים, פרט לתרומותיהם הגדולות לידע המתמטי, הייתה בלימוד המתמטיקה כשלעצמה, מתוקף ערכה הרוחני. יחסם של חלק מהיוונים הקדמונים למתמטיקה היה דתי - למשל, הכת שאסף סביבו פיתגורס האמינה כי המתמטיקה היא הבסיס לכל הדברים. היוונים נחשבים ליוצרי מושג ההוכחה המתמטית, וכן לראשונים שעסקו במתמטיקה לשם עצמה, כלומר כתחום מחקרי עיוני ומופשט ולא רק כעזר שימושי. עם זאת, לצדה`, + status: EscapeStatus{Escaped: true, HasAmbiguous: true}, }, { name: "more hebrew", @@ -64,12 +66,12 @@ var escapeControlTests = []escapeControlTest{ המתמטיקאי הבולט הראשון ביוון העתיקה, ויש האומרים בתולדות האנושות, הוא תאלס (624 לפנה"ס - 546 לפנה"ס בקירוב).[1] לא יהיה זה משולל יסוד להניח שהוא האדם הראשון שהוכיח משפט מתמטי, ולא רק גילה אותו. תאלס הוכיח שישרים מקבילים חותכים מצד אחד של שוקי זווית קטעים בעלי יחסים שווים (משפט תאלס הראשון), שהזווית המונחת על קוטר במעגל היא זווית ישרה (משפט תאלס השני), שהקוטר מחלק את המעגל לשני חלקים שווים, ושזוויות הבסיס במשולש שווה-שוקיים שוות זו לזו. מיוחסות לו גם שיטות למדידת גובהן של הפירמידות בעזרת מדידת צילן ולקביעת מיקומה של ספינה הנראית מן החוף. בשנים 582 לפנה"ס עד 496 לפנה"ס, בקירוב, חי מתמטיקאי חשוב במיוחד - פיתגורס. המקורות הראשוניים עליו מועטים, וההיסטוריונים מתקשים להפריד את העובדות משכבת המסתורין והאגדות שנקשרו בו. ידוע שסביבו התקבצה האסכולה הפיתגוראית מעין כת פסבדו-מתמטית שהאמינה ש"הכל מספר", או ליתר דיוק הכל ניתן לכימות, וייחסה למספרים משמעויות מיסטיות. ככל הנראה הפיתגוראים ידעו לבנות את הגופים האפלטוניים, הכירו את הממוצע האריתמטי, הממוצע הגאומטרי והממוצע ההרמוני והגיעו להישגים חשובים נוספים. ניתן לומר שהפיתגוראים גילו את היותו של השורש הריבועי של 2, שהוא גם האלכסון בריבוע שאורך צלעותיו 1, אי רציונלי, אך תגליתם הייתה למעשה רק שהקטעים "חסרי מידה משותפת", ומושג המספר האי רציונלי מאוחר יותר.[2] אזכור ראשון לקיומם של קטעים חסרי מידה משותפת מופיע בדיאלוג "תאיטיטוס" של אפלטון, אך רעיון זה היה מוכר עוד קודם לכן, במאה החמישית לפנה"ס להיפאסוס, בן האסכולה הפיתגוראית, ואולי לפיתגורס עצמו.[3]`, - result: `בתקופה מאוחרת יותר, השתמשו היוונים בשיטת סימון מתקדמת יותר, שבה הוצגו המספרים לפי 22 אותיות האלפבית היווני. לסימון המספרים בין 1 ל-9 נקבעו תשע האותיות הראשונות, בתוספת גרש ( ' ) בצד ימין של האות, למעלה; תשע האותיות הבאות ייצגו את העשרות מ-10 עד 90, והבאות את המאות. לסימון הספרות בין 1000 ל-900,000, השתמשו היוונים באותן אותיות, אך הוסיפו לאותיות את הגרש דווקא מצד שמאל של האותיות, למטה. ממיליון ומעלה, כנראה השתמשו היוונים בשני תגים במקום אחד. + result: `בתקופה מאוחרת יותר, השתמשו היוונים בשיטת סימון מתקדמת יותר, שבה הוצגו המספרים לפי 22 אותיות האלפבית היווני. לסימון המספרים בין 1 ל-9 נקבעו תשע האותיות הראשונות, בתוספת גרש ( ' ) בצד ימין של האות, למעלה; תשע האותיות הבאות ייצגו את העשרות מ-10 עד 90, והבאות את המאות. לסימון הספרות בין 1000 ל-900,000, השתמשו היוונים באותן אותיות, אך הוסיפו לאותיות את הגרש דווקא מצד שמאל של האותיות, למטה. ממיליון ומעלה, כנראה השתמשו היוונים בשני תגים במקום אחד. - המתמטיקאי הבולט הראשון ביוון העתיקה, ויש האומרים בתולדות האנושות, הוא תאלס (624 לפנה"ס - 546 לפנה"ס בקירוב).[1] לא יהיה זה משולל יסוד להניח שהוא האדם הראשון שהוכיח משפט מתמטי, ולא רק גילה אותו. תאלס הוכיח שישרים מקבילים חותכים מצד אחד של שוקי זווית קטעים בעלי יחסים שווים (משפט תאלס הראשון), שהזווית המונחת על קוטר במעגל היא זווית ישרה (משפט תאלס השני), שהקוטר מחלק את המעגל לשני חלקים שווים, ושזוויות הבסיס במשולש שווה-שוקיים שוות זו לזו. מיוחסות לו גם שיטות למדידת גובהן של הפירמידות בעזרת מדידת צילן ולקביעת מיקומה של ספינה הנראית מן החוף. + המתמטיקאי הבולט הראשון ביוון העתיקה, ויש האומרים בתולדות האנושות, הוא תאלס (624 לפנה"ס - 546 לפנה"ס בקירוב).[1] לא יהיה זה משולל יסוד להניח שהוא האדם הראשון שהוכיח משפט מתמטי, ולא רק גילה אותו. תאלס הוכיח שישרים מקבילים חותכים מצד אחד של שוקי זווית קטעים בעלי יחסים שווים (משפט תאלס הראשון), שהזווית המונחת על קוטר במעגל היא זווית ישרה (משפט תאלס השני), שהקוטר מחלק את המעגל לשני חלקים שווים, ושזוויות הבסיס במשולש שווה-שוקיים שוות זו לזו. מיוחסות לו גם שיטות למדידת גובהן של הפירמידות בעזרת מדידת צילן ולקביעת מיקומה של ספינה הנראית מן החוף. - בשנים 582 לפנה"ס עד 496 לפנה"ס, בקירוב, חי מתמטיקאי חשוב במיוחד - פיתגורס. המקורות הראשוניים עליו מועטים, וההיסטוריונים מתקשים להפריד את העובדות משכבת המסתורין והאגדות שנקשרו בו. ידוע שסביבו התקבצה האסכולה הפיתגוראית מעין כת פסבדו-מתמטית שהאמינה ש"הכל מספר", או ליתר דיוק הכל ניתן לכימות, וייחסה למספרים משמעויות מיסטיות. ככל הנראה הפיתגוראים ידעו לבנות את הגופים האפלטוניים, הכירו את הממוצע האריתמטי, הממוצע הגאומטרי והממוצע ההרמוני והגיעו להישגים חשובים נוספים. ניתן לומר שהפיתגוראים גילו את היותו של השורש הריבועי של 2, שהוא גם האלכסון בריבוע שאורך צלעותיו 1, אי רציונלי, אך תגליתם הייתה למעשה רק שהקטעים "חסרי מידה משותפת", ומושג המספר האי רציונלי מאוחר יותר.[2] אזכור ראשון לקיומם של קטעים חסרי מידה משותפת מופיע בדיאלוג "תאיטיטוס" של אפלטון, אך רעיון זה היה מוכר עוד קודם לכן, במאה החמישית לפנה"ס להיפאסוס, בן האסכולה הפיתגוראית, ואולי לפיתגורס עצמו.[3]`, - status: EscapeStatus{HasRTLScript: true}, + בשנים 582 לפנה"ס עד 496 לפנה"ס, בקירוב, חי מתמטיקאי חשוב במיוחד - פיתגורס. המקורות הראשוניים עליו מועטים, וההיסטוריונים מתקשים להפריד את העובדות משכבת המסתורין והאגדות שנקשרו בו. ידוע שסביבו התקבצה האסכולה הפיתגוראית מעין כת פסבדו-מתמטית שהאמינה ש"הכל מספר", או ליתר דיוק הכל ניתן לכימות, וייחסה למספרים משמעויות מיסטיות. ככל הנראה הפיתגוראים ידעו לבנות את הגופים האפלטוניים, הכירו את הממוצע האריתמטי, הממוצע הגאומטרי והממוצע ההרמוני והגיעו להישגים חשובים נוספים. ניתן לומר שהפיתגוראים גילו את היותו של השורש הריבועי של 2, שהוא גם האלכסון בריבוע שאורך צלעותיו 1, אי רציונלי, אך תגליתם הייתה למעשה רק שהקטעים "חסרי מידה משותפת", ומושג המספר האי רציונלי מאוחר יותר.[2] אזכור ראשון לקיומם של קטעים חסרי מידה משותפת מופיע בדיאלוג "תאיטיטוס" של אפלטון, אך רעיון זה היה מוכר עוד קודם לכן, במאה החמישית לפנה"ס להיפאסוס, בן האסכולה הפיתגוראית, ואולי לפיתגורס עצמו.[3]`, + status: EscapeStatus{Escaped: true, HasAmbiguous: true}, }, { name: "Mixed RTL+LTR", @@ -79,10 +81,7 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`, result: `Many computer programs fail to display bidirectional text correctly. For example, the Hebrew name Sarah (שרה) is spelled: sin (ש) (which appears rightmost), then resh (ר), and finally heh (ה) (which should appear leftmost).`, - status: EscapeStatus{ - HasRTLScript: true, - HasLTRScript: true, - }, + status: EscapeStatus{}, }, { name: "Mixed RTL+LTR+BIDI", @@ -90,32 +89,27 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`, For example, the Hebrew name Sarah ` + "\u2067" + `שרה` + "\u2066\n" + `sin (ש) (which appears rightmost), then resh (ר), and finally heh (ה) (which should appear leftmost).`, result: `Many computer programs fail to display bidirectional text correctly. - For example, the Hebrew name Sarah ` + "\u2067" + `שרה` + "\u2066" + `` + "\n" + + For example, the Hebrew name Sarah ` + "\u2067" + `שרה` + "\u2066\n" + `sin (ש) (which appears rightmost), then resh (ר), and finally heh (ה) (which should appear leftmost).`, - status: EscapeStatus{ - Escaped: true, - HasBIDI: true, - HasRTLScript: true, - HasLTRScript: true, - }, + status: EscapeStatus{}, }, { name: "Accented characters", text: string([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}), result: string([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba}), - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, { name: "Program", text: "string([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})", result: "string([]byte{0xc3, 0xa1, 0xc3, 0xa9, 0xc3, 0xad, 0xc3, 0xb3, 0xc3, 0xba})", - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, { name: "CVE testcase", text: "if access_level != \"user\u202E \u2066// Check if admin\u2069 \u2066\" {", - result: `if access_level != "user` + "\u202e" + ` ` + "\u2066" + `// Check if admin` + "\u2069" + ` ` + "\u2066" + `" {`, - status: EscapeStatus{Escaped: true, HasBIDI: true, BadBIDI: true, HasLTRScript: true}, + result: `if access_level != "user` + "\u202e" + ` ` + "\u2066" + `// Check if admin` + "\u2069" + ` ` + "\u2066" + `" {`, + status: EscapeStatus{Escaped: true, HasInvisible: true}, }, { name: "Mixed testcase with fail", @@ -124,10 +118,10 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`, `sin (ש) (which appears rightmost), then resh (ר), and finally heh (ה) (which should appear leftmost).` + "\nif access_level != \"user\u202E \u2066// Check if admin\u2069 \u2066\" {\n", result: `Many computer programs fail to display bidirectional text correctly. - For example, the Hebrew name Sarah ` + "\u2067" + `שרה` + "\u2066" + `` + "\n" + + For example, the Hebrew name Sarah ` + "\u2067" + `שרה` + "\u2066\n" + `sin (ש) (which appears rightmost), then resh (ר), and finally heh (ה) (which should appear leftmost).` + - "\n" + `if access_level != "user` + "\u202e" + ` ` + "\u2066" + `// Check if admin` + "\u2069" + ` ` + "\u2066" + `" {` + "\n", - status: EscapeStatus{Escaped: true, HasBIDI: true, BadBIDI: true, HasLTRScript: true, HasRTLScript: true}, + "\n" + `if access_level != "user` + "\u202e" + ` ` + "\u2066" + `// Check if admin` + "\u2069" + ` ` + "\u2066" + `" {` + "\n", + status: EscapeStatus{Escaped: true, HasInvisible: true}, }, { // UTF-8/16/32 all use the same codepoint for BOM @@ -135,15 +129,16 @@ then resh (ר), and finally heh (ה) (which should appear leftmost).`, name: "UTF BOM", text: "\xef\xbb\xbftest", result: "\xef\xbb\xbftest", - status: EscapeStatus{HasLTRScript: true}, + status: EscapeStatus{}, }, } func TestEscapeControlString(t *testing.T) { for _, tt := range escapeControlTests { t.Run(tt.name, func(t *testing.T) { - status, result := EscapeControlString(tt.text) - if !reflect.DeepEqual(status, tt.status) { + locale := translation.NewLocale("en_US") + status, result := EscapeControlString(tt.text, locale) + if !reflect.DeepEqual(*status, tt.status) { t.Errorf("EscapeControlString() status = %v, wanted= %v", status, tt.status) } if result != tt.result { @@ -153,20 +148,6 @@ func TestEscapeControlString(t *testing.T) { } } -func TestEscapeControlBytes(t *testing.T) { - for _, tt := range escapeControlTests { - t.Run(tt.name, func(t *testing.T) { - status, result := EscapeControlBytes([]byte(tt.text)) - if !reflect.DeepEqual(status, tt.status) { - t.Errorf("EscapeControlBytes() status = %v, wanted= %v", status, tt.status) - } - if string(result) != tt.result { - t.Errorf("EscapeControlBytes()\nresult= %v,\nwanted= %v", result, tt.result) - } - }) - } -} - func TestEscapeControlReader(t *testing.T) { // lets add some control characters to the tests tests := make([]escapeControlTest, 0, len(escapeControlTests)*3) @@ -184,16 +165,7 @@ func TestEscapeControlReader(t *testing.T) { test.text = addPrefix("\u001E", test.text) test.result = addPrefix(``+"\u001e"+``, test.result) test.status.Escaped = true - test.status.HasControls = true - tests = append(tests, test) - } - - for _, test := range escapeControlTests { - test.name += " (+Mark)" - test.text = addPrefix("\u0300", test.text) - test.result = addPrefix(``+"\u0300"+``, test.result) - test.status.Escaped = true - test.status.HasMarks = true + test.status.HasInvisible = true tests = append(tests, test) } @@ -201,13 +173,13 @@ func TestEscapeControlReader(t *testing.T) { t.Run(tt.name, func(t *testing.T) { input := strings.NewReader(tt.text) output := &strings.Builder{} - status, err := EscapeControlReader(input, output) + status, err := EscapeControlReader(input, output, translation.NewLocale("en_US")) result := output.String() if err != nil { t.Errorf("EscapeControlReader(): err = %v", err) } - if !reflect.DeepEqual(status, tt.status) { + if !reflect.DeepEqual(*status, tt.status) { t.Errorf("EscapeControlReader() status = %v, wanted= %v", status, tt.status) } if result != tt.result { @@ -223,5 +195,5 @@ func TestEscapeControlReader_panic(t *testing.T) { for i := 0; i < 6826; i++ { bs = append(bs, []byte("—")...) } - _, _ = EscapeControlBytes(bs) + _, _ = EscapeControlString(string(bs), translation.NewLocale("en_US")) } diff --git a/modules/charset/htmlstream.go b/modules/charset/htmlstream.go new file mode 100644 index 000000000000..b354ce6a48a1 --- /dev/null +++ b/modules/charset/htmlstream.go @@ -0,0 +1,201 @@ +// 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 charset + +import ( + "fmt" + "io" + + "golang.org/x/net/html" +) + +// HTMLStreamer represents a SAX-like interface for HTML +type HTMLStreamer interface { + Error(err error) error + Doctype(data string) error + Comment(data string) error + StartTag(data string, attrs ...html.Attribute) error + SelfClosingTag(data string, attrs ...html.Attribute) error + EndTag(data string) error + Text(data string) error +} + +// PassthroughHTMLStreamer is a passthrough streamer +type PassthroughHTMLStreamer struct { + next HTMLStreamer +} + +func NewPassthroughStreamer(next HTMLStreamer) *PassthroughHTMLStreamer { + return &PassthroughHTMLStreamer{next: next} +} + +var _ (HTMLStreamer) = &PassthroughHTMLStreamer{} + +// Error tells the next streamer in line that there is an error +func (p *PassthroughHTMLStreamer) Error(err error) error { + return p.next.Error(err) +} + +// Doctype tells the next streamer what the doctype is +func (p *PassthroughHTMLStreamer) Doctype(data string) error { + return p.next.Doctype(data) +} + +// Comment tells the next streamer there is a comment +func (p *PassthroughHTMLStreamer) Comment(data string) error { + return p.next.Comment(data) +} + +// StartTag tells the next streamer there is a starting tag +func (p *PassthroughHTMLStreamer) StartTag(data string, attrs ...html.Attribute) error { + return p.next.StartTag(data, attrs...) +} + +// SelfClosingTag tells the next streamer there is a self-closing tag +func (p *PassthroughHTMLStreamer) SelfClosingTag(data string, attrs ...html.Attribute) error { + return p.next.SelfClosingTag(data, attrs...) +} + +// EndTag tells the next streamer there is a end tag +func (p *PassthroughHTMLStreamer) EndTag(data string) error { + return p.next.EndTag(data) +} + +// Text tells the next streamer there is a text +func (p *PassthroughHTMLStreamer) Text(data string) error { + return p.next.Text(data) +} + +// HTMLStreamWriter acts as a writing sink +type HTMLStreamerWriter struct { + io.Writer + err error +} + +// Write implements io.Writer +func (h *HTMLStreamerWriter) Write(data []byte) (int, error) { + if h.err != nil { + return 0, h.err + } + return h.Writer.Write(data) +} + +// Write implements io.StringWriter +func (h *HTMLStreamerWriter) WriteString(data string) (int, error) { + if h.err != nil { + return 0, h.err + } + return h.Writer.Write([]byte(data)) +} + +// Error tells the next streamer in line that there is an error +func (h *HTMLStreamerWriter) Error(err error) error { + if h.err == nil { + h.err = err + } + return h.err +} + +// Doctype tells the next streamer what the doctype is +func (h *HTMLStreamerWriter) Doctype(data string) error { + _, h.err = h.WriteString("") + return h.err +} + +// Comment tells the next streamer there is a comment +func (h *HTMLStreamerWriter) Comment(data string) error { + _, h.err = h.WriteString("") + return h.err +} + +// StartTag tells the next streamer there is a starting tag +func (h *HTMLStreamerWriter) StartTag(data string, attrs ...html.Attribute) error { + return h.startTag(data, attrs, false) +} + +// SelfClosingTag tells the next streamer there is a self-closing tag +func (h *HTMLStreamerWriter) SelfClosingTag(data string, attrs ...html.Attribute) error { + return h.startTag(data, attrs, true) +} + +func (h *HTMLStreamerWriter) startTag(data string, attrs []html.Attribute, selfclosing bool) error { + if _, h.err = h.WriteString("<" + data); h.err != nil { + return h.err + } + for _, attr := range attrs { + if _, h.err = h.WriteString(" " + attr.Key + "=\"" + html.EscapeString(attr.Val) + "\""); h.err != nil { + return h.err + } + } + if selfclosing { + if _, h.err = h.WriteString("/>"); h.err != nil { + return h.err + } + } else { + if _, h.err = h.WriteString(">"); h.err != nil { + return h.err + } + } + return h.err +} + +// EndTag tells the next streamer there is a end tag +func (h *HTMLStreamerWriter) EndTag(data string) error { + _, h.err = h.WriteString("") + return h.err +} + +// Text tells the next streamer there is a text +func (h *HTMLStreamerWriter) Text(data string) error { + _, h.err = h.WriteString(html.EscapeString(data)) + return h.err +} + +// StreamHTML streams an html to a provided streamer +func StreamHTML(source io.Reader, streamer HTMLStreamer) error { + tokenizer := html.NewTokenizer(source) + for { + tt := tokenizer.Next() + switch tt { + case html.ErrorToken: + if tokenizer.Err() != io.EOF { + return tokenizer.Err() + } + return nil + case html.DoctypeToken: + token := tokenizer.Token() + if err := streamer.Doctype(token.Data); err != nil { + return err + } + case html.CommentToken: + token := tokenizer.Token() + if err := streamer.Comment(token.Data); err != nil { + return err + } + case html.StartTagToken: + token := tokenizer.Token() + if err := streamer.StartTag(token.Data, token.Attr...); err != nil { + return err + } + case html.SelfClosingTagToken: + token := tokenizer.Token() + if err := streamer.StartTag(token.Data, token.Attr...); err != nil { + return err + } + case html.EndTagToken: + token := tokenizer.Token() + if err := streamer.EndTag(token.Data); err != nil { + return err + } + case html.TextToken: + token := tokenizer.Token() + if err := streamer.Text(token.Data); err != nil { + return err + } + default: + return fmt.Errorf("unknown type of token: %d", tt) + } + } +} diff --git a/modules/charset/invisible/generate.go b/modules/charset/invisible/generate.go new file mode 100644 index 000000000000..230ff0b83216 --- /dev/null +++ b/modules/charset/invisible/generate.go @@ -0,0 +1,111 @@ +// 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 main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "os" + "text/template" + + "golang.org/x/text/unicode/rangetable" +) + +// InvisibleRunes these are runes that vscode has assigned to be invisible +// See https://github.com/hediet/vscode-unicode-data +var InvisibleRunes = []rune{ + 9, 10, 11, 12, 13, 32, 127, 160, 173, 847, 1564, 4447, 4448, 6068, 6069, 6155, 6156, 6157, 6158, 7355, 7356, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8203, 8204, 8205, 8206, 8207, 8234, 8235, 8236, 8237, 8238, 8239, 8287, 8288, 8289, 8290, 8291, 8292, 8293, 8294, 8295, 8296, 8297, 8298, 8299, 8300, 8301, 8302, 8303, 10240, 12288, 12644, 65024, 65025, 65026, 65027, 65028, 65029, 65030, 65031, 65032, 65033, 65034, 65035, 65036, 65037, 65038, 65039, 65279, 65440, 65520, 65521, 65522, 65523, 65524, 65525, 65526, 65527, 65528, 65532, 78844, 119155, 119156, 119157, 119158, 119159, 119160, 119161, 119162, 917504, 917505, 917506, 917507, 917508, 917509, 917510, 917511, 917512, 917513, 917514, 917515, 917516, 917517, 917518, 917519, 917520, 917521, 917522, 917523, 917524, 917525, 917526, 917527, 917528, 917529, 917530, 917531, 917532, 917533, 917534, 917535, 917536, 917537, 917538, 917539, 917540, 917541, 917542, 917543, 917544, 917545, 917546, 917547, 917548, 917549, 917550, 917551, 917552, 917553, 917554, 917555, 917556, 917557, 917558, 917559, 917560, 917561, 917562, 917563, 917564, 917565, 917566, 917567, 917568, 917569, 917570, 917571, 917572, 917573, 917574, 917575, 917576, 917577, 917578, 917579, 917580, 917581, 917582, 917583, 917584, 917585, 917586, 917587, 917588, 917589, 917590, 917591, 917592, 917593, 917594, 917595, 917596, 917597, 917598, 917599, 917600, 917601, 917602, 917603, 917604, 917605, 917606, 917607, 917608, 917609, 917610, 917611, 917612, 917613, 917614, 917615, 917616, 917617, 917618, 917619, 917620, 917621, 917622, 917623, 917624, 917625, 917626, 917627, 917628, 917629, 917630, 917631, 917760, 917761, 917762, 917763, 917764, 917765, 917766, 917767, 917768, 917769, 917770, 917771, 917772, 917773, 917774, 917775, 917776, 917777, 917778, 917779, 917780, 917781, 917782, 917783, 917784, 917785, 917786, 917787, 917788, 917789, 917790, 917791, 917792, 917793, 917794, 917795, 917796, 917797, 917798, 917799, 917800, 917801, 917802, 917803, 917804, 917805, 917806, 917807, 917808, 917809, 917810, 917811, 917812, 917813, 917814, 917815, 917816, 917817, 917818, 917819, 917820, 917821, 917822, 917823, 917824, 917825, 917826, 917827, 917828, 917829, 917830, 917831, 917832, 917833, 917834, 917835, 917836, 917837, 917838, 917839, 917840, 917841, 917842, 917843, 917844, 917845, 917846, 917847, 917848, 917849, 917850, 917851, 917852, 917853, 917854, 917855, 917856, 917857, 917858, 917859, 917860, 917861, 917862, 917863, 917864, 917865, 917866, 917867, 917868, 917869, 917870, 917871, 917872, 917873, 917874, 917875, 917876, 917877, 917878, 917879, 917880, 917881, 917882, 917883, 917884, 917885, 917886, 917887, 917888, 917889, 917890, 917891, 917892, 917893, 917894, 917895, 917896, 917897, 917898, 917899, 917900, 917901, 917902, 917903, 917904, 917905, 917906, 917907, 917908, 917909, 917910, 917911, 917912, 917913, 917914, 917915, 917916, 917917, 917918, 917919, 917920, 917921, 917922, 917923, 917924, 917925, 917926, 917927, 917928, 917929, 917930, 917931, 917932, 917933, 917934, 917935, 917936, 917937, 917938, 917939, 917940, 917941, 917942, 917943, 917944, 917945, 917946, 917947, 917948, 917949, 917950, 917951, 917952, 917953, 917954, 917955, 917956, 917957, 917958, 917959, 917960, 917961, 917962, 917963, 917964, 917965, 917966, 917967, 917968, 917969, 917970, 917971, 917972, 917973, 917974, 917975, 917976, 917977, 917978, 917979, 917980, 917981, 917982, 917983, 917984, 917985, 917986, 917987, 917988, 917989, 917990, 917991, 917992, 917993, 917994, 917995, 917996, 917997, 917998, 917999, +} + +var verbose bool + +func main() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, `%s: Generate InvisibleRunesRange + +Usage: %[1]s [-v] [-o output.go] +`, os.Args[0]) + flag.PrintDefaults() + } + + output := "" + flag.BoolVar(&verbose, "v", false, "verbose output") + flag.StringVar(&output, "o", "invisible_gen.go", "file to output to") + flag.Parse() + + // First we filter the runes to remove + // + filtered := make([]rune, 0, len(InvisibleRunes)) + for _, r := range InvisibleRunes { + if r == ' ' || r == '\t' || r == '\n' { + continue + } + filtered = append(filtered, r) + } + + table := rangetable.New(filtered...) + if err := runTemplate(generatorTemplate, output, table); err != nil { + fatalf("Unable to run template: %v", err) + } +} + +func runTemplate(t *template.Template, filename string, data interface{}) error { + buf := bytes.NewBuffer(nil) + if err := t.Execute(buf, data); err != nil { + return fmt.Errorf("unable to execute template: %w", err) + } + bs, err := format.Source(buf.Bytes()) + if err != nil { + verbosef("Bad source:\n%s", buf.String()) + return fmt.Errorf("unable to format source: %w", err) + } + file, err := os.Create(filename) + if err != nil { + return fmt.Errorf("failed to create file %s because %w", filename, err) + } + defer file.Close() + _, err = file.Write(bs) + if err != nil { + return fmt.Errorf("unable to write generated source: %w", err) + } + return nil +} + +var generatorTemplate = template.Must(template.New("invisibleTemplate").Parse(`// This file is generated by modules/charset/invisible/generate.go DO NOT EDIT +// 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 charset + +import "unicode" + +var InvisibleRanges = &unicode.RangeTable{ + R16: []unicode.Range16{ +{{range .R16 }} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}}, +{{end}} }, + R32: []unicode.Range32{ +{{range .R32}} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}}, +{{end}} }, + LatinOffset: {{.LatinOffset}}, +} +`)) + +func logf(format string, args ...interface{}) { + fmt.Fprintf(os.Stderr, format+"\n", args...) +} + +func verbosef(format string, args ...interface{}) { + if verbose { + logf(format, args...) + } +} + +func fatalf(format string, args ...interface{}) { + logf("fatal: "+format+"\n", args...) + os.Exit(1) +} diff --git a/modules/charset/invisible_gen.go b/modules/charset/invisible_gen.go new file mode 100644 index 000000000000..b3bfebe0c0e0 --- /dev/null +++ b/modules/charset/invisible_gen.go @@ -0,0 +1,37 @@ +// This file is generated by modules/charset/invisible/generate.go DO NOT EDIT +// 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 charset + +import "unicode" + +var InvisibleRanges = &unicode.RangeTable{ + R16: []unicode.Range16{ + {Lo: 11, Hi: 13, Stride: 1}, + {Lo: 127, Hi: 160, Stride: 33}, + {Lo: 173, Hi: 847, Stride: 674}, + {Lo: 1564, Hi: 4447, Stride: 2883}, + {Lo: 4448, Hi: 6068, Stride: 1620}, + {Lo: 6069, Hi: 6155, Stride: 86}, + {Lo: 6156, Hi: 6158, Stride: 1}, + {Lo: 7355, Hi: 7356, Stride: 1}, + {Lo: 8192, Hi: 8207, Stride: 1}, + {Lo: 8234, Hi: 8239, Stride: 1}, + {Lo: 8287, Hi: 8303, Stride: 1}, + {Lo: 10240, Hi: 12288, Stride: 2048}, + {Lo: 12644, Hi: 65024, Stride: 52380}, + {Lo: 65025, Hi: 65039, Stride: 1}, + {Lo: 65279, Hi: 65440, Stride: 161}, + {Lo: 65520, Hi: 65528, Stride: 1}, + {Lo: 65532, Hi: 65532, Stride: 1}, + }, + R32: []unicode.Range32{ + {Lo: 78844, Hi: 119155, Stride: 40311}, + {Lo: 119156, Hi: 119162, Stride: 1}, + {Lo: 917504, Hi: 917631, Stride: 1}, + {Lo: 917760, Hi: 917999, Stride: 1}, + }, + LatinOffset: 2, +} diff --git a/modules/context/context.go b/modules/context/context.go index 882491161992..0b9898acef04 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -224,7 +224,7 @@ func (ctx *Context) HTML(status int, name base.TplName) { ctx.Data["TemplateLoadTimes"] = func() string { return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms" } - if err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data); err != nil { + if err := ctx.Render.HTML(ctx.Resp, status, string(name), templates.BaseVars().Merge(ctx.Data)); err != nil { if status == http.StatusInternalServerError && name == base.TplName("status/500") { ctx.PlainText(http.StatusInternalServerError, "Unable to find status/500 template") return diff --git a/modules/convert/git_commit_test.go b/modules/convert/git_commit_test.go index 118ba3a007a2..0bba0e502e6d 100644 --- a/modules/convert/git_commit_test.go +++ b/modules/convert/git_commit_test.go @@ -19,7 +19,7 @@ import ( func TestToCommitMeta(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) sha1, _ := git.NewIDFromString("0000000000000000000000000000000000000000") signature := &git.Signature{Name: "Test Signature", Email: "test@email.com", When: time.Unix(0, 0)} tag := &git.Tag{ diff --git a/modules/convert/issue_test.go b/modules/convert/issue_test.go index 5bf04bcb52b6..ec672abad277 100644 --- a/modules/convert/issue_test.go +++ b/modules/convert/issue_test.go @@ -21,8 +21,8 @@ import ( func TestLabel_ToLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}).(*issues_model.Label) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: label.RepoID}).(*repo_model.Repository) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: label.RepoID}) assert.Equal(t, &api.Label{ ID: label.ID, Name: label.Name, diff --git a/modules/convert/pull_test.go b/modules/convert/pull_test.go index 10ef311399a6..a6ccbaca5897 100644 --- a/modules/convert/pull_test.go +++ b/modules/convert/pull_test.go @@ -20,8 +20,8 @@ import ( func TestPullRequest_APIFormat(t *testing.T) { // with HeadRepo assert.NoError(t, unittest.PrepareTestDatabase()) - headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + headRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.NoError(t, pr.LoadAttributes()) assert.NoError(t, pr.LoadIssue()) apiPullRequest := ToAPIPullRequest(git.DefaultContext, pr, nil) @@ -35,7 +35,7 @@ func TestPullRequest_APIFormat(t *testing.T) { }, apiPullRequest.Head) // withOut HeadRepo - pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}).(*issues_model.PullRequest) + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}) assert.NoError(t, pr.LoadIssue()) assert.NoError(t, pr.LoadAttributes()) // simulate fork deletion diff --git a/modules/convert/user_test.go b/modules/convert/user_test.go index 2ed962950fff..89d912e460c5 100644 --- a/modules/convert/user_test.go +++ b/modules/convert/user_test.go @@ -17,13 +17,13 @@ import ( func TestUser_ToUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1, IsAdmin: true}).(*user_model.User) + user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1, IsAdmin: true}) apiUser := toUser(user1, true, true) assert.True(t, apiUser.IsAdmin) assert.Contains(t, apiUser.AvatarURL, "://") - user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2, IsAdmin: false}).(*user_model.User) + user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2, IsAdmin: false}) apiUser = toUser(user2, true, true) assert.False(t, apiUser.IsAdmin) @@ -32,7 +32,7 @@ func TestUser_ToUser(t *testing.T) { assert.False(t, apiUser.IsAdmin) assert.EqualValues(t, api.VisibleTypePublic.String(), apiUser.Visibility) - user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate}).(*user_model.User) + user31 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 31, IsAdmin: false, Visibility: api.VisibleTypePrivate}) apiUser = toUser(user31, true, true) assert.False(t, apiUser.IsAdmin) diff --git a/modules/doctor/doctor.go b/modules/doctor/doctor.go index c8975a788e12..5d14cef55c9f 100644 --- a/modules/doctor/doctor.go +++ b/modules/doctor/doctor.go @@ -11,6 +11,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" ) @@ -49,7 +50,11 @@ func initDBDisableConsole(ctx context.Context, disableConsole bool) error { setting.NewXORMLogService(disableConsole) if err := db.InitEngine(ctx); err != nil { - return fmt.Errorf("models.SetEngine: %v", err) + return fmt.Errorf("db.InitEngine: %w", err) + } + // some doctor sub-commands need to use git command + if err := git.InitFull(ctx); err != nil { + return fmt.Errorf("git.InitFull: %w", err) } return nil } diff --git a/modules/doctor/mergebase.go b/modules/doctor/mergebase.go index 2da91cdcc35f..46369290a13d 100644 --- a/modules/doctor/mergebase.go +++ b/modules/doctor/mergebase.go @@ -30,9 +30,6 @@ func iteratePRs(ctx context.Context, repo *repo_model.Repository, each func(*rep } func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) error { - if err := git.InitOnceWithSync(ctx); err != nil { - return err - } numRepos := 0 numPRs := 0 numPRsUpdated := 0 diff --git a/modules/doctor/misc.go b/modules/doctor/misc.go index 24175fcaf4be..2d2bcb910db4 100644 --- a/modules/doctor/misc.go +++ b/modules/doctor/misc.go @@ -190,10 +190,6 @@ func checkDaemonExport(ctx context.Context, logger log.Logger, autofix bool) err } func checkCommitGraph(ctx context.Context, logger log.Logger, autofix bool) error { - if err := git.InitOnceWithSync(ctx); err != nil { - return err - } - numRepos := 0 numNeedUpdate := 0 numWritten := 0 diff --git a/modules/git/command.go b/modules/git/command.go index a1bacbb707a2..b24d32dbe874 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -95,14 +95,15 @@ func (c *Command) AddArguments(args ...string) *Command { return c } -// RunOpts represents parameters to run the command +// RunOpts represents parameters to run the command. If UseContextTimeout is specified, then Timeout is ignored. type RunOpts struct { - Env []string - Timeout time.Duration - Dir string - Stdout, Stderr io.Writer - Stdin io.Reader - PipelineFunc func(context.Context, context.CancelFunc) error + Env []string + Timeout time.Duration + UseContextTimeout bool + Dir string + Stdout, Stderr io.Writer + Stdin io.Reader + PipelineFunc func(context.Context, context.CancelFunc) error } func commonBaseEnvs() []string { @@ -171,7 +172,15 @@ func (c *Command) Run(opts *RunOpts) error { desc = fmt.Sprintf("%s %s [repo_path: %s]", c.name, strings.Join(args, " "), opts.Dir) } - ctx, cancel, finished := process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc) + var ctx context.Context + var cancel context.CancelFunc + var finished context.CancelFunc + + if opts.UseContextTimeout { + ctx, cancel, finished = process.GetManager().AddContext(c.parentContext, desc) + } else { + ctx, cancel, finished = process.GetManager().AddContextTimeout(c.parentContext, opts.Timeout, desc) + } defer finished() cmd := exec.CommandContext(ctx, c.name, c.args...) diff --git a/modules/git/git.go b/modules/git/git.go index b8317396c015..99849f1f0945 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -15,7 +15,6 @@ import ( "regexp" "runtime" "strings" - "sync" "time" "code.gitea.io/gitea/modules/log" @@ -24,8 +23,8 @@ import ( "github.com/hashicorp/go-version" ) -// GitVersionRequired is the minimum Git version required -const GitVersionRequired = "2.0.0" +// RequiredVersion is the minimum Git version required +const RequiredVersion = "2.0.0" var ( // GitExecutable is the command name of git @@ -43,7 +42,7 @@ var ( // loadGitVersion returns current Git version from shell. Internal usage only. func loadGitVersion() (*version.Version, error) { - // doesn't need RWMutex because its exec by Init() + // doesn't need RWMutex because it's executed by Init() if gitVersion != nil { return gitVersion, nil } @@ -90,7 +89,7 @@ func SetExecutablePath(path string) error { return fmt.Errorf("unable to load git version: %w", err) } - versionRequired, err := version.NewVersion(GitVersionRequired) + versionRequired, err := version.NewVersion(RequiredVersion) if err != nil { return err } @@ -104,7 +103,7 @@ func SetExecutablePath(path string) error { moreHint = "get git: https://git-scm.com/download/linux and https://ius.io" } } - return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), GitVersionRequired, moreHint) + return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", gitVersion.Original(), RequiredVersion, moreHint) } return nil @@ -131,7 +130,7 @@ func checkInit() error { return errors.New("unable to init Git's HomeDir, incorrect initialization of the setting and git modules") } if DefaultContext != nil { - log.Warn("git module has been initialized already, duplicate init should be fixed") + log.Warn("git module has been initialized already, duplicate init may work but it's better to fix it") } return nil } @@ -140,7 +139,7 @@ func checkInit() error { func HomeDir() string { if setting.Git.HomePath == "" { // strict check, make sure the git module is initialized correctly. - // attention: when the git module is called in gitea sub-command (serv/hook), the log module is not able to show messages to users. + // attention: when the git module is called in gitea sub-command (serv/hook), the log module might not obviously show messages to users/developers. // for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons. log.Fatal("Unable to init Git's HomeDir, incorrect initialization of the setting and git modules") return "" @@ -149,14 +148,14 @@ func HomeDir() string { } // InitSimple initializes git module with a very simple step, no config changes, no global command arguments. -// This method doesn't change anything to filesystem. At the moment, it is only used by "git serv" sub-command, no data-race -// However, in integration test, the sub-command function may be called in the current process, so the InitSimple would be called multiple times, too +// This method doesn't change anything to filesystem. At the moment, it is only used by some Gitea sub-commands. func InitSimple(ctx context.Context) error { if err := checkInit(); err != nil { return err } DefaultContext = ctx + globalCommandArgs = nil if setting.Git.Timeout.Default > 0 { defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second @@ -165,46 +164,46 @@ func InitSimple(ctx context.Context) error { return SetExecutablePath(setting.Git.Path) } -var initOnce sync.Once - -// InitOnceWithSync initializes git module with version check and change global variables, sync gitconfig. -// This method will update the global variables ONLY ONCE (just like git.CheckLFSVersion -- which is not ideal too), -// otherwise there will be data-race problem at the moment. -func InitOnceWithSync(ctx context.Context) (err error) { +// InitFull initializes git module with version check and change global variables, sync gitconfig. +// It should only be called once at the beginning of the program initialization (TestMain/GlobalInitInstalled) as this code makes unsynchronized changes to variables. +func InitFull(ctx context.Context) (err error) { if err = checkInit(); err != nil { return err } - initOnce.Do(func() { - if err = InitSimple(ctx); err != nil { - return - } + if err = InitSimple(ctx); err != nil { + return + } - // when git works with gnupg (commit signing), there should be a stable home for gnupg commands - if _, ok := os.LookupEnv("GNUPGHOME"); !ok { - _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg")) - } + // when git works with gnupg (commit signing), there should be a stable home for gnupg commands + if _, ok := os.LookupEnv("GNUPGHOME"); !ok { + _ = os.Setenv("GNUPGHOME", filepath.Join(HomeDir(), ".gnupg")) + } - // Since git wire protocol has been released from git v2.18 - if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { - globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2") - } + // Since git wire protocol has been released from git v2.18 + if setting.Git.EnableAutoGitWireProtocol && CheckGitVersionAtLeast("2.18") == nil { + globalCommandArgs = append(globalCommandArgs, "-c", "protocol.version=2") + } - // By default partial clones are disabled, enable them from git v2.22 - if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { - globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true") - } + // By default partial clones are disabled, enable them from git v2.22 + if !setting.Git.DisablePartialClone && CheckGitVersionAtLeast("2.22") == nil { + globalCommandArgs = append(globalCommandArgs, "-c", "uploadpack.allowfilter=true", "-c", "uploadpack.allowAnySHA1InWant=true") + } - // Explicitly disable credential helper, otherwise Git credentials might leak - if CheckGitVersionAtLeast("2.9") == nil { - globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") - } + // Explicitly disable credential helper, otherwise Git credentials might leak + if CheckGitVersionAtLeast("2.9") == nil { + globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") + } - SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil - }) - if err != nil { - return err + SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil + + if setting.LFS.StartServer { + if CheckGitVersionAtLeast("2.1.2") != nil { + return errors.New("LFS server support requires Git >= 2.1.2") + } + globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") } + return syncGitConfig() } diff --git a/modules/git/git_test.go b/modules/git/git_test.go index c5a63de0644c..091573787871 100644 --- a/modules/git/git_test.go +++ b/modules/git/git_test.go @@ -28,7 +28,7 @@ func testRun(m *testing.M) error { defer util.RemoveAll(gitHomePath) setting.Git.HomePath = gitHomePath - if err = InitOnceWithSync(context.Background()); err != nil { + if err = InitFull(context.Background()); err != nil { return fmt.Errorf("failed to call Init: %w", err) } diff --git a/modules/git/lfs.go b/modules/git/lfs.go deleted file mode 100644 index c5d8354b6dc8..000000000000 --- a/modules/git/lfs.go +++ /dev/null @@ -1,31 +0,0 @@ -// 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 git - -import ( - "sync" - - logger "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/setting" -) - -var once sync.Once - -// CheckLFSVersion will check lfs version, if not satisfied, then disable it. -func CheckLFSVersion() { - if setting.LFS.StartServer { - // Disable LFS client hooks if installed for the current OS user - // Needs at least git v2.1.2 - if CheckGitVersionAtLeast("2.1.2") != nil { - setting.LFS.StartServer = false - logger.Error("LFS server support needs at least Git v2.1.2") - } else { - once.Do(func() { - globalCommandArgs = append(globalCommandArgs, "-c", "filter.lfs.required=", - "-c", "filter.lfs.smudge=", "-c", "filter.lfs.clean=") - }) - } - } -} diff --git a/modules/git/repo_commit.go b/modules/git/repo_commit.go index 7ff23af42eb8..d3731cb928e3 100644 --- a/modules/git/repo_commit.go +++ b/modules/git/repo_commit.go @@ -7,6 +7,8 @@ package git import ( "bytes" + "encoding/hex" + "fmt" "io" "strconv" "strings" @@ -209,9 +211,9 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) ( }() go func() { stderr := strings.Builder{} - err := NewCommand(repo.Ctx, "log", revision, "--follow", + err := NewCommand(repo.Ctx, "rev-list", revision, "--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize*page), - prettyLogFormat, "--", file). + "--skip="+strconv.Itoa(skip), "--", file). Run(&RunOpts{ Dir: repo.Path, Stdout: stdoutWriter, @@ -224,32 +226,30 @@ func (repo *Repository) CommitsByFileAndRange(revision, file string, page int) ( } }() - if skip > 0 { - _, err := io.CopyN(io.Discard, stdoutReader, int64(skip*41)) - if err != nil { + commits := []*Commit{} + shaline := [41]byte{} + var sha1 SHA1 + for { + n, err := io.ReadFull(stdoutReader, shaline[:]) + if err != nil || n < 40 { if err == io.EOF { - return []*Commit{}, nil + err = nil } - _ = stdoutReader.CloseWithError(err) + return commits, err + } + n, err = hex.Decode(sha1[:], shaline[0:40]) + if n != 20 { + err = fmt.Errorf("invalid sha %q", string(shaline[:40])) + } + if err != nil { return nil, err } + commit, err := repo.getCommit(sha1) + if err != nil { + return nil, err + } + commits = append(commits, commit) } - - stdout, err := io.ReadAll(stdoutReader) - if err != nil { - return nil, err - } - return repo.parsePrettyFormatLogToList(stdout) -} - -// CommitsByFileAndRangeNoFollow return the commits according revision file and the page -func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, page int) ([]*Commit, error) { - stdout, _, err := NewCommand(repo.Ctx, "log", revision, "--skip="+strconv.Itoa((page-1)*50), - "--max-count="+strconv.Itoa(setting.Git.CommitsRangeSize), prettyLogFormat, "--", file).RunStdBytes(&RunOpts{Dir: repo.Path}) - if err != nil { - return nil, err - } - return repo.parsePrettyFormatLogToList(stdout) } // FilesCountBetween return the number of files changed between two commits diff --git a/modules/graceful/net_unix.go b/modules/graceful/net_unix.go index 680ff529af88..c7524a79dbc9 100644 --- a/modules/graceful/net_unix.go +++ b/modules/graceful/net_unix.go @@ -23,6 +23,7 @@ import ( const ( listenFDs = "LISTEN_FDS" startFD = 3 + unlinkFDs = "GITEA_UNLINK_FDS" ) // In order to keep the working directory the same as when we started we record @@ -33,8 +34,10 @@ var ( once = sync.Once{} mutex = sync.Mutex{} - providedListeners = []net.Listener{} - activeListeners = []net.Listener{} + providedListenersToUnlink = []bool{} + activeListenersToUnlink = []bool{} + providedListeners = []net.Listener{} + activeListeners = []net.Listener{} ) func getProvidedFDs() (savedErr error) { @@ -53,6 +56,16 @@ func getProvidedFDs() (savedErr error) { return } + fdsToUnlinkStr := strings.Split(os.Getenv(unlinkFDs), ",") + providedListenersToUnlink = make([]bool, n) + for _, fdStr := range fdsToUnlinkStr { + i, err := strconv.Atoi(fdStr) + if err != nil || i < 0 || i >= n { + continue + } + providedListenersToUnlink[i] = true + } + for i := startFD; i < n+startFD; i++ { file := os.NewFile(uintptr(i), fmt.Sprintf("listener_FD%d", i)) @@ -136,8 +149,11 @@ func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, err for i, l := range providedListeners { if isSameAddr(l.Addr(), address) { providedListeners = append(providedListeners[:i], providedListeners[i+1:]...) + needsUnlink := providedListenersToUnlink[i] + providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...) activeListeners = append(activeListeners, l) + activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink) return l.(*net.TCPListener), nil } } @@ -148,6 +164,7 @@ func GetListenerTCP(network string, address *net.TCPAddr) (*net.TCPListener, err return nil, err } activeListeners = append(activeListeners, l) + activeListenersToUnlink = append(activeListenersToUnlink, false) return l, nil } @@ -166,9 +183,15 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener, for i, l := range providedListeners { if isSameAddr(l.Addr(), address) { providedListeners = append(providedListeners[:i], providedListeners[i+1:]...) + needsUnlink := providedListenersToUnlink[i] + providedListenersToUnlink = append(providedListenersToUnlink[:i], providedListenersToUnlink[i+1:]...) + + activeListenersToUnlink = append(activeListenersToUnlink, needsUnlink) activeListeners = append(activeListeners, l) unixListener := l.(*net.UnixListener) - unixListener.SetUnlinkOnClose(true) + if needsUnlink { + unixListener.SetUnlinkOnClose(true) + } return unixListener, nil } } @@ -189,6 +212,7 @@ func GetListenerUnix(network string, address *net.UnixAddr) (*net.UnixListener, } activeListeners = append(activeListeners, l) + activeListenersToUnlink = append(activeListenersToUnlink, true) return l, nil } @@ -223,3 +247,11 @@ func getActiveListeners() []net.Listener { copy(listeners, activeListeners) return listeners } + +func getActiveListenersToUnlink() []bool { + mutex.Lock() + defer mutex.Unlock() + listenersToUnlink := make([]bool, len(activeListenersToUnlink)) + copy(listenersToUnlink, activeListenersToUnlink) + return listenersToUnlink +} diff --git a/modules/graceful/restart_unix.go b/modules/graceful/restart_unix.go index 2654ddfb94d8..1d0d1059e9fd 100644 --- a/modules/graceful/restart_unix.go +++ b/modules/graceful/restart_unix.go @@ -12,6 +12,7 @@ import ( "net" "os" "os/exec" + "strconv" "strings" "sync" "syscall" @@ -75,6 +76,20 @@ func RestartProcess() (int, error) { } env = append(env, fmt.Sprintf("%s=%d", listenFDs, len(listeners))) + sb := &strings.Builder{} + for i, unlink := range getActiveListenersToUnlink() { + if !unlink { + continue + } + _, _ = sb.WriteString(strconv.Itoa(i)) + _, _ = sb.WriteString(",") + } + unlinkStr := sb.String() + if len(unlinkStr) > 0 { + unlinkStr = unlinkStr[:len(unlinkStr)-1] + env = append(env, fmt.Sprintf("%s=%s", unlinkFDs, unlinkStr)) + } + allFiles := append([]*os.File{os.Stdin, os.Stdout, os.Stderr}, files...) process, err := os.StartProcess(argv0, os.Args, &os.ProcAttr{ Dir: originalWD, diff --git a/modules/hostmatcher/hostmatcher.go b/modules/hostmatcher/hostmatcher.go index 81c4202fcd98..a092e07f411a 100644 --- a/modules/hostmatcher/hostmatcher.go +++ b/modules/hostmatcher/hostmatcher.go @@ -78,6 +78,11 @@ func (hl *HostMatchList) AppendBuiltin(builtin string) { hl.builtins = append(hl.builtins, builtin) } +// AppendPattern appends more pattern to match +func (hl *HostMatchList) AppendPattern(pattern string) { + hl.patterns = append(hl.patterns, pattern) +} + // IsEmpty checks if the checklist is empty func (hl *HostMatchList) IsEmpty() bool { return hl == nil || (len(hl.builtins) == 0 && len(hl.patterns) == 0 && len(hl.ipNets) == 0) diff --git a/modules/mcaptcha/mcaptcha.go b/modules/mcaptcha/mcaptcha.go new file mode 100644 index 000000000000..b889cf423b63 --- /dev/null +++ b/modules/mcaptcha/mcaptcha.go @@ -0,0 +1,27 @@ +// 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 mcaptcha + +import ( + "context" + "fmt" + + "code.gitea.io/gitea/modules/setting" + + "codeberg.org/gusted/mcaptcha" +) + +func Verify(ctx context.Context, token string) (bool, error) { + valid, err := mcaptcha.Verify(ctx, &mcaptcha.VerifyOpts{ + InstanceURL: setting.Service.McaptchaURL, + Sitekey: setting.Service.McaptchaSitekey, + Secret: setting.Service.McaptchaSecret, + Token: token, + }) + if err != nil { + return false, fmt.Errorf("wasn't able to verify mCaptcha: %v", err) + } + return valid, nil +} diff --git a/modules/notification/action/action_test.go b/modules/notification/action/action_test.go index 2898c8ec3de4..f6de0d675959 100644 --- a/modules/notification/action/action_test.go +++ b/modules/notification/action/action_test.go @@ -26,8 +26,8 @@ func TestMain(m *testing.M) { func TestRenameRepoAction(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: user.ID}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: user.ID}) repo.Owner = user oldRepoName := repo.Name diff --git a/modules/packages/content_store.go b/modules/packages/content_store.go index 64c3eedc2328..a3a5d1a6663c 100644 --- a/modules/packages/content_store.go +++ b/modules/packages/content_store.go @@ -27,21 +27,21 @@ func NewContentStore() *ContentStore { // Get gets a package blob func (s *ContentStore) Get(key BlobHash256Key) (storage.Object, error) { - return s.store.Open(keyToRelativePath(key)) + return s.store.Open(KeyToRelativePath(key)) } // 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) + _, err := s.store.Save(KeyToRelativePath(key), r, size) return err } // Delete deletes a package blob func (s *ContentStore) Delete(key BlobHash256Key) error { - return s.store.Delete(keyToRelativePath(key)) + return s.store.Delete(KeyToRelativePath(key)) } -// keyToRelativePath converts the sha256 key aabb000000... to aa/bb/aabb000000... -func keyToRelativePath(key BlobHash256Key) string { +// KeyToRelativePath converts the sha256 key aabb000000... to aa/bb/aabb000000... +func KeyToRelativePath(key BlobHash256Key) string { return path.Join(string(key)[0:2], string(key)[2:4], string(key)) } diff --git a/modules/packages/hashed_buffer_test.go b/modules/packages/hashed_buffer_test.go new file mode 100644 index 000000000000..e21ec67e1fed --- /dev/null +++ b/modules/packages/hashed_buffer_test.go @@ -0,0 +1,47 @@ +// 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 packages + +import ( + "fmt" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestHashedBuffer(t *testing.T) { + cases := []struct { + MaxMemorySize int + Data string + HashMD5 string + HashSHA1 string + HashSHA256 string + HashSHA512 string + }{ + {5, "test", "098f6bcd4621d373cade4e832627b4f6", "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"}, + {5, "testtest", "05a671c66aefea124cc08b76ea6d30bb", "51abb9636078defbf888d8457a7c76f85c8f114c", "37268335dd6931045bdcdf92623ff819a64244b53d0e746d438797349d4da578", "125d6d03b32c84d492747f79cf0bf6e179d287f341384eb5d6d3197525ad6be8e6df0116032935698f99a09e265073d1d6c32c274591bf1d0a20ad67cba921bc"}, + } + + for _, c := range cases { + buf, err := CreateHashedBufferFromReader(strings.NewReader(c.Data), c.MaxMemorySize) + assert.NoError(t, err) + + assert.EqualValues(t, len(c.Data), buf.Size()) + + data, err := io.ReadAll(buf) + assert.NoError(t, err) + assert.Equal(t, c.Data, string(data)) + + hashMD5, hashSHA1, hashSHA256, hashSHA512 := buf.Sums() + assert.Equal(t, c.HashMD5, fmt.Sprintf("%x", hashMD5)) + assert.Equal(t, c.HashSHA1, fmt.Sprintf("%x", hashSHA1)) + assert.Equal(t, c.HashSHA256, fmt.Sprintf("%x", hashSHA256)) + assert.Equal(t, c.HashSHA512, fmt.Sprintf("%x", hashSHA512)) + + assert.NoError(t, buf.Close()) + } +} diff --git a/modules/packages/pub/metadata.go b/modules/packages/pub/metadata.go new file mode 100644 index 000000000000..1fc4908b9121 --- /dev/null +++ b/modules/packages/pub/metadata.go @@ -0,0 +1,154 @@ +// 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 pub + +import ( + "archive/tar" + "compress/gzip" + "errors" + "io" + "regexp" + "strings" + + "code.gitea.io/gitea/modules/validation" + + "github.com/hashicorp/go-version" + "gopkg.in/yaml.v2" +) + +var ( + ErrMissingPubspecFile = errors.New("Pubspec file is missing") + ErrPubspecFileTooLarge = errors.New("Pubspec file is too large") + ErrInvalidName = errors.New("Package name is invalid") + ErrInvalidVersion = errors.New("Package version is invalid") +) + +var namePattern = regexp.MustCompile(`\A[a-zA-Z_][a-zA-Z0-9_]*\z`) + +// https://github.com/dart-lang/pub-dev/blob/4d582302a8d10152a5cd6129f65bf4f4dbca239d/pkg/pub_package_reader/lib/pub_package_reader.dart#L143 +const maxPubspecFileSize = 128 * 1024 + +// Package represents a Pub package +type Package struct { + Name string + Version string + Metadata *Metadata +} + +// Metadata represents the metadata of a Pub package +type Metadata struct { + Description string `json:"description,omitempty"` + ProjectURL string `json:"project_url,omitempty"` + RepositoryURL string `json:"repository_url,omitempty"` + DocumentationURL string `json:"documentation_url,omitempty"` + Readme string `json:"readme,omitempty"` + Pubspec interface{} `json:"pubspec"` +} + +type pubspecPackage struct { + Name string `yaml:"name"` + Version string `yaml:"version"` + Description string `yaml:"description"` + Homepage string `yaml:"homepage"` + Repository string `yaml:"repository"` + Documentation string `yaml:"documentation"` +} + +// ParsePackage parses the Pub package file +func ParsePackage(r io.Reader) (*Package, error) { + gzr, err := gzip.NewReader(r) + if err != nil { + return nil, err + } + defer gzr.Close() + + var p *Package + var readme string + + tr := tar.NewReader(gzr) + for { + hd, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + + if hd.Typeflag != tar.TypeReg { + continue + } + + if hd.Name == "pubspec.yaml" { + if hd.Size > maxPubspecFileSize { + return nil, ErrPubspecFileTooLarge + } + p, err = ParsePubspecMetadata(tr) + if err != nil { + return nil, err + } + } else if strings.ToLower(hd.Name) == "readme.md" { + data, err := io.ReadAll(tr) + if err != nil { + return nil, err + } + readme = string(data) + } + } + + if p == nil { + return nil, ErrMissingPubspecFile + } + + p.Metadata.Readme = readme + + return p, nil +} + +// ParsePubspecMetadata parses a Pubspec file to retrieve the metadata of a Pub package +func ParsePubspecMetadata(r io.Reader) (*Package, error) { + buf, err := io.ReadAll(io.LimitReader(r, maxPubspecFileSize)) + if err != nil { + return nil, err + } + + var p pubspecPackage + if err := yaml.Unmarshal(buf, &p); err != nil { + return nil, err + } + + if !namePattern.MatchString(p.Name) { + return nil, ErrInvalidName + } + + v, err := version.NewSemver(p.Version) + if err != nil { + return nil, ErrInvalidVersion + } + + if !validation.IsValidURL(p.Homepage) { + p.Homepage = "" + } + if !validation.IsValidURL(p.Repository) { + p.Repository = "" + } + + var pubspec interface{} + if err := yaml.Unmarshal(buf, &pubspec); err != nil { + return nil, err + } + + return &Package{ + Name: p.Name, + Version: v.String(), + Metadata: &Metadata{ + Description: p.Description, + ProjectURL: p.Homepage, + RepositoryURL: p.Repository, + DocumentationURL: p.Documentation, + Pubspec: pubspec, + }, + }, nil +} diff --git a/modules/packages/pub/metadata_test.go b/modules/packages/pub/metadata_test.go new file mode 100644 index 000000000000..e43ed64fc6cd --- /dev/null +++ b/modules/packages/pub/metadata_test.go @@ -0,0 +1,136 @@ +// 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 pub + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "io" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +const ( + packageName = "gitea" + packageVersion = "1.0.1" + description = "Package Description" + projectURL = "https://gitea.io" + repositoryURL = "https://gitea.io/gitea/gitea" + documentationURL = "https://docs.gitea.io" +) + +const pubspecContent = `name: ` + packageName + ` +version: ` + packageVersion + ` +description: ` + description + ` +homepage: ` + projectURL + ` +repository: ` + repositoryURL + ` +documentation: ` + documentationURL + ` + +environment: + sdk: '>=2.16.0 <3.0.0' + +dependencies: + flutter: + sdk: flutter + path: '>=1.8.0 <3.0.0' + +dev_dependencies: + http: '>=0.13.0'` + +func TestParsePackage(t *testing.T) { + createArchive := func(files map[string][]byte) io.Reader { + var buf bytes.Buffer + zw := gzip.NewWriter(&buf) + tw := tar.NewWriter(zw) + for filename, content := range files { + hdr := &tar.Header{ + Name: filename, + Mode: 0o600, + Size: int64(len(content)), + } + tw.WriteHeader(hdr) + tw.Write(content) + } + tw.Close() + zw.Close() + return &buf + } + + t.Run("MissingPubspecFile", func(t *testing.T) { + data := createArchive(map[string][]byte{"dummy.txt": {}}) + + pp, err := ParsePackage(data) + assert.Nil(t, pp) + assert.ErrorIs(t, err, ErrMissingPubspecFile) + }) + + t.Run("PubspecFileTooLarge", func(t *testing.T) { + data := createArchive(map[string][]byte{"pubspec.yaml": make([]byte, 200*1024)}) + + pp, err := ParsePackage(data) + assert.Nil(t, pp) + assert.ErrorIs(t, err, ErrPubspecFileTooLarge) + }) + + t.Run("InvalidPubspecFile", func(t *testing.T) { + data := createArchive(map[string][]byte{"pubspec.yaml": {}}) + + pp, err := ParsePackage(data) + assert.Nil(t, pp) + assert.Error(t, err) + }) + + t.Run("Valid", func(t *testing.T) { + data := createArchive(map[string][]byte{"pubspec.yaml": []byte(pubspecContent)}) + + pp, err := ParsePackage(data) + assert.NoError(t, err) + assert.NotNil(t, pp) + assert.Empty(t, pp.Metadata.Readme) + }) + + t.Run("ValidWithReadme", func(t *testing.T) { + data := createArchive(map[string][]byte{"pubspec.yaml": []byte(pubspecContent), "README.md": []byte("readme")}) + + pp, err := ParsePackage(data) + assert.NoError(t, err) + assert.NotNil(t, pp) + assert.Equal(t, "readme", pp.Metadata.Readme) + }) +} + +func TestParsePubspecMetadata(t *testing.T) { + t.Run("InvalidName", func(t *testing.T) { + for _, name := range []string{"123abc", "ab-cd"} { + pp, err := ParsePubspecMetadata(strings.NewReader(`name: ` + name)) + assert.Nil(t, pp) + assert.ErrorIs(t, err, ErrInvalidName) + } + }) + + t.Run("InvalidVersion", func(t *testing.T) { + pp, err := ParsePubspecMetadata(strings.NewReader(`name: dummy +version: invalid`)) + assert.Nil(t, pp) + assert.ErrorIs(t, err, ErrInvalidVersion) + }) + + t.Run("Valid", func(t *testing.T) { + pp, err := ParsePubspecMetadata(strings.NewReader(pubspecContent)) + assert.NoError(t, err) + assert.NotNil(t, pp) + + assert.Equal(t, packageName, pp.Name) + assert.Equal(t, packageVersion, pp.Version) + assert.Equal(t, description, pp.Metadata.Description) + assert.Equal(t, projectURL, pp.Metadata.ProjectURL) + assert.Equal(t, repositoryURL, pp.Metadata.RepositoryURL) + assert.Equal(t, documentationURL, pp.Metadata.DocumentationURL) + assert.NotNil(t, pp.Metadata.Pubspec) + }) +} diff --git a/modules/repository/commits_test.go b/modules/repository/commits_test.go index 37181d2dcd0d..c62e324b66fe 100644 --- a/modules/repository/commits_test.go +++ b/modules/repository/commits_test.go @@ -49,7 +49,7 @@ func TestPushCommits_ToAPIPayloadCommits(t *testing.T) { } pushCommits.HeadCommit = &PushCommit{Sha1: "69554a6"} - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 16}) payloadCommits, headCommit, err := pushCommits.ToAPIPayloadCommits(git.DefaultContext, repo.RepoPath(), "/user2/repo16") assert.NoError(t, err) assert.Len(t, payloadCommits, 3) diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go index 2a47e9363149..39f8b11356de 100644 --- a/modules/repository/create_test.go +++ b/modules/repository/create_test.go @@ -24,7 +24,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testTeamRepositories := func(teamID int64, repoIds []int64) { - team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}).(*organization.Team) + team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) assert.NoError(t, team.GetRepositoriesCtx(db.DefaultContext), "%s: GetRepositories", team.Name) assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name) assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name) diff --git a/modules/repository/hooks.go b/modules/repository/hooks.go index c2eb3a7c75f7..7bc77552bd05 100644 --- a/modules/repository/hooks.go +++ b/modules/repository/hooks.go @@ -8,6 +8,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" @@ -153,6 +154,10 @@ func createDelegateHooks(repoPath string) (err error) { } func checkExecutable(filename string) bool { + // windows has no concept of a executable bit + if runtime.GOOS == "windows" { + return true + } fileInfo, err := os.Stat(filename) if err != nil { return false diff --git a/modules/setting/service.go b/modules/setting/service.go index bd97e10b0f0d..10e389995032 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -38,6 +38,7 @@ var Service = struct { EnableReverseProxyAuth bool EnableReverseProxyAutoRegister bool EnableReverseProxyEmail bool + EnableReverseProxyFullName bool EnableCaptcha bool RequireExternalRegistrationCaptcha bool RequireExternalRegistrationPassword bool @@ -47,6 +48,9 @@ var Service = struct { RecaptchaURL string HcaptchaSecret string HcaptchaSitekey string + McaptchaSecret string + McaptchaSitekey string + McaptchaURL string DefaultKeepEmailPrivate bool DefaultAllowCreateOrganization bool DefaultUserIsRestricted bool @@ -124,6 +128,7 @@ func newService() { Service.EnableReverseProxyAuth = sec.Key("ENABLE_REVERSE_PROXY_AUTHENTICATION").MustBool() Service.EnableReverseProxyAutoRegister = sec.Key("ENABLE_REVERSE_PROXY_AUTO_REGISTRATION").MustBool() Service.EnableReverseProxyEmail = sec.Key("ENABLE_REVERSE_PROXY_EMAIL").MustBool() + Service.EnableReverseProxyFullName = sec.Key("ENABLE_REVERSE_PROXY_FULL_NAME").MustBool() Service.EnableCaptcha = sec.Key("ENABLE_CAPTCHA").MustBool(false) Service.RequireExternalRegistrationCaptcha = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_CAPTCHA").MustBool(Service.EnableCaptcha) Service.RequireExternalRegistrationPassword = sec.Key("REQUIRE_EXTERNAL_REGISTRATION_PASSWORD").MustBool() @@ -133,6 +138,9 @@ func newService() { Service.RecaptchaURL = sec.Key("RECAPTCHA_URL").MustString("https://www.google.com/recaptcha/") Service.HcaptchaSecret = sec.Key("HCAPTCHA_SECRET").MustString("") Service.HcaptchaSitekey = sec.Key("HCAPTCHA_SITEKEY").MustString("") + Service.McaptchaURL = sec.Key("MCAPTCHA_URL").MustString("https://demo.mcaptcha.org/") + Service.McaptchaSecret = sec.Key("MCAPTCHA_SECRET").MustString("") + Service.McaptchaSitekey = sec.Key("MCAPTCHA_SITEKEY").MustString("") Service.DefaultKeepEmailPrivate = sec.Key("DEFAULT_KEEP_EMAIL_PRIVATE").MustBool() Service.DefaultAllowCreateOrganization = sec.Key("DEFAULT_ALLOW_CREATE_ORGANIZATION").MustBool(true) Service.DefaultUserIsRestricted = sec.Key("DEFAULT_USER_IS_RESTRICTED").MustBool(false) diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 23e3280dc9f1..3ab25fef6ea8 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -59,6 +59,7 @@ const ( ImageCaptcha = "image" ReCaptcha = "recaptcha" HCaptcha = "hcaptcha" + MCaptcha = "mcaptcha" ) // settings @@ -185,6 +186,7 @@ var ( CookieRememberName string ReverseProxyAuthUser string ReverseProxyAuthEmail string + ReverseProxyAuthFullName string ReverseProxyLimit int ReverseProxyTrustedProxies []string MinPasswordLength int @@ -262,8 +264,8 @@ var ( }{ ExplorePagingNum: 20, SitemapPagingNum: 20, - IssuePagingNum: 10, - RepoSearchPagingNum: 10, + IssuePagingNum: 20, + RepoSearchPagingNum: 20, MembersPagingNum: 20, FeedMaxCommitNum: 5, FeedPagingNum: 20, @@ -908,6 +910,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") ReverseProxyAuthEmail = sec.Key("REVERSE_PROXY_AUTHENTICATION_EMAIL").MustString("X-WEBAUTH-EMAIL") + ReverseProxyAuthFullName = sec.Key("REVERSE_PROXY_AUTHENTICATION_FULL_NAME").MustString("X-WEBAUTH-FULLNAME") ReverseProxyLimit = sec.Key("REVERSE_PROXY_LIMIT").MustInt(1) ReverseProxyTrustedProxies = sec.Key("REVERSE_PROXY_TRUSTED_PROXIES").Strings(",") diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index bffe29f4c385..6b601c008fe9 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -75,11 +75,20 @@ func sessionHandler(session ssh.Session) { ctx, cancel := context.WithCancel(session.Context()) defer cancel() + gitProtocol := "" + for _, env := range session.Environ() { + if strings.HasPrefix(env, "GIT_PROTOCOL=") { + _, gitProtocol, _ = strings.Cut(env, "=") + break + } + } + cmd := exec.CommandContext(ctx, setting.AppPath, args...) cmd.Env = append( os.Environ(), "SSH_ORIGINAL_COMMAND="+command, "SKIP_MINWINSVC=1", + "GIT_PROTOCOL="+gitProtocol, ) stdout, err := cmd.StdoutPipe() diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 8a15cec2c68a..602afec4135f 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -972,11 +972,11 @@ type remoteAddress struct { Password string } -func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string) remoteAddress { +func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteName string, ignoreOriginalURL bool) remoteAddress { a := remoteAddress{} remoteURL := m.OriginalURL - if remoteURL == "" { + if ignoreOriginalURL || remoteURL == "" { var err error remoteURL, err = git.GetRemoteAddress(ctx, m.RepoPath(), remoteName) if err != nil { diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index a08439e93f4c..963f79c3c6b1 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -56,7 +56,7 @@ func MockContext(t *testing.T, path string) *context.Context { // LoadRepo load a repo into a test context. func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) { ctx.Repo = &context.Repository{} - ctx.Repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + ctx.Repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) var err error ctx.Repo.Owner, err = user_model.GetUserByID(ctx.Repo.Repository.OwnerID) assert.NoError(t, err) @@ -81,7 +81,7 @@ func LoadRepoCommit(t *testing.T, ctx *context.Context) { // LoadUser load a user into a test context. func LoadUser(t *testing.T, ctx *context.Context, userID int64) { - ctx.Doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}).(*user_model.User) + ctx.Doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) } // LoadGitRepo load a git repo into a test context. Requires that ctx.Repo has diff --git a/modules/timeutil/since.go b/modules/timeutil/since.go index 5e89b0faa29a..8473d450510c 100644 --- a/modules/timeutil/since.go +++ b/modules/timeutil/since.go @@ -234,7 +234,7 @@ func TimeSince(then time.Time, lang translation.Locale) template.HTML { } func htmlTimeSince(then, now time.Time, lang translation.Locale) template.HTML { - return template.HTML(fmt.Sprintf(`%s`, + return template.HTML(fmt.Sprintf(`%s`, then.In(setting.DefaultUILocation).Format(GetTimeFormat(lang.Language())), timeSince(then, now, lang))) } @@ -245,7 +245,7 @@ func TimeSinceUnix(then TimeStamp, lang translation.Locale) template.HTML { } func htmlTimeSinceUnix(then, now TimeStamp, lang translation.Locale) template.HTML { - return template.HTML(fmt.Sprintf(`%s`, + return template.HTML(fmt.Sprintf(`%s`, then.FormatInLocation(GetTimeFormat(lang.Language()), setting.DefaultUILocation), timeSinceUnix(int64(then), int64(now), lang))) } diff --git a/modules/timeutil/since_test.go b/modules/timeutil/since_test.go index 8bdb9d7546a3..dfcf9cb01d98 100644 --- a/modules/timeutil/since_test.go +++ b/modules/timeutil/since_test.go @@ -119,7 +119,7 @@ func TestHtmlTimeSince(t *testing.T) { // test that `diff` yields a result containing `expected` test := func(expected string, diff time.Duration) { actual := htmlTimeSince(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US")) - assert.Contains(t, actual, `title="Sat Jan 1 00:00:00 UTC 2000"`) + assert.Contains(t, actual, `data-content="Sat Jan 1 00:00:00 UTC 2000"`) assert.Contains(t, actual, expected) } test("1 second", time.Second) diff --git a/modules/util/filebuffer/file_backed_buffer.go b/modules/util/filebuffer/file_backed_buffer.go index 128030b4c5c1..8e3e138e04b7 100644 --- a/modules/util/filebuffer/file_backed_buffer.go +++ b/modules/util/filebuffer/file_backed_buffer.go @@ -103,35 +103,45 @@ func (b *FileBackedBuffer) Size() int64 { return b.size } -func (b *FileBackedBuffer) switchToReader() { +func (b *FileBackedBuffer) switchToReader() error { if b.reader != nil { - return + return nil } if b.file != nil { + if _, err := b.file.Seek(0, io.SeekStart); err != nil { + return err + } b.reader = b.file } else { b.reader = bytes.NewReader(b.buffer.Bytes()) } + return nil } // Read implements io.Reader func (b *FileBackedBuffer) Read(p []byte) (int, error) { - b.switchToReader() + if err := b.switchToReader(); err != nil { + return 0, err + } return b.reader.Read(p) } // ReadAt implements io.ReaderAt func (b *FileBackedBuffer) ReadAt(p []byte, off int64) (int, error) { - b.switchToReader() + if err := b.switchToReader(); err != nil { + return 0, err + } return b.reader.ReadAt(p, off) } // Seek implements io.Seeker func (b *FileBackedBuffer) Seek(offset int64, whence int) (int64, error) { - b.switchToReader() + if err := b.switchToReader(); err != nil { + return 0, err + } return b.reader.Seek(offset, whence) } diff --git a/modules/util/filebuffer/file_backed_buffer_test.go b/modules/util/filebuffer/file_backed_buffer_test.go new file mode 100644 index 000000000000..83ef58561de5 --- /dev/null +++ b/modules/util/filebuffer/file_backed_buffer_test.go @@ -0,0 +1,36 @@ +// 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 filebuffer + +import ( + "io" + "strings" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestFileBackedBuffer(t *testing.T) { + cases := []struct { + MaxMemorySize int + Data string + }{ + {5, "test"}, + {5, "testtest"}, + } + + for _, c := range cases { + buf, err := CreateFromReader(strings.NewReader(c.Data), c.MaxMemorySize) + assert.NoError(t, err) + + assert.EqualValues(t, len(c.Data), buf.Size()) + + data, err := io.ReadAll(buf) + assert.NoError(t, err) + assert.Equal(t, c.Data, string(data)) + + assert.NoError(t, buf.Close()) + } +} diff --git a/modules/util/sec_to_time.go b/modules/util/sec_to_time.go index 9ce6fe1a13eb..13461915e6f3 100644 --- a/modules/util/sec_to_time.go +++ b/modules/util/sec_to_time.go @@ -18,10 +18,22 @@ import ( // 45677465s -> 1 year 6 months func SecToTime(duration int64) string { formattedTime := "" - years := duration / (3600 * 24 * 7 * 4 * 12) - months := (duration / (3600 * 24 * 30)) % 12 - weeks := (duration / (3600 * 24 * 7)) % 4 - days := (duration / (3600 * 24)) % 7 + + // The following four variables are calculated by taking + // into account the previously calculated variables, this avoids + // pitfalls when using remainders. As that could lead to incorrect + // results when the calculated number equals the quotient number. + remainingDays := duration / (60 * 60 * 24) + years := remainingDays / 365 + remainingDays -= years * 365 + months := remainingDays * 12 / 365 + remainingDays -= months * 365 / 12 + weeks := remainingDays / 7 + remainingDays -= weeks * 7 + days := remainingDays + + // The following three variables are calculated without depending + // on the previous calculated variables. hours := (duration / 3600) % 24 minutes := (duration / 60) % 60 seconds := duration % 60 diff --git a/modules/util/sec_to_time_test.go b/modules/util/sec_to_time_test.go index 854190462bc3..1e256aa8650c 100644 --- a/modules/util/sec_to_time_test.go +++ b/modules/util/sec_to_time_test.go @@ -11,10 +11,21 @@ import ( ) func TestSecToTime(t *testing.T) { - assert.Equal(t, SecToTime(66), "1 minute 6 seconds") - assert.Equal(t, SecToTime(52410), "14 hours 33 minutes") - assert.Equal(t, SecToTime(563418), "6 days 12 hours") - assert.Equal(t, SecToTime(1563418), "2 weeks 4 days") - assert.Equal(t, SecToTime(3937125), "1 month 2 weeks") - assert.Equal(t, SecToTime(45677465), "1 year 5 months") + second := int64(1) + minute := 60 * second + hour := 60 * minute + day := 24 * hour + year := 365 * day + + assert.Equal(t, "1 minute 6 seconds", SecToTime(minute+6*second)) + assert.Equal(t, "1 hour", SecToTime(hour)) + assert.Equal(t, "1 hour", SecToTime(hour+second)) + assert.Equal(t, "14 hours 33 minutes", SecToTime(14*hour+33*minute+30*second)) + assert.Equal(t, "6 days 12 hours", SecToTime(6*day+12*hour+30*minute+18*second)) + assert.Equal(t, "2 weeks 4 days", SecToTime((2*7+4)*day+2*hour+16*minute+58*second)) + assert.Equal(t, "4 weeks", SecToTime(4*7*day)) + assert.Equal(t, "4 weeks 1 day", SecToTime((4*7+1)*day)) + assert.Equal(t, "1 month 2 weeks", SecToTime((6*7+3)*day+13*hour+38*minute+45*second)) + assert.Equal(t, "11 months", SecToTime(year-25*day)) + assert.Equal(t, "1 year 5 months", SecToTime(year+163*day+10*hour+11*minute+5*second)) } diff --git a/modules/web/middleware/binding.go b/modules/web/middleware/binding.go index 88a3920f6e67..636e655b9e95 100644 --- a/modules/web/middleware/binding.go +++ b/modules/web/middleware/binding.go @@ -136,7 +136,16 @@ func Validate(errs binding.Errors, data map[string]interface{}, f Form, l transl case validation.ErrRegexPattern: data["ErrorMsg"] = trName + l.Tr("form.regex_pattern_error", errs[0].Message) default: - data["ErrorMsg"] = l.Tr("form.unknown_error") + " " + errs[0].Classification + msg := errs[0].Classification + if msg != "" && errs[0].Message != "" { + msg += ": " + } + + msg += errs[0].Message + if msg == "" { + msg = l.Tr("form.unknown_error") + } + data["ErrorMsg"] = trName + ": " + msg } return errs } diff --git a/options/license/CC-BY-3.0-IGO b/options/license/CC-BY-3.0-IGO new file mode 100644 index 000000000000..13ab9536e179 --- /dev/null +++ b/options/license/CC-BY-3.0-IGO @@ -0,0 +1,101 @@ +Creative Commons Attribution 3.0 IGO + +CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE. THE LICENSOR IS NOT NECESSARILY AN INTERGOVERNMENTAL ORGANIZATION (IGO), AS DEFINED IN THE LICENSE BELOW. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE COMMONS PUBLIC LICENSE ("LICENSE"). THE LICENSOR (DEFINED BELOW) HOLDS COPYRIGHT AND OTHER RIGHTS IN THE WORK. ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE IN CONSIDERATION FOR YOUR ACCEPTANCE AND AGREEMENT TO THE TERMS OF THE LICENSE. + +1. Definitions + + a. "IGO" means, solely and exclusively for purposes of this License, an organization established by a treaty or other instrument governed by international law and possessing its own international legal personality. Other organizations established to carry out activities across national borders and that accordingly enjoy immunity from legal process are also IGOs for the sole and exclusive purposes of this License. IGOs may include as members, in addition to states, other entities. + + b. "Work" means the literary and/or artistic work eligible for copyright protection, whatever may be the mode or form of its expression including digital form, and offered under the terms of this License. It is understood that a database, which by reason of the selection and arrangement of its contents constitutes an intellectual creation, is considered a Work. + + c. "Licensor" means the individual, individuals, entity or entities that offer(s) the Work under the terms of this License and may be, but is not necessarily, an IGO. + + d. "You" means an individual or entity exercising rights under this License. + + e. "Reproduce" means to make a copy of the Work in any manner or form, and by any means. + + f. "Distribute" means the activity of making publicly available the Work or Adaptation (or copies of the Work or Adaptation), as applicable, by sale, rental, public lending or any other known form of transfer of ownership or possession of the Work or copy of the Work. + + g. "Publicly Perform" means to perform public recitations of the Work and to communicate to the public those public recitations, by any means or process, including by wire or wireless means or public digital performances; to make available to the public Works in such a way that members of the public may access these Works from a place and at a place individually chosen by them; to perform the Work to the public by any means or process and the communication to the public of the performances of the Work, including by public digital performance; to broadcast and rebroadcast the Work by any means including signs, sounds or images. + + h. "Adaptation" means a work derived from or based upon the Work, or upon the Work and other pre-existing works. Adaptations may include works such as translations, derivative works, or any alterations and arrangements of any kind involving the Work. For purposes of this License, where the Work is a musical work, performance, or phonogram, the synchronization of the Work in timed-relation with a moving image is an Adaptation. For the avoidance of doubt, including the Work in a Collection is not an Adaptation. + + i. "Collection" means a collection of literary or artistic works or other works or subject matter other than works listed in Section 1(b) which by reason of the selection and arrangement of their contents, constitute intellectual creations, in which the Work is included in its entirety in unmodified form along with one or more other contributions, each constituting separate and independent works in themselves, which together are assembled into a collective whole. For the avoidance of doubt, a Collection will not be considered as an Adaptation. + +2. Scope of this License. Nothing in this License is intended to reduce, limit, or restrict any uses free from copyright protection. + +3. License Grant. Subject to the terms and conditions of this License, the Licensor hereby grants You a worldwide, royalty-free, non-exclusive license to exercise the rights in the Work as follows: + + a. to Reproduce, Distribute and Publicly Perform the Work, to incorporate the Work into one or more Collections, and to Reproduce, Distribute and Publicly Perform the Work as incorporated in the Collections; and, + + b. to create, Reproduce, Distribute and Publicly Perform Adaptations, provided that You clearly label, demarcate or otherwise identify that changes were made to the original Work. + + c. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme cannot be waived, the Licensor reserves the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; + + ii. Waivable Compulsory License Schemes. In those jurisdictions in which the right to collect royalties through any statutory or compulsory licensing scheme can be waived, the Licensor waives the exclusive right to collect such royalties for any exercise by You of the rights granted under this License; and, + + iii. Voluntary License Schemes. To the extent possible, the Licensor waives the right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary licensing scheme. + +This License lasts for the duration of the term of the copyright in the Work licensed by the Licensor. The above rights may be exercised in all media and formats whether now known or hereafter devised. The above rights include the right to make such modifications as are technically necessary to exercise the rights in other media and formats. All rights not expressly granted by the Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms of this License. You must include a copy of, or the Uniform Resource Identifier (URI) for, this License with every copy of the Work You Distribute or Publicly Perform. You may not offer or impose any terms on the Work that restrict the terms of this License or the ability of the recipient of the Work to exercise the rights granted to that recipient under the terms of the License. You may not sublicense the Work (see section 8(a)). You must keep intact all notices that refer to this License and to the disclaimer of warranties with every copy of the Work You Distribute or Publicly Perform. When You Distribute or Publicly Perform the Work, You may not impose any effective technological measures on the Work that restrict the ability of a recipient of the Work from You to exercise the rights granted to that recipient under the terms of the License. This Section 4(a) applies to the Work as incorporated in a Collection, but this does not require the Collection apart from the Work itself to be made subject to the terms of this License. If You create a Collection, upon notice from a Licensor You must, to the extent practicable, remove from the Collection any credit (inclusive of any logo, trademark, official mark or official emblem) as required by Section 4(b), as requested. If You create an Adaptation, upon notice from a Licensor You must, to the extent practicable, remove from the Adaptation any credit (inclusive of any logo, trademark, official mark or official emblem) as required by Section 4(b), as requested. + + b. If You Distribute, or Publicly Perform the Work or any Adaptations or Collections, You must, unless a request has been made pursuant to Section 4(a), keep intact all copyright notices for the Work and provide, reasonable to the medium or means You are utilizing: (i) any attributions that the Licensor indicates be associated with the Work as indicated in a copyright notice, (ii) the title of the Work if supplied; (iii) to the extent reasonably practicable, the URI, if any, that the Licensor specifies to be associated with the Work, unless such URI does not refer to the copyright notice or licensing information for the Work; and, (iv) consistent with Section 3(b), in the case of an Adaptation, a credit identifying the use of the Work in the Adaptation. The credit required by this Section 4(b) may be implemented in any reasonable manner; provided, however, that in the case of an Adaptation or Collection, at a minimum such credit will appear, if a credit for all contributors to the Adaptation or Collection appears, then as part of these credits and in a manner at least as prominent as the credits for the other contributors. For the avoidance of doubt, You may only use the credit required by this Section for the purpose of attribution in the manner set out above and, by exercising Your rights under this License, You may not implicitly or explicitly assert or imply any connection with, sponsorship or endorsement by the Licensor or others designated for attribution, of You or Your use of the Work, without the separate, express prior written permission of the Licensor or such others. + + c. Except as otherwise agreed in writing by the Licensor, if You Reproduce, Distribute or Publicly Perform the Work either by itself or as part of any Adaptations or Collections, You must not distort, mutilate, modify or take other derogatory action in relation to the Work which would be prejudicial to the honor or reputation of the Licensor where moral rights apply. + +5. Representations, Warranties and Disclaimer + +THE LICENSOR OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ERRORS, WHETHER OR NOT DISCOVERABLE. + +6. Limitation on Liability + +IN NO EVENT WILL THE LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF THE LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. Subject to the terms and conditions set forth in this License, the license granted here lasts for the duration of the term of the copyright in the Work licensed by the Licensor as stated in Section 3. Notwithstanding the above, the Licensor reserves the right to release the Work under different license terms or to stop distributing the Work at any time; provided, however that any such election will not serve to withdraw this License (or any other license that has been, or is required to be, granted under the terms of this License), and this License will continue in full force and effect unless terminated as stated below. + + b. If You fail to comply with this License, then this License and the rights granted hereunder will terminate automatically upon any breach by You of the terms of this License. Individuals or entities who have received Adaptations or Collections from You under this License, however, will not have their licenses terminated provided such individuals or entities remain in full compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will survive any termination of this License. Notwithstanding the foregoing, this License reinstates automatically as of the date the violation is cured, provided it is cured within 30 days of You discovering the violation, or upon express reinstatement by the Licensor. For the avoidance of doubt, this Section 7(b) does not affect any rights the Licensor may have to seek remedies for violations of this License by You. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, the Licensor offers to the recipient a license to the Work on the same terms and conditions as the license granted to You under this License. + + b. Each time You Distribute or Publicly Perform an Adaptation, the Licensor offers to the recipient a license to the original Work on the same terms and conditions as the license granted to You under this License. + + c. If any provision of this License is invalid or unenforceable, it shall not affect the validity or enforceability of the remainder of the terms of this License, and without further action, such provision shall be reformed to the minimum extent necessary to make such provision valid and enforceable. + + d. No term or provision of this License shall be deemed waived and no breach consented to unless such waiver or consent shall be in writing and signed by the Licensor. + + e. This License constitutes the entire agreement between You and the Licensor with respect to the Work licensed here. There are no understandings, agreements or representations with respect to the Work not specified here. The Licensor shall not be bound by any additional provisions that may appear in any communication from You. This License may not be modified without the mutual written agreement of the Licensor and You. + + f. The rights granted under, and the subject matter referenced, in this License were drafted utilizing the terminology of the Berne Convention for the Protection of Literary and Artistic Works (as amended on September 28, 1979), the Rome Convention of 1961, the WIPO Copyright Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and the Universal Copyright Convention (as revised on July 24, 1971). Interpretation of the scope of the rights granted by the Licensor and the conditions imposed on You under this License, this License, and the rights and conditions set forth herein shall be made with reference to copyright as determined in accordance with general principles of international law, including the above mentioned conventions. + + g. Nothing in this License constitutes or may be interpreted as a limitation upon or waiver of any privileges and immunities that may apply to the Licensor or You, including immunity from the legal processes of any jurisdiction, national court or other authority. + + h. Where the Licensor is an IGO, any and all disputes arising under this License that cannot be settled amicably shall be resolved in accordance with the following procedure: + + i. Pursuant to a notice of mediation communicated by reasonable means by either You or the Licensor to the other, the dispute shall be submitted to non-binding mediation conducted in accordance with rules designated by the Licensor in the copyright notice published with the Work, or if none then in accordance with those communicated in the notice of mediation. The language used in the mediation proceedings shall be English unless otherwise agreed. + + ii. If any such dispute has not been settled within 45 days following the date on which the notice of mediation is provided, either You or the Licensor may, pursuant to a notice of arbitration communicated by reasonable means to the other, elect to have the dispute referred to and finally determined by arbitration. The arbitration shall be conducted in accordance with the rules designated by the Licensor in the copyright notice published with the Work, or if none then in accordance with the UNCITRAL Arbitration Rules as then in force. The arbitral tribunal shall consist of a sole arbitrator and the language of the proceedings shall be English unless otherwise agreed. The place of arbitration shall be where the Licensor has its headquarters. The arbitral proceedings shall be conducted remotely (e.g., via telephone conference or written submissions) whenever practicable. + + iii. Interpretation of this License in any dispute submitted to mediation or arbitration shall be as set forth in Section 8(f), above. + +Creative Commons Notice + +Creative Commons is not a party to this License, and makes no warranty whatsoever in connection with the Work. Creative Commons will not be liable to You or any party on any legal theory for any damages whatsoever, including without limitation any general, special, incidental or consequential damages arising in connection to this license. Notwithstanding the foregoing two (2) sentences, if Creative Commons has expressly identified itself as the Licensor hereunder, it shall have all rights and obligations of the Licensor. + +Except for the limited purpose of indicating to the public that the Work is licensed under the CCPL, Creative Commons does not authorize the use by either party of the trademark "Creative Commons" or any related trademark or logo of Creative Commons without the prior written consent of Creative Commons. Any permitted use will be in compliance with Creative Commons' then-current trademark usage guidelines, as may be published on its website or otherwise made available upon request from time to time. For the avoidance of doubt, this trademark restriction does not form part of this License. + +Creative Commons may be contacted at https://creativecommons.org/. diff --git a/options/license/LZMA-SDK-9.11-to-9.20 b/options/license/LZMA-SDK-9.11-to-9.20 new file mode 100644 index 000000000000..5da25bf883ce --- /dev/null +++ b/options/license/LZMA-SDK-9.11-to-9.20 @@ -0,0 +1,8 @@ +LICENSE +------- + +LZMA SDK is written and placed in the public domain by Igor Pavlov. + +Some code in LZMA is based on public domain code from another developers: + 1) PPMd var.H (2001): Dmitry Shkarin + 2) SHA-256: Wei Dai (Crypto++ library) diff --git a/options/license/LZMA-SDK-9.22 b/options/license/LZMA-SDK-9.22 new file mode 100644 index 000000000000..ef4768d2a722 --- /dev/null +++ b/options/license/LZMA-SDK-9.22 @@ -0,0 +1,15 @@ +LICENSE +------- + +LZMA SDK is written and placed in the public domain by Igor Pavlov. + +Some code in LZMA SDK is based on public domain code from another developers: + 1) PPMd var.H (2001): Dmitry Shkarin + 2) SHA-256: Wei Dai (Crypto++ library) + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute the +original LZMA SDK code, either in source code form or as a compiled binary, for +any purpose, commercial or non-commercial, and by any means. + +LZMA SDK code is compatible with open source licenses, for example, you can +include it to GNU GPL or GNU LGPL code. diff --git a/options/license/NICTA-1.0 b/options/license/NICTA-1.0 new file mode 100644 index 000000000000..04622e308d1a --- /dev/null +++ b/options/license/NICTA-1.0 @@ -0,0 +1,61 @@ +NICTA Public Software Licence +Version 1.0 + +Copyright © 2004 National ICT Australia Ltd + +All rights reserved. + +By this licence, National ICT Australia Ltd (NICTA) grants permission, +free of charge, to any person who obtains a copy of this software +and any associated documentation files ("the Software") to use and +deal with the Software in source code and binary forms without +restriction, with or without modification, and to permit persons +to whom the Software is furnished to do so, provided that the +following conditions are met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimers. +- Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimers in + the documentation and/or other materials provided with the + distribution. +- The name of NICTA may not be used to endorse or promote products + derived from this Software without specific prior written permission. + +EXCEPT AS EXPRESSLY STATED IN THIS LICENCE AND TO THE FULL EXTENT +PERMITTED BY APPLICABLE LAW, THE SOFTWARE IS PROVIDED "AS-IS" AND +NICTA MAKES NO REPRESENTATIONS, WARRANTIES OR CONDITIONS OF ANY +KIND, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY +REPRESENTATIONS, WARRANTIES OR CONDITIONS REGARDING THE CONTENTS +OR ACCURACY OF THE SOFTWARE, OR OF TITLE, MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, THE ABSENCE OF LATENT +OR OTHER DEFECTS, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR +NOT DISCOVERABLE. + +TO THE FULL EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL +NICTA BE LIABLE ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, +NEGLIGENCE) FOR ANY LOSS OR DAMAGE WHATSOEVER, INCLUDING (WITHOUT +LIMITATION) LOSS OF PRODUCTION OR OPERATION TIME, LOSS, DAMAGE OR +CORRUPTION OF DATA OR RECORDS; OR LOSS OF ANTICIPATED SAVINGS, +OPPORTUNITY, REVENUE, PROFIT OR GOODWILL, OR OTHER ECONOMIC LOSS; +OR ANY SPECIAL, INCIDENTAL, INDIRECT, CONSEQUENTIAL, PUNITIVE OR +EXEMPLARY DAMAGES ARISING OUT OF OR IN CONNECTION WITH THIS LICENCE, +THE SOFTWARE OR THE USE OF THE SOFTWARE, EVEN IF NICTA HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +If applicable legislation implies warranties or conditions, or +imposes obligations or liability on NICTA in respect of the Software +that cannot be wholly or partly excluded, restricted or modified, +NICTA's liability is limited, to the full extent permitted by the +applicable legislation, at its option, to: + +a. in the case of goods, any one or more of the following: + i. the replacement of the goods or the supply of equivalent goods; + ii. the repair of the goods; + iii. the payment of the cost of replacing the goods or of acquiring + equivalent goods; + iv. the payment of the cost of having the goods repaired; or +b. in the case of services: + i. the supplying of the services again; or + ii. the payment of the cost of having the services supplied + again. diff --git a/options/license/Python-2.0.1 b/options/license/Python-2.0.1 new file mode 100644 index 000000000000..2b90e0400c36 --- /dev/null +++ b/options/license/Python-2.0.1 @@ -0,0 +1,207 @@ +PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 +-------------------------------------------- + +1. This LICENSE AGREEMENT is between the Python Software Foundation +("PSF"), and the Individual or Organization ("Licensee") accessing and +otherwise using this software ("Python") in source or binary form and +its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby +grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, +analyze, test, perform and/or display publicly, prepare derivative works, +distribute, and otherwise use Python alone or in any derivative version, +provided, however, that PSF's License Agreement and PSF's notice of copyright, +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022 Python Software Foundation; +All Rights Reserved" are retained in Python alone or in any derivative version +prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python. + +4. PSF is making Python available to Licensee on an "AS IS" +basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between PSF and +Licensee. This License Agreement does not grant permission to use PSF +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using Python, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 +------------------------------------------- + +BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 + +1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an +office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the +Individual or Organization ("Licensee") accessing and otherwise using +this software in source or binary form and its associated +documentation ("the Software"). + +2. Subject to the terms and conditions of this BeOpen Python License +Agreement, BeOpen hereby grants Licensee a non-exclusive, +royalty-free, world-wide license to reproduce, analyze, test, perform +and/or display publicly, prepare derivative works, distribute, and +otherwise use the Software alone or in any derivative version, +provided, however, that the BeOpen Python License is retained in the +Software, alone or in any derivative version prepared by Licensee. + +3. BeOpen is making the Software available to Licensee on an "AS IS" +basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE +SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS +AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY +DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +5. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +6. This License Agreement shall be governed by and interpreted in all +respects by the law of the State of California, excluding conflict of +law provisions. Nothing in this License Agreement shall be deemed to +create any relationship of agency, partnership, or joint venture +between BeOpen and Licensee. This License Agreement does not grant +permission to use BeOpen trademarks or trade names in a trademark +sense to endorse or promote products or services of Licensee, or any +third party. As an exception, the "BeOpen Python" logos available at +http://www.pythonlabs.com/logos.html may be used according to the +permissions granted on that web page. + +7. By copying, installing or otherwise using the software, Licensee +agrees to be bound by the terms and conditions of this License +Agreement. + + +CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 +--------------------------------------- + +1. This LICENSE AGREEMENT is between the Corporation for National +Research Initiatives, having an office at 1895 Preston White Drive, +Reston, VA 20191 ("CNRI"), and the Individual or Organization +("Licensee") accessing and otherwise using Python 1.6.1 software in +source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, CNRI +hereby grants Licensee a nonexclusive, royalty-free, world-wide +license to reproduce, analyze, test, perform and/or display publicly, +prepare derivative works, distribute, and otherwise use Python 1.6.1 +alone or in any derivative version, provided, however, that CNRI's +License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) +1995-2001 Corporation for National Research Initiatives; All Rights +Reserved" are retained in Python 1.6.1 alone or in any derivative +version prepared by Licensee. Alternately, in lieu of CNRI's License +Agreement, Licensee may substitute the following text (omitting the +quotes): "Python 1.6.1 is made available subject to the terms and +conditions in CNRI's License Agreement. This Agreement together with +Python 1.6.1 may be located on the internet using the following +unique, persistent identifier (known as a handle): 1895.22/1013. This +Agreement may also be obtained from a proxy server on the internet +using the following URL: http://hdl.handle.net/1895.22/1013". + +3. In the event Licensee prepares a derivative work that is based on +or incorporates Python 1.6.1 or any part thereof, and wants to make +the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to Python 1.6.1. + +4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" +basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT +INFRINGE ANY THIRD PARTY RIGHTS. + +5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON +1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS +A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, +OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. This License Agreement shall be governed by the federal +intellectual property law of the United States, including without +limitation the federal copyright law, and, to the extent such +U.S. federal law does not apply, by the law of the Commonwealth of +Virginia, excluding Virginia's conflict of law provisions. +Notwithstanding the foregoing, with regard to derivative works based +on Python 1.6.1 that incorporate non-separable material that was +previously distributed under the GNU General Public License (GPL), the +law of the Commonwealth of Virginia shall govern this License +Agreement only as to issues arising under or with respect to +Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this +License Agreement shall be deemed to create any relationship of +agency, partnership, or joint venture between CNRI and Licensee. This +License Agreement does not grant permission to use CNRI trademarks or +trade name in a trademark sense to endorse or promote products or +services of Licensee, or any third party. + +8. By clicking on the "ACCEPT" button where indicated, or by copying, +installing or otherwise using Python 1.6.1, Licensee agrees to be +bound by the terms and conditions of this License Agreement. + + ACCEPT + + +CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 +-------------------------------------------------- + +Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, +The Netherlands. All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior +permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +ZERO-CLAUSE BSD LICENSE FOR CODE IN THE PYTHON DOCUMENTATION +---------------------------------------------------------------------- + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/options/license/mpi-permissive b/options/license/mpi-permissive new file mode 100644 index 000000000000..2abcbe3ab0c6 --- /dev/null +++ b/options/license/mpi-permissive @@ -0,0 +1,15 @@ +* Copyright (C) 2000-2004 by Etnus, LLC + * + * Permission is hereby granted to use, reproduce, prepare derivative + * works, and to redistribute to others. + * + * DISCLAIMER + * + * Neither Etnus, nor any of their employees, makes any warranty + * express or implied, or assumes any legal liability or + * responsibility for the accuracy, completeness, or usefulness of any + * information, apparatus, product, or process disclosed, or + * represents that its use would not infringe privately owned rights. + * + * This code was written by + * James Cownie: Etnus, LLC. diff --git a/options/license/mpich2 b/options/license/mpich2 index 5c32b0ec1d60..1fa4acbc6293 100644 --- a/options/license/mpich2 +++ b/options/license/mpich2 @@ -3,11 +3,17 @@ COPYRIGHT The following is a notice of limited availability of the code, and disclaimer which must be included in the prologue of the code and in all source listings of the code. Copyright Notice -+ 2002 University of Chicago +1998--2020, Argonne National Laboratory Permission is hereby granted to use, reproduce, prepare derivative works, and to redistribute to others. This software was authored by: -Argonne National Laboratory Group W. Gropp: (630) 252-4318; FAX: (630) 252-5986; e-mail: gropp@mcs.anl.gov E. Lusk: (630) 252-7852; FAX: (630) 252-5986; e-mail: lusk@mcs.anl.gov Mathematics and Computer Science Division Argonne National Laboratory, Argonne IL 60439 +Mathematics and Computer Science Division +Argonne National Laboratory, Argonne IL 60439 + +(and) + +Department of Computer Science +University of Illinois at Urbana-Champaign GOVERNMENT LICENSE diff --git a/options/locale/locale_bg-BG.ini b/options/locale/locale_bg-BG.ini index c6faee5cf605..497aab66c73a 100644 --- a/options/locale/locale_bg-BG.ini +++ b/options/locale/locale_bg-BG.ini @@ -8,7 +8,6 @@ sign_out=Изход sign_up=Регистриране link_account=Свържи профил register=Регистрация -website=Уебсайт version=Версия powered_by=С подкрепата на %s page=Страница @@ -129,7 +128,6 @@ log_root_path_helper=Директория, в която да се съхран optional_title=Опционални настройки email_title=Имейл настройки -smtp_host=SMTP сървър smtp_from=Изпрати имейл като smtp_from_helper=E-mail адрес, който да се използва от Gitea. Въведете само E-mail адреса или име и E-mail във формат "Name ". mailer_user=SMTP потребител @@ -1151,9 +1149,7 @@ config.queue_length=Дължина на опашка config.deliver_timeout=Време за отказ при изпращане config.mailer_enabled=Активен -config.mailer_disable_helo=Изключи HELO config.mailer_name=Име -config.mailer_host=Сървър config.mailer_user=Потребител config.oauth_config=OAuth конфигурация diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 2b7c18ca12bc..2b3ddeace389 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -8,7 +8,6 @@ sign_out=Odhlásit se sign_up=Registrovat se link_account=Propojit účet register=Registrovat se -website=Webové stránky version=Verze powered_by=Běží na %s page=Strana @@ -176,7 +175,6 @@ log_root_path_helper=Soubory protokolu budou zapsány do tohoto adresáře. optional_title=Dodatečná nastavení email_title=Nastavení e-mailu -smtp_host=Server SMTP smtp_from=Odeslat e-mail jako smtp_from_helper=E-mailová adresa, kterou bude Gitea používat. Zadejte běžnou e-mailovou adresu, nebo použijte formát "Jméno". mailer_user=Uživatelské jméno SMTP @@ -994,8 +992,6 @@ file_view_rendered=Zobrazit vykreslené file_view_raw=Zobrazit v surovém stavu file_permalink=Trvalý odkaz file_too_large=Soubor je příliš velký pro zobrazení. -bidi_bad_header=`Tento soubor obsahuje neočekávané obousměrné znaky Unicode!` -line_unicode=`Tento řádek má skryté unicode znaky` file_copy_permalink=Kopírovat trvalý odkaz video_not_supported_in_browser=Váš prohlížeč nepodporuje značku pro HTML5 video. @@ -2661,11 +2657,8 @@ config.queue_length=Délka fronty config.deliver_timeout=Časový limit doručení config.skip_tls_verify=Přeskočit verifikaci TLS -config.mailer_config=Konfigurace služby SMTP config.mailer_enabled=Zapnutý -config.mailer_disable_helo=Zakázat HELO config.mailer_name=Název -config.mailer_host=Server config.mailer_user=Uživatel config.mailer_use_sendmail=Použít Sendmail config.mailer_sendmail_path=Cesta k Sendmail diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index b4e59e504a46..84630dbc3485 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -9,7 +9,6 @@ sign_out=Abmelden sign_up=Registrieren link_account=Account verbinden register=Registrieren -website=Webseite version=Version powered_by=Powered by %s page=Seite @@ -179,7 +178,6 @@ log_root_path_helper=Log-Dateien werden in diesem Verzeichnis gespeichert. optional_title=Optionale Einstellungen email_title=E-Mail-Einstellungen -smtp_host=SMTP-Server smtp_from=E-Mail senden als smtp_from_helper=E-Mail-Adresse, die von Gitea genutzt werden soll. Bitte gib die E-Mail-Adresse im Format „"Name" “ ein. mailer_user=SMTP-Benutzername @@ -1033,13 +1031,7 @@ file_view_rendered=Ansicht rendern file_view_raw=Originalformat anzeigen file_permalink=Permalink file_too_large=Die Datei ist zu groß zum Anzeigen. -bidi_bad_header=`Diese Datei enthält unerwartete Bidirektionale Unicode-Zeichen!` -bidi_bad_description=`Diese Datei enthält unerwartete Bidirektionale Unicode-Zeichen, die anders verarbeitet werden können als nachstehend angezeigt. Wenn dein Anwendungsfall absichtlich und legitim ist, kannst du diese Warnung ignorieren. Benutze den "Escape" Button, um versteckte Zeichen anzuzeigen.` -bidi_bad_description_escaped=`Diese Datei enthält unerwartete Unicode-Zeichen. Versteckte Unicode-Zeichen werden unten escaped. Benutze den "Unescapen" Button, um zu sehen, wie sie ansonsten aussehen.` -unicode_header=`Diese Datei enthält versteckte Unicode-Zeichen!` -unicode_description=`Diese Datei enthält versteckte Unicode-Zeichen, die anders verarbeitet werden können als unten angezeigt. Wenn dein Anwendungsfall absichtlich und legitim ist, kannst du diese Warnung ignorieren. Benutze den Escape Button, um versteckte Zeichen anzuzeigen.` -unicode_description_escaped=`Diese Datei enthält versteckte Unicode-Zeichen. Versteckte Unicode-Zeichen werden unten escaped. Benutze den "Unescapen" Button, um zu sehen, wie sie ansonsten aussehen.` -line_unicode=`Diese Zeile hat versteckte Unicode-Zeichen` +ambiguous_character=`%[1]c [U+%04[1]X] kann mit %[2]c [U+%04[2]X] verwechselt werden` escape_control_characters=Escapen unescape_control_characters=Unescapen @@ -1060,6 +1052,7 @@ normal_view=Normale Ansicht line=zeile lines=Zeilen +editor.add_file=Datei hinzufügen editor.new_file=Neue Datei editor.upload_file=Datei hochladen editor.edit_file=Datei bearbeiten @@ -1265,6 +1258,8 @@ issues.filter_milestone=Meilenstein issues.filter_milestone_no_select=Alle Meilensteine issues.filter_assignee=Zuständig issues.filter_assginee_no_select=Alle Zuständigen +issues.filter_poster=Autor +issues.filter_poster_no_select=Alle Autoren issues.filter_type=Typ issues.filter_type.all_issues=Alle Issues issues.filter_type.assigned_to_you=Dir zugewiesen @@ -2790,11 +2785,10 @@ config.queue_length=Warteschlangenlänge config.deliver_timeout=Zeitlimit für Zustellung config.skip_tls_verify=TLS-Verifikation überspringen -config.mailer_config=SMTP-Mailer-Konfiguration config.mailer_enabled=Aktiviert -config.mailer_disable_helo=HELO deaktivieren +config.mailer_enable_helo=HELO aktivieren config.mailer_name=Name -config.mailer_host=Host +config.mailer_protocol=Protokoll config.mailer_user=Benutzer config.mailer_use_sendmail=Sendmail benutzen config.mailer_sendmail_path=Sendmail-Pfad @@ -3101,6 +3095,7 @@ npm.dependencies.development=Entwicklungsabhängigkeiten npm.dependencies.peer=Peer Abhängigkeiten npm.dependencies.optional=Optionale Abhängigkeiten npm.details.tag=Tag +pub.install=Um das Paket mit Dart zu installieren, führe den folgenden Befehl aus: pypi.requires=Erfordert Python pypi.install=Nutze folgenden Befehl, um das Paket mit pip zu installieren: pypi.documentation=Weitere Informationen zur PyPI-Paketverwaltung findest du in der Dokumentation. diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index c123bd6d2661..e06a3e539258 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -9,7 +9,6 @@ sign_out=Έξοδος sign_up=Εγγραφή link_account=Σύνδεση λογαριασμού register=Εγγραφή -website=Ιστοσελίδα version=Έκδοση powered_by=Με τη δύναμη του %s page=Σελίδα @@ -179,7 +178,6 @@ log_root_path_helper=Τα αρχεία καταγραφής θα γράφοντ optional_title=Προαιρετικές Ρυθμίσεις email_title=Ρυθμίσεις Email -smtp_host=Διακομιστής SMTP smtp_from=Αποστολή Email Ως smtp_from_helper=Η διεύθυνση email που θα χρησιμοποιεί το Gitea. Εισάγετε μια απλή διεύθυνση ηλεκτρονικού ταχυδρομείου ή χρησιμοποιήστε τη μορφή "Όνομα" . mailer_user=Όνομα Χρήστη SMTP @@ -1034,13 +1032,6 @@ file_view_rendered=Προβολή Απόδοσης file_view_raw=Προβολή Ακατέργαστου file_permalink=Permalink file_too_large=Το αρχείο είναι πολύ μεγάλο για να εμφανιστεί. -bidi_bad_header=`Αυτό το αρχείο περιέχει μη αναμενόμενους χαρακτήρες Unicode!` -bidi_bad_description=`Αυτό το αρχείο περιέχει μη αναμενόμενους χαρακτήρες Bidirectional Unicode που ίσως να επεξεργάζονται διαφορετικά από ότι εμφανίζεται παρακάτω. Αν η χρήση αυτή είναι σκόπιμη και νόμιμη, μπορείτε να αγνοήσετε με ασφάλεια αυτή την προειδοποίηση. Χρησιμοποιήστε το κουμπί Escape για να αποκαλύψετε κρυμμένους χαρακτήρες.` -bidi_bad_description_escaped=`Αυτό το αρχείο περιέχει μη αναμενόμενους χαρακτήρες Bidirectional Unicode. Οι κρυμμένοι χαρακτήρες unicode εμφανίζονται κωδικοποιημένοι παρακάτω. Χρησιμοποιήστε το κουμπί Unescape για να δείτε πώς αποδίδονται.` -unicode_header=`Αυτό το αρχείο περιέχει κρυφούς χαρακτήρες Unicode!` -unicode_description=`Αυτό το αρχείο περιέχει κρυφούς χαρακτήρες Unicode που μπορεί να επεξεργάζονται διαφορετικά από όπως εμφανίζονται παρακάτω. Αν η χρήση είναι σκόπιμη και νόμιμη, μπορείτε να αγνοήσετε με ασφάλεια αυτή την προειδοποίηση. Χρησιμοποιήστε το κουμπί Escape για να αποκαλύψετε τους κρυφούς χαρακτήρες.` -unicode_description_escaped=`Αυτό το αρχείο περιέχει κρυφούς χαρακτήρες Unicode. Οι κρυφοί χαρακτήρες unicode εμφανίζονται κωδικοποιημένοι παρακάτω. Χρησιμοποιήστε το κουμπί Unescape για να δείτε πώς αποδίδονται.` -line_unicode=`Αυτή η γραμμή έχει κρυφούς χαρακτήρες unicode` escape_control_characters=Escape unescape_control_characters=Unescape @@ -2794,11 +2785,8 @@ config.queue_length=Μέγεθος Ουράς config.deliver_timeout=Χρονικό Όριο Παράδοσης config.skip_tls_verify=Παράλειψη Επαλήθευσης TLS -config.mailer_config=Ρυθμίσεις SMTP Mailer config.mailer_enabled=Ενεργοποιημένο -config.mailer_disable_helo=Απενεργοποίηση HELO config.mailer_name=Όνομα -config.mailer_host=Διακομιστής config.mailer_user=Χρήστης config.mailer_use_sendmail=Χρήση Sendmail config.mailer_sendmail_path=Διαδρομή Sendmail diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a774bf92fff4..0e309279d29b 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -9,7 +9,6 @@ sign_out = Sign Out sign_up = Register link_account = Link Account register = Register -website = Website version = Version powered_by = Powered by %s page = Page @@ -1036,13 +1035,13 @@ file_view_rendered = View Rendered file_view_raw = View Raw file_permalink = Permalink file_too_large = The file is too large to be shown. -bidi_bad_header = `This file contains unexpected Bidirectional Unicode characters!` -bidi_bad_description = `This file contains unexpected Bidirectional Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.` -bidi_bad_description_escaped = `This file contains unexpected Bidirectional Unicode characters. Hidden unicode characters are escaped below. Use the Unescape button to show how they render.` -unicode_header = `This file contains hidden Unicode characters!` -unicode_description = `This file contains hidden Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.` -unicode_description_escaped = `This file contains hidden Unicode characters. Hidden unicode characters are escaped below. Use the Unescape button to show how they render.` -line_unicode = `This line has hidden unicode characters` +invisible_runes_header = `This file contains invisible Unicode characters!` +invisible_runes_description = `This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.` +ambiguous_runes_header = `This file contains ambiguous Unicode characters!` +ambiguous_runes_description = `This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.` +invisible_runes_line = `This line has invisible unicode characters` +ambiguous_runes_line = `This line has ambiguous unicode characters` +ambiguous_character = `%[1]c [U+%04[1]X] is confusable with %[2]c [U+%04[2]X]` escape_control_characters = Escape unescape_control_characters = Unescape @@ -1063,6 +1062,7 @@ normal_view = Normal View line = line lines = lines +editor.add_file = Add File editor.new_file = New File editor.upload_file = Upload File editor.edit_file = Edit File @@ -1268,6 +1268,8 @@ issues.filter_milestone = Milestone issues.filter_milestone_no_select = All milestones issues.filter_assignee = Assignee issues.filter_assginee_no_select = All assignees +issues.filter_poster = Author +issues.filter_poster_no_select = All authors issues.filter_type = Type issues.filter_type.all_issues = All issues issues.filter_type.assigned_to_you = Assigned to you @@ -2796,16 +2798,19 @@ config.queue_length = Queue Length config.deliver_timeout = Deliver Timeout config.skip_tls_verify = Skip TLS Verification -config.mailer_config = SMTP Mailer Configuration +config.mailer_config = Mailer Configuration config.mailer_enabled = Enabled -config.mailer_disable_helo = Disable HELO +config.mailer_enable_helo = Enable HELO config.mailer_name = Name -config.mailer_host = Host +config.mailer_protocol = Protocol +config.mailer_smtp_addr = SMTP Addr +config.mailer_smtp_port = SMTP Port config.mailer_user = User config.mailer_use_sendmail = Use Sendmail config.mailer_sendmail_path = Sendmail Path config.mailer_sendmail_args = Extra Arguments to Sendmail config.mailer_sendmail_timeout = Sendmail Timeout +config.mailer_use_dummy = Dummy config.test_email_placeholder = Email (e.g. test@example.com) config.send_test_mail = Send Testing Email config.test_mail_failed = Failed to send a testing email to '%s': %v @@ -2890,6 +2895,7 @@ monitor.queue.nopool.title = No Worker Pool monitor.queue.nopool.desc = This queue wraps other queues and does not itself have a worker pool. monitor.queue.wrapped.desc = A wrapped queue wraps a slow starting queue, buffering queued requests in a channel. It does not have a worker pool itself. monitor.queue.persistable-channel.desc = A persistable-channel wraps two queues, a channel queue that has its own worker pool and a level queue for persisted requests from previous shutdowns. It does not have a worker pool itself. +monitor.queue.flush = Flush worker monitor.queue.pool.timeout = Timeout monitor.queue.pool.addworkers.title = Add Workers monitor.queue.pool.addworkers.submit = Add Workers @@ -3108,6 +3114,10 @@ npm.dependencies.development = Development Dependencies npm.dependencies.peer = Peer Dependencies npm.dependencies.optional = Optional Dependencies npm.details.tag = Tag +pub.install = To install the package using Dart, run the following command: +pub.documentation = For more information on the Pub registry, see the documentation. +pub.details.repository_site = Repository Site +pub.details.documentation_site = Documentation Site pypi.requires = Requires Python pypi.install = To install the package using pip, run the following command: pypi.documentation = For more information on the PyPI registry, see the documentation. diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 4507bc553b6a..ea1ce54749a7 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -9,7 +9,6 @@ sign_out=Cerrar sesión sign_up=Registrarse link_account=Vincular cuenta register=Registro -website=Página web version=Versión powered_by=Impulsado por %s page=Página @@ -179,7 +178,8 @@ log_root_path_helper=Archivos de registro se escribirán en este directorio. optional_title=Configuración opcional email_title=Configuración de Correo -smtp_host=Servidor SMTP +smtp_addr=Servidor SMTP +smtp_port=Puerto SMTP smtp_from=Enviar correos electrónicos como smtp_from_helper=Dirección de correo electrónico que utilizará Gitea. Introduzca una dirección de correo electrónico normal o utilice el formato "Nombre" . mailer_user=Nombre de usuario SMTP @@ -978,7 +978,7 @@ migrate.migrating_topics=Migrando Temas migrate.migrating_milestones=Migrando Hitos migrate.migrating_labels=Migrando etiquetas migrate.migrating_releases=Migrando Lanzamientos -migrate.migrating_issues=Migrando Incidencías +migrate.migrating_issues=Migrando incidencias migrate.migrating_pulls=Migrando Pull Requests mirror_from=réplica de @@ -1035,13 +1035,13 @@ file_view_rendered=Ver procesado file_view_raw=Ver original file_permalink=Enlace permanente file_too_large=El archivo es demasiado grande para ser mostrado. -bidi_bad_header=`¡Este archivo contiene caracteres Unicode bidireccional inesperados!` -bidi_bad_description=`Este archivo contiene caracteres Bidirectional Unicode inesperados que pueden ser procesados de forma diferente a lo que aparece a continuación. Si su caso de uso es intencional y legítimo, puede ignorar esta advertencia. Use el botón de Escape para revelar caracteres ocultos.` -bidi_bad_description_escaped=`Este archivo contiene caracteres Unicode bidireccionales inesperados. Los caracteres unicode ocultos se escapan debajo. Utilice el botón Unescape para mostrar cómo se renderizan.` -unicode_header=`¡Este archivo contiene caracteres Unicode ocultos!` -unicode_description=`Este archivo contiene caracteres Unicode ocultos que pueden ser procesados de forma diferente a lo que aparece a continuación. Si su caso de uso es intencional y legítimo, puede ignorar esta advertencia. Use el botón de Escape para revelar caracteres ocultos.` -unicode_description_escaped=`Este archivo contiene caracteres Unicode ocultos. Los caracteres unicode ocultos se escapan debajo. Utilice el botón Unescape para mostrar cómo renderizan.` -line_unicode=`Esta línea tiene caracteres unicode ocultos` +invisible_runes_header=`¡Este archivo contiene caracteres Unicode invisibles!` +invisible_runes_description=`Este archivo contiene caracteres Unicode invisibles que pueden ser procesados de forma diferente a lo que aparece a continuación. Si su caso de uso es intencional y legítimo, puede ignorar esta advertencia. Use el botón de Escape para revelar caracteres ocultos.` +ambiguous_runes_header=`¡Este archivo contiene caracteres Unicode ambiguos!` +ambiguous_runes_description=`Este archivo contiene caracteres Unicode ambiguos que pueden confundirse con otros en tu idioma actual. Si tu caso de uso es intencional y legítimo, puedes ignorar esta advertencia. Usa el botón de Escape para resaltar estos caracteres.` +invisible_runes_line=`Esta línea tiene caracteres unicode invisibles` +ambiguous_runes_line=`Esta línea tiene caracteres unicode ambiguos` +ambiguous_character=`%[1]c [U+%04[1]X] es confusable con %[2]c [U+%04[2]X]` escape_control_characters=Escapar unescape_control_characters=No Escapar @@ -1062,6 +1062,7 @@ normal_view=Vista normal line=línea lines=líneas +editor.add_file=Añadir archivo editor.new_file=Nuevo Archivo editor.upload_file=Subir archivo editor.edit_file=Editar Archivo @@ -1267,6 +1268,8 @@ issues.filter_milestone=Milestone issues.filter_milestone_no_select=Todos los hitos issues.filter_assignee=Asignada a issues.filter_assginee_no_select=Todos los asignados +issues.filter_poster=Autor +issues.filter_poster_no_select=Todos los autores issues.filter_type=Tipo issues.filter_type.all_issues=Todas las incidencias issues.filter_type.assigned_to_you=Asignadas a ti @@ -2797,14 +2800,17 @@ config.skip_tls_verify=Saltar verificación TLS config.mailer_config=Configuración del servidor de correo config.mailer_enabled=Activado -config.mailer_disable_helo=Desactivar HELO +config.mailer_enable_helo=Habilitar HELO config.mailer_name=Nombre -config.mailer_host=Servidor +config.mailer_protocol=Protocolo +config.mailer_smtp_addr=Dirección SMTP +config.mailer_smtp_port=Puerto SMTP config.mailer_user=Usuario config.mailer_use_sendmail=Usar Sendmail config.mailer_sendmail_path=Ruta de Sendmail config.mailer_sendmail_args=Argumentos adicionales por Sendmail config.mailer_sendmail_timeout=Tiempo de espera de Sendmail +config.mailer_use_dummy=Dummy config.test_email_placeholder=Correo electrónico (ej. test@ejemplo.com) config.send_test_mail=Enviar prueba de correo config.test_mail_failed=Fallo al enviar correo electrónico de prueba a '%s': %v @@ -2889,6 +2895,7 @@ monitor.queue.nopool.title=No existe un grupo de trabajadores monitor.queue.nopool.desc=Esta cola envuelve otras colas y no tiene grupos de trabajadores. monitor.queue.wrapped.desc=Una cola de tipo envuelto envuelve una cola de inicio lenta, búfer de peticiones en un canal. No tiene grupos de trabajadores en si misma. monitor.queue.persistable-channel.desc=Una cola de tipo canal persistente envuelve dos colas, una cola de canales que tiene sus propios grupos de trabajadores y una cola de niveles para peticiones persistentes de apagones anteriores. No tiene grupos de trabajadores en sí misma. +monitor.queue.flush=Vaciar trabajador monitor.queue.pool.timeout=Tiempo de espera monitor.queue.pool.addworkers.title=Añadir trabajadores monitor.queue.pool.addworkers.submit=Añadir trabajadores @@ -3107,6 +3114,10 @@ npm.dependencies.development=Dependencias de desarrollo npm.dependencies.peer=Dependencias de pares npm.dependencies.optional=Dependencias opcionales npm.details.tag=Etiqueta +pub.install=Para instalar el paquete usando Dart, ejecute el siguiente comando: +pub.documentation=Para obtener más información sobre el registro de Pub, consulte la documentación. +pub.details.repository_site=Sitio del repositorio +pub.details.documentation_site=Sitio de documentación pypi.requires=Requiere Python pypi.install=Para instalar el paquete usando pip, ejecute el siguiente comando: pypi.documentation=Para obtener más información sobre el registro PyPI, consulte la documentación. diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 9999425f157f..d60b6dceea44 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -8,7 +8,6 @@ sign_out=خروج sign_up=ثبت نام link_account=پیوند به حساب register=ثبت نام -website=وب‌سایت version=نسخه powered_by=قدرت از %s page=صفحه @@ -158,7 +157,6 @@ log_root_path_helper=فایل‌های گزارش روی این مسیر ذخی optional_title=تنظیمات اختیاری email_title=تنظیمات ایمیل -smtp_host=میزبان SMTP smtp_from=ارسال ایمیل به عنوان smtp_from_helper=آدرس ایمیلی که گیتی استفاده میکند. یک ایمیل وارد کنید یا به "Name" شکل استفاده کنید. mailer_user=نام کاربری SMTP @@ -2576,11 +2574,8 @@ config.queue_length=طول صف config.deliver_timeout=مهلت تحویل config.skip_tls_verify=صرف نظر از اعتبارسنجی TLS -config.mailer_config=پیکربندی سامانه ایمیلی SMTP config.mailer_enabled=فعال شده -config.mailer_disable_helo=غیر فعال کردن HELO config.mailer_name=نام -config.mailer_host=میزبان config.mailer_user=کاربر config.mailer_use_sendmail=استفاده از ارسال رایانامه (ایمیل) مستقیم config.mailer_sendmail_path=مسیر ارسال ایمیل مستقیم diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 2699598ed9b2..7c0cc310973c 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -2,13 +2,13 @@ home=Etusivu dashboard=Kojelauta explore=Tutki help=Apua +logo=Logo sign_in=Kirjaudu sisään sign_in_with=Kirjaudu sisään tunnuksilla sign_out=Kirjaudu ulos sign_up=Rekisteröidy link_account=Yhdistä tili register=Rekisteröidy -website=Nettisivut version=Versio powered_by=Voimanlähteenä %s page=Sivu @@ -21,16 +21,28 @@ signed_in_as=Kirjautuneena käyttäjänä enable_javascript=Tämä sivusto toimii paremmin JavaScriptillä. toc=Sisällysluettelo licenses=Lisenssit +return_to_gitea=Palaa Giteaan username=Käyttäjätunnus email=Sähköpostiosoite password=Salasana +access_token=Pääsymerkki re_type=Kirjoita salasana uudelleen captcha=CAPTCHA twofa=Kaksivaiheinen todennus twofa_scratch=Kaksivaiheinen kertakäyttöinen koodi passcode=Tunnuskoodi +webauthn_insert_key=Aseta turva-avaimesi +webauthn_press_button=Paina turva-avaimesi painiketta… +webauthn_error=Turva-avainta ei voitu lukea. +webauthn_unsupported_browser=Selaimesi ei tällä hetkellä tue WebAuthnia. +webauthn_error_insecure=WebAuthn tukee vain suojattuja yhteyksiä. Testaukseen HTTP:n yli, voit käyttää osoitetta "localhost" tai "127.0.0.1" +webauthn_error_unable_to_process=Palvelin ei pystynyt toteuttamaan kutsua. +webauthn_error_duplicated=Turva-avainta ei ole sallittu tässä pyynnössä. Varmista, ettei avainta ole jo rekisteröity. +webauthn_error_empty=Sinun täytyy asettaa nimi tälle avaimelle. +webauthn_error_timeout=Aikakatkaisu saavutettu ennenkuin avaintasi on voitu lukea. Lataa tämä sivu uudelleen ja yritä uudelleen. +webauthn_reload=Päivitä repository=Repo organization=Organisaatio @@ -40,6 +52,7 @@ new_migrate=Uusi migraatio new_mirror=Uusi peilaus new_fork=Uusi repositorio new_org=Uusi organisaatio +new_project=Uusi projekti manage_org=Ylläpidä organisaatioita admin_panel=Sivuston ylläpito account_settings=Tilin asetukset @@ -59,28 +72,47 @@ pull_requests=Pull requestit issues=Ongelmat milestones=Merkkipaalut +ok=OK cancel=Peruuta save=Tallenna add=Lisää add_all=Lisää kaikki remove=Poista remove_all=Poista kaikki +edit=Muokkaa +copy=Kopioi +copy_url=Kopioi osoite +copy_branch=Kopioi haaran nimi +copy_success=Kopioitu! +copy_error=Kopiointi epäonnistui write=Kirjoita preview=Esikatselu loading=Ladataan… +step1=Vaihe 1: +step2=Vaihe 2: +error=Virhe error404=Sivu, jota yrität nähdä, joko ei löydy tai et ole oikeutettu katsomaan sitä. +never=Ei koskaan +rss_feed=RSS-syöte [error] +occurred=Virhe tapahtui +report_message=Jos olet varma, että tämä on ongelma Giteassa, etsi ongelmaa GitHubista tai avaa uusi ongelma tarvittaessa. +missing_csrf=Virheellinen pyyntö: CSRF-tunnusta ei ole olemassa +invalid_csrf=Virheellinen pyyntö: Virheellinen CSRF-tunniste +not_found=Kohdetta ei löytynyt. +network_error=Verkkovirhe [startpage] app_desc=Kivuton, itsehostattu Git-palvelu install=Helppo asentaa +install_desc=Yksinkertaisesti aja binääri alustallasi, toimita se Dockerilla, tai saa se pakettina. platform=Alustariippumaton platform_desc=Gitea käy missä tahansa alustassa, johon Go kykenee kääntämään. Windows, macOS, Linux, ARM, jne. Valitse omasi! lightweight=Kevyt @@ -92,6 +124,7 @@ license_desc=Mene osoitteeseen ohjeet ennen minkään asetuksen muuttamista. +require_db_desc=Gitea tarvitsee toimiakseen MySQL, PostgreSQL, MSSQL, SQLite3 tai TiDB (MySQL protokolla) tietokannan. db_title=Tietokanta asetukset db_type=Tietokanta tyyppi host=Isäntä @@ -99,10 +132,16 @@ user=Käyttäjätunnus password=Salasana db_name=Tietokannan nimi db_helper=Huomautus MySQL-käyttäjille: käytä InnoDB-tallennusmoottoria, ja jos käytät "utf8mb4" merkistöä, InnoDB-version on oltava yli 5.6. +db_schema=Skeema ssl_mode=SSL charset=Merkistö path=Polku sqlite_helper=SQLite3-tietokannan tiedostopolku.
Syötä absoluuttinen polku, jos ajat Giteaa palveluna. +reinstall_error=Yrität asentaa olemassa olevaan Gitea tietokantaan +reinstall_confirm_message=Asentaminen uudelleen olemassa olevalla Gitea-tietokannalla voi aiheuttaa useita ongelmia. Useimmissa tapauksissa sinun pitäisi käyttää olemassa olevia "app.ini" asetuksia Gitean käyttöön. Jos tiedät mitä teet, vahvista seuraavat seikat: +reinstall_confirm_check_1=Tiedot, jotka on salattu SECRET_KEY:llä app.ini:ssä saatetaan menettää: käyttäjät eivät ehkä voi kirjautua sisään 2FA/OTP:lla ja peilit eivät välttämättä toimi oikein. Ruksaamalla tämän vahvistat, että nykyinen app.ini -tiedosto sisältää oikean SECRET_KEY:n. +reinstall_confirm_check_2=Repot ja asetukset saattaa olla tarpeen uudelleensynkronoida. Valitsemalla tämän vahvistat, että uudelleensynkronoit repojen koukut ja authorized_keys -tiedoston manuaalisesti. Varmistat, että repon ja peilin asetukset ovat oikeat. +reinstall_confirm_check_3=Vahvistat, että olet täysin varma siitä, että tämä Gitea toimii oikealla app.ini sijainnilla ja että olet varma, että sinun täytyy asentaa uudelleen. Vahvistat, että tunnustat edellä mainitut riskit. err_empty_db_path=SQLite3-tietokannan polku ei voi olla tyhjä. no_admin_and_disable_registration=Et voi kytkeä rekisteröintiä pois luomatta sitä ennen ylläpitotiliä. err_empty_admin_password=Ylläpitäjän salasana ei voi olla tyhjä. @@ -119,6 +158,7 @@ lfs_path=Git LFS -juuripolku lfs_path_helper=Git LFS:n ylläpitämät tiedostot tullaan tallentamaan tähän hakemistoon. Jätä tyhjäksi kytkeäksesi toiminnon pois. run_user=Aja käyttäjänä run_user_helper=Anna käyttäjätunnus, jona Giteaa ajetaan. Käyttäjällä on oltava oikeudet repositorioiden juuripolkuun. +domain=Palvelimen verkkotunnus ssh_port=SSH-palvelimen portti ssh_port_helper=Porttinumero, jossa SSH-palvelimesi kuuntelee. Jätä tyhjäksi kytkeäksesi pois. http_port=Gitean HTTP-kuunteluportti @@ -130,7 +170,6 @@ log_root_path_helper=Lokitiedostot kirjoitetaan tähän kansioon. optional_title=Valinnaiset asetukset email_title=Sähköpostiasetukset -smtp_host=SMTP isäntä smtp_from=Lähetä sähköpostit osoitteella smtp_from_helper=Sähköpostiosoite, jota Gitea käyttää. Kirjoita osoite ”nimi” -muodossa. mailer_user=SMTP-käyttäjätunnus @@ -151,6 +190,7 @@ openid_signin=Ota OpenID kirjautuminen käyttöön openid_signin_popup=Ota käyttöön kirjautuminen OpenID:n kautta. openid_signup=Ota käyttöön OpenID itse-rekisteröinti openid_signup_popup=Ota käyttöön OpenID-pohjainen käyttäjän itse-rekisteröinti. +enable_captcha=Ota käyttöön CAPTCHA rekisteröityessä enable_captcha_popup=Pakollinen captcha käyttäjän itse rekisteröityessä. require_sign_in_view=Vaadi sisäänkirjautuminen sivujen näkemiseksi require_sign_in_view_popup=Rajoita pääsy vain kirjautuneille käyttäjille. Vierailijat näkevät vain 'kirjaudu sisään' ja rekisteröidy -sivut. @@ -165,22 +205,42 @@ test_git_failed=Epäonnistui testata 'git' komentoa: %v sqlite3_not_available=Tämä Gitea versio ei tue SQLite3. Lataa virallinen binääriversio kohteesta %s (ei 'gobuild' versio). invalid_db_setting=Tietokanta-asetukset ovat väärin: %v invalid_repo_path=Repojen juuri polku on virheellinen: %v +invalid_app_data_path=Sovelluksen datapolku on virheellinen: %v +internal_token_failed=Sisäisen pääsymerkin luonti epäonnistui: %v save_config_failed=Asetusten tallentaminen epäonnistui: %v install_success=Tervetuloa! Kiitos kun valitsit Gitean. Pidä hauskaa! +default_keep_email_private=Piilota sähköpostiosoitteet oletuksena +default_enable_timetracking=Ota ajan seuranta oletusarvoisesti käyttöön +default_enable_timetracking_popup=Ota käyttöön uusien repojen aikaseuranta oletusarvoisesti. +no_reply_address=Piilotettu sähköpostin verkkotunnus +no_reply_address_helper=Verkkotunnuksen nimi käyttäjille, joilla on piilotettu sähköpostiosoite. Esimerkiksi käyttäjätunnus 'joe' kirjataan Git nimellä 'joe@noreply.example.org' jos piilotettu sähköpostiosoite on asetettu 'noreply.example.org'. +password_algorithm=Salasanan hajautusalgoritmi +password_algorithm_helper=Aseta salasanan hajautusalgoritmi. Algoritmeillä on eri vaatimukset ja vahvuudet. `argon2`, vaikka sillä on hyvät ominaisuudet, käyttää paljon muistia ja voi olla sopimaton pienille järjestelmille. [home] uname_holder=Käyttäjätunnus tai sähköpostiosoite password_holder=Salasana switch_dashboard_context=Vaihda kojelaudan kontekstia my_repos=Repot +show_more_repos=Näytä lisää repoja… collaborative_repos=Yhteistyö repot my_orgs=Organisaationi my_mirrors=Peilini view_home=Näytä %s search_repos=Etsi repo… +filter=Muut suodattimet +filter_by_team_repositories=Suodata tiimin repojen mukaan +feed_of=Syöte "%s" +show_archived=Arkistoidut +show_both_archived_unarchived=Näytetään arkistoidut ja arkistoimattomat +show_only_archived=Näytetään vain arkistoidut +show_only_unarchived=Näytetään vain arkistoimattomat show_private=Yksityinen +show_both_private_public=Näytetään sekä julkiset että yksityiset +show_only_private=Näytetään vain yksityiset +show_only_public=Näytetään vain julkiset issues.in_your_repos=Repoissasi @@ -190,6 +250,7 @@ users=Käyttäjät organizations=Organisaatiot search=Hae code=Koodi +search.match=Osuma repo_no_results=Vastaavia repoja ei löydy. user_no_results=Vastaavia käyttäjiä ei löytynyt. org_no_results=Ei löytynyt vastaavia organisaatioita. @@ -203,6 +264,7 @@ register_helper_msg=On jo tili? Kirjaudu sisään nyt! social_register_helper_msg=Onko sinulla jo tili? Linkitä se nyt! disable_register_prompt=Rekisteröinti on estetty. Ota yhteys ylläpitäjääsi. disable_register_mail=Sähköpostivahvistus rekisteröinnille on estetty. +remember_me=Muista tämä laite forgot_password_title=Unohtuiko salasana forgot_password=Unohtuiko salasana? sign_up_now=Tarvitsetko tilin? Rekisteröidy nyt. @@ -210,6 +272,7 @@ sign_up_successful=Tilin luonti onnistui. confirmation_mail_sent_prompt=Uusi varmistussähköposti on lähetetty osoitteeseen %s, ole hyvä ja tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi rekisteröintiprosessin valmiiksi. must_change_password=Vaihda salasanasi allow_password_change=Vaadi käyttäjää vaihtamaan salasanansa (suositeltava) +reset_password_mail_sent_prompt=Varmistussähköposti on lähetetty osoitteeseen %s. Tarkista saapuneet seuraavan %s tunnin sisällä saadaksesi tilin palauttamisen valmiiksi. active_your_account=Aktivoi tilisi account_activated=Tili on aktivoitu prohibit_login=Kirjautuminen estetty @@ -218,9 +281,11 @@ resent_limit_prompt=Olet jo tilannut aktivointisähköpostin hetki sitten. Ole h has_unconfirmed_mail=Hei %s, sinulla on varmistamaton sähköposti osoite (%s). Jos et ole saanut varmistus sähköpostia tai tarvitset uudelleenlähetyksen, ole hyvä ja klikkaa allaolevaa painiketta. resend_mail=Klikkaa tästä uudelleenlähettääksesi aktivointi sähköpostisi email_not_associate=Tätä sähköpostiosoitetta ei ole liitetty mihinkään tiliin. +send_reset_mail=Lähetä tilin palautussähköposti reset_password=Tilin palautus invalid_code=Vahvistusavain on virheellinen tai vanhentunut. reset_password_helper=Palauta käyttäjätili +reset_password_wrong_user=Olet kirjautunut sisään nimellä %s, mutta tilin palautuslinkki on tarkoitettu kohteelle %s password_too_short=Salasanan pituus ei voi olla vähemmän kuin %d merkkiä. non_local_account=Ei-lokaalit käyttäjät eivät voi päivittää salasanojaan Gitean web-käyttöliittymän kautta. verify=Vahvista @@ -232,10 +297,12 @@ twofa_scratch_token_incorrect=Kertakäyttökoodisi on virheellinen. login_userpass=Kirjaudu sisään login_openid=OpenID oauth_signup_tab=Rekisteröi uusi tili +oauth_signup_title=Viimeistele tili oauth_signup_submit=Viimeistele tili oauth_signin_tab=Linkitä olemassa olevaan tiliin oauth_signin_title=Kirjaudu sisään valtuuttaaksesi linkitetyn tilin oauth_signin_submit=Yhdistä tiliin +oauth.signin.error.access_denied=Valtuutuspyyntö on evätty. openid_connect_submit=Connect openid_connect_title=Yhdistä olemassaolevaan tiliin openid_connect_desc=Valittu OpenID-osoite on tuntematon. Liitä se uuteen tiliin täällä. @@ -251,22 +318,38 @@ authorize_title=Valtuutatko "%s" pääsemään tilillesi? authorization_failed=Käyttöoikeuden varmistus epäonnistui authorization_failed_desc=Käyttöoikeuden varmistus epäonnistui virheellisen pyynnön takia. Ota yhteyttä sovelluksen ylläpitäjään, jonka olet yrittänyt valtuuttaa. sspi_auth_failed=SSPI todennus epäonnistui +password_pwned=Valitsemasi salasana on varastettujen salasanojen luettelossa, joka on aiemmin paljastunut julkisissa tietorikkomuksissa. Yritä uudelleen toisella salasanalla. [mail] +view_it_on=Näytä %s +link_not_working_do_paste=Eikö toimi? Yritä kopioida ja liittää se selaimeesi. +hi_user_x=Hei %s, activate_account=Ole hyvä ja aktivoi tilisi activate_email=Vahvista sähköpostiosoitteesi +activate_email.title=%s, vahvista sähköpostiosoitteesi register_notify=Tervetuloa Giteaan +register_notify.text_2=Voit nyt kirjautua käyttäjätunnuksella: %s. reset_password=Palauta käyttäjätili +reset_password.title=%s, olet pyytänyt tilisi palauttamista register_success=Rekisteröinti onnistui +issue.x_mentioned_you=@%s mainitsi sinut: +issue.action.push_1=@%[1]s työnsi %[3]d commitin kohteeseen %[2]s +issue.action.push_n=@%[1]s työnsi %[3]d committia kohteeseen %[2]s +release.title=Otsikko: %s +release.note=Huomautus: +release.downloads=Lataukset: +release.download.zip=Lähdekoodi (ZIP) +release.download.targz=Lähdekoodi (TAR.GZ) +repo.transfer.to_you=sinä [modal] @@ -287,6 +370,7 @@ AuthName=Luvan nimi AdminEmail=Ylläpito sähköposti NewBranchName=Uuden haaran nimi +CommitSummary=Commitin yhteenveto CommitMessage=Commitin viesti CommitChoice=Commitin valinta TreeName=Tiedostopolku @@ -302,17 +386,24 @@ max_size_error=` täytyy sisältää enintään %s merkkiä.` email_error=` ei ole kelvollinen sähköpostiosoite.` include_error=` täytyy sisältää tekstiosa '%s'.` unknown_error=Tuntematon virhe: +captcha_incorrect=CAPTCHA koodi on virheellinen. password_not_match=Salasanat eivät täsmää. +lang_select_error=Valitse kieli listalta. username_been_taken=Käyttäjätunnus on jo varattu. +repo_name_been_taken=Repon nimi on jo käytössä. +repository_force_private=Pakotettu yksityisyys käytössä: yksityisiä repoja ei voida muuttaa julkisiksi. org_name_been_taken=Organisaation nimi on jo käytössä. team_name_been_taken=Tiimin nimi on jo varattu. email_been_used=Sähköpostiosoite on jo käytössä. +email_invalid=Sähköpostiosoite on virheellinen. +openid_been_used=OpenID-osoite '%s' on jo käytössä. username_password_incorrect=Käyttäjätunnus tai salasana on virheellinen. password_lowercase_one=Ainakin yksi pieni kirjan password_uppercase_one=Ainakin yksi iso kirjain password_digit_one=Ainakin yksi numero password_special_one=Ainakin yksi erikoismerkki (välimerkki, sulut, lainausmerkit, jne.) +enterred_invalid_org_name=Antamasi organisaation nimi on virheellinen. enterred_invalid_password=Syöttämäsi salasana oli väärä. user_not_exist=Käyttäjää ei ole olemassa. team_not_exist=Tiimiä ei ole olemassa. @@ -333,16 +424,20 @@ repositories=Repot activity=Julkinen toiminta followers=Seuraajat starred=Tähdelliset repot +projects=Projektit following=Seurataan follow=Seuraa unfollow=Lopeta seuraaminen +heatmap.loading=Ladataan lämpökarttaa… user_bio=Elämäkerta form.name_reserved=Käyttäjätunnus '%s' on varattu. +form.name_chars_not_allowed=Käyttäjänimi '%s' sisältää virheellisiä merkkejä. [settings] profile=Profiili account=Tili +appearance=Ulkoasu password=Salasana security=Turvallisuus avatar=Profiilikuva @@ -356,8 +451,10 @@ twofa=Kaksivaiheinen todennus account_link=Linkitetyt tilit organization=Organisaatiot uid=Käyttäjä ID +webauthn=Turva-avaimet public_profile=Julkinen profiili +biography_placeholder=Kerro itsestäsi profile_desc=Sähköpostiosoitettasi käytetään ilmoituksiin ja muihin toimintoihin. password_username_disabled=Ei-paikalliset käyttäjät eivät voi muuttaa käyttäjätunnustaan. Ole hyvä ja ota yhteyttä sivuston ylläpitäjään saadaksesi lisätietoa. full_name=Kokonimi @@ -365,6 +462,9 @@ website=Nettisivut location=Sijainti update_theme=Päivitä teema update_profile=Päivitä profiili +update_language=Päivitä kieli +update_language_not_found=Kieli '%s' ei ole käytettävissä. +update_language_success=Kieli on päivitetty. update_profile_success=Profiilisi on päivitetty. change_username=Käyttäjätunnuksesi on muutettu. change_username_prompt=Huomio: käyttäjätunnuksen muutos muuttaa myös tilisi URL:n. @@ -372,6 +472,23 @@ continue=Jatka cancel=Peruuta language=Kieli ui=Teema +hidden_comment_types=Piilotetut kommenttityypit +comment_type_group_reference=Viittaus +comment_type_group_label=Tunniste +comment_type_group_milestone=Merkkipaalu +comment_type_group_assignee=Osoitettu henkilölle +comment_type_group_title=Otsikko +comment_type_group_branch=Haara +comment_type_group_time_tracking=Ajan seuranta +comment_type_group_deadline=Määräaika +comment_type_group_dependency=Riippuvuus +comment_type_group_lock=Lukituksen tila +comment_type_group_review_request=Arviointipyyntö +comment_type_group_pull_request_push=Lisätyt commitit +comment_type_group_project=Projekti +saved_successfully=Asetuksesi tallennettiin onnistuneesti. +privacy=Yksityisyys +keep_activity_private=Piilota toiminta profiilisivulta lookup_avatar_by_mail=Hae profiilikuva sähköpostin perusteella federated_avatar_lookup=Ulkopuolinen profiilikuvan haku @@ -398,17 +515,23 @@ primary=Ensisijainen activated=Aktivoitu requires_activation=Vaatii aktivoinnin primary_email=Tee ensisijainen +activate_email=Lähetä aktivointi +activations_pending=Odottaa aktivointia delete_email=Poista email_deletion=Poista sähköpostiosoite email_deletion_desc=Sähköpostiosoite ja siihen liittyvät tiedot poistetaan tililtäsi. Kyseisen sähköpostiosoitteen sisältävät commitit pysyvät muuttumattomia. Jatketaanko? email_deletion_success=Sähköpostiosoite on poistettu. theme_update_success=Teemasi on päivitetty. theme_update_error=Valittua teemaa ei löydy. +openid_deletion=Poista OpenID-osoite +openid_deletion_success=OpenID-osoite on poistettu. add_new_email=Lisää uusi sähköpostiosoite add_new_openid=Lisää uusi OpenID URI add_email=Lisää sähköpostiosoite add_openid=Lisää OpenID URI add_email_success=Uusi sähköpostiosoite on lisätty. +email_preference_set_success=Sähköpostin asetukset on asetettu onnistuneesti. +add_openid_success=Uusi OpenID-osoite on lisätty. keep_email_private=Piilota sähköpostiosoite keep_email_private_popup=Sähköpostiosoitteesi on piilotettu muilta käyttäjiltä. openid_desc=OpenID mahdollistaa todentamisen delegoinnin ulkopuoliselle palvelun tarjoajalle. @@ -422,10 +545,35 @@ ssh_helper=Tarvitsetko apua? Tutustu GitHubin oppaaseen Tarvitsetko apua? Katso GitHubin opas GPG:stä. add_new_key=Lisää SSH avain add_new_gpg_key=Lisää GPG-avain +key_content_ssh_placeholder=Alkaa sanoilla 'ssh-ed25519', 'ssh-rsa', 'ecdsa-sha2-nistp256', 'ecdsa-sha2-nistp384', 'ecdsa-sha2-nistp521', 'sk-ecdsa-sha2-nistp256@openssh.com', tai 'sk-ssh-ed25519@openssh.com' +key_content_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP PUBLIC KEY BLOCK-----' +ssh_key_name_used=Samanniminen SSH avain on jo olemassa tililläsi. +gpg_key_id_used=Julkinen GPG-avain samalla tunnuksella on jo olemassa. +gpg_no_key_email_found=Tämä GPG-avain ei vastaa mitään tiliisi liitettyä aktivoitua sähköpostiosoitetta. Se voidaan silti lisätä, jos allekirjoitat annetun pääsymerkin. +gpg_key_verified=Vahvistettu avain +gpg_key_verified_long=Avain on vahvistettu pääsymerkillä ja sitä voidaan käyttää todentamaan commitit, jotka vastaavat tämän käyttäjän aktivoituja sähköpostiosoitteita tämän avaimen kaikkien vastaavien identiteettien lisäksi. +gpg_key_verify=Vahvista +gpg_token_required=Sinun täytyy antaa allekirjoitus alla olevalle pääsymerkille +gpg_token=Pääsymerkki +gpg_token_help=Voit luoda allekirjoituksen käyttäen: +gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig +gpg_token_signature=Panssaroitu GPG-allekirjoitus +key_signature_gpg_placeholder=Alkaa sanoilla '-----BEGIN PGP SIGNATURE-----' +verify_gpg_key_success=GPG-avain '%s' on vahvistettu. +ssh_key_verified=Vahvistettu avain +ssh_key_verified_long=Avain on vahvistettu pääsymerkillä ja sitä voidaan käyttää todentamaan commitit, jotka vastaavat tämän käyttäjän aktivoituja sähköpostiosoitteita. +ssh_key_verify=Vahvista +ssh_token_required=Sinun täytyy antaa allekirjoitus alla olevalle pääsymerkille +ssh_token=Pääsymerkki +ssh_token_help=Voit luoda allekirjoituksen käyttäen: +ssh_token_signature=Panssaroitu SSH-allekirjoitus +key_signature_ssh_placeholder=Alkaa sanoilla '-----BEGIN SSH SIGNATURE-----' +verify_ssh_key_success=SSH avain '%s' on vahvistettu. subkeys=Aliavaimet key_id=Avain ID key_name=Avaimen nimi key_content=Sisältö +principal_content=Sisältö add_key_success=SSH-avain '%s' on lisätty. add_gpg_key_success=GPG-avain '%s' lisättiin. delete_key=Poista @@ -435,13 +583,22 @@ gpg_key_deletion_desc=GPG-avaimen poistaminen peruuttaa sillä allekirjoitettuje gpg_key_deletion_success=GPG-avain on poistettu. add_on=Lisätty valid_until=Vanhenee +valid_forever=Voimassa ikuisesti last_used=Käytetty viimeksi no_activity=Ei viimeaikaista toimintaa +can_read_info=Luku +can_write_info=Kirjoitus +show_openid=Näytä profiilissa +hide_openid=Piilota profiilista +ssh_disabled=SSH pois käytöstä manage_social=Hallitse liitettyjä sosiaalisia tilejä +manage_access_token=Hallitse pääsymerkkejä generate_new_token=Luo uusi pääsymerkki +new_token_desc=Pääsymerkkiä käyttävillä sovelluksilla on täysi pääsy tiliisi. token_name=Pääsymerkin nimi generate_token=Luo pääsymerkki +generate_token_success=Uusi pääsymerkkisi on nyt luotu. Kopioi se nyt, koska sitä ei näytetä enää uudelleen. delete_token=Poista access_token_deletion=Poista pääsymerkki @@ -459,8 +616,15 @@ oauth2_application_edit=Muokkaa twofa_desc=Kaksivaiheinen todennus parantaa tilisi turvallisuutta. +twofa_is_enrolled=Tilisi käyttää kaksivaiheista vahvistusta. +twofa_not_enrolled=Tilisi ei tällä hetkellä käytä kaksivaiheista vahvistusta. +twofa_enroll=Ota kaksivaiheinen vahvistus käyttöön twofa_disabled=Kaksivaiheinen todennus on otettu pois käytöstä. +scan_this_image=Skannaa tämä kuva tunnistautumissovelluksellasi: +or_enter_secret=Tai kirjoita salainen avain: %s +twofa_enrolled=Tiliisi on otettu käyttöön kaksivaiheinen vahvistus. Ota palautustunnus (%s) talteen turvalliseen paikkaan, sillä se näytetään vain kerran! +webauthn_nickname=Nimimerkki manage_account_links=Hallitse linkitettyjä tilejä manage_account_links_desc=Nämä ulkoiset tilit on linkitetty Gitea tiliisi. @@ -476,37 +640,61 @@ delete_prompt=Tämä toiminto poistaa käyttäjätilisi pysyvästi. Toimintoa Voit siirtää repon. owner=Omistaja +owner_helper=Jotkin organisaatiot eivät välttämättä näy pudotusvalikossa, koska repojen maksimimäärää on rajoitettu. repo_name=Repon nimi repo_name_helper=Hyvä repon nimi on lyhyt, mieleenpainuva ja yksilöllinen. +repo_size=Repon koko template=Malli template_select=Valitse malli. +template_helper=Tee reposta mallipohja visibility=Näkyvyys visibility_description=Vain omistaja tai organisaation jäsenet, jos heillä on oikeudet, voivat nähdä sen. visibility_helper=Tee reposta yksityinen +visibility_helper_forced=Sivuston ylläpitäjä pakottaa uudet repot olemaan yksityisiä. fork_repo=Forkkaa repo fork_from=Forkkaa lähteestä fork_visibility_helper=Forkatun repon näkyvyyttä ei voi muuttaa. +clone_in_vsc=Kloonaa VS Codessa +download_zip=Lataa ZIP +download_tar=Lataa TAR.GZ repo_desc=Kuvaus repo_lang=Kieli repo_gitignore_helper=Valitse .gitignore mallit. issue_labels=Ongelmien tunnisteet +issue_labels_helper=Valitse pohja ongelmien nimilapuille. license=Lisenssi license_helper=Valitse lisenssitiedosto. readme=README auto_init=Alusta repo (Luo .gitignore, License ja README) create_repo=Luo repo default_branch=Oletus branch +mirror_prune=Karsi watchers=Tarkkailijat stargazers=Tähtiharrastajat forks=Haarat pick_reaction=Valitse reaktiosi +delete_preexisting_label=Poista +desc.private=Yksityinen +desc.public=Julkinen +desc.private_template=Yksityinen malli +desc.public_template=Malli +desc.internal=Sisäinen +template.git_hooks=Git-koukut +template.webhooks=Webkoukut template.topics=Aiheet template.avatar=Profiilikuva template.issue_labels=Ongelmien tunnisteet @@ -522,15 +710,18 @@ migrate_items_pullrequests=Vetopyynnöt migrate_items_releases=Julkaisut migrate_repo=Siirrä repo migrate.clone_address=Migraation / Kloonaa URL osoitteesta +migrate.github_token_desc=Voit laittaa yhden tai useamman pääsymerkin pilkulla erotellen tähän nopeuttaaksesi migraatiota GitHub APIn vauhtirajojen takia. VAROITUS: Tämän ominaisuuden väärinkäyttö voi rikkoa palveluntarjoajan ehtoja ja johtaa tilin estämiseen. migrate.permission_denied=Sinun ei sallita tuovan paikallisia repoja. migrate.failed=Siirto epäonnistui: %v +migrate.migrate_items_options=Pääsymerkki vaaditaan lisäkohteiden siirtämiseen +migrate.migrating_failed.error=Virhe: %s mirror_from=peilaus alkaen forked_from=forkattu lähteestä unwatch=Lopeta tarkkailu watch=Tarkkaile -unstar=Peru ääni -star=Äänestä +unstar=Poista tähti +star=Tähti download_archive=Lataa varasto no_desc=Ei kuvausta @@ -550,7 +741,10 @@ labels=Tunnisteet milestones=Merkkipaalut commits=Commitit +commit=Commit releases=Julkaisut +tag=Tagi +released_this=julkaisi tämän file_raw=Raaka file_history=Historia file_view_raw=Näytä raaka @@ -558,6 +752,8 @@ file_permalink=Pysyvä linkki video_not_supported_in_browser=Selaimesi ei tue HTML5 video-tagia. audio_not_supported_in_browser=Selaimesi ei tue HTML5 audio-tagia. +blame=Selitys +download_file=Lataa tiedosto normal_view=Normaali näkymä line=rivi lines=rivejä @@ -586,6 +782,7 @@ editor.create_new_branch_np=Luo uusi haara tälle commitille. editor.cancel=Peruuta editor.filename_cannot_be_empty=Tiedostonimi ei voi olla tyhjä. editor.filename_is_invalid=Tiedostonnimi on epäkelpo: '%s'. +editor.branch_already_exists=Haara '%s' on jo olemassa tässä repossa. editor.no_changes_to_show=Ei muutoksia näytettäväksi. editor.add_subdir=Lisää hakemisto… editor.unable_to_upload_files=Tiedostojen lataaminen kohteeseen '%s' epäonnistui virheellä: %v @@ -601,9 +798,32 @@ commits.date=Päivämäärä commits.older=Vanhemmat commits.newer=Uudemmat commits.signed_by=Allekirjoittanut - - - +commits.gpg_key_id=GPG avaimen ID +commits.ssh_key_fingerprint=SSH avaimen sormenjälki + + + +projects=Projektit +projects.description_placeholder=Kuvaus +projects.create=Luo projekti +projects.title=Otsikko +projects.new=Uusi projekti +projects.create_success=Projekti '%s' on luotu. +projects.deletion=Poista projekti +projects.deletion_success=Projekti on poistettu. +projects.edit=Muokkaa projektia +projects.modify=Päivitä projekti +projects.edit_success=Projekti '%s' on päivitetty. +projects.type.basic_kanban=Yksinkertainen Kanban +projects.type.uncategorized=Luokittelematon +projects.board.edit=Muokkaa luetteloa +projects.board.new_submit=Lähetä +projects.board.new=Uusi taulu +projects.board.set_default=Aseta oletukseksi +projects.board.delete=Poista taulu +projects.board.color=Väri +projects.open=Avaa +projects.close=Sulje issues.desc=Ongelmien, tehtävien ja merkkipaalujen hallinta. issues.filter_milestones=Suodata merkkipaalu @@ -620,12 +840,14 @@ issues.new.closed_milestone=Suljetut merkkipaalut issues.new.assignees=Käsittelijä issues.new.clear_assignees=Tyhjennä käsittelijä issues.new.no_assignees=Ei käsittelijää +issues.choose.blank=Oletus issues.no_ref=Haaraa/tagia ei määritelty issues.create=Ilmoita ongelma issues.new_label=Uusi tunniste issues.new_label_placeholder=Tunnisteen nimi issues.new_label_desc_placeholder=Kuvaus issues.create_label=Luo tunniste +issues.label_templates.helper=Valitse tunnistejoukko issues.add_milestone_at=`lisäsi tämän merkkipaaluun %s %s` issues.deleted_milestone=`(poistettu)` issues.self_assign_at=`itse otti tämän käsittelyyn %s` @@ -641,6 +863,7 @@ issues.filter_type.all_issues=Kaikki ongelmat issues.filter_type.assigned_to_you=Osoitettu sinulle issues.filter_type.created_by_you=Ilmoittamasi issues.filter_type.mentioning_you=Jotka mainitsee sinut +issues.filter_type.review_requested=Arvostelua pyydetty issues.filter_sort=Lajittele issues.filter_sort.latest=Uusin issues.filter_sort.oldest=Vanhin @@ -658,6 +881,7 @@ issues.action_open=Avaa issues.action_close=Sulje issues.action_label=Tunniste issues.action_milestone=Merkkipaalu +issues.action_milestone_no_select=Ei merkkipaalua issues.opened_by=%[1]s avasi %[3]s issues.previous=Edellinen issues.next=Seuraava @@ -725,9 +949,11 @@ issues.add_time_minutes=Minuuttia issues.add_time_sum_to_small=Aikaa ei syötetty. issues.time_spent_from_all_authors=`Käytetty kokonaisaika: %s` issues.due_date=Määräpäivä +issues.due_date_form=vvvv-kk-pp issues.due_date_form_edit=Muokkaa issues.due_date_form_remove=Poista issues.due_date_not_set=Määräpäivää ei asetettu. +issues.due_date_overdue=Myöhässä issues.dependency.title=Riippuvuudet issues.dependency.add=Lisää riippuvuus… issues.dependency.cancel=Peru @@ -735,6 +961,12 @@ issues.dependency.remove=Poista issues.dependency.remove_info=Poistä tämä riippuvuus issues.review.self.approval=Et voi hyväksyä omia vetopyyntöjä. issues.review.approve=hyväksyi nämä muutokset %s +issues.review.left_comment=jätti kommentin +issues.review.pending=Odottaa +issues.reference_issue.body=Kuvaus +issues.content_history.deleted=poistettu +issues.content_history.edited=muokattu +issues.content_history.created=luotu pulls.new=Uusi pull pyyntö @@ -776,12 +1008,17 @@ milestones.edit_success=Merkkipaalu '%s' on päivitetty. milestones.filter_sort.most_issues=Eniten ongelmia milestones.filter_sort.least_issues=Vähiten ongelmia +signing.wont_sign.always=Commitit ovat aina allekirjoitettuja wiki=Wiki +wiki.welcome=Tervetuloa Wikiin. +wiki.welcome_desc=Wikissä voit kirjoittaa ja jakaa dokumentaatiota käyttäjien kesken. +wiki.create_first_page=Luo ensimmäinen sivu wiki.page=Sivu wiki.filter_page=Suodatin sivu wiki.new_page=Sivu +wiki.default_commit_message=Kirjoita muistiinpano tästä päivityksestä (valinnainen). wiki.save_page=Tallenna sivu wiki.last_commit_info=%s muokkasi tätä sivua %s wiki.edit_page_button=Muokkaa @@ -814,6 +1051,7 @@ activity.new_issues_count_n=Uutta ongelmaa activity.new_issue_label=Avoinna activity.unresolved_conv_label=Auki activity.published_release_label=Julkaistu +activity.git_stats_pushed_1=on työntänyt activity.git_stats_file_1=%d tiedosto activity.git_stats_file_n=%d tiedostoa activity.git_stats_addition_1=%d lisäys @@ -850,6 +1088,7 @@ settings.danger_zone=Vaaravyöhyke settings.new_owner_has_same_repo=Uudella omistajalla on jo samanniminen repo. Ole hyvä ja valitse toinen nimi. settings.transfer=Siirrä omistajuus settings.transfer_form_title=Syötä repon nimi vahvistuksena: +settings.transfer_notices_3=- Jos arkisto on yksityinen ja se siirretään yksittäiselle käyttäjälle, tämä toiminto varmistaa, että käyttäjällä on ainakin lukuoikeudet (ja muuttaa käyttöoikeuksia tarvittaessa). settings.transfer_owner=Uusi omistaja settings.wiki_delete=Poista Wiki data settings.wiki_delete_desc=Repon wikin data poistaminen on pysyvä eikä voi peruuttaa. @@ -882,43 +1121,96 @@ settings.discord_username=Käyttäjätunnus settings.event_create=Luo settings.event_delete=Poista settings.event_release_desc=Julkaisu julkaistu, päivitetty tai poistettu varastosta. +settings.event_push=Työnnä settings.event_repository=Repo settings.event_issue_comment_desc=Ongelman kommentti luotu, muokattu tai poistettu. settings.event_pull_request=Vetopyyntö settings.update_webhook=Päivitä webkoukku +settings.delete_webhook=Poista webkoukku settings.recent_deliveries=Viimeisimmät toimitukset settings.hook_type=Koukkutyyppi settings.slack_token=Pääsymerkki settings.slack_domain=Verkkotunnus settings.slack_channel=Kanava -settings.deploy_keys=Deploy avaimet -settings.add_deploy_key=Lisää deploy avain +settings.web_hook_name_gitea=Gitea +settings.web_hook_name_gogs=Gogs +settings.web_hook_name_slack=Slack +settings.web_hook_name_discord=Discord +settings.web_hook_name_dingtalk=DingTalk +settings.web_hook_name_telegram=Telegram +settings.web_hook_name_matrix=Matrix +settings.web_hook_name_feishu=Feishu +settings.web_hook_name_larksuite=Lark Suite +settings.web_hook_name_packagist=Packagist +settings.deploy_keys=Julkaisuavaimet +settings.add_deploy_key=Lisää julkaisuavain +settings.deploy_key_desc=Julkaisuavaimilla on vain-luku oikeudet repoon. +settings.is_writable_info=Salli tämän julkaisuavaimen puskea repoon. +settings.no_deploy_keys=Julkaisuavaimia ei ole käytössä vielä. settings.title=Otsikko settings.deploy_key_content=Sisältö +settings.key_been_used=Julkaisuavain identtisellä sisällöllä on jo käytössä. +settings.key_name_used=Julkaisuavain samalla nimellä on jo olemassa. +settings.add_key_success=Julkaisuavain '%s' on lisätty. +settings.deploy_key_deletion=Poista julkaisuavain +settings.deploy_key_deletion_desc=Julkaisuavaimen poistaminen kumoaa sen pääsyn tähän repoon. Jatketaanko? +settings.deploy_key_deletion_success=Julkaisuavain on poistettu. settings.branches=Haarat settings.protected_branch=Haaran suojaus settings.branch_protection=Haaran '%s' suojaus settings.protect_this_branch=Ota haaran suojaus käyttöön +settings.protect_whitelist_deploy_keys=Lisää julkaisuavaimet sallittujen listalle mahdollistaaksesi repohin kirjoituksen. settings.protect_whitelist_users=Lista käyttäjistä joilla työntö oikeus: settings.protect_whitelist_search_users=Etsi käyttäjiä… settings.protect_merge_whitelist_committers_desc=Salli vain listaan merkittyjen käyttäjien ja tiimien yhdistää vetopyynnöt tähän haaraan. settings.protect_merge_whitelist_users=Lista käyttäjistä joilla yhdistämis-oikeus: settings.protect_required_approvals=Vaadittavat hyväksynnät: settings.protect_approvals_whitelist_users=Sallittujen tarkastajien lista: +settings.protect_protected_file_patterns_desc=Suojatut tiedostot, joita ei voi muuttaa suoraan, vaikka käyttäjällä olisi oikeudet lisätä, muokata tai poistaa tiedostoja tässä haarassa. Useita malleja voidaan erottaa puolipisteellä ('\;'). Katso github.com/gobwas/glob dokumentaatio mallisyntaksille. Esimerkkejä: .drone.yml, /docs/**/*.txt. +settings.protect_unprotected_file_patterns_desc=Suojaamattomat tiedostot, joita voidaan muuttaa suoraan, jos käyttäjällä on kirjoitusoikeudet, ohittaen push-rajoituksen. Useita kuvioita voidaan erottaa puolipisteellä ('\;'). Katso github.com/gobwas/glob dokumentaatio kuviosyntaksille. Esimerkkejä: .drone.yml, /docs/**/*.txt. settings.update_protect_branch_success=Haaran '%s' suojaus on päivitetty. settings.remove_protected_branch_success=Haaran '%s' suojaus on poistettu käytöstä. settings.choose_branch=Valitse haara… settings.no_protected_branch=Suojattuja haaroja ei ole. settings.edit_protected_branch=Muokkaa settings.protected_branch_required_approvals_min=Vaadittavat hyväksynnät ei voi olla negatiivinen. +settings.tags=Tagit +settings.tags.protection.pattern=Tagin kuvio +settings.tags.protection.pattern.description=Voit käyttää yhtä nimeä tai glob-kuviota tai säännöllistä lauseketta, joka täsmää useisiin tageihin. Lue lisää suojatut tagit oppaasta. +settings.bot_token=Botti pääsymerkki +settings.matrix.homeserver_url=Kotipalvelimen URL +settings.matrix.access_token=Pääsymerkki settings.archive.button=Arkistoi repo settings.archive.header=Arkistoi tämä repo settings.lfs=LFS +settings.lfs_filelist=LFS-tiedostot tallennettu tähän repoon +settings.lfs_no_lfs_files=LFS-tiedostoja ei ole tallennettu tähän repoon. +settings.lfs_findcommits=Etsi commitit +settings.lfs_lfs_file_no_commits=LFS-tiedostolle ei löytynyt committeja +settings.lfs_noattribute=Tällä polulla ei ole lukittavaa attribuuttia oletushaarassa +settings.lfs_delete=Poista LFS-tiedosto OID:lla %s +settings.lfs_delete_warning=LFS-tiedoston poistaminen voi aiheuttaa 'object does not exists'-virheitä checkouttattaessa. Oletko varma? +settings.lfs_findpointerfiles=Etsi osoitintiedostoja +settings.lfs_locks=Lukot +settings.lfs_invalid_locking_path=Virheellinen polku: %s +settings.lfs_invalid_lock_directory=Hakemistoa ei voida lukita: %s +settings.lfs_lock_already_exists=Lukitus on jo olemassa: %s +settings.lfs_lock_path=Lukittavan tiedostopolku... +settings.lfs_locks_no_locks=Ei lukkoja +settings.lfs_lock_file_no_exist=Lukittua tiedostoa ei ole olemassa oletushaarassa +settings.lfs_force_unlock=Pakota lukituksen avaus +settings.lfs_pointers.found=Löytyi %d blob osoitinta - %d yhdistettyö, %d yhdistämätöntä (%d puuttuu varastosta) +settings.lfs_pointers.sha=Blob SHA settings.lfs_pointers.oid=OID +settings.lfs_pointers.inRepo=Repossa +settings.lfs_pointers.exists=Löytyy varastosta +settings.lfs_pointers.accessible=Saatavilla käyttäjälle diff.browse_source=Selaa lähdekoodia diff.parent=vanhempi +diff.commit=commit diff.git-notes=Muistiinpanot +diff.options_button=Vertailun asetukset diff.show_split_view=Jaettu näkymä diff.show_unified_view=Yhdistetty näkymä diff.whitespace_button=Tyhjämerkki @@ -938,6 +1230,7 @@ diff.review.comment=Kommentoi diff.review.approve=Hyväksy release.releases=Julkaisut +release.tags=Tagit release.new_release=Uusi julkaisu release.draft=Työversio release.prerelease=Esiversio @@ -964,6 +1257,7 @@ release.downloads=Lataukset branch.name=Haaran nimi branch.delete_head=Poista branch.delete=Poista haara '%s' +branch.create_branch=Luo haara %s @@ -1003,7 +1297,9 @@ settings.permission=Käyttöoikeudet settings.visibility=Näkyvyys settings.visibility.public=Julkinen settings.visibility.limited=Rajoitettu (näkyvä vain kirjautuneille käyttäjille) +settings.visibility.limited_shortname=Rajattu settings.visibility.private=Yksityinen (näkyvä vain organisaation jäsenille) +settings.visibility.private_shortname=Yksityinen settings.update_settings=Päivitä asetukset settings.delete=Poista organisaatio @@ -1054,6 +1350,7 @@ users=Käyttäjätilit organizations=Organisaatiot repositories=Repot authentication=Todennuslähteet +emails=Käyttäjien sähköpostit config=Asetukset notices=Järjestelmän ilmoitukset monitor=Valvonta @@ -1062,10 +1359,13 @@ last_page=Viimeisin total=Yhteensä: %d dashboard.statistic=Yhteenveto +dashboard.operations=Huoltotoimet dashboard.system_status=Järjestelmän tila dashboard.operation_name=Toiminnon nimi dashboard.operation_switch=Vaihda dashboard.operation_run=Suorita +dashboard.delete_inactive_accounts=Poista kaikki aktivoimattomat käyttäjät +dashboard.delete_repo_archives=Poista kaikki repojen arkistot (ZIP, TAR.GZ, jne..) dashboard.server_uptime=Palvelimen Uptime dashboard.current_goroutine=Nykyiset Goroutinet dashboard.current_memory_usage=Nykyinen muistinkäyttö @@ -1100,23 +1400,48 @@ users.name=Käyttäjätunnus users.full_name=Kokonimi users.activated=Aktivoitu users.admin=Ylläpito +users.restricted=Rajoitettu +users.2fa=2FA users.repos=Repot users.created=Luotu users.last_login=Viimeksi kirjautunut +users.never_login=Ei koskaan kirjautunut users.edit=Muokkaa users.auth_source=Todennuslähde users.local=Paikallinen users.password_helper=Jätä salasanakenttä tyhjäksi jos haluat pitää sen muuttamattomana. users.update_profile_success=Käyttäjän tili on päivitetty. users.edit_account=Muokkaa käyttäjän tiliä +users.max_repo_creation_desc=(Aseta -1 käyttääksesi globaalia oletusrajaa.) +users.is_activated=Käyttäjätili on aktivoitu +users.prohibit_login=Ota sisäänkirjautuminen pois käytöstä +users.is_admin=Ylläpitäjä +users.is_restricted=Rajoitettu tili +users.allow_git_hook=Voi luoda Git koukkuja +users.allow_create_organization=Voi luoda organisaatioita users.update_profile=Päivitä käyttäjän tili users.delete_account=Poista käyttäjän tili +users.list_status_filter.menu_text=Suodata +users.list_status_filter.reset=Tyhjennä +users.list_status_filter.is_active=Aktiivinen +users.list_status_filter.not_active=Ei-aktiivinen +users.list_status_filter.is_admin=Ylläpitäjä +users.list_status_filter.not_admin=Ei ylläpitäjä +users.list_status_filter.is_restricted=Rajoitettu +users.list_status_filter.not_restricted=Ei rajoitettu +users.list_status_filter.is_prohibit_login=Kirjautuminen estetty +users.list_status_filter.not_prohibit_login=Kirjautuminen sallittu +users.list_status_filter.is_2fa_enabled=2FA käytössä +users.list_status_filter.not_2fa_enabled=2FA ei käytössä emails.email_manage_panel=Käyttäjien sähköpostien hallinta emails.primary=Ensisijainen emails.activated=Aktivoitu emails.filter_sort.email=Sähköposti +emails.filter_sort.email_reverse=Sähköposti (käänteinen) emails.filter_sort.name=Käyttäjänimi +emails.filter_sort.name_reverse=Käyttäjänimi (käänteinen) +emails.duplicate_active=Tämä sähköpostiosoite on jo käytössä toisella käyttäjällä. orgs.org_manage_panel=Organisaatioiden hallinta orgs.name=Nimi @@ -1129,11 +1454,12 @@ repos.owner=Omistaja repos.name=Nimi repos.private=Yksityinen repos.watches=Tarkkailijat -repos.stars=Äänet +repos.stars=Tähdet repos.forks=Haarat repos.issues=Ongelmat repos.size=Koko +packages.owner=Omistaja @@ -1155,12 +1481,14 @@ auths.user_dn=Käyttäjä DN auths.search_page_size=Sivukoko auths.filter=Käyttäjäsuodatin auths.admin_filter=Ylläpitosuodatin +auths.restricted_filter=Rajoitettu suodatin auths.smtp_auth=SMTP todennustyyppi auths.smtphost=SMTP isäntä auths.smtpport=SMTP portti auths.allowed_domains=Sallitut verkkotunnukset auths.skip_tls_verify=Ohita TLS tarkistaminen auths.pam_service_name=PAM palvelun nimi +auths.oauth2_tokenURL=Pääsymerkki URL auths.enable_auto_register=Ota käyttöön automaattinen rekisteröinti auths.tips=Vinkit auths.tips.oauth2.general=OAuth2-autentikointi @@ -1217,9 +1545,7 @@ config.queue_length=Jonon pituus config.deliver_timeout=Toimitus aikakatkaisu config.mailer_enabled=Käytössä -config.mailer_disable_helo=Poista käytöstä HELO config.mailer_name=Nimi -config.mailer_host=Isäntä config.mailer_user=Käyttäjä config.oauth_config=OAuth asetukset @@ -1285,6 +1611,8 @@ notices.op=Toiminta create_repo=luotu repo %s rename_repo=uudelleennimetty repo %[1]s nimelle %[3]s transfer_repo=siirretty repo %s kohteeseen %s +push_tag=työnsi tagin %[3]s kohteeseen %[4]s +compare_commits_general=Vertaa committeja [tool] ago=%s sitten @@ -1324,8 +1652,29 @@ mark_as_unread=Merkitse lukemattomaksi mark_all_as_read=Merkitse kaikki luetuiksi [gpg] +error.no_committer_account=Committaajan sähköpostiosoitteeseen ei ole linkitetty tiliä +error.not_signed_commit=Ei allekirjoitettu committi [units] [packages] +title=Paketit +desc=Hallitse repon paketteja. +empty=Täällä ei vielä ole paketteja. +empty.documentation=Lisätietoa pakettirekisteristä löydät dokumentaatiosta. +filter.type=Tyyppi +filter.type.all=Kaikki +filter.no_result=Suodattimesi ei tuottanut tuloksia. +installation=Asennus +details.author=Tekijä +composer.documentation=Lisätietoa Composer-rekisteristä löydät dokumentaatiosta. +conan.documentation=Lisätietoa Conan-rekisteristä löydät dokumentaatiosta. +container.documentation=Lisätietoa Container-rekisteristä löydätdokumentaatiosta. +generic.documentation=Lisätietoa yleisestä pakettirekisteristä löydät dokumentaatiosta. +helm.documentation=Lisätietoa Helm-rekisteristä löydät dokumentaatiosta. +maven.documentation=Lisätietoa Maven-rekisteristä löydät dokumentaatiosta. +nuget.documentation=Lisätietoa NuGet-rekisteristä löydät dokumentaatiosta. +npm.documentation=Lisätietoa npm-rekisteristä löydät dokumentaatiosta. +pypi.documentation=Lisätietoa PyPI-rekisteristä löydät dokumentaatiosta. +rubygems.documentation=Lisätietoa RubyGems-rekisteristä löydät dokumentaatiosta. diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index acd17f88c595..18eb44b16a3d 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -9,7 +9,6 @@ sign_out=Déconnexion sign_up=S'inscrire link_account=Lier un Compte register=S'inscrire -website=Site web version=Version powered_by=Propulsé par %s page=Page @@ -43,6 +42,11 @@ webauthn_error=Impossible de lire votre clé de sécurité. webauthn_unsupported_browser=Votre navigateur ne prend actuellement pas en charge WebAuthn. webauthn_error_unknown=Une erreur indéterminée s'est produite. Veuillez réessayer. webauthn_error_insecure=WebAuthn ne prend en charge que les connexions sécurisées. Pour les tests via HTTP, vous pouvez utiliser l'origine "localhost" ou "127.0.0.1" +webauthn_error_unable_to_process=Le serveur n'a pas pu traiter votre demande. +webauthn_error_duplicated=La clé de sécurité n'est pas autorisée pour cette demande. Veuillez vous assurer que la clé n'est pas déjà enregistrée. +webauthn_error_empty=Vous devez définir un nom pour cette clé. +webauthn_error_timeout=Le délai d'attente imparti a été atteint avant que votre clé ne puisse être lue. Veuillez recharger la page pour réessayer. +webauthn_reload=Recharger repository=Dépôt organization=Organisation @@ -103,7 +107,12 @@ never=Jamais rss_feed=Flux RSS [error] +occurred=Une erreur s’est produite +report_message=Si vous êtes sûr qu'il s'agit d'un bug de Gitea, cherchez s’il existe des tickets sur GitHub ou ouvrez-en un nouveau si nécessaire. missing_csrf=Requête incorrecte: aucun jeton CSRF présent +invalid_csrf=Requête incorrecte : jeton CSRF invalide +not_found=La cible n'a pu être trouvée. +network_error=Erreur réseau [startpage] app_desc=Un service Git auto-hébergé sans prise de tête @@ -169,7 +178,8 @@ log_root_path_helper=Les fichiers de journalisation seront écrits dans ce répe optional_title=Paramètres facultatifs email_title=Paramètres E-mail -smtp_host=Hôte SMTP +smtp_addr=Hôte SMTP +smtp_port=Port SMTP smtp_from=Envoyer les e-mails en tant que smtp_from_helper=Adresse e-mail utilisée par Gitea. Veuillez entrer votre e-mail directement ou sous la forme . mailer_user=Utilisateur SMTP @@ -260,6 +270,7 @@ search=Rechercher code=Code search.fuzzy=Approximative search.match=Exacte +code_search_unavailable=Actuellement, la recherche de code n'est pas disponible. Veuillez contacter l'administrateur de votre site. repo_no_results=Aucun dépôt correspondant n'a été trouvé. user_no_results=Aucun utilisateur correspondant n'a été trouvé. org_no_results=Aucune organisation correspondante n'a été trouvée. @@ -273,6 +284,7 @@ register_helper_msg=Déjà enregistré ? Connectez-vous ! social_register_helper_msg=Déjà inscrit ? Connectez-vous ! disable_register_prompt=Les inscriptions sont désactivées. Veuillez contacter l'administrateur du site. disable_register_mail=La confirmation par e-mail à l'inscription est désactivée. +manual_activation_only=Contactez l'administrateur de votre site pour terminer l'activation. remember_me=Mémoriser cet appareil forgot_password_title=Mot de passe oublié forgot_password=Mot de passe oublié ? @@ -311,6 +323,9 @@ oauth_signup_submit=Finaliser la création du compte oauth_signin_tab=Lier à un compte existant oauth_signin_title=Connectez-vous pour autoriser le compte lié oauth_signin_submit=Lier un compte +oauth.signin.error=Une erreur s'est produite lors du traitement de la demande d'autorisation. Si cette erreur persiste, veuillez contacter l'administrateur du site. +oauth.signin.error.access_denied=La demande d'autorisation a été refusée. +oauth.signin.error.temporarily_unavailable=L'autorisation a échoué car le serveur d'authentification est temporairement indisponible. Veuillez réessayer plus tard. openid_connect_submit=Se connecter openid_connect_title=Se connecter à un compte existant openid_connect_desc=L'URI OpenID choisie est inconnue. Associez-le à un nouveau compte ici. @@ -357,6 +372,7 @@ reset_password.text=Veuillez cliquer sur le lien suivant pour récupérer votre register_success=Inscription réussie +issue_assigned.pull=@%[1]s vous a assigné à la demande d’ajout %[2]s dans le dépôt %[3]s. issue_assigned.issue=@%[1]s vous a assigné le ticket %[2]s dans le dépôt %[3]s. issue.x_mentioned_you=@%s vous a mentionné: @@ -972,6 +988,9 @@ file_view_rendered=Voir le rendu file_view_raw=Voir le Raw file_permalink=Lien permanent file_too_large=Le fichier est trop gros pour être affiché. +invisible_runes_line=`Cette ligne contient des caractères Unicode invisibles` +ambiguous_runes_line=`Cette ligne contient des caractères Unicode ambigus` +ambiguous_character=`%[1]c [U+%04[1]X] peut être confondu avec %[2]c [U+%04[2]X]` file_copy_permalink=Copier le lien permanent video_not_supported_in_browser=Votre navigateur ne supporte pas le tag HTML5 "video". @@ -989,6 +1008,7 @@ normal_view=Vue normale line=ligne lines=lignes +editor.add_file=Ajouter un fichier editor.new_file=Nouveau fichier editor.upload_file=Téléverser un fichier editor.edit_file=Modifier le fichier @@ -1012,6 +1032,10 @@ editor.add_tmpl=Ajouter '' editor.add=Ajouter '%s' editor.update=Mise à jour de '%s' editor.delete=Supprimer '%s' +editor.patch=Appliquer le correctif +editor.patching=Correction: +editor.fail_to_apply_patch=Impossible d'appliquer le correctif '%s' +editor.new_patch=Nouveau correctif editor.commit_message_desc=Ajouter une description détaillée facultative… editor.signoff_desc=Ajout d'un trailer Signed-off-by par le committeur à la fin du message du journal de commit. editor.commit_directly_to_this_branch=Soumettre directement dans la branche %s. @@ -1036,6 +1060,8 @@ editor.commit_empty_file_text=Le fichier que vous allez commiter est vide. Conti editor.no_changes_to_show=Il n’y a aucun changement à afficher. editor.fail_to_update_file=Impossible de mettre à jour/créer le fichier '%s'. editor.fail_to_update_file_summary=Message d'erreur : +editor.push_rejected_no_message=La modification a été rejetée par le serveur sans message. Veuillez vérifier les Git Hooks. +editor.push_rejected=La modification a été rejetée par le serveur. Veuillez vérifier vos Git Hooks. editor.push_rejected_summary=Message de rejet complet : editor.add_subdir=Ajouter un dossier… editor.unable_to_upload_files=Échec lors de l'envoie du fichier '%s' avec l’erreur : %v @@ -1045,6 +1071,7 @@ editor.cannot_commit_to_protected_branch=Impossible de créer une révision sur editor.no_commit_to_branch=Impossible d'enregistrer la révisions directement sur la branche parce que : editor.user_no_push_to_branch=L'utilisateur ne peut pas pousser vers la branche editor.require_signed_commit=Cette branche nécessite une révision signée +editor.cherry_pick=Picorer %s vers: editor.revert=Rétablir %s sur: commits.desc=Naviguer dans l'historique des modifications. @@ -1064,7 +1091,15 @@ commits.signed_by=Signé par commits.signed_by_untrusted_user=Signé par un utilisateur non approuvé commits.signed_by_untrusted_user_unmatched=Signé par un utilisateur non fiable qui ne correspond pas au validateur commits.gpg_key_id=ID de la clé GPG +commits.ssh_key_fingerprint=Empreinte numérique de la clé SSH +commit.actions=Actions +commit.revert=Rétablir +commit.revert-header=Rétablir : %s +commit.revert-content=Sélectionnez la branche sur laquelle revenir : +commit.cherry-pick=Picorer +commit.cherry-pick-header=Picorer : %s +commit.cherry-pick-content=Sélectionner la branche à picorer : ext_issues.desc=Lien vers un gestionnaire de tickets externe. @@ -1384,6 +1419,7 @@ compare.compare_head=comparer pulls.desc=Activer les demandes de fusion et la revue de code. pulls.new=Nouvelle demande d'ajout +pulls.view=Voir la demande d'ajout pulls.compare_changes=Nouvelle demande de fusion pulls.compare_changes_desc=Sélectionnez la branche dans laquelle fusionner et la branche depuis laquelle tirer les modifications. pulls.compare_base=fusionner dans @@ -1393,6 +1429,7 @@ pulls.filter_branch=Filtre de branche pulls.no_results=Aucun résultat trouvé. pulls.nothing_to_compare=Ces branches sont identiques. Il n'y a pas besoin de créer une demande de fusion. pulls.nothing_to_compare_and_allow_empty_pr=Ces branches sont égales. Cette demande d'ajout sera vide. +pulls.has_pull_request='Il existe déjà une demande d'ajout entre ces deux branches : %[2]s#%[3]d' pulls.create=Créer une demande d'ajout pulls.title_desc=veut fusionner %[1]d révision(s) depuis %[2]s vers %[3]s pulls.merged_title_desc=a fusionné %[1]d révision(s) à partir de %[2]s vers %[3]s %[4]s @@ -1421,7 +1458,6 @@ pulls.required_status_check_missing=Certains contrôles requis sont manquants. pulls.required_status_check_administrator=En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull. pulls.blocked_by_approvals=Cette demande d'ajout n'a pas assez d'approbation. %d sur %d approbations accordées. pulls.blocked_by_rejection=Cette demande de fusion a des modifications demandées par un réviseur officiel. -pulls.blocked_by_official_review_requests=Cette demande d'ajout a des demandes de revue officielles. pulls.blocked_by_outdated_branch=Cette demande d'ajout est bloquée car elle est obsolète. pulls.blocked_by_changed_protected_files_1=Cette demande d'ajout est bloquée car elle modifie un fichier protégé : pulls.blocked_by_changed_protected_files_n=Cette Pull Request est bloquée car elle modifie les fichiers protégés : @@ -1443,6 +1479,10 @@ pulls.no_merge_helper=Activez des options de fusion dans les paramètres du dép pulls.no_merge_wip=Cette demande d'ajout ne peut pas être fusionnée car elle est marquée comme en cours de chantier. pulls.no_merge_not_ready=Cette demande d'ajout n'est pas prête à être fusionnée, vérifiez l'état de la revue et les vérifications. pulls.no_merge_access=Vous n'êtes pas autorisé⋅e à fusionner cette demande d'ajout. +pulls.merge_pull_request=Créer une révision de fusion +pulls.rebase_merge_pull_request=Rebaser puis avancer rapidement +pulls.rebase_merge_commit_pull_request=Rebaser puis créer une révision de fusion +pulls.squash_merge_pull_request=Créer une révision de concaténation pulls.merge_manually=Fusionné manuellement pulls.merge_commit_id=L'ID de la révision de fusion pulls.require_signed_wont_sign=La branche nécessite des révisions signées mais cette fusion ne sera pas signée @@ -1473,9 +1513,17 @@ pulls.merge_instruction_hint=`Vous pouvez également voir %s rename_repo=a rebaptisé le dépôt de %[1]s vers %[3]s +create_pull_request=`a créé la demande d'ajout %[3]s#%[2]s` +close_pull_request=`a fermé la demande d'ajout %[3]s#%[2]s` +reopen_pull_request=`a réouvert la demande d'ajout %[3]s#%[2]s` +comment_pull=`a commenté la demande d'ajout %[3]s#%[2]s` +merge_pull_request=`a fusionné la demande d'ajout %[3]s#%[2]s` transfer_repo=a transféré le dépôt %s à %s delete_tag=étiquette supprimée %[2]s de %[3]s delete_branch=branche %[2]s supprimée de %[3]s @@ -2647,6 +2698,8 @@ compare_branch=Comparer compare_commits=Comparer %d révisions compare_commits_general=Comparer les révisions mirror_sync_delete=a synchronisé puis supprimé la nouvelle référence %[2]s vers %[3]s depuis le miroir +approve_pull_request=`a approuvé %[3]s#%[2]s` +reject_pull_request=`a suggérés des changements pour %[3]s#%[2]s` review_dismissed_reason=Raison : [tool] diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index a98bbedf3e84..c996aef38560 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -8,7 +8,6 @@ sign_out=Kijelentkezés sign_up=Regisztrálás link_account=Fiók kapcsolása register=Regisztráció -website=Webhely version=Verzió powered_by=Biztosítja: %s page=Oldal @@ -135,7 +134,6 @@ log_root_path_helper=A naplófájlok ebbe a mappába fognak íródni. optional_title=További beállítások email_title=E-mail beállítások -smtp_host=SMTP kiszolgáló smtp_from=E-mail küldése mint smtp_from_helper=Az E-mail cím a mit a Gitea használni fog. Megadhatja sima email címként vagy "Név" formátumban. mailer_user=SMTP-felhasználónév @@ -1625,11 +1623,8 @@ config.queue_length=Várakozási Sor Hossza config.deliver_timeout=Kézbesítési Időtúllépés config.skip_tls_verify=A TLS Hitelesítés Kihagyása -config.mailer_config=SMTP levelező Beállítások config.mailer_enabled=Engedélyezett -config.mailer_disable_helo=HELO Letiltása config.mailer_name=Név -config.mailer_host=Kiszolgáló config.mailer_user=Felhasználó config.mailer_use_sendmail=Sendmail Használata config.mailer_sendmail_path=Sendmail Elérési Útja diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 34c7db6b23ea..e7ddd418c62e 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -8,7 +8,6 @@ sign_out=Keluar sign_up=Daftar link_account=Tautan Akun register=Daftar -website=Situs Web version=Versi powered_by=Diberdayakan oleh %s page=Halaman @@ -131,7 +130,6 @@ log_root_path_helper=Berkas log akan ditulis ke direktori ini. optional_title=Pengaturan Opsional email_title=Pengaturan Surel -smtp_host=Host SMTP smtp_from=Kirim Surel sebagai smtp_from_helper=Alamat surel Gitea akan digunakan. Masukkan alamat surel atau gunakan fomat "Nama" . mailer_user=Nama Pengguna SMTP @@ -1235,11 +1233,8 @@ config.queue_length=Panjang antrian config.deliver_timeout=Berikan waktu habis config.skip_tls_verify=Melewatkan verifikasi TLS -config.mailer_config=Pengaturan SMTP Mailer config.mailer_enabled=Diaktifkan -config.mailer_disable_helo=Nonaktifkan HELO config.mailer_name=Nama -config.mailer_host=Host config.mailer_user=Pengguna config.mailer_use_sendmail=Menggunakan Sendmail config.mailer_sendmail_path=Jalur Sendmail diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 9503c3c2778c..90979837cbb4 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -8,7 +8,6 @@ sign_out=Skrá Út sign_up=Nýskráning link_account=Tengja Notanda register=Nýskráning -website=Vefsíða version=Útgáfa powered_by=Keyrt af %s page=Síða @@ -177,7 +176,6 @@ log_root_path_helper=Annálaskrár verða skrifaðar í þessa möppu. optional_title=Valfrjálsar Stillingar email_title=Tölvupóstsstillingar -smtp_host=SMTP Hýsill smtp_from=Senda Tölvupóst Sem smtp_from_helper=Netfang sem Gitea mun nota. Sláðu inn venjulegt netfang eða notaðu „Nafn“ sniðið. mailer_user=SMTP Notandanafn @@ -1265,7 +1263,6 @@ config.db_path=Slóð config.mailer_name=Heiti -config.mailer_host=Hýsill config.mailer_user=Notandi diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 7fd829873706..ac29c5b841d4 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -9,7 +9,6 @@ sign_out=Esci sign_up=Registrati link_account=Collega account register=Registrati -website=Sito Web version=Versione powered_by=Gestito da %s page=Pagina @@ -179,7 +178,8 @@ log_root_path_helper=I file di log saranno scritti in questa directory. optional_title=Impostazioni Facoltative email_title=Impostazioni Email -smtp_host=Host SMTP +smtp_addr=Host SMTP +smtp_port=Porta SMTP smtp_from=Invia Email come smtp_from_helper=Indirizzo Email che Gitea utilizzerà. Inserisci un indirizzo email o usa il formato "Name" . mailer_user=Nome utente SMTP @@ -1035,13 +1035,13 @@ file_view_rendered=Visualizza Renderizzato file_view_raw=Vedi originale file_permalink=Permalink file_too_large=Il file è troppo grande per essere visualizzato. -bidi_bad_header=`Questo file contiene caratteri Unicode Bidirezionali inattesi!` -bidi_bad_description=`Questo file contiene caratteri inaspettati Bidirezionali Unicode che possono essere elaborati in modo diverso da quello che appare di seguito. Se il tuo caso di utilizzo è intenzionale e legittimo, puoi tranquillamente ignorare questo avviso. Usa il pulsante Escape per rivelare caratteri nascosti.` -bidi_bad_description_escaped=`Questo file contiene caratteri Unicode bidirezionali inattesi. I caratteri unicode nascosti sono sfuggiti qui sotto. Usa il pulsante Unescape per mostrare come render.` -unicode_header=`Questo file contiene caratteri Unicode nascosti!` -unicode_description=`Questo file contiene caratteri Unicode nascosti che possono essere elaborati in modo diverso da quello che appare di seguito. Se il tuo caso di utilizzo è intenzionale e legittimo, puoi tranquillamente ignorare questo avviso. Usa il pulsante Escape per rivelare caratteri nascosti.` -unicode_description_escaped=`Questo file contiene caratteri Unicode nascosti. I caratteri unicode nascosti sono fuggiti qui sotto. Usa il pulsante Unescape per mostrare come render.` -line_unicode=`Questa riga ha caratteri unicode nascosti` +invisible_runes_header=`Questo file contiene caratteri Unicode invisibili!` +invisible_runes_description=`Questo file contiene caratteri Unicode invisibili che possono essere elaborati in modo diverso da quello che appare di seguito. Se il tuo caso di utilizzo è intenzionale e legittimo, puoi tranquillamente ignorare questo avviso. Usa il pulsante Escape per rivelare caratteri nascosti.` +ambiguous_runes_header=`Questo file contiene caratteri Unicode ambigui!` +ambiguous_runes_description=`Questo file contiene caratteri Unicode ambigui che possono essere confusi con altri nella tua localizzazione attuale. Se il tuo caso di utilizzo è intenzionale e legittimo, puoi tranquillamente ignorare questo avviso. Usa il pulsante Escape per evidenziare questi caratteri.` +invisible_runes_line=`Questa riga ha caratteri unicode invisibili` +ambiguous_runes_line=`Questa riga ha caratteri unicode ambigui` +ambiguous_character=`%[1]c [U+%04[1]X] è confondibile con %[2]c [U+%04[2]X]` escape_control_characters=Fuga unescape_control_characters=Unescape @@ -1062,6 +1062,7 @@ normal_view=Vista normale line=riga lines=righe +editor.add_file=Aggiungi file editor.new_file=Nuovo file editor.upload_file=Carica File editor.edit_file=Modifica File @@ -1267,6 +1268,8 @@ issues.filter_milestone=Traguardo issues.filter_milestone_no_select=Tutte le pietre miliari issues.filter_assignee=Assegnatario issues.filter_assginee_no_select=Tutte le assegnazioni +issues.filter_poster=Autore +issues.filter_poster_no_select=Tutti gli autori issues.filter_type=Tipo issues.filter_type.all_issues=Tutti i problemi issues.filter_type.assigned_to_you=Assegnati a te @@ -2795,16 +2798,19 @@ config.queue_length=Lunghezza della coda config.deliver_timeout=Tempo Limite di Consegna config.skip_tls_verify=Salta autenticazione TLS -config.mailer_config=Configurazione Mailer SMTP +config.mailer_config=Configurazione Mailer config.mailer_enabled=Attivo -config.mailer_disable_helo=Disattiva HELO +config.mailer_enable_helo=Abilita HELO config.mailer_name=Nome -config.mailer_host=Host +config.mailer_protocol=Protocollo +config.mailer_smtp_addr=Indirizzo SMTP +config.mailer_smtp_port=Porta SMTP config.mailer_user=Utente config.mailer_use_sendmail=Utilizza Sendmail config.mailer_sendmail_path=Percorso Sendmail config.mailer_sendmail_args=Argomenti aggiuntivi per Sendmail config.mailer_sendmail_timeout=Timeout Sendmail +config.mailer_use_dummy=Dummy config.test_email_placeholder=Email (es. test@example.com) config.send_test_mail=Invia email di prova config.test_mail_failed=Impossibile inviare mail di prova a '%s': %v @@ -2889,6 +2895,7 @@ monitor.queue.nopool.title=Nessun pool di Workers monitor.queue.nopool.desc=Questa coda racchiude altre code al suo interno e non ha un proprio pool. monitor.queue.wrapped.desc=Una coda a capo avvolge una coda iniziale lenta, le richieste in coda di buffering in un canale. Non ha un pool di lavoratori stesso. monitor.queue.persistable-channel.desc=Un canale persistibile avvolge due code, una coda di canale che ha un proprio pool di operatori e una coda di livello per le richieste persistenti dagli arresti precedenti. Non ha un pool di operai. +monitor.queue.flush=Flush worker monitor.queue.pool.timeout=Timeout monitor.queue.pool.addworkers.title=Aggiungi Workers monitor.queue.pool.addworkers.submit=Aggiungi Workers @@ -3107,6 +3114,9 @@ npm.dependencies.development=Dipendenze Di Sviluppo npm.dependencies.peer=Dipendenze Peer npm.dependencies.optional=Dipendenze Opzionali npm.details.tag=Tag +pub.install=Per installare il pacchetto utilizzando NuGet, eseguire il seguente comando: +pub.documentation=Per ulteriori informazioni sul registro Pub, consultare la documentazione. +pub.details.repository_site=Sito Repository pypi.requires=Richiede Python pypi.install=Per installare il pacchetto usando pip, eseguire il seguente comando: pypi.documentation=Per ulteriori informazioni sul registro PyPI, consultare la documentazione. diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index b91f3c87e73b..efb41ddd84c4 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -9,7 +9,6 @@ sign_out=サインアウト sign_up=登録 link_account=アカウント連携 register=登録 -website=Webサイト version=バージョン powered_by=Powered by %s page=ページ @@ -179,7 +178,8 @@ log_root_path_helper=ログファイルがこのディレクトリに書き込 optional_title=オプション設定 email_title=メール設定 -smtp_host=SMTPホスト +smtp_addr=SMTPホスト +smtp_port=SMTPポート smtp_from=メール送信者 smtp_from_helper=Giteaが使用するメールアドレス。 メールアドレスのみ、または、 "名前" の形式で入力してください。 mailer_user=SMTPユーザー名 @@ -1035,13 +1035,6 @@ file_view_rendered=レンダリング表示 file_view_raw=Rawデータを見る file_permalink=パーマリンク file_too_large=このファイルは大きすぎるため、表示できません。 -bidi_bad_header=`このファイルには予期しない双方向Unicode文字が含まれています!` -bidi_bad_description=`このファイルには予期しない双方向Unicode文字が含まれており、下に見えているものとは異なる処理が行われる可能性があります。 あなたのユースケースが意図的かつ正当な場合はこの警告を無視して構いません。 不可視文字を表示するにはエスケープボタンを使用します。` -bidi_bad_description_escaped=`このファイルには予期しない双方向Unicode文字が含まれています。 下の表示では、不可視Unicode文字はエスケープされています。 どのようにレンダリングされるかを表示するにはエスケープ解除ボタンを使用します。` -unicode_header=`このファイルには不可視Unicode文字が含まれています!` -unicode_description=`このファイルには不可視Unicode文字が含まれており、下に見えているものとは異なる処理が行われる可能性があります。 あなたのユースケースが意図的かつ正当な場合はこの警告を無視して構いません。 不可視文字を表示するにはエスケープボタンを使用します。` -unicode_description_escaped=`このファイルには不可視Unicode文字が含まれています。 下の表示では、不可視Unicode文字はエスケープされています。 どのようにレンダリングされるかを表示するにはエスケープ解除ボタンを使用します。` -line_unicode=`この行には不可視Unicode文字があります` escape_control_characters=エスケープ unescape_control_characters=エスケープ解除 @@ -1062,6 +1055,7 @@ normal_view=通常表示 line=行 lines=行 +editor.add_file=ファイル追加 editor.new_file=新規ファイル editor.upload_file=ファイルをアップロード editor.edit_file=ファイルを編集 @@ -1267,6 +1261,8 @@ issues.filter_milestone=マイルストーン issues.filter_milestone_no_select=すべてのマイルストーン issues.filter_assignee=担当者 issues.filter_assginee_no_select=すべての担当者 +issues.filter_poster=作成者 +issues.filter_poster_no_select=すべての作成者 issues.filter_type=タイプ issues.filter_type.all_issues=すべてのイシュー issues.filter_type.assigned_to_you=自分が担当 @@ -2795,16 +2791,19 @@ config.queue_length=キューの長さ config.deliver_timeout=送信タイムアウト config.skip_tls_verify=TLS検証を省略 -config.mailer_config=SMTPメーラーの設定 +config.mailer_config=メーラー設定 config.mailer_enabled=有効 -config.mailer_disable_helo=HELOコマンド無効 +config.mailer_enable_helo=HELO有効 config.mailer_name=名称 -config.mailer_host=ホスト +config.mailer_protocol=プロトコル +config.mailer_smtp_addr=SMTPアドレス +config.mailer_smtp_port=SMTPポート config.mailer_user=ユーザー config.mailer_use_sendmail=Sendmailを使う config.mailer_sendmail_path=Sendmailのパス config.mailer_sendmail_args=Sendmailの追加引数 config.mailer_sendmail_timeout=Sendmail のタイムアウト +config.mailer_use_dummy=Dummy config.test_email_placeholder=Email (例 test@example.com) config.send_test_mail=テストメールを送信 config.test_mail_failed='%s' へのテストメール送信に失敗しました: %v @@ -3107,6 +3106,10 @@ npm.dependencies.development=開発用依存関係 npm.dependencies.peer=Peer依存関係 npm.dependencies.optional=オプションの依存関係 npm.details.tag=タグ +pub.install=Dart を使用してパッケージをインストールするには、次のコマンドを実行します: +pub.documentation=Pub レジストリの詳細については、ドキュメント を参照してください。 +pub.details.repository_site=リポジトリサイト +pub.details.documentation_site=ドキュメントサイト pypi.requires=必要なPython pypi.install=pip を使用してパッケージをインストールするには、次のコマンドを実行します: pypi.documentation=PyPI レジストリの詳細については、ドキュメント を参照してください。 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index ab8908e531f3..d4917f861ab4 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -8,7 +8,6 @@ sign_out=로그아웃 sign_up=가입하기 link_account=계정 연결 register=가입하기 -website=웹 사이트 version=버전 powered_by=%s 제공 page=페이지 @@ -126,7 +125,6 @@ log_root_path_helper=로그파일은 이 디렉토리에 저장됩니다. optional_title=추가설정 email_title=이메일 설정 -smtp_host=SMTP 호스트 smtp_from=이메일 발신인 smtp_from_helper=Gitea 가 사용할 이메일 주소. 이메일 주소 또는 "이름" 형식으로 입력하세요. mailer_user=SMTP 사용자이름 @@ -1450,11 +1448,8 @@ config.queue_length=큐 길이 config.deliver_timeout=시간 제한 사용 config.skip_tls_verify=TLS 검증 건너뛰기 -config.mailer_config=SMTP 메일러 설정 config.mailer_enabled=활성화됨 -config.mailer_disable_helo=HELO 비활성화 config.mailer_name=이름 -config.mailer_host=호스트 config.mailer_user=사용자 config.mailer_use_sendmail=Sendmail 사용 config.mailer_sendmail_path=Sendmail 경로 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 5cecb321dc4c..b82675762035 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -9,7 +9,6 @@ sign_out=Izrakstīties sign_up=Reģistrēties link_account=Saistītie konti register=Reģistrēties -website=Mājas lapa version=Versija powered_by=Darbina %s page=Lapa @@ -179,7 +178,8 @@ log_root_path_helper=Žurnalizēšanas faili tiks rakstīti šajā direktorijā. optional_title=Neobligātie iestatījumi email_title=E-pastu iestatījumi -smtp_host=SMTP resursdators +smtp_addr=SMTP resursdators +smtp_port=SMTP ports smtp_from=Nosūtīt e-pastu kā smtp_from_helper=E-pasta adrese, ko Gitea izmantos. Ievadiet tika e-pasta adrese vai izmantojiet "Vārds" formātu. mailer_user=SMTP lietotāja vārds @@ -799,6 +799,7 @@ email_notifications.enable=Iespējot e-pasta paziņojumus email_notifications.onmention=Tikai, ja esmu pieminēts email_notifications.disable=Nesūtīt paziņojumus email_notifications.submit=Saglabāt sūtīšanas iestatījumus +email_notifications.andyourown=Iekļaut savus paziņojumus visibility=Lietotāja redzamība visibility.public=Publisks @@ -861,7 +862,9 @@ default_branch=Noklusējuma atzars default_branch_helper=Noklusētais atzars nosaka pamata atzaru uz kuru tiks veidoti izmaiņu pieprasījumi un koda revīziju iesūtīšana. mirror_prune=Izmest mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē +mirror_interval=Spoguļošanas intervāls (derīgas laika vienības ir 'h', 'm', 's'). Norādiet 0, lai atslēgtu periodisku spoguļošanu. (Minimālais intervāls: %s) mirror_interval_invalid=Nekorekts spoguļošanas intervāls. +mirror_sync_on_commit=Sinhronizēt, kad revīzijas tiek iesūtītas mirror_address=Spoguļa adrese mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā. mirror_address_url_invalid=Norādītais URL nav korekts. Norādiet visas URL daļas korekti. @@ -930,6 +933,7 @@ form.name_pattern_not_allowed=Repozitorija nosaukums '%s' nav atļauts. need_auth=Autorizācija migrate_options=Migrācijas opcijas migrate_service=Migrācijas serviss +migrate_options_mirror_helper=Šis repozitorijs būs spogulis migrate_options_lfs=Migrēt LFS failus migrate_options_lfs_endpoint.label=LFS galapunkts migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai noteiktu LFS serveri. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā. @@ -1031,13 +1035,6 @@ file_view_rendered=Skatīt rezultātu file_view_raw=Rādīt neapstrādātu file_permalink=Patstāvīgā saite file_too_large=Šis fails ir par lielu, lai to parādītu. -bidi_bad_header=`Šis fails satur neparedzētus virzienmaiņas unikoda simbolus!` -bidi_bad_description=`Šis fails satur neparedzētus virzienmaiņas unikoda simbolus, kas var mainīt kā saturs tiek attēlots. Ja tie ir izmantoti ar pamatotu nodumu, tad varat ignorēt šo brīdinājumu. Izmantojiet Kodēt pogu, lai parādītu šos neredzamos simbolus.` -bidi_bad_description_escaped=`Šis fails satur neparedzētus virzienmaiņas unikoda simbolus. Neredzamie unikoda simboli ir kodēti, lai būtu redzami. Izmantojiet Atkodēt pogu, lai redzētu kā tie tiek attēloti.` -unicode_header=`Šis fails satur neredzamus unikoda simbolus!` -unicode_description=`Šis fails satur neredzamus unikoda simbolus, kas var mainīt kā saturs tiek attēlots. Ja tie ir izmantoti ar pamatotu nodumu, tad varat ignorēt šo brīdinājumu. Izmantojiet Kodēt pogu, lai parādītu šos neredzamos simbolus.` -unicode_description_escaped=`Šis fails satur neredzamus unikoda simbolus. Neredzamie unikoda simboli ir kodēti, lai būtu redzami. Izmantojiet Atkodēt pogu, lai redzētu kā tie tiek attēloti.` -line_unicode=`Šajā līnijā ir paslēpti unikoda simboli` escape_control_characters=Kodēt unescape_control_characters=Atkodēt @@ -1058,6 +1055,7 @@ normal_view=Parastais skats line=rinda lines=rindas +editor.add_file=Pievienot editor.new_file=Jauna datne editor.upload_file=Augšupielādēt failu editor.edit_file=Labot failu @@ -1300,6 +1298,7 @@ issues.previous=Iepriekšējā issues.next=Nākamā issues.open_title=Atvērta issues.closed_title=Slēgta +issues.draft_title=Melnraksts issues.num_comments=%d komentāri issues.commented_at=` komentēja %s` issues.delete_comment_confirm=Vai patiešām vēlaties dzēst šo komentāru? @@ -1416,6 +1415,7 @@ issues.due_date_form_remove=Noņemt issues.due_date_not_writer=Jums ir nepieciešamas rakstīšanas tiesības uz šo repozitoriju, lai mainītu izpildes termiņu. issues.due_date_not_set=Izpildes termiņš nav uzstādīts. issues.due_date_added=pievienoja izpildes termiņu %s %s +issues.due_date_modified=mainīja termiņa datumu no %[2]s uz %[1]s %[3]s issues.due_date_remove=noņēma izpildes termiņu %s %s issues.due_date_overdue=Nokavēts issues.due_date_invalid=Datums līdz nav korekts. Izmantojiet formātu 'gggg-mm-dd'. @@ -1527,6 +1527,8 @@ pulls.remove_prefix=Noņemt %s prefiksu pulls.data_broken=Izmaiņu pieprasījums ir bojāts, jo dzēsta informācija no atdalītā repozitorija. pulls.files_conflicted=Šīs izmaiņu pieprasījuma izmaiņas konfliktē ar mērķa atzaru. pulls.is_checking=Notiek konfliktu pārbaude, mirkli uzgaidiet un atjaunojiet lapu. +pulls.is_ancestor=Atzars jau ir pilnībā iekļauts mērķā atzarā. Nav izmaiņu, ko sapludināt. +pulls.is_empty=Mērķa atzars jau satur šī atzara izmaiņas. Šī revīzija būs tukša. pulls.required_status_check_failed=Dažas no pārbaudēm nebija veiksmīgas. pulls.required_status_check_missing=Trūkst dažu obligāto pārbaužu. pulls.required_status_check_administrator=Kā administrators Jūs varat sapludināt šo izmaiņu pieprasījumu. @@ -1605,6 +1607,8 @@ pulls.auto_merge_canceled_schedule=Automātiskā sapludināšana šim izmaiņu p pulls.auto_merge_newly_scheduled_comment=`ieplānoja automātisko sapludināšanu šim izmaiņu pieprasījumam, kad visas pārbaudes būs veiksmīgas %[1]s` pulls.auto_merge_canceled_schedule_comment=`atcēla automātisko sapludināšanu šim izmaiņu pieprasījumam %[1]s` +pulls.delete.title=Dzēst šo izmaiņu pieprasījumu? +pulls.delete.text=Vai patiešām vēlaties dzēst šo izmaiņu pieprasījumu? (Neatgriezeniski tiks izdzēsts viss saturs. Apsveriet iespēju to aizvērt, ja vēlaties informāciju saglabāt vēsturei) milestones.new=Jauns atskaites punkts milestones.closed=Aizvērts %s @@ -2527,6 +2531,8 @@ users.delete_account=Dzēst lietotāja kontu users.cannot_delete_self=Nevar izdzēst sevi users.still_own_repo=Lietotājam pieder repozitoriji, tos sākumā ir nepieciešams izdzēst vai mainīt to īpašnieku. users.still_has_org=Šis lietotājs ir vienas vai vairāku organizāciju biedrs, lietotāju sākumā ir nepieciešams pamest šīs organizācijas vai viņu no tām ir jāizdzēš. +users.purge=Attīrīt lietotu +users.purge_help=Piespiedu dzēst lietotāju un visus tā repozitorijus, organizācijas un pakotnes. Arī visi lietotāja komentāri tiks dzēsti. users.still_own_packages=Šim lietotājam pieder viena vai vairākas pakotnes. Tās nepieciešams izdzēst. users.deletion_success=Lietotāja konts veiksmīgi izdzēsts. users.reset_2fa=Noņemt 2FA @@ -2783,16 +2789,19 @@ config.queue_length=Rindas garums config.deliver_timeout=Piegādes noildze config.skip_tls_verify=Izlaist TLS pārbaudi -config.mailer_config=SMTP sūtītāja konfigurācija +config.mailer_config=Pasta sūtītāja konfigurācija config.mailer_enabled=Iespējota -config.mailer_disable_helo=Atspējot HELO +config.mailer_enable_helo=Iespējot HELO config.mailer_name=Nosaukums -config.mailer_host=Resursdators +config.mailer_protocol=Protokols +config.mailer_smtp_addr=SMTP adrese +config.mailer_smtp_port=SMTP ports config.mailer_user=Lietotājs config.mailer_use_sendmail=Izmantot Sendmail config.mailer_sendmail_path=Ceļš līdz sendmail programmai config.mailer_sendmail_args=Papildus Sendmail komandrindas argumenti config.mailer_sendmail_timeout=Sendmail noildze +config.mailer_use_dummy=Tukšs config.test_email_placeholder=E-pasts (piemēram, test@example.com) config.send_test_mail=Nosūtīt pārbaudes e-pastu config.test_mail_failed=Neizdevās nosūtīt pārbaudes e-pastu uz '%s': %v @@ -3029,6 +3038,7 @@ title=Pakotnes desc=Pārvaldīt repozitorija pakotnes. empty=Pašlaik šeit nav nevienas pakotnes. empty.documentation=Papildus informācija par pakotņu reģistru pieejama dokumentācijā. +empty.repo=Neparādās augšupielādēta pakotne? Apmeklējiet pakotņu iestatījumus, lai sasaistītu ar repozitoriju. filter.type=Veids filter.type.all=Visas filter.no_result=Pēc norādītajiem kritērijiem nekas netika atrasts. @@ -3094,6 +3104,10 @@ npm.dependencies.development=Izstrādes atkarības npm.dependencies.peer=Netiešās atkarības npm.dependencies.optional=Neobligātās atkarības npm.details.tag=Tags +pub.install=Lai instalētu Dart pakotni, izpildiet sekojošu komandu: +pub.documentation=Papildus informācija par Pub reģistru pieejama dokumentācijā. +pub.details.repository_site=Repozitorija izmērs +pub.details.documentation_site=Dokumentācijas lapa pypi.requires=Nepieciešams Python pypi.install=Lai instalētu pip pakotni, izpildiet sekojošu komandu: pypi.documentation=Papildus informācija par PyPI reģistru pieejama dokumentācijā. diff --git a/options/locale/locale_ml-IN.ini b/options/locale/locale_ml-IN.ini index 27e4f1127938..7ee595bf4fce 100644 --- a/options/locale/locale_ml-IN.ini +++ b/options/locale/locale_ml-IN.ini @@ -8,7 +8,6 @@ sign_out=പുറത്തുകടക്കുക sign_up=രജിസ്റ്റർ link_account=അക്കൌണ്ട് ബന്ധിപ്പിയ്ക്കുക register=രജിസ്റ്റർ -website=വെബ് സൈറ്റ് version=പതിപ്പ് page=പേജ് template=ടെംപ്ലേറ്റ് @@ -112,7 +111,6 @@ log_root_path_helper=ലോഗ് ഫയലുകൾ ഈ ഡയറക്ടറ optional_title=ഐച്ഛികമായ ക്രമീകരണങ്ങൾ email_title=ഇമെയിൽ ക്രമീകരണങ്ങൾ -smtp_host=SMTP ഹോസ്റ്റ് smtp_from=ഈ വിലാസത്തില്‍ ഇമെയിൽ അയയ്‌ക്കുക smtp_from_helper=ഗിറ്റീ ഉപയോഗിയ്ക്കുന്ന ഇമെയില്‍ വിലാസം. ഒരു സാധാ ഇമെയിൽ വിലാസം നൽകുക അല്ലെങ്കിൽ "പേര്" എന്ന ഘടന ഉപയോഗിക്കുക. mailer_user=SMTP ഉപയോക്തൃനാമം diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index fcc048b3c1c5..5b18185fefd5 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -9,7 +9,6 @@ sign_out=Uitloggen sign_up=Registreren link_account=Account Koppelen register=Registreren -website=Website version=Versie powered_by=Powered by %s page=Pagina @@ -179,7 +178,8 @@ log_root_path_helper=Logboekbestanden worden geschreven naar deze map. optional_title=Optionele instellingen email_title=E-mail instellingen -smtp_host=SMTP host +smtp_addr=SMTP Host +smtp_port=SMTP Poort smtp_from=E-mails versturen als smtp_from_helper=E-mailadres dat Gitea gaat gebruiken. Voer een gewoon e-mailadres in of gebruik de "Naam" -indeling. mailer_user=SMTP gebruikersnaam @@ -1035,13 +1035,13 @@ file_view_rendered=Weergave weergeven file_view_raw=Weergave ruw bestand file_permalink=Permalink file_too_large=Dit bestand is te groot om te tonen. -bidi_bad_header=`Dit bestand bevat onverwachte Bidirectionele Unicode karakters!` -bidi_bad_description=`Dit bestand bevat onverwachte Bidirectionele Unicode-tekens die anders verwerkt kunnen worden dan hieronder het geval is. Als uw gebruik ervan opzettelijk en legitiem is, kunt u deze waarschuwing veilig negeren. Gebruik de Escape knop om verborgen karakters te onthullen.` -bidi_bad_description_escaped=`Dit bestand bevat onverwachte Bidirectionele Unicode-tekens. Verborgen unicode tekens worden hieronder ge-escaped. Gebruik de knop Onescape om te laten zien hoe ze renderen.` -unicode_header=`Dit bestand bevat verborgen Unicode karakters!` -unicode_description=`Dit bestand bevat verborgen Unicode-tekens die anders verwerkt kunnen worden dan hieronder het geval is. Als uw gebruik ervan opzettelijk en legitiem is, kunt u deze waarschuwing veilig negeren. Gebruik de Escape knop om verborgen karakters te onthullen.` -unicode_description_escaped=`Dit bestand bevat verborgen Unicode-tekens. Verborgen unicode tekens zijn hieronder ge-escaped. Gebruik de knop Onescape om te laten zien hoe ze renderen.` -line_unicode=`Deze regel bevat verborgen Unicode karakters` +invisible_runes_header=`Dit bestand bevat onzichtbare Unicode-karakters!` +invisible_runes_description=`Dit bestand bevat onzichtbare Unicode karakters die mogelijk anders verwerkt worden dan wat hieronder staat. Als uw gebruik opzettelijk en legitiem is, kunt u deze waarschuwing veilig negeren. Gebruik de Escape knop om verborgen karakters te onthullen.` +ambiguous_runes_header=`Dit bestand bevat dubbelzinnige Unicode karakters!` +ambiguous_runes_description=`Dit bestand bevat dubbelzinnige Unicode karakters die verward kunnen worden met andere karakters in uw huidige taal. Als je het opzettelijk en legitiem gebruikt, kun je deze waarschuwing veilig negeren. Gebruik de Escape knop om deze karakters te markeren.` +invisible_runes_line=`Deze lijn heeft onzichtbare unicode karakters` +ambiguous_runes_line=`Deze lijn heeft dubbelzinnige unicode karakters` +ambiguous_character=`%[1]c [U+%04[1]X] is verwarrend met %[2]c [U+%04[2]X]` escape_control_characters=Escape unescape_control_characters=Onescape @@ -1062,6 +1062,7 @@ normal_view=Normale weergave line=regel lines=regels +editor.add_file=Bestand toevoegen editor.new_file=Nieuw bestand editor.upload_file=Upload bestand editor.edit_file=Bewerk bestand @@ -1242,6 +1243,7 @@ issues.add_label=voegde het %s label %s toe issues.add_labels=voegde de %s labels %s toe issues.remove_label=verwijderde het %s label %s issues.remove_labels=verwijderde de %s labels %s +issues.add_remove_labels=voegde de %s toe en verwijderde de %s labels %s issues.add_milestone_at=`heeft dit %[2]s aan de mijlpaal %[1]s toegevoegd` issues.add_project_at=`heeft dit toegevoegd aan het %s project %s` issues.change_milestone_at='mijlpaal bewerkt van %s %s %s' @@ -1255,6 +1257,9 @@ issues.add_assignee_at=`was toegekend door %s %s` issues.remove_assignee_at=`is niet toegewezen door %s %s` issues.remove_self_assignment=`heeft %s zijn/haar toewijzing verwijderd` issues.change_title_at='titel aangepast van %s naar %s %s' +issues.change_ref_at=`wijzig referentie van %s naar %s %s` +issues.remove_ref_at=`heeft referentie %s verwijderd %s` +issues.add_ref_at=`heeft referentie %s toegevoegd %s` issues.delete_branch_at=`heeft %[2]s de branch %[1]s verwijderd.` issues.filter_label=Label issues.filter_label_exclude=`Gebruik alt + klik/voer in om labels uit te sluiten @@ -1263,11 +1268,14 @@ issues.filter_milestone=Mijlpaal issues.filter_milestone_no_select=Alle mijlpalen issues.filter_assignee=Aangewezene issues.filter_assginee_no_select=Alle toegewezen personen +issues.filter_poster=Auteur +issues.filter_poster_no_select=Alle auteurs issues.filter_type=Type issues.filter_type.all_issues=Alle kwesties issues.filter_type.assigned_to_you=Aan jou toegewezen issues.filter_type.created_by_you=Aangemaakt door jou issues.filter_type.mentioning_you=Vermelden jou +issues.filter_type.review_requested=Review aangevraagd issues.filter_sort=Sorteer issues.filter_sort.latest=Nieuwste issues.filter_sort.oldest=Oudste @@ -1281,6 +1289,7 @@ issues.filter_sort.moststars=Meeste sterren issues.filter_sort.feweststars=Minste sterren issues.filter_sort.mostforks=Meeste forks issues.filter_sort.fewestforks=Minste forks +issues.keyword_search_unavailable=Zoeken op trefwoord is momenteel niet beschikbaar. Neem contact op met de websitebeheerder. issues.action_open=Open issues.action_close=Sluit issues.action_label=Label @@ -1289,19 +1298,28 @@ issues.action_milestone_no_select=Geen mijlpaal issues.action_assignee=Toegewezene issues.action_assignee_no_select=Geen verantwoordelijke issues.opened_by=%[1]s geopend door %[3]s +pulls.merged_by=door %[3]s was samengevoegd %[1]s +pulls.merged_by_fake=bij %[2]s is %[1]s samengevoegd +issues.closed_by=door %[3]s was gesloten %[1]s +issues.opened_by_fake=%[1]s geopend door %[2]s +issues.closed_by_fake=door %[2]s was gesloten %[1]s issues.previous=Vorige issues.next=Volgende issues.open_title=Open issues.closed_title=Gesloten +issues.draft_title=Concept issues.num_comments=%d opmerkingen issues.commented_at=`reageerde %s` issues.delete_comment_confirm=Weet u zeker dat u deze reactie wilt verwijderen? issues.context.copy_link=Link kopiëren issues.context.quote_reply=Citeer antwoord +issues.context.reference_issue=Verwijs in nieuw issue issues.context.edit=Bewerken issues.context.delete=Verwijder issues.no_content=Er is nog geen inhoud. issues.close_issue=Sluit +issues.pull_merged_at=`commit samengevoegd %[2]s in %[3]s %[4]s` +issues.manually_pull_merged_at=`commit handmatig samengevoegd %[2]s in %[3]s %[4]s` issues.close_comment_issue=Reageer en sluit issues.reopen_issue=Heropen issues.reopen_comment_issue=Heropen en geef commentaar @@ -1323,6 +1341,8 @@ issues.re_request_review=Opnieuw aanvragen review issues.is_stale=Er zijn wijzigingen aangebracht in deze PR sinds deze beoordeling issues.remove_request_review=Verwijder beoordelingsverzoek issues.remove_request_review_block=Kan beoordelingsverzoek niet verwijderen +issues.dismiss_review=Beoordeling afwijzen +issues.dismiss_review_warning=Bent u zeker dat u deze beoordeling wilt afwijzen? issues.sign_in_require_desc=Log in om deel te nemen aan deze discussie. issues.edit=Bewerken issues.cancel=Annuleren @@ -1366,13 +1386,21 @@ issues.lock.reason=Reden voor vergrendeling issues.lock.title=Vergrendel gesprek over dit probleem. issues.unlock.title=Ontgrendel gesprek over dit probleem. issues.comment_on_locked=Je kunt geen commentaar geven op een vergrendeld probleem. +issues.delete=Verwijderen +issues.delete.title=Deze issue verwijderen? +issues.delete.text=Wilt u deze issue echt verwijderen? (Dit is permanent en verwijdert alle inhoud. Overweeg om deze issue te sluiten, als u liever deze als archief wilt bijhouden) issues.tracker=Tijdregistratie +issues.start_tracking_short=Start timer issues.start_tracking=Start tijdregistratie issues.start_tracking_history=`%s is begonnen` issues.tracker_auto_close=Timer wordt automatisch gestopt wanneer dit probleem wordt gesloten +issues.tracking_already_started=`Je houd al tijd bij voor een ander issue!` +issues.stop_tracking=Stop timer issues.stop_tracking_history=`gestopt met werken aan %s` +issues.cancel_tracking=Weggooien issues.cancel_tracking_history=`tijd bijhouden geannuleerd: %s` issues.add_time=Tijd handmatig toevoegen +issues.del_time=Verwijder deze tijdlog issues.add_time_short=Timer toevoegen issues.add_time_cancel=Annuleren issues.add_time_history=`heeft besteedde tijd toegevoegd: %s` @@ -1388,6 +1416,7 @@ issues.error_modifying_due_date=Deadline aanpassen mislukt. issues.error_removing_due_date=Deadline verwijderen mislukt. issues.push_commit_1=toegevoegd %d commit %s issues.push_commits_n=toegevoegd %d commits %s +issues.force_push_codes=`force-push %[1]s van %[2]s naar %[4]s %[6]s` issues.due_date_form=jjjj-mm-dd issues.due_date_form_add=Vervaldatum toevoegen issues.due_date_form_edit=Bewerk @@ -1395,16 +1424,20 @@ issues.due_date_form_remove=Verwijder issues.due_date_not_writer=Je hebt schrijftoegang in deze repository nodig om de deadline van een kwestie aan te passen. issues.due_date_not_set=Geen vervaldatum ingesteld. issues.due_date_added=heeft %[2]s de deadline %[1]s toegevoegd +issues.due_date_modified=de vervaldatum van %[2]s is gewijzigd naar %[1]s[3]s issues.due_date_remove=heeft %[2]s de deadline %[1]s verwijderd issues.due_date_overdue=Over tijd issues.due_date_invalid=De deadline is ongeldig of buiten bereik. Gebruik het formaat 'jjjj-mm-dd'. issues.dependency.title=Afhankelijkheden +issues.dependency.issue_no_dependencies=Geen afhankelijkheden ingesteld. +issues.dependency.pr_no_dependencies=Geen afhankelijkheden ingesteld. issues.dependency.add=Voeg afhankelijkheid toe… issues.dependency.cancel=Annuleer issues.dependency.remove=Verwijder issues.dependency.remove_info=Verwijder afhankelijkheid issues.dependency.added_dependency=`voegde een nieuwe afhankelijkheid %s toe ` issues.dependency.removed_dependency=`verwijderde een afhankelijkheid %s` +issues.dependency.pr_closing_blockedby=Het sluiten van deze pull-aanvraag is geblokkeerd door de volgende issues issues.dependency.issue_closing_blockedby=Het sluiten van dit issue is geblokkeerd door de volgende problemen issues.dependency.issue_close_blocks=Deze kwestie blokkeert het sluiten van de volgende kwesties issues.dependency.pr_close_blocks=Deze pull-aanvraag blokkeert het sluiten van de volgende kwesties @@ -1577,8 +1610,12 @@ pulls.auto_merge_newly_scheduled=De pull-verzoek was gepland om samen te voegen pulls.auto_merge_has_pending_schedule=%[1]s heeft deze pull-verzoek automatisch samengevoegd wanneer alle checks succesvol zijn geweest %[2]s. pulls.auto_merge_cancel_schedule=Automatisch samenvoegen annuleren +pulls.auto_merge_not_scheduled=Deze pull-aanvraag is niet gepland om automatisch samen te voegen. +pulls.auto_merge_canceled_schedule=De automatisch samenvoegen is geannuleerd voor deze pull-aanvraag. +pulls.delete.title=Deze pull-verzoek verwijderen? +pulls.delete.text=Weet je zeker dat je deze pull-verzoek wilt verwijderen? (Dit zal alle inhoud permanent verwijderen. Overweeg om het te sluiten als je het gearchiveerd wilt houden) milestones.new=Nieuwe mijlpaal milestones.closed=%s werd gesloten @@ -1624,6 +1661,7 @@ signing.wont_sign.commitssigned=De samenvoeging wordt niet ondertekend omdat all signing.wont_sign.approved=De samenvoeging wordt niet ondertekend omdat de PR niet is goedgekeurd signing.wont_sign.not_signed_in=U bent niet ingelogd +ext_wiki=Toegang tot Externe Wiki ext_wiki.desc=Koppelen aan een externe wiki. wiki=Wiki @@ -1648,6 +1686,7 @@ wiki.page_already_exists=Er bestaat al een wiki-pagina met deze naam. wiki.reserved_page=De wiki-paginanaam '%s' is gereserveerd. wiki.pages=Pagina’s wiki.last_updated=Laatst bijgewerkt: %s +wiki.page_name_desc=Voer een naam in voor deze Wiki pagina. Sommige speciale namen zijn: 'Home', '_Sidebar' en '_Footer'. activity=Activiteit activity.period.filter_label=Periode: @@ -1679,6 +1718,7 @@ activity.closed_issues_count_1=Gesloten problemen activity.closed_issues_count_n=Gesloten problemen activity.title.issues_1=%d Probleem activity.title.issues_n=%d Problemen +activity.title.issues_closed_from=%s gesloten van %s activity.title.issues_created_by=%s gemaakt door %s activity.closed_issue_label=Gesloten activity.new_issues_count_1=Nieuw probleem @@ -1716,7 +1756,11 @@ activity.git_stats_deletion_n=%d verwijderingen search=Zoek search.search_repo=Zoek repository +search.fuzzy=Vergelijkbaar +search.match=Overeenkomst search.results=Zoek resultaat voor "%s" in %s +search.code_no_results=Geen broncode gevonden die aan uw zoekterm voldoet. +search.code_search_unavailable=Er is momenteel geen code zoekfunctie beschikbaar. Neem contact op met uw sitebeheerder. settings=Instellingen settings.desc=In de instellingen kan je de instellingen van de repository aanpassen @@ -1731,14 +1775,18 @@ settings.hooks=Webhooks settings.githooks=Git-hooks settings.basic_settings=Basis instellingen settings.mirror_settings=Kopie Settings +settings.mirror_settings.mirrored_repository=Gespiegelde repository settings.mirror_settings.direction=Richting settings.mirror_settings.direction.pull=Pull settings.mirror_settings.direction.push=Push +settings.mirror_settings.last_update=Laatst bijgewerkt settings.mirror_settings.push_mirror.none=Geen spiegels geconfigureerd +settings.mirror_settings.push_mirror.add=Voeg Push Mirror toe settings.sync_mirror=Synchroniseer settings.mirror_sync_in_progress=Mirror-synchronisatie is momenteel bezig - kom later terug. settings.site=Website settings.update_settings=Instellingen bewerken +settings.branches.update_default_branch=Standaard branch bijwerken settings.advanced_settings=Geavanceerde opties settings.wiki_desc=Repository-wiki inschakelen settings.use_internal_wiki=Ingebouwde wiki gebruiken @@ -1757,6 +1805,8 @@ settings.tracker_url_format_error=Het URL-formaat van de externe wiki is geen ge settings.tracker_issue_style=Nummerformaat van de externe kwestie-tracker settings.tracker_issue_style.numeric=Nummeriek settings.tracker_issue_style.alphanumeric=Alfanummeriek +settings.tracker_issue_style.regexp=Reguliere expressie +settings.tracker_issue_style.regexp_pattern=Reguliere expressie patroon settings.tracker_url_format_desc=Gebruik de aanduidingen {user}, {repo} en {index} voor de gebruikersnaam, repositorynaam en kwestie-index. settings.enable_timetracker=Tijdregistratie inschakelen settings.allow_only_contributors_to_track_time=Sta alleen bijdragers toe tijdregistratie te gebruiken @@ -2603,16 +2653,15 @@ config.queue_length=Lengte van wachtrij config.deliver_timeout=Bezorging verlooptijd config.skip_tls_verify=TLS-verificatie overslaan -config.mailer_config=SMTP Mailerconfiguatie config.mailer_enabled=Ingeschakeld -config.mailer_disable_helo=Schakel HELO uit config.mailer_name=Naam -config.mailer_host=Host +config.mailer_smtp_port=SMTP Poort config.mailer_user=Gebruiker config.mailer_use_sendmail=Gebruik Sendmail config.mailer_sendmail_path=Sendmail pad config.mailer_sendmail_args=Extra argumenten voor Sendmail config.mailer_sendmail_timeout=Sendmail time-out +config.mailer_use_dummy=Dummy config.test_email_placeholder=E-mailadres (bijv. test@example.com) config.send_test_mail=Test e-mail verzenden config.test_mail_failed=Verzenden van een testmail naar '%s' is mislukt: %v @@ -2689,6 +2738,7 @@ monitor.queue.review=Configuratie herzien monitor.queue.review_add=Beoordeel/Voeg workers toe monitor.queue.configuration=Initiële configuratie monitor.queue.nopool.title=Geen Worker-pool +monitor.queue.flush=Spoel werker monitor.queue.pool.timeout=Time-out monitor.queue.pool.addworkers.title=Voeg workers toe monitor.queue.pool.addworkers.submit=Voeg workers toe diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 75c3d6287c3d..840f69d9308f 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -8,7 +8,6 @@ sign_out=Wyloguj sign_up=Zarejestruj link_account=Powiąż konto register=Zarejestruj się -website=Strona version=Wersja powered_by=Wspierane przez %s page=Strona @@ -177,7 +176,6 @@ log_root_path_helper=Pliki logów będą zapisywane w tym katalogu. optional_title=Ustawienia opcjonalne email_title=Ustawienia e-mail -smtp_host=Serwer SMTP smtp_from=Wyślij e-mail jako smtp_from_helper=Adres e-mail, z którego Gitea będzie korzystać. Wpisz prosty adres e-mail, lub użyj formatu "Nazwa" . mailer_user=Nazwa użytkownika SMTP @@ -2494,11 +2492,8 @@ config.queue_length=Długość kolejki config.deliver_timeout=Limit czasu doręczenia config.skip_tls_verify=Pomiń weryfikację TLS -config.mailer_config=Konfiguracja dostawcy SMTP config.mailer_enabled=Włączona -config.mailer_disable_helo=Wyłącz HELO config.mailer_name=Nazwa -config.mailer_host=Serwer config.mailer_user=Użytkownik config.mailer_use_sendmail=Używaj Sendmail config.mailer_sendmail_path=Ścieżka Sendmail diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 99d8fb2db18a..b5c81702dc70 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -9,7 +9,6 @@ sign_out=Sair sign_up=Cadastrar link_account=Vincular conta register=Cadastrar -website=Site version=Versão powered_by=Desenvolvido por %s page=Página @@ -179,7 +178,8 @@ log_root_path_helper=Arquivos de log serão gravados neste diretório. optional_title=Configurações opcionais email_title=Configurações de e-mail -smtp_host=Host SMTP +smtp_addr=Host SMTP +smtp_port=Porta SMTP smtp_from=Enviar e-mail como smtp_from_helper=Endereço de e-mail que o Gitea irá usar. Digite um endereço de e-mail simples ou use o formato "Nome" . mailer_user=Nome de usuário do SMTP @@ -799,6 +799,7 @@ email_notifications.enable=Habilitar notificações de e-mail email_notifications.onmention=Somente e-mail com menção email_notifications.disable=Desabilitar notificações de e-mail email_notifications.submit=Atualizar preferências de e-mail +email_notifications.andyourown=E Suas Próprias Notificações visibility=Visibilidade do usuário visibility.public=Pública @@ -1034,13 +1035,6 @@ file_view_rendered=Ver Renderizado file_view_raw=Ver original file_permalink=Link permanente file_too_large=O arquivo é muito grande para ser mostrado. -bidi_bad_header=`Este arquivo contém caracteres Unicode Bidirecionais inesperados!` -bidi_bad_description=`Este arquivo contém caracteres Unicode bidirecionais inesperados que podem ser processados de forma diferente do que aparece abaixo. Se seu caso de uso for intencional e legítimo, você pode ignorar com segurança esse aviso. Use o botão Escapar para revelar caracteres ocultos.` -bidi_bad_description_escaped=`Este arquivo contém caracteres Unicode Bidirecionais inesperados. Caracteres unicode ocultos estão escapados abaixo. Use o botão Desescapar para mostrar como eles são mostrados.` -unicode_header=`Este arquivo contém caracteres Unicode ocultos!` -unicode_description=`Este arquivo contém caracteres Unicode ocultos que podem ser processados de forma diferente do que aparece abaixo. Se seu caso de uso for intencional e legítimo, você pode ignorar com segurança esse aviso. Use o botão Escapar para revelar caracteres ocultos.` -unicode_description_escaped=`Este arquivo contém caracteres Unicode ocultos. Caracteres unicode ocultos estão escapados abaixo. Utilize o botão Desescapar para mostrar como eles são mostrados.` -line_unicode=`Esta linha possui caracteres unicode ocultos` escape_control_characters=Escapar unescape_control_characters=Desescapar @@ -2773,11 +2767,11 @@ config.queue_length=Tamanho da fila config.deliver_timeout=Intervalo de entrega config.skip_tls_verify=Ignorar verificação de TLS -config.mailer_config=Configuração SMTP para envio de e-mail +config.mailer_config=Configuração de Envio de E-mail config.mailer_enabled=Habilitado -config.mailer_disable_helo=Desabilitar HELO config.mailer_name=Nome -config.mailer_host=Servidor +config.mailer_protocol=Protocolo +config.mailer_smtp_port=Porta SMTP config.mailer_user=Usuário config.mailer_use_sendmail=Usar o Sendmail config.mailer_sendmail_path=Caminho do Sendmail diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 57254925c488..de7935e78bb5 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -9,7 +9,6 @@ sign_out=Terminar sessão sign_up=Fazer inscrição link_account=Vincular conta register=Inscrição -website=Sítio web version=Versão powered_by=Implementado com %s page=Página @@ -179,7 +178,8 @@ log_root_path_helper=Os ficheiros de registo serão escritos nesta pasta. optional_title=Configurações opcionais email_title=Configurações de email -smtp_host=Servidor SMTP +smtp_addr=Servidor SMTP +smtp_port=Porto do SMTP smtp_from=Email do remetente smtp_from_helper=Endereço de email que o Gitea vai usar. Insira um endereço de email simples ou use o formato "Nome" . mailer_user=Nome de utilizador do SMTP @@ -1035,13 +1035,13 @@ file_view_rendered=Ver resultado processado file_view_raw=Ver em bruto file_permalink=Ligação permanente file_too_large=O ficheiro é demasiado grande para ser apresentado. -bidi_bad_header=`Este ficheiro contém caracteres Unicode Bidireccionais inesperados!` -bidi_bad_description=`Este ficheiro contém caracteres Unicode Bidireccionais inesperados que podem ser processados de forma diferente do que aparece abaixo. Se o uso é intencional e legítimo, pode ignorar este aviso com segurança. Use o botão Revelar para mostrar os caracteres escondidos.` -bidi_bad_description_escaped=`Este ficheiro contém caracteres Unicode Bidireccionais inesperados. Os caracteres escondidos unicode estão revelados abaixo. Use o botão Esconder para mostrar como é que eles são apresentados.` -unicode_header=`Este ficheiro contém caracteres Unicode escondidos!` -unicode_description=`Este ficheiro contém caracteres Unicode escondidos que podem ser processados de forma diferente do que aparece abaixo. Se o uso é intencional e legítimo, pode ignorar este aviso com segurança. Use o botão Revelar para mostrar os caracteres escondidos.` -unicode_description_escaped=`Este ficheiro contém caracteres Unicode escondidos. Os caracteres unicode escondidos estão revelados abaixo. Use o botão Esconder para mostrar como é que eles são apresentados.` -line_unicode=`Esta linha tem caracteres unicode escondidos` +invisible_runes_header=`Este ficheiro contém caracteres Unicode invisíveis!` +invisible_runes_description=`Este ficheiro contém caracteres Unicode invisíveis que podem ser processados de forma diferente do que aparece abaixo. Se o uso é intencional e legítimo, pode ignorar este aviso com segurança. Use o botão Revelar para mostrar os caracteres invisíveis.` +ambiguous_runes_header=`Este ficheiro contém caracteres Unicode ambíguos!` +ambiguous_runes_description=`Este ficheiro contém caracteres Unicode ambíguos que podem ser confundidos com outros da sua configuração regional vigente. Se o uso é intencional e legítimo, pode ignorar este aviso com segurança. Use o botão Revelar para realçar esses caracteres.` +invisible_runes_line=`Esta linha tem caracteres unicode invisíveis` +ambiguous_runes_line=`Esta linha tem caracteres unicode ambíguos` +ambiguous_character=`%[1]c [U+%04[1]X] pode confundir-se com %[2]c [U+%04[2]X]` escape_control_characters=Revelar unescape_control_characters=Esconder @@ -1062,6 +1062,7 @@ normal_view=Vista normal line=linha lines=linhas +editor.add_file=Adicionar ficheiro editor.new_file=Novo ficheiro editor.upload_file=Carregar ficheiro editor.edit_file=Editar ficheiro @@ -1267,6 +1268,8 @@ issues.filter_milestone=Etapa issues.filter_milestone_no_select=Todas as etapas issues.filter_assignee=Encarregado issues.filter_assginee_no_select=Todos os encarregados +issues.filter_poster=Autor(a) +issues.filter_poster_no_select=Todos os autores issues.filter_type=Tipo issues.filter_type.all_issues=Todas as questões issues.filter_type.assigned_to_you=Atribuídas a si @@ -2795,16 +2798,19 @@ config.queue_length=Tamanho da fila config.deliver_timeout=Prazo da entrega config.skip_tls_verify=Ignorar validação TLS -config.mailer_config=Configuração da aplicação SMTP +config.mailer_config=Configuração de envio de email config.mailer_enabled=Habilitado -config.mailer_disable_helo=Desabilitar HELO +config.mailer_enable_helo=Habilitar HELO config.mailer_name=Nome -config.mailer_host=Servidor +config.mailer_protocol=Protocolo +config.mailer_smtp_addr=Endereço SMTP +config.mailer_smtp_port=Porto do SMTP config.mailer_user=Utilizador config.mailer_use_sendmail=Usar o sendmail config.mailer_sendmail_path=Caminho do sendmail config.mailer_sendmail_args=Argumentos extras para o sendmail config.mailer_sendmail_timeout=Tempo limite do Sendmail +config.mailer_use_dummy=Fictício config.test_email_placeholder=Email (ex.: teste@exemplo.com) config.send_test_mail=Enviar email de teste config.test_mail_failed=Falhou o envio de um email de teste para '%s': %v @@ -2887,20 +2893,21 @@ monitor.queue.review_add=Rever/Adicionar trabalhadores monitor.queue.configuration=Configuração inicial monitor.queue.nopool.title=Sem agregado de trabalhadores monitor.queue.nopool.desc=Esta fila engloba outras filas e ela própria não tem um agregado de trabalhadores. -monitor.queue.wrapped.desc=Uma fila envolvente envolve uma fila de início lento, armazenando pedidos em fila num canal. Ela própria não tem um conjunto de tarefas. +monitor.queue.wrapped.desc=Uma fila envolvente envolve uma fila de início lento, armazenando pedidos em fila num canal. Ela própria não tem um agregado de trabalhadores. monitor.queue.persistable-channel.desc=Um canal persistente engloba duas filas, uma fila de canal que tem o seu próprio agregado de trabalhadores e uma fila de nível para pedidos persistentes de encerramentos anteriores. Ele próprio não tem um agregado de trabalhadores. +monitor.queue.flush=Trabalhador descartável monitor.queue.pool.timeout=Prazo monitor.queue.pool.addworkers.title=Adicionar trabalhadores monitor.queue.pool.addworkers.submit=Adicionar trabalhadores -monitor.queue.pool.addworkers.desc=Adicione trabalhadores a este agregado com, ou sem, prazo. Se definir um prazo, estes trabalhadores serão removidos do agregado, após o fim do prazo. +monitor.queue.pool.addworkers.desc=Adicione trabalhadores a este agregado com, ou sem, um prazo. Se definir um prazo, estes trabalhadores serão removidos do agregado, quando terminar esse prazo. monitor.queue.pool.addworkers.numberworkers.placeholder=Número de trabalhadores monitor.queue.pool.addworkers.timeout.placeholder=Insira 0 para indicar que não tem prazo -monitor.queue.pool.addworkers.mustnumbergreaterzero=O número de trabalhadores a adicionar deve ser maior que zero +monitor.queue.pool.addworkers.mustnumbergreaterzero=O número de trabalhadores a adicionar deve ser maior do que zero monitor.queue.pool.addworkers.musttimeoutduration=O prazo tem que ser uma duração no formato golang (ex.: 5m) ou 0 monitor.queue.pool.flush.title=Despejar fila -monitor.queue.pool.flush.desc=O despejo irá adicionar um trabalhador que termina assim que a fila esteja vazia ou o prazo acabe. -monitor.queue.pool.flush.submit=Adicionar trabalhador de despejo -monitor.queue.pool.flush.added=Foi adicionado um trabalhador de despejo para %[1]s +monitor.queue.pool.flush.desc='Descartável' irá adicionar um trabalhador que termina assim que a fila esteja vazia ou o prazo acabe. +monitor.queue.pool.flush.submit=Adicionar trabalhador descartável +monitor.queue.pool.flush.added=Foi adicionado um trabalhador descartável para %[1]s monitor.queue.pool.pause.title=Pausar fila monitor.queue.pool.pause.desc=Pausar uma fila impede que ela processe dados monitor.queue.pool.pause.submit=Pausar fila @@ -2909,11 +2916,11 @@ monitor.queue.pool.resume.desc=Definir esta fila para continuar o trabalho monitor.queue.pool.resume.submit=Retomar fila monitor.queue.settings.title=Configurações do agregado -monitor.queue.settings.desc=Os agregados crescem dinamicamente com um impulso em resposta à ocorrência de bloqueios na sua fila de trabalhadores. Essas mudanças não irão influenciar os grupos de trabalhadores correntes. +monitor.queue.settings.desc=Os agregados crescem dinamicamente com um aumento em resposta à ocorrência de bloqueios na sua fila de trabalhadores. Essas mudanças não irão influenciar os grupos de trabalhadores correntes. monitor.queue.settings.timeout=Prazo do impulso monitor.queue.settings.timeout.placeholder=De momento %[1]v monitor.queue.settings.timeout.error=O prazo tem que ser uma duração no formato golang (ex: 5m) ou 0 -monitor.queue.settings.numberworkers=Número de trabalhadores do impulso +monitor.queue.settings.numberworkers=Aumentar o número de trabalhadores monitor.queue.settings.numberworkers.placeholder=De momento %[1]d monitor.queue.settings.numberworkers.error=O número de trabalhadores a adicionar tem que ser maior ou igual a zero monitor.queue.settings.maxnumberworkers=Número máximo de trabalhadores @@ -2925,14 +2932,14 @@ monitor.queue.settings.blocktimeout=Prazo do bloco corrente monitor.queue.settings.blocktimeout.value=%[1]v monitor.queue.pool.none=Esta fila não tem um agregado -monitor.queue.pool.added=Foi adicionado um agregado de trabalhadores +monitor.queue.pool.added=Foi adicionado um grupo de trabalhadores monitor.queue.pool.max_changed=O número máximo de trabalhadores mudou monitor.queue.pool.workers.title=Grupos de trabalhadores operantes -monitor.queue.pool.workers.none=Não há agregados de trabalhadores. -monitor.queue.pool.cancel=Desligar agregado de trabalhadores -monitor.queue.pool.cancelling=O agregado de trabalhadores está a encerrar -monitor.queue.pool.cancel_notices=Desligar este agregado de %s trabalhadores? -monitor.queue.pool.cancel_desc=Deixar uma fila sem quaisquer agregados de trabalhadores pode fazer com que os pedidos bloqueiem indefinidamente. +monitor.queue.pool.workers.none=Não há grupos de trabalhadores. +monitor.queue.pool.cancel=Desligar o grupo de trabalhadores +monitor.queue.pool.cancelling=O grupo de trabalhadores está a encerrar +monitor.queue.pool.cancel_notices=Desligar este grupo de %s trabalhadores? +monitor.queue.pool.cancel_desc=Deixar uma fila sem quaisquer grupos de trabalhadores pode fazer com que os pedidos sejam bloqueados indefinidamente. notices.system_notice_list=Notificações do sistema notices.view_detail_header=Ver os detalhes da notificação @@ -3107,6 +3114,10 @@ npm.dependencies.development=Dependências de desenvolvimento npm.dependencies.peer=Dependências de pares npm.dependencies.optional=Dependências opcionais npm.details.tag=Etiqueta +pub.install=Para instalar o pacote usando o Dart, execute o seguinte comando: +pub.documentation=Para obter mais informações sobre o registo Pub, consulte a documentação. +pub.details.repository_site=Página web do repositório +pub.details.documentation_site=Página web da documentação pypi.requires=Requer Python pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando: pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação. @@ -3114,6 +3125,8 @@ rubygems.install=Para instalar o pacote usando o gem, execute o seguinte comando rubygems.install2=ou adicione-o ao ficheiro Gemfile: rubygems.dependencies.runtime=Dependências do tempo de execução (runtime) rubygems.dependencies.development=Dependências de desenvolvimento +rubygems.required.ruby=Requer a versão do Ruby +rubygems.required.rubygems=Requer a versão do RubyGem rubygems.documentation=Para obter mais informações sobre o registo do RubyGems, consulte a documentação. settings.link=Vincular este pacote a um repositório settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index ad8ee86d02e1..a185fe0cb074 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -9,7 +9,6 @@ sign_out=Выход sign_up=Регистрация link_account=Привязать аккаунт register=Регистрация -website=Веб-сайт version=Версия powered_by=Работает на %s page=Страница @@ -177,7 +176,6 @@ log_root_path_helper=Файлы журнала будут записыватьс optional_title=Расширенные настройки email_title=Настройки электронной почты -smtp_host=Узел SMTP smtp_from=Отправить эл. почту как smtp_from_helper=Адрес электронной почты, который будет использоваться Gitea. Введите обычный адрес электронной почты или используйте формат "Имя" . mailer_user=SMTP логин @@ -2681,11 +2679,8 @@ config.queue_length=Длина очереди config.deliver_timeout=Задержка доставки config.skip_tls_verify=Пропустить проверку TLS -config.mailer_config=Настройки почты config.mailer_enabled=Почта включена -config.mailer_disable_helo=Отключить HELO config.mailer_name=Имя -config.mailer_host=Сервер config.mailer_user=Пользователь config.mailer_use_sendmail=Использовать Sendmail config.mailer_sendmail_path=Путь к Sendmail diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index 069a871045c2..7e7b140f2690 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -8,7 +8,6 @@ sign_out=නික්මෙන්න sign_up=ලියාපදිංචිය link_account=ගිණුම සබැඳින්න register=ලියාපදිංචිය -website=වියමන අඩවිය version=අනුවාදය powered_by=%s මගින් බලගන්වා ඇත page=පිටුව @@ -151,7 +150,6 @@ log_root_path_helper=ලොග් ගොනු මෙම ඩිරෙක්ට optional_title=වෛකල්පිත සැකසුම් email_title=වි-තැපෑලේ සැකසුම් -smtp_host=SMTP සත්කාරක smtp_from=ලෙස වි-තැපෑල යවන්න smtp_from_helper=විද්යුත් තැපැල් ලිපිනය Gitea භාවිතා කරනු ඇත. සරල විද්යුත් තැපැල් ලිපිනයක් ඇතුළත් කරන්න හෝ “නම” ආකෘතිය භාවිතා කරන්න. mailer_user=SMTP පරිශීලක නාමය @@ -2508,11 +2506,8 @@ config.queue_length=පෝලිම් දිග config.deliver_timeout=කාලය ගලවාගන්න config.skip_tls_verify=TLS සත්යාපනය මඟ හරින්න -config.mailer_config=SMTP තැපැල්කරු වින්යාසය config.mailer_enabled=සබල කර ඇත -config.mailer_disable_helo=හෙලෝ අක්රීය කරන්න config.mailer_name=නම -config.mailer_host=සත්කාරක config.mailer_user=පරිශීලක config.mailer_use_sendmail=සෙන්ඩ්මේල් භාවිතා කරන්න config.mailer_sendmail_path=සෙන්ඩ්මේල් මාර්ගය diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 717481ec5401..00d1034fc614 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -8,7 +8,6 @@ sign_out=Logga ut sign_up=Registrera link_account=Länka konto register=Registrera dig -website=Webbplats version=Version powered_by=Drivs av %s page=Sida @@ -60,7 +59,7 @@ forks=Forks activities=Aktiviteter pull_requests=Pull förfrågningar -issues=Problem +issues=Ärenden milestones=Milstolpar cancel=Avbryt @@ -138,7 +137,6 @@ log_root_path_helper=Loggfiler kommer skrivas till denna katalog. optional_title=Övriga inställningar email_title=Mejlinställningar -smtp_host=SMTP-server smtp_from=Skicka Mejl Som smtp_from_helper=Mejladress som Gitea kommer att använda. Anges i simpelt ('email@example.com') eller fullständigt ('Name ') format. mailer_user=SMTP-Användarnamn @@ -644,15 +642,19 @@ generate_from=Generera från repo_desc=Beskrivning repo_lang=Språk repo_gitignore_helper=Välj .gitignore-mallar. +repo_gitignore_helper_desc=Välj vilka filer som inte ska spåras från en lista med mallar för vanliga språk. Typiska artefakter som genereras av varje språk byggverktyg ingår i .gitignore som standard. issue_labels=Ärendeetiketter issue_labels_helper=Välj en grupp av ärendeetiketter. license=Licens license_helper=Välj licensfil. +license_helper_desc=En licens styr vad andra kan och inte kan göra med din kod. Inte säker på vilken som är rätt för ditt projekt? Se Välj en licens. readme=README readme_helper=Välj en mall för README-filen. +readme_helper_desc=Här kan du skriva en fullständig beskrivning för ditt projekt. auto_init=Initiera utvecklingskatalog (Lägger till .gitignore, License and README) create_repo=Skapa utvecklingskatalog default_branch=Standardgren +default_branch_helper=Den förvalda grenen är bas-gren för pull requests och kod-commits. mirror_prune=Rensa mirror_prune_desc=Ta bort förlegade fjärrföljande referenser mirror_interval_invalid=Speglingsintervallen är inte giltig. @@ -721,6 +723,7 @@ migrated_from_fake=Migrerad från %[1]s migrate.migrate=Migrera från %s migrate.migrating=Migrerar från %s ... migrate.migrating_failed=Migrering från %s misslyckades. +migrate.migrating_issues=Migrerar Ärenden mirror_from=spegling av forked_from=forkad från @@ -907,7 +910,7 @@ issues.new.add_reviewer_title=Begär granskning issues.choose.get_started=Kom igång issues.choose.blank=Standard issues.choose.blank_about=Skapa ett ärende från standardmall. -issues.no_ref=Ingen branch/Tag specificerad +issues.no_ref=Ingen Branch/Tag specificerad issues.create=Skapa Ärende issues.new_label=Ny etikett issues.new_label_placeholder=Etikettsnamn @@ -973,6 +976,7 @@ issues.commented_at=`kommenterad %s` issues.delete_comment_confirm=Är du säker på att du vill ta bort den här kommentaren? issues.context.copy_link=Kopiera länk issues.context.quote_reply=Citerat svar +issues.context.reference_issue=Referens i nytt ärende issues.context.edit=Redigera issues.context.delete=Ta bort issues.no_content=Det finns inget innehåll än. @@ -982,6 +986,7 @@ issues.reopen_issue=Återöppna issues.reopen_comment_issue=Kommentera och återöppna issues.create_comment=Kommentera issues.closed_at=`stängde ärendet %[2]s` +issues.reopened_at=`återöppnade detta ärende %[2]s` issues.commit_ref_at=`refererade till detta ärende från en incheckning %[2]s` issues.ref_issue_from=`refererade till detta ärende %[4]s %[2]s` issues.ref_pull_from=`refererade till denna pull-förfrågan %[4]s %[2]s` @@ -1039,10 +1044,13 @@ issues.lock.reason=Anledningen till att låsa issues.lock.title=Lås konversationen för detta ärende. issues.unlock.title=Lås upp konversation för ärendet. issues.comment_on_locked=Du kan inte kommentera ett låst ärende. +issues.delete.title=Radera detta ärende? +issues.delete.text=Vill du verkligen ta bort detta ärende? (Detta kommer att permanent ta bort allt innehåll. Överväg att stänga det istället om du avser att hålla det arkiverat) issues.tracker=Tidsredovisning issues.start_tracking=Starta tidsredovisning issues.start_tracking_history=`började arbeta %s` issues.tracker_auto_close=Timern stoppas automatiskt när ärendet stängs +issues.tracking_already_started=`Du har redan påbörjat tidredovisning på ett annat ärende!` issues.stop_tracking_history=`slutade arbeta %s` issues.cancel_tracking_history=”avbröt tidredovisning %s' issues.add_time=Lägg till tid manuellt @@ -1115,6 +1123,7 @@ issues.review.hide_resolved=Dölj löst issues.review.resolve_conversation=Lös konversation issues.review.resolved_by=markerade denna konversation som löst issues.assignee.error=Inte alla tilldelade har lagts till på grund av ett oväntat fel. +issues.content_history.options=Alternativ pulls.desc=Aktivera pull-förfrågningar och kodgranskning. @@ -1158,6 +1167,7 @@ pulls.invalid_merge_option=Du kan inte använda detta mergealternativet för den ; %[2]s
%[3]s
pulls.open_unmerged_pull_exists=`Du kan inte återuppliva denna pull-request då det redan finns en identisk pull-request öppen (#%d).` pulls.update_branch_success=Uppdatering av branchen lyckades +pulls.update_not_allowed=Du är inte behörig att uppdatera grenen pulls.outdated_with_base_branch=Denna branch är föråldrad gentemot bas-branchen @@ -1270,6 +1280,7 @@ activity.git_stats_exclude_merges=Exkludera merger, activity.git_stats_author_1=%d författare activity.git_stats_author_n=%d författare activity.git_stats_push_to_all_branches=till alla brancher. +activity.git_stats_on_default_branch=På %s, activity.git_stats_file_1=%d fil activity.git_stats_file_n=%d filer activity.git_stats_files_changed_1=har ändrats @@ -1414,6 +1425,7 @@ settings.event_push=Pusha settings.event_push_desc=Git push till en utvecklingskatalog. settings.event_repository=Utvecklingskatalog settings.event_repository_desc=Utvecklingskatalogen skapad eller borttagen. +settings.event_header_issue=Ärendehändelser settings.event_issues=Ärenden settings.event_issue_comment=Kommentar settings.event_issue_comment_desc=Kommentar skapad, ändrad eller borttagen. @@ -1516,6 +1528,7 @@ settings.lfs_force_unlock=Tvinga upplåsning settings.lfs_pointers.sha=Blob SHA settings.lfs_pointers.oid=OID settings.lfs_pointers.inRepo=I utvecklingskatalogen +settings.rename_branch_failed_not_exist=Kan inte byta namn på branchen %s eftersom den inte finns. diff.browse_source=Bläddra i källkod diff.parent=förälder @@ -1969,11 +1982,8 @@ config.queue_length=Kölängd config.deliver_timeout=Tidsfrist för leverans config.skip_tls_verify=Skippa TLS verifiering -config.mailer_config=SMTP-Mailer konfiguration config.mailer_enabled=Aktiverad -config.mailer_disable_helo=Avaktivera HELO config.mailer_name=Namn -config.mailer_host=Server config.mailer_user=Användare config.mailer_use_sendmail=Använd Sendmail config.mailer_sendmail_path=Sendmail sökväg diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 4197f14e5069..d92c46eae420 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -9,7 +9,6 @@ sign_out=Çıkış Yap sign_up=Kaydol link_account=Bağlantı hesabı register=Üye Ol -website=Web sitesi version=Sürüm powered_by=%s tarafından desteklenen page=Sayfa @@ -111,6 +110,7 @@ rss_feed=RSS Beslemesi occurred=Bir hata oluştu report_message=Bunun bir Gitea hatası olduğundan eminseniz, lütfen GitHub sayfasında sorunu arayın veya gerekiyorsa yeni bir sorun açın. missing_csrf=Hatalı İstek: CSRF anahtarı yok +invalid_csrf=Hatalı İstek: geçersiz CSRF erişim anahtarı not_found=Hedef bulunamadı. network_error=Ağ hatası @@ -178,7 +178,8 @@ log_root_path_helper=Günlük dosyaları bu dizine kaydedilecektir. optional_title=İsteğe Bağlı Ayarlar email_title=E-posta Ayarları -smtp_host=SMTP Sunucusu +smtp_addr=SMTP Sunucusu +smtp_port=SMTP Portu smtp_from=E-posta Gönderen smtp_from_helper=Gitea'nın kullanacağı e-posta adresi. Yalın bir e-posta adresi girin veya "İsim" biçimini kullanın. mailer_user=SMTP Kullanıcı Adı @@ -555,6 +556,7 @@ cancel=İptal language=Dil ui=Tema hidden_comment_types=Gizli yorum türleri +comment_type_group_reference=Referans comment_type_group_label=Etiket comment_type_group_milestone=Dönüm noktası comment_type_group_assignee=Atanan @@ -660,7 +662,13 @@ verify_gpg_key_success=GPG anahtarı '%s' doğrulandı. ssh_key_verified=Doğrulanmış Anahtar ssh_key_verified_long=Bu anahtar bir belirteç ile doğrulandı ve bu kullanıcı için etkinleştirilmiş herhangi bir e-posta adresi ile uyuşan işlemeleri doğrulamak için kullanılabilir. ssh_key_verify=Doğrula +ssh_invalid_token_signature=Verilen SSH anahtarı, imza veya erişim anahtarı uyuşmuyor veya erişim anahtarı çok eski. +ssh_token_required=Aşağıdaki erişim anahtarı için bir imza sağlamalısınız +ssh_token=Erişim Anahtarı ssh_token_help=Şunu kullanarak bir imza oluşturabilirsiniz: +ssh_token_signature=Korumalı SSH imzası +key_signature_ssh_placeholder='-----BEGIN SSH SIGNATURE-----' ile başlar +verify_ssh_key_success=SSH anahtarı '%s' doğrulandı. subkeys=Alt anahtarlar key_id=Anahtar Kimliği key_name=Anahtar İsmi @@ -708,6 +716,9 @@ generate_token_success=Yeni bir jeton oluşturuldu. Tekrar gösterilmeyeceği i generate_token_name_duplicate=%s zaten bir uygulama adı olarak kullanılmış. Lütfen yeni bir tane kullanın. delete_token=Sil access_token_deletion=Erişim Jetonunu Sil +access_token_deletion_cancel_action=İptal +access_token_deletion_confirm_action=Sil +access_token_deletion_desc=Bir erişim anahtarını silmek, onu kullanan uygulamaların hesabınıza erişimini kaldırır. Bu geri alınamaz. Devam edilsin mi? delete_token_success=Jeton silindi. Onu kullanan uygulamalar artık hesabınıza erişemez. manage_oauth2_applications=OAuth2 Uygulamalarını Yönet @@ -760,10 +771,16 @@ passcode_invalid=Şifre geçersiz. Tekrar deneyin. twofa_enrolled=Hesabınız iki faktörlü kimlik doğrulamasına kaydedildi. Kazıma belirtecini (%s) yalnızca bir kez gösterdiği gibi güvenli bir yerde saklayın! twofa_failed_get_secret=Gizlilik elde edilemedi. +webauthn_desc=Güvenlik anahtarları, şifreleme anahtarlarını içeren donanım aygıtlarıdır. İki aşamalı kimlik doğrulama için kullanılabilirler. Güvenlik anahtarları WebAuthn Authenticator standardını desteklemelidir. +webauthn_register_key=Güvenlik Anahtarı Ekle +webauthn_nickname=Takma Ad +webauthn_delete_key=Güvenlik Anahtarını Kaldır +webauthn_delete_key_desc=Bir güvenlik anahtarını kaldırırsanız, onunla artık giriş yapamazsınız. Devam edilsin mi? manage_account_links=Bağlı Hesapları Yönet manage_account_links_desc=Bu harici hesaplar Gitea hesabınızla bağlantılı. account_links_not_available=Şu anda Gitea hesabınıza bağlı harici bir hesap yok. +link_account=Hesap Bağla remove_account_link=Bağlantılı Hesabı Kaldır remove_account_link_desc=Bağlantılı bir hesabı kaldırmak, onunla Gitea hesabınıza erişimi iptal edecektir. Devam edilsin mi? remove_account_link_success=Bağlantılı hesap kaldırıldı. @@ -782,6 +799,7 @@ email_notifications.enable=E-posta Bildirimlerini Etkinleştir email_notifications.onmention=Sadece Bahsedilen E-posta email_notifications.disable=E-posta Bildirimlerini Devre Dışı Bırak email_notifications.submit=E-posta Tercihlerini Ayarla +email_notifications.andyourown=Ve Sizin Bildirimleriniz visibility=Kullanıcı görünürlüğü visibility.public=Herkese Açık @@ -844,7 +862,9 @@ default_branch=Varsayılan Dal default_branch_helper=Varsayılan dal, değişiklik istekleri ve kod işlemeleri için temel daldır. mirror_prune=Buda mirror_prune_desc=Kullanılmayan uzak depoları izleyen referansları kaldır +mirror_interval=Yansı Aralığı (geçerli zaman birimleri 'h', 'm', 's'). Periyodik senkronizasyonu devre dışı bırakmak için 0 kullanın. (Asgari aralık: %s) mirror_interval_invalid=Yansı süre aralığı geçerli değil. +mirror_sync_on_commit=İşlemeler gönderildiğinde senkronize et mirror_address=URL'den Klonla mirror_address_desc=Yetkilendirme bölümüne gerekli tüm kimlik bilgilerini girin. mirror_address_url_invalid=Sağlanan Url geçersiz. Url'nin tüm bileşenlerinden doğru olarak kaçmalısınız. @@ -892,7 +912,8 @@ desc.archived=Arşivlenmiş template.items=Şablon Öğeleri template.git_content=Git İçeriği (Varsayılan Dal) -template.git_hooks=Git İstekleri +template.git_hooks=Git İstemcileri +template.git_hooks_tooltip=Eklendikten sonra Git İstemcilerini değiştirmek veya kaldırmak mümkün değildir. Bunu yalnızca şablon deposuna güveniyorsanız seçin. template.webhooks=Web İstemcileri template.topics=Konular template.avatar=Profil Resmi @@ -912,6 +933,7 @@ form.name_pattern_not_allowed='%s' deseni, depo adı için geçerli değildir. need_auth=Yetkilendirme migrate_options=Göç Seçenekleri migrate_service=Göç Hizmeti +migrate_options_mirror_helper=Bu depo bir yansı olacaktır migrate_options_lfs=LFS dosyalarını taşı migrate_options_lfs_endpoint.label=LFS Uç Noktası migrate_options_lfs_endpoint.description=Taşıma, LFS sunucusunu belirlemek için Git uzak sunucusunu kullanmaya çalışacak. Eğer LFS veri deposu başka yerdeyse özel bir uç nokta da belirtebilirsiniz. @@ -928,8 +950,10 @@ migrate_items_releases=Sürümler migrate_repo=Depoyu Göç Ettir migrate.clone_address=URL'den Taşı / Klonla migrate.clone_address_desc=Varolan bir deponun HTTP(S) veya Git 'klonlama' URL'si +migrate.github_token_desc=GitHub API hız sınırı nedeniyle göçü hızlandırmak için buraya virgülle ayrılmış bir veya daha fazla erişm anahtarı koyabilirsiniz. UYARI: Bu özelliğin kötüye kullanılması, hizmet sağlayıcının politikasını ihlal edebilir ve hesabın engellenmesine yol açabilir. migrate.clone_local_path=veya bir yerel sunucu yolu migrate.permission_denied=Yerel depoları içeri aktarma izniniz yok. +migrate.permission_denied_blocked=İzin verilmeyen sunuculardan içe aktaramazsınız, lütfen yöneticiden ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS ayarlarını kontrol etmesini isteyin. migrate.invalid_local_path=Yerel yol geçersiz. Mevcut değil veya bir dizin değil. migrate.invalid_lfs_endpoint=LFS Uç noktası geçerli değil. migrate.failed=Göç başarısız: %v @@ -977,6 +1001,7 @@ clone_this_repo=Bu depoyu klonla create_new_repo_command=Komut satırında yeni bir depo oluşturuluyor push_exist_repo=Komut satırından mevcut bir depo itiliyor empty_message=Bu depoda herhangi bir içerik yok. +broken_message=Bu deponun altındaki Git verisi okunamıyor. Bu sunucunun yöneticisiyle bağlantıya geçin veya bu depoyu silin. code=Kod code.desc=Kaynak koda, dosyalara, işlemelere ve dallara eriş. @@ -990,6 +1015,7 @@ tags=Etiket issues=Konular pulls=Değişiklik İstekleri project_board=Projeler +packages=Paketler labels=Etiketler org_labels_desc=Bu organizasyon altında tüm depolarla kullanılabilen organizasyon düzeyinde etiketler org_labels_desc_manage=yönet @@ -1001,6 +1027,7 @@ release=Sürüm releases=Sürüm tag=Etiket released_this=bu sürümü yayınladı +file.title=%s dalındaki/etiketindeki %s file_raw=Ham file_history=Geçmiş file_view_source=Kaynağı Görüntüle @@ -1008,7 +1035,18 @@ file_view_rendered=Oluşturulanları Görüntüle file_view_raw=Ham Görünüm file_permalink=Kalıcı Bağlantı file_too_large=Bu dosya görüntülemek için çok büyük. - +invisible_runes_header=`Bu dosya görünmez Evrensel Kodlu karakter içeriyor!` +invisible_runes_description=`Bu dosya, aşağıda görünenden farklı bir şekilde işlenebilecek görünmez Evrensel Kodlu karakter içeriyor. Eğer bunu kasıtlı ve meşru olarak yaptıysanız bu uyarıyı yok sayabilirsiniz. Gizli karakterleri göstermek için Kaçış düğmesine tıklayın.` +ambiguous_runes_header=`Bu dosya muğlak Evrensel Kodlu karakter içeriyor!` +ambiguous_runes_description=`Bu dosya, aşağıda görünenden farklı bir şekilde işlenebilecek muğlak Evrensel Kodlu karakter içeriyor. Eğer bunu kasıtlı ve meşru olarak yaptıysanız bu uyarıyı yok sayabilirsiniz. Bu karakterleri göstermek için Kaçış düğmesine tıklayın.` +invisible_runes_line=`Bu satırda görünmez evrensel kodlu karakter var` +ambiguous_runes_line=`Bu satırda muğlak evrensel kodlu karakter var` +ambiguous_character=`%[1]c [U+%04[1]X], %[2]c [U+%04[2]X] ile karıştırılabilir` + +escape_control_characters=Kaçış Karakterli +unescape_control_characters=Kaçış Karaktersiz +file_copy_permalink=Kalıcı Bağlantıyı Kopyala +view_git_blame=Git Suç Görüntüle video_not_supported_in_browser=Tarayıcınız HTML5 'video' etiketini desteklemiyor. audio_not_supported_in_browser=Tarayıcınız HTML5 'audio' etiketini desteklemiyor. stored_lfs=Git LFS ile depolandı @@ -1024,6 +1062,7 @@ normal_view=Normal Görünüm line=satır lines=satır +editor.add_file=Dosya Ekle editor.new_file=Yeni dosya editor.upload_file=Dosya Yükle editor.edit_file=Dosyayı Düzenle @@ -1086,6 +1125,8 @@ editor.cannot_commit_to_protected_branch=Korunan '%s' dalına işleme yapılamı editor.no_commit_to_branch=Doğrudan dala işleme yapılamıyor çünkü: editor.user_no_push_to_branch=Kullanıcı dala gönderemez editor.require_signed_commit=Dal imzalı bir işleme gerektirir +editor.cherry_pick=%s şunun üzerine cımbızla: +editor.revert=%s şuna geri döndür: commits.desc=Kaynak kodu değişiklik geçmişine göz atın. commits.commits=İşleme @@ -1109,6 +1150,7 @@ commits.ssh_key_fingerprint=SSH Anahtar Parmak İzi commit.actions=Eylemler commit.revert=Geri Al commit.revert-header=Geri al: %s +commit.revert-content=Geri almak için dal seçin: commit.cherry-pick=Cımbızla commit.cherry-pick-header=Cımbızla: %s commit.cherry-pick-content=Cımbızlamak için dal seçin: @@ -1150,6 +1192,7 @@ projects.board.deletion_desc=Bir proje panosunun silinmesi, ilgili tüm konular projects.board.color=Renk projects.open=Aç projects.close=Kapat +projects.board.assigned_to=Atanan issues.desc=Hata raporlarını, görevleri ve kilometre taşlarını yönetmenizi sağlar. issues.filter_assignees=Atama Süzgeci @@ -1214,6 +1257,9 @@ issues.add_assignee_at=`%[2]s %[1]s tarafından atandı` issues.remove_assignee_at=`ataması %[2]s %[1]s tarafından kaldırıldı` issues.remove_self_assignment=`atamalarını kaldırdı %s` issues.change_title_at=`başlığı %s iken %s olarak %s değiştirdi` +issues.change_ref_at=`%s referans %s %s olarak değiştirildi` +issues.remove_ref_at=`%s referansı %s tarihinde kaldırıldı` +issues.add_ref_at=`%s referansı %s tarihinde eklendi` issues.delete_branch_at=`%s dalı silindi %s` issues.filter_label=Etiket issues.filter_label_exclude=`Etiketleri hariç tutmak için alt + tıkla/enter kullanın` @@ -1222,6 +1268,8 @@ issues.filter_milestone=Kilometre Taşı issues.filter_milestone_no_select=Tüm kilometre taşları issues.filter_assignee=Atanan issues.filter_assginee_no_select=Tüm atananlar +issues.filter_poster=Yazar +issues.filter_poster_no_select=Tüm yazarlar issues.filter_type=Tür issues.filter_type.all_issues=Tüm konular issues.filter_type.assigned_to_you=Size atanan @@ -1241,6 +1289,7 @@ issues.filter_sort.moststars=En çok yıldızlılar issues.filter_sort.feweststars=En az yıldızlılar issues.filter_sort.mostforks=En çok çatallananlar issues.filter_sort.fewestforks=En az çatallananlar +issues.keyword_search_unavailable=Anahtar kelime ile arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin. issues.action_open=Açık issues.action_close=Kapat issues.action_label=Etiket @@ -1249,7 +1298,11 @@ issues.action_milestone_no_select=Kilometre Taşı Yok issues.action_assignee=Atanan issues.action_assignee_no_select=Atanan yok issues.opened_by=%[3]s tarafından %[1]s açıldı +pulls.merged_by=%[1]s %[3]s tarafından açılan istek birleştirildi +pulls.merged_by_fake=%[2]s tarafından açılan istek %[1]s birleştirildi +issues.closed_by=%[3]s tarafından %[1]s kapatıldı issues.opened_by_fake=%[2]s tarafından %[1]s açıldı +issues.closed_by_fake=%[2]s tarafından %[1]s kapatıldı issues.previous=Önceki issues.next=Sonraki issues.open_title=Açık @@ -1370,7 +1423,8 @@ issues.due_date_form_edit=Düzenle issues.due_date_form_remove=Kaldır issues.due_date_not_writer=Bir konunun bitiş tarihini değiştirmek için depoda yazma hakkınız olmalıdır. issues.due_date_not_set=Bitiş tarihi atanmadı. -issues.due_date_added=%[2]s %[1]s bitiş tarihini ekledi +issues.due_date_added=bitiş tarihini %s olarak %s ekledi +issues.due_date_modified=bitiş tarihini %[2]s iken %[1]s olarak %[3]s değiştirdi issues.due_date_remove=%[2]s %[1]s bitiş tarihini kaldırdı issues.due_date_overdue=Süresi Geçmiş issues.due_date_invalid=Bitiş tarihi geçersiz veya aralık dışında. Lütfen 'yyyy-aa-gg' biçimini kullanın. @@ -1432,6 +1486,7 @@ issues.content_history.deleted=silindi issues.content_history.edited=düzenlendi issues.content_history.created=oluşturuldu issues.content_history.delete_from_history=Geçmişten kaldır +issues.content_history.delete_from_history_confirm=Geçmişten kaldırılsın mı? issues.content_history.options=Seçenekler issues.reference_link=Referans: %s @@ -1442,6 +1497,8 @@ pulls.desc=Değişiklik isteklerini ve kod incelemelerini etkinleştir. pulls.new=Yeni Değişiklik İsteği pulls.view=Değişiklik İsteği Görüntüle pulls.compare_changes=Yeni Değişiklik İsteği +pulls.allow_edits_from_maintainers=Bakımcıların düzenlemelerine izin ver +pulls.allow_edits_from_maintainers_desc=Ana dala yazma hakkı olan kullanıcılar bu dala da gönderebilirler pulls.allow_edits_from_maintainers_err=Güncelleme başarısız oldu pulls.compare_changes_desc=Birleştirmek için hedef ve kaynak dalı seçin. pulls.has_viewed_file=Görüldü @@ -1524,7 +1581,10 @@ pulls.rebase_conflict_summary=Hata Mesajı ; %[2]s
%[3]s
pulls.unrelated_histories=Birleştirme Başarısız: Birleştirme başlığı ve tabanı ortak bir geçmişi paylaşmıyor. İpucu: Farklı bir strateji deneyin pulls.merge_out_of_date=Birleştirme Başarısız: Birleştirme oluşturulurken, taban güncellendi. İpucu: Tekrar deneyin. +pulls.head_out_of_date=Birleştirme Başarısız: Birleştirme oluşturulurken, ana güncellendi. İpucu: Tekrar deneyin. +pulls.push_rejected=Birleştirme Başarısız Oldu: Gönderme reddedildi. Bu depo için Git İstemcilerini inceleyin. pulls.push_rejected_summary=Tam Red Mesajı +pulls.push_rejected_no_message=Birleştirme başarısız oldu: Gönderme reddedildi, ancak uzak bir mesaj yoktu.
Bu depo için Git İstemcilerini inceleyin pulls.open_unmerged_pull_exists=`Aynı özelliklere sahip bekleyen bir değişiklik isteği (#%d) olduğundan yeniden açma işlemini gerçekleştiremezsiniz.` pulls.status_checking=Bazı denetlemeler beklemede pulls.status_checks_success=Tüm denetlemeler başarılı oldu @@ -1547,9 +1607,17 @@ pulls.merge_instruction_step2_desc=Gitea'daki değişiklikleri ve güncellemeler pulls.auto_merge_button_when_succeed=(Denetlemeler başarılı olduğunda) pulls.auto_merge_when_succeed=Tüm denetlemeler başarılı olduğundan otomatik olarak birleştir pulls.auto_merge_newly_scheduled=Değişiklik İsteği tüm denetlemeler başarılı olduğunda birleştirilecek şekilde ayarlanmış. +pulls.auto_merge_has_pending_schedule=%[1]s, bu değişiklik isteğini tüm denetlemeler başarılı olduğunda %[2]s, otomatik olarak birleşecek şekilde ayarlamış. +pulls.auto_merge_cancel_schedule=Otomatik birleştirmeyi iptal et +pulls.auto_merge_not_scheduled=Bu değişiklik isteği için otomatik birleştirme zamanlanmamış. +pulls.auto_merge_canceled_schedule=Bu değişiklik isteği için otomatik birleştirme iptal edildi. +pulls.auto_merge_newly_scheduled_comment=`bu değişiklik isteği, tüm denetlemeler başarılı olduğunda %[1]s, otomatik olarak birleşecek şekilde ayarlandı` +pulls.auto_merge_canceled_schedule_comment=`bu değişiklik isteğinin, tüm denetlemeler başarılı olduğunda %[1]s, otomatik birleştirmesi iptal edildi` +pulls.delete.title=Bu değişiklik isteği silinsin mi? +pulls.delete.text=Bu değişiklik isteğini gerçekten silmek istiyor musunuz? (Bu işlem tüm içeriği kalıcı olarak silecektir. Arşivde tutma niyetiniz varsa silmek yerine kapatmayı düşünün) milestones.new=Yeni Kilometre Taşı milestones.closed=Kapalı %s @@ -1595,6 +1663,7 @@ signing.wont_sign.commitssigned=İlişkili tüm işlemeler imzalanmadığı içi signing.wont_sign.approved=Değişiklik İsteği onaylanmadığı için birleştirme imzalanmayacak signing.wont_sign.not_signed_in=Oturum açmadınız +ext_wiki=Harici Vikiye Erişim ext_wiki.desc=Harici bir wiki'ye bağlantı. wiki=Wiki @@ -1619,6 +1688,7 @@ wiki.page_already_exists=Aynı isimde bir Wiki sayfası zaten var. wiki.reserved_page='%s' wiki sayfa adı rezerve edilmiştir. wiki.pages=Sayfalar wiki.last_updated=Son güncelleme %s +wiki.page_name_desc=Bu Viki sayfası için bir ad girin. Bazı özel isimler 'Home', '_Sidebar' ve '_Footer' şeklindedir. activity=Aktivite activity.period.filter_label=Dönem: @@ -1691,6 +1761,8 @@ search.search_repo=Depo ara search.fuzzy=Belirsiz search.match=Eşleştir search.results="%s" için %s içinde sonuçları ara +search.code_no_results=Arama teriminizle eşleşen bir kaynak kod bulunamadı. +search.code_search_unavailable=Kod arama şu an mevcut değil. Lütfen site yöneticisiyle iletişime geçin. settings=Ayarlar settings.desc=Ayarlar, depo için ayarları yönetebileceğiniz yerdir @@ -1702,7 +1774,7 @@ settings.collaboration.read=Oku settings.collaboration.owner=Sahibi settings.collaboration.undefined=Belirsiz settings.hooks=Web İstemcileri -settings.githooks=Git İstekleri +settings.githooks=Git İstemcileri settings.basic_settings=Temel Ayarlar settings.mirror_settings=Yansıma Ayarları settings.mirror_settings.docs=Projenizi, değişiklikleri başka bir depoya/depodan otomatik olarak gönderecek ve/veya çekecek şekilde ayarlayın. Dallar, etiketler ve işlemeler otomatik olarak senkronize edilecektir. Depoları nasıl yansıtrım? @@ -1737,6 +1809,9 @@ settings.tracker_url_format_error=Harici konu izleyici URL biçimi geçerli bir settings.tracker_issue_style=Harici Konu İzleyici Numara Biçimi settings.tracker_issue_style.numeric=Sayısal settings.tracker_issue_style.alphanumeric=Alfanumerik +settings.tracker_issue_style.regexp=Düzenli ifade +settings.tracker_issue_style.regexp_pattern=Düzenli İfade Kalıbı +settings.tracker_issue_style.regexp_pattern_desc={index} yerine ilk eşleşen grup kullanılacaktır. settings.tracker_url_format_desc=Kullanıcı adı, depo adı ve yayın dizini için {user}, {repo} ve {index} yer tutucularını kullanın. settings.enable_timetracker=Zaman Takibini Etkinleştir settings.allow_only_contributors_to_track_time=Sadece Katkıcılar İçin Zaman Takibine İzin Ver @@ -1748,10 +1823,18 @@ settings.pulls.allow_rebase_merge_commit=Açık birleştirme işlemeleri ile Yen settings.pulls.allow_squash_commits=İşlemeleri Birleştirmek için Ezmeyi Etkinleştir settings.pulls.allow_manual_merge=Dİ'yi elle birleştirilmiş olarak işaretlemeyi etkinleştir settings.pulls.enable_autodetect_manual_merge=Kendiliğinden algılamalı elle birleştirmeyi etkinleştir (Not: Bazı özel durumlarda yanlış kararlar olabilir) +settings.pulls.allow_rebase_update=Değişiklik isteği dalının yeniden yapılandırmayla güncellenmesine izin ver settings.pulls.default_delete_branch_after_merge=Varsayılan olarak birleştirmeden sonra değişiklik isteği dalını sil +settings.packages_desc=Depo Paket Kütüğünü Etkinleştir settings.projects_desc=Depo Projelerini Etkinleştir settings.admin_settings=Yönetici Ayarları settings.admin_enable_health_check=Depo Sağlık Kontrollerini Etkinleştir (git fsck) +settings.admin_code_indexer=Kod Dizinleyici +settings.admin_stats_indexer=Kod İstatistiği Dizinleyici +settings.admin_indexer_commit_sha=Son Dizinlenen SHA +settings.admin_indexer_unindexed=Dizinlenmemiş +settings.reindex_button=Yeniden Dizinleme Kuyruğuna Ekle +settings.reindex_requested=Yeniden Dizinleme İstendi settings.admin_enable_close_issues_via_commit_in_any_branch=Varsayılan olmayan bir dalda yapılan bir işlemeyle konuyu kapat settings.danger_zone=Tehlike Alanı settings.new_owner_has_same_repo=Yeni sahibin aynı isimde başka bir deposu var. Lütfen farklı bir isim seçin. @@ -1840,6 +1923,9 @@ settings.webhook.response=Cevaplar settings.webhook.headers=Başlıklar settings.webhook.payload=İçerik settings.webhook.body=Gövde +settings.webhook.replay.description=Bu web kancasını tekrar çalıştır. +settings.webhook.delivery.success=Teslim kuyruğuna bir olay eklendi. Teslim geçmişinde görünmesi birkaç saniye alabilir. +settings.githooks_desc=Git İstemcileri Git'in kendisi tarafından desteklenmektedir. Özel işlemler ayarlamak için aşağıdaki istemci dosyalarını düzenleyebilirsiniz. settings.githook_edit_desc=İstek aktif değilse örnek içerik sunulacaktır. İçeriği boş bırakmak, isteği devre dışı bırakmayı beraberinde getirecektir. settings.githook_name=İstek İsmi settings.githook_content=İstek İçeriği @@ -1851,6 +1937,7 @@ settings.content_type=POST İçerik Türü settings.secret=Gizli settings.slack_username=Kullanıcı Adı settings.slack_icon_url=Simge Bağlantısı +settings.slack_color=Renk settings.discord_username=Kullanıcı adı settings.discord_icon_url=Simge URL'si settings.event_desc=Tetikleyici Açık: @@ -1896,6 +1983,8 @@ settings.event_pull_request_review=Değişiklik İsteği İncelendi settings.event_pull_request_review_desc=Değişiklik isteği onaylandı, reddedildi veya yorumu incelendi. settings.event_pull_request_sync=Değişiklik İsteği Senkronize Edildi settings.event_pull_request_sync_desc=Değişiklik isteği senkronize edildi. +settings.event_package=Paket +settings.event_package_desc=Bir depoda paket oluşturuldu veya silindi. settings.branch_filter=Dal filtresi settings.branch_filter_desc=Gönderme, dal oluşturma ve dal silme olayları için glob deseni olarak belirtilen dal beyaz listesi. Boşsa veya * ise, tüm dallar için olaylar raporlanır. Sözdizimi için github.com/gobwas/glob belgelerine bakın. Örnekler: master, {master,release*}. settings.active=Etkin @@ -1909,6 +1998,23 @@ settings.hook_type=İstek Türü settings.slack_token=Erişim Anahtarı settings.slack_domain=Alan Adı settings.slack_channel=Kanal +settings.add_web_hook_desc=%s web kancasını deponuza ekleyin. +settings.web_hook_name_gitea=Gitea +settings.web_hook_name_gogs=Gogs +settings.web_hook_name_slack=Slack +settings.web_hook_name_discord=Discord +settings.web_hook_name_dingtalk=DingTalk +settings.web_hook_name_telegram=Telegram +settings.web_hook_name_matrix=Matrix +settings.web_hook_name_msteams=Microsoft Teams +settings.web_hook_name_feishu_or_larksuite=Feishu / Lark Suite +settings.web_hook_name_feishu=Feishu +settings.web_hook_name_larksuite=Lark Suite +settings.web_hook_name_wechatwork=WeCom (Wechat Work) +settings.web_hook_name_packagist=Packagist +settings.packagist_username=Packagist kullanıcı adı +settings.packagist_api_token=API erişim anahtarı +settings.packagist_package_url=Packagist paket URL'si settings.deploy_keys=Dağıtım Anahtarları settings.add_deploy_key=Dağıtım Anahtarı Ekle settings.deploy_key_desc=Dağıtım anahtarları, depoyu salt okunur çekme yetkisine sahip. @@ -2036,6 +2142,12 @@ settings.lfs_pointers.inRepo=Depoda settings.lfs_pointers.exists=Mağazada var settings.lfs_pointers.accessible=Kullanıcı tarafından erişilebilir settings.lfs_pointers.associateAccessible=Erişilebilir %d OID ilişkilendirme +settings.rename_branch_failed_exist=%s dalı zaten mevcut olduğu için dalın adı değiştirilemiyor. +settings.rename_branch_failed_not_exist=%s dalının adı değiştirilemiyor, çünkü böyle bir dal yok. +settings.rename_branch_success=%s dalının adı başarılı bir şekilde %s oldu. +settings.rename_branch_from=önceki dal adı +settings.rename_branch_to=yeni dal adı +settings.rename_branch=Dalı yeniden adlandır diff.browse_source=Kaynağa Gözat diff.parent=ebeveyn @@ -2065,6 +2177,9 @@ diff.file_image_height=Yükseklik diff.file_byte_size=Boyut diff.file_suppressed=Dosya farkı çok büyük olduğundan ihmal edildi diff.file_suppressed_line_too_long=Dosya farkları bir veya daha fazla satır çok uzun olduğundan bastırıldı +diff.too_many_files=Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor +diff.show_more=Daha Fazla Göster +diff.load=Fark Yükle diff.generated=üretilen diff.vendored=sağlanmış diff.comment.placeholder=Yorum Yap @@ -2084,6 +2199,7 @@ diff.protected=Korumalı diff.image.side_by_side=Yan Yana diff.image.swipe=Kaydır diff.image.overlay=Arayüz +diff.has_escaped=Bu satırda gizli evrensel kod karakterler var releases.desc=Proje sürümlerini ve indirmeleri takip edin. release.releases=Sürümler @@ -2154,10 +2270,15 @@ branch.included_desc=Bu dal varsayılan dalın bir parçasıdır branch.included=Dahil branch.create_new_branch=Şu daldan dal oluştur: branch.confirm_create_branch=Dal oluştur +branch.create_branch_operation=Dal oluştur branch.new_branch=Yeni dal oluştur branch.new_branch_from='%s' dalından yeni dal oluştur +branch.renamed=%s dalının adı %s olarak değiştirildi. tag.create_tag=%s etiketi oluştur +tag.create_tag_operation=Etiket oluştur +tag.confirm_create_tag=Etiket oluştur +tag.create_tag_from='%s' kullanarak yeni etiket oluştur tag.create_success='%s' etiketi oluşturuldu. @@ -2166,6 +2287,8 @@ topic.done=Bitti topic.count_prompt=25'ten fazla konu seçemezsiniz topic.format_prompt=Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir. +find_file.go_to_file=Dosyaya git +find_file.no_matching=Eşleşen dosya bulunamadı error.csv.too_large=Bu dosya çok büyük olduğu için işlenemiyor. error.csv.unexpected=%d satırı ve %d sütununda beklenmeyen bir karakter içerdiğinden bu dosya işlenemiyor. @@ -2246,7 +2369,13 @@ teams.leave=Ayrıl teams.leave.detail=%s bırakılsın mı? teams.can_create_org_repo=Depoları oluştur teams.can_create_org_repo_helper=Üyeler organizasyonda yeni depolar oluşturabilirler. Oluşturan yeni depoya yönetici erişimi sağlayacak. +teams.none_access=Erişim Yok +teams.none_access_helper=Üyeler bu birimi görüntüleyemez veya üzerinde başka bir işlem yapamaz. +teams.general_access=Genel Erişim +teams.general_access_helper=Üyelerin izinleri aşağıdaki izin tablosuna göre kararlaştırılacaktır. +teams.read_access=Okuma teams.read_access_helper=Üyeler, takım depolarını görüntüleyebilir ve klonlayabilir. +teams.write_access=Yazma teams.write_access_helper=Üyeler takım depolarını okuyabilir ve itme yapabilir. teams.admin_access=Yönetici Erişimi teams.admin_access_helper=Üyeler takım depolarını çekip itebilir ve katkıcı ekleyebilir. @@ -2297,6 +2426,7 @@ first_page=İlk last_page=Son total=Toplam: %d +dashboard.new_version_hint=Gitea %s şimdi hazır, %s çalıştırıyorsunuz. Ayrıntılar için blog'a bakabilirsiniz. dashboard.statistic=Özet dashboard.operations=Bakım İşlemleri dashboard.system_status=Sistem Durumu @@ -2339,6 +2469,7 @@ dashboard.resync_all_hooks=Tüm depoların alma öncesi, güncelleme ve alma son dashboard.reinit_missing_repos=Kayıtları bulunanlar için tüm eksik Git depolarını yeniden başlat dashboard.sync_external_users=Harici kullanıcı verisini senkronize et dashboard.cleanup_hook_task_table=Hook_task tablosunu temizleme +dashboard.cleanup_packages=Süresi dolmuş paketleri temizleme dashboard.server_uptime=Sunucunun Ayakta Kalma Süresi dashboard.current_goroutine=Güncel Goroutine'ler dashboard.current_memory_usage=Güncel Bellek Kullanımı @@ -2370,6 +2501,8 @@ dashboard.last_gc_pause=Son GC Durması dashboard.gc_times=GC Zamanları dashboard.delete_old_actions=Veritabanından tüm eski eylemleri sil dashboard.delete_old_actions.started=Veritabanından başlatılan tüm eski eylemleri silin. +dashboard.update_checker=Denetleyiciyi güncelle +dashboard.delete_old_system_notices=Veritabanından tüm eski sistem bildirimlerini sil users.user_manage_panel=Kullanıcı Hesap Yönetimi users.new_account=Yeni Kullanıcı Hesabı @@ -2404,10 +2537,26 @@ users.allow_import_local=Yerel Depoları Alabilir users.allow_create_organization=Organizasyon Oluşturabilir users.update_profile=Kullanıcı Hesabını Güncelle users.delete_account=Kullanıcı Hesabını Sil +users.cannot_delete_self=Kendinizi silemezsiniz users.still_own_repo=Bu kullanıcı hala bir veya daha fazla depoya sahip. Önce bu depoları silin veya transfer edin. users.still_has_org=Bu kullanıcı bir organizasyonun üyesidir. Önce kullanıcıyı tüm organizasyonlardan çıkarın. +users.purge=Kullanıcıyı Temizle +users.purge_help=Kullanıcıyı ve sahip olduğu herhangi bir depoyu, organizasyonu ve paketleri zorla sil. Tüm yorumlar da silinecektir. +users.still_own_packages=Kullanıcının bir veya daha fazla paketi var. Önce bu paketleri silin. users.deletion_success=Kullanıcı hesabı silindi. users.reset_2fa=2FD'yi sıfırla +users.list_status_filter.menu_text=Filtre +users.list_status_filter.reset=Sıfırla +users.list_status_filter.is_active=Etkin +users.list_status_filter.not_active=Etkin değil +users.list_status_filter.is_admin=Yönetici +users.list_status_filter.not_admin=Yönetici Değil +users.list_status_filter.is_restricted=Kısıtlanmış +users.list_status_filter.not_restricted=Kısıtlanmamış +users.list_status_filter.is_prohibit_login=Oturum Açmayı Önle +users.list_status_filter.not_prohibit_login=Oturum Açmaya İzin Ver +users.list_status_filter.is_2fa_enabled=2FA Etkin +users.list_status_filter.not_2fa_enabled=2FA Devre Dışı emails.email_manage_panel=Kullanıcı E-posta Yönetimi emails.primary=Birincil @@ -2440,6 +2589,16 @@ repos.forks=Çatallar repos.issues=Konular repos.size=Boyut +packages.package_manage_panel=Paket Yönetimi +packages.total_size=Toplam Boyut: %s +packages.owner=Sahibi +packages.creator=Oluşturan +packages.name=İsim +packages.version=Sürüm +packages.type=Tür +packages.repository=Depo +packages.size=Boyut +packages.published=Yayınlandı defaulthooks=Varsayılan Web İstemcileri defaulthooks.desc=Web İstemcileri, belirli Gitea olayları tetiklendiğinde otomatik olarak HTTP POST isteklerini sunucuya yapar. Burada tanımlanan Web İstemcileri varsayılandır ve tüm yeni depolara kopyalanır. web istemcileri kılavuzunda daha fazla bilgi edinin. @@ -2483,9 +2642,13 @@ auths.filter=Kullanıcı Filtresi auths.admin_filter=Yönetici Filtresi auths.restricted_filter=Kısıtlı Süzgeç auths.restricted_filter_helper=Hiçbir kullanıcıyı kısıtlı olarak ayarlamamak için boş bırakın. Yönetici Süzgeci ile eşleşmeyen tüm kullanıcıları kısıtlanmış olarak ayarlamak için yıldız işareti ('*') kullanın. +auths.verify_group_membership=LDAP'ta grup üyeliğini doğrula (atlamak için filtreyi boş bırakın) auths.group_search_base=Grup Arama Tabanı DN auths.group_attribute_list_users=Kullanıcı Listesi İçeren Grup Özelliği auths.user_attribute_in_group=Grupta Listelenen Kullanıcı Özelliği +auths.map_group_to_team=LDAP gruplarını Organizasyon takımlarına eşle (atlamak için bu alanı boş bırakın) +auths.map_group_to_team_removal=Eğer kullanıcı ilişkili LDAP grubuna ait değilse, kullanıcıları eşleşmiş takımlardan çıkarın +auths.enable_ldap_groups=LDAP gruplarını etkinleştir auths.ms_ad_sa=MS AD Arama Nitelikleri auths.smtp_auth=SMTP Yetkilendirme Türü auths.smtphost=SMTP Sunucusu @@ -2513,6 +2676,14 @@ auths.oauth2_emailURL=E-posta URL'si auths.skip_local_two_fa=Yerel 2FA'yı atla auths.skip_local_two_fa_helper=Bunu seçmediğinizde, 2FA ayarlamış olan yerel kullanıcıların, giriş yapabilmek için 2FA'yı yine de geçmeleri gerekiyor auths.oauth2_tenant=Kiracı +auths.oauth2_scopes=Ek Kapsamlar +auths.oauth2_required_claim_name=Gerekli Talep İsmi +auths.oauth2_required_claim_name_helper=Bu ismi, bu kaynağa oturum açmayı bu isimdeki talebe sahip kullanıcıların girişiyle sınırlamak için ayarlayın +auths.oauth2_required_claim_value=Gerekli Talep Değeri +auths.oauth2_required_claim_value_helper=Bu değeri, bu kaynağa oturum açmayı bu isimdeki ve değerdeki talebe sahip kullanıcıların girişiyle sınırlamak için ayarlayın +auths.oauth2_group_claim_name=Talep ismi bu kaynak için grup isimlerini sağlıyor. (İsteğe bağlı) +auths.oauth2_admin_group=Yönetici kullanıcıları için Grup Talep değeri. (İsteğe bağlı, yukarıda talep ismine gerek duyar) +auths.oauth2_restricted_group=Kısıtlı kullanıcılar için Grup Talep değeri. (İsteğe bağlı, yukarıda talep ismine gerek duyar) auths.enable_auto_register=Otomatik Kaydolmayı Etkinleştir auths.sspi_auto_create_users=Kullanıcıları otomatik olarak oluştur auths.sspi_auto_create_users_helper=SSPI kimlik doğrulama yönteminin ilk kez oturum açan kullanıcılar için otomatik olarak yeni hesaplar oluşturmasına izin ver @@ -2560,6 +2731,7 @@ config.app_ver=Gitea Sürümü config.app_url=Gitea Taban URL'si config.custom_conf=Yapılandırma Dosyası Yolu config.custom_file_root_path=Özel Dosya Kök Yolu +config.domain=Sunucu Alan Adı config.offline_mode=Yerel Kip config.disable_router_log=Yönlendirici Log'larını Devre Dışı Bırak config.run_user=Şu Kullanıcı Olarak Çalıştır @@ -2575,6 +2747,7 @@ config.reverse_auth_user=Tersine Yetkilendirme Kullanıcısı config.ssh_config=SSH Yapılandırması config.ssh_enabled=Aktif config.ssh_start_builtin_server=Yerleşik Sunucuyu Kullan +config.ssh_domain=SSH Sunucusu Alan Adı config.ssh_port=Bağlantı Noktası config.ssh_listen_port=Port'u Dinle config.ssh_root_path=Kök Yol @@ -2625,16 +2798,19 @@ config.queue_length=Kuyruk Uzunluğu config.deliver_timeout=Dağıtım Zaman Aşımı config.skip_tls_verify=TLS Doğrulamasını Geç -config.mailer_config=SMTP Mailer Yapılandırması +config.mailer_config=Mailer Yapılandırması config.mailer_enabled=Aktif -config.mailer_disable_helo=HELO'yu Devre Dışı Bırak +config.mailer_enable_helo=HELO'yu etkinleştir config.mailer_name=İsim -config.mailer_host=Sunucu +config.mailer_protocol=Protokol +config.mailer_smtp_addr=SMTP Adresi +config.mailer_smtp_port=SMTP Portu config.mailer_user=Kullanıcı config.mailer_use_sendmail=Sendmail Kullan config.mailer_sendmail_path=Sendmail Yolu config.mailer_sendmail_args=Sendmail İçin İlave Değişkenler config.mailer_sendmail_timeout=Sendmail Zaman Aşımı +config.mailer_use_dummy=Sahte config.test_email_placeholder=E-posta (ör. test@example.com) config.send_test_mail=Test E-postası Gönder config.test_mail_failed='%s' adresine test e-postası gönderilemedi: %v @@ -2694,12 +2870,16 @@ monitor.next=Sonraki Zaman monitor.previous=Önceki Zaman monitor.execute_times=Çalıştırma monitor.process=Çalışan Süreçler +monitor.stacktrace=Yığın izleme +monitor.goroutines=%d Gorutinleri monitor.desc=Açıklama monitor.start=Başlangıç Zamanı monitor.execute_time=Çalıştırma Zamanı +monitor.last_execution_result=Sonuç monitor.process.cancel=İşlemi iptal et monitor.process.cancel_desc=Bir işlemi iptal etmek veri kaybına neden olabilir monitor.process.cancel_notices=İptal et: %s? +monitor.process.children=Çocuklar monitor.queues=Kuyruklar monitor.queue=Kuyruk: %s monitor.queue.name=İsim @@ -2707,6 +2887,7 @@ monitor.queue.type=Tür monitor.queue.exemplar=Örnek Türü monitor.queue.numberworkers=Çalışan Sayısı monitor.queue.maxnumberworkers=En Fazla Çalışan Sayısı +monitor.queue.numberinqueue=Kuyruktaki Sayı monitor.queue.review=Yapılandırmayı İncele monitor.queue.review_add=Çalışanları İncele/Ekle monitor.queue.configuration=Başlangıç Yapılandırması @@ -2714,6 +2895,7 @@ monitor.queue.nopool.title=Çalışan Havuzu Yok monitor.queue.nopool.desc=Bu kuyruk diğer kuyrukları sarar ve kendisinin bir işçi havuzu yoktur. monitor.queue.wrapped.desc=Sarılmış bir kuyruk, yavaş bir başlangıç kuyruğunu sararak kanaldaki kuyruk isteklerini arabelleğe alır. Bir işçi havuzu yoktur. monitor.queue.persistable-channel.desc=Kesintisiz bir kanal, kendi alt havuzuna sahip bir kanal kuyruğu ve önceki kapanmalardan gelen kalıcı istekler için bir seviye kuyruğu olan iki kuyruğu sarar. Bir işçi havuzu yoktur. +monitor.queue.flush=Çalışanı boşalt monitor.queue.pool.timeout=Zaman aşımı monitor.queue.pool.addworkers.title=Çalışan Ekle monitor.queue.pool.addworkers.submit=Çalışan Ekle @@ -2726,6 +2908,12 @@ monitor.queue.pool.flush.title=Kuyruk Temizleme monitor.queue.pool.flush.desc=Temizleme, kuyruk boş olduğunda veya zaman aşımına uğradığında sona erecek bir işçi ekler. monitor.queue.pool.flush.submit=Temizleme İşçisi Ekle monitor.queue.pool.flush.added=%[1]s için Temizleme İşçisi eklendi +monitor.queue.pool.pause.title=Kuyruğu Duraklat +monitor.queue.pool.pause.desc=Kuyruğun duraklatılması veriyi işlemesini önleyecektir +monitor.queue.pool.pause.submit=Kuyruğu Duraklat +monitor.queue.pool.resume.title=Kuyruğu Sürdür +monitor.queue.pool.resume.desc=Bu kuyruğun çalışmasını sürdür +monitor.queue.pool.resume.submit=Kuyruğu Sürdür monitor.queue.settings.title=Havuz Ayarları monitor.queue.settings.desc=Havuzlar, çalışan kuyruğunun engellenmesine yanıt olarak dinamik bir şekilde büyür. Bu değişiklikler mevcut çalışan gruplarını etkilemeyecektir. @@ -2771,18 +2959,34 @@ notices.delete_success=Sistem bildirimleri silindi. [action] create_repo=depo %s oluşturuldu rename_repo=%[1]s olan depo adını %[3]s buna çevirdi +commit_repo=%[4]s deposuna %[3]s dalını gönderdi create_issue=`%[3]s#%[2]s konusunu açtı` close_issue=`%[3]s#%[2]s konusunu kapattı` reopen_issue=`%[3]s#%[2]s konusunu tekrar açtı` +create_pull_request=`%[3]s#%[2]s değişiklik isteğini oluşturdu` +close_pull_request=`%[3]s#%[2]s değişiklik isteğini kapattı` +reopen_pull_request=`%[3]s#%[2]s değişiklik isteğini yeniden açtı` comment_issue=`%[3]s#%[2]s konusuna yorum yaptı` +comment_pull=`%[3]s#%[2]s değişiklik isteğine yorum yaptı` +merge_pull_request=`%[3]s#%[2]s değişiklik isteğini birleştirdi` transfer_repo=depo %s %s'a aktarıldı +push_tag=%[3]s etiketini %[4]s dalına gönderdi delete_tag=%[2]s etiketi %[3]s deposundan silindi delete_branch=%[3]s deposundan %[2]s dalı silindi compare_branch=Karşılaştır compare_commits=%d işlemeyi karşılaştır compare_commits_general=İşlemeleri karşılaştır +mirror_sync_push=yansıdan %[4]s deposundaki %[3]s dalına işlemeleri eşitledi +mirror_sync_create=%[3]s yeni referansını, %[4]s olarak yansıdan eşledi mirror_sync_delete=%[3]s adresindeki %[2]s referansını eşitledi ve sildi +approve_pull_request=`%[3]s#%[2]s değişiklik isteğini onayladı` +reject_pull_request=`%[3]s#%[2]s için değişiklikler önerdi` +publish_release=`%[3]s deposu için "%[4]s" sürümü yayınlandı` +review_dismissed=`%[3]s#%[2]s için %[4]s yorumunu reddetti` review_dismissed_reason=Sebep: +create_branch=%[4]s deposunda %[3]s dalını oluşturdu +starred_repo=%[2]s deposuna yıldız bıraktı +watched_repo=%[2]s deposunu izlemeye başladı [tool] ago=%s önce @@ -2835,8 +3039,104 @@ error.probable_bad_signature=UYARI! Veritabanında bu kimliğe sahip bir anahtar error.probable_bad_default_signature=UYARI! Varsayılan anahtarın bu kimliği olmasına rağmen, bu işlemeyi doğrulamaz! Bu işleme ŞÜPHELİDİR. [units] +unit=Birim error.no_unit_allowed_repo=Bu deponun hiçbir bölümüne erişme izniniz yok. error.unit_not_allowed=Bu depo bölümüne erişme izniniz yok. [packages] +title=Paketler +desc=Depo paketlerini yönet. +empty=Henüz hiçbir paket yok. +empty.documentation=Paket kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +empty.repo=Bir paket yüklediniz ama burada gösterilmiyor mu? Paket ayarlarına gidin ve bu depoya bağlantı verin. +filter.type=Tür +filter.type.all=Tümü +filter.no_result=Filtreniz herhangi bir sonuç döndürmedi. +filter.container.tagged=Etiketlenmiş +filter.container.untagged=Etiketlenmemiş +published_by=%[1]s, %[3]s tarafından yayınlandı +published_by_in=%[1]s, %[3]s tarafından %[5]s içerisinde yayınlanmış +installation=Kurulum +about=Bu paket hakkında +requirements=Gereksinimler +dependencies=Bağımlılıklar +keywords=Anahtar Kelimeler +details=Ayrıntılar +details.author=Yazar +details.project_site=Proje Web Sitesi +details.license=Lisans +assets=Varlıklar +versions=Sürümler +versions.on=açık +versions.view_all=Tümünü görüntüle +dependency.id=Kimlik +dependency.version=Sürüm +composer.registry=Bu kütüğü ~/.composer/config.json dosyasında ayarlayın: +composer.install=Paketi Composer ile kurmak için, şu komutu çalıştırın: +composer.documentation=Composer kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +composer.dependencies=Bağımlılıklar +composer.dependencies.development=Geliştirme Bağımlılıkları +conan.details.repository=Depo +conan.registry=Bu kütüğü komut satırını kullanarak kurun: +conan.install=Conan ile paket kurmak için aşağıdaki komutu çalıştırın: +conan.documentation=Conan kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +container.details.type=Görüntü Türü +container.details.platform=Platform +container.details.repository_site=Depo Sitesi +container.details.documentation_site=Belge Sitesi +container.pull=Görüntüyü komut satırını kullanarak çekin: +container.documentation=Taşıyıcı kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +container.multi_arch=İşletim Sistemi / Mimari +container.layers=Görüntü Katmanları +container.labels=Etiketler +container.labels.key=Anahtar +container.labels.value=Değer +generic.download=Paketi komut satırında indirin: +generic.documentation=Genel kütük hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +helm.registry=Bu kütüğü komut satırını kullanarak kurun: +helm.install=Paketi kurmak için, aşağıdaki komutu çalıştırın: +helm.documentation=Helm kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +maven.registry=Bu kütüğü projenizdeki pom.xml dosyasında ayarlayın: +maven.install=Paketi kullanmak için aşağıdaki dependencies parçasını pom.xml dosyasınıza ekleyin: +maven.install2=Komut satırında çalıştırın: +maven.download=Bağımlılığı indirmek için, komut satırında çalıştırın: +maven.documentation=Maven kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +nuget.registry=Bu kütüğü komut satırını kullanarak kurun: +nuget.install=Paketi NuGet ile kurmak için, şu komutu çalıştırın: +nuget.documentation=NuGet kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +nuget.dependency.framework=Hedef Çerçeve +npm.registry=Bu kütüğü projenizdeki .npmrc dosyasında ayarlayın: +npm.install=Paketi npm ile kurmak için, şu komutu çalıştırın: +npm.install2=veya paketi package.json dosyasına ekleyin: +npm.documentation=Npm kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +npm.dependencies=Bağımlılıklar +npm.dependencies.development=Geliştirme Bağımlılıkları +npm.dependencies.peer=Eş Bağımlılıkları +npm.dependencies.optional=İsteğe Bağlı Bağımlılıklar +npm.details.tag=Etiket +pub.install=Paketi Dart ile kurmak için, şu komutu çalıştırın: +pub.documentation=Pub kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +pub.details.repository_site=Depo Sitesi +pub.details.documentation_site=Belge Sitesi +pypi.requires=Gereken Python +pypi.install=Paketi pip ile kurmak için, şu komutu çalıştırın: +pypi.documentation=PyPI kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +rubygems.install=Paketi gem ile kurmak için, şu komutu çalıştırın: +rubygems.install2=veya paketi Gemfile dosyasına ekleyin: +rubygems.dependencies.runtime=Çalışma Zamanı Bağımlılıkları +rubygems.dependencies.development=Geliştirme Bağımlılıkları +rubygems.required.ruby=Gereken Ruby sürümü +rubygems.required.rubygems=Gereken RubyGem sürümü +rubygems.documentation=RubyGems kütüğü hakkında daha fazla bilgi için, belgeye bakabilirsiniz. +settings.link=Bu paketi bir depoya bağlayın +settings.link.description=Eğer bir paketi bir depoya bağlarsanız, paket deponun paket listesinde listelenecektir. +settings.link.select=Depo Seç +settings.link.button=Depo Bağlantısını Güncelle +settings.link.success=Depo bağlantısı başarıyla güncellendi. +settings.link.error=Depo bağlantısı güncellenemedi. +settings.delete=Paket Sil +settings.delete.description=Bir paketi silmek kalıcıdır ve geri alınamaz. +settings.delete.notice=%s (%s) paketini silmek üzeresiniz. Bu işlem geri alınamaz, emin misiniz? +settings.delete.success=Paket silindi. +settings.delete.error=Paket silinemedi. diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 49be51a4de7d..bed92be4fd65 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -8,7 +8,6 @@ sign_out=Вийти sign_up=Реєстрація link_account=Прив'язати обліковий запис register=Реєстрація -website=Веб-сайт version=Версія powered_by=Працює на %s page=Сторінка @@ -161,7 +160,6 @@ log_root_path_helper=Файли журналу будуть записані в optional_title=Додаткові налаштування email_title=Налаштування Email -smtp_host=SMTP хост smtp_from=Відправляти Email від імені smtp_from_helper=Електронна пошта для використання в Gіtea. Введіть звичайну електронну адресу або використовуйте формат: "Ім'я" . mailer_user=SMTP Ім'я кристувача @@ -2582,11 +2580,8 @@ config.queue_length=Довжина черги config.deliver_timeout=Затримка доставки config.skip_tls_verify=Пропустити перевірку TLS -config.mailer_config=Конфігурація SMTP-сервера config.mailer_enabled=Увімкнено -config.mailer_disable_helo=Вимкнути HELO config.mailer_name=Ім'я -config.mailer_host=Хост config.mailer_user=Користувач config.mailer_use_sendmail=Використовувати Sendmail config.mailer_sendmail_path=Шлях до Sendmail diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index fb7c0e505586..fd0a6a8b4e11 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -9,7 +9,6 @@ sign_out=退出 sign_up=注册 link_account=链接账户 register=注册 -website=官方网站 version=当前版本 powered_by=Powered by %s page=页面 @@ -20,7 +19,7 @@ active_stopwatch=活动时间跟踪器 create_new=创建… user_profile_and_more=个人信息和配置 signed_in_as=已登录用户 -enable_javascript=使用 JavaScript能使本网站更好的工作。 +enable_javascript=使用 JavaScript 能使本网站更好的工作。 toc=目录 licenses=许可证 return_to_gitea=返回 Gitea @@ -179,9 +178,10 @@ log_root_path_helper=日志文件将写入此目录。 optional_title=可选设置 email_title=电子邮箱设置 -smtp_host=SMTP 主机 +smtp_addr=SMTP 主机地址 +smtp_port=SMTP 端口 smtp_from=电子邮件发件人 -smtp_from_helper=电子邮件地址 Gitea 将使用。输入一个普通的电子邮件地址或使用 "名称" 格式。 +smtp_from_helper=请输入一个用于 Gitea 的电子邮件地址,或者使用完整格式:"名称" mailer_user=SMTP 用户名 mailer_password=SMTP 密码 register_confirm=需要发电子邮件确认注册 @@ -799,6 +799,7 @@ email_notifications.enable=启用邮件通知 email_notifications.onmention=只在被提到时邮件通知 email_notifications.disable=停用邮件通知 email_notifications.submit=邮件通知设置 +email_notifications.andyourown=和您自己的通知 visibility=用户可见性 visibility.public=公开 @@ -932,6 +933,7 @@ form.name_pattern_not_allowed=仓库名称中不允许使用模式 "%s"。 need_auth=授权 migrate_options=迁移选项 migrate_service=迁移服务 +migrate_options_mirror_helper=该仓库将是一个镜像 migrate_options_lfs=迁移 LFS 文件 migrate_options_lfs_endpoint.label=LFS 网址 migrate_options_lfs_endpoint.description=迁移将尝试使用你的 Git remote 来 确定 LFS 服务器。如果仓库 LFS 数据存储在其他位置,你还可以指定自定义网址。 @@ -1033,13 +1035,13 @@ file_view_rendered=渲染模式 file_view_raw=查看原始文件 file_permalink=永久链接 file_too_large=文件过大,无法显示。 -bidi_bad_header=`此文件包含意外的双向 Unicode 字符!` -bidi_bad_description=`此文件包含意外的双向 Unicode 字符,其处理方式可能与下面显示的不同。 如果您是有意且合法地使用它们,可以放心地忽略此警告。 使用 Escape 按钮显示隐藏的字符。` -bidi_bad_description_escaped=`此文件包含意外的双向 Unicode 字符。隐藏的 Unicode 字符在下面被转义。使用 Unescape 按钮来显示它们是如何渲染的。` -unicode_header=`此文件包含隐藏的 Unicode 字符!` -unicode_description=`该文件包含隐藏的 Unicode 字符,这些字符的处理方式可能与下面显示的不同。 如果您是有意且合法地使用它们,可以放心地忽略此警告。 使用 Escape 按钮显示隐藏的字符。` -unicode_description_escaped=`此文件包含隐藏的 Unicode 字符。隐藏的 unicode 字符在下面被转义。请使用 Unescape 按钮来显示它们是如何渲染的。` -line_unicode=`这一行有隐藏的 Unicode 字符` +invisible_runes_header=`此文件包含不可见的 Unicode 字符!` +invisible_runes_description=`这个文件包含不可见的 Unicode 字符,其处理方式可能不同于下面显示的字符。 如果您是有意且正当地使用它们,您可以安全地忽略这个警告。使用 Escape 按钮来显示隐藏的字符。 +ambiguous_runes_header=`此行包含模棱两可的 Unicode 字符!` +ambiguous_runes_description=`此文件包含模棱两可的 Unicode 字符,这些字符可能会与您当前语言环境的其他字符混淆。 如果您是有意且正当地使用它们,您可以安全地忽略这个警告。使用 Escape 按钮来高亮这些字符。` +invisible_runes_line=`此行含有不可见的 unicode 字符` +ambiguous_runes_line=`此行有模棱两可的 unicode 字符` +ambiguous_character=`%[1]c [U+%04[1]X] 容易和 %[2]c [U+%04[2]X] 混淆` escape_control_characters=Escape unescape_control_characters=Unescape @@ -1060,6 +1062,7 @@ normal_view=普通视图 line=行 lines=行 +editor.add_file=添加文件 editor.new_file=新建文件 editor.upload_file=上传文件 editor.edit_file=编辑文件 @@ -1265,6 +1268,8 @@ issues.filter_milestone=里程碑筛选 issues.filter_milestone_no_select=所有里程碑 issues.filter_assignee=指派人筛选 issues.filter_assginee_no_select=所有指派成员 +issues.filter_poster=作者 +issues.filter_poster_no_select=所有作者 issues.filter_type=类型筛选 issues.filter_type.all_issues=所有工单 issues.filter_type.assigned_to_you=指派给您的 @@ -1419,6 +1424,7 @@ issues.due_date_form_remove=删除 issues.due_date_not_writer=你需要仓库写入权限来修改工单到期时间。 issues.due_date_not_set=未设置到期时间。 issues.due_date_added=于 %[2]s 设置到期时间为 %[1]s +issues.due_date_modified=将到期日从 %[2]s 修改为 %[1]s %[3]s issues.due_date_remove=于 %[2]s 删除了到期时间 %[1]s issues.due_date_overdue=过期 issues.due_date_invalid=到期日期无效或超出范围。请使用 'yyyy-mm-dd' 格式。 @@ -1530,6 +1536,8 @@ pulls.remove_prefix=删除 %s 前缀 pulls.data_broken=此合并请求因为派生仓库信息缺失而中断。 pulls.files_conflicted=此合并请求有变更与目标分支冲突。 pulls.is_checking=正在进行合并冲突检测,请稍后再试。 +pulls.is_ancestor=此分支已经包含在目标分支中,没有什么可以合并。 +pulls.is_empty=此分支上的更改已经在目标分支上。这将是一个空提交。 pulls.required_status_check_failed=一些必要的检查没有成功 pulls.required_status_check_missing=缺少一些必要的检查。 pulls.required_status_check_administrator=作为管理员,您仍可合并此合并请求 @@ -2204,7 +2212,7 @@ release.stable=稳定 release.compare=比较 release.edit=编辑 release.ahead.commits=%d 次提交 -release.ahead.target=到 %s 自发布后 +release.ahead.target=在此版本发布后被加入到 %s release.source_code=源代码 release.new_subheader=版本发布组织项目的版本。 release.edit_subheader=版本发布组织项目的版本。 @@ -2315,7 +2323,7 @@ form.create_org_not_allowed=此账号禁止创建组织 settings=组织设置 settings.options=组织 settings.full_name=组织全名 -settings.website=官方网站 +settings.website=网站 settings.location=所在地区 settings.permission=权限 settings.repoadminchangeteam=仓库管理员可以添加或移除团队的访问权限 @@ -2453,9 +2461,9 @@ dashboard.archive_cleanup=删除旧的仓库存档 dashboard.deleted_branches_cleanup=清理已删除的分支 dashboard.update_migration_poster_id=更新迁移的发表者ID dashboard.git_gc_repos=对仓库进行垃圾回收 -dashboard.resync_all_sshkeys=使用 Gitea SSH 密钥更新'.ssh/authorized_keys' 文件。 +dashboard.resync_all_sshkeys=使用 Gitea 的 SSH 密钥更新 '.ssh/authorized_keys' 文件。 dashboard.resync_all_sshkeys.desc=(内置的 SSH 服务器不需要。) -dashboard.resync_all_sshprincipals=使用 Gitea SSH 规则更新 '.ssh/authorized_principals' 文件。 +dashboard.resync_all_sshprincipals=使用 Gitea 的 SSH 规则更新 '.ssh/authorized_principals' 文件。 dashboard.resync_all_sshprincipals.desc=(内置的 SSH 服务器不需要。) dashboard.resync_all_hooks=重新同步所有仓库的 pre-receive、update 和 post-receive 钩子 dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在的记录 @@ -2532,6 +2540,8 @@ users.delete_account=删除帐户 users.cannot_delete_self=你不能删除自己 users.still_own_repo=此用户仍然拥有一个或多个仓库。必须首先删除或转让这些仓库。 users.still_has_org=此用户是组织的成员。必须先从组织中删除用户。 +users.purge=清理用户 +users.purge_help=强制删除用户和用户拥有的任何仓库、组织和软件包。所有评论也将被删除。 users.still_own_packages=此用户仍然拥有一个或多个软件包。请先删除这些软件包。 users.deletion_success=用户帐户已被删除。 users.reset_2fa=重置两步验证 @@ -2788,16 +2798,19 @@ config.queue_length=队列长度 config.deliver_timeout=推送超时 config.skip_tls_verify=跳过 TLS 验证 -config.mailer_config=邮件配置 +config.mailer_config=Mailer 配置 config.mailer_enabled=启用服务 -config.mailer_disable_helo=禁用 HELO 操作 +config.mailer_enable_helo=启用HELO config.mailer_name=任务名称 -config.mailer_host=邮件主机地址 +config.mailer_protocol=协议 +config.mailer_smtp_addr=SMTP 地址 +config.mailer_smtp_port=SMTP 端口 config.mailer_user=发送者帐号 config.mailer_use_sendmail=使用 Sendmail config.mailer_sendmail_path=Sendmail 路径 config.mailer_sendmail_args=Sendmail 的额外参数 config.mailer_sendmail_timeout=Sendmail 超时 +config.mailer_use_dummy=Dummy config.test_email_placeholder=电子邮址 (例如,test@example.com) config.send_test_mail=发送测试邮件 config.test_mail_failed=发送测试邮件至 '%s' 时失败:%v @@ -2882,6 +2895,7 @@ monitor.queue.nopool.title=没有工作者池 monitor.queue.nopool.desc=此队列包装其它队列,本身没有工作者池。 monitor.queue.wrapped.desc=一个包装队列包装一个启动缓慢队列,缓存队列请求到 channel 中。它本身没有一个工作者池。 monitor.queue.persistable-channel.desc=一个 persistable-channel 队列包装2个队列,一个 channel 队列拥有自己的工作者池,一个 level 队列用于永久存储。它没有自己的工作者池。 +monitor.queue.flush=Flush worker monitor.queue.pool.timeout=超时 monitor.queue.pool.addworkers.title=新增工作者 monitor.queue.pool.addworkers.submit=新增工作者 @@ -3034,6 +3048,7 @@ title=软件包 desc=管理仓库软件包。 empty=还没有软件包。 empty.documentation=关于软件包注册中心的更多信息,请参阅 文档 。 +empty.repo=您上传了一个包,但没有显示在这里吗?转到 包设置 并将其链接到这个仓库中。 filter.type=类型 filter.type.all=所有 filter.no_result=您的过滤器没有产生任何结果。 @@ -3099,6 +3114,10 @@ npm.dependencies.development=开发依赖 npm.dependencies.peer=Peer 依赖 npm.dependencies.optional=可选依赖 npm.details.tag=标签 +pub.install=要使用 Dart 安装软件包,请运行以下命令: +pub.documentation=关于 Pub 注册中心的信息,请参阅 文档。 +pub.details.repository_site=仓库站点 +pub.details.documentation_site=文档站点 pypi.requires=需要 Python pypi.install=要使用 pip 安装软件包,请运行以下命令: pypi.documentation=关于 PyPI 注册中心的信息,请参阅 文档。 diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index c6ea7ce67351..18168c1db904 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -6,7 +6,6 @@ sign_in=登入 sign_out=登出 link_account=連結帳戶 register=註冊 -website=網站 version=版本 page=頁面 template=樣板 @@ -64,7 +63,6 @@ repo_path=儲存庫的根目錄 log_root_path=日誌路徑 optional_title=可選設定 -smtp_host=SMTP 主機 federated_avatar_lookup_popup=開啟聯合頭像查詢並使用基於開放源碼的 libravatar 服務 enable_captcha_popup=要求在用戶註冊時輸入驗證碼 admin_password=管理員密碼 @@ -760,9 +758,7 @@ config.deliver_timeout=推送超時 config.skip_tls_verify=略過 TLS 驗證 config.mailer_enabled=啟用服務 -config.mailer_disable_helo=禁用 HELO 操作 config.mailer_name=發送者名稱 -config.mailer_host=郵件主機地址 config.mailer_user=發送者帳號 config.oauth_config=社交帳號設定 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 8d89c51a1d20..47f8ffcdf68e 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -9,7 +9,6 @@ sign_out=登出 sign_up=註冊 link_account=連結帳戶 register=註冊 -website=網站 version=版本 powered_by=技術提供: %s page=頁面 @@ -179,7 +178,6 @@ log_root_path_helper=日誌檔將寫入此目錄。 optional_title=可選設定 email_title=電子郵件設定 -smtp_host=SMTP 主機 smtp_from=電子郵件寄件者 smtp_from_helper=Gitea 將會使用的電子信箱,直接輸入電子信箱或使用「"名稱" 」的格式。 mailer_user=SMTP 帳號 @@ -1033,13 +1031,6 @@ file_view_rendered=檢視渲染圖 file_view_raw=查看原始文件 file_permalink=永久連結 file_too_large=檔案太大,無法顯示。 -bidi_bad_header=`此檔案含有未預期的 Bidirectional Unicode 字元!` -bidi_bad_description=`此檔案含有未預期的 Bidirectional Unicode 字元,這些字元的處理方式可能和下面呈現的不同。若您是有意且合理的使用,您可以放心地忽略此警告。使用 Escape 按鈕顯示隱藏的字元。` -bidi_bad_description_escaped=`此檔案含有未預期的 Bidirectional Unicode 字元。隱藏的 Unicode 字元已在下面被跳脫 (Escaped)。使用 Unescape 按鈕以顯示它們呈現的樣子。` -unicode_header=`此檔案含有隱藏的 Unicode 字元!` -unicode_description=`此檔案含有隱藏的 Unicode 字元,這些字元的處理方式可能和下面呈現的不同。若您是有意且合理的使用,您可以放心地忽略此警告。使用 Escape 按鈕顯示隱藏的字元。` -unicode_description_escaped=`此檔案含有隱藏的 Unicode 字元。隱藏的 Unicode 字元已在下面被跳脫 (Escaped)。使用 Unescape 按鈕以顯示它們呈現的樣子。` -line_unicode=`這一行有隱藏的 Unicode 字元` escape_control_characters=Escape unescape_control_characters=Unescape @@ -2788,11 +2779,8 @@ config.queue_length=佇列長度 config.deliver_timeout=傳送逾時 config.skip_tls_verify=略過 TLS 驗證 -config.mailer_config=SMTP 組態 config.mailer_enabled=啟用服務 -config.mailer_disable_helo=停用 HELO 操作 config.mailer_name=發送者名稱 -config.mailer_host=郵件主機地址 config.mailer_user=發送者帳號 config.mailer_use_sendmail=使用 Sendmail config.mailer_sendmail_path=Sendmail 路徑 diff --git a/package-lock.json b/package-lock.json index 8ebff450e2a5..aabbd84fd9bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,8 @@ "license": "MIT", "dependencies": { "@claviska/jquery-minicolors": "2.3.6", - "@primer/octicons": "17.3.0", + "@mcaptcha/vanilla-glue": "0.1.0-alpha-2", + "@primer/octicons": "17.4.0", "add-asset-webpack-plugin": "2.0.1", "css-loader": "6.7.1", "dropzone": "6.0.0-beta.2", @@ -28,7 +29,7 @@ "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.13.0", + "swagger-ui-dist": "4.13.2", "tippy.js": "6.3.7", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", @@ -37,22 +38,22 @@ "vue-calendar-heatmap": "0.8.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", - "webpack": "5.73.0", + "webpack": "5.74.0", "webpack-cli": "4.10.0", - "workbox-routing": "6.5.3", - "workbox-strategies": "6.5.3", + "workbox-routing": "6.5.4", + "workbox-strategies": "6.5.4", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { "@happy-dom/jest-environment": "6.0.4", - "@stoplight/spectral-cli": "6.4.1", - "eslint": "8.20.0", + "@stoplight/spectral-cli": "6.5.0", + "eslint": "8.21.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-jquery": "1.5.1", - "eslint-plugin-sonarjs": "0.13.0", + "eslint-plugin-sonarjs": "0.14.0", "eslint-plugin-unicorn": "43.0.2", - "eslint-plugin-vue": "9.2.0", + "eslint-plugin-vue": "9.3.0", "jest": "28.1.3", "jest-extended": "3.0.1", "markdownlint-cli": "0.32.1", @@ -60,7 +61,7 @@ "stylelint": "14.9.1", "stylelint-config-standard": "26.0.0", "svgo": "2.8.0", - "updates": "13.1.2" + "updates": "13.1.4" }, "engines": { "node": ">= 14.0.0" @@ -107,21 +108,21 @@ } }, "node_modules/@babel/core": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", - "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", + "@babel/generator": "^7.18.10", "@babel/helper-compilation-targets": "^7.18.9", "@babel/helper-module-transforms": "^7.18.9", "@babel/helpers": "^7.18.9", - "@babel/parser": "^7.18.9", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -146,12 +147,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", - "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.10.tgz", + "integrity": "sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA==", "dev": true, "dependencies": { - "@babel/types": "^7.18.9", + "@babel/types": "^7.18.10", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -298,6 +299,15 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", @@ -416,9 +426,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.10.tgz", + "integrity": "sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -601,33 +611,33 @@ } }, "node_modules/@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", - "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.10.tgz", + "integrity": "sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", + "@babel/generator": "^7.18.10", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.18.9", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.9", - "@babel/types": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -645,11 +655,12 @@ } }, "node_modules/@babel/types": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", - "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "dev": true, "dependencies": { + "@babel/helper-string-parser": "^7.18.10", "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" }, @@ -701,6 +712,21 @@ "node": ">=10.0.0" } }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz", + "integrity": "sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -758,9 +784,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -771,6 +797,16 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -867,15 +903,6 @@ "node": ">=8" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -1636,6 +1663,55 @@ "jsep": "^0.4.0||^1.0.0" } }, + "node_modules/@mcaptcha/core-glue": { + "version": "0.1.0-alpha-3", + "resolved": "https://registry.npmjs.org/@mcaptcha/core-glue/-/core-glue-0.1.0-alpha-3.tgz", + "integrity": "sha512-avphBVgf3PPDWuUoDsB2qiXAss2pc00lUILswJaMQofr8FQyflzkhha8H2Z+qGFiX0Iib/yyP2TOtBDbHqE9Tg==", + "funding": [ + { + "type": "individual", + "url": "http://mcaptcha.org/donate" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mcaptcha" + }, + { + "type": "individual", + "url": "http://batsense.net/donate" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/realaravinth" + } + ] + }, + "node_modules/@mcaptcha/vanilla-glue": { + "version": "0.1.0-alpha-2", + "resolved": "https://registry.npmjs.org/@mcaptcha/vanilla-glue/-/vanilla-glue-0.1.0-alpha-2.tgz", + "integrity": "sha512-cQOg3EIhdjk1xoZtjD9SVPwQAnd49FCvHKchwFZZuhdNTeFs7SUHynOCekuGow2Ip0RJZuMZGcRxvWMgd0ogng==", + "funding": [ + { + "type": "individual", + "url": "http://mcaptcha.org/donate" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mcaptcha" + }, + { + "type": "individual", + "url": "http://batsense.net/donate" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/realaravinth" + } + ], + "dependencies": { + "@mcaptcha/core-glue": "^0.1.0-alpha-3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1678,9 +1754,9 @@ } }, "node_modules/@primer/octicons": { - "version": "17.3.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.3.0.tgz", - "integrity": "sha512-4zPwwloYWdR6RznMafV7Fsw3n2CeDPp/+qEIQbaX/tBbPY1KmU0OAXmhRfhD5AzgB5kdV1aQ7KnQr1GeQXl9Dg==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.4.0.tgz", + "integrity": "sha512-fRD9A/JszKOe5mDIU+g1b8jvcPj/qzusxdxnrIrg8Db0mLHsbGc4xNMUtHbRmgFOKaF6/QBR+WnWGQxv4yTcBg==", "dependencies": { "object-assign": "^4.1.1" } @@ -1730,9 +1806,9 @@ "dev": true }, "node_modules/@sinclair/typebox": { - "version": "0.24.20", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.20.tgz", - "integrity": "sha512-kVaO5aEFZb33nPMTZBxiPEkY+slxiPtqC7QX8f9B3eGOMBvEfuMfxp9DSTTCsRJPumPKjrge4yagyssO4q6qzQ==", + "version": "0.24.26", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.26.tgz", + "integrity": "sha512-1ZVIyyS1NXDRVT8GjWD5jULjhDyM3IsIHef2VGUMdnWOlX2tkPjyEX/7K0TGSH2S8EaPhp1ylFdjSjUGQ+gecg==", "dev": true }, "node_modules/@sinonjs/commons": { @@ -1857,9 +1933,9 @@ } }, "node_modules/@stoplight/spectral-cli": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.4.1.tgz", - "integrity": "sha512-l5nWXy/6YEyk51VVrOurhupVScIqfK0ra8yIRSli+gnW5Kf5Nfw5PLci5GceQGaM5WE+wmqZ/iY95yOVFwHc+A==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.5.0.tgz", + "integrity": "sha512-BmTnQkkhG6E301ADUX7dhQtIIUT/WVRszRHy+90M5Bxk+4kod/6Gi8w7sWuQ5myDls3mLEMjYWUOKaUALuPvug==", "dev": true, "dependencies": { "@rollup/plugin-commonjs": "^20.0.0", @@ -1922,9 +1998,9 @@ } }, "node_modules/@stoplight/spectral-core": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.12.3.tgz", - "integrity": "sha512-+PhVzTD8q6kUZw4BcbM+ibVaH5/ELryKt5tlLitA8SJIaJ+5/9ZKaGN0AV3ExZQZGYvXwucPOQuJKYZYKA6mWg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.13.0.tgz", + "integrity": "sha512-h++UIhdYK6bCZYHCK8byeyOq2tgAUbXdwdR3+Wy1O3PrJERdA9fyL0I3KQ595HylZRo7z1PUoSeyY6FMypWTBQ==", "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.1", @@ -1935,11 +2011,13 @@ "@stoplight/spectral-ref-resolver": "^1.0.0", "@stoplight/spectral-runtime": "^1.0.0", "@stoplight/types": "~13.2.0", + "@types/es-aggregate-error": "^1.0.2", "@types/json-schema": "^7.0.11", "ajv": "^8.6.0", "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.0", "blueimp-md5": "2.18.0", + "es-aggregate-error": "^1.0.7", "jsonpath-plus": "6.0.1", "lodash": "~4.17.21", "lodash.topath": "^4.5.2", @@ -1998,9 +2076,9 @@ } }, "node_modules/@stoplight/spectral-functions": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.6.1.tgz", - "integrity": "sha512-f4cFtbI35bQtY0t4fYhKtS+/nMU3UsAeFlqm4tARGGG5WjOv4ieCFNFbgodKNiO3F4O+syMEjVQuXlBNPuY7jw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.0.tgz", + "integrity": "sha512-ya3ovvH17QqHeL1o41rEXISJIUegb763Y8yWI01VaLj4zehKOjLzVNKIp1PsUNkG88M5fwB8Lrvjzcd3M8O3iw==", "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.1", @@ -2068,12 +2146,12 @@ } }, "node_modules/@stoplight/spectral-ruleset-bundler": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.3.0.tgz", - "integrity": "sha512-6Tif7GQL18F0LN1+FhEmhFWgE/TiWudb/pFl4DC7oS1QRoutB7QJPqIfVFSmteToPidxlrIbC6VAXSyEhlpDVQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.3.1.tgz", + "integrity": "sha512-TWjLFYBor1s/0v3xXwdVzzyUVu7ez2vYVNN4RMbJG7HIZgYW8MMVx4AVg5Eo1ZgLTkj/aeaoAOjIP7t+u6IBUg==", "dev": true, "dependencies": { - "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-commonjs": "~22.0.0", "@stoplight/path": "1.3.2", "@stoplight/spectral-core": ">=1", "@stoplight/spectral-formats": ">=1", @@ -2086,7 +2164,7 @@ "@stoplight/types": "^12.3.0", "@types/node": "*", "pony-cause": "1.1.1", - "rollup": "~2.67.0", + "rollup": "~2.75.5", "tslib": "^2.3.1", "validate-npm-package-name": "3.0.0" }, @@ -2095,9 +2173,9 @@ } }, "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/@rollup/plugin-commonjs": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz", - "integrity": "sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA==", + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.1.tgz", + "integrity": "sha512-dGfEZvdjDHObBiP5IvwTKMVeq/tBZGMBHZFMdIV1ClMM/YoWS34xrHFGfag9SN2ZtMgNZRFruqvxZQEa70O6nQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^3.1.0", @@ -2109,16 +2187,16 @@ "resolve": "^1.17.0" }, "engines": { - "node": ">= 8.0.0" + "node": ">= 12.0.0" }, "peerDependencies": { - "rollup": "^2.38.3" + "rollup": "^2.68.0" } }, "node_modules/@stoplight/spectral-ruleset-bundler/node_modules/rollup": { - "version": "2.67.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.3.tgz", - "integrity": "sha512-G/x1vUwbGtP6O5ZM8/sWr8+p7YfZhI18pPqMRtMYMWSbHjKZ/ajHGiM+GWNTlWyOR0EHIdT8LHU+Z4ciIZ1oBw==", + "version": "2.75.7", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz", + "integrity": "sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -2165,9 +2243,9 @@ } }, "node_modules/@stoplight/spectral-rulesets": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.11.0.tgz", - "integrity": "sha512-0zFbxIuoWmGrkl2txOuaEDF8o6aoKDpMAYOG2oDfmmX9FhXX3c3ivIy80hyb2tMKkIYuqqx/zwIiOuww5S8iUA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.11.1.tgz", + "integrity": "sha512-0MDr5MW000FIZ3C47YY2Cg4NzU6wJFvvpSl1QRijRzdAVqQ1DgD3FgRDKHTA6OO7BmgWdCQYKSI8KwOH1Ju3kw==", "dev": true, "dependencies": { "@asyncapi/specs": "^2.14.0", @@ -2335,6 +2413,15 @@ "@types/node": "*" } }, + "node_modules/@types/es-aggregate-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.2.tgz", + "integrity": "sha512-erqUpFXksaeR2kejKnhnjZjbFxUpGZx4Z7ydNL9ie8tEhXPiZTsLeUDJ6aR1F8j5wWUAtOAQWUqkc7givBJbBA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz", @@ -2423,9 +2510,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", - "integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==" + "version": "18.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz", + "integrity": "sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -2440,9 +2527,9 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", - "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz", + "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==", "dev": true }, "node_modules/@types/qs": { @@ -2726,9 +2813,9 @@ } }, "node_modules/acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", "bin": { "acorn": "bin/acorn" }, @@ -3177,9 +3264,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "funding": [ { "type": "opencollective", @@ -3191,10 +3278,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" + "update-browserslist-db": "^1.0.5" }, "bin": { "browserslist": "cli.js" @@ -3293,9 +3380,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001367", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", - "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==", + "version": "1.0.30001373", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz", + "integrity": "sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==", "funding": [ { "type": "opencollective", @@ -3454,9 +3541,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.6", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.6.tgz", - "integrity": "sha512-zNihMSMoDxK9Gqv9oEyDT8oM51rcRrQ+IEo2zyS48gJByBq5Fj8XuNEguMra+MuIOuh6lkpnLUJeL70DoTt6yw==" + "version": "5.65.7", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.7.tgz", + "integrity": "sha512-zb67cXzgugIQmb6tfD4G11ILjYoMfTjwcjn+cWsa4GewlI2adhR/h3kolkoCQTm1msD/1BuqVTKuO09ELsS++A==" }, "node_modules/codemirror-spell-checker": { "version": "1.1.2", @@ -3512,11 +3599,12 @@ } }, "node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", + "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", + "dev": true, "engines": { - "node": ">= 10" + "node": "^12.20.0 || >=14" } }, "node_modules/commondir": { @@ -3909,6 +3997,14 @@ "node": ">=12" } }, + "node_modules/d3-dsv/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/d3-ease": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", @@ -4652,6 +4748,15 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -4725,9 +4830,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.195", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.195.tgz", - "integrity": "sha512-vefjEh0sk871xNmR5whJf9TEngX+KTKS3hOHpjoMpauKkwlGwtMz1H8IaIjAT/GNnX0TbGwAdmVoXCAzXf+PPg==" + "version": "1.4.210", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.210.tgz", + "integrity": "sha512-kSiX4tuyZijV7Cz0MWVmGT8K2siqaOA4Z66K5dCttPPRh0HicOcOAEj1KlC8O8J1aOS/1M8rGofOzksLKaHWcQ==" }, "node_modules/emittery": { "version": "0.10.2", @@ -4767,10 +4872,13 @@ } }, "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true, + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -4850,6 +4958,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-aggregate-error": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.8.tgz", + "integrity": "sha512-AKUb5MKLWMozPlFRHOKqWD7yta5uaEhH21qwtnf6FlKjNjTJOoqFi0/G14+FfSkIQhhu6X68Af4xgRC6y8qG4A==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "function-bind": "^1.1.1", + "functions-have-names": "^1.2.3", + "get-intrinsic": "^1.1.1", + "globalthis": "^1.0.2", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -4882,9 +5011,9 @@ } }, "node_modules/esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.53.tgz", + "integrity": "sha512-ohO33pUBQ64q6mmheX1mZ8mIXj8ivQY/L4oVuAshr+aJI+zLl+amrp3EodrUNDNYVrKJXGPfIHFGhO8slGRjuw==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -4893,32 +5022,33 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" + "@esbuild/linux-loong64": "0.14.53", + "esbuild-android-64": "0.14.53", + "esbuild-android-arm64": "0.14.53", + "esbuild-darwin-64": "0.14.53", + "esbuild-darwin-arm64": "0.14.53", + "esbuild-freebsd-64": "0.14.53", + "esbuild-freebsd-arm64": "0.14.53", + "esbuild-linux-32": "0.14.53", + "esbuild-linux-64": "0.14.53", + "esbuild-linux-arm": "0.14.53", + "esbuild-linux-arm64": "0.14.53", + "esbuild-linux-mips64le": "0.14.53", + "esbuild-linux-ppc64le": "0.14.53", + "esbuild-linux-riscv64": "0.14.53", + "esbuild-linux-s390x": "0.14.53", + "esbuild-netbsd-64": "0.14.53", + "esbuild-openbsd-64": "0.14.53", + "esbuild-sunos-64": "0.14.53", + "esbuild-windows-32": "0.14.53", + "esbuild-windows-64": "0.14.53", + "esbuild-windows-arm64": "0.14.53" } }, "node_modules/esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz", + "integrity": "sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==", "cpu": [ "x64" ], @@ -4931,9 +5061,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz", + "integrity": "sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==", "cpu": [ "arm64" ], @@ -4946,9 +5076,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz", + "integrity": "sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==", "cpu": [ "x64" ], @@ -4961,9 +5091,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz", + "integrity": "sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==", "cpu": [ "arm64" ], @@ -4976,9 +5106,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz", + "integrity": "sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==", "cpu": [ "x64" ], @@ -4991,9 +5121,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz", + "integrity": "sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==", "cpu": [ "arm64" ], @@ -5006,9 +5136,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz", + "integrity": "sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==", "cpu": [ "ia32" ], @@ -5021,9 +5151,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz", + "integrity": "sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==", "cpu": [ "x64" ], @@ -5036,9 +5166,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz", + "integrity": "sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==", "cpu": [ "arm" ], @@ -5051,9 +5181,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz", + "integrity": "sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==", "cpu": [ "arm64" ], @@ -5066,9 +5196,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz", + "integrity": "sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==", "cpu": [ "mips64el" ], @@ -5081,9 +5211,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz", + "integrity": "sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==", "cpu": [ "ppc64" ], @@ -5096,9 +5226,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz", + "integrity": "sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==", "cpu": [ "riscv64" ], @@ -5111,9 +5241,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz", + "integrity": "sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==", "cpu": [ "s390x" ], @@ -5145,9 +5275,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz", + "integrity": "sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==", "cpu": [ "x64" ], @@ -5160,9 +5290,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz", + "integrity": "sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==", "cpu": [ "x64" ], @@ -5175,9 +5305,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz", + "integrity": "sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==", "cpu": [ "x64" ], @@ -5190,9 +5320,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz", + "integrity": "sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==", "cpu": [ "ia32" ], @@ -5205,9 +5335,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz", + "integrity": "sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==", "cpu": [ "x64" ], @@ -5220,9 +5350,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz", + "integrity": "sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==", "cpu": [ "arm64" ], @@ -5348,13 +5478,14 @@ } }, "node_modules/eslint": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz", - "integrity": "sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", + "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", "dev": true, "dependencies": { "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -5364,14 +5495,17 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.3.3", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -5440,6 +5574,73 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-module-utils/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-module-utils/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-plugin-import": { "version": "2.26.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", @@ -5504,9 +5705,9 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.13.0.tgz", - "integrity": "sha512-t3m7ta0EspzDxSOZh3cEOJIJVZgN/TlJYaBGnQlK6W/PZNbWep8q4RQskkJkA7/zwNpX0BaoEOSUUrqaADVoqA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.14.0.tgz", + "integrity": "sha512-0X0q3fB8ghppms19cR2oIK2ajoFp7DEy3AVGDqO7WX02r1aWOzkrHa+veatGZw+R7amgBvfcF0qHCG66p9Zoag==", "dev": true, "engines": { "node": ">=12" @@ -5547,9 +5748,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.2.0.tgz", - "integrity": "sha512-W2hc+NUXoce8sZtWgZ45miQTy6jNyuSdub5aZ1IBune4JDeAyzucYX0TzkrQ1jMO52sNUDYlCIHDoaNePe0p5g==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.3.0.tgz", + "integrity": "sha512-iscKKkBZgm6fGZwFt6poRoWC0Wy2dQOlwUPW++CiPoQiw1enctV2Hj5DBzzjJZfyqs+FAXhgzL4q0Ww03AgSmQ==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -5639,17 +5840,20 @@ "dev": true }, "node_modules/espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", + "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", "dev": true, "dependencies": { - "acorn": "^8.7.1", + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/esprima": { @@ -5900,9 +6104,9 @@ "dev": true }, "node_modules/fastest-levenshtein": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.14.tgz", - "integrity": "sha512-tFfWHjnuUfKE186Tfgr+jtaFc0mZTApEgKDOeyN+FwOqRkO/zK/3h1AiRd8u8CY53owL3CUmGr/oI9p/RdyLTA==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", "engines": { "node": ">= 4.9.1" } @@ -5957,15 +6161,19 @@ } }, "node_modules/find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "dependencies": { - "locate-path": "^2.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat-cache": { @@ -6160,12 +6368,12 @@ "dev": true }, "node_modules/get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6278,6 +6486,12 @@ "node": ">=6" } }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/global-prefix/node_modules/which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -6291,9 +6505,9 @@ } }, "node_modules/globals": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", - "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6305,6 +6519,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -6336,6 +6565,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "node_modules/graphlib": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", @@ -6688,10 +6923,13 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } }, "node_modules/internal-slot": { "version": "1.0.3", @@ -6764,15 +7002,18 @@ } }, "node_modules/is-builtin-module": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.1.0.tgz", - "integrity": "sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", "dev": true, "dependencies": { - "builtin-modules": "^3.0.0" + "builtin-modules": "^3.3.0" }, "engines": { "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-callable": { @@ -8883,16 +9124,18 @@ } }, "node_modules/locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "dependencies": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^5.0.0" }, "engines": { - "node": ">=4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/lodash": { @@ -9031,18 +9274,6 @@ "markdown-it": "bin/markdown-it.js" } }, - "node_modules/markdown-it/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/markdownlint": { "version": "0.26.1", "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.26.1.tgz", @@ -9088,27 +9319,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/markdownlint-cli/node_modules/commander": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", - "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", - "dev": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/markdownlint-cli/node_modules/get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/markdownlint-cli/node_modules/glob": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", @@ -9723,36 +9933,18 @@ } }, "node_modules/p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "dependencies": { - "p-limit": "^1.1.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "dependencies": { - "p-try": "^1.0.0" + "node": ">=10" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-locate/node_modules/p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -9853,12 +10045,11 @@ } }, "node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true, + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/path-is-absolute": { @@ -9984,14 +10175,6 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "engines": { - "node": ">=8" - } - }, "node_modules/pluralize": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", @@ -10466,15 +10649,6 @@ "node": ">=8" } }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -10681,9 +10855,9 @@ "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" }, "node_modules/rollup": { - "version": "2.77.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.0.tgz", - "integrity": "sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==", + "version": "2.77.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", + "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", "dev": true, "peer": true, "bin": { @@ -10711,15 +10885,6 @@ "run-con": "cli.js" } }, - "node_modules/run-con/node_modules/ini": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", - "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", - "dev": true, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -11339,6 +11504,18 @@ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, + "node_modules/stylelint/node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -11421,10 +11598,19 @@ "node": ">=10.13.0" } }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/swagger-ui-dist": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.13.0.tgz", - "integrity": "sha512-5yqhkUU9uV5oT/MTMBeSgDGI0Vx6eCOU43AszQBs88poI8OB1v+FoXEFHv+NaBbEfTkXCMWlAJrH6iWyDzLETQ==" + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.13.2.tgz", + "integrity": "sha512-jHL6UyIYpvEI7NsuWd0R3hJaPQTg6Oo4qSBo+oVfOEkv6rrQm/475RGSMmZgV6ajp+Sgrp9CqrDjQYAgQqiv1A==" }, "node_modules/sync-request": { "version": "6.1.0", @@ -11814,9 +12000,9 @@ "dev": true }, "node_modules/typo-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.1.tgz", - "integrity": "sha512-bTGLjbD3WqZDR3CgEFkyi9Q/SS2oM29ipXrWfDb4M74ea69QwKAECVceYpaBu0GfdnASMg9Qfl67ttB23nePHg==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.2.tgz", + "integrity": "sha512-C7pYBQK17EjSg8tVNY91KHdUt5Nf6FMJ+c3js076quPmBML57PmNMzAcIq/2kf/hSYtFABNDIYNYlJRl5BJhGw==" }, "node_modules/uc.micro": { "version": "1.0.6", @@ -11888,9 +12074,9 @@ } }, "node_modules/updates": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.1.2.tgz", - "integrity": "sha512-wixXdKufbYwxKFMqWmkjnf6vlkZ8Lpx8fWYFrkxawNO9j7xlGQHCtbqW7LHkl/+tl57fFlvgvQ5dAIrseqk3Qw==", + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.1.4.tgz", + "integrity": "sha512-s8FKpHpREDoIbd1JDcEvsdf+wenhcQjrZK8v7OTIW69kozPttm6rW84Mm/LFouiDVYgaubY3us7sZlRUiGVx4Q==", "dev": true, "bin": { "updates": "bin/updates.js" @@ -12181,20 +12367,20 @@ } }, "node_modules/webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -12207,7 +12393,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "bin": { @@ -12272,6 +12458,14 @@ } } }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/webpack-merge": { "version": "5.8.0", "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", @@ -12462,24 +12656,24 @@ } }, "node_modules/workbox-core": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.3.tgz", - "integrity": "sha512-Bb9ey5n/M9x+l3fBTlLpHt9ASTzgSGj6vxni7pY72ilB/Pb3XtN+cZ9yueboVhD5+9cNQrC9n/E1fSrqWsUz7Q==" + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.4.tgz", + "integrity": "sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q==" }, "node_modules/workbox-routing": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.3.tgz", - "integrity": "sha512-DFjxcuRAJjjt4T34RbMm3MCn+xnd36UT/2RfPRfa8VWJGItGJIn7tG+GwVTdHmvE54i/QmVTJepyAGWtoLPTmg==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.4.tgz", + "integrity": "sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg==", "dependencies": { - "workbox-core": "6.5.3" + "workbox-core": "6.5.4" } }, "node_modules/workbox-strategies": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.3.tgz", - "integrity": "sha512-MgmGRrDVXs7rtSCcetZgkSZyMpRGw8HqL2aguszOc3nUmzGZsT238z/NN9ZouCxSzDu3PQ3ZSKmovAacaIhu1w==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.4.tgz", + "integrity": "sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw==", "dependencies": { - "workbox-core": "6.5.3" + "workbox-core": "6.5.4" } }, "node_modules/worker-loader": { @@ -12761,21 +12955,21 @@ "dev": true }, "@babel/core": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz", - "integrity": "sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", + "@babel/generator": "^7.18.10", "@babel/helper-compilation-targets": "^7.18.9", "@babel/helper-module-transforms": "^7.18.9", "@babel/helpers": "^7.18.9", - "@babel/parser": "^7.18.9", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.9", - "@babel/types": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -12792,12 +12986,12 @@ } }, "@babel/generator": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.9.tgz", - "integrity": "sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.10.tgz", + "integrity": "sha512-0+sW7e3HjQbiHbj1NeU/vN8ornohYlacAfZIaXhdoGweQqgcNy69COVciYYqEXJ/v+9OBA7Frxm4CVAuNqKeNA==", "dev": true, "requires": { - "@babel/types": "^7.18.9", + "@babel/types": "^7.18.10", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, @@ -12909,6 +13103,12 @@ "@babel/types": "^7.18.6" } }, + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==", + "dev": true + }, "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", @@ -13002,9 +13202,9 @@ } }, "@babel/parser": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", - "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.10.tgz", + "integrity": "sha512-TYk3OA0HKL6qNryUayb5UUEhM/rkOQozIBEA5ITXh5DWrSp0TlUQXMyZmnWxG/DizSWBeeQ0Zbc5z8UGaaqoeg==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -13133,30 +13333,30 @@ } }, "@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.9.tgz", - "integrity": "sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.10.tgz", + "integrity": "sha512-J7ycxg0/K9XCtLyHf0cz2DqDihonJeIo+z+HEdRe9YuT8TY4A66i+Ab2/xZCEW7Ro60bPCBBfqqboHSamoV3+g==", "dev": true, "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.9", + "@babel/generator": "^7.18.10", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.18.9", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.9", - "@babel/types": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -13170,11 +13370,12 @@ } }, "@babel/types": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", - "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "dev": true, "requires": { + "@babel/helper-string-parser": "^7.18.10", "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" } @@ -13208,6 +13409,12 @@ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, + "@esbuild/linux-loong64": { + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz", + "integrity": "sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg==", + "optional": true + }, "@eslint/eslintrc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", @@ -13260,9 +13467,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz", + "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -13270,6 +13477,12 @@ "minimatch": "^3.0.4" } }, + "@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true + }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -13345,12 +13558,6 @@ "p-limit": "^2.2.0" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -13987,6 +14194,19 @@ "dev": true, "requires": {} }, + "@mcaptcha/core-glue": { + "version": "0.1.0-alpha-3", + "resolved": "https://registry.npmjs.org/@mcaptcha/core-glue/-/core-glue-0.1.0-alpha-3.tgz", + "integrity": "sha512-avphBVgf3PPDWuUoDsB2qiXAss2pc00lUILswJaMQofr8FQyflzkhha8H2Z+qGFiX0Iib/yyP2TOtBDbHqE9Tg==" + }, + "@mcaptcha/vanilla-glue": { + "version": "0.1.0-alpha-2", + "resolved": "https://registry.npmjs.org/@mcaptcha/vanilla-glue/-/vanilla-glue-0.1.0-alpha-2.tgz", + "integrity": "sha512-cQOg3EIhdjk1xoZtjD9SVPwQAnd49FCvHKchwFZZuhdNTeFs7SUHynOCekuGow2Ip0RJZuMZGcRxvWMgd0ogng==", + "requires": { + "@mcaptcha/core-glue": "^0.1.0-alpha-3" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -14016,9 +14236,9 @@ "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" }, "@primer/octicons": { - "version": "17.3.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.3.0.tgz", - "integrity": "sha512-4zPwwloYWdR6RznMafV7Fsw3n2CeDPp/+qEIQbaX/tBbPY1KmU0OAXmhRfhD5AzgB5kdV1aQ7KnQr1GeQXl9Dg==", + "version": "17.4.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.4.0.tgz", + "integrity": "sha512-fRD9A/JszKOe5mDIU+g1b8jvcPj/qzusxdxnrIrg8Db0mLHsbGc4xNMUtHbRmgFOKaF6/QBR+WnWGQxv4yTcBg==", "requires": { "object-assign": "^4.1.1" } @@ -14058,9 +14278,9 @@ } }, "@sinclair/typebox": { - "version": "0.24.20", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.20.tgz", - "integrity": "sha512-kVaO5aEFZb33nPMTZBxiPEkY+slxiPtqC7QX8f9B3eGOMBvEfuMfxp9DSTTCsRJPumPKjrge4yagyssO4q6qzQ==", + "version": "0.24.26", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.26.tgz", + "integrity": "sha512-1ZVIyyS1NXDRVT8GjWD5jULjhDyM3IsIHef2VGUMdnWOlX2tkPjyEX/7K0TGSH2S8EaPhp1ylFdjSjUGQ+gecg==", "dev": true }, "@sinonjs/commons": { @@ -14163,9 +14383,9 @@ "dev": true }, "@stoplight/spectral-cli": { - "version": "6.4.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.4.1.tgz", - "integrity": "sha512-l5nWXy/6YEyk51VVrOurhupVScIqfK0ra8yIRSli+gnW5Kf5Nfw5PLci5GceQGaM5WE+wmqZ/iY95yOVFwHc+A==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.5.0.tgz", + "integrity": "sha512-BmTnQkkhG6E301ADUX7dhQtIIUT/WVRszRHy+90M5Bxk+4kod/6Gi8w7sWuQ5myDls3mLEMjYWUOKaUALuPvug==", "dev": true, "requires": { "@rollup/plugin-commonjs": "^20.0.0", @@ -14218,9 +14438,9 @@ } }, "@stoplight/spectral-core": { - "version": "1.12.3", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.12.3.tgz", - "integrity": "sha512-+PhVzTD8q6kUZw4BcbM+ibVaH5/ELryKt5tlLitA8SJIaJ+5/9ZKaGN0AV3ExZQZGYvXwucPOQuJKYZYKA6mWg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.13.0.tgz", + "integrity": "sha512-h++UIhdYK6bCZYHCK8byeyOq2tgAUbXdwdR3+Wy1O3PrJERdA9fyL0I3KQ595HylZRo7z1PUoSeyY6FMypWTBQ==", "dev": true, "requires": { "@stoplight/better-ajv-errors": "1.0.1", @@ -14231,11 +14451,13 @@ "@stoplight/spectral-ref-resolver": "^1.0.0", "@stoplight/spectral-runtime": "^1.0.0", "@stoplight/types": "~13.2.0", + "@types/es-aggregate-error": "^1.0.2", "@types/json-schema": "^7.0.11", "ajv": "^8.6.0", "ajv-errors": "~3.0.0", "ajv-formats": "~2.1.0", "blueimp-md5": "2.18.0", + "es-aggregate-error": "^1.0.7", "jsonpath-plus": "6.0.1", "lodash": "~4.17.21", "lodash.topath": "^4.5.2", @@ -14284,9 +14506,9 @@ } }, "@stoplight/spectral-functions": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.6.1.tgz", - "integrity": "sha512-f4cFtbI35bQtY0t4fYhKtS+/nMU3UsAeFlqm4tARGGG5WjOv4ieCFNFbgodKNiO3F4O+syMEjVQuXlBNPuY7jw==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.0.tgz", + "integrity": "sha512-ya3ovvH17QqHeL1o41rEXISJIUegb763Y8yWI01VaLj4zehKOjLzVNKIp1PsUNkG88M5fwB8Lrvjzcd3M8O3iw==", "dev": true, "requires": { "@stoplight/better-ajv-errors": "1.0.1", @@ -14344,12 +14566,12 @@ } }, "@stoplight/spectral-ruleset-bundler": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.3.0.tgz", - "integrity": "sha512-6Tif7GQL18F0LN1+FhEmhFWgE/TiWudb/pFl4DC7oS1QRoutB7QJPqIfVFSmteToPidxlrIbC6VAXSyEhlpDVQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.3.1.tgz", + "integrity": "sha512-TWjLFYBor1s/0v3xXwdVzzyUVu7ez2vYVNN4RMbJG7HIZgYW8MMVx4AVg5Eo1ZgLTkj/aeaoAOjIP7t+u6IBUg==", "dev": true, "requires": { - "@rollup/plugin-commonjs": "^21.0.1", + "@rollup/plugin-commonjs": "~22.0.0", "@stoplight/path": "1.3.2", "@stoplight/spectral-core": ">=1", "@stoplight/spectral-formats": ">=1", @@ -14362,15 +14584,15 @@ "@stoplight/types": "^12.3.0", "@types/node": "*", "pony-cause": "1.1.1", - "rollup": "~2.67.0", + "rollup": "~2.75.5", "tslib": "^2.3.1", "validate-npm-package-name": "3.0.0" }, "dependencies": { "@rollup/plugin-commonjs": { - "version": "21.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-21.1.0.tgz", - "integrity": "sha512-6ZtHx3VHIp2ReNNDxHjuUml6ur+WcQ28N1yHgCQwsbNkQg2suhxGMDQGJOn/KuDxKtd1xuZP5xSTwBA4GQ8hbA==", + "version": "22.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-22.0.1.tgz", + "integrity": "sha512-dGfEZvdjDHObBiP5IvwTKMVeq/tBZGMBHZFMdIV1ClMM/YoWS34xrHFGfag9SN2ZtMgNZRFruqvxZQEa70O6nQ==", "dev": true, "requires": { "@rollup/pluginutils": "^3.1.0", @@ -14383,9 +14605,9 @@ } }, "rollup": { - "version": "2.67.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.67.3.tgz", - "integrity": "sha512-G/x1vUwbGtP6O5ZM8/sWr8+p7YfZhI18pPqMRtMYMWSbHjKZ/ajHGiM+GWNTlWyOR0EHIdT8LHU+Z4ciIZ1oBw==", + "version": "2.75.7", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.75.7.tgz", + "integrity": "sha512-VSE1iy0eaAYNCxEXaleThdFXqZJ42qDBatAwrfnPlENEZ8erQ+0LYX4JXOLPceWfZpV1VtZwZ3dFCuOZiSyFtQ==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -14424,9 +14646,9 @@ } }, "@stoplight/spectral-rulesets": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.11.0.tgz", - "integrity": "sha512-0zFbxIuoWmGrkl2txOuaEDF8o6aoKDpMAYOG2oDfmmX9FhXX3c3ivIy80hyb2tMKkIYuqqx/zwIiOuww5S8iUA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.11.1.tgz", + "integrity": "sha512-0MDr5MW000FIZ3C47YY2Cg4NzU6wJFvvpSl1QRijRzdAVqQ1DgD3FgRDKHTA6OO7BmgWdCQYKSI8KwOH1Ju3kw==", "dev": true, "requires": { "@asyncapi/specs": "^2.14.0", @@ -14575,6 +14797,15 @@ "@types/node": "*" } }, + "@types/es-aggregate-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/es-aggregate-error/-/es-aggregate-error-1.0.2.tgz", + "integrity": "sha512-erqUpFXksaeR2kejKnhnjZjbFxUpGZx4Z7ydNL9ie8tEhXPiZTsLeUDJ6aR1F8j5wWUAtOAQWUqkc7givBJbBA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/eslint": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.5.tgz", @@ -14663,9 +14894,9 @@ "dev": true }, "@types/node": { - "version": "18.0.6", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.6.tgz", - "integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==" + "version": "18.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.3.tgz", + "integrity": "sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -14680,9 +14911,9 @@ "dev": true }, "@types/prettier": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.3.tgz", - "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.4.tgz", + "integrity": "sha512-fOwvpvQYStpb/zHMx0Cauwywu9yLDmzWiiQBC7gJyq5tYLUXFZvDG7VK1B7WBxxjBJNKFOZ0zLoOQn8vmATbhw==", "dev": true }, "@types/qs": { @@ -14943,9 +15174,9 @@ } }, "acorn": { - "version": "8.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", - "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==" }, "acorn-import-assertions": { "version": "1.8.0", @@ -15267,14 +15498,14 @@ } }, "browserslist": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.2.tgz", - "integrity": "sha512-MonuOgAtUB46uP5CezYbRaYKBNt2LxP0yX+Pmj4LkcDFGkn9Cbpi83d9sCjwQDErXsIJSzY5oKGDbgOlF/LPAA==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "requires": { - "caniuse-lite": "^1.0.30001366", - "electron-to-chromium": "^1.4.188", + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.4" + "update-browserslist-db": "^1.0.5" } }, "bser": { @@ -15343,9 +15574,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001367", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001367.tgz", - "integrity": "sha512-XDgbeOHfifWV3GEES2B8rtsrADx4Jf+juKX2SICJcaUhjYBO3bR96kvEIHa15VU6ohtOhBZuPGGYGbXMRn0NCw==" + "version": "1.0.30001373", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz", + "integrity": "sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==" }, "caseless": { "version": "0.12.0", @@ -15463,9 +15694,9 @@ "dev": true }, "codemirror": { - "version": "5.65.6", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.6.tgz", - "integrity": "sha512-zNihMSMoDxK9Gqv9oEyDT8oM51rcRrQ+IEo2zyS48gJByBq5Fj8XuNEguMra+MuIOuh6lkpnLUJeL70DoTt6yw==" + "version": "5.65.7", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.7.tgz", + "integrity": "sha512-zb67cXzgugIQmb6tfD4G11ILjYoMfTjwcjn+cWsa4GewlI2adhR/h3kolkoCQTm1msD/1BuqVTKuO09ELsS++A==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -15515,9 +15746,10 @@ } }, "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", + "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", + "dev": true }, "commondir": { "version": "1.0.1", @@ -15816,6 +16048,13 @@ "commander": "7", "iconv-lite": "0.6", "rw": "1" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + } } }, "d3-ease": { @@ -16426,6 +16665,14 @@ "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } } }, "domelementtype": { @@ -16486,9 +16733,9 @@ } }, "electron-to-chromium": { - "version": "1.4.195", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.195.tgz", - "integrity": "sha512-vefjEh0sk871xNmR5whJf9TEngX+KTKS3hOHpjoMpauKkwlGwtMz1H8IaIjAT/GNnX0TbGwAdmVoXCAzXf+PPg==" + "version": "1.4.210", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.210.tgz", + "integrity": "sha512-kSiX4tuyZijV7Cz0MWVmGT8K2siqaOA4Z66K5dCttPPRh0HicOcOAEj1KlC8O8J1aOS/1M8rGofOzksLKaHWcQ==" }, "emittery": { "version": "0.10.2", @@ -16516,9 +16763,9 @@ } }, "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true }, "envinfo": { @@ -16581,6 +16828,21 @@ "unbox-primitive": "^1.0.2" } }, + "es-aggregate-error": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.8.tgz", + "integrity": "sha512-AKUb5MKLWMozPlFRHOKqWD7yta5uaEhH21qwtnf6FlKjNjTJOoqFi0/G14+FfSkIQhhu6X68Af4xgRC6y8qG4A==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "function-bind": "^1.1.1", + "functions-have-names": "^1.2.3", + "get-intrinsic": "^1.1.1", + "globalthis": "^1.0.2", + "has-property-descriptors": "^1.0.0" + } + }, "es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", @@ -16607,114 +16869,115 @@ } }, "esbuild": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.49.tgz", - "integrity": "sha512-/TlVHhOaq7Yz8N1OJrjqM3Auzo5wjvHFLk+T8pIue+fhnhIMpfAzsG6PLVMbFveVxqD2WOp3QHei+52IMUNmCw==", - "requires": { - "esbuild-android-64": "0.14.49", - "esbuild-android-arm64": "0.14.49", - "esbuild-darwin-64": "0.14.49", - "esbuild-darwin-arm64": "0.14.49", - "esbuild-freebsd-64": "0.14.49", - "esbuild-freebsd-arm64": "0.14.49", - "esbuild-linux-32": "0.14.49", - "esbuild-linux-64": "0.14.49", - "esbuild-linux-arm": "0.14.49", - "esbuild-linux-arm64": "0.14.49", - "esbuild-linux-mips64le": "0.14.49", - "esbuild-linux-ppc64le": "0.14.49", - "esbuild-linux-riscv64": "0.14.49", - "esbuild-linux-s390x": "0.14.49", - "esbuild-netbsd-64": "0.14.49", - "esbuild-openbsd-64": "0.14.49", - "esbuild-sunos-64": "0.14.49", - "esbuild-windows-32": "0.14.49", - "esbuild-windows-64": "0.14.49", - "esbuild-windows-arm64": "0.14.49" + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.53.tgz", + "integrity": "sha512-ohO33pUBQ64q6mmheX1mZ8mIXj8ivQY/L4oVuAshr+aJI+zLl+amrp3EodrUNDNYVrKJXGPfIHFGhO8slGRjuw==", + "requires": { + "@esbuild/linux-loong64": "0.14.53", + "esbuild-android-64": "0.14.53", + "esbuild-android-arm64": "0.14.53", + "esbuild-darwin-64": "0.14.53", + "esbuild-darwin-arm64": "0.14.53", + "esbuild-freebsd-64": "0.14.53", + "esbuild-freebsd-arm64": "0.14.53", + "esbuild-linux-32": "0.14.53", + "esbuild-linux-64": "0.14.53", + "esbuild-linux-arm": "0.14.53", + "esbuild-linux-arm64": "0.14.53", + "esbuild-linux-mips64le": "0.14.53", + "esbuild-linux-ppc64le": "0.14.53", + "esbuild-linux-riscv64": "0.14.53", + "esbuild-linux-s390x": "0.14.53", + "esbuild-netbsd-64": "0.14.53", + "esbuild-openbsd-64": "0.14.53", + "esbuild-sunos-64": "0.14.53", + "esbuild-windows-32": "0.14.53", + "esbuild-windows-64": "0.14.53", + "esbuild-windows-arm64": "0.14.53" } }, "esbuild-android-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.49.tgz", - "integrity": "sha512-vYsdOTD+yi+kquhBiFWl3tyxnj2qZJsl4tAqwhT90ktUdnyTizgle7TjNx6Ar1bN7wcwWqZ9QInfdk2WVagSww==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz", + "integrity": "sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==", "optional": true }, "esbuild-android-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.49.tgz", - "integrity": "sha512-g2HGr/hjOXCgSsvQZ1nK4nW/ei8JUx04Li74qub9qWrStlysaVmadRyTVuW32FGIpLQyc5sUjjZopj49eGGM2g==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz", + "integrity": "sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==", "optional": true }, "esbuild-darwin-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.49.tgz", - "integrity": "sha512-3rvqnBCtX9ywso5fCHixt2GBCUsogNp9DjGmvbBohh31Ces34BVzFltMSxJpacNki96+WIcX5s/vum+ckXiLYg==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz", + "integrity": "sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==", "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.49.tgz", - "integrity": "sha512-XMaqDxO846srnGlUSJnwbijV29MTKUATmOLyQSfswbK/2X5Uv28M9tTLUJcKKxzoo9lnkYPsx2o8EJcTYwCs/A==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz", + "integrity": "sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==", "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.49.tgz", - "integrity": "sha512-NJ5Q6AjV879mOHFri+5lZLTp5XsO2hQ+KSJYLbfY9DgCu8s6/Zl2prWXVANYTeCDLlrIlNNYw8y34xqyLDKOmQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz", + "integrity": "sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==", "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.49.tgz", - "integrity": "sha512-lFLtgXnAc3eXYqj5koPlBZvEbBSOSUbWO3gyY/0+4lBdRqELyz4bAuamHvmvHW5swJYL7kngzIZw6kdu25KGOA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz", + "integrity": "sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==", "optional": true }, "esbuild-linux-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.49.tgz", - "integrity": "sha512-zTTH4gr2Kb8u4QcOpTDVn7Z8q7QEIvFl/+vHrI3cF6XOJS7iEI1FWslTo3uofB2+mn6sIJEQD9PrNZKoAAMDiA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz", + "integrity": "sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==", "optional": true }, "esbuild-linux-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.49.tgz", - "integrity": "sha512-hYmzRIDzFfLrB5c1SknkxzM8LdEUOusp6M2TnuQZJLRtxTgyPnZZVtyMeCLki0wKgYPXkFsAVhi8vzo2mBNeTg==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz", + "integrity": "sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==", "optional": true }, "esbuild-linux-arm": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.49.tgz", - "integrity": "sha512-iE3e+ZVv1Qz1Sy0gifIsarJMQ89Rpm9mtLSRtG3AH0FPgAzQ5Z5oU6vYzhc/3gSPi2UxdCOfRhw2onXuFw/0lg==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz", + "integrity": "sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==", "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.49.tgz", - "integrity": "sha512-KLQ+WpeuY+7bxukxLz5VgkAAVQxUv67Ft4DmHIPIW+2w3ObBPQhqNoeQUHxopoW/aiOn3m99NSmSV+bs4BSsdA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz", + "integrity": "sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==", "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.49.tgz", - "integrity": "sha512-n+rGODfm8RSum5pFIqFQVQpYBw+AztL8s6o9kfx7tjfK0yIGF6tm5HlG6aRjodiiKkH2xAiIM+U4xtQVZYU4rA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz", + "integrity": "sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==", "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.49.tgz", - "integrity": "sha512-WP9zR4HX6iCBmMFH+XHHng2LmdoIeUmBpL4aL2TR8ruzXyT4dWrJ5BSbT8iNo6THN8lod6GOmYDLq/dgZLalGw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz", + "integrity": "sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==", "optional": true }, "esbuild-linux-riscv64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.49.tgz", - "integrity": "sha512-h66ORBz+Dg+1KgLvzTVQEA1LX4XBd1SK0Fgbhhw4akpG/YkN8pS6OzYI/7SGENiN6ao5hETRDSkVcvU9NRtkMQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz", + "integrity": "sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==", "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.49.tgz", - "integrity": "sha512-DhrUoFVWD+XmKO1y7e4kNCqQHPs6twz6VV6Uezl/XHYGzM60rBewBF5jlZjG0nCk5W/Xy6y1xWeopkrhFFM0sQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz", + "integrity": "sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==", "optional": true }, "esbuild-loader": { @@ -16731,39 +16994,39 @@ } }, "esbuild-netbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.49.tgz", - "integrity": "sha512-BXaUwFOfCy2T+hABtiPUIpWjAeWK9P8O41gR4Pg73hpzoygVGnj0nI3YK4SJhe52ELgtdgWP/ckIkbn2XaTxjQ==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz", + "integrity": "sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==", "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.49.tgz", - "integrity": "sha512-lP06UQeLDGmVPw9Rg437Btu6J9/BmyhdoefnQ4gDEJTtJvKtQaUcOQrhjTq455ouZN4EHFH1h28WOJVANK41kA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz", + "integrity": "sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==", "optional": true }, "esbuild-sunos-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.49.tgz", - "integrity": "sha512-4c8Zowp+V3zIWje329BeLbGh6XI9c/rqARNaj5yPHdC61pHI9UNdDxT3rePPJeWcEZVKjkiAS6AP6kiITp7FSw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz", + "integrity": "sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==", "optional": true }, "esbuild-windows-32": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.49.tgz", - "integrity": "sha512-q7Rb+J9yHTeKr9QTPDYkqfkEj8/kcKz9lOabDuvEXpXuIcosWCJgo5Z7h/L4r7rbtTH4a8U2FGKb6s1eeOHmJA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz", + "integrity": "sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==", "optional": true }, "esbuild-windows-64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.49.tgz", - "integrity": "sha512-+Cme7Ongv0UIUTniPqfTX6mJ8Deo7VXw9xN0yJEN1lQMHDppTNmKwAM3oGbD/Vqff+07K2gN0WfNkMohmG+dVw==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz", + "integrity": "sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==", "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.49", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.49.tgz", - "integrity": "sha512-v+HYNAXzuANrCbbLFJ5nmO3m5y2PGZWLe3uloAkLt87aXiO2mZr3BTmacZdjwNkNEHuH3bNtN8cak+mzVjVPfA==", + "version": "0.14.53", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz", + "integrity": "sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==", "optional": true }, "escalade": { @@ -16843,13 +17106,14 @@ } }, "eslint": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.20.0.tgz", - "integrity": "sha512-d4ixhz5SKCa1D6SCPrivP7yYVi7nyD6A4vs6HIAul9ujBzcEmZVM3/0NN/yu5nKhmO1wjp5xQ46iRfmDGlOviA==", + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.21.0.tgz", + "integrity": "sha512-/XJ1+Qurf1T9G2M5IHrsjp+xrGT73RZf23xA1z5wB1ZzzEAWSZKvRwhWxTFp1rvkvCfwcvAUNAP31bhKTTGfDA==", "dev": true, "requires": { "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@humanwhocodes/config-array": "^0.10.4", + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -16859,14 +17123,17 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.3.3", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", + "globby": "^11.1.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", @@ -16944,6 +17211,55 @@ "requires": { "ms": "^2.1.1" } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true } } }, @@ -17002,9 +17318,9 @@ "requires": {} }, "eslint-plugin-sonarjs": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.13.0.tgz", - "integrity": "sha512-t3m7ta0EspzDxSOZh3cEOJIJVZgN/TlJYaBGnQlK6W/PZNbWep8q4RQskkJkA7/zwNpX0BaoEOSUUrqaADVoqA==", + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.14.0.tgz", + "integrity": "sha512-0X0q3fB8ghppms19cR2oIK2ajoFp7DEy3AVGDqO7WX02r1aWOzkrHa+veatGZw+R7amgBvfcF0qHCG66p9Zoag==", "dev": true, "requires": {} }, @@ -17031,9 +17347,9 @@ } }, "eslint-plugin-vue": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.2.0.tgz", - "integrity": "sha512-W2hc+NUXoce8sZtWgZ45miQTy6jNyuSdub5aZ1IBune4JDeAyzucYX0TzkrQ1jMO52sNUDYlCIHDoaNePe0p5g==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.3.0.tgz", + "integrity": "sha512-iscKKkBZgm6fGZwFt6poRoWC0Wy2dQOlwUPW++CiPoQiw1enctV2Hj5DBzzjJZfyqs+FAXhgzL4q0Ww03AgSmQ==", "dev": true, "requires": { "eslint-utils": "^3.0.0", @@ -17079,12 +17395,12 @@ "dev": true }, "espree": { - "version": "9.3.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", - "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz", + "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==", "dev": true, "requires": { - "acorn": "^8.7.1", + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" } @@ -17286,9 +17602,9 @@ "dev": true }, "fastest-levenshtein": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.14.tgz", - "integrity": "sha512-tFfWHjnuUfKE186Tfgr+jtaFc0mZTApEgKDOeyN+FwOqRkO/zK/3h1AiRd8u8CY53owL3CUmGr/oI9p/RdyLTA==" + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==" }, "fastq": { "version": "1.13.0", @@ -17331,12 +17647,13 @@ } }, "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "locate-path": "^2.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" } }, "flat-cache": { @@ -17487,9 +17804,9 @@ } }, "get-stdin": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", - "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", "dev": true }, "get-stream": { @@ -17569,6 +17886,12 @@ "which": "^1.3.1" }, "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -17581,14 +17904,23 @@ } }, "globals": { - "version": "13.16.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.16.0.tgz", - "integrity": "sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q==", + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", "dev": true, "requires": { "type-fest": "^0.20.2" } }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, "globby": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", @@ -17614,6 +17946,12 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, "graphlib": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", @@ -17872,9 +18210,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", "dev": true }, "internal-slot": { @@ -17930,12 +18268,12 @@ } }, "is-builtin-module": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.1.0.tgz", - "integrity": "sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.0.tgz", + "integrity": "sha512-phDA4oSGt7vl1n5tJvTWooWWAsXLY+2xCnxNqvKhGEzujg+A43wPlPOyDg3C8XQHN+6k/JTQWJ/j0dQh/qr+Hw==", "dev": true, "requires": { - "builtin-modules": "^3.0.0" + "builtin-modules": "^3.3.0" } }, "is-callable": { @@ -19624,13 +19962,12 @@ } }, "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "p-locate": "^2.0.0", - "path-exists": "^3.0.0" + "p-locate": "^5.0.0" } }, "lodash": { @@ -19751,14 +20088,6 @@ "linkify-it": "^4.0.1", "mdurl": "^1.0.1", "uc.micro": "^1.0.5" - }, - "dependencies": { - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - } } }, "markdownlint": { @@ -19797,18 +20126,6 @@ "balanced-match": "^1.0.0" } }, - "commander": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.4.0.tgz", - "integrity": "sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==", - "dev": true - }, - "get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "dev": true - }, "glob": { "version": "8.0.3", "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", @@ -20265,29 +20582,12 @@ } }, "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^1.1.0" - }, - "dependencies": { - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, - "requires": { - "p-try": "^1.0.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", - "dev": true - } + "p-limit": "^3.0.2" } }, "p-try": { @@ -20361,10 +20661,9 @@ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" }, "path-is-absolute": { "version": "1.0.1", @@ -20449,11 +20748,6 @@ "requires": { "p-limit": "^2.2.0" } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" } } }, @@ -20790,12 +21084,6 @@ "p-limit": "^2.2.0" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -20936,9 +21224,9 @@ "integrity": "sha512-ndEIpszUHiG4HtDsQLeIuMvRsDnn8c8rYStabochtUeCvfuvNptb5TUbVD68LRAILPX7p9nqQGh4xJgn3EHS/g==" }, "rollup": { - "version": "2.77.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.0.tgz", - "integrity": "sha512-vL8xjY4yOQEw79DvyXLijhnhh+R/O9zpF/LEgkCebZFtb6ELeN9H3/2T0r8+mp+fFTBHZ5qGpOpW2ela2zRt3g==", + "version": "2.77.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz", + "integrity": "sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==", "dev": true, "peer": true, "requires": { @@ -20955,14 +21243,6 @@ "ini": "~3.0.0", "minimist": "^1.2.6", "strip-json-comments": "~3.1.1" - }, - "dependencies": { - "ini": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", - "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", - "dev": true - } } }, "run-parallel": { @@ -21448,6 +21728,12 @@ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + }, "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -21525,12 +21811,20 @@ "csso": "^4.2.0", "picocolors": "^1.0.0", "stable": "^0.1.8" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true + } } }, "swagger-ui-dist": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.13.0.tgz", - "integrity": "sha512-5yqhkUU9uV5oT/MTMBeSgDGI0Vx6eCOU43AszQBs88poI8OB1v+FoXEFHv+NaBbEfTkXCMWlAJrH6iWyDzLETQ==" + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.13.2.tgz", + "integrity": "sha512-jHL6UyIYpvEI7NsuWd0R3hJaPQTg6Oo4qSBo+oVfOEkv6rrQm/475RGSMmZgV6ajp+Sgrp9CqrDjQYAgQqiv1A==" }, "sync-request": { "version": "6.1.0", @@ -21828,9 +22122,9 @@ "dev": true }, "typo-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.1.tgz", - "integrity": "sha512-bTGLjbD3WqZDR3CgEFkyi9Q/SS2oM29ipXrWfDb4M74ea69QwKAECVceYpaBu0GfdnASMg9Qfl67ttB23nePHg==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.2.tgz", + "integrity": "sha512-C7pYBQK17EjSg8tVNY91KHdUt5Nf6FMJ+c3js076quPmBML57PmNMzAcIq/2kf/hSYtFABNDIYNYlJRl5BJhGw==" }, "uc.micro": { "version": "1.0.6", @@ -21877,9 +22171,9 @@ } }, "updates": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.1.2.tgz", - "integrity": "sha512-wixXdKufbYwxKFMqWmkjnf6vlkZ8Lpx8fWYFrkxawNO9j7xlGQHCtbqW7LHkl/+tl57fFlvgvQ5dAIrseqk3Qw==", + "version": "13.1.4", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.1.4.tgz", + "integrity": "sha512-s8FKpHpREDoIbd1JDcEvsdf+wenhcQjrZK8v7OTIW69kozPttm6rW84Mm/LFouiDVYgaubY3us7sZlRUiGVx4Q==", "dev": true }, "uri-js": { @@ -22114,20 +22408,20 @@ "dev": true }, "webpack": { - "version": "5.73.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.73.0.tgz", - "integrity": "sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA==", + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", + "acorn": "^8.7.1", "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", + "enhanced-resolve": "^5.10.0", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -22140,7 +22434,7 @@ "schema-utils": "^3.1.0", "tapable": "^2.1.1", "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", + "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, "dependencies": { @@ -22219,6 +22513,13 @@ "interpret": "^2.2.0", "rechoir": "^0.7.0", "webpack-merge": "^5.7.3" + }, + "dependencies": { + "commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==" + } } }, "webpack-merge": { @@ -22311,24 +22612,24 @@ "dev": true }, "workbox-core": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.3.tgz", - "integrity": "sha512-Bb9ey5n/M9x+l3fBTlLpHt9ASTzgSGj6vxni7pY72ilB/Pb3XtN+cZ9yueboVhD5+9cNQrC9n/E1fSrqWsUz7Q==" + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.4.tgz", + "integrity": "sha512-OXYb+m9wZm8GrORlV2vBbE5EC1FKu71GGp0H4rjmxmF4/HLbMCoTFws87M3dFwgpmg0v00K++PImpNQ6J5NQ6Q==" }, "workbox-routing": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.3.tgz", - "integrity": "sha512-DFjxcuRAJjjt4T34RbMm3MCn+xnd36UT/2RfPRfa8VWJGItGJIn7tG+GwVTdHmvE54i/QmVTJepyAGWtoLPTmg==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.4.tgz", + "integrity": "sha512-apQswLsbrrOsBUWtr9Lf80F+P1sHnQdYodRo32SjiByYi36IDyL2r7BH1lJtFX8fwNHDa1QOVY74WKLLS6o5Pg==", "requires": { - "workbox-core": "6.5.3" + "workbox-core": "6.5.4" } }, "workbox-strategies": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.3.tgz", - "integrity": "sha512-MgmGRrDVXs7rtSCcetZgkSZyMpRGw8HqL2aguszOc3nUmzGZsT238z/NN9ZouCxSzDu3PQ3ZSKmovAacaIhu1w==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.4.tgz", + "integrity": "sha512-DEtsxhx0LIYWkJBTQolRxG4EI0setTJkqR4m7r4YpBdxtWJH1Mbg01Cj8ZjNOO8etqfA3IZaOPHUxCs8cBsKLw==", "requires": { - "workbox-core": "6.5.3" + "workbox-core": "6.5.4" } }, "worker-loader": { diff --git a/package.json b/package.json index e4741f98fec8..42cba24f8515 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ }, "dependencies": { "@claviska/jquery-minicolors": "2.3.6", - "@primer/octicons": "17.3.0", + "@mcaptcha/vanilla-glue": "0.1.0-alpha-2", + "@primer/octicons": "17.4.0", "add-asset-webpack-plugin": "2.0.1", "css-loader": "6.7.1", "dropzone": "6.0.0-beta.2", @@ -28,7 +29,7 @@ "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.13.0", + "swagger-ui-dist": "4.13.2", "tippy.js": "6.3.7", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", @@ -37,22 +38,22 @@ "vue-calendar-heatmap": "0.8.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", - "webpack": "5.73.0", + "webpack": "5.74.0", "webpack-cli": "4.10.0", - "workbox-routing": "6.5.3", - "workbox-strategies": "6.5.3", + "workbox-routing": "6.5.4", + "workbox-strategies": "6.5.4", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { "@happy-dom/jest-environment": "6.0.4", - "@stoplight/spectral-cli": "6.4.1", - "eslint": "8.20.0", + "@stoplight/spectral-cli": "6.5.0", + "eslint": "8.21.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-jquery": "1.5.1", - "eslint-plugin-sonarjs": "0.13.0", + "eslint-plugin-sonarjs": "0.14.0", "eslint-plugin-unicorn": "43.0.2", - "eslint-plugin-vue": "9.2.0", + "eslint-plugin-vue": "9.3.0", "jest": "28.1.3", "jest-extended": "3.0.1", "markdownlint-cli": "0.32.1", @@ -60,7 +61,7 @@ "stylelint": "14.9.1", "stylelint-config-standard": "26.0.0", "svgo": "2.8.0", - "updates": "13.1.2" + "updates": "13.1.4" }, "browserslist": [ "defaults", diff --git a/public/img/svg/fontawesome-send.svg b/public/img/svg/fontawesome-send.svg new file mode 100644 index 000000000000..b1170fd9e7c6 --- /dev/null +++ b/public/img/svg/fontawesome-send.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/gitea-exclamation.svg b/public/img/svg/gitea-exclamation.svg new file mode 100644 index 000000000000..d6c86136b31c --- /dev/null +++ b/public/img/svg/gitea-exclamation.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/gitea-pub.svg b/public/img/svg/gitea-pub.svg new file mode 100644 index 000000000000..4a750c7082ed --- /dev/null +++ b/public/img/svg/gitea-pub.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-cache.svg b/public/img/svg/octicon-cache.svg new file mode 100644 index 000000000000..20b14138d910 --- /dev/null +++ b/public/img/svg/octicon-cache.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-checkbox.svg b/public/img/svg/octicon-checkbox.svg new file mode 100644 index 000000000000..f0313bc747fc --- /dev/null +++ b/public/img/svg/octicon-checkbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-command-palette.svg b/public/img/svg/octicon-command-palette.svg new file mode 100644 index 000000000000..92fcd6314951 --- /dev/null +++ b/public/img/svg/octicon-command-palette.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-git-merge-queue.svg b/public/img/svg/octicon-git-merge-queue.svg new file mode 100644 index 000000000000..17d7767b058c --- /dev/null +++ b/public/img/svg/octicon-git-merge-queue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-paperclip.svg b/public/img/svg/octicon-paperclip.svg new file mode 100644 index 000000000000..ddae143818ff --- /dev/null +++ b/public/img/svg/octicon-paperclip.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-table.svg b/public/img/svg/octicon-table.svg index 905b2bb9b4c2..5b80f78357b6 100644 --- a/public/img/svg/octicon-table.svg +++ b/public/img/svg/octicon-table.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/img/svg/octicon-tasklist.svg b/public/img/svg/octicon-tasklist.svg index 81e41a87ced5..41b7c90f6de4 100644 --- a/public/img/svg/octicon-tasklist.svg +++ b/public/img/svg/octicon-tasklist.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index bb9a42e33dc9..cbf041a7e136 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/routers/api/packages/maven" "code.gitea.io/gitea/routers/api/packages/npm" "code.gitea.io/gitea/routers/api/packages/nuget" + "code.gitea.io/gitea/routers/api/packages/pub" "code.gitea.io/gitea/routers/api/packages/pypi" "code.gitea.io/gitea/routers/api/packages/rubygems" "code.gitea.io/gitea/services/auth" @@ -45,6 +46,7 @@ func Routes() *web.Route { authMethods := []auth.Method{ &auth.OAuth2{}, &auth.Basic{}, + &nuget.Auth{}, &conan.Auth{}, } if setting.Service.EnableReverseProxyAuth { @@ -155,12 +157,15 @@ func Routes() *web.Route { }) }) r.Group("/generic", func() { - r.Group("/{packagename}/{packageversion}/{filename}", func() { - r.Get("", generic.DownloadPackageFile) - r.Group("", func() { - r.Put("", generic.UploadPackage) - r.Delete("", generic.DeletePackage) - }, reqPackageAccess(perm.AccessModeWrite)) + r.Group("/{packagename}/{packageversion}", func() { + r.Delete("", reqPackageAccess(perm.AccessModeWrite), generic.DeletePackage) + r.Group("/{filename}", func() { + r.Get("", generic.DownloadPackageFile) + r.Group("", func() { + r.Put("", generic.UploadPackage) + r.Delete("", generic.DeletePackageFile) + }, reqPackageAccess(perm.AccessModeWrite)) + }) }) }) r.Group("/helm", func() { @@ -194,12 +199,26 @@ func Routes() *web.Route { r.Group("/@{scope}/{id}", func() { r.Get("", npm.PackageMetadata) r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage) - r.Get("/-/{version}/{filename}", npm.DownloadPackageFile) + r.Group("/-/{version}/{filename}", func() { + r.Get("", npm.DownloadPackageFile) + r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion) + }) + r.Group("/-rev/{revision}", func() { + r.Delete("", npm.DeletePackage) + r.Put("", npm.DeletePreview) + }, reqPackageAccess(perm.AccessModeWrite)) }) r.Group("/{id}", func() { r.Get("", npm.PackageMetadata) r.Put("", reqPackageAccess(perm.AccessModeWrite), npm.UploadPackage) - r.Get("/-/{version}/{filename}", npm.DownloadPackageFile) + r.Group("/-/{version}/{filename}", func() { + r.Get("", npm.DownloadPackageFile) + r.Delete("/-rev/{revision}", reqPackageAccess(perm.AccessModeWrite), npm.DeletePackageVersion) + }) + r.Group("/-rev/{revision}", func() { + r.Delete("", npm.DeletePackage) + r.Put("", npm.DeletePreview) + }, reqPackageAccess(perm.AccessModeWrite)) }) r.Group("/-/package/@{scope}/{id}/dist-tags", func() { r.Get("", npm.ListPackageTags) @@ -216,6 +235,20 @@ func Routes() *web.Route { }, reqPackageAccess(perm.AccessModeWrite)) }) }) + r.Group("/pub", func() { + r.Group("/api/packages", func() { + r.Group("/versions/new", func() { + r.Get("", pub.RequestUpload) + r.Post("/upload", pub.UploadPackageFile) + r.Get("/finalize/{id}/{version}", pub.FinalizePackage) + }, reqPackageAccess(perm.AccessModeWrite)) + r.Group("/{id}", func() { + r.Get("", pub.EnumeratePackageVersions) + r.Get("/files/{version}", pub.DownloadPackageFile) + r.Get("/{version}", pub.PackageVersionMetadata) + }) + }) + }) r.Group("/pypi", func() { r.Post("/", reqPackageAccess(perm.AccessModeWrite), pypi.UploadPackageFile) r.Get("/files/{id}/{version}/{filename}", pypi.DownloadPackageFile) diff --git a/routers/api/packages/container/manifest.go b/routers/api/packages/container/manifest.go index 319c9bcabc11..8beed3dbb729 100644 --- a/routers/api/packages/container/manifest.go +++ b/routers/api/packages/container/manifest.go @@ -312,6 +312,9 @@ func createPackageAndVersion(ctx context.Context, mci *manifestCreationInfo, met return nil, err } + // keep download count on overwrite + _pv.DownloadCount = pv.DownloadCount + if pv, err = packages_model.GetOrInsertVersion(ctx, _pv); err != nil { log.Error("Error inserting package: %v", err) return nil, err diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index 9a3a185d9da5..79e5afb03cae 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -31,22 +31,16 @@ func apiError(ctx *context.Context, status int, obj interface{}) { // DownloadPackageFile serves the specific generic package. func DownloadPackageFile(ctx *context.Context) { - packageName, packageVersion, filename, err := sanitizeParameters(ctx) - if err != nil { - apiError(ctx, http.StatusBadRequest, err) - return - } - s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion( ctx, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, PackageType: packages_model.TypeGeneric, - Name: packageName, - Version: packageVersion, + Name: ctx.Params("packagename"), + Version: ctx.Params("packageversion"), }, &packages_service.PackageFileInfo{ - Filename: filename, + Filename: ctx.Params("filename"), }, ) if err != nil { @@ -65,9 +59,17 @@ func DownloadPackageFile(ctx *context.Context) { // UploadPackage uploads the specific generic package. // Duplicated packages get rejected. func UploadPackage(ctx *context.Context) { - packageName, packageVersion, filename, err := sanitizeParameters(ctx) - if err != nil { - apiError(ctx, http.StatusBadRequest, err) + packageName := ctx.Params("packagename") + filename := ctx.Params("filename") + + if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) { + apiError(ctx, http.StatusBadRequest, errors.New("Invalid package name or filename")) + return + } + + packageVersion := ctx.Params("packageversion") + if packageVersion != strings.TrimSpace(packageVersion) { + apiError(ctx, http.StatusBadRequest, errors.New("Invalid package version")) return } @@ -88,7 +90,7 @@ func UploadPackage(ctx *context.Context) { } defer buf.Close() - _, _, err = packages_service.CreatePackageAndAddFile( + _, _, err = packages_service.CreatePackageOrAddFileToExisting( &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -107,8 +109,8 @@ func UploadPackage(ctx *context.Context) { }, ) if err != nil { - if err == packages_model.ErrDuplicatePackageVersion { - apiError(ctx, http.StatusBadRequest, err) + if err == packages_model.ErrDuplicatePackageFile { + apiError(ctx, http.StatusConflict, err) return } apiError(ctx, http.StatusInternalServerError, err) @@ -120,19 +122,13 @@ func UploadPackage(ctx *context.Context) { // DeletePackage deletes the specific generic package. func DeletePackage(ctx *context.Context) { - packageName, packageVersion, _, err := sanitizeParameters(ctx) - if err != nil { - apiError(ctx, http.StatusBadRequest, err) - return - } - - err = packages_service.RemovePackageVersionByNameAndVersion( + err := packages_service.RemovePackageVersionByNameAndVersion( ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, PackageType: packages_model.TypeGeneric, - Name: packageName, - Version: packageVersion, + Name: ctx.Params("packagename"), + Version: ctx.Params("packageversion"), }, ) if err != nil { @@ -144,21 +140,50 @@ func DeletePackage(ctx *context.Context) { return } - ctx.Status(http.StatusOK) + ctx.Status(http.StatusNoContent) } -func sanitizeParameters(ctx *context.Context) (string, string, string, error) { - packageName := ctx.Params("packagename") - filename := ctx.Params("filename") +// DeletePackageFile deletes the specific file of a generic package. +func DeletePackageFile(ctx *context.Context) { + pv, pf, err := func() (*packages_model.PackageVersion, *packages_model.PackageFile, error) { + pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeGeneric, ctx.Params("packagename"), ctx.Params("packageversion")) + if err != nil { + return nil, nil, err + } - if !packageNameRegex.MatchString(packageName) || !filenameRegex.MatchString(filename) { - return "", "", "", errors.New("Invalid package name or filename") + pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, ctx.Params("filename"), packages_model.EmptyFileKey) + if err != nil { + return nil, nil, err + } + + return pv, pf, nil + }() + if err != nil { + if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist { + apiError(ctx, http.StatusNotFound, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return } - packageVersion := strings.TrimSpace(ctx.Params("packageversion")) - if packageVersion == "" { - return "", "", "", errors.New("Invalid package version") + pfs, err := packages_model.GetFilesByVersionID(ctx, pv.ID) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + if len(pfs) == 1 { + if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + } else { + if err := packages_service.DeletePackageFile(ctx, pf); err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } } - return packageName, packageVersion, filename, nil + ctx.Status(http.StatusNoContent) } diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index bba4babf04f6..072a15f95c41 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -266,8 +266,9 @@ func UploadPackageFile(ctx *context.Context) { PackageFileInfo: packages_service.PackageFileInfo{ Filename: params.Filename, }, - Data: buf, - IsLead: false, + Data: buf, + IsLead: false, + OverwriteExisting: params.IsMeta, } // If it's the package pom file extract the metadata diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 152edc681a04..d5ba70f9645b 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -164,6 +164,63 @@ func UploadPackage(ctx *context.Context) { ctx.Status(http.StatusCreated) } +// DeletePreview does nothing +// The client tells the server what package version it knows about after deleting a version. +func DeletePreview(ctx *context.Context) { + ctx.Status(http.StatusOK) +} + +// DeletePackageVersion deletes the package version +func DeletePackageVersion(ctx *context.Context) { + packageName := packageNameFromParams(ctx) + packageVersion := ctx.Params("version") + + err := packages_service.RemovePackageVersionByNameAndVersion( + ctx.Doer, + &packages_service.PackageInfo{ + Owner: ctx.Package.Owner, + PackageType: packages_model.TypeNpm, + Name: packageName, + Version: packageVersion, + }, + ) + if err != nil { + if err == packages_model.ErrPackageNotExist { + apiError(ctx, http.StatusNotFound, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return + } + + ctx.Status(http.StatusOK) +} + +// DeletePackage deletes the package and all versions +func DeletePackage(ctx *context.Context) { + packageName := packageNameFromParams(ctx) + + pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeNpm, packageName) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + if len(pvs) == 0 { + apiError(ctx, http.StatusNotFound, err) + return + } + + for _, pv := range pvs { + if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + } + + ctx.Status(http.StatusOK) +} + // ListPackageTags returns all tags for a package func ListPackageTags(ctx *context.Context) { packageName := packageNameFromParams(ctx) diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go new file mode 100644 index 000000000000..26a5b9018931 --- /dev/null +++ b/routers/api/packages/nuget/auth.go @@ -0,0 +1,45 @@ +// 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 nuget + +import ( + "net/http" + + "code.gitea.io/gitea/models" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/services/auth" +) + +type Auth struct{} + +func (a *Auth) Name() string { + return "nuget" +} + +// https://docs.microsoft.com/en-us/nuget/api/package-publish-resource#request-parameters +func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) *user_model.User { + token, err := models.GetAccessTokenBySHA(req.Header.Get("X-NuGet-ApiKey")) + if err != nil { + if !(models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err)) { + log.Error("GetAccessTokenBySHA: %v", err) + } + return nil + } + + u, err := user_model.GetUserByID(token.UID) + if err != nil { + log.Error("GetUserByID: %v", err) + return nil + } + + token.UpdatedUnix = timeutil.TimeStampNow() + if err := models.UpdateAccessToken(token); err != nil { + log.Error("UpdateAccessToken: %v", err) + } + + return u +} diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index b7667a32225a..81ea28bcad49 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -102,7 +102,7 @@ func RegistrationLeaf(ctx *context.Context) { packageName := ctx.Params("id") packageVersion := strings.TrimSuffix(ctx.Params("version"), ".json") - pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, ctx.Package.Owner.ID, packages_model.TypeNuGet, packageName, packageVersion) + pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypeNuGet, packageName, packageVersion) if err != nil { if err == packages_model.ErrPackageNotExist { apiError(ctx, http.StatusNotFound, err) @@ -217,7 +217,7 @@ func UploadPackage(ctx *context.Context) { ) if err != nil { if err == packages_model.ErrDuplicatePackageVersion { - apiError(ctx, http.StatusBadRequest, err) + apiError(ctx, http.StatusConflict, err) return } apiError(ctx, http.StatusInternalServerError, err) @@ -274,7 +274,7 @@ func UploadSymbolPackage(ctx *context.Context) { case packages_model.ErrPackageNotExist: apiError(ctx, http.StatusNotFound, err) case packages_model.ErrDuplicatePackageFile: - apiError(ctx, http.StatusBadRequest, err) + apiError(ctx, http.StatusConflict, err) default: apiError(ctx, http.StatusInternalServerError, err) } @@ -299,7 +299,7 @@ func UploadSymbolPackage(ctx *context.Context) { if err != nil { switch err { case packages_model.ErrDuplicatePackageFile: - apiError(ctx, http.StatusBadRequest, err) + apiError(ctx, http.StatusConflict, err) default: apiError(ctx, http.StatusInternalServerError, err) } @@ -414,4 +414,6 @@ func DeletePackage(ctx *context.Context) { } apiError(ctx, http.StatusInternalServerError, err) } + + ctx.Status(http.StatusNoContent) } diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go new file mode 100644 index 000000000000..470f4462388a --- /dev/null +++ b/routers/api/packages/pub/pub.go @@ -0,0 +1,275 @@ +// 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 pub + +import ( + "fmt" + "io" + "net/http" + "net/url" + "sort" + "strings" + "time" + + packages_model "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/log" + packages_module "code.gitea.io/gitea/modules/packages" + pub_module "code.gitea.io/gitea/modules/packages/pub" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/routers/api/packages/helper" + packages_service "code.gitea.io/gitea/services/packages" +) + +func jsonResponse(ctx *context.Context, status int, obj interface{}) { + resp := ctx.Resp + resp.Header().Set("Content-Type", "application/vnd.pub.v2+json") + resp.WriteHeader(status) + if err := json.NewEncoder(resp).Encode(obj); err != nil { + log.Error("JSON encode: %v", err) + } +} + +func apiError(ctx *context.Context, status int, obj interface{}) { + type Error struct { + Code string `json:"code"` + Message string `json:"message"` + } + type ErrorWrapper struct { + Error Error `json:"error"` + } + + helper.LogAndProcessError(ctx, status, obj, func(message string) { + jsonResponse(ctx, status, ErrorWrapper{ + Error: Error{ + Code: http.StatusText(status), + Message: message, + }, + }) + }) +} + +type packageVersions struct { + Name string `json:"name"` + Latest *versionMetadata `json:"latest"` + Versions []*versionMetadata `json:"versions"` +} + +type versionMetadata struct { + Version string `json:"version"` + ArchiveURL string `json:"archive_url"` + Published time.Time `json:"published"` + Pubspec interface{} `json:"pubspec,omitempty"` +} + +func packageDescriptorToMetadata(baseURL string, pd *packages_model.PackageDescriptor) *versionMetadata { + return &versionMetadata{ + Version: pd.Version.Version, + ArchiveURL: fmt.Sprintf("%s/files/%s.tar.gz", baseURL, url.PathEscape(pd.Version.Version)), + Published: time.Unix(int64(pd.Version.CreatedUnix), 0), + Pubspec: pd.Metadata.(*pub_module.Metadata).Pubspec, + } +} + +func baseURL(ctx *context.Context) string { + return setting.AppURL + "api/packages/" + ctx.Package.Owner.Name + "/pub/api/packages" +} + +// https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md#list-all-versions-of-a-package +func EnumeratePackageVersions(ctx *context.Context) { + packageName := ctx.Params("id") + + pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + if len(pvs) == 0 { + apiError(ctx, http.StatusNotFound, err) + return + } + + pds, err := packages_model.GetPackageDescriptors(ctx, pvs) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + sort.Slice(pds, func(i, j int) bool { + return pds[i].SemVer.LessThan(pds[j].SemVer) + }) + + baseURL := fmt.Sprintf("%s/%s", baseURL(ctx), url.PathEscape(pds[0].Package.Name)) + + versions := make([]*versionMetadata, 0, len(pds)) + for _, pd := range pds { + versions = append(versions, packageDescriptorToMetadata(baseURL, pd)) + } + + jsonResponse(ctx, http.StatusOK, &packageVersions{ + Name: pds[0].Package.Name, + Latest: packageDescriptorToMetadata(baseURL, pds[0]), + Versions: versions, + }) +} + +// https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md#deprecated-inspect-a-specific-version-of-a-package +func PackageVersionMetadata(ctx *context.Context) { + packageName := ctx.Params("id") + packageVersion := ctx.Params("version") + + pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion) + if err != nil { + if err == packages_model.ErrPackageNotExist { + apiError(ctx, http.StatusNotFound, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return + } + + pd, err := packages_model.GetPackageDescriptor(ctx, pv) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + jsonResponse(ctx, http.StatusOK, packageDescriptorToMetadata( + fmt.Sprintf("%s/%s", baseURL(ctx), url.PathEscape(pd.Package.Name)), + pd, + )) +} + +// https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md#publishing-packages +func RequestUpload(ctx *context.Context) { + type UploadRequest struct { + URL string `json:"url"` + Fields map[string]string `json:"fields"` + } + + jsonResponse(ctx, http.StatusOK, UploadRequest{ + URL: baseURL(ctx) + "/versions/new/upload", + Fields: make(map[string]string), + }) +} + +// https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md#publishing-packages +func UploadPackageFile(ctx *context.Context) { + file, _, err := ctx.Req.FormFile("file") + if err != nil { + apiError(ctx, http.StatusBadRequest, err) + return + } + defer file.Close() + + buf, err := packages_module.CreateHashedBufferFromReader(file, 32*1024*1024) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + defer buf.Close() + + pck, err := pub_module.ParsePackage(buf) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + if _, err := buf.Seek(0, io.SeekStart); err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + _, _, err = packages_service.CreatePackageAndAddFile( + &packages_service.PackageCreationInfo{ + PackageInfo: packages_service.PackageInfo{ + Owner: ctx.Package.Owner, + PackageType: packages_model.TypePub, + Name: pck.Name, + Version: pck.Version, + }, + SemverCompatible: true, + Creator: ctx.Doer, + Metadata: pck.Metadata, + }, + &packages_service.PackageFileCreationInfo{ + PackageFileInfo: packages_service.PackageFileInfo{ + Filename: strings.ToLower(pck.Version + ".tar.gz"), + }, + Data: buf, + IsLead: true, + }, + ) + if err != nil { + if err == packages_model.ErrDuplicatePackageVersion { + apiError(ctx, http.StatusBadRequest, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return + } + + ctx.Resp.Header().Set("Location", fmt.Sprintf("%s/versions/new/finalize/%s/%s", baseURL(ctx), url.PathEscape(pck.Name), url.PathEscape(pck.Version))) + ctx.Status(http.StatusNoContent) +} + +// https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md#publishing-packages +func FinalizePackage(ctx *context.Context) { + packageName := ctx.Params("id") + packageVersion := ctx.Params("version") + + _, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion) + if err != nil { + if err == packages_model.ErrPackageNotExist { + apiError(ctx, http.StatusNotFound, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return + } + + type Success struct { + Message string `json:"message"` + } + type SuccessWrapper struct { + Success Success `json:"success"` + } + + jsonResponse(ctx, http.StatusOK, SuccessWrapper{Success{}}) +} + +// https://github.com/dart-lang/pub/blob/master/doc/repository-spec-v2.md#deprecated-download-a-specific-version-of-a-package +func DownloadPackageFile(ctx *context.Context) { + packageName := ctx.Params("id") + packageVersion := strings.TrimSuffix(ctx.Params("version"), ".tar.gz") + + pv, err := packages_model.GetVersionByNameAndVersion(ctx, ctx.Package.Owner.ID, packages_model.TypePub, packageName, packageVersion) + if err != nil { + if err == packages_model.ErrPackageNotExist { + apiError(ctx, http.StatusNotFound, err) + return + } + apiError(ctx, http.StatusInternalServerError, err) + return + } + + pd, err := packages_model.GetPackageDescriptor(ctx, pv) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + + pf := pd.Files[0].File + + s, _, err := packages_service.GetPackageFileStream(ctx, pf) + if err != nil { + apiError(ctx, http.StatusInternalServerError, err) + return + } + defer s.Close() + + ctx.ServeStream(s, pf.Name) +} diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index 5a9c93b3ca06..2c023891022a 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -41,7 +41,7 @@ func ListPackages(ctx *context.APIContext) { // in: query // description: package type filter // type: string - // enum: [composer, conan, container, generic, helm, maven, npm, nuget, pypi, rubygems] + // enum: [composer, conan, container, generic, helm, maven, npm, nuget, pub, pypi, rubygems] // - name: q // in: query // description: name filter diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index ddad18ef62ca..08e3e037417c 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -282,7 +282,7 @@ func SearchIssues(ctx *context.APIContext) { } } - ctx.SetLinkHeader(int(filteredCount), setting.UI.IssuePagingNum) + ctx.SetLinkHeader(int(filteredCount), limit) ctx.SetTotalCountHeader(filteredCount) ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) } diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index a3a590492500..d423bddbbd4d 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -427,9 +427,9 @@ func ListPageRevisions(ctx *context.APIContext) { } // get Commit Count - commitsHistory, err := wikiRepo.CommitsByFileAndRangeNoFollow("master", pageFilename, page) + commitsHistory, err := wikiRepo.CommitsByFileAndRange("master", pageFilename, page) if err != nil { - ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRangeNoFollow", err) + ctx.Error(http.StatusInternalServerError, "CommitsByFileAndRange", err) return } diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index f0dc595ad5cc..ba008f587c69 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -15,7 +15,6 @@ import ( "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "code.gitea.io/gitea/routers/utils" webhook_service "code.gitea.io/gitea/services/webhook" ) @@ -141,14 +140,15 @@ func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID ctx.Error(http.StatusUnprocessableEntity, "", "Missing config option: channel") return nil, false } + channel = strings.TrimSpace(channel) - if !utils.IsValidSlackChannel(channel) { + if !webhook_service.IsValidSlackChannel(channel) { ctx.Error(http.StatusBadRequest, "", "Invalid slack channel name") return nil, false } meta, err := json.Marshal(&webhook_service.SlackMeta{ - Channel: strings.TrimSpace(channel), + Channel: channel, Username: form.Config["username"], IconURL: form.Config["icon_url"], Color: form.Config["color"], diff --git a/routers/init.go b/routers/init.go index e640ca48453b..612fc5a83dbb 100644 --- a/routers/init.go +++ b/routers/init.go @@ -100,10 +100,8 @@ func GlobalInitInstalled(ctx context.Context) { log.Fatal("Gitea is not installed") } - mustInitCtx(ctx, git.InitOnceWithSync) + mustInitCtx(ctx, git.InitFull) log.Info("Git Version: %s (home: %s)", git.VersionInfo(), git.HomeDir()) - - git.CheckLFSVersion() log.Info("AppPath: %s", setting.AppPath) log.Info("AppWorkPath: %s", setting.AppWorkPath) log.Info("Custom path: %s", setting.CustomPath) diff --git a/routers/private/mail.go b/routers/private/mail.go index 966a83816800..e858992aee13 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -9,6 +9,7 @@ import ( "net/http" "strconv" + "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/json" @@ -59,7 +60,7 @@ func SendEmail(ctx *context.PrivateContext) { } } } else { - err := user_model.IterateUser(func(user *user_model.User) error { + err := db.IterateObjects(ctx, func(user *user_model.User) error { if len(user.Email) > 0 && user.IsActive { emails = append(emails, user.Email) } diff --git a/routers/utils/utils.go b/routers/utils/utils.go index f15bc1e62e4b..66eaa1d9ce17 100644 --- a/routers/utils/utils.go +++ b/routers/utils/utils.go @@ -20,25 +20,6 @@ func RemoveUsernameParameterSuffix(name string) string { return name } -// IsValidSlackChannel validates a channel name conforms to what slack expects. -// It makes sure a channel name cannot be empty and invalid ( only an # ) -func IsValidSlackChannel(channelName string) bool { - switch len(strings.TrimSpace(channelName)) { - case 0: - return false - case 1: - // Keep default behaviour where a channel name is still - // valid without an # - // But if it contains only an #, it should be regarded as - // invalid - if channelName[0] == '#' { - return false - } - } - - return true -} - // SanitizeFlashErrorString will sanitize a flash error string func SanitizeFlashErrorString(x string) string { return strings.ReplaceAll(html.EscapeString(x), "\n", "
") diff --git a/routers/utils/utils_test.go b/routers/utils/utils_test.go index f49ed77b6fc0..42cf948e3091 100644 --- a/routers/utils/utils_test.go +++ b/routers/utils/utils_test.go @@ -18,23 +18,6 @@ func TestRemoveUsernameParameterSuffix(t *testing.T) { assert.Equal(t, "", RemoveUsernameParameterSuffix("")) } -func TestIsValidSlackChannel(t *testing.T) { - tt := []struct { - channelName string - expected bool - }{ - {"gitea", true}, - {" ", false}, - {"#", false}, - {"gitea ", true}, - {" gitea", true}, - } - - for _, v := range tt { - assert.Equal(t, v.expected, IsValidSlackChannel(v.channelName)) - } -} - func TestIsExternalURL(t *testing.T) { setting.AppURL = "https://try.gitea.io/" type test struct { diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index ebe5066d2cf6..c773034c533f 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -257,6 +257,7 @@ func Config(ctx *context.Context) { ctx.Data["ScriptType"] = setting.ScriptType ctx.Data["ReverseProxyAuthUser"] = setting.ReverseProxyAuthUser ctx.Data["ReverseProxyAuthEmail"] = setting.ReverseProxyAuthEmail + ctx.Data["ReverseProxyAuthFullName"] = setting.ReverseProxyAuthFullName ctx.Data["SSH"] = setting.SSH ctx.Data["LFS"] = setting.LFS diff --git a/routers/web/admin/users_test.go b/routers/web/admin/users_test.go index e63367ccf2cd..da67cd5cb45d 100644 --- a/routers/web/admin/users_test.go +++ b/routers/web/admin/users_test.go @@ -25,7 +25,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, ID: 2, - }).(*user_model.User) + }) ctx.Doer = u @@ -62,7 +62,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, ID: 2, - }).(*user_model.User) + }) ctx.Doer = u @@ -99,7 +99,7 @@ func TestNewUserPost_InvalidEmail(t *testing.T) { u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, ID: 2, - }).(*user_model.User) + }) ctx.Doer = u @@ -129,7 +129,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, ID: 2, - }).(*user_model.User) + }) ctx.Doer = u @@ -167,7 +167,7 @@ func TestNewUserPost_VisibilityPrivate(t *testing.T) { u := unittest.AssertExistsAndLoadBean(t, &user_model.User{ IsAdmin: true, ID: 2, - }).(*user_model.User) + }) ctx.Doer = u diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 610e4d29045d..8a4c12d57b57 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/eventsource" "code.gitea.io/gitea/modules/hcaptcha" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/session" @@ -414,6 +415,8 @@ func SignUp(ctx *context.Context) { ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["PageIsSignUp"] = true // Show Disabled Registration message if DisableRegistration or AllowOnlyExternalRegistration options are true @@ -435,6 +438,8 @@ func SignUpPost(ctx *context.Context) { ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["PageIsSignUp"] = true // Permission denied if DisableRegistration or AllowOnlyExternalRegistration options are true @@ -458,6 +463,8 @@ func SignUpPost(ctx *context.Context) { valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) case setting.HCaptcha: valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) + case setting.MCaptcha: + valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) default: ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) return diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index a2d76e9c5a34..4f3f2062b689 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/hcaptcha" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" @@ -40,6 +41,8 @@ func LinkAccount(ctx *context.Context) { ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["AllowOnlyInternalRegistration"] = setting.Service.AllowOnlyInternalRegistration ctx.Data["ShowRegistrationButton"] = false @@ -96,6 +99,8 @@ func LinkAccountPostSignIn(ctx *context.Context) { ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false @@ -195,6 +200,8 @@ func LinkAccountPostRegister(ctx *context.Context) { ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["DisableRegistration"] = setting.Service.DisableRegistration ctx.Data["ShowRegistrationButton"] = false @@ -233,6 +240,8 @@ func LinkAccountPostRegister(ctx *context.Context) { valid, err = recaptcha.Verify(ctx, form.GRecaptchaResponse) case setting.HCaptcha: valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) + case setting.MCaptcha: + valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) default: ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) return diff --git a/routers/web/auth/oauth_test.go b/routers/web/auth/oauth_test.go index 57f2477dba3e..48400846d245 100644 --- a/routers/web/auth/oauth_test.go +++ b/routers/web/auth/oauth_test.go @@ -60,7 +60,7 @@ func TestNewAccessTokenResponse_OIDCToken(t *testing.T) { assert.Empty(t, oidcToken.Email) assert.False(t, oidcToken.EmailVerified) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) grants, err = auth.GetOAuth2GrantsByUserID(db.DefaultContext, user.ID) assert.NoError(t, err) assert.Len(t, grants, 1) diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 32ae91da47b8..3b1065189d9d 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/hcaptcha" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/mcaptcha" "code.gitea.io/gitea/modules/recaptcha" "code.gitea.io/gitea/modules/session" "code.gitea.io/gitea/modules/setting" @@ -341,6 +342,8 @@ func RegisterOpenID(ctx *context.Context) { ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey ctx.Data["RecaptchaURL"] = setting.Service.RecaptchaURL + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["OpenID"] = oid userName, _ := ctx.Session.Get("openid_determined_username").(string) if userName != "" { @@ -372,6 +375,8 @@ func RegisterOpenIDPost(ctx *context.Context) { ctx.Data["CaptchaType"] = setting.Service.CaptchaType ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey + ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey + ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL ctx.Data["OpenID"] = oid if setting.Service.AllowOnlyInternalRegistration { @@ -397,6 +402,12 @@ func RegisterOpenIDPost(ctx *context.Context) { return } valid, err = hcaptcha.Verify(ctx, form.HcaptchaResponse) + case setting.MCaptcha: + if err := ctx.Req.ParseForm(); err != nil { + ctx.ServerError("", err) + return + } + valid, err = mcaptcha.Verify(ctx, form.McaptchaResponse) default: ctx.ServerError("Unknown Captcha Type", fmt.Errorf("Unknown Captcha Type: %s", setting.Service.CaptchaType)) return diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index 06c43aec19fb..c53a53b47193 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -40,7 +40,7 @@ type blameRow struct { CommitMessage string CommitSince gotemplate.HTML Code gotemplate.HTML - EscapeStatus charset.EscapeStatus + EscapeStatus *charset.EscapeStatus } // RefBlame render blame page @@ -235,7 +235,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m } lines := make([]string, 0) rows := make([]*blameRow, 0) - escapeStatus := charset.EscapeStatus{} + escapeStatus := &charset.EscapeStatus{} i := 0 commitCnt := 0 @@ -280,7 +280,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m fileName := fmt.Sprintf("%v", ctx.Data["FileName"]) line = highlight.Code(fileName, language, line) - br.EscapeStatus, line = charset.EscapeControlString(line) + br.EscapeStatus, line = charset.EscapeControlHTML(line, ctx.Locale) br.Code = gotemplate.HTML(line) rows = append(rows, br) escapeStatus = escapeStatus.Or(br.EscapeStatus) diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index 6a85bca16b2f..5aa2bcd13471 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -474,11 +474,12 @@ func serviceRPC(ctx gocontext.Context, h serviceHandler, service string) { cmd := git.NewCommand(h.r.Context(), service, "--stateless-rpc", h.dir) cmd.SetDescription(fmt.Sprintf("%s %s %s [repo_path: %s]", git.GitExecutable, service, "--stateless-rpc", h.dir)) if err := cmd.Run(&git.RunOpts{ - Dir: h.dir, - Env: append(os.Environ(), h.environ...), - Stdout: h.w, - Stdin: reqBody, - Stderr: &stderr, + Dir: h.dir, + Env: append(os.Environ(), h.environ...), + Stdout: h.w, + Stdin: reqBody, + Stderr: &stderr, + UseContextTimeout: true, }); err != nil { if err.Error() != "signal: killed" { log.Error("Fail to serve RPC(%s) in %s: %v - %s", service, h.dir, err, stderr.String()) diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index e6f9529e31e8..ad25a94e13b1 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -133,7 +133,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti var ( assigneeID = ctx.FormInt64("assignee") - posterID int64 + posterID = ctx.FormInt64("poster") mentionedID int64 reviewRequestedID int64 forceEmpty bool @@ -291,6 +291,12 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti return } + ctx.Data["Posters"], err = repo_model.GetIssuePosters(ctx, repo, isPullOption.IsTrue()) + if err != nil { + ctx.ServerError("GetIssuePosters", err) + return + } + handleTeamMentions(ctx) if ctx.Written() { return @@ -364,6 +370,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti ctx.Data["SortType"] = sortType ctx.Data["MilestoneID"] = milestoneID ctx.Data["AssigneeID"] = assigneeID + ctx.Data["PosterID"] = posterID ctx.Data["IsShowClosed"] = isShowClosed ctx.Data["Keyword"] = keyword if isShowClosed { @@ -379,6 +386,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti pager.AddParam(ctx, "labels", "SelectLabels") pager.AddParam(ctx, "milestone", "MilestoneID") pager.AddParam(ctx, "assignee", "AssigneeID") + pager.AddParam(ctx, "poster", "PosterID") ctx.Data["Page"] = pager } diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go index 0e446f2de068..baec48bfea77 100644 --- a/routers/web/repo/lfs.go +++ b/routers/web/repo/lfs.go @@ -309,7 +309,7 @@ func LFSFileGet(ctx *context.Context) { // Building code view blocks with line number on server side. escapedContent := &bytes.Buffer{} - ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, escapedContent) + ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, escapedContent, ctx.Locale) var output bytes.Buffer lines := strings.Split(escapedContent.String(), "\n") diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 2a961c3cbc55..7c140a4e5991 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -510,6 +510,8 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C return nil } ctx.Data["GetCommitMessages"] = pull_service.GetSquashMergeCommitMessages(ctx, pull) + } else { + ctx.Data["GetCommitMessages"] = "" } sha, err := baseGitRepo.GetRefCommitID(pull.GetGitRefName()) diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 6a9c6b9bbace..72ffda7e0147 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -328,35 +328,31 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin if markupType := markup.Type(readmeFile.name); markupType != "" { ctx.Data["IsMarkup"] = true ctx.Data["MarkupType"] = markupType - var result strings.Builder - err := markup.Render(&markup.RenderContext{ + + ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{ Ctx: ctx, RelativePath: path.Join(ctx.Repo.TreePath, readmeFile.name), // ctx.Repo.TreePath is the directory not the Readme so we must append the Readme filename (and path). URLPrefix: readmeTreelink, Metas: ctx.Repo.Repository.ComposeDocumentMetas(), GitRepo: ctx.Repo.GitRepo, - }, rd, &result) + }, rd) if err != nil { - log.Error("Render failed: %v then fallback", err) + log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.name, ctx.Repo.Repository, err) buf := &bytes.Buffer{} - ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf) + ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale) ctx.Data["FileContent"] = strings.ReplaceAll( gotemplate.HTMLEscapeString(buf.String()), "\n", `
`, ) - } else { - ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String()) } } else { ctx.Data["IsRenderedHTML"] = true buf := &bytes.Buffer{} - ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, buf) + ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, &charset.BreakWriter{Writer: buf}, ctx.Locale, charset.RuneNBSP) if err != nil { log.Error("Read failed: %v", err) } - ctx.Data["FileContent"] = strings.ReplaceAll( - gotemplate.HTMLEscapeString(buf.String()), "\n", `
`, - ) + ctx.Data["FileContent"] = buf.String() } } @@ -498,32 +494,30 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st if markupType != "" && !shouldRenderSource { ctx.Data["IsMarkup"] = true ctx.Data["MarkupType"] = markupType - var result strings.Builder if !detected { markupType = "" } metas := ctx.Repo.Repository.ComposeDocumentMetas() metas["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL() - err := markup.Render(&markup.RenderContext{ + ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{ Ctx: ctx, Type: markupType, RelativePath: ctx.Repo.TreePath, URLPrefix: path.Dir(treeLink), Metas: metas, GitRepo: ctx.Repo.GitRepo, - }, rd, &result) + }, rd) if err != nil { ctx.ServerError("Render", err) return } // to prevent iframe load third-party url ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'") - ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String()) } else if readmeExist && !shouldRenderSource { buf := &bytes.Buffer{} ctx.Data["IsRenderedHTML"] = true - ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf) + ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale) ctx.Data["FileContent"] = strings.ReplaceAll( gotemplate.HTMLEscapeString(buf.String()), "\n", `
`, @@ -570,12 +564,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st log.Error("highlight.File failed, fallback to plain text: %v", err) fileContent = highlight.PlainText(buf) } - status, _ := charset.EscapeControlReader(bytes.NewReader(buf), io.Discard) - ctx.Data["EscapeStatus"] = status - statuses := make([]charset.EscapeStatus, len(fileContent)) + status := &charset.EscapeStatus{} + statuses := make([]*charset.EscapeStatus, len(fileContent)) for i, line := range fileContent { - statuses[i], fileContent[i] = charset.EscapeControlString(line) + statuses[i], fileContent[i] = charset.EscapeControlHTML(line, ctx.Locale) + status = status.Or(statuses[i]) } + ctx.Data["EscapeStatus"] = status ctx.Data["FileContent"] = fileContent ctx.Data["LineEscapeStatus"] = statuses } @@ -613,20 +608,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st rd := io.MultiReader(bytes.NewReader(buf), dataRc) ctx.Data["IsMarkup"] = true ctx.Data["MarkupType"] = markupType - var result strings.Builder - err := markup.Render(&markup.RenderContext{ + ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{ Ctx: ctx, RelativePath: ctx.Repo.TreePath, URLPrefix: path.Dir(treeLink), Metas: ctx.Repo.Repository.ComposeDocumentMetas(), GitRepo: ctx.Repo.GitRepo, - }, rd, &result) + }, rd) if err != nil { ctx.ServerError("Render", err) return } - - ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String()) } } @@ -645,6 +637,23 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } +func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input io.Reader) (escaped *charset.EscapeStatus, output string, err error) { + markupRd, markupWr := io.Pipe() + defer markupWr.Close() + done := make(chan struct{}) + go func() { + sb := &strings.Builder{} + // We allow NBSP here this is rendered + escaped, _ = charset.EscapeControlReader(markupRd, sb, ctx.Locale, charset.RuneNBSP) + output = sb.String() + close(done) + }() + err = markup.Render(renderCtx, input, markupWr) + _ = markupWr.CloseWithError(err) + <-done + return escaped, output, err +} + func safeURL(address string) string { u, err := url.Parse(address) if err != nil { diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index a9b14ee21f45..d4419a1e1095 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -185,14 +185,22 @@ func ParseHookEvent(form forms.WebhookForm) *webhook.HookEvent { } } -// GiteaHooksNewPost response for creating Gitea webhook -func GiteaHooksNewPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.NewWebhookForm) +type webhookCreationParams struct { + URL string + ContentType webhook.HookContentType + Secret string + HTTPMethod string + WebhookForm forms.WebhookForm + Type string + Meta interface{} +} + +func createWebhook(ctx *context.Context, params webhookCreationParams) { ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") ctx.Data["PageIsSettingsHooks"] = true ctx.Data["PageIsSettingsHooksNew"] = true ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.GITEA + ctx.Data["HookType"] = params.Type orCtx, err := getOrgRepoCtx(ctx) if err != nil { @@ -206,20 +214,25 @@ func GiteaHooksNewPost(ctx *context.Context) { return } - contentType := webhook.ContentTypeJSON - if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { - contentType = webhook.ContentTypeForm + var meta []byte + if params.Meta != nil { + meta, err = json.Marshal(params.Meta) + if err != nil { + ctx.ServerError("Marshal", err) + return + } } w := &webhook.Webhook{ RepoID: orCtx.RepoID, - URL: form.PayloadURL, - HTTPMethod: form.HTTPMethod, - ContentType: contentType, - Secret: form.Secret, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.GITEA, + URL: params.URL, + HTTPMethod: params.HTTPMethod, + ContentType: params.ContentType, + Secret: params.Secret, + HookEvent: ParseHookEvent(params.WebhookForm), + IsActive: params.WebhookForm.Active, + Type: params.Type, + Meta: string(meta), OrgID: orCtx.OrgID, IsSystemWebhook: orCtx.IsSystemWebhook, } @@ -235,503 +248,175 @@ func GiteaHooksNewPost(ctx *context.Context) { ctx.Redirect(orCtx.Link) } -// GogsHooksNewPost response for creating webhook -func GogsHooksNewPost(ctx *context.Context) { - form := web.GetForm(ctx).(*forms.NewGogshookForm) - newGogsWebhookPost(ctx, *form, webhook.GOGS) -} - -// newGogsWebhookPost response for creating gogs hook -func newGogsWebhookPost(ctx *context.Context, form forms.NewGogshookForm, kind webhook.HookType) { - ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.GOGS +// GiteaHooksNewPost response for creating Gitea webhook +func GiteaHooksNewPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.NewWebhookForm) - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return + contentType := webhook.ContentTypeJSON + if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { + contentType = webhook.ContentTypeForm } - ctx.Data["BaseLink"] = orCtx.LinkNew - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: contentType, + Secret: form.Secret, + HTTPMethod: form.HTTPMethod, + WebhookForm: form.WebhookForm, + Type: webhook.GITEA, + }) +} + +// GogsHooksNewPost response for creating webhook +func GogsHooksNewPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.NewGogshookForm) contentType := webhook.ContentTypeJSON if webhook.HookContentType(form.ContentType) == webhook.ContentTypeForm { contentType = webhook.ContentTypeForm } - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: contentType, - Secret: form.Secret, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: kind, - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: contentType, + Secret: form.Secret, + WebhookForm: form.WebhookForm, + Type: webhook.GOGS, + }) } // DiscordHooksNewPost response for creating discord hook func DiscordHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewDiscordHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.DISCORD - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&webhook_service.DiscordMeta{ - Username: form.Username, - IconURL: form.IconURL, + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.DISCORD, + Meta: &webhook_service.DiscordMeta{ + Username: form.Username, + IconURL: form.IconURL, + }, }) - if err != nil { - ctx.ServerError("Marshal", err) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.DISCORD, - Meta: string(meta), - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) } // DingtalkHooksNewPost response for creating dingtalk hook func DingtalkHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewDingtalkHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.DINGTALK - - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.DINGTALK, - Meta: "", - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.DINGTALK, + }) } // TelegramHooksNewPost response for creating telegram hook func TelegramHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewTelegramHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.TELEGRAM - - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - meta, err := json.Marshal(&webhook_service.TelegramMeta{ - BotToken: form.BotToken, - ChatID: form.ChatID, + createWebhook(ctx, webhookCreationParams{ + URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", url.PathEscape(form.BotToken), url.QueryEscape(form.ChatID)), + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.TELEGRAM, + Meta: &webhook_service.TelegramMeta{ + BotToken: form.BotToken, + ChatID: form.ChatID, + }, }) - if err != nil { - ctx.ServerError("Marshal", err) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage?chat_id=%s", url.PathEscape(form.BotToken), url.QueryEscape(form.ChatID)), - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.TELEGRAM, - Meta: string(meta), - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) } // MatrixHooksNewPost response for creating a Matrix hook func MatrixHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewMatrixHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.MATRIX - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&webhook_service.MatrixMeta{ - HomeserverURL: form.HomeserverURL, - Room: form.RoomID, - AccessToken: form.AccessToken, - MessageType: form.MessageType, + createWebhook(ctx, webhookCreationParams{ + URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, url.PathEscape(form.RoomID)), + ContentType: webhook.ContentTypeJSON, + HTTPMethod: http.MethodPut, + WebhookForm: form.WebhookForm, + Type: webhook.MATRIX, + Meta: &webhook_service.MatrixMeta{ + HomeserverURL: form.HomeserverURL, + Room: form.RoomID, + AccessToken: form.AccessToken, + MessageType: form.MessageType, + }, }) - if err != nil { - ctx.ServerError("Marshal", err) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: fmt.Sprintf("%s/_matrix/client/r0/rooms/%s/send/m.room.message", form.HomeserverURL, url.PathEscape(form.RoomID)), - ContentType: webhook.ContentTypeJSON, - HTTPMethod: "PUT", - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.MATRIX, - Meta: string(meta), - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) } // MSTeamsHooksNewPost response for creating MS Teams hook func MSTeamsHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewMSTeamsHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.MSTEAMS - - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.MSTEAMS, - Meta: "", - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.MSTEAMS, + }) } // SlackHooksNewPost response for creating slack hook func SlackHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewSlackHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.SLACK - - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - if form.HasInvalidChannel() { - ctx.Flash.Error(ctx.Tr("repo.settings.add_webhook.invalid_channel_name")) - ctx.Redirect(orCtx.LinkNew + "/slack/new") - return - } - meta, err := json.Marshal(&webhook_service.SlackMeta{ - Channel: strings.TrimSpace(form.Channel), - Username: form.Username, - IconURL: form.IconURL, - Color: form.Color, + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.SLACK, + Meta: &webhook_service.SlackMeta{ + Channel: strings.TrimSpace(form.Channel), + Username: form.Username, + IconURL: form.IconURL, + Color: form.Color, + }, }) - if err != nil { - ctx.ServerError("Marshal", err) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.SLACK, - Meta: string(meta), - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) } // FeishuHooksNewPost response for creating feishu hook func FeishuHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewFeishuHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.FEISHU - - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.FEISHU, - Meta: "", - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.FEISHU, + }) } // WechatworkHooksNewPost response for creating wechatwork hook func WechatworkHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewWechatWorkHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.WECHATWORK - - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: form.PayloadURL, - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.WECHATWORK, - Meta: "", - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) + createWebhook(ctx, webhookCreationParams{ + URL: form.PayloadURL, + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.WECHATWORK, + }) } // PackagistHooksNewPost response for creating packagist hook func PackagistHooksNewPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.NewPackagistHookForm) - ctx.Data["Title"] = ctx.Tr("repo.settings") - ctx.Data["PageIsSettingsHooks"] = true - ctx.Data["PageIsSettingsHooksNew"] = true - ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook.HookEvent{}} - ctx.Data["HookType"] = webhook.PACKAGIST - orCtx, err := getOrgRepoCtx(ctx) - if err != nil { - ctx.ServerError("getOrgRepoCtx", err) - return - } - - if ctx.HasError() { - ctx.HTML(http.StatusOK, orCtx.NewTemplate) - return - } - - meta, err := json.Marshal(&webhook_service.PackagistMeta{ - Username: form.Username, - APIToken: form.APIToken, - PackageURL: form.PackageURL, + createWebhook(ctx, webhookCreationParams{ + URL: fmt.Sprintf("https://packagist.org/api/update-package?username=%s&apiToken=%s", url.QueryEscape(form.Username), url.QueryEscape(form.APIToken)), + ContentType: webhook.ContentTypeJSON, + WebhookForm: form.WebhookForm, + Type: webhook.PACKAGIST, + Meta: &webhook_service.PackagistMeta{ + Username: form.Username, + APIToken: form.APIToken, + PackageURL: form.PackageURL, + }, }) - if err != nil { - ctx.ServerError("Marshal", err) - return - } - - w := &webhook.Webhook{ - RepoID: orCtx.RepoID, - URL: fmt.Sprintf("https://packagist.org/api/update-package?username=%s&apiToken=%s", url.QueryEscape(form.Username), url.QueryEscape(form.APIToken)), - ContentType: webhook.ContentTypeJSON, - HookEvent: ParseHookEvent(form.WebhookForm), - IsActive: form.Active, - Type: webhook.PACKAGIST, - Meta: string(meta), - OrgID: orCtx.OrgID, - IsSystemWebhook: orCtx.IsSystemWebhook, - } - if err := w.UpdateEvent(); err != nil { - ctx.ServerError("UpdateEvent", err) - return - } else if err := webhook.CreateWebhook(ctx, w); err != nil { - ctx.ServerError("CreateWebhook", err) - return - } - - ctx.Flash.Success(ctx.Tr("repo.settings.add_hook_success")) - ctx.Redirect(orCtx.Link) } func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) { @@ -894,12 +579,6 @@ func SlackHooksEditPost(ctx *context.Context) { return } - if form.HasInvalidChannel() { - ctx.Flash.Error(ctx.Tr("repo.settings.add_webhook.invalid_channel_name")) - ctx.Redirect(fmt.Sprintf("%s/%d", orCtx.Link, w.ID)) - return - } - meta, err := json.Marshal(&webhook_service.SlackMeta{ Channel: strings.TrimSpace(form.Channel), Username: form.Username, diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index e4134028aa9d..4cd5856ea647 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -239,9 +239,28 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { Metas: ctx.Repo.Repository.ComposeDocumentMetas(), IsWiki: true, } - - var buf strings.Builder - if err := markdown.Render(rctx, bytes.NewReader(data), &buf); err != nil { + buf := &strings.Builder{} + + renderFn := func(data []byte) (escaped *charset.EscapeStatus, output string, err error) { + markupRd, markupWr := io.Pipe() + defer markupWr.Close() + done := make(chan struct{}) + go func() { + // We allow NBSP here this is rendered + escaped, _ = charset.EscapeControlReader(markupRd, buf, ctx.Locale, charset.RuneNBSP) + output = buf.String() + buf.Reset() + close(done) + }() + + err = markdown.Render(rctx, bytes.NewReader(data), markupWr) + _ = markupWr.CloseWithError(err) + <-done + return escaped, output, err + } + + ctx.Data["EscapeStatus"], ctx.Data["content"], err = renderFn(data) + if err != nil { if wikiRepo != nil { wikiRepo.Close() } @@ -249,11 +268,10 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { return nil, nil } - ctx.Data["EscapeStatus"], ctx.Data["content"] = charset.EscapeControlString(buf.String()) - if !isSideBar { buf.Reset() - if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil { + ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"], err = renderFn(sidebarContent) + if err != nil { if wikiRepo != nil { wikiRepo.Close() } @@ -261,14 +279,14 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { return nil, nil } ctx.Data["sidebarPresent"] = sidebarContent != nil - ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String()) } else { ctx.Data["sidebarPresent"] = false } if !isFooter { buf.Reset() - if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil { + ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"], err = renderFn(footerContent) + if err != nil { if wikiRepo != nil { wikiRepo.Close() } @@ -276,7 +294,6 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { return nil, nil } ctx.Data["footerPresent"] = footerContent != nil - ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String()) } else { ctx.Data["footerPresent"] = false } @@ -343,12 +360,12 @@ func renderRevisionPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) } // get Commit Count - commitsHistory, err := wikiRepo.CommitsByFileAndRangeNoFollow("master", pageFilename, page) + commitsHistory, err := wikiRepo.CommitsByFileAndRange("master", pageFilename, page) if err != nil { if wikiRepo != nil { wikiRepo.Close() } - ctx.ServerError("CommitsByFileAndRangeNoFollow", err) + ctx.ServerError("CommitsByFileAndRange", err) return nil, nil } ctx.Data["Commits"] = git_model.ConvertFromGitCommit(commitsHistory, ctx.Repo.Repository) diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 648269980472..5e17239e348c 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -607,10 +607,8 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { var shownIssues int if !isShowClosed { shownIssues = int(issueStats.OpenCount) - ctx.Data["TotalIssueCount"] = shownIssues } else { shownIssues = int(issueStats.ClosedCount) - ctx.Data["TotalIssueCount"] = shownIssues } if len(repoIDs) != 0 { shownIssues = 0 @@ -619,6 +617,19 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { } } + var allIssueCount int64 + for _, issueCount := range issueCountByRepo { + allIssueCount += issueCount + } + ctx.Data["TotalIssueCount"] = allIssueCount + + if len(repoIDs) == 1 { + repo := showReposMap[repoIDs[0]] + if repo != nil { + ctx.Data["SingleRepoLink"] = repo.Link() + } + } + ctx.Data["IsShowClosed"] = isShowClosed ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink")) diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 6f23d239e26a..c804be3c5f74 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -105,6 +105,13 @@ func Profile(ctx *context.Context) { ctx.Data["Orgs"] = orgs ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer) + badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser) + if err != nil { + ctx.ServerError("GetUserBadges", err) + return + } + ctx.Data["Badges"] = badges + tab := ctx.FormString("tab") ctx.Data["TabName"] = tab diff --git a/routers/web/web.go b/routers/web/web.go index a9f43fb2c4fe..34d3de6fde0a 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -22,7 +22,6 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/routing" @@ -43,7 +42,6 @@ import ( context_service "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/lfs" - "code.gitea.io/gitea/services/mailer" _ "code.gitea.io/gitea/modules/session" // to registers all internal adapters @@ -152,8 +150,6 @@ func Routes() *web.Route { common = append(common, h) } - mailer.InitMailRender(templates.Mailer()) - if setting.Service.EnableCaptcha { // The captcha http.Handler should only fire on /captcha/* so we can just mount this on that url routes.Route("/captcha/*", "GET,HEAD", append(common, captcha.Captchaer(context.GetImageCaptcha()))...) diff --git a/services/asymkey/ssh_key_test.go b/services/asymkey/ssh_key_test.go index 182371271a4c..9bc23a719c68 100644 --- a/services/asymkey/ssh_key_test.go +++ b/services/asymkey/ssh_key_test.go @@ -18,7 +18,7 @@ import ( func TestAddLdapSSHPublicKeys(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) s := &auth.Source{ID: 1} testCases := []struct { diff --git a/services/attachment/attachment_test.go b/services/attachment/attachment_test.go index 889151d8f350..561792db2f20 100644 --- a/services/attachment/attachment_test.go +++ b/services/attachment/attachment_test.go @@ -26,7 +26,7 @@ func TestMain(m *testing.M) { func TestUploadAttachment(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) fPath := "./attachment_test.go" f, err := os.Open(fPath) diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 05d6af78f174..d9d1b63e8fea 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -105,9 +105,15 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User { } } + var fullname string + if setting.Service.EnableReverseProxyFullName { + fullname = req.Header.Get(setting.ReverseProxyAuthFullName) + } + user := &user_model.User{ - Name: username, - Email: email, + Name: username, + Email: email, + FullName: fullname, } overwriteDefault := user_model.CreateUserOverwriteOptions{ diff --git a/services/auth/source/oauth2/jwtsigningkey.go b/services/auth/source/oauth2/jwtsigningkey.go index 24f2c41119c1..d6b3c05a4fcb 100644 --- a/services/auth/source/oauth2/jwtsigningkey.go +++ b/services/auth/source/oauth2/jwtsigningkey.go @@ -31,11 +31,11 @@ import ( // ErrInvalidAlgorithmType represents an invalid algorithm error. type ErrInvalidAlgorithmType struct { - Algorightm string + Algorithm string } func (err ErrInvalidAlgorithmType) Error() string { - return fmt.Sprintf("JWT signing algorithm is not supported: %s", err.Algorightm) + return fmt.Sprintf("JWT signing algorithm is not supported: %s", err.Algorithm) } // JWTSigningKey represents a algorithm/key pair to sign JWTs diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index afecc205f31e..7a4a2123ebd2 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -17,7 +17,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" - "code.gitea.io/gitea/routers/utils" + "code.gitea.io/gitea/services/webhook" "gitea.com/go-chi/binding" ) @@ -305,14 +305,16 @@ type NewSlackHookForm struct { // Validate validates the fields func (f *NewSlackHookForm) Validate(req *http.Request, errs binding.Errors) binding.Errors { ctx := context.GetContext(req) + if !webhook.IsValidSlackChannel(strings.TrimSpace(f.Channel)) { + errs = append(errs, binding.Error{ + FieldNames: []string{"Channel"}, + Classification: "", + Message: ctx.Tr("repo.settings.add_webhook.invalid_channel_name"), + }) + } return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// HasInvalidChannel validates the channel name is in the right format -func (f NewSlackHookForm) HasInvalidChannel() bool { - return !utils.IsValidSlackChannel(f.Channel) -} - // NewDiscordHookForm form for creating discord hook type NewDiscordHookForm struct { PayloadURL string `binding:"Required;ValidUrl"` diff --git a/services/forms/user_form.go b/services/forms/user_form.go index c8f2b02d8c80..8ce1d85c5778 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -96,6 +96,7 @@ type RegisterForm struct { Retype string GRecaptchaResponse string `form:"g-recaptcha-response"` HcaptchaResponse string `form:"h-captcha-response"` + McaptchaResponse string `form:"m-captcha-response"` } // Validate validates the fields diff --git a/services/forms/user_form_auth_openid.go b/services/forms/user_form_auth_openid.go index fd3368d303a9..992517f34f0f 100644 --- a/services/forms/user_form_auth_openid.go +++ b/services/forms/user_form_auth_openid.go @@ -31,6 +31,7 @@ type SignUpOpenIDForm struct { Email string `binding:"Required;Email;MaxSize(254)"` GRecaptchaResponse string `form:"g-recaptcha-response"` HcaptchaResponse string `form:"h-captcha-response"` + McaptchaResponse string `form:"m-captcha-response"` } // Validate validates the fields diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 6dd237bbc8d4..9844992f5b11 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -32,6 +32,7 @@ import ( "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/translation" "github.com/sergi/go-diff/diffmatchpatch" stdcharset "golang.org/x/net/html/charset" @@ -169,11 +170,11 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int } // escape a line's content or return
needed for copy/paste purposes -func getLineContent(content string) DiffInline { +func getLineContent(content string, locale translation.Locale) DiffInline { if len(content) > 0 { - return DiffInlineWithUnicodeEscape(template.HTML(html.EscapeString(content))) + return DiffInlineWithUnicodeEscape(template.HTML(html.EscapeString(content)), locale) } - return DiffInline{Content: "
"} + return DiffInline{EscapeStatus: &charset.EscapeStatus{}, Content: "
"} } // DiffSection represents a section of a DiffFile. @@ -267,26 +268,26 @@ func init() { // DiffInline is a struct that has a content and escape status type DiffInline struct { - EscapeStatus charset.EscapeStatus + EscapeStatus *charset.EscapeStatus Content template.HTML } // DiffInlineWithUnicodeEscape makes a DiffInline with hidden unicode characters escaped -func DiffInlineWithUnicodeEscape(s template.HTML) DiffInline { - status, content := charset.EscapeControlString(string(s)) +func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) DiffInline { + status, content := charset.EscapeControlHTML(string(s), locale) return DiffInline{EscapeStatus: status, Content: template.HTML(content)} } // DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped -func DiffInlineWithHighlightCode(fileName, language, code string) DiffInline { - status, content := charset.EscapeControlString(highlight.Code(fileName, language, code)) +func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline { + status, content := charset.EscapeControlHTML(highlight.Code(fileName, language, code), locale) return DiffInline{EscapeStatus: status, Content: template.HTML(content)} } // GetComputedInlineDiffFor computes inline diff for the given line. -func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) DiffInline { +func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, locale translation.Locale) DiffInline { if setting.Git.DisableDiffHighlight { - return getLineContent(diffLine.Content[1:]) + return getLineContent(diffLine.Content[1:], locale) } var ( @@ -303,26 +304,26 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif // try to find equivalent diff line. ignore, otherwise switch diffLine.Type { case DiffLineSection: - return getLineContent(diffLine.Content[1:]) + return getLineContent(diffLine.Content[1:], locale) case DiffLineAdd: compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx) if compareDiffLine == nil { - return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:]) + return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale) } diff1 = compareDiffLine.Content diff2 = diffLine.Content case DiffLineDel: compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx) if compareDiffLine == nil { - return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:]) + return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale) } diff1 = diffLine.Content diff2 = compareDiffLine.Content default: if strings.IndexByte(" +-", diffLine.Content[0]) > -1 { - return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:]) + return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale) } - return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content) + return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content, locale) } hcd := newHighlightCodeDiff() @@ -330,7 +331,7 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif // it seems that Gitea doesn't need the line wrapper of Chroma, so do not add them back // if the line wrappers are still needed in the future, it can be added back by "diffToHTML(hcd.lineWrapperTags. ...)" diffHTML := diffToHTML(nil, diffRecord, diffLine.Type) - return DiffInlineWithUnicodeEscape(template.HTML(diffHTML)) + return DiffInlineWithUnicodeEscape(template.HTML(diffHTML), locale) } // DiffFile represents a file diff. diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index e88d831759b7..dfdd4df9c445 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -601,8 +601,8 @@ func setupDefaultDiff() *Diff { func TestDiff_LoadComments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}).(*issues_model.Issue) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) diff := setupDefaultDiff() assert.NoError(t, diff.LoadComments(db.DefaultContext, issue, user)) assert.Len(t, diff.Files[0].Sections[0].Lines[0].Comments, 2) diff --git a/services/issue/commit_test.go b/services/issue/commit_test.go index ce3f91362717..f9ad0302ffd6 100644 --- a/services/issue/commit_test.go +++ b/services/issue/commit_test.go @@ -47,8 +47,8 @@ func TestUpdateIssuesCommit(t *testing.T) { }, } - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo.Owner = user commentBean := &issues_model.Comment{ @@ -77,7 +77,7 @@ func TestUpdateIssuesCommit(t *testing.T) { Message: "close #1", }, } - repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) commentBean = &issues_model.Comment{ Type: issues_model.CommentTypeCommitRef, CommitSHA: "abcdef1", @@ -103,7 +103,7 @@ func TestUpdateIssuesCommit(t *testing.T) { Message: "close " + setting.AppURL + repo.FullName() + "/pulls/1", }, } - repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) commentBean = &issues_model.Comment{ Type: issues_model.CommentTypeCommitRef, CommitSHA: "abcdef3", @@ -133,8 +133,8 @@ func TestUpdateIssuesCommit_Colon(t *testing.T) { }, } - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repo.Owner = user issueBean := &issues_model.Issue{RepoID: repo.ID, Index: 4} @@ -147,7 +147,7 @@ func TestUpdateIssuesCommit_Colon(t *testing.T) { func TestUpdateIssuesCommit_Issue5957(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Test that push to a non-default branch closes an issue. pushCommits := []*repository.PushCommit{ @@ -161,7 +161,7 @@ func TestUpdateIssuesCommit_Issue5957(t *testing.T) { }, } - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) commentBean := &issues_model.Comment{ Type: issues_model.CommentTypeCommitRef, CommitSHA: "abcdef1", @@ -181,7 +181,7 @@ func TestUpdateIssuesCommit_Issue5957(t *testing.T) { func TestUpdateIssuesCommit_AnotherRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Test that a push to default branch closes issue in another repo // If the user also has push permissions to that repo @@ -196,7 +196,7 @@ func TestUpdateIssuesCommit_AnotherRepo(t *testing.T) { }, } - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) commentBean := &issues_model.Comment{ Type: issues_model.CommentTypeCommitRef, CommitSHA: "abcdef1", @@ -216,7 +216,7 @@ func TestUpdateIssuesCommit_AnotherRepo(t *testing.T) { func TestUpdateIssuesCommit_AnotherRepo_FullAddress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Test that a push to default branch closes issue in another repo // If the user also has push permissions to that repo @@ -231,7 +231,7 @@ func TestUpdateIssuesCommit_AnotherRepo_FullAddress(t *testing.T) { }, } - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) commentBean := &issues_model.Comment{ Type: issues_model.CommentTypeCommitRef, CommitSHA: "abcdef1", @@ -251,7 +251,7 @@ func TestUpdateIssuesCommit_AnotherRepo_FullAddress(t *testing.T) { func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 10}) // Test that a push with close reference *can not* close issue // If the committer doesn't have push rights in that repo @@ -274,7 +274,7 @@ func TestUpdateIssuesCommit_AnotherRepoNoPermission(t *testing.T) { }, } - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 6}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 6}) commentBean := &issues_model.Comment{ Type: issues_model.CommentTypeCommitRef, CommitSHA: "abcdef3", diff --git a/services/issue/label_test.go b/services/issue/label_test.go index 120c9ea4f131..482db95139b0 100644 --- a/services/issue/label_test.go +++ b/services/issue/label_test.go @@ -27,12 +27,12 @@ func TestIssue_AddLabels(t *testing.T) { } for _, test := range tests { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}).(*issues_model.Issue) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}) labels := make([]*issues_model.Label, len(test.labelIDs)) for i, labelID := range test.labelIDs { - labels[i] = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}).(*issues_model.Label) + labels[i] = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}) } - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}) assert.NoError(t, AddLabels(issue, doer, labels)) for _, labelID := range test.labelIDs { unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: test.issueID, LabelID: labelID}) @@ -53,9 +53,9 @@ func TestIssue_AddLabel(t *testing.T) { } for _, test := range tests { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}).(*issues_model.Issue) - label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: test.labelID}).(*issues_model.Label) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: test.issueID}) + label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: test.labelID}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}) assert.NoError(t, AddLabel(issue, doer, label)) unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: test.issueID, LabelID: test.labelID}) } diff --git a/services/issue/milestone_test.go b/services/issue/milestone_test.go index d08b1ae8c7fe..087c25670004 100644 --- a/services/issue/milestone_test.go +++ b/services/issue/milestone_test.go @@ -16,8 +16,8 @@ import ( func TestChangeMilestoneAssign(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: 1}).(*issues_model.Issue) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{RepoID: 1}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.NotNil(t, issue) assert.NotNil(t, doer) diff --git a/services/mailer/mail.go b/services/mailer/mail.go index b8d79bd818a0..738a207ce8d0 100644 --- a/services/mailer/mail.go +++ b/services/mailer/mail.go @@ -55,12 +55,6 @@ var ( subjectRemoveSpaces = regexp.MustCompile(`[\s]+`) ) -// InitMailRender initializes the mail renderer -func InitMailRender(subjectTpl *texttmpl.Template, bodyTpl *template.Template) { - subjectTemplates = subjectTpl - bodyTemplates = bodyTpl -} - // SendTestMail sends a test mail func SendTestMail(email string) error { if setting.MailService == nil { diff --git a/services/mailer/mail_test.go b/services/mailer/mail_test.go index 93837ba8c4ca..4302b2c74b6e 100644 --- a/services/mailer/mail_test.go +++ b/services/mailer/mail_test.go @@ -56,20 +56,19 @@ func prepareMailerTest(t *testing.T) (doer *user_model.User, repo *repo_model.Re setting.MailService = &mailService setting.Domain = "localhost" - doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1, Owner: doer}).(*repo_model.Repository) - issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1, Repo: repo, Poster: doer}).(*issues_model.Issue) + doer = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1, Owner: doer}) + issue = unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1, Repo: repo, Poster: doer}) assert.NoError(t, issue.LoadRepo(db.DefaultContext)) - comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2, Issue: issue}).(*issues_model.Comment) + comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 2, Issue: issue}) return doer, repo, issue, comment } func TestComposeIssueCommentMessage(t *testing.T) { doer, _, issue, comment := prepareMailerTest(t) - stpl := texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl)) - btpl := template.Must(template.New("issue/comment").Parse(bodyTpl)) - InitMailRender(stpl, btpl) + subjectTemplates = texttmpl.Must(texttmpl.New("issue/comment").Parse(subjectTpl)) + bodyTemplates = template.Must(template.New("issue/comment").Parse(bodyTpl)) recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}} msgs, err := composeIssueCommentMessages(&mailCommentContext{ @@ -97,9 +96,8 @@ func TestComposeIssueCommentMessage(t *testing.T) { func TestComposeIssueMessage(t *testing.T) { doer, _, issue, _ := prepareMailerTest(t) - stpl := texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl)) - btpl := template.Must(template.New("issue/new").Parse(bodyTpl)) - InitMailRender(stpl, btpl) + subjectTemplates = texttmpl.Must(texttmpl.New("issue/new").Parse(subjectTpl)) + bodyTemplates = template.Must(template.New("issue/new").Parse(bodyTpl)) recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}, {Name: "Test2", Email: "test2@gitea.com"}} msgs, err := composeIssueCommentMessages(&mailCommentContext{ @@ -128,17 +126,15 @@ func TestTemplateSelection(t *testing.T) { doer, repo, issue, comment := prepareMailerTest(t) recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}} - stpl := texttmpl.Must(texttmpl.New("issue/default").Parse("issue/default/subject")) - texttmpl.Must(stpl.New("issue/new").Parse("issue/new/subject")) - texttmpl.Must(stpl.New("pull/comment").Parse("pull/comment/subject")) - texttmpl.Must(stpl.New("issue/close").Parse("")) // Must default to fallback subject + subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse("issue/default/subject")) + texttmpl.Must(subjectTemplates.New("issue/new").Parse("issue/new/subject")) + texttmpl.Must(subjectTemplates.New("pull/comment").Parse("pull/comment/subject")) + texttmpl.Must(subjectTemplates.New("issue/close").Parse("")) // Must default to fallback subject - btpl := template.Must(template.New("issue/default").Parse("issue/default/body")) - template.Must(btpl.New("issue/new").Parse("issue/new/body")) - template.Must(btpl.New("pull/comment").Parse("pull/comment/body")) - template.Must(btpl.New("issue/close").Parse("issue/close/body")) - - InitMailRender(stpl, btpl) + bodyTemplates = template.Must(template.New("issue/default").Parse("issue/default/body")) + template.Must(bodyTemplates.New("issue/new").Parse("issue/new/body")) + template.Must(bodyTemplates.New("pull/comment").Parse("pull/comment/body")) + template.Must(bodyTemplates.New("issue/close").Parse("issue/close/body")) expect := func(t *testing.T, msg *Message, expSubject, expBody string) { subject := msg.ToMessage().GetHeader("Subject") @@ -163,8 +159,8 @@ func TestTemplateSelection(t *testing.T) { }, recipients, false, "TestTemplateSelection") expect(t, msg, "issue/default/subject", "issue/default/body") - pull := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2, Repo: repo, Poster: doer}).(*issues_model.Issue) - comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 4, Issue: pull}).(*issues_model.Comment) + pull := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 2, Repo: repo, Poster: doer}) + comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: 4, Issue: pull}) msg = testComposeIssueCommentMessage(t, &mailCommentContext{ Context: context.TODO(), // TODO: use a correct context Issue: pull, Doer: doer, ActionType: models.ActionCommentPull, @@ -187,9 +183,8 @@ func TestTemplateServices(t *testing.T) { expect := func(t *testing.T, issue *issues_model.Issue, comment *issues_model.Comment, doer *user_model.User, actionType models.ActionType, fromMention bool, tplSubject, tplBody, expSubject, expBody string, ) { - stpl := texttmpl.Must(texttmpl.New("issue/default").Parse(tplSubject)) - btpl := template.Must(template.New("issue/default").Parse(tplBody)) - InitMailRender(stpl, btpl) + subjectTemplates = texttmpl.Must(texttmpl.New("issue/default").Parse(tplSubject)) + bodyTemplates = template.Must(template.New("issue/default").Parse(tplBody)) recipients := []*user_model.User{{Name: "Test", Email: "test@gitea.com"}} msg := testComposeIssueCommentMessage(t, &mailCommentContext{ diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index c86c54c748c5..fdbb6e562bfc 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/queue" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/templates" "github.com/jaytaylor/html2text" "gopkg.in/gomail.v2" @@ -379,6 +380,8 @@ func NewContext() { }, &Message{}) go graceful.GetManager().RunWithShutdownFns(mailQueue.Run) + + subjectTemplates, bodyTemplates = templates.Mailer() } // SendAsync send mail asynchronously diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index 6ea1c20592b2..9fb3d6ffd6fc 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -37,7 +37,7 @@ func TestGiteaUploadRepo(t *testing.T) { unittest.PrepareTestEnv(t) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) var ( ctx = context.Background() @@ -63,7 +63,7 @@ func TestGiteaUploadRepo(t *testing.T) { }, nil) assert.NoError(t, err) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: user.ID, Name: repoName}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerID: user.ID, Name: repoName}) assert.True(t, repo.HasWiki()) assert.EqualValues(t, repo_model.RepositoryReady, repo.Status) @@ -127,8 +127,8 @@ func TestGiteaUploadRepo(t *testing.T) { func TestGiteaUploadRemapLocalUser(t *testing.T) { unittest.PrepareTestEnv(t) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repoName := "migrated" uploader := NewGiteaLocalUploader(context.Background(), doer, doer.Name, repoName) @@ -177,7 +177,7 @@ func TestGiteaUploadRemapLocalUser(t *testing.T) { func TestGiteaUploadRemapExternalUser(t *testing.T) { unittest.PrepareTestEnv(t) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) repoName := "migrated" uploader := NewGiteaLocalUploader(context.Background(), doer, doer.Name, repoName) @@ -205,7 +205,7 @@ func TestGiteaUploadRemapExternalUser(t *testing.T) { // // Link the external ID to an existing user // - linkedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + linkedUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) externalLoginUser := &user_model.ExternalLoginUser{ ExternalID: strconv.FormatInt(externalID, 10), UserID: linkedUser.ID, @@ -232,7 +232,7 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { // // fromRepo master // - fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + fromRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) baseRef := "master" assert.NoError(t, git.InitRepository(git.DefaultContext, fromRepo.RepoPath(), false)) err := git.NewCommand(git.DefaultContext, "symbolic-ref", "HEAD", git.BranchPrefix+baseRef).Run(&git.RunOpts{Dir: fromRepo.RepoPath()}) @@ -273,13 +273,13 @@ func TestGiteaUploadUpdateGitForPullRequest(t *testing.T) { headSHA, err := fromGitRepo.GetBranchCommitID(headRef) assert.NoError(t, err) - fromRepoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: fromRepo.OwnerID}).(*user_model.User) + fromRepoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: fromRepo.OwnerID}) // // forkRepo branch2 // forkHeadRef := "branch2" - forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}).(*repo_model.Repository) + forkRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}) assert.NoError(t, git.CloneWithArgs(git.DefaultContext, fromRepo.RepoPath(), forkRepo.RepoPath(), []string{}, git.CloneRepoOptions{ Branch: headRef, })) diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go index f2542173a0ee..9460c66dbce9 100644 --- a/services/migrations/migrate.go +++ b/services/migrations/migrate.go @@ -479,5 +479,10 @@ func Init() error { } // TODO: at the moment, if ALLOW_LOCALNETWORKS=false, ALLOWED_DOMAINS=domain.com, and domain.com has IP 127.0.0.1, then it's still allowed. // if we want to block such case, the private&loopback should be added to the blockList when ALLOW_LOCALNETWORKS=false + + if setting.Proxy.Enabled && setting.Proxy.ProxyURLFixed != nil { + allowList.AppendPattern(setting.Proxy.ProxyURLFixed.Host) + } + return nil } diff --git a/services/migrations/migrate_test.go b/services/migrations/migrate_test.go index 53cfe6d3ebe8..3fc4034777e4 100644 --- a/services/migrations/migrate_test.go +++ b/services/migrations/migrate_test.go @@ -19,8 +19,8 @@ import ( func TestMigrateWhiteBlocklist(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}).(*user_model.User) - nonAdminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}).(*user_model.User) + adminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user1"}) + nonAdminUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: "user2"}) setting.Migrations.AllowedDomains = "github.com" setting.Migrations.AllowLocalNetworks = false diff --git a/services/org/org_test.go b/services/org/org_test.go index 7f90d85807a7..c4e6088a7132 100644 --- a/services/org/org_test.go +++ b/services/org/org_test.go @@ -24,18 +24,18 @@ func TestMain(m *testing.M) { func TestDeleteOrganization(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 6}).(*organization.Organization) + org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 6}) assert.NoError(t, DeleteOrganization(org)) unittest.AssertNotExistsBean(t, &organization.Organization{ID: 6}) unittest.AssertNotExistsBean(t, &organization.OrgUser{OrgID: 6}) unittest.AssertNotExistsBean(t, &organization.Team{OrgID: 6}) - org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization) + org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) err := DeleteOrganization(org) assert.Error(t, err) assert.True(t, models.IsErrUserOwnRepos(err)) - user := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 5}).(*organization.Organization) + user := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 5}) assert.Error(t, DeleteOrganization(user)) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) } diff --git a/services/packages/packages.go b/services/packages/packages.go index 975c5ddd3589..4bc31a34e805 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -450,7 +450,7 @@ func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_mod // GetFileStreamByPackageVersion returns the content of the specific package file func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadCloser, *packages_model.PackageFile, error) { - pf, err := packages_model.GetFileForVersionByName(db.DefaultContext, pv.ID, pfi.Filename, pfi.CompositeKey) + pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey) if err != nil { return nil, nil, err } diff --git a/services/pull/check_test.go b/services/pull/check_test.go index 21fe675bbcd5..b4de02b5e231 100644 --- a/services/pull/check_test.go +++ b/services/pull/check_test.go @@ -43,11 +43,11 @@ func TestPullRequest_AddToTaskQueue(t *testing.T) { prPatchCheckerQueue = q.(queue.UniqueQueue) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) AddToTaskQueue(pr) assert.Eventually(t, func() bool { - pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) return pr.Status == issues_model.PullRequestStatusChecking }, 1*time.Second, 100*time.Millisecond) @@ -72,7 +72,7 @@ func TestPullRequest_AddToTaskQueue(t *testing.T) { assert.False(t, has) assert.NoError(t, err) - pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pr = unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) assert.Equal(t, issues_model.PullRequestStatusChecking, pr.Status) for _, callback := range queueShutdown { diff --git a/services/pull/pull_test.go b/services/pull/pull_test.go index 9160c434600c..769e3c72e9d2 100644 --- a/services/pull/pull_test.go +++ b/services/pull/pull_test.go @@ -38,7 +38,7 @@ func TestPullRequest_CommitMessageTrailersPattern(t *testing.T) { func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}) assert.NoError(t, pr.LoadBaseRepo()) gitRepo, err := git.OpenRepository(git.DefaultContext, pr.BaseRepo.RepoPath()) @@ -65,10 +65,10 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { ExternalTrackerFormat: "https://someurl.com/{user}/{repo}/{issue}", }, } - baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) baseRepo.Units = []*repo_model.RepoUnit{&externalTracker} - pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2, BaseRepo: baseRepo}).(*issues_model.PullRequest) + pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2, BaseRepo: baseRepo}) assert.NoError(t, pr.LoadBaseRepo()) gitRepo, err := git.OpenRepository(git.DefaultContext, pr.BaseRepo.RepoPath()) diff --git a/services/release/release_test.go b/services/release/release_test.go index 0f5b74f70d57..d1a9298b6995 100644 --- a/services/release/release_test.go +++ b/services/release/release_test.go @@ -30,8 +30,8 @@ func TestMain(m *testing.M) { func TestRelease_Create(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repoPath := repo_model.RepoPath(user.Name, repo.Name) gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath) @@ -134,8 +134,8 @@ func TestRelease_Create(t *testing.T) { func TestRelease_Update(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repoPath := repo_model.RepoPath(user.Name, repo.Name) gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath) @@ -276,8 +276,8 @@ func TestRelease_Update(t *testing.T) { func TestRelease_createTag(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) repoPath := repo_model.RepoPath(user.Name, repo.Name) gitRepo, err := git.OpenRepository(git.DefaultContext, repoPath) @@ -358,8 +358,8 @@ func TestRelease_createTag(t *testing.T) { func TestCreateNewTag(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.NoError(t, CreateNewTag(git.DefaultContext, user, repo, "master", "v2.0", "v2.0 is released \n\n BUGFIX: .... \n\n 123")) diff --git a/services/repository/avatar.go b/services/repository/avatar.go index dcf04c7e547c..b9bd36ab6658 100644 --- a/services/repository/avatar.go +++ b/services/repository/avatar.go @@ -96,7 +96,7 @@ func DeleteAvatar(repo *repo_model.Repository) error { // RemoveRandomAvatars removes the randomly generated avatars that were created for repositories func RemoveRandomAvatars(ctx context.Context) error { - return repo_model.IterateRepository(func(repository *repo_model.Repository) error { + return db.IterateObjects(ctx, func(repository *repo_model.Repository) error { select { case <-ctx.Done(): return db.ErrCancelledf("before random avatars removed for %s", repository.FullName()) diff --git a/services/repository/avatar_test.go b/services/repository/avatar_test.go index efad392a2dbc..e5d9ac9d53e5 100644 --- a/services/repository/avatar_test.go +++ b/services/repository/avatar_test.go @@ -25,7 +25,7 @@ func TestUploadAvatar(t *testing.T) { png.Encode(&buff, myImage) assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) err := UploadAvatar(repo, buff.Bytes()) assert.NoError(t, err) @@ -39,7 +39,7 @@ func TestUploadBigAvatar(t *testing.T) { png.Encode(&buff, myImage) assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) err := UploadAvatar(repo, buff.Bytes()) assert.Error(t, err) @@ -52,7 +52,7 @@ func TestDeleteAvatar(t *testing.T) { png.Encode(&buff, myImage) assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) err := UploadAvatar(repo, buff.Bytes()) assert.NoError(t, err) diff --git a/services/repository/fork_test.go b/services/repository/fork_test.go index 965887b5d14b..376c5c06d944 100644 --- a/services/repository/fork_test.go +++ b/services/repository/fork_test.go @@ -20,8 +20,8 @@ func TestForkRepository(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // user 13 has already forked repo10 - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 13}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 13}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}) fork, err := ForkRepository(git.DefaultContext, user, user, ForkRepoOptions{ BaseRepo: repo, diff --git a/services/repository/review_test.go b/services/repository/review_test.go index 640657d1dd22..badacf39a6f1 100644 --- a/services/repository/review_test.go +++ b/services/repository/review_test.go @@ -16,12 +16,12 @@ import ( func TestRepoGetReviewerTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) teams, err := GetReviewerTeams(repo2) assert.NoError(t, err) assert.Empty(t, teams) - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) teams, err = GetReviewerTeams(repo3) assert.NoError(t, err) assert.Len(t, teams, 2) diff --git a/services/repository/template.go b/services/repository/template.go index d7e8145811fe..b73abdce587f 100644 --- a/services/repository/template.go +++ b/services/repository/template.go @@ -7,12 +7,10 @@ package repository import ( "context" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" repo_module "code.gitea.io/gitea/modules/repository" ) @@ -23,6 +21,11 @@ func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_m if err != nil { return err } + // Prevent insert being called with an empty slice which would result in + // err "no element on slice when insert". + if len(templateLabels) == 0 { + return nil + } newLabels := make([]*issues_model.Label, 0, len(templateLabels)) for _, templateLabel := range templateLabels { @@ -95,11 +98,6 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R return nil }); err != nil { - if generateRepo != nil && generateRepo.ID > 0 { - if errDelete := models.DeleteRepository(doer, owner.ID, generateRepo.ID); errDelete != nil { - log.Error("Rollback deleteRepository: %v", errDelete) - } - } return nil, err } diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go index 8be8c5353ddf..3c929f2f7bed 100644 --- a/services/repository/transfer_test.go +++ b/services/repository/transfer_test.go @@ -35,12 +35,12 @@ func TestTransferOwnership(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) - repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) + repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) assert.NoError(t, TransferOwnership(doer, doer, repo, nil)) - transferredRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + transferredRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.EqualValues(t, 2, transferredRepo.OwnerID) exist, err := util.IsExist(repo_model.RepoPath("user3", "repo3")) @@ -62,10 +62,10 @@ func TestTransferOwnership(t *testing.T) { func TestStartRepositoryTransferSetPermission(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) - recipient := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) - repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) + recipient := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) + repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) hasAccess, err := access_model.HasAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) diff --git a/services/user/user_test.go b/services/user/user_test.go index d8673593df22..c07244e7e1e7 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -28,7 +28,7 @@ func TestMain(m *testing.M) { func TestDeleteUser(t *testing.T) { test := func(userID int64) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) ownedRepos := make([]*repo_model.Repository, 0, 10) assert.NoError(t, db.GetEngine(db.DefaultContext).Find(&ownedRepos, &repo_model.Repository{OwnerID: userID})) @@ -56,14 +56,14 @@ func TestDeleteUser(t *testing.T) { test(8) test(11) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) assert.Error(t, DeleteUser(db.DefaultContext, org, false)) } func TestPurgeUser(t *testing.T) { test := func(userID int64) { assert.NoError(t, unittest.PrepareTestDatabase()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}).(*user_model.User) + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) err := DeleteUser(db.DefaultContext, user, true) assert.NoError(t, err) @@ -76,7 +76,7 @@ func TestPurgeUser(t *testing.T) { test(8) test(11) - org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) assert.Error(t, DeleteUser(db.DefaultContext, org, false)) } diff --git a/services/webhook/slack.go b/services/webhook/slack.go index 11e1d3c081c2..e3d0d406de3f 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -7,6 +7,7 @@ package webhook import ( "errors" "fmt" + "regexp" "strings" webhook_model "code.gitea.io/gitea/models/webhook" @@ -286,3 +287,13 @@ func GetSlackPayload(p api.Payloader, event webhook_model.HookEventType, meta st return convertPayloader(s, p, event) } + +var slackChannel = regexp.MustCompile(`^#?[a-z0-9_-]{1,80}$`) + +// IsValidSlackChannel validates a channel name conforms to what slack expects: +// https://api.slack.com/methods/conversations.rename#naming +// Conversation names can only contain lowercase letters, numbers, hyphens, and underscores, and must be 80 characters or less. +// Gitea accepts if it starts with a #. +func IsValidSlackChannel(name string) bool { + return slackChannel.MatchString(name) +} diff --git a/services/webhook/slack_test.go b/services/webhook/slack_test.go index 8278afb69a8c..0f08785d25e4 100644 --- a/services/webhook/slack_test.go +++ b/services/webhook/slack_test.go @@ -170,3 +170,22 @@ func TestSlackJSONPayload(t *testing.T) { require.NoError(t, err) assert.NotEmpty(t, json) } + +func TestIsValidSlackChannel(t *testing.T) { + tt := []struct { + channelName string + expected bool + }{ + {"gitea", true}, + {"#gitea", true}, + {" ", false}, + {"#", false}, + {" #", false}, + {"gitea ", false}, + {" gitea", false}, + } + + for _, v := range tt { + assert.Equal(t, v.expected, IsValidSlackChannel(v.channelName)) + } +} diff --git a/services/webhook/webhook_test.go b/services/webhook/webhook_test.go index 85fc39770e21..1887cc71fef1 100644 --- a/services/webhook/webhook_test.go +++ b/services/webhook/webhook_test.go @@ -30,7 +30,7 @@ func TestWebhook_GetSlackHook(t *testing.T) { func TestPrepareWebhooks(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) hookTasks := []*webhook_model.HookTask{ {RepoID: repo.ID, HookID: 1, EventType: webhook_model.HookEventPush}, } @@ -46,7 +46,7 @@ func TestPrepareWebhooks(t *testing.T) { func TestPrepareWebhooksBranchFilterMatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) hookTasks := []*webhook_model.HookTask{ {RepoID: repo.ID, HookID: 4, EventType: webhook_model.HookEventPush}, } @@ -63,7 +63,7 @@ func TestPrepareWebhooksBranchFilterMatch(t *testing.T) { func TestPrepareWebhooksBranchFilterNoMatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) hookTasks := []*webhook_model.HookTask{ {RepoID: repo.ID, HookID: 4, EventType: webhook_model.HookEventPush}, } diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go index 0c73074dbe27..1852ddbcb3f2 100644 --- a/services/wiki/wiki_test.go +++ b/services/wiki/wiki_test.go @@ -116,11 +116,11 @@ func TestWikiNameToFilenameToName(t *testing.T) { func TestRepository_InitWiki(t *testing.T) { unittest.PrepareTestEnv(t) // repo1 already has a wiki - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.NoError(t, InitWiki(git.DefaultContext, repo1)) // repo2 does not already have a wiki - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.NoError(t, InitWiki(git.DefaultContext, repo2)) assert.True(t, repo2.HasWiki()) } @@ -129,8 +129,8 @@ func TestRepository_AddWikiPage(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) const wikiContent = "This is the wiki content" const commitMsg = "Commit message" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) for _, wikiName := range []string{ "Another page", "Here's a and a/slash", @@ -174,8 +174,8 @@ func TestRepository_EditWikiPage(t *testing.T) { const newWikiContent = "This is the new content" const commitMsg = "Commit message" - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) for _, newWikiName := range []string{ "Home", // same name as before "New home", @@ -204,8 +204,8 @@ func TestRepository_EditWikiPage(t *testing.T) { func TestRepository_DeleteWikiPage(t *testing.T) { unittest.PrepareTestEnv(t) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) assert.NoError(t, DeleteWikiPage(git.DefaultContext, doer, repo, "Home")) // Now need to show that the page has been added: @@ -221,7 +221,7 @@ func TestRepository_DeleteWikiPage(t *testing.T) { func TestPrepareWikiFileName(t *testing.T) { unittest.PrepareTestEnv(t) - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath()) defer gitRepo.Close() assert.NoError(t, err) diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index a55a797262a0..ccd1029cd80c 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -218,12 +218,7 @@ {{if .MailerEnabled}}
{{.locale.Tr "admin.config.mailer_name"}}
{{.Mailer.Name}}
- {{if eq .Mailer.MailerType "smtp"}} -
{{.locale.Tr "admin.config.mailer_disable_helo"}}
-
{{if .DisableHelo}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
-
{{.locale.Tr "admin.config.mailer_host"}}
-
{{.Mailer.Host}}
- {{else if eq .Mailer.MailerType "sendmail"}} + {{if eq .Mailer.Protocol "sendmail"}}
{{.locale.Tr "admin.config.mailer_use_sendmail"}}
{{svg "octicon-check"}}
{{.locale.Tr "admin.config.mailer_sendmail_path"}}
@@ -232,6 +227,18 @@
{{.Mailer.SendmailArgs}}
{{.locale.Tr "admin.config.mailer_sendmail_timeout"}}
{{.Mailer.SendmailTimeout}} {{.locale.Tr "tool.raw_seconds"}}
+ {{else if eq .Mailer.Protocol "dummy"}} +
{{.locale.Tr "admin.config.mailer_use_dummy"}}
+
{{svg "octicon-check"}}
+ {{else}}{{/* SMTP family */}} +
{{.locale.Tr "admin.config.mailer_protocol"}}
+
{{.Mailer.Protocol}}
+
{{.locale.Tr "admin.config.mailer_enable_helo"}}
+
{{if .Mailer.EnableHelo}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
+
{{.locale.Tr "admin.config.mailer_smtp_addr"}}
+
{{.Mailer.SMTPAddr}}
+
{{.locale.Tr "admin.config.mailer_smtp_port"}}
+
{{.Mailer.SMTPPort}}
{{end}}
{{.locale.Tr "admin.config.mailer_user"}}
{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}

diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 18e8c5fed8da..61721532a441 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -21,6 +21,7 @@ + diff --git a/templates/admin/user/edit.tmpl b/templates/admin/user/edit.tmpl index 17cbef9f108a..dd2646b50a17 100644 --- a/templates/admin/user/edit.tmpl +++ b/templates/admin/user/edit.tmpl @@ -117,7 +117,7 @@
-
+
diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index dfc0646610be..88dec014f615 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -1,7 +1,7 @@
diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 8dc0083b76e3..459beb551512 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -86,10 +86,10 @@ {{.locale.Tr "active_stopwatch"}} - {{end}} - {{if (not .IsDeleted)}} + {{if and (not .IsDeleted) (not $.DisableDownloadSourceArchives)}} diff --git a/templates/repo/issue/openclose.tmpl b/templates/repo/issue/openclose.tmpl index 9242d0c5ca68..ccfb40684c3f 100644 --- a/templates/repo/issue/openclose.tmpl +++ b/templates/repo/issue/openclose.tmpl @@ -1,5 +1,5 @@ diff --git a/templates/repo/issue/view_content/add_reaction.tmpl b/templates/repo/issue/view_content/add_reaction.tmpl index 9f4fb21cefcd..1d0ddb62a9cb 100644 --- a/templates/repo/issue/view_content/add_reaction.tmpl +++ b/templates/repo/issue/view_content/add_reaction.tmpl @@ -7,7 +7,7 @@
{{ .ctx.locale.Tr "repo.pick_reaction"}}
{{range $value := AllowedReactions}} -
{{ReactionToEmoji $value}}
+
{{ReactionToEmoji $value}}
{{end}}
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 59e0962d1795..fd901f013ebd 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -395,7 +395,7 @@ 'allowed': {{$prUnit.PullRequestsConfig.AllowSquash}}, 'textDoMerge': {{$.locale.Tr "repo.pulls.squash_merge_pull_request"}}, 'mergeTitleFieldText': defaultSquashMergeTitle, - 'mergeMessageFieldText': defaultMergeMessage, + 'mergeMessageFieldText': {{.GetCommitMessages}} + defaultMergeMessage, 'hideAutoMerge': generalHideAutoMerge, }, { diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index 0a7e614ca812..2f8a4c6c1e25 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -56,7 +56,7 @@
- {{svg "octicon-key" 32}} + {{svg "octicon-key" 32}}
{{.Name}} diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 98cf4f88c870..f34057d9c05e 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -91,7 +91,7 @@ {{if .Repository.IsMirror}} - {{(MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName).Address}} + {{(MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName false).Address}} {{$.locale.Tr "repo.settings.mirror_settings.direction.pull"}} {{.Mirror.UpdatedUnix.AsTime}} @@ -119,7 +119,7 @@
- {{$address := MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName}} + {{$address := MirrorRemoteAddress $.Context .Repository .Mirror.GetRemoteName false}}
@@ -168,7 +168,7 @@ {{range .PushMirrors}} - {{$address := MirrorRemoteAddress $.Context $.Repository .GetRemoteName}} + {{$address := MirrorRemoteAddress $.Context $.Repository .GetRemoteName true}} {{$address.Address}} {{$.locale.Tr "repo.settings.mirror_settings.direction.push"}} {{if .LastUpdateUnix}}{{.LastUpdateUnix.AsTime}}{{else}}{{$.locale.Tr "never"}}{{end}} {{if .LastError}}
{{$.locale.Tr "error"}}
{{end}} diff --git a/templates/repo/settings/webhook/history.tmpl b/templates/repo/settings/webhook/history.tmpl index d3d84c1439a7..e99ff6a0b9ca 100644 --- a/templates/repo/settings/webhook/history.tmpl +++ b/templates/repo/settings/webhook/history.tmpl @@ -44,7 +44,7 @@ {{end}} diff --git a/templates/repo/sub_menu.tmpl b/templates/repo/sub_menu.tmpl index bd8fcc40ebe8..276bf05a4f79 100644 --- a/templates/repo/sub_menu.tmpl +++ b/templates/repo/sub_menu.tmpl @@ -1,4 +1,4 @@ -
+