diff --git a/.drone.yml b/.drone.yml index 30843517700..1989b6760e8 100644 --- a/.drone.yml +++ b/.drone.yml @@ -44,7 +44,10 @@ steps: image: techknowlogick/xgo:go-1.21.x pull: always commands: - - curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get -qqy install nodejs + - apt-get update && apt-get -qqy install ca-certificates curl gnupg + - mkdir -p /etc/apt/keyrings && curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg + - echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" > /etc/apt/sources.list.d/nodesource.list + - apt-get update && apt-get -qqy install nodejs - export PATH=$PATH:$GOPATH/bin - make release environment: diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 846823abc77..689a4f919ca 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -11,7 +11,6 @@ parserOptions: plugins: - "@eslint-community/eslint-plugin-eslint-comments" - eslint-plugin-array-func - - eslint-plugin-custom-elements - eslint-plugin-import - eslint-plugin-jquery - eslint-plugin-no-jquery @@ -19,6 +18,7 @@ plugins: - eslint-plugin-regexp - eslint-plugin-sonarjs - eslint-plugin-unicorn + - eslint-plugin-vitest-globals - eslint-plugin-wc env: @@ -46,6 +46,12 @@ overrides: - files: ["*.config.*"] rules: import/no-unused-modules: [0] + - files: ["**/*.test.*", "web_src/js/test/setup.js"] + env: + vitest-globals/env: true + - files: ["web_src/js/modules/fetch.js", "web_src/js/standalone/**/*"] + rules: + no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression] rules: "@eslint-community/eslint-comments/disable-enable-pair": [2] @@ -85,19 +91,6 @@ rules: consistent-this: [0] constructor-super: [2] curly: [0] - custom-elements/expose-class-on-global: [0] - custom-elements/extends-correct-class: [2] - custom-elements/file-name-matches-element: [2] - custom-elements/no-constructor: [2] - custom-elements/no-customized-built-in-elements: [2] - custom-elements/no-dom-traversal-in-attributechangedcallback: [2] - custom-elements/no-dom-traversal-in-connectedcallback: [2] - custom-elements/no-exports-with-element: [2] - custom-elements/no-method-prefixed-with-on: [2] - custom-elements/no-unchecked-define: [0] - custom-elements/one-element-per-file: [0] - custom-elements/tag-name-matches-class: [2] - custom-elements/valid-tag-name: [2] default-case-last: [2] default-case: [0] default-param-last: [0] @@ -420,7 +413,7 @@ rules: 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, __dirname, __filename] no-restricted-imports: [0] - no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression] + no-restricted-syntax: [2, WithStatement, ForInStatement, LabeledStatement, SequenceExpression, {selector: "CallExpression[callee.name='fetch']", message: "use modules/fetch.js instead"}] no-return-assign: [0] no-script-url: [2] no-self-assign: [2, {props: true}] @@ -737,14 +730,27 @@ rules: valid-typeof: [2, {requireStringLiterals: true}] vars-on-top: [0] wc/attach-shadow-constructor: [2] + wc/define-tag-after-class-definition: [0] + wc/expose-class-on-global: [0] + wc/file-name-matches-element: [2] + wc/guard-define-call: [0] wc/guard-super-call: [2] + wc/max-elements-per-file: [0] + wc/no-child-traversal-in-attributechangedcallback: [2] + wc/no-child-traversal-in-connectedcallback: [2] wc/no-closed-shadow-root: [2] wc/no-constructor-attributes: [2] wc/no-constructor-params: [2] - wc/no-invalid-element-name: [0] # covered by custom-elements/valid-tag-name + wc/no-constructor: [2] + wc/no-customized-built-in-elements: [2] + wc/no-exports-with-element: [2] + wc/no-invalid-element-name: [2] + wc/no-invalid-extends: [2] + wc/no-method-prefixed-with-on: [2] wc/no-self-class: [2] wc/no-typos: [2] wc/require-listener-teardown: [2] + wc/tag-name-matches-class: [2] wrap-iife: [2, inside] wrap-regex: [0] yield-star-spacing: [2, after] diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml index acdf7cd3646..5de165487c1 100644 --- a/.github/workflows/cron-licenses.yml +++ b/.github/workflows/cron-licenses.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'go-gitea/gitea' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml index 3f147c685d8..b0effdee9d6 100644 --- a/.github/workflows/cron-translations.yml +++ b/.github/workflows/cron-translations.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'go-gitea/gitea' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: download from crowdin uses: docker://jonasfranz/crowdin env: @@ -35,7 +35,7 @@ jobs: runs-on: ubuntu-latest if: github.repository == 'go-gitea/gitea' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: push translations to crowdin uses: docker://jonasfranz/crowdin env: diff --git a/.github/workflows/files-changed.yml b/.github/workflows/files-changed.yml index 48db7a732e6..e7039053af9 100644 --- a/.github/workflows/files-changed.yml +++ b/.github/workflows/files-changed.yml @@ -34,7 +34,7 @@ jobs: swagger: ${{ steps.changes.outputs.swagger }} yaml: ${{ steps.changes.outputs.yaml }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@v2 id: changes with: @@ -64,9 +64,12 @@ jobs: - "**/*.md" - "docs/**" - ".markdownlint.yaml" + - "package.json" + - "package-lock.json" actions: - ".github/workflows/*" + - "Makefile" templates: - "templates/**/*.tmpl" @@ -90,3 +93,5 @@ jobs: - "**/*.yml" - "**/*.yaml" - ".yamllint.yaml" + - "pyproject.toml" + - "poetry.lock" diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index bcbd2188461..d19fa16024d 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -16,7 +16,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -31,7 +31,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.11" @@ -44,7 +44,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-python@v4 with: python-version: "3.11" @@ -57,7 +57,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 20 @@ -69,7 +69,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -86,7 +86,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -101,7 +101,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -114,7 +114,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 20 @@ -129,7 +129,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -161,7 +161,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-node@v3 with: node-version: 20 @@ -174,6 +174,6 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 - run: make lint-actions diff --git a/.github/workflows/pull-db-tests.yml b/.github/workflows/pull-db-tests.yml index bbe589d5c8d..9fcdea44ee1 100644 --- a/.github/workflows/pull-db-tests.yml +++ b/.github/workflows/pull-db-tests.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest services: pgsql: - image: postgres:15 + image: postgres:12 env: POSTGRES_DB: test POSTGRES_PASSWORD: postgres @@ -31,14 +31,14 @@ jobs: minio: # as github actions doesn't support "entrypoint", we need to use a non-official image # that has a custom entrypoint set to "minio server /data" - image: bitnami/minio:2021.3.17 + image: bitnami/minio:2023.8.31 env: - MINIO_ACCESS_KEY: 123456 - MINIO_SECRET_KEY: 12345678 + MINIO_ROOT_USER: 123456 + MINIO_ROOT_PASSWORD: 12345678 ports: - "9000:9000" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -63,7 +63,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -85,13 +85,6 @@ jobs: needs: files-changed runs-on: ubuntu-latest services: - mysql: - image: mysql:5.7 - env: - MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_DATABASE: test - ports: - - "3306:3306" elasticsearch: image: elasticsearch:7.5.0 env: @@ -104,13 +97,6 @@ jobs: MEILI_ENV: development # disable auth ports: - "7700:7700" - smtpimap: - image: tabascoterrier/docker-imap-devel:latest - ports: - - "25:25" - - "143:143" - - "587:587" - - "993:993" redis: image: redis options: >- # wait until redis has started @@ -128,7 +114,7 @@ jobs: ports: - "9000:9000" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -152,16 +138,16 @@ jobs: RACE_ENABLED: true GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }} - test-mysql5: + test-mysql: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest services: mysql: - image: mysql:5.7 + image: mysql:8.0 env: MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_DATABASE: test + MYSQL_DATABASE: testgitea ports: - "3306:3306" elasticsearch: @@ -178,7 +164,7 @@ jobs: - "587:587" - "993:993" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" @@ -197,43 +183,13 @@ jobs: USE_REPO_TEST_DIR: 1 TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200" - test-mysql8: - if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' - needs: files-changed - runs-on: ubuntu-latest - services: - mysql8: - image: mysql:8 - env: - MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_DATABASE: testgitea - ports: - - "3306:3306" - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-go@v4 - with: - go-version: "~1.21" - check-latest: true - - name: Add hosts to /etc/hosts - run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 mysql8" | sudo tee -a /etc/hosts' - - run: make deps-backend - - run: make backend - env: - TAGS: bindata - - run: make test-mysql8-migration test-mysql8 - timeout-minutes: 50 - env: - TAGS: bindata - USE_REPO_TEST_DIR: 1 - test-mssql: if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true' needs: files-changed runs-on: ubuntu-latest services: mssql: - image: mcr.microsoft.com/mssql/server:latest + image: mcr.microsoft.com/mssql/server:2017-latest env: ACCEPT_EULA: Y MSSQL_PID: Standard @@ -241,7 +197,7 @@ jobs: ports: - "1433:1433" steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" diff --git a/.github/workflows/pull-e2e-tests.yml b/.github/workflows/pull-e2e-tests.yml index 7b950bfd380..3fca2bee80b 100644 --- a/.github/workflows/pull-e2e-tests.yml +++ b/.github/workflows/pull-e2e-tests.yml @@ -16,7 +16,7 @@ jobs: needs: files-changed runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: actions/setup-go@v4 with: go-version: "~1.21" diff --git a/.github/workflows/release-nightly.yml b/.github/workflows/release-nightly.yml index 0671ecee8bc..ef3db2db73e 100644 --- a/.github/workflows/release-nightly.yml +++ b/.github/workflows/release-nightly.yml @@ -12,7 +12,7 @@ jobs: nightly-binary: runs-on: actuated-4cpu-16gb steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force @@ -58,7 +58,7 @@ jobs: nightly-docker-rootful: runs-on: actuated-4cpu-16gb steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force @@ -95,7 +95,7 @@ jobs: nightly-docker-rootless: runs-on: actuated-4cpu-16gb steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 # fetch all commits instead of only the last as some branches are long lived and could have many between versions # fetch all tags to ensure that "git describe" reports expected Gitea version, eg. v1.21.0-dev-1-g1234567 - run: git fetch --unshallow --quiet --tags --force diff --git a/.yamllint.yaml b/.yamllint.yaml index c0fce7c301f..7f0517fb7eb 100644 --- a/.yamllint.yaml +++ b/.yamllint.yaml @@ -44,5 +44,3 @@ rules: ignore: | .venv node_modules - /models/fixtures - /models/migrations/fixtures diff --git a/CHANGELOG.md b/CHANGELOG.md index 8ef677b88ca..ea0f80c0c91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,33 @@ 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.com). +## [1.20.5](https://github.com/go-gitea/gitea/releases/tag/v1.20.5) - 2023-10-03 + +* ENHANCEMENTS + * Fix z-index on markdown completion (#27237) (#27242 & #27238) + * Use secure cookie for HTTPS sites (#26999) (#27013) +* BUGFIXES + * Fix git 2.11 error when checking IsEmpty (#27393) (#27396) + * Allow get release download files and lfs files with oauth2 token format (#26430) (#27378) + * Fix orphan check for deleted branch (#27310) (#27320) + * Quote table `release` in sql queries (#27205) (#27219) + * Fix release URL in webhooks (#27182) (#27184) + * Fix successful return value for `SyncAndGetUserSpecificDiff` (#27152) (#27156) + * fix pagination for followers and following (#27127) (#27138) + * Fix issue templates when blank isses are disabled (#27061) (#27082) + * Fix context cache bug & enable context cache for dashabord commits' authors(#26991) (#27017) + * Fix INI parsing for value with trailing slash (#26995) (#27001) + * Fix PushEvent NullPointerException jenkinsci/github-plugin (#27203) (#27249) + * Fix organization field being null in POST /orgs/{orgid}/teams (#27150) (#27167 & #27162) + * Fix bug of review request number (#27406) (#27104) +* TESTING + * services/wiki: Close() after error handling (#27129) (#27137) +* DOCS + * Improve actions docs related to `pull_request` event (#27126) (#27145) +* MISC + * Add logs for data broken of comment review (#27326) (#27344) + * Load reviewer before sending notification (#27063) (#27064) + ## [1.20.4](https://github.com/go-gitea/gitea/releases/tag/v1.20.4) - 2023-09-08 * SECURITY diff --git a/Makefile b/Makefile index fd852cbaf93..cbf3aff8eb1 100644 --- a/Makefile +++ b/Makefile @@ -167,10 +167,6 @@ TEST_MYSQL_HOST ?= mysql:3306 TEST_MYSQL_DBNAME ?= testgitea TEST_MYSQL_USERNAME ?= root TEST_MYSQL_PASSWORD ?= -TEST_MYSQL8_HOST ?= mysql8:3306 -TEST_MYSQL8_DBNAME ?= testgitea -TEST_MYSQL8_USERNAME ?= root -TEST_MYSQL8_PASSWORD ?= TEST_PGSQL_HOST ?= pgsql:5432 TEST_PGSQL_DBNAME ?= testgitea TEST_PGSQL_USERNAME ?= postgres @@ -226,6 +222,7 @@ help: @echo " - test-frontend test frontend files" @echo " - test-backend test backend files" @echo " - test-e2e[\#TestSpecificName] test end to end using playwright" + @echo " - update update js and py dependencies" @echo " - update-js update js dependencies" @echo " - update-py update py dependencies" @echo " - webpack build webpack files" @@ -281,12 +278,12 @@ clean: rm -rf $(EXECUTABLE) $(DIST) $(BINDATA_DEST) $(BINDATA_HASH) \ integrations*.test \ e2e*.test \ - tests/integration/gitea-integration-pgsql/ tests/integration/gitea-integration-mysql/ tests/integration/gitea-integration-mysql8/ tests/integration/gitea-integration-sqlite/ \ - tests/integration/gitea-integration-mssql/ tests/integration/indexers-mysql/ tests/integration/indexers-mysql8/ tests/integration/indexers-pgsql tests/integration/indexers-sqlite \ - tests/integration/indexers-mssql tests/mysql.ini tests/mysql8.ini tests/pgsql.ini tests/mssql.ini man/ \ - tests/e2e/gitea-e2e-pgsql/ tests/e2e/gitea-e2e-mysql/ tests/e2e/gitea-e2e-mysql8/ tests/e2e/gitea-e2e-sqlite/ \ - tests/e2e/gitea-e2e-mssql/ tests/e2e/indexers-mysql/ tests/e2e/indexers-mysql8/ tests/e2e/indexers-pgsql/ tests/e2e/indexers-sqlite/ \ - tests/e2e/indexers-mssql/ tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ + tests/integration/gitea-integration-* \ + tests/integration/indexers-* \ + tests/mysql.ini tests/pgsql.ini tests/mssql.ini man/ \ + tests/e2e/gitea-e2e-*/ \ + tests/e2e/indexers-*/ \ + tests/e2e/reports/ tests/e2e/test-artifacts/ tests/e2e/test-snapshots/ .PHONY: fmt fmt: @@ -550,27 +547,6 @@ test-mysql\#%: integrations.mysql.test generate-ini-mysql .PHONY: test-mysql-migration test-mysql-migration: migrations.mysql.test migrations.individual.mysql.test -generate-ini-mysql8: - sed -e 's|{{TEST_MYSQL8_HOST}}|${TEST_MYSQL8_HOST}|g' \ - -e 's|{{TEST_MYSQL8_DBNAME}}|${TEST_MYSQL8_DBNAME}|g' \ - -e 's|{{TEST_MYSQL8_USERNAME}}|${TEST_MYSQL8_USERNAME}|g' \ - -e 's|{{TEST_MYSQL8_PASSWORD}}|${TEST_MYSQL8_PASSWORD}|g' \ - -e 's|{{REPO_TEST_DIR}}|${REPO_TEST_DIR}|g' \ - -e 's|{{TEST_LOGGER}}|$(or $(TEST_LOGGER),test$(COMMA)file)|g' \ - -e 's|{{TEST_TYPE}}|$(or $(TEST_TYPE),integration)|g' \ - tests/mysql8.ini.tmpl > tests/mysql8.ini - -.PHONY: test-mysql8 -test-mysql8: integrations.mysql8.test generate-ini-mysql8 - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./integrations.mysql8.test - -.PHONY: test-mysql8\#% -test-mysql8\#%: integrations.mysql8.test generate-ini-mysql8 - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./integrations.mysql8.test -test.run $(subst .,/,$*) - -.PHONY: test-mysql8-migration -test-mysql8-migration: migrations.mysql8.test migrations.individual.mysql8.test - generate-ini-pgsql: sed -e 's|{{TEST_PGSQL_HOST}}|${TEST_PGSQL_HOST}|g' \ -e 's|{{TEST_PGSQL_DBNAME}}|${TEST_PGSQL_DBNAME}|g' \ @@ -643,14 +619,6 @@ test-e2e-mysql: playwright e2e.mysql.test generate-ini-mysql test-e2e-mysql\#%: playwright e2e.mysql.test generate-ini-mysql GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./e2e.mysql.test -test.run TestE2e/$* -.PHONY: test-e2e-mysql8 -test-e2e-mysql8: playwright e2e.mysql8.test generate-ini-mysql8 - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./e2e.mysql8.test - -.PHONY: test-e2e-mysql8\#% -test-e2e-mysql8\#%: playwright e2e.mysql8.test generate-ini-mysql8 - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./e2e.mysql8.test -test.run TestE2e/$* - .PHONY: test-e2e-pgsql test-e2e-pgsql: playwright e2e.pgsql.test generate-ini-pgsql GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/pgsql.ini ./e2e.pgsql.test @@ -694,9 +662,6 @@ integration-test-coverage-sqlite: integrations.cover.sqlite.test generate-ini-sq integrations.mysql.test: git-check $(GO_SOURCES) $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql.test -integrations.mysql8.test: git-check $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.mysql8.test - integrations.pgsql.test: git-check $(GO_SOURCES) $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration -o integrations.pgsql.test @@ -717,11 +682,6 @@ migrations.mysql.test: $(GO_SOURCES) generate-ini-mysql $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql.test GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini ./migrations.mysql.test -.PHONY: migrations.mysql8.test -migrations.mysql8.test: $(GO_SOURCES) generate-ini-mysql8 - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.mysql8.test - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini ./migrations.mysql8.test - .PHONY: migrations.pgsql.test migrations.pgsql.test: $(GO_SOURCES) generate-ini-pgsql $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/integration/migration-test -o migrations.pgsql.test @@ -743,13 +703,7 @@ migrations.individual.mysql.test: $(GO_SOURCES) GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \ done -.PHONY: migrations.individual.mysql8.test -migrations.individual.mysql8.test: $(GO_SOURCES) - for pkg in $(shell $(GO) list code.gitea.io/gitea/models/migrations/...); do \ - GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/mysql8.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' $$pkg; \ - done - -.PHONY: migrations.individual.mysql8.test\#% +.PHONY: migrations.individual.sqlite.test\#% migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite GITEA_ROOT="$(CURDIR)" GITEA_CONF=tests/sqlite.ini $(GO) test $(GOTESTFLAGS) -tags '$(TEST_TAGS)' code.gitea.io/gitea/models/migrations/$* @@ -787,9 +741,6 @@ migrations.individual.sqlite.test\#%: $(GO_SOURCES) generate-ini-sqlite e2e.mysql.test: $(GO_SOURCES) $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql.test -e2e.mysql8.test: $(GO_SOURCES) - $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.mysql8.test - e2e.pgsql.test: $(GO_SOURCES) $(GO) test $(GOTESTFLAGS) -c code.gitea.io/gitea/tests/e2e -o e2e.pgsql.test @@ -924,6 +875,9 @@ node_modules: package-lock.json poetry install @touch .venv +.PHONY: update +update: update-js update-py + .PHONY: update-js update-js: node-check | node_modules npx updates -u -f package.json diff --git a/cmd/admin.go b/cmd/admin.go index a4f48b05130..49d0e4ef74a 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -6,26 +6,13 @@ package cmd import ( "context" - "errors" "fmt" - "net/url" - "os" - "strings" - "text/tabwriter" - asymkey_model "code.gitea.io/gitea/models/asymkey" - auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/git" - "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" - "code.gitea.io/gitea/modules/util" - auth_service "code.gitea.io/gitea/services/auth" - "code.gitea.io/gitea/services/auth/source/oauth2" - "code.gitea.io/gitea/services/auth/source/smtp" - repo_service "code.gitea.io/gitea/services/repository" "github.com/urfave/cli/v2" ) @@ -59,28 +46,16 @@ var ( }, } - microcmdRegenHooks = &cli.Command{ - Name: "hooks", - Usage: "Regenerate git-hooks", - Action: runRegenerateHooks, - } - - microcmdRegenKeys = &cli.Command{ - Name: "keys", - Usage: "Regenerate authorized_keys file", - Action: runRegenerateKeys, - } - subcmdAuth = &cli.Command{ Name: "auth", Usage: "Modify external auth providers", Subcommands: []*cli.Command{ microcmdAuthAddOauth, microcmdAuthUpdateOauth, - cmdAuthAddLdapBindDn, - cmdAuthUpdateLdapBindDn, - cmdAuthAddLdapSimpleAuth, - cmdAuthUpdateLdapSimpleAuth, + microcmdAuthAddLdapBindDn, + microcmdAuthUpdateLdapBindDn, + microcmdAuthAddLdapSimpleAuth, + microcmdAuthUpdateLdapSimpleAuth, microcmdAuthAddSMTP, microcmdAuthUpdateSMTP, microcmdAuthList, @@ -88,170 +63,6 @@ var ( }, } - microcmdAuthList = &cli.Command{ - Name: "list", - Usage: "List auth sources", - Action: runListAuth, - Flags: []cli.Flag{ - &cli.IntFlag{ - Name: "min-width", - Usage: "Minimal cell width including any padding for the formatted table", - Value: 0, - }, - &cli.IntFlag{ - Name: "tab-width", - Usage: "width of tab characters in formatted table (equivalent number of spaces)", - Value: 8, - }, - &cli.IntFlag{ - Name: "padding", - Usage: "padding added to a cell before computing its width", - Value: 1, - }, - &cli.StringFlag{ - Name: "pad-char", - Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`, - Value: "\t", - }, - &cli.BoolFlag{ - Name: "vertical-bars", - Usage: "Set to true to print vertical bars between columns", - }, - }, - } - - idFlag = &cli.Int64Flag{ - Name: "id", - Usage: "ID of authentication source", - } - - microcmdAuthDelete = &cli.Command{ - Name: "delete", - Usage: "Delete specific auth source", - Flags: []cli.Flag{idFlag}, - Action: runDeleteAuth, - } - - oauthCLIFlags = []cli.Flag{ - &cli.StringFlag{ - Name: "name", - Value: "", - Usage: "Application Name", - }, - &cli.StringFlag{ - Name: "provider", - Value: "", - Usage: "OAuth2 Provider", - }, - &cli.StringFlag{ - Name: "key", - Value: "", - Usage: "Client ID (Key)", - }, - &cli.StringFlag{ - Name: "secret", - Value: "", - Usage: "Client Secret", - }, - &cli.StringFlag{ - Name: "auto-discover-url", - Value: "", - Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)", - }, - &cli.StringFlag{ - Name: "use-custom-urls", - Value: "false", - Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints", - }, - &cli.StringFlag{ - Name: "custom-tenant-id", - Value: "", - Usage: "Use custom Tenant ID for OAuth endpoints", - }, - &cli.StringFlag{ - Name: "custom-auth-url", - Value: "", - Usage: "Use a custom Authorization URL (option for GitLab/GitHub)", - }, - &cli.StringFlag{ - Name: "custom-token-url", - Value: "", - Usage: "Use a custom Token URL (option for GitLab/GitHub)", - }, - &cli.StringFlag{ - Name: "custom-profile-url", - Value: "", - Usage: "Use a custom Profile URL (option for GitLab/GitHub)", - }, - &cli.StringFlag{ - Name: "custom-email-url", - Value: "", - Usage: "Use a custom Email URL (option for GitHub)", - }, - &cli.StringFlag{ - Name: "icon-url", - Value: "", - Usage: "Custom icon URL for OAuth2 login source", - }, - &cli.BoolFlag{ - Name: "skip-local-2fa", - Usage: "Set to true to skip local 2fa for users authenticated by this source", - }, - &cli.StringSliceFlag{ - Name: "scopes", - Value: nil, - Usage: "Scopes to request when to authenticate against this OAuth2 source", - }, - &cli.StringFlag{ - Name: "required-claim-name", - Value: "", - Usage: "Claim name that has to be set to allow users to login with this source", - }, - &cli.StringFlag{ - Name: "required-claim-value", - Value: "", - Usage: "Claim value that has to be set to allow users to login with this source", - }, - &cli.StringFlag{ - Name: "group-claim-name", - Value: "", - Usage: "Claim name providing group names for this source", - }, - &cli.StringFlag{ - Name: "admin-group", - Value: "", - Usage: "Group Claim value for administrator users", - }, - &cli.StringFlag{ - Name: "restricted-group", - Value: "", - Usage: "Group Claim value for restricted users", - }, - &cli.StringFlag{ - Name: "group-team-map", - Value: "", - Usage: "JSON mapping between groups and org teams", - }, - &cli.BoolFlag{ - Name: "group-team-map-removal", - Usage: "Activate automatic team membership removal depending on groups", - }, - } - - microcmdAuthUpdateOauth = &cli.Command{ - Name: "update-oauth", - Usage: "Update existing Oauth authentication source", - Action: runUpdateOauth, - Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...), - } - - microcmdAuthAddOauth = &cli.Command{ - Name: "add-oauth", - Usage: "Add new Oauth authentication source", - Action: runAddOauth, - Flags: oauthCLIFlags, - } - subcmdSendMail = &cli.Command{ Name: "sendmail", Usage: "Send a message to all users", @@ -275,75 +86,9 @@ var ( }, } - smtpCLIFlags = []cli.Flag{ - &cli.StringFlag{ - Name: "name", - Value: "", - Usage: "Application Name", - }, - &cli.StringFlag{ - Name: "auth-type", - Value: "PLAIN", - Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", - }, - &cli.StringFlag{ - Name: "host", - Value: "", - Usage: "SMTP Host", - }, - &cli.IntFlag{ - Name: "port", - Usage: "SMTP Port", - }, - &cli.BoolFlag{ - Name: "force-smtps", - Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", - Value: true, - }, - &cli.BoolFlag{ - Name: "skip-verify", - Usage: "Skip TLS verify.", - Value: true, - }, - &cli.StringFlag{ - Name: "helo-hostname", - Value: "", - Usage: "Hostname sent with HELO. Leave blank to send current hostname", - }, - &cli.BoolFlag{ - Name: "disable-helo", - Usage: "Disable SMTP helo.", - Value: true, - }, - &cli.StringFlag{ - Name: "allowed-domains", - Value: "", - Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')", - }, - &cli.BoolFlag{ - Name: "skip-local-2fa", - Usage: "Skip 2FA to log on.", - Value: true, - }, - &cli.BoolFlag{ - Name: "active", - Usage: "This Authentication Source is Activated.", - Value: true, - }, - } - - microcmdAuthAddSMTP = &cli.Command{ - Name: "add-smtp", - Usage: "Add new SMTP authentication source", - Action: runAddSMTP, - Flags: smtpCLIFlags, - } - - microcmdAuthUpdateSMTP = &cli.Command{ - Name: "update-smtp", - Usage: "Update existing SMTP authentication source", - Action: runUpdateSMTP, - Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...), + idFlag = &cli.Int64Flag{ + Name: "id", + Usage: "ID of authentication source", } ) @@ -389,7 +134,7 @@ func runRepoSyncReleases(_ *cli.Context) error { } log.Trace(" currentNumReleases is %d, running SyncReleasesWithTags", oldnum) - if err = repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil { + if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { log.Warn(" SyncReleasesWithTags: %v", err) gitRepo.Close() continue @@ -420,351 +165,3 @@ func getReleaseCount(ctx context.Context, id int64) (int64, error) { }, ) } - -func runRegenerateHooks(_ *cli.Context) error { - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) -} - -func runRegenerateKeys(_ *cli.Context) error { - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - return asymkey_model.RewriteAllPublicKeys() -} - -func parseOAuth2Config(c *cli.Context) *oauth2.Source { - var customURLMapping *oauth2.CustomURLMapping - if c.IsSet("use-custom-urls") { - customURLMapping = &oauth2.CustomURLMapping{ - TokenURL: c.String("custom-token-url"), - AuthURL: c.String("custom-auth-url"), - ProfileURL: c.String("custom-profile-url"), - EmailURL: c.String("custom-email-url"), - Tenant: c.String("custom-tenant-id"), - } - } else { - customURLMapping = nil - } - return &oauth2.Source{ - Provider: c.String("provider"), - ClientID: c.String("key"), - ClientSecret: c.String("secret"), - OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"), - CustomURLMapping: customURLMapping, - IconURL: c.String("icon-url"), - SkipLocalTwoFA: c.Bool("skip-local-2fa"), - Scopes: c.StringSlice("scopes"), - RequiredClaimName: c.String("required-claim-name"), - RequiredClaimValue: c.String("required-claim-value"), - GroupClaimName: c.String("group-claim-name"), - AdminGroup: c.String("admin-group"), - RestrictedGroup: c.String("restricted-group"), - GroupTeamMap: c.String("group-team-map"), - GroupTeamMapRemoval: c.Bool("group-team-map-removal"), - } -} - -func runAddOauth(c *cli.Context) error { - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - config := parseOAuth2Config(c) - if config.Provider == "openidConnect" { - discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL) - if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") { - return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL) - } - } - - return auth_model.CreateSource(&auth_model.Source{ - Type: auth_model.OAuth2, - Name: c.String("name"), - IsActive: true, - Cfg: config, - }) -} - -func runUpdateOauth(c *cli.Context) error { - if !c.IsSet("id") { - return fmt.Errorf("--id flag is missing") - } - - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - source, err := auth_model.GetSourceByID(c.Int64("id")) - if err != nil { - return err - } - - oAuth2Config := source.Cfg.(*oauth2.Source) - - if c.IsSet("name") { - source.Name = c.String("name") - } - - if c.IsSet("provider") { - oAuth2Config.Provider = c.String("provider") - } - - if c.IsSet("key") { - oAuth2Config.ClientID = c.String("key") - } - - if c.IsSet("secret") { - oAuth2Config.ClientSecret = c.String("secret") - } - - if c.IsSet("auto-discover-url") { - oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url") - } - - if c.IsSet("icon-url") { - oAuth2Config.IconURL = c.String("icon-url") - } - - if c.IsSet("scopes") { - oAuth2Config.Scopes = c.StringSlice("scopes") - } - - if c.IsSet("required-claim-name") { - oAuth2Config.RequiredClaimName = c.String("required-claim-name") - } - if c.IsSet("required-claim-value") { - oAuth2Config.RequiredClaimValue = c.String("required-claim-value") - } - - if c.IsSet("group-claim-name") { - oAuth2Config.GroupClaimName = c.String("group-claim-name") - } - if c.IsSet("admin-group") { - oAuth2Config.AdminGroup = c.String("admin-group") - } - if c.IsSet("restricted-group") { - oAuth2Config.RestrictedGroup = c.String("restricted-group") - } - if c.IsSet("group-team-map") { - oAuth2Config.GroupTeamMap = c.String("group-team-map") - } - if c.IsSet("group-team-map-removal") { - oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal") - } - - // update custom URL mapping - customURLMapping := &oauth2.CustomURLMapping{} - - if oAuth2Config.CustomURLMapping != nil { - customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL - customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL - customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL - customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL - customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant - } - if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") { - customURLMapping.TokenURL = c.String("custom-token-url") - } - - if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") { - customURLMapping.AuthURL = c.String("custom-auth-url") - } - - if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") { - customURLMapping.ProfileURL = c.String("custom-profile-url") - } - - if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") { - customURLMapping.EmailURL = c.String("custom-email-url") - } - - if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") { - customURLMapping.Tenant = c.String("custom-tenant-id") - } - - oAuth2Config.CustomURLMapping = customURLMapping - source.Cfg = oAuth2Config - - return auth_model.UpdateSource(source) -} - -func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { - if c.IsSet("auth-type") { - conf.Auth = c.String("auth-type") - validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"} - if !util.SliceContainsString(validAuthTypes, strings.ToUpper(c.String("auth-type"))) { - return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5") - } - conf.Auth = c.String("auth-type") - } - if c.IsSet("host") { - conf.Host = c.String("host") - } - if c.IsSet("port") { - conf.Port = c.Int("port") - } - if c.IsSet("allowed-domains") { - conf.AllowedDomains = c.String("allowed-domains") - } - if c.IsSet("force-smtps") { - conf.ForceSMTPS = c.Bool("force-smtps") - } - if c.IsSet("skip-verify") { - conf.SkipVerify = c.Bool("skip-verify") - } - if c.IsSet("helo-hostname") { - conf.HeloHostname = c.String("helo-hostname") - } - if c.IsSet("disable-helo") { - conf.DisableHelo = c.Bool("disable-helo") - } - if c.IsSet("skip-local-2fa") { - conf.SkipLocalTwoFA = c.Bool("skip-local-2fa") - } - return nil -} - -func runAddSMTP(c *cli.Context) error { - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - if !c.IsSet("name") || len(c.String("name")) == 0 { - return errors.New("name must be set") - } - if !c.IsSet("host") || len(c.String("host")) == 0 { - return errors.New("host must be set") - } - if !c.IsSet("port") { - return errors.New("port must be set") - } - active := true - if c.IsSet("active") { - active = c.Bool("active") - } - - var smtpConfig smtp.Source - if err := parseSMTPConfig(c, &smtpConfig); err != nil { - return err - } - - // If not set default to PLAIN - if len(smtpConfig.Auth) == 0 { - smtpConfig.Auth = "PLAIN" - } - - return auth_model.CreateSource(&auth_model.Source{ - Type: auth_model.SMTP, - Name: c.String("name"), - IsActive: active, - Cfg: &smtpConfig, - }) -} - -func runUpdateSMTP(c *cli.Context) error { - if !c.IsSet("id") { - return fmt.Errorf("--id flag is missing") - } - - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - source, err := auth_model.GetSourceByID(c.Int64("id")) - if err != nil { - return err - } - - smtpConfig := source.Cfg.(*smtp.Source) - - if err := parseSMTPConfig(c, smtpConfig); err != nil { - return err - } - - if c.IsSet("name") { - source.Name = c.String("name") - } - - if c.IsSet("active") { - source.IsActive = c.Bool("active") - } - - source.Cfg = smtpConfig - - return auth_model.UpdateSource(source) -} - -func runListAuth(c *cli.Context) error { - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - authSources, err := auth_model.Sources() - if err != nil { - return err - } - - flags := tabwriter.AlignRight - if c.Bool("vertical-bars") { - flags |= tabwriter.Debug - } - - padChar := byte('\t') - if len(c.String("pad-char")) > 0 { - padChar = c.String("pad-char")[0] - } - - // loop through each source and print - w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags) - fmt.Fprintf(w, "ID\tName\tType\tEnabled\n") - for _, source := range authSources { - fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive) - } - w.Flush() - - return nil -} - -func runDeleteAuth(c *cli.Context) error { - if !c.IsSet("id") { - return fmt.Errorf("--id flag is missing") - } - - ctx, cancel := installSignals() - defer cancel() - - if err := initDB(ctx); err != nil { - return err - } - - source, err := auth_model.GetSourceByID(c.Int64("id")) - if err != nil { - return err - } - - return auth_service.DeleteSource(source) -} diff --git a/cmd/admin_auth.go b/cmd/admin_auth.go new file mode 100644 index 00000000000..ef826a48939 --- /dev/null +++ b/cmd/admin_auth.go @@ -0,0 +1,109 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "fmt" + "os" + "text/tabwriter" + + auth_model "code.gitea.io/gitea/models/auth" + auth_service "code.gitea.io/gitea/services/auth" + + "github.com/urfave/cli/v2" +) + +var ( + microcmdAuthDelete = &cli.Command{ + Name: "delete", + Usage: "Delete specific auth source", + Flags: []cli.Flag{idFlag}, + Action: runDeleteAuth, + } + microcmdAuthList = &cli.Command{ + Name: "list", + Usage: "List auth sources", + Action: runListAuth, + Flags: []cli.Flag{ + &cli.IntFlag{ + Name: "min-width", + Usage: "Minimal cell width including any padding for the formatted table", + Value: 0, + }, + &cli.IntFlag{ + Name: "tab-width", + Usage: "width of tab characters in formatted table (equivalent number of spaces)", + Value: 8, + }, + &cli.IntFlag{ + Name: "padding", + Usage: "padding added to a cell before computing its width", + Value: 1, + }, + &cli.StringFlag{ + Name: "pad-char", + Usage: `ASCII char used for padding if padchar == '\\t', the Writer will assume that the width of a '\\t' in the formatted output is tabwidth, and cells are left-aligned independent of align_left (for correct-looking results, tabwidth must correspond to the tab width in the viewer displaying the result)`, + Value: "\t", + }, + &cli.BoolFlag{ + Name: "vertical-bars", + Usage: "Set to true to print vertical bars between columns", + }, + }, + } +) + +func runListAuth(c *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + authSources, err := auth_model.Sources() + if err != nil { + return err + } + + flags := tabwriter.AlignRight + if c.Bool("vertical-bars") { + flags |= tabwriter.Debug + } + + padChar := byte('\t') + if len(c.String("pad-char")) > 0 { + padChar = c.String("pad-char")[0] + } + + // loop through each source and print + w := tabwriter.NewWriter(os.Stdout, c.Int("min-width"), c.Int("tab-width"), c.Int("padding"), padChar, flags) + fmt.Fprintf(w, "ID\tName\tType\tEnabled\n") + for _, source := range authSources { + fmt.Fprintf(w, "%d\t%s\t%s\t%t\n", source.ID, source.Name, source.Type.String(), source.IsActive) + } + w.Flush() + + return nil +} + +func runDeleteAuth(c *cli.Context) error { + if !c.IsSet("id") { + return fmt.Errorf("--id flag is missing") + } + + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + source, err := auth_model.GetSourceByID(c.Int64("id")) + if err != nil { + return err + } + + return auth_service.DeleteSource(source) +} diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index cfa1a232353..111bc7955cc 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -132,10 +132,10 @@ var ( ldapSimpleAuthCLIFlags = append(commonLdapCLIFlags, &cli.StringFlag{ Name: "user-dn", - Usage: "The user’s DN.", + Usage: "The user's DN.", }) - cmdAuthAddLdapBindDn = &cli.Command{ + microcmdAuthAddLdapBindDn = &cli.Command{ Name: "add-ldap", Usage: "Add new LDAP (via Bind DN) authentication source", Action: func(c *cli.Context) error { @@ -144,7 +144,7 @@ var ( Flags: ldapBindDnCLIFlags, } - cmdAuthUpdateLdapBindDn = &cli.Command{ + microcmdAuthUpdateLdapBindDn = &cli.Command{ Name: "update-ldap", Usage: "Update existing LDAP (via Bind DN) authentication source", Action: func(c *cli.Context) error { @@ -153,7 +153,7 @@ var ( Flags: append([]cli.Flag{idFlag}, ldapBindDnCLIFlags...), } - cmdAuthAddLdapSimpleAuth = &cli.Command{ + microcmdAuthAddLdapSimpleAuth = &cli.Command{ Name: "add-ldap-simple", Usage: "Add new LDAP (simple auth) authentication source", Action: func(c *cli.Context) error { @@ -162,7 +162,7 @@ var ( Flags: ldapSimpleAuthCLIFlags, } - cmdAuthUpdateLdapSimpleAuth = &cli.Command{ + microcmdAuthUpdateLdapSimpleAuth = &cli.Command{ Name: "update-ldap-simple", Usage: "Update existing LDAP (simple auth) authentication source", Action: func(c *cli.Context) error { diff --git a/cmd/admin_auth_ldap_test.go b/cmd/admin_auth_ldap_test.go index 210a6463c31..228c9dd3ed2 100644 --- a/cmd/admin_auth_ldap_test.go +++ b/cmd/admin_auth_ldap_test.go @@ -226,7 +226,7 @@ func TestAddLdapBindDn(t *testing.T) { // Create a copy of command to test app := cli.NewApp() - app.Flags = cmdAuthAddLdapBindDn.Flags + app.Flags = microcmdAuthAddLdapBindDn.Flags app.Action = service.addLdapBindDn // Run it @@ -457,7 +457,7 @@ func TestAddLdapSimpleAuth(t *testing.T) { // Create a copy of command to test app := cli.NewApp() - app.Flags = cmdAuthAddLdapSimpleAuth.Flags + app.Flags = microcmdAuthAddLdapSimpleAuth.Flags app.Action = service.addLdapSimpleAuth // Run it @@ -920,7 +920,7 @@ func TestUpdateLdapBindDn(t *testing.T) { // Create a copy of command to test app := cli.NewApp() - app.Flags = cmdAuthUpdateLdapBindDn.Flags + app.Flags = microcmdAuthUpdateLdapBindDn.Flags app.Action = service.updateLdapBindDn // Run it @@ -1310,7 +1310,7 @@ func TestUpdateLdapSimpleAuth(t *testing.T) { // Create a copy of command to test app := cli.NewApp() - app.Flags = cmdAuthUpdateLdapSimpleAuth.Flags + app.Flags = microcmdAuthUpdateLdapSimpleAuth.Flags app.Action = service.updateLdapSimpleAuth // Run it diff --git a/cmd/admin_auth_oauth.go b/cmd/admin_auth_oauth.go new file mode 100644 index 00000000000..cc54ac9454b --- /dev/null +++ b/cmd/admin_auth_oauth.go @@ -0,0 +1,298 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "fmt" + "net/url" + + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/services/auth/source/oauth2" + + "github.com/urfave/cli/v2" +) + +var ( + oauthCLIFlags = []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Value: "", + Usage: "Application Name", + }, + &cli.StringFlag{ + Name: "provider", + Value: "", + Usage: "OAuth2 Provider", + }, + &cli.StringFlag{ + Name: "key", + Value: "", + Usage: "Client ID (Key)", + }, + &cli.StringFlag{ + Name: "secret", + Value: "", + Usage: "Client Secret", + }, + &cli.StringFlag{ + Name: "auto-discover-url", + Value: "", + Usage: "OpenID Connect Auto Discovery URL (only required when using OpenID Connect as provider)", + }, + &cli.StringFlag{ + Name: "use-custom-urls", + Value: "false", + Usage: "Use custom URLs for GitLab/GitHub OAuth endpoints", + }, + &cli.StringFlag{ + Name: "custom-tenant-id", + Value: "", + Usage: "Use custom Tenant ID for OAuth endpoints", + }, + &cli.StringFlag{ + Name: "custom-auth-url", + Value: "", + Usage: "Use a custom Authorization URL (option for GitLab/GitHub)", + }, + &cli.StringFlag{ + Name: "custom-token-url", + Value: "", + Usage: "Use a custom Token URL (option for GitLab/GitHub)", + }, + &cli.StringFlag{ + Name: "custom-profile-url", + Value: "", + Usage: "Use a custom Profile URL (option for GitLab/GitHub)", + }, + &cli.StringFlag{ + Name: "custom-email-url", + Value: "", + Usage: "Use a custom Email URL (option for GitHub)", + }, + &cli.StringFlag{ + Name: "icon-url", + Value: "", + Usage: "Custom icon URL for OAuth2 login source", + }, + &cli.BoolFlag{ + Name: "skip-local-2fa", + Usage: "Set to true to skip local 2fa for users authenticated by this source", + }, + &cli.StringSliceFlag{ + Name: "scopes", + Value: nil, + Usage: "Scopes to request when to authenticate against this OAuth2 source", + }, + &cli.StringFlag{ + Name: "required-claim-name", + Value: "", + Usage: "Claim name that has to be set to allow users to login with this source", + }, + &cli.StringFlag{ + Name: "required-claim-value", + Value: "", + Usage: "Claim value that has to be set to allow users to login with this source", + }, + &cli.StringFlag{ + Name: "group-claim-name", + Value: "", + Usage: "Claim name providing group names for this source", + }, + &cli.StringFlag{ + Name: "admin-group", + Value: "", + Usage: "Group Claim value for administrator users", + }, + &cli.StringFlag{ + Name: "restricted-group", + Value: "", + Usage: "Group Claim value for restricted users", + }, + &cli.StringFlag{ + Name: "group-team-map", + Value: "", + Usage: "JSON mapping between groups and org teams", + }, + &cli.BoolFlag{ + Name: "group-team-map-removal", + Usage: "Activate automatic team membership removal depending on groups", + }, + } + + microcmdAuthAddOauth = &cli.Command{ + Name: "add-oauth", + Usage: "Add new Oauth authentication source", + Action: runAddOauth, + Flags: oauthCLIFlags, + } + + microcmdAuthUpdateOauth = &cli.Command{ + Name: "update-oauth", + Usage: "Update existing Oauth authentication source", + Action: runUpdateOauth, + Flags: append(oauthCLIFlags[:1], append([]cli.Flag{idFlag}, oauthCLIFlags[1:]...)...), + } +) + +func parseOAuth2Config(c *cli.Context) *oauth2.Source { + var customURLMapping *oauth2.CustomURLMapping + if c.IsSet("use-custom-urls") { + customURLMapping = &oauth2.CustomURLMapping{ + TokenURL: c.String("custom-token-url"), + AuthURL: c.String("custom-auth-url"), + ProfileURL: c.String("custom-profile-url"), + EmailURL: c.String("custom-email-url"), + Tenant: c.String("custom-tenant-id"), + } + } else { + customURLMapping = nil + } + return &oauth2.Source{ + Provider: c.String("provider"), + ClientID: c.String("key"), + ClientSecret: c.String("secret"), + OpenIDConnectAutoDiscoveryURL: c.String("auto-discover-url"), + CustomURLMapping: customURLMapping, + IconURL: c.String("icon-url"), + SkipLocalTwoFA: c.Bool("skip-local-2fa"), + Scopes: c.StringSlice("scopes"), + RequiredClaimName: c.String("required-claim-name"), + RequiredClaimValue: c.String("required-claim-value"), + GroupClaimName: c.String("group-claim-name"), + AdminGroup: c.String("admin-group"), + RestrictedGroup: c.String("restricted-group"), + GroupTeamMap: c.String("group-team-map"), + GroupTeamMapRemoval: c.Bool("group-team-map-removal"), + } +} + +func runAddOauth(c *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + config := parseOAuth2Config(c) + if config.Provider == "openidConnect" { + discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL) + if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") { + return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL) + } + } + + return auth_model.CreateSource(&auth_model.Source{ + Type: auth_model.OAuth2, + Name: c.String("name"), + IsActive: true, + Cfg: config, + }) +} + +func runUpdateOauth(c *cli.Context) error { + if !c.IsSet("id") { + return fmt.Errorf("--id flag is missing") + } + + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + source, err := auth_model.GetSourceByID(c.Int64("id")) + if err != nil { + return err + } + + oAuth2Config := source.Cfg.(*oauth2.Source) + + if c.IsSet("name") { + source.Name = c.String("name") + } + + if c.IsSet("provider") { + oAuth2Config.Provider = c.String("provider") + } + + if c.IsSet("key") { + oAuth2Config.ClientID = c.String("key") + } + + if c.IsSet("secret") { + oAuth2Config.ClientSecret = c.String("secret") + } + + if c.IsSet("auto-discover-url") { + oAuth2Config.OpenIDConnectAutoDiscoveryURL = c.String("auto-discover-url") + } + + if c.IsSet("icon-url") { + oAuth2Config.IconURL = c.String("icon-url") + } + + if c.IsSet("scopes") { + oAuth2Config.Scopes = c.StringSlice("scopes") + } + + if c.IsSet("required-claim-name") { + oAuth2Config.RequiredClaimName = c.String("required-claim-name") + } + if c.IsSet("required-claim-value") { + oAuth2Config.RequiredClaimValue = c.String("required-claim-value") + } + + if c.IsSet("group-claim-name") { + oAuth2Config.GroupClaimName = c.String("group-claim-name") + } + if c.IsSet("admin-group") { + oAuth2Config.AdminGroup = c.String("admin-group") + } + if c.IsSet("restricted-group") { + oAuth2Config.RestrictedGroup = c.String("restricted-group") + } + if c.IsSet("group-team-map") { + oAuth2Config.GroupTeamMap = c.String("group-team-map") + } + if c.IsSet("group-team-map-removal") { + oAuth2Config.GroupTeamMapRemoval = c.Bool("group-team-map-removal") + } + + // update custom URL mapping + customURLMapping := &oauth2.CustomURLMapping{} + + if oAuth2Config.CustomURLMapping != nil { + customURLMapping.TokenURL = oAuth2Config.CustomURLMapping.TokenURL + customURLMapping.AuthURL = oAuth2Config.CustomURLMapping.AuthURL + customURLMapping.ProfileURL = oAuth2Config.CustomURLMapping.ProfileURL + customURLMapping.EmailURL = oAuth2Config.CustomURLMapping.EmailURL + customURLMapping.Tenant = oAuth2Config.CustomURLMapping.Tenant + } + if c.IsSet("use-custom-urls") && c.IsSet("custom-token-url") { + customURLMapping.TokenURL = c.String("custom-token-url") + } + + if c.IsSet("use-custom-urls") && c.IsSet("custom-auth-url") { + customURLMapping.AuthURL = c.String("custom-auth-url") + } + + if c.IsSet("use-custom-urls") && c.IsSet("custom-profile-url") { + customURLMapping.ProfileURL = c.String("custom-profile-url") + } + + if c.IsSet("use-custom-urls") && c.IsSet("custom-email-url") { + customURLMapping.EmailURL = c.String("custom-email-url") + } + + if c.IsSet("use-custom-urls") && c.IsSet("custom-tenant-id") { + customURLMapping.Tenant = c.String("custom-tenant-id") + } + + oAuth2Config.CustomURLMapping = customURLMapping + source.Cfg = oAuth2Config + + return auth_model.UpdateSource(source) +} diff --git a/cmd/admin_auth_stmp.go b/cmd/admin_auth_stmp.go new file mode 100644 index 00000000000..8c65de8a1b6 --- /dev/null +++ b/cmd/admin_auth_stmp.go @@ -0,0 +1,201 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + "errors" + "fmt" + "strings" + + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/auth/source/smtp" + + "github.com/urfave/cli/v2" +) + +var ( + smtpCLIFlags = []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Value: "", + Usage: "Application Name", + }, + &cli.StringFlag{ + Name: "auth-type", + Value: "PLAIN", + Usage: "SMTP Authentication Type (PLAIN/LOGIN/CRAM-MD5) default PLAIN", + }, + &cli.StringFlag{ + Name: "host", + Value: "", + Usage: "SMTP Host", + }, + &cli.IntFlag{ + Name: "port", + Usage: "SMTP Port", + }, + &cli.BoolFlag{ + Name: "force-smtps", + Usage: "SMTPS is always used on port 465. Set this to force SMTPS on other ports.", + Value: true, + }, + &cli.BoolFlag{ + Name: "skip-verify", + Usage: "Skip TLS verify.", + Value: true, + }, + &cli.StringFlag{ + Name: "helo-hostname", + Value: "", + Usage: "Hostname sent with HELO. Leave blank to send current hostname", + }, + &cli.BoolFlag{ + Name: "disable-helo", + Usage: "Disable SMTP helo.", + Value: true, + }, + &cli.StringFlag{ + Name: "allowed-domains", + Value: "", + Usage: "Leave empty to allow all domains. Separate multiple domains with a comma (',')", + }, + &cli.BoolFlag{ + Name: "skip-local-2fa", + Usage: "Skip 2FA to log on.", + Value: true, + }, + &cli.BoolFlag{ + Name: "active", + Usage: "This Authentication Source is Activated.", + Value: true, + }, + } + + microcmdAuthAddSMTP = &cli.Command{ + Name: "add-smtp", + Usage: "Add new SMTP authentication source", + Action: runAddSMTP, + Flags: smtpCLIFlags, + } + + microcmdAuthUpdateSMTP = &cli.Command{ + Name: "update-smtp", + Usage: "Update existing SMTP authentication source", + Action: runUpdateSMTP, + Flags: append(smtpCLIFlags[:1], append([]cli.Flag{idFlag}, smtpCLIFlags[1:]...)...), + } +) + +func parseSMTPConfig(c *cli.Context, conf *smtp.Source) error { + if c.IsSet("auth-type") { + conf.Auth = c.String("auth-type") + validAuthTypes := []string{"PLAIN", "LOGIN", "CRAM-MD5"} + if !util.SliceContainsString(validAuthTypes, strings.ToUpper(c.String("auth-type"))) { + return errors.New("Auth must be one of PLAIN/LOGIN/CRAM-MD5") + } + conf.Auth = c.String("auth-type") + } + if c.IsSet("host") { + conf.Host = c.String("host") + } + if c.IsSet("port") { + conf.Port = c.Int("port") + } + if c.IsSet("allowed-domains") { + conf.AllowedDomains = c.String("allowed-domains") + } + if c.IsSet("force-smtps") { + conf.ForceSMTPS = c.Bool("force-smtps") + } + if c.IsSet("skip-verify") { + conf.SkipVerify = c.Bool("skip-verify") + } + if c.IsSet("helo-hostname") { + conf.HeloHostname = c.String("helo-hostname") + } + if c.IsSet("disable-helo") { + conf.DisableHelo = c.Bool("disable-helo") + } + if c.IsSet("skip-local-2fa") { + conf.SkipLocalTwoFA = c.Bool("skip-local-2fa") + } + return nil +} + +func runAddSMTP(c *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + if !c.IsSet("name") || len(c.String("name")) == 0 { + return errors.New("name must be set") + } + if !c.IsSet("host") || len(c.String("host")) == 0 { + return errors.New("host must be set") + } + if !c.IsSet("port") { + return errors.New("port must be set") + } + active := true + if c.IsSet("active") { + active = c.Bool("active") + } + + var smtpConfig smtp.Source + if err := parseSMTPConfig(c, &smtpConfig); err != nil { + return err + } + + // If not set default to PLAIN + if len(smtpConfig.Auth) == 0 { + smtpConfig.Auth = "PLAIN" + } + + return auth_model.CreateSource(&auth_model.Source{ + Type: auth_model.SMTP, + Name: c.String("name"), + IsActive: active, + Cfg: &smtpConfig, + }) +} + +func runUpdateSMTP(c *cli.Context) error { + if !c.IsSet("id") { + return fmt.Errorf("--id flag is missing") + } + + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + + source, err := auth_model.GetSourceByID(c.Int64("id")) + if err != nil { + return err + } + + smtpConfig := source.Cfg.(*smtp.Source) + + if err := parseSMTPConfig(c, smtpConfig); err != nil { + return err + } + + if c.IsSet("name") { + source.Name = c.String("name") + } + + if c.IsSet("active") { + source.IsActive = c.Bool("active") + } + + source.Cfg = smtpConfig + + return auth_model.UpdateSource(source) +} diff --git a/cmd/admin_regenerate.go b/cmd/admin_regenerate.go new file mode 100644 index 00000000000..0db505ff9c7 --- /dev/null +++ b/cmd/admin_regenerate.go @@ -0,0 +1,46 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package cmd + +import ( + asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/modules/graceful" + repo_service "code.gitea.io/gitea/services/repository" + + "github.com/urfave/cli/v2" +) + +var ( + microcmdRegenHooks = &cli.Command{ + Name: "hooks", + Usage: "Regenerate git-hooks", + Action: runRegenerateHooks, + } + + microcmdRegenKeys = &cli.Command{ + Name: "keys", + Usage: "Regenerate authorized_keys file", + Action: runRegenerateKeys, + } +) + +func runRegenerateHooks(_ *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + return repo_service.SyncRepositoryHooks(graceful.GetManager().ShutdownContext()) +} + +func runRegenerateKeys(_ *cli.Context) error { + ctx, cancel := installSignals() + defer cancel() + + if err := initDB(ctx); err != nil { + return err + } + return asymkey_model.RewriteAllPublicKeys(ctx) +} diff --git a/cmd/admin_user_create.go b/cmd/admin_user_create.go index 52ce46c353b..fefe18d39c5 100644 --- a/cmd/admin_user_create.go +++ b/cmd/admin_user_create.go @@ -115,7 +115,7 @@ func runCreateUser(c *cli.Context) error { // If this is the first user being created. // Take it as the admin and don't force a password update. - if n := user_model.CountUsers(nil); n == 0 { + if n := user_model.CountUsers(ctx, nil); n == 0 { changePassword = false } @@ -146,7 +146,7 @@ func runCreateUser(c *cli.Context) error { IsRestricted: restricted, } - if err := user_model.CreateUser(u, overwriteDefault); err != nil { + if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil { return fmt.Errorf("CreateUser: %w", err) } @@ -156,7 +156,7 @@ func runCreateUser(c *cli.Context) error { UID: u.ID, } - if err := auth_model.NewAccessToken(t); err != nil { + if err := auth_model.NewAccessToken(ctx, t); err != nil { return err } diff --git a/cmd/admin_user_generate_access_token.go b/cmd/admin_user_generate_access_token.go index 0febb916613..6e78939680a 100644 --- a/cmd/admin_user_generate_access_token.go +++ b/cmd/admin_user_generate_access_token.go @@ -63,7 +63,7 @@ func runGenerateAccessToken(c *cli.Context) error { UID: user.ID, } - exist, err := auth_model.AccessTokenByNameExists(t) + exist, err := auth_model.AccessTokenByNameExists(ctx, t) if err != nil { return err } @@ -79,7 +79,7 @@ func runGenerateAccessToken(c *cli.Context) error { t.Scope = accessTokenScope // create the token - if err := auth_model.NewAccessToken(t); err != nil { + if err := auth_model.NewAccessToken(ctx, t); err != nil { return err } diff --git a/cmd/admin_user_list.go b/cmd/admin_user_list.go index 9db9b5e56f7..4c2b26d1dfd 100644 --- a/cmd/admin_user_list.go +++ b/cmd/admin_user_list.go @@ -33,7 +33,7 @@ func runListUsers(c *cli.Context) error { return err } - users, err := user_model.GetAllUsers() + users, err := user_model.GetAllUsers(ctx) if err != nil { return err } @@ -48,7 +48,7 @@ func runListUsers(c *cli.Context) error { } } } else { - twofa := user_model.UserList(users).GetTwoFaStatus() + twofa := user_model.UserList(users).GetTwoFaStatus(ctx) fmt.Fprintf(w, "ID\tUsername\tEmail\tIsActive\tIsAdmin\t2FA\n") for _, u := range users { fmt.Fprintf(w, "%d\t%s\t%s\t%t\t%t\t%t\n", u.ID, u.Name, u.Email, u.IsActive, u.IsAdmin, twofa[u.ID]) diff --git a/cmd/main_test.go b/cmd/main_test.go index 0e32dce5648..a916c61f853 100644 --- a/cmd/main_test.go +++ b/cmd/main_test.go @@ -20,9 +20,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: "..", - }) + unittest.MainTest(m) } func makePathOutput(workPath, customPath, customConf string) string { diff --git a/cmd/migrate_storage_test.go b/cmd/migrate_storage_test.go index 644e0dc18bc..5d8c8679930 100644 --- a/cmd/migrate_storage_test.go +++ b/cmd/migrate_storage_test.go @@ -9,6 +9,7 @@ import ( "strings" "testing" + "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" @@ -30,7 +31,7 @@ func TestMigratePackages(t *testing.T) { assert.NoError(t, err) defer buf.Close() - v, f, err := packages_service.CreatePackageAndAddFile(&packages_service.PackageCreationInfo{ + v, f, err := packages_service.CreatePackageAndAddFile(db.DefaultContext, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: creator, PackageType: packages.TypeGeneric, diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index a39cd46a390..423d7e83627 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2571,12 +2571,18 @@ LEVEL = Info ; [actions] ;; Enable/Disable actions capabilities -;ENABLED = false +;ENABLED = true ;; ;; Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance. ;DEFAULT_ACTIONS_URL = github ;; Default artifact retention time in days, default is 90 days ;ARTIFACT_RETENTION_DAYS = 90 +;; Timeout to stop the task which have running status, but haven't been updated for a long time +;ZOMBIE_TASK_TIMEOUT = 10m +;; Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time +;ENDLESS_TASK_TIMEOUT = 3h +;; Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time +;ABANDONED_JOB_TIMEOUT = 24h ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/administration/config-cheat-sheet.en-us.md b/docs/content/administration/config-cheat-sheet.en-us.md index d4638d49a4a..188625c074b 100644 --- a/docs/content/administration/config-cheat-sheet.en-us.md +++ b/docs/content/administration/config-cheat-sheet.en-us.md @@ -1387,11 +1387,14 @@ PROXY_HOSTS = *.github.com ## Actions (`actions`) -- `ENABLED`: **false**: Enable/Disable actions capabilities +- `ENABLED`: **true**: Enable/Disable actions capabilities - `DEFAULT_ACTIONS_URL`: **github**: Default platform to get action plugins, `github` for `https://github.com`, `self` for the current Gitea instance. - `STORAGE_TYPE`: **local**: Storage type for actions logs, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]` - `MINIO_BASE_PATH`: **actions_log/**: Minio base path on the bucket only available when STORAGE_TYPE is `minio` - `ARTIFACT_RETENTION_DAYS`: **90**: Number of days to keep artifacts. Set to 0 to disable artifact retention. Default is 90 days if not set. +- `ZOMBIE_TASK_TIMEOUT`: **10m**: Timeout to stop the task which have running status, but haven't been updated for a long time +- `ENDLESS_TASK_TIMEOUT`: **3h**: Timeout to stop the tasks which have running status and continuous updates, but don't end for a long time +- `ABANDONED_JOB_TIMEOUT`: **24h**: Timeout to cancel the jobs which have waiting status, but haven't been picked by a runner for a long time `DEFAULT_ACTIONS_URL` indicates where the Gitea Actions runners should find the actions with relative path. For example, `uses: actions/checkout@v3` means `https://github.com/actions/checkout@v3` since the value of `DEFAULT_ACTIONS_URL` is `github`. diff --git a/docs/content/administration/config-cheat-sheet.zh-cn.md b/docs/content/administration/config-cheat-sheet.zh-cn.md index b3e7d1024a1..2849752c0ab 100644 --- a/docs/content/administration/config-cheat-sheet.zh-cn.md +++ b/docs/content/administration/config-cheat-sheet.zh-cn.md @@ -1331,7 +1331,7 @@ PROXY_HOSTS = *.github.com ## Actions (`actions`) -- `ENABLED`: **false**:启用/禁用操作功能 +- `ENABLED`: **true**:启用/禁用操作功能 - `DEFAULT_ACTIONS_URL`: **github**:获取操作插件的默认平台,`github`表示`https://github.com`,`self`表示当前的 Gitea 实例。 - `STORAGE_TYPE`: **local**:用于操作日志的存储类型,`local`表示本地磁盘,`minio`表示与S3兼容的对象存储服务,默认为`local`,或者使用定义为`[storage.xxx]`的其他名称。 - `MINIO_BASE_PATH`: **actions_log/**:Minio存储桶上的基本路径,仅在`STORAGE_TYPE`为`minio`时可用。 diff --git a/docs/content/contributing/guidelines-frontend.en-us.md b/docs/content/contributing/guidelines-frontend.en-us.md index 921c2b02336..0d9e510e700 100644 --- a/docs/content/contributing/guidelines-frontend.en-us.md +++ b/docs/content/contributing/guidelines-frontend.en-us.md @@ -95,7 +95,7 @@ Some lint rules and IDEs also have warnings if the returned Promise is not handl ### Fetching data To fetch data, use the wrapper functions `GET`, `POST` etc. from `modules/fetch.js`. They -accept a `data` option for the content, will automatically set CSFR token and return a +accept a `data` option for the content, will automatically set CSRF token and return a Promise for a [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response). ### HTML Attributes and `dataset` diff --git a/docs/content/installation/comparison.en-us.md b/docs/content/installation/comparison.en-us.md index 80fa9b7054d..e48410ba6fa 100644 --- a/docs/content/installation/comparison.en-us.md +++ b/docs/content/installation/comparison.en-us.md @@ -33,117 +33,117 @@ _Symbols used in table:_ ## General Features -| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | -| ------------------------------------------------ | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | -| Open source and free | ✓ | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | -| Low RAM/ CPU usage | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | -| Multiple database support | ✓ | ✓ | ✘ | ⁄ | ⁄ | ✓ | ✓ | -| Multiple OS support | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | -| Easy upgrades | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ | -| Telemetry | **✘** | ✘ | ✓ | ✓ | ✓ | ✓ | ? | -| Third-party render tool support | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ? | -| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ? | -| Extensive API | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Built-in Package/Container Registry | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Sync commits to an external repo (push mirror) | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ | -| Sync commits from an external repo (pull mirror) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ? | -| Light and Dark Theme | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ? | -| Custom Theme Support | ✓ | ✓ | ✘ | ✘ | ✘ | ✓ | ✘ | -| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ? | -| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | -| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| RSS Feeds | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | ✘ | -| Built-in CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Subgroups: groups within groups | [✘](https://github.com/go-gitea/gitea/issues/1872) | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ | -| Interaction with other instances | [/](https://github.com/go-gitea/gitea/issues/18240) | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | -| Mermaid diagrams in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Math syntax in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE | +| ------------------------------------------------ | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ | +| Open source and free | ✓ | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✓ | +| Low RAM/ CPU usage | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | +| Multiple database support | ✓ | ✓ | ✘ | ⁄ | ⁄ | ✓ | ✓ | ✓ | +| Multiple OS support | ✓ | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ✓ | +| Easy upgrades | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ | +| Telemetry | **✘** | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Third-party render tool support | ✓ | ✘ | ✘ | ✘ | ✘ | ✓ | ✘ | ✘ | +| WebAuthn (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ | +| Extensive API | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Built-in Package/Container Registry | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Sync commits to an external repo (push mirror) | ✓ | ✓ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ | +| Sync commits from an external repo (pull mirror) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ | +| Light and Dark Theme | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Custom Theme Support | ✓ | ✓ | ✘ | ✘ | ✘ | ✓ | ✓ | ✓ | +| Markdown support | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| CSV support | ✓ | ✘ | ✓ | ✘ | ✘ | ✓ | ✘ | ✘ | +| 'GitHub / GitLab pages' | [⚙️][gitea-pages-server], [⚙️][gitea-caddy-plugin] | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Repo-specific wiki (as a repo itself) | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ | +| Deploy Tokens | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Repository Tokens with write rights | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| RSS Feeds | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | ✓ | ✓ | +| Built-in CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Subgroups: groups within groups | [✘](https://github.com/go-gitea/gitea/issues/1872) | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ | ✓ | +| Interaction with other instances | [/](https://github.com/go-gitea/gitea/issues/18240) | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | +| Mermaid diagrams in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Math syntax in Markdown | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ | ✓ | ## Code management -| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | -| ------------------------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | -| Repository topics | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Repository code search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Global code search | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ | -| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Group Milestones | [✘](https://github.com/go-gitea/gitea/issues/14622) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| Granular user roles (Code, Issues, Wiki, …) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| Verified Committer | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ | -| GPG Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| SSH Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ? | -| Reject unsigned commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Migrating repos from other services | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Repository Activity page | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Branch manager | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Create new branches | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Web code editor | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Commit graph | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Template Repositories | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ | -| Git Blame | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Visual comparison of image changes | ✓ | ✘ | ✓ | ? | ? | ? | ? | +| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE | +| ------------------------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ | +| Repository topics | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Repository code search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Global code search | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | +| Git LFS 2.0 | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Group Milestones | [✘](https://github.com/go-gitea/gitea/issues/14622) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Granular user roles (Code, Issues, Wiki, …) | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Verified Committer | ⁄ | ✘ | ? | ✓ | ✓ | ✓ | ✘ | ✘ | +| GPG Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| SSH Signed Commits | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | ✘ | +| Reject unsigned commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Migrating repos from other services | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Repository Activity page | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Branch manager | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Create new branches | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Web code editor | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Commit graph | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Template Repositories | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✘ | ✘ | +| Git Blame | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Visual comparison of image changes | ✓ | ✘ | ✓ | ? | ? | ? | ✘ | ✘ | ## Issue Tracker -| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | -| ----------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | -| Issue tracker | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | -| Issue templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Labels | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Time tracking | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Multiple assignees for issues | ✓ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ | -| Related issues | ✘ | ✘ | ⁄ | ✓ | ✓ | ✘ | ✘ | -| Confidential issues | [✘](https://github.com/go-gitea/gitea/issues/3217) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| Comment reactions | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Lock Discussion | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Batch issue handling | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Issue Boards (Kanban) | [/](https://github.com/go-gitea/gitea/issues/14710) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| Create branch from issue | [✘](https://github.com/go-gitea/gitea/issues/20226) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| Convert comment to new issue | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Issue search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Global issue search | [/](https://github.com/go-gitea/gitea/issues/2434) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Issue dependency | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | -| Create issue via email | [✘](https://github.com/go-gitea/gitea/issues/6226) | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | -| Service Desk | [✘](https://github.com/go-gitea/gitea/issues/6219) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | +| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE | +| ----------------------------- | --------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ | +| Issue tracker | ✓ | ✓ | ✓ | ✓ | ✓ | / | ✘ | ✘ | +| Issue templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Labels | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Time tracking | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Multiple assignees for issues | ✓ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | +| Related issues | ✘ | ✘ | ⁄ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Confidential issues | [✘](https://github.com/go-gitea/gitea/issues/3217) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Comment reactions | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Lock Discussion | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Batch issue handling | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Issue Boards (Kanban) | [/](https://github.com/go-gitea/gitea/issues/14710) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Create branch from issue | [✘](https://github.com/go-gitea/gitea/issues/20226) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Convert comment to new issue | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Issue search | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Global issue search | [/](https://github.com/go-gitea/gitea/issues/2434) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Issue dependency | ✓ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | ✘ | +| Create issue via email | [✘](https://github.com/go-gitea/gitea/issues/6226) | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Service Desk | [✘](https://github.com/go-gitea/gitea/issues/6219) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✘ | ## Pull/Merge requests -| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | -| ----------------------------------------------- | -------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | -| Pull/Merge requests | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Squash merging | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Rebase merging | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Pull/Merge request inline comments | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Pull/Merge request approval | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Pull/Merge require approval | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ | -| Pull/Merge multiple reviewers | ✓ | ✓ | ✓ | ✘ | ✓ | ✓ | ✓ | -| Merge conflict resolution | [✘](https://github.com/go-gitea/gitea/issues/9014) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Restrict push and merge access to certain users | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Revert specific commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Pull/Merge requests templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | -| Cherry-picking changes | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | -| Download Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✘ | -| Merge queues | ✘ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ | +| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE | +| ----------------------------------------------- | -------------------------------------------------- | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ | +| Pull/Merge requests | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Squash merging | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Rebase merging | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Pull/Merge request inline comments | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Pull/Merge request approval | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Pull/Merge require approval | ✓ | ✘ | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | +| Pull/Merge multiple reviewers | ✓ | ✓ | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | +| Merge conflict resolution | [✘](https://github.com/go-gitea/gitea/issues/9014) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Restrict push and merge access to certain users | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Revert specific commits | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Pull/Merge requests templates | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | ✘ | +| Cherry-picking changes | ✓ | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ | ✓ | +| Download Patch | ✓ | ✘ | ✓ | ✓ | ✓ | / | ✓ | ✓ | +| Merge queues | ✘ | ✘ | ✓ | ✘ | ✓ | ✘ | ✘ | ✘ | ## 3rd-party integrations -| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | -| ---------------------------------------------- | ------------------------------------------------ | ---- | --------- | --------- | --------- | --------- | ------------ | -| Webhooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Git Hooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| AD / LDAP integration | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| Multiple LDAP / AD server support | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | -| LDAP user synchronization | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | -| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| OpenID Connect support | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | -| OAuth 2.0 integration (external authorization) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✓ | -| Act as OAuth 2.0 provider | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Two factor authentication (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | -| Integration with the most common services | ✓ | / | ⁄ | ✓ | ✓ | ⁄ | ✓ | -| Incorporate external CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Feature | Gitea | Gogs | GitHub EE | GitLab CE | GitLab EE | BitBucket | RhodeCode CE | RhodeCode EE | +| ---------------------------------------------- | ------------------------------------------------ | ---- | --------- | --------- | --------- | --------- | ------------ | ------------ | +| Webhooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Git Hooks | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| AD / LDAP integration | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | +| Multiple LDAP / AD server support | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ | ✓ | +| LDAP user synchronization | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ | +| SAML 2.0 service provider | [✘](https://github.com/go-gitea/gitea/issues/5512) | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ | +| OpenID Connect support | ✓ | ✘ | ✓ | ✓ | ✓ | ? | ✘ | ✓ | +| OAuth 2.0 integration (external authorization) | ✓ | ✘ | ⁄ | ✓ | ✓ | ? | ✘ | ✓ | +| Act as OAuth 2.0 provider | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ | ✘ | +| Two factor authentication (2FA) | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✘ | ✓ | +| Integration with the most common services | ✓ | / | ⁄ | ✓ | ✓ | ⁄ | ✓ | ✓ | +| Incorporate external CI/CD | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | [gitea-caddy-plugin]: https://github.com/42wim/caddy-gitea [gitea-pages-server]: https://codeberg.org/Codeberg/pages-server diff --git a/docs/content/installation/database-preparation.en-us.md b/docs/content/installation/database-preparation.en-us.md index 21360fa4d27..ea378a95c28 100644 --- a/docs/content/installation/database-preparation.en-us.md +++ b/docs/content/installation/database-preparation.en-us.md @@ -17,13 +17,15 @@ menu: # Database Preparation -You need a database to use Gitea. Gitea supports PostgreSQL (>=10), MySQL (>=5.7), SQLite, and MSSQL (>=2008R2 SP3). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter. +You need a database to use Gitea. Gitea supports PostgreSQL (>= 12), MySQL (>= 8.0), MariaDB, SQLite, and MSSQL (>= 2012 SP4). This page will guide into preparing database. Only PostgreSQL and MySQL will be covered here since those database engines are widely-used in production. If you plan to use SQLite, you can ignore this chapter. + +If you use an unsupported database version, please [get in touch](/help/support) with us for information on our Extended Support Contracts. We can provide testing and support for older databases and integrate those fixes into the Gitea codebase. Database instance can be on same machine as Gitea (local database setup), or on different machine (remote database). Note: All steps below requires that the database engine of your choice is installed on your system. For remote database setup, install the server application on database instance and client program on your Gitea server. The client program is used to test connection to the database from Gitea server, while Gitea itself use database driver provided by Go to accomplish the same thing. In addition, make sure you use same engine version for both server and client for some engine features to work. For security reason, protect `root` (MySQL) or `postgres` (PostgreSQL) database superuser with secure password. The steps assumes that you run Linux for both database and Gitea servers. -## MySQL +## MySQL/MariaDB 1. For remote database setup, you will need to make MySQL listen to your IP address. Edit `bind-address` option on `/etc/mysql/my.cnf` on database instance to: @@ -45,7 +47,7 @@ Note: All steps below requires that the database engine of your choice is instal ```sql SET old_passwords=0; - CREATE USER 'gitea' IDENTIFIED BY 'gitea'; + CREATE USER 'gitea'@'%' IDENTIFIED BY 'gitea'; ``` For remote database: diff --git a/docs/content/installation/database-preparation.zh-cn.md b/docs/content/installation/database-preparation.zh-cn.md index b5e8b73f1f6..26bacb7d423 100644 --- a/docs/content/installation/database-preparation.zh-cn.md +++ b/docs/content/installation/database-preparation.zh-cn.md @@ -17,7 +17,7 @@ menu: # 数据库准备 -在使用 Gitea 前,您需要准备一个数据库。Gitea 支持 PostgreSQL(>=10)、MySQL(>=5.7)、SQLite 和 MSSQL(>=2008R2 SP3)这几种数据库。本页将指导您准备数据库。由于 PostgreSQL 和 MySQL 在生产环境中被广泛使用,因此本文档将仅涵盖这两种数据库。如果您计划使用 SQLite,则可以忽略本章内容。 +在使用 Gitea 前,您需要准备一个数据库。Gitea 支持 PostgreSQL(>= 12)、MySQL(>= 8.0)、SQLite 和 MSSQL(>= 2012 SP4)这几种数据库。本页将指导您准备数据库。由于 PostgreSQL 和 MySQL 在生产环境中被广泛使用,因此本文档将仅涵盖这两种数据库。如果您计划使用 SQLite,则可以忽略本章内容。 数据库实例可以与 Gitea 实例在相同机器上(本地数据库),也可以与 Gitea 实例在不同机器上(远程数据库)。 diff --git a/docs/content/installation/from-package.en-us.md b/docs/content/installation/from-package.en-us.md index 4c29c31efca..aa559f28336 100644 --- a/docs/content/installation/from-package.en-us.md +++ b/docs/content/installation/from-package.en-us.md @@ -24,7 +24,6 @@ Following the [deployment from binary](installation/from-binary.md) guide may wo but is not supported. To install Gitea via `brew`: ``` -brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea brew install gitea ``` diff --git a/docs/content/installation/from-package.fr-fr.md b/docs/content/installation/from-package.fr-fr.md index 256c913dcff..32e020dc7be 100644 --- a/docs/content/installation/from-package.fr-fr.md +++ b/docs/content/installation/from-package.fr-fr.md @@ -30,7 +30,6 @@ Nous n'avons pas encore publié de paquet pour Windows, nous allons mettre à jo Actuellement, nous ne supportons que l'installation via `brew` pour macOS. Si vous n'utilisez pas [Homebrew](http://brew.sh/), vous pouvez suivre les [instructions d'installation](installation/from-binary.md) avec le binaire pré-compilé. Pour installer Gitea depuis `brew`, utilisez les commandes suivantes : ``` -brew tap go-gitea/gitea brew install gitea ``` diff --git a/docs/content/installation/from-package.zh-cn.md b/docs/content/installation/from-package.zh-cn.md index 66db4d322d1..929782f23c7 100644 --- a/docs/content/installation/from-package.zh-cn.md +++ b/docs/content/installation/from-package.zh-cn.md @@ -22,7 +22,6 @@ menu: macOS 平台下当前我们仅支持通过 `brew` 来安装。如果你没有安装 [Homebrew](http://brew.sh/),你也可以查看 [从二进制安装](installation/from-binary.md)。在你安装了 `brew` 之后, 你可以执行以下命令: ``` -brew tap gitea/tap https://gitea.com/gitea/homebrew-gitea brew install gitea ``` diff --git a/docs/content/installation/from-package.zh-tw.md b/docs/content/installation/from-package.zh-tw.md index 5a417ee2029..8a2de2997d5 100644 --- a/docs/content/installation/from-package.zh-tw.md +++ b/docs/content/installation/from-package.zh-tw.md @@ -36,7 +36,6 @@ choco install gitea 目前我們只支援透過 `brew` 來安裝套件。假如您尚未使用 [Homebrew](http://brew.sh/),您就必須參考[執行檔安裝](installation/from-binary.md)方式。透過 `brew` 安裝 Gitea,您只需要執行底下指令: ``` -brew tap go-gitea/gitea brew install gitea ``` diff --git a/docs/content/installation/from-source.en-us.md b/docs/content/installation/from-source.en-us.md index ef720f08246..f6a95e8d0cf 100644 --- a/docs/content/installation/from-source.en-us.md +++ b/docs/content/installation/from-source.en-us.md @@ -128,8 +128,6 @@ If pre-built frontend files are present it is possible to only build the backend TAGS="bindata" make backend ``` -Webpack source maps are by default enabled in development builds and disabled in production builds. They can be enabled by setting the `ENABLE_SOURCEMAP=true` environment variable. - ## Test After following the steps above, a `gitea` binary will be available in the working directory. @@ -260,3 +258,11 @@ GOARCH=amd64 \ TAGS="bindata sqlite sqlite_unlock_notify" \ make build ``` + +## Source Maps + +By default, gitea generates reduced source maps for frontend files to conserve space. This can be controlled with the `ENABLE_SOURCEMAP` environment variable: + +- `ENABLE_SOURCEMAP=true` generates all source maps, the default for development builds +- `ENABLE_SOURCEMAP=reduced` generates limited source maps, the default for production builds +- `ENABLE_SOURCEMAP=false` generates no source maps diff --git a/docs/content/installation/from-source.zh-cn.md b/docs/content/installation/from-source.zh-cn.md index 260ccbee3c6..40a314340c6 100644 --- a/docs/content/installation/from-source.zh-cn.md +++ b/docs/content/installation/from-source.zh-cn.md @@ -100,8 +100,6 @@ TAGS="bindata sqlite sqlite_unlock_notify" make build TAGS="bindata" make backend ``` -在开发构建中,默认启用 Webpack 源映射,在生产构建中禁用。可以通过设置`ENABLE_SOURCEMAP=true`环境变量来启用它们。 - ## 测试 按照上述步骤完成后,工作目录中将会有一个`gitea`二进制文件。可以从该目录进行测试,或将其移动到带有测试数据的目录中。当手动从命令行启动 Gitea 时,可以通过按下`Ctrl + C`来停止程序。 @@ -221,3 +219,11 @@ GOARCH=amd64 \ TAGS="bindata sqlite sqlite_unlock_notify" \ make build ``` + +## Source Map + +默认情况下,gitea 会为前端文件生成精简的 Source Map 以节省空间。 这可以通过“ENABLE_SOURCEMAP”环境变量进行控制: + +- `ENABLE_SOURCEMAP=true` 生成所有Source Map,这是开发版本的默认设置 +- `ENABLE_SOURCEMAP=reduced` 生成有限的Source Map,这是生产版本的默认设置 +- `ENABLE_SOURCEMAP=false` 不生成Source Map diff --git a/docs/content/installation/upgrade-from-gogs.en-us.md b/docs/content/installation/upgrade-from-gogs.en-us.md deleted file mode 100644 index 47cddc1c305..00000000000 --- a/docs/content/installation/upgrade-from-gogs.en-us.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -date: "2016-12-01T16:00:00+02:00" -title: "Upgrade from Gogs" -slug: "upgrade-from-gogs" -sidebar_position: 101 -toc: false -draft: false -aliases: - - /en-us/upgrade-from-gogs -menu: - sidebar: - parent: "installation" - name: "Upgrade From Gogs" - sidebar_position: 101 - identifier: "upgrade-from-gogs" ---- - -# Upgrade from Gogs - -Gogs, version 0.9.146 and older, can be easily migrated to Gitea. - -There are some basic steps to follow. On a Linux system run as the Gogs user: - -* Create a Gogs backup with `gogs backup`. This creates `gogs-backup-[timestamp].zip` file - containing all important Gogs data. You would need it if you wanted to move to the `gogs` back later. -* Download the file matching the destination platform from the [downloads page](https://dl.gitea.com/gitea/). - It should be `1.0.x` version. Migrating from `gogs` to any other version is impossible. -* Put the binary at the desired install location. -* Copy `gogs/custom/conf/app.ini` to `gitea/custom/conf/app.ini`. -* Copy custom `templates, public` from `gogs/custom/` to `gitea/custom/`. -* For any other custom folders, such as `gitignore, label, license, locale, readme` in - `gogs/custom/conf`, copy them to `gitea/custom/options`. -* Copy `gogs/data/` to `gitea/data/`. It contains issue attachments and avatars. -* Verify by starting Gitea with `gitea web`. -* Enter Gitea admin panel on the UI, run `Rewrite '.ssh/authorized_keys' file`. -* Launch every major version of the binary ( `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → etc ) to migrate database. -* If custom or config path was changed, run `Rewrite all update hook of repositories`. - -## Change gogs specific information - -* Rename `gogs-repositories/` to `gitea-repositories/` -* Rename `gogs-data/` to `gitea-data/` -* In `gitea/custom/conf/app.ini` change: - - FROM: - - ```ini - [database] - PATH = /home/:USER/gogs/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gogs-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars - [log] - ROOT_PATH = /home/:USER/gogs/log - ``` - - TO: - - ```ini - [database] - PATH = /home/:USER/gitea/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gitea-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars - [log] - ROOT_PATH = /home/:USER/gitea/log - ``` - -* Verify by starting Gitea with `gitea web` - -## Upgrading to most recent `gitea` version - -After successful migration from `gogs` to `gitea 1.0.x`, it is possible to upgrade `gitea` to a modern version -in a two steps process. - -Upgrade to [`gitea 1.6.4`](https://dl.gitea.com/gitea/1.6.4/) first. Download the file matching -the destination platform from the [downloads page](https://dl.gitea.com/gitea/1.6.4/) and replace the binary. -Run Gitea at least once and check that everything works as expected. - -Then repeat the procedure, but this time using the [latest release](https://dl.gitea.com/gitea/@version@/). - -## Upgrading from a more recent version of Gogs - -Upgrading from a more recent version of Gogs (up to `0.11.x`) may also be possible, but will require a bit more work. -See [#4286](https://github.com/go-gitea/gitea/issues/4286), which includes various Gogs `0.11.x` versions. - -Upgrading from Gogs `0.12.x` and above will be increasingly more difficult as the projects diverge further apart in configuration and schema. - -## Troubleshooting - -* If errors are encountered relating to custom templates in the `gitea/custom/templates` - folder, try moving the templates causing the errors away one by one. They may not be - compatible with Gitea or an update. - -## Add Gitea to startup on Unix - -Update the appropriate file from [gitea/contrib](https://github.com/go-gitea/gitea/tree/main/contrib) -with the right environment variables. - -For distros with systemd: - -* Copy the updated script to `/etc/systemd/system/gitea.service` -* Add the service to the startup with: `sudo systemctl enable gitea` -* Disable old gogs startup script: `sudo systemctl disable gogs` - -For distros with SysVinit: - -* Copy the updated script to `/etc/init.d/gitea` -* Add the service to the startup with: `sudo rc-update add gitea` -* Disable old gogs startup script: `sudo rc-update del gogs` diff --git a/docs/content/installation/upgrade-from-gogs.fr-fr.md b/docs/content/installation/upgrade-from-gogs.fr-fr.md deleted file mode 100644 index a5cd8759825..00000000000 --- a/docs/content/installation/upgrade-from-gogs.fr-fr.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -date: "2017-08-23T09:00:00+02:00" -title: "Mise à jour depuis Gogs" -slug: "upgrade-from-gogs" -sidebar_position: 101 -toc: false -draft: false -aliases: - - /fr-fr/upgrade-from-gogs -menu: - sidebar: - parent: "installation" - name: "Depuis Gogs" - sidebar_position: 101 - identifier: "upgrade-from-gogs" ---- - -# Mise à jour depuis Gogs - -À partir de la version 0.9.146 (schéma de la base de données : version 15) de Gogs, Il est possible de migrer vers Gitea simplement et sans encombre. - -Veuillez suivre les étapes ci-dessous. Sur Unix, toute les commandes s'exécutent en tant que l'utilisateur utilisé pour votre installation de Gogs : - -* Crééer une sauvegarde de Gogs avec la commande `gogs dump`. Le fichier nouvellement créé `gogs-dump-[timestamp].zip` contient toutes les données de votre instance de Gogs. -* Téléchargez le fichier correspondant à votre plateforme à partir de la [page de téléchargements](https://dl.gitea.com/gitea). -* Mettez la binaire dans le répertoire d'installation souhaité. -* Copiez le fichier `gogs/custom/conf/app.ini` vers `gitea/custom/conf/app.ini`. -* Si vous avez personnalisé les répertoires `templates, public` dans `gogs/custom/`, copiez-les vers `gitea/custom/`. -* Si vous avez d'autres répertoires personnalisés comme `gitignore, label, license, locale, readme` dans `gogs/custom/conf` copiez-les vers `gitea/custom/options`. -* Copiez le répertoire `gogs/data/` vers `gitea/data/`. -* Vérifiez votre installation en exécutant Gitea avec la commande `gitea web`. -* Lancez le binaire de version majeure en version majeure ( `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → etc ) afin de récupérer les migrations de base de données. -* Connectez vous au panel d'administration de Gitea et exécutez l'action `Rewrite '.ssh/authorized_keys' file`, puis l'action `Rewrite all update hook of repositories` (obligatoire si le chemin menant à votre configuration personnalisée à changé). - -## Modifier les informations spécifiques de gogs - -* Renommez `gogs-repositories/` vers `gitea-repositories/` -* Renommez `gogs-data/` to `gitea-data/` -* Dans votre fichier `gitea/custom/conf/app.ini`, modifiez les éléments suivants: - - DE : - - ```ini - [database] - PATH = /home/:USER/gogs/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gogs-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars - [log] - ROOT_PATH = /home/:USER/gogs/log - ``` - - VERS : - - ```ini - [database] - PATH = /home/:USER/gitea/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gitea-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars - [log] - ROOT_PATH = /home/:USER/gitea/log - ``` - -* Vérifiez votre installation en exécutant Gitea avec la commande `gitea web`. - -## Dépannage - -* Si vous rencontrez des erreurs relatives à des modèles personnalisés dans le dossier `gitea/custom/templates`, essayez de déplacer un par un les modèles provoquant les erreurs. Il est possible qu'ils ne soient pas compatibles avec Gitea. - -## Démarrer automatiquement Gitea (Unix) - -Distributions utilisant systemd: - -* Copiez le script mis à jour vers `/etc/systemd/system/gitea.service` -* Ajoutez le service avec la commande `sudo systemctl enable gitea` -* Désactivez Gogs avec la commande `sudo systemctl disable gogs` - -Distributions utilisant SysVinit: - -* Copiez le script mis à jour vers `/etc/init.d/gitea` -* Ajoutez le service avec la commande `sudo rc-update add gitea` -* Désactivez Gogs avec la commande `sudo rc-update del gogs` diff --git a/docs/content/installation/upgrade-from-gogs.zh-cn.md b/docs/content/installation/upgrade-from-gogs.zh-cn.md deleted file mode 100644 index 29788c929f2..00000000000 --- a/docs/content/installation/upgrade-from-gogs.zh-cn.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -date: "2016-12-01T16:00:00+02:00" -title: "从 Gogs 升级" -slug: "upgrade-from-gogs" -sidebar_position: 101 -toc: false -draft: false -aliases: - - /zh-cn/upgrade-from-gogs -menu: - sidebar: - parent: "installation" - name: "从 Gogs 升级" - sidebar_position: 101 - identifier: "upgrade-from-gogs" ---- - -# 从 Gogs 升级 - -如果你正在运行Gogs 0.9.146以下版本,你可以平滑的升级到Gitea。该升级需要如下的步骤: - -* 使用 `gogs backup` 创建 Gogs 备份。这会创建一个名为 `gogs-backup-[时间戳].zip` 的文件,其中包含所有重要的 Gogs 数据。如果您将来想要返回到 `gogs`,您会需要这个备份文件。 -* 从 [下载页面](https://dl.gitea.com/gitea/) 下载适用于目标平台的文件。应该选择 `1.0.x` 版本。从 `gogs` 迁移到其他任何版本是不可能的。 -* 将二进制文件放置在所需的安装位置。 -* 将 `gogs/custom/conf/app.ini` 复制到 `gitea/custom/conf/app.ini`。 -* 将 `gogs/custom/` 中的自定义 `templates, public` 复制到 `gitea/custom/`。 -* 对于其他自定义文件夹,例如 `gogs/custom/conf` 中的 `gitignore, label, license, locale, readme`,将它们复制到 `gitea/custom/options`。 -* 将 `gogs/data/` 复制到 `gitea/data/`。其中包含问题附件和头像。 -* 使用 `gitea web` 启动 Gitea 进行验证。 -* 在 UI 上进入 Gitea 管理面板,运行 `Rewrite '.ssh/authorized_keys' file`。 -* 启动每个主要版本的二进制文件(例如 `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → 等)以迁移数据库。 -* 如果自定义或配置路径已更改,请运行 `Rewrite all update hook of repositories`。 - -## 更改特定于 Gogs 的信息 - -* 将 `gogs-repositories/` 重命名为 `gitea-repositories/` -* 将 `gogs-data/` 重命名为 `gitea-data/` -* 在 `gitea/custom/conf/app.ini` 中进行更改: -从: - - ```ini - [database] - PATH = /home/:USER/gogs/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gogs-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars - [log] - ROOT_PATH = /home/:USER/gogs/log - ``` - -到: - - ```ini - [database] - PATH = /home/:USER/gitea/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gitea-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars - [log] - ROOT_PATH = /home/:USER/gitea/log - ``` - -* 使用 `gitea web` 启动 Gitea 进行验证 - -## 升级到最新版本的 `gitea` - -在成功从 `gogs` 迁移到 `gitea 1.0.x` 之后,可以通过两步过程将 `gitea` 升级到现代版本。 - -首先升级到 [`gitea 1.6.4`](https://dl.gitea.com/gitea/1.6.4/)。从 [下载页面](https://dl.gitea.com/gitea/1.6.4/) 下载适用于目标平台的文件,并替换二进制文件。至少运行一次 Gitea 并检查是否一切正常。 - -然后重复这个过程,但这次使用 [最新版本](https://dl.gitea.com/gitea/@version@/)。 - -## 从较新的 Gogs 版本升级 - -从较新的 Gogs 版本(最高到 `0.11.x`)可能也是可能的,但需要更多的工作。 -请参见 [#4286](https://github.com/go-gitea/gitea/issues/4286),其中包括各种 Gogs `0.11.x` 版本。 - -从 Gogs `0.12.x` 及更高版本升级将变得越来越困难,因为项目在配置和架构上逐渐分歧。 - -## 故障排除 - -* 如果在 `gitea/custom/templates` 文件夹中遇到与自定义模板相关的错误,请尝试逐个移除引发错误的模板。 - 它们可能与 Gitea 或更新不兼容。 - -## 将 Gitea 添加到 Unix 的启动项 - -从 [gitea/contrib](https://github.com/go-gitea/gitea/tree/main/contrib) 更新适当的文件,确保正确的环境变量。 - -对于使用 systemd 的发行版: - -* 将更新后的脚本复制到 `/etc/systemd/system/gitea.service` -* 使用以下命令将服务添加到启动项:`sudo systemctl enable gitea` -* 禁用旧的 gogs 启动脚本:`sudo systemctl disable gogs` - -对于使用 SysVinit 的发行版: - -* 将更新后的脚本复制到 `/etc/init.d/gitea` -* 使用以下命令将服务添加到启动项:`sudo rc-update add gitea` -* 禁用旧的 gogs 启动脚本:`sudo rc-update del gogs` diff --git a/docs/content/installation/upgrade-from-gogs.zh-tw.md b/docs/content/installation/upgrade-from-gogs.zh-tw.md deleted file mode 100644 index ef5737bc6d2..00000000000 --- a/docs/content/installation/upgrade-from-gogs.zh-tw.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -date: "2016-12-01T16:00:00+02:00" -title: "從 Gogs 升級" -slug: "upgrade-from-gogs" -sidebar_position: 101 -toc: false -draft: false -aliases: - - /zh-tw/upgrade-from-gogs -menu: - sidebar: - parent: "installation" - name: "從 Gogs 升級" - sidebar_position: 101 - identifier: "upgrade-from-gogs" ---- - -# 從 Gogs 升級 - -**目錄** - -若您正在執行 Gogs 0.9.146 以下版本,您可以很簡單地遷移到 Gitea。 - -請參考下列步驟。在 Linux 系統上請以 Gogs 的使用者身份執行: - -- 使用 `gogs backup` 建立 Gogs 的備份。這會建立檔案 `gogs-backup-[timestamp].zip` 包含所有重要的 Gogs 資料。 - 如果稍後您要恢復到 `gogs` 時會用到它。 -- 從[下載頁](https://dl.gitea.com/gitea/)下載對應您平臺的檔案。請下載 `1.0.x` 版,從 `gogs` 遷移到其它版本是不可行的。 -- 將二進位檔放到適當的安裝位置。 -- 複製 `gogs/custom/conf/app.ini` 到 `gitea/custom/conf/app.ini`。 -- 從 `gogs/custom/` 複製自訂 `templates, public` 到 `gitea/custom/`。 -- `gogs/custom/conf` 中的其它自訂資料夾如: `gitignore, label, license, locale, readme`, - 請複製到 `gitea/custom/options`。 -- 複製 `gogs/data/` 到 `gitea/data/`。它包含了問題附件和大頭貼。 -- 以指令 `gitea web` 啟動 Gitea 驗證上列設定是否正確。 -- 從網頁 UI 進入 Gitea 管理員面板, 執行 `Rewrite '.ssh/authorized_keys' file`。 -- 執行每個主要版本的二進位檔 ( `1.1.4` → `1.2.3` → `1.3.4` → `1.4.2` → 等等 ) 以遷移資料庫。 -- 如果變更了自訂檔、設定檔路徑,請執行 `Rewrite all update hook of repositories`。 - -## 修改指定的 gogs 資訊 - -- 重新命名 `gogs-repositories/` 為 `gitea-repositories/` -- 重新命名 `gogs-data/` 為 `gitea-data/` -- 在 `gitea/custom/conf/app.ini` 中修改: - - 修改前: - - ```ini - [database] - PATH = /home/:USER/gogs/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gogs-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gogs-data/avatars - [log] - ROOT_PATH = /home/:USER/gogs/log - ``` - - 修改後: - - ```ini - [database] - PATH = /home/:USER/gitea/data/:DATABASE.db - [attachment] - PATH = /home/:USER/gitea-data/attachments - [picture] - AVATAR_UPLOAD_PATH = /home/:USER/gitea-data/avatars - [log] - ROOT_PATH = /home/:USER/gitea/log - ``` - -- 執行 `gitea web` 啟動 Gitea 檢查是否正確執行 - -## 升級到最新版的 `gitea` - -成功從 `gogs` 升級到 `gitea 1.0.x` 後再用 2 個步驟即可升級到最新版的 `gitea`。 - -請先升級到 [`gitea 1.6.4`](https://dl.gitea.com/gitea/1.6.4/),先從[下載頁](https://dl.gitea.com/gitea/1.6.4/)下載 -您平臺的二進位檔取代既有的。至少執行一次 Gitea 並確認一切符合預期。 - -接著重複上述步驟,但這次請使用[最新發行版本](https://dl.gitea.com/gitea/@version@/)。 - -## 從更新版本的 Gogs 升級 - -您也可以從更新版本的 Gogs 升級,但需要更多步驟。 -請參考 [#4286](https://github.com/go-gitea/gitea/issues/4286)。 - -## 疑難排解 - -- 如果錯誤和 `gitea/custom/templates` 中 的自訂樣板有關,請試著逐一移除它們。 - 它們可能和 Gitea 或更新不相容。 - -## 在 Unix 啟動時執行 Gitea - -從 [gitea/contrib](https://github.com/go-gitea/gitea/tree/master/contrib) 更新必要的檔案以取得正確的環境變數。 - -使用 systemd 的發行版: - -- 複製新的腳本到 `/etc/systemd/system/gitea.service` -- 啟動系統時執行服務: `sudo systemctl enable gitea` -- 停用舊的 gogs 腳本: `sudo systemctl disable gogs` - -使用 SysVinit 的發行版: - -- 複製新的腳本到 `/etc/init.d/gitea` -- 啟動系統時執行服務: `sudo rc-update add gitea` -- 停用舊的 gogs 腳本: `sudo rc-update del gogs` diff --git a/docs/content/usage/actions/comparison.en-us.md b/docs/content/usage/actions/comparison.en-us.md index 64a5eff4d5a..caec9d3dea3 100644 --- a/docs/content/usage/actions/comparison.en-us.md +++ b/docs/content/usage/actions/comparison.en-us.md @@ -91,12 +91,6 @@ As a workaround, you can use [go-hashfiles](https://gitea.com/actions/go-hashfil ## Missing features -### Variables - -See [Variables](https://docs.github.com/en/actions/learn-github-actions/variables). - -It's under development. - ### Problem Matchers Problem Matchers are a way to scan the output of actions for a specified regex pattern and surface that information prominently in the UI. @@ -120,15 +114,17 @@ Pre and Post steps don't have their own section in the job log user interface. ### Downloading actions -Gitea Actions doesn't download actions from GitHub by default. -"By default" means that you don't specify the host in the `uses` field, like `uses: actions/checkout@v3`. -As a contrast, `uses: https://github.com/actions/checkout@v3` has specified host. +Previously (Pre 1.21.0), `[actions].DEFAULT_ACTIONS_URL` defaulted to `https://gitea.com`. +We have since restricted this option to only allow two values (`github` and `self`). +When set to `github`, the new default, Gitea will download non-fully-qualified actions from . +For example, if you use `uses: actions/checkout@v3`, it will download the checkout repository from . -The missing host will be filled with `https://gitea.com` if you don't configure it. -That means `uses: actions/checkout@v3` will download the action from [gitea.com/actions/checkout](https://gitea.com/actions/checkout), instead of [github.com/actions/checkout](https://github.com/actions/checkout). +If you want to download an action from another git hoster, you can use an absolute URL, e.g. `uses: https://gitea.com/actions/checkout@v3`. -As mentioned, it's configurable. -If you want your runners to download actions from GitHub or your own Gitea instance by default, you can configure it by setting `[actions].DEFAULT_ACTIONS_URL`. See [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions). +If your Gitea instance is in an intranet or a restricted area, you can set the URL to `self` to only download actions from your own instance by default. +Of course, you can still use absolute URLs in workflows. + +More details about the `[actions].DEFAULT_ACTIONS_URL` configuration can be found in the [Configuration Cheat Sheet](administration/config-cheat-sheet.md#actions-actions)。 ### Context availability diff --git a/docs/content/usage/actions/comparison.zh-cn.md b/docs/content/usage/actions/comparison.zh-cn.md index cfea7970f7d..5dae75a44ba 100644 --- a/docs/content/usage/actions/comparison.zh-cn.md +++ b/docs/content/usage/actions/comparison.zh-cn.md @@ -120,15 +120,13 @@ Gitea Actions目前不支持此功能。 ### 下载Actions -Gitea Actions默认不从GitHub下载Actions。 -"默认" 意味着您在`uses` 字段中不指定主机,如`uses: actions/checkout@v3`。 -相反,`uses: https://github.com/actions/checkout@v3`是有指定主机的。 +当 `[actions].DEFAULT_ACTIONS_URL` 保持默认值为 `github` 时,Gitea将会从 https://github.com 下载相对路径的actions。比如: +如果你使用 `uses: actions/checkout@v3`,Gitea将会从 https://github.com/actions/checkout.git 下载这个 actions 项目。 +如果你想要从另外一个 Git服务下载actions,你只需要使用绝对URL `uses: https://gitea.com/actions/checkout@v3` 来下载。 -如果您不进行配置,缺失的主机将填充为`https://gitea.com`。 -这意味着`uses: actions/checkout@v3`将从[gitea.com/actions/checkout](https://gitea.com/actions/checkout)下载该Action,而不是[github.com/actions/checkout](https://github.com/actions/checkout)。 +如果你的 Gitea 实例是部署在一个互联网限制的网络中,有可以使用绝对地址来下载 actions。你也可以讲配置项修改为 `[actions].DEFAULT_ACTIONS_URL = self`。这样所有的相对路径的actions引用,将不再会从 github.com 去下载,而会从这个 Gitea 实例自己的仓库中去下载。例如: `uses: actions/checkout@v3` 将会从 `[server].ROOT_URL`/actions/checkout.git 这个地址去下载 actions。 -正如前面提到的,这是可配置的。 -如果您希望您的运行程序默认从GitHub或您自己的Gitea实例下载动作,您可以通过设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。 +设置`[actions].DEFAULT_ACTIONS_URL`进行配置。请参阅[配置备忘单](administration/config-cheat-sheet.md#actions-actions)。 ### 上下文可用性 diff --git a/docs/content/usage/actions/faq.en-us.md b/docs/content/usage/actions/faq.en-us.md index 031509a033e..1d59872936a 100644 --- a/docs/content/usage/actions/faq.en-us.md +++ b/docs/content/usage/actions/faq.en-us.md @@ -180,3 +180,6 @@ For events supported only by GitHub, see GitHub's [documentation](https://docs.g | pull_request_review_comment | `created`, `edited` | | release | `published`, `edited` | | registry_package | `published` | + +> For `pull_request` events, in [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request), the `ref` is `refs/pull/:prNumber/merge`, which is a reference to the merge commit preview. However, Gitea has no such reference. +> Therefore, the `ref` in Gitea Actions is `refs/pull/:prNumber/head`, which points to the head of pull request rather than the preview of the merge commit. diff --git a/docs/content/usage/actions/faq.zh-cn.md b/docs/content/usage/actions/faq.zh-cn.md index f5dc8e179bd..7bb79d02fc4 100644 --- a/docs/content/usage/actions/faq.zh-cn.md +++ b/docs/content/usage/actions/faq.zh-cn.md @@ -180,3 +180,6 @@ defaults: | pull_request_review_comment | `created`, `edited` | | release | `published`, `edited` | | registry_package | `published` | + +> 对于 `pull_request` 事件,在 [GitHub Actions](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request) 中 `ref` 是 `refs/pull/:prNumber/merge`,它指向这个拉取请求合并提交的一个预览。但是 Gitea 没有这种 reference。 +> 因此,Gitea Actions 中 `ref` 是 `refs/pull/:prNumber/head`,它指向这个拉取请求的头分支而不是合并提交的预览。 diff --git a/docs/content/usage/blame.en-us.md b/docs/content/usage/blame.en-us.md new file mode 100644 index 00000000000..7772bbc16d7 --- /dev/null +++ b/docs/content/usage/blame.en-us.md @@ -0,0 +1,38 @@ +--- +date: "2023-08-14T00:00:00+00:00" +title: "Blame File View" +slug: "blame" +sidebar_position: 13 +toc: false +draft: false +aliases: + - /en-us/blame +menu: + sidebar: + parent: "usage" + name: "Blame" + sidebar_position: 13 + identifier: "blame" +--- + +# Blame File View + +Gitea supports viewing the line-by-line revision history for a file also known as blame view. +You can also use [`git blame`](https://git-scm.com/docs/git-blame) on the command line to view the revision history of lines within a file. + +1. Navigate to and open the file whose line history you want to view. +1. Click the `Blame` button in the file header bar. +1. The new view shows the line-by-line revision history for a file with author and commit information on the left side. +1. To navigate to an older commit, click the ![versions](/octicon-versions.svg) icon. + +## Ignore commits in the blame view + +All revisions specified in the `.git-blame-ignore-revs` file are hidden from the blame view. +This is especially useful to hide reformatting changes and keep the benefits of `git blame`. +Lines that were changed or added by an ignored commit will be blamed on the previous commit that changed that line or nearby lines. +The `.git-blame-ignore-revs` file must be located in the root directory of the repository. +For more information like the file format, see [the `git blame --ignore-revs-file` documentation](https://git-scm.com/docs/git-blame#Documentation/git-blame.txt---ignore-revs-fileltfilegt). + +### Bypassing `.git-blame-ignore-revs` in the blame view + +If the blame view for a file shows a message about ignored revisions, you can see the normal blame view by appending the url parameter `?bypass-blame-ignore=true`. diff --git a/docs/content/usage/linked-references.zh-cn.md b/docs/content/usage/linked-references.zh-cn.md index 4d63d754066..2f1b888047c 100644 --- a/docs/content/usage/linked-references.zh-cn.md +++ b/docs/content/usage/linked-references.zh-cn.md @@ -113,7 +113,7 @@ menu: ## 外部跟踪器 -Gitea 支持使用外部工单跟踪器,并可以在合并请求中创建对外部托管的工单的引用。但是,如果外部跟踪器使用数字来标识工单,那么它们将与 Gitea 中托管的合并请求无法区分。为了解决这个工单,Gitea 允许使用 `!` 标记来标识合并请求。例如: +Gitea 支持使用外部工单跟踪器,并可以在合并请求中创建对外部托管的工单的引用。但是,如果外部跟踪器使用数字来标识工单,那么它们将与 Gitea 中托管的合并请求无法区分。为了解决这个问题,Gitea 允许使用 `!` 标记来标识合并请求。例如: > 这是工单 [#1234](#),并链接到外部跟踪器。 > 这是合并请求 [!1234](#),并链接到 Gitea 中的合并请求。 diff --git a/docs/static/octicon-versions.svg b/docs/static/octicon-versions.svg new file mode 100644 index 00000000000..aaf5f9cc2b2 --- /dev/null +++ b/docs/static/octicon-versions.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/go.mod b/go.mod index a6e83df05a7..94ee158cb80 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/PuerkitoBio/goquery v1.8.1 github.com/alecthomas/chroma/v2 v2.9.1 github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb - github.com/blevesearch/bleve/v2 v2.3.9 + github.com/blevesearch/bleve/v2 v2.3.10 github.com/bufbuild/connect-go v1.10.0 github.com/buildkite/terminal-to-html/v3 v3.9.1 github.com/caddyserver/certmagic v0.19.2 @@ -42,7 +42,7 @@ require ( github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-co-op/gocron v1.31.1 - github.com/go-enry/go-enry/v2 v2.8.4 + github.com/go-enry/go-enry/v2 v2.8.5 github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e github.com/go-git/go-billy/v5 v5.4.1 github.com/go-git/go-git/v5 v5.8.1 @@ -145,22 +145,22 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/bits-and-blooms/bitset v1.8.0 // indirect - github.com/blevesearch/bleve_index_api v1.0.5 // indirect - github.com/blevesearch/geo v0.1.17 // indirect + github.com/bits-and-blooms/bitset v1.9.0 // indirect + github.com/blevesearch/bleve_index_api v1.0.6 // indirect + github.com/blevesearch/geo v0.1.18 // indirect github.com/blevesearch/go-porterstemmer v1.0.3 // indirect github.com/blevesearch/gtreap v0.1.1 // indirect github.com/blevesearch/mmap-go v1.0.4 // indirect - github.com/blevesearch/scorch_segment_api/v2 v2.1.5 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.1.6 // indirect github.com/blevesearch/segment v0.9.1 // indirect github.com/blevesearch/snowballstem v0.9.0 // indirect github.com/blevesearch/upsidedown_store_api v1.0.2 // indirect github.com/blevesearch/vellum v1.0.10 // indirect - github.com/blevesearch/zapx/v11 v11.3.9 // indirect - github.com/blevesearch/zapx/v12 v12.3.9 // indirect - github.com/blevesearch/zapx/v13 v13.3.9 // indirect - github.com/blevesearch/zapx/v14 v14.3.9 // indirect - github.com/blevesearch/zapx/v15 v15.3.12 // indirect + github.com/blevesearch/zapx/v11 v11.3.10 // indirect + github.com/blevesearch/zapx/v12 v12.3.10 // indirect + github.com/blevesearch/zapx/v13 v13.3.10 // indirect + github.com/blevesearch/zapx/v14 v14.3.10 // indirect + github.com/blevesearch/zapx/v15 v15.3.13 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20230611145640-acc696258285 // indirect github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect diff --git a/go.sum b/go.sum index 5e32daf0c14..44bfa1029f9 100644 --- a/go.sum +++ b/go.sum @@ -149,18 +149,18 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c= -github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/bits-and-blooms/bitset v1.9.0 h1:g1YivPG8jOtrN013Fe8OBXubkiTwvm7/vG2vXz03ANU= +github.com/bits-and-blooms/bitset v1.9.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM= -github.com/blevesearch/bleve/v2 v2.3.9 h1:pUMvK0mxAexqasZcVj8lazmWnEW5XiV0tASIqANiNTQ= -github.com/blevesearch/bleve/v2 v2.3.9/go.mod h1:1PibElcjlQMQHF9uS9mRv58ODQgj4pCWHA1Wfd+qagU= +github.com/blevesearch/bleve/v2 v2.3.10 h1:z8V0wwGoL4rp7nG/O3qVVLYxUqCbEwskMt4iRJsPLgg= +github.com/blevesearch/bleve/v2 v2.3.10/go.mod h1:RJzeoeHC+vNHsoLR54+crS1HmOWpnH87fL70HAUCzIA= github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= -github.com/blevesearch/bleve_index_api v1.0.5 h1:Lc986kpC4Z0/n1g3gg8ul7H+lxgOQPcXb9SxvQGu+tw= -github.com/blevesearch/bleve_index_api v1.0.5/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms= -github.com/blevesearch/geo v0.1.17 h1:AguzI6/5mHXapzB0gE9IKWo+wWPHZmXZoscHcjFgAFA= -github.com/blevesearch/geo v0.1.17/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM= +github.com/blevesearch/bleve_index_api v1.0.6 h1:gyUUxdsrvmW3jVhhYdCVL6h9dCjNT/geNU7PxGn37p8= +github.com/blevesearch/bleve_index_api v1.0.6/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms= +github.com/blevesearch/geo v0.1.18 h1:Np8jycHTZ5scFe7VEPLrDoHnnb9C4j636ue/CGrhtDw= +github.com/blevesearch/geo v0.1.18/go.mod h1:uRMGWG0HJYfWfFJpK3zTdnnr1K+ksZTuWKhXeSokfnM= github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= @@ -169,8 +169,8 @@ github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+ github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU= -github.com/blevesearch/scorch_segment_api/v2 v2.1.5 h1:1g713kpCQZ8u4a3stRGBfrwVOuGRnmxOVU5MQkUPrHU= -github.com/blevesearch/scorch_segment_api/v2 v2.1.5/go.mod h1:f2nOkKS1HcjgIWZgDAErgBdxmr2eyt0Kn7IY+FU1Xe4= +github.com/blevesearch/scorch_segment_api/v2 v2.1.6 h1:CdekX/Ob6YCYmeHzD72cKpwzBjvkOGegHOqhAkXp6yA= +github.com/blevesearch/scorch_segment_api/v2 v2.1.6/go.mod h1:nQQYlp51XvoSVxcciBjtvuHPIVjlWrN1hX4qwK2cqdc= github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ= github.com/blevesearch/segment v0.9.1 h1:+dThDy+Lvgj5JMxhmOVlgFfkUtZV2kw49xax4+jTfSU= github.com/blevesearch/segment v0.9.1/go.mod h1:zN21iLm7+GnBHWTao9I+Au/7MBiL8pPFtJBJTsk6kQw= @@ -184,20 +184,20 @@ github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRv github.com/blevesearch/vellum v1.0.10 h1:HGPJDT2bTva12hrHepVT3rOyIKFFF4t7Gf6yMxyMIPI= github.com/blevesearch/vellum v1.0.10/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k= github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM= -github.com/blevesearch/zapx/v11 v11.3.9 h1:y3ijS4h4MJdmQ07MHASxat4owAixreK2xdo76w9ncrw= -github.com/blevesearch/zapx/v11 v11.3.9/go.mod h1:jcAYnQwlr+LqD2vLjDWjWiZDXDXGFqPbpPDRTd3XmS4= +github.com/blevesearch/zapx/v11 v11.3.10 h1:hvjgj9tZ9DeIqBCxKhi70TtSZYMdcFn7gDb71Xo/fvk= +github.com/blevesearch/zapx/v11 v11.3.10/go.mod h1:0+gW+FaE48fNxoVtMY5ugtNHHof/PxCqh7CnhYdnMzQ= github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A= -github.com/blevesearch/zapx/v12 v12.3.9 h1:MXGLlZ03oxXH3DMJTZaBaRj2xb6t4wQVZeZK/wu1M6w= -github.com/blevesearch/zapx/v12 v12.3.9/go.mod h1:QXCMwmOkdLnMDgTN1P4CcuX5F851iUOtOwXbw0HMBYs= +github.com/blevesearch/zapx/v12 v12.3.10 h1:yHfj3vXLSYmmsBleJFROXuO08mS3L1qDCdDK81jDl8s= +github.com/blevesearch/zapx/v12 v12.3.10/go.mod h1:0yeZg6JhaGxITlsS5co73aqPtM04+ycnI6D1v0mhbCs= github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ= -github.com/blevesearch/zapx/v13 v13.3.9 h1:+VAz9V0VmllHXlZV4DCvfYj0nqaZHgF3MeEHwOyRBwQ= -github.com/blevesearch/zapx/v13 v13.3.9/go.mod h1:s+WjNp4WSDtrBVBpa37DUOd7S/Gr/jTZ7ST/MbCVj/0= +github.com/blevesearch/zapx/v13 v13.3.10 h1:0KY9tuxg06rXxOZHg3DwPJBjniSlqEgVpxIqMGahDE8= +github.com/blevesearch/zapx/v13 v13.3.10/go.mod h1:w2wjSDQ/WBVeEIvP0fvMJZAzDwqwIEzVPnCPrz93yAk= github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g= -github.com/blevesearch/zapx/v14 v14.3.9 h1:wuqxATgsTCNHM9xsOFOeFp8H2heZ/gMX/tsl9lRK8U4= -github.com/blevesearch/zapx/v14 v14.3.9/go.mod h1:MWZ4v8AzFBRurhDzkLvokFW8ljcq9Evm27mkWe8OGbM= +github.com/blevesearch/zapx/v14 v14.3.10 h1:SG6xlsL+W6YjhX5N3aEiL/2tcWh3DO75Bnz77pSwwKU= +github.com/blevesearch/zapx/v14 v14.3.10/go.mod h1:qqyuR0u230jN1yMmE4FIAuCxmahRQEOehF78m6oTgns= github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A= -github.com/blevesearch/zapx/v15 v15.3.12 h1:w/kU9aHyfMDEdwHGZzCiakC3HZ9z5gYlXaALDC4Dct8= -github.com/blevesearch/zapx/v15 v15.3.12/go.mod h1:tx53gDJS/7Oa3Je820cmVurqCuJ4dqdAy1kiDMV/IUo= +github.com/blevesearch/zapx/v15 v15.3.13 h1:6EkfaZiPlAxqXz0neniq35my6S48QI94W/wyhnpDHHQ= +github.com/blevesearch/zapx/v15 v15.3.13/go.mod h1:Turk/TNRKj9es7ZpKK95PS7f6D44Y7fAFy8F4LXQtGg= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -347,8 +347,8 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-co-op/gocron v1.31.1 h1:LZAuBlU0t3SPGUMJGhrJ6VuCc3CsrYzkzicygvVWlfA= github.com/go-co-op/gocron v1.31.1/go.mod h1:39f6KNSGVOU1LO/ZOoZfcSxwlsJDQOKSu8erN0SH48Y= -github.com/go-enry/go-enry/v2 v2.8.4 h1:QrY3hx/RiqCJJRbdU0MOcjfTM1a586J0WSooqdlJIhs= -github.com/go-enry/go-enry/v2 v2.8.4/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= +github.com/go-enry/go-enry/v2 v2.8.5 h1:jtYXblst2+d9k7ZgEgkv6Q5hKRKPf0qHRjt715BZEX4= +github.com/go-enry/go-enry/v2 v2.8.5/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= diff --git a/models/actions/runner_token.go b/models/actions/runner_token.go index fabd6c644c8..cf4e90f3f11 100644 --- a/models/actions/runner_token.go +++ b/models/actions/runner_token.go @@ -22,7 +22,7 @@ type ActionRunnerToken struct { Owner *user_model.User `xorm:"-"` RepoID int64 `xorm:"index"` // repo level runner, if orgid also is zero, then it's a global Repo *repo_model.Repository `xorm:"-"` - IsActive bool + IsActive bool // true means it can be used Created timeutil.TimeStamp `xorm:"created"` Updated timeutil.TimeStamp `xorm:"updated"` @@ -57,7 +57,7 @@ func UpdateRunnerToken(ctx context.Context, r *ActionRunnerToken, cols ...string return err } -// NewRunnerToken creates a new runner token +// NewRunnerToken creates a new active runner token and invalidate all old tokens func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { token, err := util.CryptoRandomString(40) if err != nil { @@ -66,17 +66,27 @@ func NewRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerTo runnerToken := &ActionRunnerToken{ OwnerID: ownerID, RepoID: repoID, - IsActive: false, + IsActive: true, Token: token, } - _, err = db.GetEngine(ctx).Insert(runnerToken) - return runnerToken, err + + return runnerToken, db.WithTx(ctx, func(ctx context.Context) error { + if _, err := db.GetEngine(ctx).Where("owner_id =? AND repo_id = ?", ownerID, repoID).Cols("is_active").Update(&ActionRunnerToken{ + IsActive: false, + }); err != nil { + return err + } + + _, err = db.GetEngine(ctx).Insert(runnerToken) + return err + }) } -// GetUnactivatedRunnerToken returns a unactivated runner token -func GetUnactivatedRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { +// GetLastestRunnerToken returns the latest runner token +func GetLastestRunnerToken(ctx context.Context, ownerID, repoID int64) (*ActionRunnerToken, error) { var runnerToken ActionRunnerToken - has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=? AND is_active=?", ownerID, repoID, false).OrderBy("id DESC").Get(&runnerToken) + has, err := db.GetEngine(ctx).Where("owner_id=? AND repo_id=?", ownerID, repoID). + OrderBy("id DESC").Get(&runnerToken) if err != nil { return nil, err } else if !has { diff --git a/models/actions/schedule.go b/models/actions/schedule.go index b0bc40dadc7..34d23f1c017 100644 --- a/models/actions/schedule.go +++ b/models/actions/schedule.go @@ -41,15 +41,15 @@ func init() { } // GetSchedulesMapByIDs returns the schedules by given id slice. -func GetSchedulesMapByIDs(ids []int64) (map[int64]*ActionSchedule, error) { +func GetSchedulesMapByIDs(ctx context.Context, ids []int64) (map[int64]*ActionSchedule, error) { schedules := make(map[int64]*ActionSchedule, len(ids)) - return schedules, db.GetEngine(db.DefaultContext).In("id", ids).Find(&schedules) + return schedules, db.GetEngine(ctx).In("id", ids).Find(&schedules) } // GetReposMapByIDs returns the repos by given id slice. -func GetReposMapByIDs(ids []int64) (map[int64]*repo_model.Repository, error) { +func GetReposMapByIDs(ctx context.Context, ids []int64) (map[int64]*repo_model.Repository, error) { repos := make(map[int64]*repo_model.Repository, len(ids)) - return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos) + return repos, db.GetEngine(ctx).In("id", ids).Find(&repos) } var cronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor) diff --git a/models/actions/schedule_spec_list.go b/models/actions/schedule_spec_list.go index d379490b4e9..2c017fdabc9 100644 --- a/models/actions/schedule_spec_list.go +++ b/models/actions/schedule_spec_list.go @@ -23,9 +23,9 @@ func (specs SpecList) GetScheduleIDs() []int64 { return ids.Values() } -func (specs SpecList) LoadSchedules() error { +func (specs SpecList) LoadSchedules(ctx context.Context) error { scheduleIDs := specs.GetScheduleIDs() - schedules, err := GetSchedulesMapByIDs(scheduleIDs) + schedules, err := GetSchedulesMapByIDs(ctx, scheduleIDs) if err != nil { return err } @@ -34,7 +34,7 @@ func (specs SpecList) LoadSchedules() error { } repoIDs := specs.GetRepoIDs() - repos, err := GetReposMapByIDs(repoIDs) + repos, err := GetReposMapByIDs(ctx, repoIDs) if err != nil { return err } @@ -95,7 +95,7 @@ func FindSpecs(ctx context.Context, opts FindSpecOptions) (SpecList, int64, erro return nil, 0, err } - if err := specs.LoadSchedules(); err != nil { + if err := specs.LoadSchedules(ctx); err != nil { return nil, 0, err } return specs, total, nil diff --git a/models/activities/action.go b/models/activities/action.go index 07c80534256..1bfd62438bf 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -140,7 +140,7 @@ func (at ActionType) InActions(actions ...string) bool { // used in template render. type Action struct { ID int64 `xorm:"pk autoincr"` - UserID int64 // Receiver user id. + UserID int64 `xorm:"INDEX"` // Receiver user id. OpType ActionType ActUserID int64 // Action user id. ActUser *user_model.User `xorm:"-"` @@ -208,91 +208,91 @@ func (a *Action) loadRepo(ctx context.Context) { } // GetActFullName gets the action's user full name. -func (a *Action) GetActFullName() string { - a.LoadActUser(db.DefaultContext) +func (a *Action) GetActFullName(ctx context.Context) string { + a.LoadActUser(ctx) return a.ActUser.FullName } // GetActUserName gets the action's user name. -func (a *Action) GetActUserName() string { - a.LoadActUser(db.DefaultContext) +func (a *Action) GetActUserName(ctx context.Context) string { + a.LoadActUser(ctx) return a.ActUser.Name } // ShortActUserName gets the action's user name trimmed to max 20 // chars. -func (a *Action) ShortActUserName() string { - return base.EllipsisString(a.GetActUserName(), 20) +func (a *Action) ShortActUserName(ctx context.Context) string { + return base.EllipsisString(a.GetActUserName(ctx), 20) } // GetDisplayName gets the action's display name based on DEFAULT_SHOW_FULL_NAME, or falls back to the username if it is blank. -func (a *Action) GetDisplayName() string { +func (a *Action) GetDisplayName(ctx context.Context) string { if setting.UI.DefaultShowFullName { - trimmedFullName := strings.TrimSpace(a.GetActFullName()) + trimmedFullName := strings.TrimSpace(a.GetActFullName(ctx)) if len(trimmedFullName) > 0 { return trimmedFullName } } - return a.ShortActUserName() + return a.ShortActUserName(ctx) } // GetDisplayNameTitle gets the action's display name used for the title (tooltip) based on DEFAULT_SHOW_FULL_NAME -func (a *Action) GetDisplayNameTitle() string { +func (a *Action) GetDisplayNameTitle(ctx context.Context) string { if setting.UI.DefaultShowFullName { - return a.ShortActUserName() + return a.ShortActUserName(ctx) } - return a.GetActFullName() + return a.GetActFullName(ctx) } // GetRepoUserName returns the name of the action repository owner. -func (a *Action) GetRepoUserName() string { - a.loadRepo(db.DefaultContext) +func (a *Action) GetRepoUserName(ctx context.Context) string { + a.loadRepo(ctx) return a.Repo.OwnerName } // ShortRepoUserName returns the name of the action repository owner // trimmed to max 20 chars. -func (a *Action) ShortRepoUserName() string { - return base.EllipsisString(a.GetRepoUserName(), 20) +func (a *Action) ShortRepoUserName(ctx context.Context) string { + return base.EllipsisString(a.GetRepoUserName(ctx), 20) } // GetRepoName returns the name of the action repository. -func (a *Action) GetRepoName() string { - a.loadRepo(db.DefaultContext) +func (a *Action) GetRepoName(ctx context.Context) string { + a.loadRepo(ctx) return a.Repo.Name } // ShortRepoName returns the name of the action repository // trimmed to max 33 chars. -func (a *Action) ShortRepoName() string { - return base.EllipsisString(a.GetRepoName(), 33) +func (a *Action) ShortRepoName(ctx context.Context) string { + return base.EllipsisString(a.GetRepoName(ctx), 33) } // GetRepoPath returns the virtual path to the action repository. -func (a *Action) GetRepoPath() string { - return path.Join(a.GetRepoUserName(), a.GetRepoName()) +func (a *Action) GetRepoPath(ctx context.Context) string { + return path.Join(a.GetRepoUserName(ctx), a.GetRepoName(ctx)) } // ShortRepoPath returns the virtual path to the action repository // trimmed to max 20 + 1 + 33 chars. -func (a *Action) ShortRepoPath() string { - return path.Join(a.ShortRepoUserName(), a.ShortRepoName()) +func (a *Action) ShortRepoPath(ctx context.Context) string { + return path.Join(a.ShortRepoUserName(ctx), a.ShortRepoName(ctx)) } // GetRepoLink returns relative link to action repository. -func (a *Action) GetRepoLink() string { +func (a *Action) GetRepoLink(ctx context.Context) string { // path.Join will skip empty strings - return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName()), url.PathEscape(a.GetRepoName())) + return path.Join(setting.AppSubURL, "/", url.PathEscape(a.GetRepoUserName(ctx)), url.PathEscape(a.GetRepoName(ctx))) } // GetRepoAbsoluteLink returns the absolute link to action repository. -func (a *Action) GetRepoAbsoluteLink() string { - return setting.AppURL + url.PathEscape(a.GetRepoUserName()) + "/" + url.PathEscape(a.GetRepoName()) +func (a *Action) GetRepoAbsoluteLink(ctx context.Context) string { + return setting.AppURL + url.PathEscape(a.GetRepoUserName(ctx)) + "/" + url.PathEscape(a.GetRepoName(ctx)) } // GetCommentHTMLURL returns link to action comment. -func (a *Action) GetCommentHTMLURL() string { - return a.getCommentHTMLURL(db.DefaultContext) +func (a *Action) GetCommentHTMLURL(ctx context.Context) string { + return a.getCommentHTMLURL(ctx) } func (a *Action) loadComment(ctx context.Context) (err error) { @@ -309,7 +309,7 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string { } _ = a.loadComment(ctx) if a.Comment != nil { - return a.Comment.HTMLURL() + return a.Comment.HTMLURL(ctx) } if len(a.GetIssueInfos()) == 0 { return "#" @@ -334,8 +334,8 @@ func (a *Action) getCommentHTMLURL(ctx context.Context) string { } // GetCommentLink returns link to action comment. -func (a *Action) GetCommentLink() string { - return a.getCommentLink(db.DefaultContext) +func (a *Action) GetCommentLink(ctx context.Context) string { + return a.getCommentLink(ctx) } func (a *Action) getCommentLink(ctx context.Context) string { @@ -344,7 +344,7 @@ func (a *Action) getCommentLink(ctx context.Context) string { } _ = a.loadComment(ctx) if a.Comment != nil { - return a.Comment.Link() + return a.Comment.Link(ctx) } if len(a.GetIssueInfos()) == 0 { return "#" @@ -374,8 +374,8 @@ func (a *Action) GetBranch() string { } // GetRefLink returns the action's ref link. -func (a *Action) GetRefLink() string { - return git.RefURL(a.GetRepoLink(), a.RefName) +func (a *Action) GetRefLink(ctx context.Context) string { + return git.RefURL(a.GetRepoLink(ctx), a.RefName) } // GetTag returns the action's repository tag. @@ -399,11 +399,10 @@ func (a *Action) GetIssueInfos() []string { return strings.SplitN(a.Content, "|", 3) } -// GetIssueTitle returns the title of first issue associated -// with the action. This function will be invoked in template so keep db.DefaultContext here -func (a *Action) GetIssueTitle() string { +// GetIssueTitle returns the title of first issue associated with the action. +func (a *Action) GetIssueTitle(ctx context.Context) string { index, _ := strconv.ParseInt(a.GetIssueInfos()[0], 10, 64) - issue, err := issues_model.GetIssueByIndex(db.DefaultContext, a.RepoID, index) + issue, err := issues_model.GetIssueByIndex(ctx, a.RepoID, index) if err != nil { log.Error("GetIssueByIndex: %v", err) return "500 when get issue" @@ -442,7 +441,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo") } - cond, err := activityQueryCondition(opts) + cond, err := activityQueryCondition(ctx, opts) if err != nil { return nil, 0, err } @@ -473,11 +472,11 @@ func ActivityReadable(user, doer *user_model.User) bool { doer != nil && (doer.IsAdmin || user.ID == doer.ID) } -func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { +func activityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) { cond := builder.NewCond() if opts.RequestedTeam != nil && opts.RequestedUser == nil { - org, err := user_model.GetUserByID(db.DefaultContext, opts.RequestedTeam.OrgID) + org, err := user_model.GetUserByID(ctx, opts.RequestedTeam.OrgID) if err != nil { return nil, err } @@ -525,7 +524,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { } if opts.RequestedTeam != nil { - env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(opts.RequestedTeam) + env := organization.OrgFromUser(opts.RequestedUser).AccessibleTeamReposEnv(ctx, opts.RequestedTeam) teamRepoIDs, err := env.RepoIDs(1, opts.RequestedUser.NumRepos) if err != nil { return nil, fmt.Errorf("GetTeamRepositories: %w", err) @@ -564,12 +563,12 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { } // DeleteOldActions deletes all old actions from database. -func DeleteOldActions(olderThan time.Duration) (err error) { +func DeleteOldActions(ctx context.Context, olderThan time.Duration) (err error) { if olderThan <= 0 { return nil } - _, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{}) + _, err = db.GetEngine(ctx).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Action{}) return err } @@ -679,8 +678,8 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error { } // NotifyWatchersActions creates batch of actions for every watcher. -func NotifyWatchersActions(acts []*Action) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func NotifyWatchersActions(ctx context.Context, acts []*Action) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/activities/action_test.go b/models/activities/action_test.go index 9a427408800..5467bd35fb8 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -24,7 +24,7 @@ func TestAction_GetRepoPath(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) action := &activities_model.Action{RepoID: repo.ID} - assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath()) + assert.Equal(t, path.Join(owner.Name, repo.Name), action.GetRepoPath(db.DefaultContext)) } func TestAction_GetRepoLink(t *testing.T) { @@ -35,9 +35,9 @@ func TestAction_GetRepoLink(t *testing.T) { action := &activities_model.Action{RepoID: repo.ID, CommentID: comment.ID} setting.AppSubURL = "/suburl" expected := path.Join(setting.AppSubURL, owner.Name, repo.Name) - assert.Equal(t, expected, action.GetRepoLink()) - assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink()) - assert.Equal(t, comment.HTMLURL(), action.GetCommentHTMLURL()) + assert.Equal(t, expected, action.GetRepoLink(db.DefaultContext)) + assert.Equal(t, repo.HTMLURL(), action.GetRepoAbsoluteLink(db.DefaultContext)) + assert.Equal(t, comment.HTMLURL(db.DefaultContext), action.GetCommentHTMLURL(db.DefaultContext)) } func TestGetFeeds(t *testing.T) { diff --git a/models/activities/main_test.go b/models/activities/main_test.go index 6be54db658b..43afb84ef15 100644 --- a/models/activities/main_test.go +++ b/models/activities/main_test.go @@ -4,7 +4,6 @@ package activities_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,7 +13,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/activities/notification.go b/models/activities/notification.go index ef263ef735c..7c794564b67 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -175,8 +175,8 @@ func CreateRepoTransferNotification(ctx context.Context, doer, newOwner *user_mo // CreateOrUpdateIssueNotifications creates an issue notification // for each watcher, or updates it if already exists // receiverID > 0 just send to receiver, else send to all watcher -func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, receiverID int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func CreateOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -435,21 +435,21 @@ func (n *Notification) loadUser(ctx context.Context) (err error) { } // GetRepo returns the repo of the notification -func (n *Notification) GetRepo() (*repo_model.Repository, error) { - return n.Repository, n.loadRepo(db.DefaultContext) +func (n *Notification) GetRepo(ctx context.Context) (*repo_model.Repository, error) { + return n.Repository, n.loadRepo(ctx) } // GetIssue returns the issue of the notification -func (n *Notification) GetIssue() (*issues_model.Issue, error) { - return n.Issue, n.loadIssue(db.DefaultContext) +func (n *Notification) GetIssue(ctx context.Context) (*issues_model.Issue, error) { + return n.Issue, n.loadIssue(ctx) } // HTMLURL formats a URL-string to the notification -func (n *Notification) HTMLURL() string { +func (n *Notification) HTMLURL(ctx context.Context) string { switch n.Source { case NotificationSourceIssue, NotificationSourcePullRequest: if n.Comment != nil { - return n.Comment.HTMLURL() + return n.Comment.HTMLURL(ctx) } return n.Issue.HTMLURL() case NotificationSourceCommit: @@ -461,11 +461,11 @@ func (n *Notification) HTMLURL() string { } // Link formats a relative URL-string to the notification -func (n *Notification) Link() string { +func (n *Notification) Link(ctx context.Context) string { switch n.Source { case NotificationSourceIssue, NotificationSourcePullRequest: if n.Comment != nil { - return n.Comment.Link() + return n.Comment.Link(ctx) } return n.Issue.Link() case NotificationSourceCommit: @@ -733,12 +733,12 @@ type UserIDCount struct { } // GetUIDsAndNotificationCounts between the two provided times -func GetUIDsAndNotificationCounts(since, until timeutil.TimeStamp) ([]UserIDCount, error) { +func GetUIDsAndNotificationCounts(ctx context.Context, since, until timeutil.TimeStamp) ([]UserIDCount, error) { sql := `SELECT user_id, count(*) AS count FROM notification ` + `WHERE user_id IN (SELECT user_id FROM notification WHERE updated_unix >= ? AND ` + `updated_unix < ?) AND status = ? GROUP BY user_id` var res []UserIDCount - return res, db.GetEngine(db.DefaultContext).SQL(sql, since, until, NotificationStatusUnread).Find(&res) + return res, db.GetEngine(ctx).SQL(sql, since, until, NotificationStatusUnread).Find(&res) } // SetIssueReadBy sets issue to be read by given user. diff --git a/models/activities/notification_test.go b/models/activities/notification_test.go index 2d4c369a99b..b90ce70536f 100644 --- a/models/activities/notification_test.go +++ b/models/activities/notification_test.go @@ -20,7 +20,7 @@ func TestCreateOrUpdateIssueNotifications(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) - assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(issue.ID, 0, 2, 0)) + assert.NoError(t, activities_model.CreateOrUpdateIssueNotifications(db.DefaultContext, issue.ID, 0, 2, 0)) // User 9 is inactive, thus notifications for user 1 and 4 are created notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{UserID: 1, IssueID: issue.ID}) @@ -50,7 +50,7 @@ func TestNotificationsForUser(t *testing.T) { func TestNotification_GetRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1}) - repo, err := notf.GetRepo() + repo, err := notf.GetRepo(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, repo, notf.Repository) assert.EqualValues(t, notf.RepoID, repo.ID) @@ -59,7 +59,7 @@ func TestNotification_GetRepo(t *testing.T) { func TestNotification_GetIssue(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) notf := unittest.AssertExistsAndLoadBean(t, &activities_model.Notification{RepoID: 1}) - issue, err := notf.GetIssue() + issue, err := notf.GetIssue(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, issue, notf.Issue) assert.EqualValues(t, notf.IssueID, issue.ID) diff --git a/models/activities/repo_activity.go b/models/activities/repo_activity.go index 509f9caaf3e..91f5ac12bdc 100644 --- a/models/activities/repo_activity.go +++ b/models/activities/repo_activity.go @@ -342,7 +342,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from // Published releases list sess := releasesForActivityStatement(ctx, repoID, fromTime) - sess.OrderBy("release.created_unix DESC") + sess.OrderBy("`release`.created_unix DESC") stats.PublishedReleases = make([]*repo_model.Release, 0) if err = sess.Find(&stats.PublishedReleases); err != nil { return err @@ -350,7 +350,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from // Published releases authors sess = releasesForActivityStatement(ctx, repoID, fromTime) - if _, err = sess.Select("count(distinct release.publisher_id) as `count`").Table("release").Get(&count); err != nil { + if _, err = sess.Select("count(distinct `release`.publisher_id) as `count`").Table("release").Get(&count); err != nil { return err } stats.PublishedReleaseAuthorCount = count @@ -359,7 +359,7 @@ func (stats *ActivityStats) FillReleases(ctx context.Context, repoID int64, from } func releasesForActivityStatement(ctx context.Context, repoID int64, fromTime time.Time) *xorm.Session { - return db.GetEngine(ctx).Where("release.repo_id = ?", repoID). - And("release.is_draft = ?", false). - And("release.created_unix >= ?", fromTime.Unix()) + return db.GetEngine(ctx).Where("`release`.repo_id = ?", repoID). + And("`release`.is_draft = ?", false). + And("`release`.created_unix >= ?", fromTime.Unix()) } diff --git a/models/activities/statistic.go b/models/activities/statistic.go index 9d379cd0c4f..ea13f3ed5c8 100644 --- a/models/activities/statistic.go +++ b/models/activities/statistic.go @@ -4,6 +4,8 @@ package activities import ( + "context" + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" @@ -47,12 +49,12 @@ type IssueByRepositoryCount struct { } // GetStatistic returns the database statistics -func GetStatistic() (stats Statistic) { - e := db.GetEngine(db.DefaultContext) - stats.Counter.User = user_model.CountUsers(nil) - stats.Counter.Org, _ = organization.CountOrgs(organization.FindOrgOptions{IncludePrivate: true}) +func GetStatistic(ctx context.Context) (stats Statistic) { + e := db.GetEngine(ctx) + stats.Counter.User = user_model.CountUsers(ctx, nil) + stats.Counter.Org, _ = organization.CountOrgs(ctx, organization.FindOrgOptions{IncludePrivate: true}) stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey)) - stats.Counter.Repo, _ = repo_model.CountRepositories(db.DefaultContext, repo_model.CountRepositoryOptions{}) + stats.Counter.Repo, _ = repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{}) stats.Counter.Watch, _ = e.Count(new(repo_model.Watch)) stats.Counter.Star, _ = e.Count(new(repo_model.Star)) stats.Counter.Access, _ = e.Count(new(access_model.Access)) diff --git a/models/activities/user_heatmap.go b/models/activities/user_heatmap.go index 33207995267..78fcd76d43a 100644 --- a/models/activities/user_heatmap.go +++ b/models/activities/user_heatmap.go @@ -4,6 +4,8 @@ package activities import ( + "context" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" @@ -18,16 +20,16 @@ type UserHeatmapData struct { } // GetUserHeatmapDataByUser returns an array of UserHeatmapData -func GetUserHeatmapDataByUser(user, doer *user_model.User) ([]*UserHeatmapData, error) { - return getUserHeatmapData(user, nil, doer) +func GetUserHeatmapDataByUser(ctx context.Context, user, doer *user_model.User) ([]*UserHeatmapData, error) { + return getUserHeatmapData(ctx, user, nil, doer) } // GetUserHeatmapDataByUserTeam returns an array of UserHeatmapData -func GetUserHeatmapDataByUserTeam(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) { - return getUserHeatmapData(user, team, doer) +func GetUserHeatmapDataByUserTeam(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) { + return getUserHeatmapData(ctx, user, team, doer) } -func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) { +func getUserHeatmapData(ctx context.Context, user *user_model.User, team *organization.Team, doer *user_model.User) ([]*UserHeatmapData, error) { hdata := make([]*UserHeatmapData, 0) if !ActivityReadable(user, doer) { @@ -45,7 +47,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us groupByName = groupBy } - cond, err := activityQueryCondition(GetFeedsOptions{ + cond, err := activityQueryCondition(ctx, GetFeedsOptions{ RequestedUser: user, RequestedTeam: team, Actor: doer, @@ -60,7 +62,7 @@ func getUserHeatmapData(user *user_model.User, team *organization.Team, doer *us return nil, err } - return hdata, db.GetEngine(db.DefaultContext). + return hdata, db.GetEngine(ctx). Select(groupBy+" AS timestamp, count(user_id) as contributions"). Table("action"). Where(cond). diff --git a/models/activities/user_heatmap_test.go b/models/activities/user_heatmap_test.go index 98df7b38aa0..657f0f043cf 100644 --- a/models/activities/user_heatmap_test.go +++ b/models/activities/user_heatmap_test.go @@ -83,7 +83,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) { assert.NoError(t, err) // Get the heatmap and compare - heatmap, err := activities_model.GetUserHeatmapDataByUser(user, doer) + heatmap, err := activities_model.GetUserHeatmapDataByUser(db.DefaultContext, user, doer) var contributions int for _, hm := range heatmap { contributions += int(hm.Contributions) diff --git a/models/admin/task.go b/models/admin/task.go index 8aa397ad351..c8bc95f9814 100644 --- a/models/admin/task.go +++ b/models/admin/task.go @@ -48,11 +48,7 @@ type TranslatableMessage struct { } // LoadRepo loads repository of the task -func (task *Task) LoadRepo() error { - return task.loadRepo(db.DefaultContext) -} - -func (task *Task) loadRepo(ctx context.Context) error { +func (task *Task) LoadRepo(ctx context.Context) error { if task.Repo != nil { return nil } @@ -70,13 +66,13 @@ func (task *Task) loadRepo(ctx context.Context) error { } // LoadDoer loads do user -func (task *Task) LoadDoer() error { +func (task *Task) LoadDoer(ctx context.Context) error { if task.Doer != nil { return nil } var doer user_model.User - has, err := db.GetEngine(db.DefaultContext).ID(task.DoerID).Get(&doer) + has, err := db.GetEngine(ctx).ID(task.DoerID).Get(&doer) if err != nil { return err } else if !has { @@ -90,13 +86,13 @@ func (task *Task) LoadDoer() error { } // LoadOwner loads owner user -func (task *Task) LoadOwner() error { +func (task *Task) LoadOwner(ctx context.Context) error { if task.Owner != nil { return nil } var owner user_model.User - has, err := db.GetEngine(db.DefaultContext).ID(task.OwnerID).Get(&owner) + has, err := db.GetEngine(ctx).ID(task.OwnerID).Get(&owner) if err != nil { return err } else if !has { @@ -110,8 +106,8 @@ func (task *Task) LoadOwner() error { } // UpdateCols updates some columns -func (task *Task) UpdateCols(cols ...string) error { - _, err := db.GetEngine(db.DefaultContext).ID(task.ID).Cols(cols...).Update(task) +func (task *Task) UpdateCols(ctx context.Context, cols ...string) error { + _, err := db.GetEngine(ctx).ID(task.ID).Cols(cols...).Update(task) return err } @@ -169,12 +165,12 @@ func (err ErrTaskDoesNotExist) Unwrap() error { } // GetMigratingTask returns the migrating task by repo's id -func GetMigratingTask(repoID int64) (*Task, error) { +func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) { task := Task{ RepoID: repoID, Type: structs.TaskTypeMigrateRepo, } - has, err := db.GetEngine(db.DefaultContext).Get(&task) + has, err := db.GetEngine(ctx).Get(&task) if err != nil { return nil, err } else if !has { @@ -184,13 +180,13 @@ func GetMigratingTask(repoID int64) (*Task, error) { } // GetMigratingTaskByID returns the migrating task by repo's id -func GetMigratingTaskByID(id, doerID int64) (*Task, *migration.MigrateOptions, error) { +func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) { task := Task{ ID: id, DoerID: doerID, Type: structs.TaskTypeMigrateRepo, } - has, err := db.GetEngine(db.DefaultContext).Get(&task) + has, err := db.GetEngine(ctx).Get(&task) if err != nil { return nil, nil, err } else if !has { @@ -205,12 +201,12 @@ func GetMigratingTaskByID(id, doerID int64) (*Task, *migration.MigrateOptions, e } // CreateTask creates a task on database -func CreateTask(task *Task) error { - return db.Insert(db.DefaultContext, task) +func CreateTask(ctx context.Context, task *Task) error { + return db.Insert(ctx, task) } // FinishMigrateTask updates database when migrate task finished -func FinishMigrateTask(task *Task) error { +func FinishMigrateTask(ctx context.Context, task *Task) error { task.Status = structs.TaskStatusFinished task.EndTime = timeutil.TimeStampNow() @@ -231,6 +227,6 @@ func FinishMigrateTask(task *Task) error { } task.PayloadContent = string(confBytes) - _, err = db.GetEngine(db.DefaultContext).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task) + _, err = db.GetEngine(ctx).ID(task.ID).Cols("status", "end_time", "payload_content").Update(task) return err } diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index be019184eb5..21d271bed42 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -88,14 +88,14 @@ func ListGPGKeys(ctx context.Context, uid int64, listOptions db.ListOptions) ([] } // CountUserGPGKeys return number of gpg keys a user own -func CountUserGPGKeys(userID int64) (int64, error) { - return db.GetEngine(db.DefaultContext).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{}) +func CountUserGPGKeys(ctx context.Context, userID int64) (int64, error) { + return db.GetEngine(ctx).Where("owner_id=? AND primary_key_id=''", userID).Count(&GPGKey{}) } // GetGPGKeyByID returns public key by given ID. -func GetGPGKeyByID(keyID int64) (*GPGKey, error) { +func GetGPGKeyByID(ctx context.Context, keyID int64) (*GPGKey, error) { key := new(GPGKey) - has, err := db.GetEngine(db.DefaultContext).ID(keyID).Get(key) + has, err := db.GetEngine(ctx).ID(keyID).Get(key) if err != nil { return nil, err } else if !has { @@ -105,9 +105,9 @@ func GetGPGKeyByID(keyID int64) (*GPGKey, error) { } // GetGPGKeysByKeyID returns public key by given ID. -func GetGPGKeysByKeyID(keyID string) ([]*GPGKey, error) { +func GetGPGKeysByKeyID(ctx context.Context, keyID string) ([]*GPGKey, error) { keys := make([]*GPGKey, 0, 1) - return keys, db.GetEngine(db.DefaultContext).Where("key_id=?", keyID).Find(&keys) + return keys, db.GetEngine(ctx).Where("key_id=?", keyID).Find(&keys) } // GPGKeyToEntity retrieve the imported key and the traducted entity @@ -144,7 +144,7 @@ func parseSubGPGKey(ownerID int64, primaryID string, pubkey *packet.PublicKey, e } // parseGPGKey parse a PrimaryKey entity (primary key + subs keys + self-signature) -func parseGPGKey(ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, error) { +func parseGPGKey(ctx context.Context, ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, error) { pubkey := e.PrimaryKey expiry := getExpiryTime(e) @@ -159,7 +159,7 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, erro } // Check emails - userEmails, err := user_model.GetEmailAddresses(ownerID) + userEmails, err := user_model.GetEmailAddresses(ctx, ownerID) if err != nil { return nil, err } @@ -224,8 +224,8 @@ func deleteGPGKey(ctx context.Context, keyID string) (int64, error) { } // DeleteGPGKey deletes GPG key information in database. -func DeleteGPGKey(doer *user_model.User, id int64) (err error) { - key, err := GetGPGKeyByID(id) +func DeleteGPGKey(ctx context.Context, doer *user_model.User, id int64) (err error) { + key, err := GetGPGKeyByID(ctx, id) if err != nil { if IsErrGPGKeyNotExist(err) { return nil @@ -238,7 +238,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) { return ErrGPGKeyAccessDenied{doer.ID, key.ID} } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -251,7 +251,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) { return committer.Commit() } -func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) { +func checkKeyEmails(ctx context.Context, email string, keys ...*GPGKey) (bool, string) { uid := int64(0) var userEmails []*user_model.EmailAddress var user *user_model.User @@ -263,10 +263,10 @@ func checkKeyEmails(email string, keys ...*GPGKey) (bool, string) { } if key.Verified && key.OwnerID != 0 { if uid != key.OwnerID { - userEmails, _ = user_model.GetEmailAddresses(key.OwnerID) + userEmails, _ = user_model.GetEmailAddresses(ctx, key.OwnerID) uid = key.OwnerID user = &user_model.User{ID: uid} - _, _ = user_model.GetUser(user) + _, _ = user_model.GetUser(ctx, user) } for _, e := range userEmails { if e.IsActivated && (email == "" || strings.EqualFold(e.Email, email)) { diff --git a/models/asymkey/gpg_key_add.go b/models/asymkey/gpg_key_add.go index eb4027b3a44..11124b13665 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -66,13 +66,13 @@ func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) { } // AddGPGKey adds new public key to database. -func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, error) { +func AddGPGKey(ctx context.Context, ownerID int64, content, token, signature string) ([]*GPGKey, error) { ekeys, err := checkArmoredGPGKeyString(content) if err != nil { return nil, err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } @@ -153,7 +153,7 @@ func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, erro // Get DB session - key, err := parseGPGKey(ownerID, ekey, verified) + key, err := parseGPGKey(ctx, ownerID, ekey, verified) if err != nil { return nil, err } diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 65af0bc9453..8ac43644045 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -125,7 +125,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific // If this a SSH signature handle it differently if strings.HasPrefix(c.Signature.Signature, "-----BEGIN SSH SIGNATURE-----") { - return ParseCommitWithSSHSignature(c, committer) + return ParseCommitWithSSHSignature(ctx, c, committer) } // Parsing signature @@ -150,6 +150,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific // First check if the sig has a keyID and if so just look at that if commitVerification := hashAndVerifyForKeyID( + ctx, sig, c.Signature.Payload, committer, @@ -165,7 +166,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific // Now try to associate the signature with the committer, if present if committer.ID != 0 { - keys, err := ListGPGKeys(db.DefaultContext, committer.ID, db.ListOptions{}) + keys, err := ListGPGKeys(ctx, committer.ID, db.ListOptions{}) if err != nil { // Skipping failed to get gpg keys of user log.Error("ListGPGKeys: %v", err) return &CommitVerification{ @@ -175,7 +176,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific } } - committerEmailAddresses, _ := user_model.GetEmailAddresses(committer.ID) + committerEmailAddresses, _ := user_model.GetEmailAddresses(ctx, committer.ID) activated := false for _, e := range committerEmailAddresses { if e.IsActivated && strings.EqualFold(e.Email, c.Committer.Email) { @@ -222,7 +223,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific } if err := gpgSettings.LoadPublicKeyContent(); err != nil { log.Error("Error getting default signing key: %s %v", gpgSettings.KeyID, err) - } else if commitVerification := verifyWithGPGSettings(&gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { + } else if commitVerification := verifyWithGPGSettings(ctx, &gpgSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { if commitVerification.Reason == BadSignature { defaultReason = BadSignature } else { @@ -237,7 +238,7 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific } else if defaultGPGSettings == nil { log.Warn("Unable to get defaultGPGSettings for unattached commit: %s", c.ID.String()) } else if defaultGPGSettings.Sign { - if commitVerification := verifyWithGPGSettings(defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { + if commitVerification := verifyWithGPGSettings(ctx, defaultGPGSettings, sig, c.Signature.Payload, committer, keyID); commitVerification != nil { if commitVerification.Reason == BadSignature { defaultReason = BadSignature } else { @@ -257,9 +258,9 @@ func ParseCommitWithSignature(ctx context.Context, c *git.Commit) *CommitVerific } } -func verifyWithGPGSettings(gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification { +func verifyWithGPGSettings(ctx context.Context, gpgSettings *git.GPGSettings, sig *packet.Signature, payload string, committer *user_model.User, keyID string) *CommitVerification { // First try to find the key in the db - if commitVerification := hashAndVerifyForKeyID(sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil { + if commitVerification := hashAndVerifyForKeyID(ctx, sig, payload, committer, gpgSettings.KeyID, gpgSettings.Name, gpgSettings.Email); commitVerification != nil { return commitVerification } @@ -387,11 +388,11 @@ func hashAndVerifyWithSubKeysCommitVerification(sig *packet.Signature, payload s return nil } -func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification { +func hashAndVerifyForKeyID(ctx context.Context, sig *packet.Signature, payload string, committer *user_model.User, keyID, name, email string) *CommitVerification { if keyID == "" { return nil } - keys, err := GetGPGKeysByKeyID(keyID) + keys, err := GetGPGKeysByKeyID(ctx, keyID) if err != nil { log.Error("GetGPGKeysByKeyID: %v", err) return &CommitVerification{ @@ -406,7 +407,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use for _, key := range keys { var primaryKeys []*GPGKey if key.PrimaryKeyID != "" { - primaryKeys, err = GetGPGKeysByKeyID(key.PrimaryKeyID) + primaryKeys, err = GetGPGKeysByKeyID(ctx, key.PrimaryKeyID) if err != nil { log.Error("GetGPGKeysByKeyID: %v", err) return &CommitVerification{ @@ -417,7 +418,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use } } - activated, email := checkKeyEmails(email, append([]*GPGKey{key}, primaryKeys...)...) + activated, email := checkKeyEmails(ctx, email, append([]*GPGKey{key}, primaryKeys...)...) if !activated { continue } @@ -427,7 +428,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use Email: email, } if key.OwnerID != 0 { - owner, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID) + owner, err := user_model.GetUserByID(ctx, key.OwnerID) if err == nil { signer = owner } else if !user_model.IsErrUserNotExist(err) { diff --git a/models/asymkey/gpg_key_test.go b/models/asymkey/gpg_key_test.go index 6a0f9c61444..dee74bc281d 100644 --- a/models/asymkey/gpg_key_test.go +++ b/models/asymkey/gpg_key_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" @@ -228,7 +229,7 @@ Q0KHb+QcycSgbDx0ZAvdIacuKvBBcbxrsmFUI4LR+oIup0G9gUc0roPvr014jYQL =zHo9 -----END PGP PUBLIC KEY BLOCK-----` - keys, err := AddGPGKey(1, testEmailWithUpperCaseLetters, "", "") + keys, err := AddGPGKey(db.DefaultContext, 1, testEmailWithUpperCaseLetters, "", "") assert.NoError(t, err) if assert.NotEmpty(t, keys) { key := keys[0] diff --git a/models/asymkey/main_test.go b/models/asymkey/main_test.go index 701722be12e..be71f848d9d 100644 --- a/models/asymkey/main_test.go +++ b/models/asymkey/main_test.go @@ -4,7 +4,6 @@ package asymkey import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -12,7 +11,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), FixtureFiles: []string{ "gpg_key.yml", "public_key.yml", diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index 77803d6709e..f0a3a77eaff 100644 --- a/models/asymkey/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -117,7 +117,7 @@ func appendAuthorizedKeysToFile(keys ...*PublicKey) error { // RewriteAllPublicKeys removes any authorized key and rewrite all keys from database again. // Note: db.GetEngine(db.DefaultContext).Iterate does not get latest data after insert/delete, so we have to call this function // outside any session scope independently. -func RewriteAllPublicKeys() error { +func RewriteAllPublicKeys(ctx context.Context) error { // Don't rewrite key if internal server if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedKeysFile { return nil @@ -165,7 +165,7 @@ func RewriteAllPublicKeys() error { } } - if err := RegeneratePublicKeys(db.DefaultContext, t); err != nil { + if err := RegeneratePublicKeys(ctx, t); err != nil { return err } diff --git a/models/asymkey/ssh_key_commit_verification.go b/models/asymkey/ssh_key_commit_verification.go index af73637c4a8..80931c9af46 100644 --- a/models/asymkey/ssh_key_commit_verification.go +++ b/models/asymkey/ssh_key_commit_verification.go @@ -5,6 +5,7 @@ package asymkey import ( "bytes" + "context" "fmt" "strings" @@ -17,7 +18,7 @@ import ( ) // ParseCommitWithSSHSignature check if signature is good against keystore. -func ParseCommitWithSSHSignature(c *git.Commit, committer *user_model.User) *CommitVerification { +func ParseCommitWithSSHSignature(ctx context.Context, c *git.Commit, committer *user_model.User) *CommitVerification { // Now try to associate the signature with the committer, if present if committer.ID != 0 { keys, err := ListPublicKeys(committer.ID, db.ListOptions{}) @@ -30,7 +31,7 @@ func ParseCommitWithSSHSignature(c *git.Commit, committer *user_model.User) *Com } } - committerEmailAddresses, err := user_model.GetEmailAddresses(committer.ID) + committerEmailAddresses, err := user_model.GetEmailAddresses(ctx, committer.ID) if err != nil { log.Error("GetEmailAddresses: %v", err) } diff --git a/models/asymkey/ssh_key_principals.go b/models/asymkey/ssh_key_principals.go index 6d43437ec10..150b77c7b20 100644 --- a/models/asymkey/ssh_key_principals.go +++ b/models/asymkey/ssh_key_principals.go @@ -4,6 +4,7 @@ package asymkey import ( + "context" "fmt" "strings" @@ -63,7 +64,7 @@ func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*Public } // CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines -func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, err error) { +func CheckPrincipalKeyString(ctx context.Context, user *user_model.User, content string) (_ string, err error) { if setting.SSH.Disabled { return "", db.ErrSSHDisabled{} } @@ -80,7 +81,7 @@ func CheckPrincipalKeyString(user *user_model.User, content string) (_ string, e case "anything": return content, nil case "email": - emails, err := user_model.GetEmailAddresses(user.ID) + emails, err := user_model.GetEmailAddresses(ctx, user.ID) if err != nil { return "", err } diff --git a/models/auth/main_test.go b/models/auth/main_test.go index f8cbf3bd546..d772ea6b1c8 100644 --- a/models/auth/main_test.go +++ b/models/auth/main_test.go @@ -4,7 +4,6 @@ package auth_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -17,7 +16,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/auth/session.go b/models/auth/session.go index b60e6a903b9..28f25170eec 100644 --- a/models/auth/session.go +++ b/models/auth/session.go @@ -4,6 +4,7 @@ package auth import ( + "context" "fmt" "code.gitea.io/gitea/models/db" @@ -22,8 +23,8 @@ func init() { } // UpdateSession updates the session with provided id -func UpdateSession(key string, data []byte) error { - _, err := db.GetEngine(db.DefaultContext).ID(key).Update(&Session{ +func UpdateSession(ctx context.Context, key string, data []byte) error { + _, err := db.GetEngine(ctx).ID(key).Update(&Session{ Data: data, Expiry: timeutil.TimeStampNow(), }) @@ -31,12 +32,12 @@ func UpdateSession(key string, data []byte) error { } // ReadSession reads the data for the provided session -func ReadSession(key string) (*Session, error) { +func ReadSession(ctx context.Context, key string) (*Session, error) { session := Session{ Key: key, } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } @@ -55,24 +56,24 @@ func ReadSession(key string) (*Session, error) { } // ExistSession checks if a session exists -func ExistSession(key string) (bool, error) { +func ExistSession(ctx context.Context, key string) (bool, error) { session := Session{ Key: key, } - return db.GetEngine(db.DefaultContext).Get(&session) + return db.GetEngine(ctx).Get(&session) } // DestroySession destroys a session -func DestroySession(key string) error { - _, err := db.GetEngine(db.DefaultContext).Delete(&Session{ +func DestroySession(ctx context.Context, key string) error { + _, err := db.GetEngine(ctx).Delete(&Session{ Key: key, }) return err } // RegenerateSession regenerates a session from the old id -func RegenerateSession(oldKey, newKey string) (*Session, error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func RegenerateSession(ctx context.Context, oldKey, newKey string) (*Session, error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } @@ -114,12 +115,12 @@ func RegenerateSession(oldKey, newKey string) (*Session, error) { } // CountSessions returns the number of sessions -func CountSessions() (int64, error) { - return db.GetEngine(db.DefaultContext).Count(&Session{}) +func CountSessions(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Count(&Session{}) } // CleanupSessions cleans up expired sessions -func CleanupSessions(maxLifetime int64) error { - _, err := db.GetEngine(db.DefaultContext).Where("expiry <= ?", timeutil.TimeStampNow().Add(-maxLifetime)).Delete(&Session{}) +func CleanupSessions(ctx context.Context, maxLifetime int64) error { + _, err := db.GetEngine(ctx).Where("expiry <= ?", timeutil.TimeStampNow().Add(-maxLifetime)).Delete(&Session{}) return err } diff --git a/models/auth/token.go b/models/auth/token.go index fed03803d56..8abcc622bc8 100644 --- a/models/auth/token.go +++ b/models/auth/token.go @@ -5,6 +5,7 @@ package auth import ( + "context" "crypto/subtle" "encoding/hex" "fmt" @@ -95,7 +96,7 @@ func init() { } // NewAccessToken creates new access token. -func NewAccessToken(t *AccessToken) error { +func NewAccessToken(ctx context.Context, t *AccessToken) error { salt, err := util.CryptoRandomString(10) if err != nil { return err @@ -108,7 +109,7 @@ func NewAccessToken(t *AccessToken) error { t.Token = hex.EncodeToString(token) t.TokenHash = HashToken(t.Token, t.TokenSalt) t.TokenLastEight = t.Token[len(t.Token)-8:] - _, err = db.GetEngine(db.DefaultContext).Insert(t) + _, err = db.GetEngine(ctx).Insert(t) return err } @@ -137,7 +138,7 @@ func getAccessTokenIDFromCache(token string) int64 { } // GetAccessTokenBySHA returns access token by given token value -func GetAccessTokenBySHA(token string) (*AccessToken, error) { +func GetAccessTokenBySHA(ctx context.Context, token string) (*AccessToken, error) { if token == "" { return nil, ErrAccessTokenEmpty{} } @@ -158,7 +159,7 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) { TokenLastEight: lastEight, } // Re-get the token from the db in case it has been deleted in the intervening period - has, err := db.GetEngine(db.DefaultContext).ID(id).Get(accessToken) + has, err := db.GetEngine(ctx).ID(id).Get(accessToken) if err != nil { return nil, err } @@ -169,7 +170,7 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) { } var tokens []AccessToken - err := db.GetEngine(db.DefaultContext).Table(&AccessToken{}).Where("token_last_eight = ?", lastEight).Find(&tokens) + err := db.GetEngine(ctx).Table(&AccessToken{}).Where("token_last_eight = ?", lastEight).Find(&tokens) if err != nil { return nil, err } else if len(tokens) == 0 { @@ -189,8 +190,8 @@ func GetAccessTokenBySHA(token string) (*AccessToken, error) { } // AccessTokenByNameExists checks if a token name has been used already by a user. -func AccessTokenByNameExists(token *AccessToken) (bool, error) { - return db.GetEngine(db.DefaultContext).Table("access_token").Where("name = ?", token.Name).And("uid = ?", token.UID).Exist() +func AccessTokenByNameExists(ctx context.Context, token *AccessToken) (bool, error) { + return db.GetEngine(ctx).Table("access_token").Where("name = ?", token.Name).And("uid = ?", token.UID).Exist() } // ListAccessTokensOptions contain filter options @@ -201,8 +202,8 @@ type ListAccessTokensOptions struct { } // ListAccessTokens returns a list of access tokens belongs to given user. -func ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, error) { - sess := db.GetEngine(db.DefaultContext).Where("uid=?", opts.UserID) +func ListAccessTokens(ctx context.Context, opts ListAccessTokensOptions) ([]*AccessToken, error) { + sess := db.GetEngine(ctx).Where("uid=?", opts.UserID) if len(opts.Name) != 0 { sess = sess.Where("name=?", opts.Name) @@ -222,14 +223,14 @@ func ListAccessTokens(opts ListAccessTokensOptions) ([]*AccessToken, error) { } // UpdateAccessToken updates information of access token. -func UpdateAccessToken(t *AccessToken) error { - _, err := db.GetEngine(db.DefaultContext).ID(t.ID).AllCols().Update(t) +func UpdateAccessToken(ctx context.Context, t *AccessToken) error { + _, err := db.GetEngine(ctx).ID(t.ID).AllCols().Update(t) return err } // CountAccessTokens count access tokens belongs to given user by options -func CountAccessTokens(opts ListAccessTokensOptions) (int64, error) { - sess := db.GetEngine(db.DefaultContext).Where("uid=?", opts.UserID) +func CountAccessTokens(ctx context.Context, opts ListAccessTokensOptions) (int64, error) { + sess := db.GetEngine(ctx).Where("uid=?", opts.UserID) if len(opts.Name) != 0 { sess = sess.Where("name=?", opts.Name) } @@ -237,8 +238,8 @@ func CountAccessTokens(opts ListAccessTokensOptions) (int64, error) { } // DeleteAccessTokenByID deletes access token by given ID. -func DeleteAccessTokenByID(id, userID int64) error { - cnt, err := db.GetEngine(db.DefaultContext).ID(id).Delete(&AccessToken{ +func DeleteAccessTokenByID(ctx context.Context, id, userID int64) error { + cnt, err := db.GetEngine(ctx).ID(id).Delete(&AccessToken{ UID: userID, }) if err != nil { diff --git a/models/auth/token_test.go b/models/auth/token_test.go index 8a1e6649502..72c937ffd6a 100644 --- a/models/auth/token_test.go +++ b/models/auth/token_test.go @@ -7,6 +7,7 @@ import ( "testing" auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -18,7 +19,7 @@ func TestNewAccessToken(t *testing.T) { UID: 3, Name: "Token C", } - assert.NoError(t, auth_model.NewAccessToken(token)) + assert.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token)) unittest.AssertExistsAndLoadBean(t, token) invalidToken := &auth_model.AccessToken{ @@ -26,7 +27,7 @@ func TestNewAccessToken(t *testing.T) { UID: 2, Name: "Token F", } - assert.Error(t, auth_model.NewAccessToken(invalidToken)) + assert.Error(t, auth_model.NewAccessToken(db.DefaultContext, invalidToken)) } func TestAccessTokenByNameExists(t *testing.T) { @@ -39,16 +40,16 @@ func TestAccessTokenByNameExists(t *testing.T) { } // Check to make sure it doesn't exists already - exist, err := auth_model.AccessTokenByNameExists(token) + exist, err := auth_model.AccessTokenByNameExists(db.DefaultContext, token) assert.NoError(t, err) assert.False(t, exist) // Save it to the database - assert.NoError(t, auth_model.NewAccessToken(token)) + assert.NoError(t, auth_model.NewAccessToken(db.DefaultContext, token)) unittest.AssertExistsAndLoadBean(t, token) // This token must be found by name in the DB now - exist, err = auth_model.AccessTokenByNameExists(token) + exist, err = auth_model.AccessTokenByNameExists(db.DefaultContext, token) assert.NoError(t, err) assert.True(t, exist) @@ -59,32 +60,32 @@ func TestAccessTokenByNameExists(t *testing.T) { // Name matches but different user ID, this shouldn't exists in the // database - exist, err = auth_model.AccessTokenByNameExists(user4Token) + exist, err = auth_model.AccessTokenByNameExists(db.DefaultContext, user4Token) assert.NoError(t, err) assert.False(t, exist) } func TestGetAccessTokenBySHA(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - token, err := auth_model.GetAccessTokenBySHA("d2c6c1ba3890b309189a8e618c72a162e4efbf36") + token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "d2c6c1ba3890b309189a8e618c72a162e4efbf36") assert.NoError(t, err) assert.Equal(t, int64(1), token.UID) assert.Equal(t, "Token A", token.Name) assert.Equal(t, "2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f", token.TokenHash) assert.Equal(t, "e4efbf36", token.TokenLastEight) - _, err = auth_model.GetAccessTokenBySHA("notahash") + _, err = auth_model.GetAccessTokenBySHA(db.DefaultContext, "notahash") assert.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenNotExist(err)) - _, err = auth_model.GetAccessTokenBySHA("") + _, err = auth_model.GetAccessTokenBySHA(db.DefaultContext, "") assert.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenEmpty(err)) } func TestListAccessTokens(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 1}) + tokens, err := auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 1}) assert.NoError(t, err) if assert.Len(t, tokens, 2) { assert.Equal(t, int64(1), tokens[0].UID) @@ -93,39 +94,39 @@ func TestListAccessTokens(t *testing.T) { assert.Contains(t, []string{tokens[0].Name, tokens[1].Name}, "Token B") } - tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 2}) + tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 2}) assert.NoError(t, err) if assert.Len(t, tokens, 1) { assert.Equal(t, int64(2), tokens[0].UID) assert.Equal(t, "Token A", tokens[0].Name) } - tokens, err = auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: 100}) + tokens, err = auth_model.ListAccessTokens(db.DefaultContext, auth_model.ListAccessTokensOptions{UserID: 100}) assert.NoError(t, err) assert.Empty(t, tokens) } func TestUpdateAccessToken(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c") + token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c") assert.NoError(t, err) token.Name = "Token Z" - assert.NoError(t, auth_model.UpdateAccessToken(token)) + assert.NoError(t, auth_model.UpdateAccessToken(db.DefaultContext, token)) unittest.AssertExistsAndLoadBean(t, token) } func TestDeleteAccessTokenByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - token, err := auth_model.GetAccessTokenBySHA("4c6f36e6cf498e2a448662f915d932c09c5a146c") + token, err := auth_model.GetAccessTokenBySHA(db.DefaultContext, "4c6f36e6cf498e2a448662f915d932c09c5a146c") assert.NoError(t, err) assert.Equal(t, int64(1), token.UID) - assert.NoError(t, auth_model.DeleteAccessTokenByID(token.ID, 1)) + assert.NoError(t, auth_model.DeleteAccessTokenByID(db.DefaultContext, token.ID, 1)) unittest.AssertNotExistsBean(t, token) - err = auth_model.DeleteAccessTokenByID(100, 100) + err = auth_model.DeleteAccessTokenByID(db.DefaultContext, 100, 100) assert.Error(t, err) assert.True(t, auth_model.IsErrAccessTokenNotExist(err)) } diff --git a/models/auth/twofactor.go b/models/auth/twofactor.go index 751a281f7e8..51061e52055 100644 --- a/models/auth/twofactor.go +++ b/models/auth/twofactor.go @@ -4,6 +4,7 @@ package auth import ( + "context" "crypto/md5" "crypto/subtle" "encoding/base32" @@ -121,22 +122,22 @@ func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) { } // NewTwoFactor creates a new two-factor authentication token. -func NewTwoFactor(t *TwoFactor) error { - _, err := db.GetEngine(db.DefaultContext).Insert(t) +func NewTwoFactor(ctx context.Context, t *TwoFactor) error { + _, err := db.GetEngine(ctx).Insert(t) return err } // UpdateTwoFactor updates a two-factor authentication token. -func UpdateTwoFactor(t *TwoFactor) error { - _, err := db.GetEngine(db.DefaultContext).ID(t.ID).AllCols().Update(t) +func UpdateTwoFactor(ctx context.Context, t *TwoFactor) error { + _, err := db.GetEngine(ctx).ID(t.ID).AllCols().Update(t) return err } // GetTwoFactorByUID returns the two-factor authentication token associated with // the user, if any. -func GetTwoFactorByUID(uid int64) (*TwoFactor, error) { +func GetTwoFactorByUID(ctx context.Context, uid int64) (*TwoFactor, error) { twofa := &TwoFactor{} - has, err := db.GetEngine(db.DefaultContext).Where("uid=?", uid).Get(twofa) + has, err := db.GetEngine(ctx).Where("uid=?", uid).Get(twofa) if err != nil { return nil, err } else if !has { @@ -147,13 +148,13 @@ func GetTwoFactorByUID(uid int64) (*TwoFactor, error) { // HasTwoFactorByUID returns the two-factor authentication token associated with // the user, if any. -func HasTwoFactorByUID(uid int64) (bool, error) { - return db.GetEngine(db.DefaultContext).Where("uid=?", uid).Exist(&TwoFactor{}) +func HasTwoFactorByUID(ctx context.Context, uid int64) (bool, error) { + return db.GetEngine(ctx).Where("uid=?", uid).Exist(&TwoFactor{}) } // DeleteTwoFactorByID deletes two-factor authentication token by given ID. -func DeleteTwoFactorByID(id, userID int64) error { - cnt, err := db.GetEngine(db.DefaultContext).ID(id).Delete(&TwoFactor{ +func DeleteTwoFactorByID(ctx context.Context, id, userID int64) error { + cnt, err := db.GetEngine(ctx).ID(id).Delete(&TwoFactor{ UID: userID, }) if err != nil { diff --git a/models/auth/webauthn.go b/models/auth/webauthn.go index db5dd7eea58..d12713bd37c 100644 --- a/models/auth/webauthn.go +++ b/models/auth/webauthn.go @@ -67,11 +67,7 @@ func (cred WebAuthnCredential) TableName() string { } // UpdateSignCount will update the database value of SignCount -func (cred *WebAuthnCredential) UpdateSignCount() error { - return cred.updateSignCount(db.DefaultContext) -} - -func (cred *WebAuthnCredential) updateSignCount(ctx context.Context) error { +func (cred *WebAuthnCredential) UpdateSignCount(ctx context.Context) error { _, err := db.GetEngine(ctx).ID(cred.ID).Cols("sign_count").Update(cred) return err } @@ -113,30 +109,18 @@ func (list WebAuthnCredentialList) ToCredentials() []webauthn.Credential { } // GetWebAuthnCredentialsByUID returns all WebAuthn credentials of the given user -func GetWebAuthnCredentialsByUID(uid int64) (WebAuthnCredentialList, error) { - return getWebAuthnCredentialsByUID(db.DefaultContext, uid) -} - -func getWebAuthnCredentialsByUID(ctx context.Context, uid int64) (WebAuthnCredentialList, error) { +func GetWebAuthnCredentialsByUID(ctx context.Context, uid int64) (WebAuthnCredentialList, error) { creds := make(WebAuthnCredentialList, 0) return creds, db.GetEngine(ctx).Where("user_id = ?", uid).Find(&creds) } // ExistsWebAuthnCredentialsForUID returns if the given user has credentials -func ExistsWebAuthnCredentialsForUID(uid int64) (bool, error) { - return existsWebAuthnCredentialsByUID(db.DefaultContext, uid) -} - -func existsWebAuthnCredentialsByUID(ctx context.Context, uid int64) (bool, error) { +func ExistsWebAuthnCredentialsForUID(ctx context.Context, uid int64) (bool, error) { return db.GetEngine(ctx).Where("user_id = ?", uid).Exist(&WebAuthnCredential{}) } // GetWebAuthnCredentialByName returns WebAuthn credential by id -func GetWebAuthnCredentialByName(uid int64, name string) (*WebAuthnCredential, error) { - return getWebAuthnCredentialByName(db.DefaultContext, uid, name) -} - -func getWebAuthnCredentialByName(ctx context.Context, uid int64, name string) (*WebAuthnCredential, error) { +func GetWebAuthnCredentialByName(ctx context.Context, uid int64, name string) (*WebAuthnCredential, error) { cred := new(WebAuthnCredential) if found, err := db.GetEngine(ctx).Where("user_id = ? AND lower_name = ?", uid, strings.ToLower(name)).Get(cred); err != nil { return nil, err @@ -147,11 +131,7 @@ func getWebAuthnCredentialByName(ctx context.Context, uid int64, name string) (* } // GetWebAuthnCredentialByID returns WebAuthn credential by id -func GetWebAuthnCredentialByID(id int64) (*WebAuthnCredential, error) { - return getWebAuthnCredentialByID(db.DefaultContext, id) -} - -func getWebAuthnCredentialByID(ctx context.Context, id int64) (*WebAuthnCredential, error) { +func GetWebAuthnCredentialByID(ctx context.Context, id int64) (*WebAuthnCredential, error) { cred := new(WebAuthnCredential) if found, err := db.GetEngine(ctx).ID(id).Get(cred); err != nil { return nil, err @@ -162,16 +142,12 @@ func getWebAuthnCredentialByID(ctx context.Context, id int64) (*WebAuthnCredenti } // HasWebAuthnRegistrationsByUID returns whether a given user has WebAuthn registrations -func HasWebAuthnRegistrationsByUID(uid int64) (bool, error) { - return db.GetEngine(db.DefaultContext).Where("user_id = ?", uid).Exist(&WebAuthnCredential{}) +func HasWebAuthnRegistrationsByUID(ctx context.Context, uid int64) (bool, error) { + return db.GetEngine(ctx).Where("user_id = ?", uid).Exist(&WebAuthnCredential{}) } // GetWebAuthnCredentialByCredID returns WebAuthn credential by credential ID -func GetWebAuthnCredentialByCredID(userID int64, credID []byte) (*WebAuthnCredential, error) { - return getWebAuthnCredentialByCredID(db.DefaultContext, userID, credID) -} - -func getWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []byte) (*WebAuthnCredential, error) { +func GetWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []byte) (*WebAuthnCredential, error) { cred := new(WebAuthnCredential) if found, err := db.GetEngine(ctx).Where("user_id = ? AND credential_id = ?", userID, credID).Get(cred); err != nil { return nil, err @@ -182,11 +158,7 @@ func getWebAuthnCredentialByCredID(ctx context.Context, userID int64, credID []b } // CreateCredential will create a new WebAuthnCredential from the given Credential -func CreateCredential(userID int64, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) { - return createCredential(db.DefaultContext, userID, name, cred) -} - -func createCredential(ctx context.Context, userID int64, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) { +func CreateCredential(ctx context.Context, userID int64, name string, cred *webauthn.Credential) (*WebAuthnCredential, error) { c := &WebAuthnCredential{ UserID: userID, Name: name, @@ -205,18 +177,14 @@ func createCredential(ctx context.Context, userID int64, name string, cred *weba } // DeleteCredential will delete WebAuthnCredential -func DeleteCredential(id, userID int64) (bool, error) { - return deleteCredential(db.DefaultContext, id, userID) -} - -func deleteCredential(ctx context.Context, id, userID int64) (bool, error) { +func DeleteCredential(ctx context.Context, id, userID int64) (bool, error) { had, err := db.GetEngine(ctx).ID(id).Where("user_id = ?", userID).Delete(&WebAuthnCredential{}) return had > 0, err } // WebAuthnCredentials implementns the webauthn.User interface -func WebAuthnCredentials(userID int64) ([]webauthn.Credential, error) { - dbCreds, err := GetWebAuthnCredentialsByUID(userID) +func WebAuthnCredentials(ctx context.Context, userID int64) ([]webauthn.Credential, error) { + dbCreds, err := GetWebAuthnCredentialsByUID(ctx, userID) if err != nil { return nil, err } diff --git a/models/auth/webauthn_test.go b/models/auth/webauthn_test.go index 6f2ec087c7a..f1cf398adf5 100644 --- a/models/auth/webauthn_test.go +++ b/models/auth/webauthn_test.go @@ -7,6 +7,7 @@ import ( "testing" auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "github.com/go-webauthn/webauthn/webauthn" @@ -16,11 +17,11 @@ import ( func TestGetWebAuthnCredentialByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - res, err := auth_model.GetWebAuthnCredentialByID(1) + res, err := auth_model.GetWebAuthnCredentialByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, "WebAuthn credential", res.Name) - _, err = auth_model.GetWebAuthnCredentialByID(342432) + _, err = auth_model.GetWebAuthnCredentialByID(db.DefaultContext, 342432) assert.Error(t, err) assert.True(t, auth_model.IsErrWebAuthnCredentialNotExist(err)) } @@ -28,7 +29,7 @@ func TestGetWebAuthnCredentialByID(t *testing.T) { func TestGetWebAuthnCredentialsByUID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - res, err := auth_model.GetWebAuthnCredentialsByUID(32) + res, err := auth_model.GetWebAuthnCredentialsByUID(db.DefaultContext, 32) assert.NoError(t, err) assert.Len(t, res, 1) assert.Equal(t, "WebAuthn credential", res[0].Name) @@ -42,7 +43,7 @@ func TestWebAuthnCredential_UpdateSignCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred.SignCount = 1 - assert.NoError(t, cred.UpdateSignCount()) + assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 1}) } @@ -50,14 +51,14 @@ func TestWebAuthnCredential_UpdateLargeCounter(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) cred := unittest.AssertExistsAndLoadBean(t, &auth_model.WebAuthnCredential{ID: 1}) cred.SignCount = 0xffffffff - assert.NoError(t, cred.UpdateSignCount()) + assert.NoError(t, cred.UpdateSignCount(db.DefaultContext)) unittest.AssertExistsIf(t, true, &auth_model.WebAuthnCredential{ID: 1, SignCount: 0xffffffff}) } func TestCreateCredential(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - res, err := auth_model.CreateCredential(1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")}) + res, err := auth_model.CreateCredential(db.DefaultContext, 1, "WebAuthn Created Credential", &webauthn.Credential{ID: []byte("Test")}) assert.NoError(t, err) assert.Equal(t, "WebAuthn Created Credential", res.Name) assert.Equal(t, []byte("Test"), res.CredentialID) diff --git a/models/avatars/main_test.go b/models/avatars/main_test.go index 65076327177..c721a7dc2ac 100644 --- a/models/avatars/main_test.go +++ b/models/avatars/main_test.go @@ -4,7 +4,6 @@ package avatars_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -15,7 +14,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/db/main_test.go b/models/db/main_test.go index ce485029185..7d80b400fe5 100644 --- a/models/db/main_test.go +++ b/models/db/main_test.go @@ -4,7 +4,6 @@ package db_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,7 +13,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/db/paginator/main_test.go b/models/db/paginator/main_test.go index b0557bc5a4a..47993aed6be 100644 --- a/models/db/paginator/main_test.go +++ b/models/db/paginator/main_test.go @@ -4,14 +4,11 @@ package paginator import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/dbfs/main_test.go b/models/dbfs/main_test.go index 62db3592bed..537ba0935d6 100644 --- a/models/dbfs/main_test.go +++ b/models/dbfs/main_test.go @@ -4,14 +4,11 @@ package dbfs import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/fixture_generation.go b/models/fixture_generation.go index abf880ee8e2..d3429198954 100644 --- a/models/fixture_generation.go +++ b/models/fixture_generation.go @@ -40,7 +40,9 @@ func GetYamlFixturesAccess() (string, error) { fmt.Fprintf(&b, " user_id: %d\n", a.UserID) fmt.Fprintf(&b, " repo_id: %d\n", a.RepoID) fmt.Fprintf(&b, " mode: %d\n", a.Mode) - fmt.Fprintf(&b, "\n") + if i < len(accesses)-1 { + fmt.Fprintf(&b, "\n") + } } return b.String(), nil diff --git a/models/fixture_test.go b/models/fixture_test.go index 8a28db81649..b70fdb536d3 100644 --- a/models/fixture_test.go +++ b/models/fixture_test.go @@ -22,12 +22,13 @@ func TestFixtureGeneration(t *testing.T) { if !assert.NoError(t, err) { return } - bytes, err := os.ReadFile(filepath.Join(unittest.FixturesDir(), name+".yml")) + p := filepath.Join(unittest.FixturesDir(), name+".yml") + bytes, err := os.ReadFile(p) if !assert.NoError(t, err) { return } data := string(util.NormalizeEOL(bytes)) - assert.True(t, data == expected, "Differences detected for %s.yml", name) + assert.EqualValues(t, expected, data, "Differences detected for %s", p) } test(GetYamlFixturesAccess, "access") diff --git a/models/fixtures/access.yml b/models/fixtures/access.yml index 446502843ef..1bb6a9a8acc 100644 --- a/models/fixtures/access.yml +++ b/models/fixtures/access.yml @@ -135,4 +135,3 @@ user_id: 31 repo_id: 28 mode: 4 - diff --git a/models/fixtures/access_token.yml b/models/fixtures/access_token.yml index 791b3da1c45..0744255f664 100644 --- a/models/fixtures/access_token.yml +++ b/models/fixtures/access_token.yml @@ -2,7 +2,7 @@ id: 1 uid: 1 name: Token A - #token: d2c6c1ba3890b309189a8e618c72a162e4efbf36 + # token: d2c6c1ba3890b309189a8e618c72a162e4efbf36 token_hash: 2b3668e11cb82d3af8c6e4524fc7841297668f5008d1626f0ad3417e9fa39af84c268248b78c481daa7e5dc437784003494f token_salt: QuSiZr1byZ token_last_eight: e4efbf36 @@ -13,7 +13,7 @@ id: 2 uid: 1 name: Token B - #token: 4c6f36e6cf498e2a448662f915d932c09c5a146c + # token: 4c6f36e6cf498e2a448662f915d932c09c5a146c token_hash: 1a0e32a231ebbd582dc626c1543a42d3c63d4fa76c07c72862721467c55e8f81c923d60700f0528b5f5f443f055559d3a279 token_salt: Lfwopukrq5 token_last_eight: 9c5a146c @@ -24,10 +24,10 @@ id: 3 uid: 2 name: Token A - #token: 90a18faa671dc43924b795806ffe4fd169d28c91 + # token: 90a18faa671dc43924b795806ffe4fd169d28c91 token_hash: d6d404048048812d9e911d93aefbe94fc768d4876fdf75e3bef0bdc67828e0af422846d3056f2f25ec35c51dc92075685ec5 token_salt: 99ArgXKlQQ token_last_eight: 69d28c91 created_unix: 946687980 updated_unix: 946687980 -#commented out tokens so you can see what they are in plaintext + # commented out tokens so you can see what they are in plaintext diff --git a/models/fixtures/attachment.yml b/models/fixtures/attachment.yml index 9ad43fa2b7e..7882d8bff20 100644 --- a/models/fixtures/attachment.yml +++ b/models/fixtures/attachment.yml @@ -140,3 +140,16 @@ download_count: 0 size: 0 created_unix: 946684800 + +- + id: 12 + uuid: a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a22 + repo_id: 2 + issue_id: 0 + release_id: 11 + uploader_id: 2 + comment_id: 0 + name: README.md + download_count: 0 + size: 0 + created_unix: 946684800 diff --git a/models/fixtures/commit_status_index.yml b/models/fixtures/commit_status_index.yml index 3f252e87ef0..f63343b042a 100644 --- a/models/fixtures/commit_status_index.yml +++ b/models/fixtures/commit_status_index.yml @@ -2,4 +2,4 @@ id: 1 repo_id: 1 sha: "1234123412341234123412341234123412341234" - max_index: 5 \ No newline at end of file + max_index: 5 diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index fa72f9b647d..ccc1fe41fbd 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -321,3 +321,20 @@ created_unix: 946684830 updated_unix: 978307200 is_locked: false + +- + id: 20 + repo_id: 23 + index: 1 + poster_id: 2 + original_author_id: 0 + name: issue for pr + content: content + milestone_id: 0 + priority: 0 + is_closed: false + is_pull: true + num_comments: 0 + created_unix: 978307210 + updated_unix: 978307210 + is_locked: false diff --git a/models/fixtures/public_key.yml b/models/fixtures/public_key.yml index 08f5c349a7b..ae620ee2d19 100644 --- a/models/fixtures/public_key.yml +++ b/models/fixtures/public_key.yml @@ -8,4 +8,4 @@ type: 1 created_unix: 1559593109 updated_unix: 1565224552 - login_source_id: 0 \ No newline at end of file + login_source_id: 0 diff --git a/models/fixtures/pull_request.yml b/models/fixtures/pull_request.yml index e5589ac703d..560674c370b 100644 --- a/models/fixtures/pull_request.yml +++ b/models/fixtures/pull_request.yml @@ -89,3 +89,12 @@ base_branch: main merge_base: cbff181af4c9c7fee3cf6c106699e07d9a3f54e6 has_merged: false + +- + id: 8 + type: 0 # gitea pull request + status: 2 # mergable + issue_id: 20 + index: 1 + head_repo_id: 23 + base_repo_id: 23 diff --git a/models/fixtures/reaction.yml b/models/fixtures/reaction.yml index 4925935fe6f..ee571a73a48 100644 --- a/models/fixtures/reaction.yml +++ b/models/fixtures/reaction.yml @@ -1,5 +1,5 @@ - - id: 1 #issue reaction + id: 1 # issue reaction type: zzz # not allowed reaction (added before allowed reaction list has changed) issue_id: 1 comment_id: 0 @@ -7,7 +7,7 @@ created_unix: 1573248001 - - id: 2 #issue reaction + id: 2 # issue reaction type: zzz # not allowed reaction (added before allowed reaction list has changed) issue_id: 1 comment_id: 0 @@ -15,7 +15,7 @@ created_unix: 1573248002 - - id: 3 #issue reaction + id: 3 # issue reaction type: eyes # allowed reaction issue_id: 1 comment_id: 0 @@ -23,7 +23,7 @@ created_unix: 1573248003 - - id: 4 #comment reaction + id: 4 # comment reaction type: laugh # allowed reaction issue_id: 1 comment_id: 2 @@ -31,7 +31,7 @@ created_unix: 1573248004 - - id: 5 #comment reaction + id: 5 # comment reaction type: laugh # allowed reaction issue_id: 1 comment_id: 2 diff --git a/models/fixtures/release.yml b/models/fixtures/release.yml index 4ed7df440db..372a79509f0 100644 --- a/models/fixtures/release.yml +++ b/models/fixtures/release.yml @@ -136,3 +136,17 @@ is_prerelease: false is_tag: false created_unix: 946684803 + +- id: 11 + repo_id: 2 + publisher_id: 2 + tag_name: "v1.1" + lower_tag_name: "v1.1" + target: "" + title: "v1.1" + sha1: "205ac761f3326a7ebe416e8673760016450b5cec" + num_commits: 2 + is_draft: false + is_prerelease: false + is_tag: false + created_unix: 946684803 diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml index c22eb8c2a2f..01044195505 100644 --- a/models/fixtures/repo_unit.yml +++ b/models/fixtures/repo_unit.yml @@ -649,3 +649,23 @@ repo_id: 49 type: 2 created_unix: 946684810 + +- + id: 98 + repo_id: 1 + type: 8 + created_unix: 946684810 + +- + id: 99 + repo_id: 1 + type: 9 + config: "{}" + created_unix: 946684810 + +- + id: 100 + repo_id: 1 + type: 10 + config: "{}" + created_unix: 946684810 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index c63b7ebd481..373c1caa625 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -679,7 +679,7 @@ num_forks: 0 num_issues: 0 num_closed_issues: 0 - num_pulls: 0 + num_pulls: 1 num_closed_pulls: 0 num_milestones: 0 num_closed_milestones: 0 diff --git a/models/fixtures/review.yml b/models/fixtures/review.yml index dda13dc468e..7a880800684 100644 --- a/models/fixtures/review.yml +++ b/models/fixtures/review.yml @@ -132,3 +132,41 @@ content: "singular review from org6 and final review for this pr" updated_unix: 946684831 created_unix: 946684831 + +- + id: 16 + type: 4 + reviewer_id: 20 + issue_id: 20 + content: "review request for user20" + updated_unix: 946684832 + created_unix: 946684832 + +- + id: 17 + type: 1 + reviewer_id: 20 + issue_id: 20 + content: "review approved by user20" + updated_unix: 946684833 + created_unix: 946684833 + +- + id: 18 + type: 4 + reviewer_id: 0 + reviewer_team_id: 5 + issue_id: 20 + content: "review request for team5" + updated_unix: 946684834 + created_unix: 946684834 + +- + id: 19 + type: 4 + reviewer_id: 15 + reviewer_team_id: 0 + issue_id: 20 + content: "review request for user15" + updated_unix: 946684835 + created_unix: 946684835 diff --git a/models/fixtures/team.yml b/models/fixtures/team.yml index 65326eedbf4..295e51e39ce 100644 --- a/models/fixtures/team.yml +++ b/models/fixtures/team.yml @@ -93,7 +93,7 @@ name: review_team authorize: 1 # read num_repos: 1 - num_members: 2 + num_members: 3 includes_all_repositories: false can_create_org_repo: false diff --git a/models/fixtures/team_repo.yml b/models/fixtures/team_repo.yml index a523a90b204..8497720892f 100644 --- a/models/fixtures/team_repo.yml +++ b/models/fixtures/team_repo.yml @@ -62,4 +62,4 @@ id: 11 org_id: 17 team_id: 9 - repo_id: 24 \ No newline at end of file + repo_id: 24 diff --git a/models/fixtures/team_user.yml b/models/fixtures/team_user.yml index feace5f2a53..9142fe609ad 100644 --- a/models/fixtures/team_user.yml +++ b/models/fixtures/team_user.yml @@ -123,3 +123,9 @@ org_id: 36 team_id: 20 uid: 5 + +- + id: 22 + org_id: 17 + team_id: 9 + uid: 15 diff --git a/models/fixtures/watch.yml b/models/fixtures/watch.yml index c29f6bb65a8..1950ac99e7f 100644 --- a/models/fixtures/watch.yml +++ b/models/fixtures/watch.yml @@ -26,4 +26,4 @@ id: 5 user_id: 11 repo_id: 1 - mode: 3 # auto + mode: 3 # auto diff --git a/models/git/branch_list.go b/models/git/branch_list.go index 131a149782e..b5c1301a1dc 100644 --- a/models/git/branch_list.go +++ b/models/git/branch_list.go @@ -70,6 +70,7 @@ type FindBranchOptions struct { ExcludeBranchNames []string IsDeletedBranch util.OptionalBool OrderBy string + Keyword string } func (opts *FindBranchOptions) Cond() builder.Cond { @@ -84,6 +85,9 @@ func (opts *FindBranchOptions) Cond() builder.Cond { if !opts.IsDeletedBranch.IsNone() { cond = cond.And(builder.Eq{"is_deleted": opts.IsDeletedBranch.IsTrue()}) } + if opts.Keyword != "" { + cond = cond.And(builder.Like{"name", opts.Keyword}) + } return cond } diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 24fee8c3b4f..acb01102005 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -514,7 +514,7 @@ func ConvertFromGitCommit(ctx context.Context, commits []*git.Commit, repo *repo user_model.ValidateCommitsWithEmails(ctx, commits), repo.GetTrustModel(), func(user *user_model.User) (bool, error) { - return repo_model.IsOwnerMemberCollaborator(repo, user.ID) + return repo_model.IsOwnerMemberCollaborator(ctx, repo, user.ID) }, ), repo, diff --git a/models/git/main_test.go b/models/git/main_test.go index a8658d70c4c..aab1fa9a26f 100644 --- a/models/git/main_test.go +++ b/models/git/main_test.go @@ -4,7 +4,6 @@ package git_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -15,7 +14,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/git/protected_branch.go b/models/git/protected_branch.go index 5ed10037497..5be35f4b113 100644 --- a/models/git/protected_branch.go +++ b/models/git/protected_branch.go @@ -315,6 +315,11 @@ type WhitelistOptions struct { // This function also performs check if whitelist user and team's IDs have been changed // to avoid unnecessary whitelist delete and regenerate. func UpdateProtectBranch(ctx context.Context, repo *repo_model.Repository, protectBranch *ProtectedBranch, opts WhitelistOptions) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + if err = repo.LoadOwner(ctx); err != nil { return fmt.Errorf("LoadOwner: %v", err) } @@ -445,9 +450,14 @@ func updateTeamWhitelist(ctx context.Context, repo *repo_model.Repository, curre } // DeleteProtectedBranch removes ProtectedBranch relation between the user and repository. -func DeleteProtectedBranch(ctx context.Context, repoID, id int64) (err error) { +func DeleteProtectedBranch(ctx context.Context, repo *repo_model.Repository, id int64) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + protectedBranch := &ProtectedBranch{ - RepoID: repoID, + RepoID: repo.ID, ID: id, } diff --git a/models/issues/assignees_test.go b/models/issues/assignees_test.go index 65a5ddba31a..3898e814c31 100644 --- a/models/issues/assignees_test.go +++ b/models/issues/assignees_test.go @@ -18,7 +18,7 @@ func TestUpdateAssignee(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // Fake issue with assignees - issue, err := issues_model.GetIssueWithAttrsByID(1) + issue, err := issues_model.GetIssueWithAttrsByID(db.DefaultContext, 1) assert.NoError(t, err) // Assign multiple users diff --git a/models/issues/comment.go b/models/issues/comment.go index e045b71d23b..901958dc5d5 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -246,7 +246,7 @@ type Comment struct { NewTitle string OldRef string NewRef string - DependentIssueID int64 + DependentIssueID int64 `xorm:"index"` // This is used by issue_service.deleteIssue DependentIssue *Issue `xorm:"-"` CommitID int64 @@ -359,54 +359,54 @@ func (c *Comment) LoadPoster(ctx context.Context) (err error) { } // AfterDelete is invoked from XORM after the object is deleted. -func (c *Comment) AfterDelete() { +func (c *Comment) AfterDelete(ctx context.Context) { if c.ID <= 0 { return } - _, err := repo_model.DeleteAttachmentsByComment(c.ID, true) + _, err := repo_model.DeleteAttachmentsByComment(ctx, c.ID, true) if err != nil { log.Info("Could not delete files for comment %d on issue #%d: %s", c.ID, c.IssueID, err) } } // HTMLURL formats a URL-string to the issue-comment -func (c *Comment) HTMLURL() string { - err := c.LoadIssue(db.DefaultContext) +func (c *Comment) HTMLURL(ctx context.Context) string { + err := c.LoadIssue(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.LoadRepo(db.DefaultContext) + err = c.Issue.LoadRepo(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" } - return c.Issue.HTMLURL() + c.hashLink() + return c.Issue.HTMLURL() + c.hashLink(ctx) } // Link formats a relative URL-string to the issue-comment -func (c *Comment) Link() string { - err := c.LoadIssue(db.DefaultContext) +func (c *Comment) Link(ctx context.Context) string { + err := c.LoadIssue(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.LoadRepo(db.DefaultContext) + err = c.Issue.LoadRepo(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" } - return c.Issue.Link() + c.hashLink() + return c.Issue.Link() + c.hashLink(ctx) } -func (c *Comment) hashLink() string { +func (c *Comment) hashLink(ctx context.Context) string { if c.Type == CommentTypeCode { if c.ReviewID == 0 { return "/files#" + c.HashTag() } if c.Review == nil { - if err := c.LoadReview(); err != nil { + if err := c.LoadReview(ctx); err != nil { log.Warn("LoadReview(%d): %v", c.ReviewID, err) return "/files#" + c.HashTag() } @@ -419,13 +419,13 @@ func (c *Comment) hashLink() string { } // APIURL formats a API-string to the issue-comment -func (c *Comment) APIURL() string { - err := c.LoadIssue(db.DefaultContext) +func (c *Comment) APIURL(ctx context.Context) string { + err := c.LoadIssue(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.LoadRepo(db.DefaultContext) + err = c.Issue.LoadRepo(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -435,8 +435,8 @@ func (c *Comment) APIURL() string { } // IssueURL formats a URL-string to the issue -func (c *Comment) IssueURL() string { - err := c.LoadIssue(db.DefaultContext) +func (c *Comment) IssueURL(ctx context.Context) string { + err := c.LoadIssue(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" @@ -446,7 +446,7 @@ func (c *Comment) IssueURL() string { return "" } - err = c.Issue.LoadRepo(db.DefaultContext) + err = c.Issue.LoadRepo(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -455,14 +455,14 @@ func (c *Comment) IssueURL() string { } // PRURL formats a URL-string to the pull-request -func (c *Comment) PRURL() string { - err := c.LoadIssue(db.DefaultContext) +func (c *Comment) PRURL(ctx context.Context) string { + err := c.LoadIssue(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.LoadRepo(db.DefaultContext) + err = c.Issue.LoadRepo(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -490,9 +490,9 @@ func (c *Comment) EventTag() string { } // LoadLabel if comment.Type is CommentTypeLabel, then load Label -func (c *Comment) LoadLabel() error { +func (c *Comment) LoadLabel(ctx context.Context) error { var label Label - has, err := db.GetEngine(db.DefaultContext).ID(c.LabelID).Get(&label) + has, err := db.GetEngine(ctx).ID(c.LabelID).Get(&label) if err != nil { return err } else if has { @@ -506,10 +506,10 @@ func (c *Comment) LoadLabel() error { } // LoadProject if comment.Type is CommentTypeProject, then load project. -func (c *Comment) LoadProject() error { +func (c *Comment) LoadProject(ctx context.Context) error { if c.OldProjectID > 0 { var oldProject project_model.Project - has, err := db.GetEngine(db.DefaultContext).ID(c.OldProjectID).Get(&oldProject) + has, err := db.GetEngine(ctx).ID(c.OldProjectID).Get(&oldProject) if err != nil { return err } else if has { @@ -519,7 +519,7 @@ func (c *Comment) LoadProject() error { if c.ProjectID > 0 { var project project_model.Project - has, err := db.GetEngine(db.DefaultContext).ID(c.ProjectID).Get(&project) + has, err := db.GetEngine(ctx).ID(c.ProjectID).Get(&project) if err != nil { return err } else if has { @@ -569,8 +569,8 @@ func (c *Comment) LoadAttachments(ctx context.Context) error { } // UpdateAttachments update attachments by UUIDs for the comment -func (c *Comment) UpdateAttachments(uuids []string) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func (c *Comment) UpdateAttachments(ctx context.Context, uuids []string) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -591,11 +591,11 @@ func (c *Comment) UpdateAttachments(uuids []string) error { } // LoadAssigneeUserAndTeam if comment.Type is CommentTypeAssignees, then load assignees -func (c *Comment) LoadAssigneeUserAndTeam() error { +func (c *Comment) LoadAssigneeUserAndTeam(ctx context.Context) error { var err error if c.AssigneeID > 0 && c.Assignee == nil { - c.Assignee, err = user_model.GetUserByID(db.DefaultContext, c.AssigneeID) + c.Assignee, err = user_model.GetUserByID(ctx, c.AssigneeID) if err != nil { if !user_model.IsErrUserNotExist(err) { return err @@ -603,20 +603,20 @@ func (c *Comment) LoadAssigneeUserAndTeam() error { c.Assignee = user_model.NewGhostUser() } } else if c.AssigneeTeamID > 0 && c.AssigneeTeam == nil { - if err = c.LoadIssue(db.DefaultContext); err != nil { + if err = c.LoadIssue(ctx); err != nil { return err } - if err = c.Issue.LoadRepo(db.DefaultContext); err != nil { + if err = c.Issue.LoadRepo(ctx); err != nil { return err } - if err = c.Issue.Repo.LoadOwner(db.DefaultContext); err != nil { + if err = c.Issue.Repo.LoadOwner(ctx); err != nil { return err } if c.Issue.Repo.Owner.IsOrganization() { - c.AssigneeTeam, err = organization.GetTeamByID(db.DefaultContext, c.AssigneeTeamID) + c.AssigneeTeam, err = organization.GetTeamByID(ctx, c.AssigneeTeamID) if err != nil && !organization.IsErrTeamNotExist(err) { return err } @@ -626,11 +626,11 @@ func (c *Comment) LoadAssigneeUserAndTeam() error { } // LoadResolveDoer if comment.Type is CommentTypeCode and ResolveDoerID not zero, then load resolveDoer -func (c *Comment) LoadResolveDoer() (err error) { +func (c *Comment) LoadResolveDoer(ctx context.Context) (err error) { if c.ResolveDoerID == 0 || c.Type != CommentTypeCode { return nil } - c.ResolveDoer, err = user_model.GetUserByID(db.DefaultContext, c.ResolveDoerID) + c.ResolveDoer, err = user_model.GetUserByID(ctx, c.ResolveDoerID) if err != nil { if user_model.IsErrUserNotExist(err) { c.ResolveDoer = user_model.NewGhostUser() @@ -646,21 +646,21 @@ func (c *Comment) IsResolved() bool { } // LoadDepIssueDetails loads Dependent Issue Details -func (c *Comment) LoadDepIssueDetails() (err error) { +func (c *Comment) LoadDepIssueDetails(ctx context.Context) (err error) { if c.DependentIssueID <= 0 || c.DependentIssue != nil { return nil } - c.DependentIssue, err = GetIssueByID(db.DefaultContext, c.DependentIssueID) + c.DependentIssue, err = GetIssueByID(ctx, c.DependentIssueID) return err } // LoadTime loads the associated time for a CommentTypeAddTimeManual -func (c *Comment) LoadTime() error { +func (c *Comment) LoadTime(ctx context.Context) error { if c.Time != nil || c.TimeID == 0 { return nil } var err error - c.Time, err = GetTrackedTimeByID(c.TimeID) + c.Time, err = GetTrackedTimeByID(ctx, c.TimeID) return err } @@ -683,8 +683,8 @@ func (c *Comment) loadReactions(ctx context.Context, repo *repo_model.Repository } // LoadReactions loads comment reactions -func (c *Comment) LoadReactions(repo *repo_model.Repository) error { - return c.loadReactions(db.DefaultContext, repo) +func (c *Comment) LoadReactions(ctx context.Context, repo *repo_model.Repository) error { + return c.loadReactions(ctx, repo) } func (c *Comment) loadReview(ctx context.Context) (err error) { @@ -698,8 +698,8 @@ func (c *Comment) loadReview(ctx context.Context) (err error) { } // LoadReview loads the associated review -func (c *Comment) LoadReview() error { - return c.loadReview(db.DefaultContext) +func (c *Comment) LoadReview(ctx context.Context) error { + return c.loadReview(ctx) } // DiffSide returns "previous" if Comment.Line is a LOC of the previous changes and "proposed" if it is a LOC of the proposed changes. @@ -719,13 +719,13 @@ func (c *Comment) UnsignedLine() uint64 { } // CodeCommentLink returns the url to a comment in code -func (c *Comment) CodeCommentLink() string { - err := c.LoadIssue(db.DefaultContext) +func (c *Comment) CodeCommentLink(ctx context.Context) string { + err := c.LoadIssue(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("LoadIssue(%d): %v", c.IssueID, err) return "" } - err = c.Issue.LoadRepo(db.DefaultContext) + err = c.Issue.LoadRepo(ctx) if err != nil { // Silently dropping errors :unamused: log.Error("loadRepo(%d): %v", c.Issue.RepoID, err) return "" @@ -1074,8 +1074,8 @@ func FindComments(ctx context.Context, opts *FindCommentsOptions) (CommentList, } // CountComments count all comments according options by ignoring pagination -func CountComments(opts *FindCommentsOptions) (int64, error) { - sess := db.GetEngine(db.DefaultContext).Where(opts.ToConds()) +func CountComments(ctx context.Context, opts *FindCommentsOptions) (int64, error) { + sess := db.GetEngine(ctx).Where(opts.ToConds()) if opts.RepoID > 0 { sess.Join("INNER", "issue", "issue.id = comment.issue_id") } @@ -1089,8 +1089,8 @@ func UpdateCommentInvalidate(ctx context.Context, c *Comment) error { } // UpdateComment updates information of comment. -func UpdateComment(c *Comment, doer *user_model.User) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateComment(ctx context.Context, c *Comment, doer *user_model.User) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -1147,8 +1147,8 @@ func DeleteComment(ctx context.Context, comment *Comment) error { } // UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id -func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error { - _, err := db.GetEngine(db.DefaultContext).Table("comment"). +func UpdateCommentsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error { + _, err := db.GetEngine(ctx).Table("comment"). Where(builder.In("issue_id", builder.Select("issue.id"). From("issue"). @@ -1250,7 +1250,7 @@ func (c *Comment) HasOriginalAuthor() bool { } // InsertIssueComments inserts many comments of issues. -func InsertIssueComments(comments []*Comment) error { +func InsertIssueComments(ctx context.Context, comments []*Comment) error { if len(comments) == 0 { return nil } @@ -1260,7 +1260,7 @@ func InsertIssueComments(comments []*Comment) error { issueIDs.Add(comment.IssueID) } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/issues/comment_code.go b/models/issues/comment_code.go index d447d7542cd..49927fbbe2f 100644 --- a/models/issues/comment_code.go +++ b/models/issues/comment_code.go @@ -99,11 +99,11 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu comments[n] = comment n++ - if err := comment.LoadResolveDoer(); err != nil { + if err := comment.LoadResolveDoer(ctx); err != nil { return nil, err } - if err := comment.LoadReactions(issue.Repo); err != nil { + if err := comment.LoadReactions(ctx, issue.Repo); err != nil { return nil, err } diff --git a/models/issues/comment_list.go b/models/issues/comment_list.go index 6f1d350eb42..93af45870ed 100644 --- a/models/issues/comment_list.go +++ b/models/issues/comment_list.go @@ -10,6 +10,7 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/log" ) // CommentList defines a list of comments @@ -422,37 +423,18 @@ func (comments CommentList) loadReviews(ctx context.Context) error { reviewIDs := comments.getReviewIDs() reviews := make(map[int64]*Review, len(reviewIDs)) - left := len(reviewIDs) - for left > 0 { - limit := db.DefaultMaxInSize - if left < limit { - limit = left - } - rows, err := db.GetEngine(ctx). - In("id", reviewIDs[:limit]). - Rows(new(Review)) - if err != nil { - return err - } - - for rows.Next() { - var review Review - err = rows.Scan(&review) - if err != nil { - _ = rows.Close() - return err - } - - reviews[review.ID] = &review - } - _ = rows.Close() - - left -= limit - reviewIDs = reviewIDs[limit:] + if err := db.GetEngine(ctx).In("id", reviewIDs).Find(&reviews); err != nil { + return err } for _, comment := range comments { comment.Review = reviews[comment.ReviewID] + if comment.Review == nil { + if comment.ReviewID > 0 { + log.Error("comment with review id [%d] but has no review record", comment.ReviewID) + } + continue + } // If the comment dismisses a review, we need to load the reviewer to show whose review has been dismissed. // Otherwise, the reviewer is the poster of the comment, so we don't need to load it. diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index 90db4765713..c5bbfdedc28 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -89,7 +89,7 @@ func TestMigrate_InsertIssueComments(t *testing.T) { Reactions: []*issues_model.Reaction{reaction}, } - err := issues_model.InsertIssueComments([]*issues_model.Comment{comment}) + err := issues_model.InsertIssueComments(db.DefaultContext, []*issues_model.Comment{comment}) assert.NoError(t, err) issueModified := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 1}) diff --git a/models/issues/issue.go b/models/issues/issue.go index 341ec8547a1..6d9c8727b33 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -201,12 +201,12 @@ func (issue *Issue) IsTimetrackerEnabled(ctx context.Context) bool { } // GetPullRequest returns the issue pull request -func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) { +func (issue *Issue) GetPullRequest(ctx context.Context) (pr *PullRequest, err error) { if !issue.IsPull { return nil, fmt.Errorf("Issue is not a pull request") } - pr, err = GetPullRequestByIssueID(db.DefaultContext, issue.ID) + pr, err = GetPullRequestByIssueID(ctx, issue.ID) if err != nil { return nil, err } @@ -369,9 +369,9 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { } // GetIsRead load the `IsRead` field of the issue -func (issue *Issue) GetIsRead(userID int64) error { +func (issue *Issue) GetIsRead(ctx context.Context, userID int64) error { issueUser := &IssueUser{IssueID: issue.ID, UID: userID} - if has, err := db.GetEngine(db.DefaultContext).Get(issueUser); err != nil { + if has, err := db.GetEngine(ctx).Get(issueUser); err != nil { return err } else if !has { issue.IsRead = false @@ -382,9 +382,9 @@ func (issue *Issue) GetIsRead(userID int64) error { } // APIURL returns the absolute APIURL to this issue. -func (issue *Issue) APIURL() string { +func (issue *Issue) APIURL(ctx context.Context) string { if issue.Repo == nil { - err := issue.LoadRepo(db.DefaultContext) + err := issue.LoadRepo(ctx) if err != nil { log.Error("Issue[%d].APIURL(): %v", issue.ID, err) return "" @@ -479,9 +479,9 @@ func (issue *Issue) GetLastEventLabel() string { } // GetLastComment return last comment for the current issue. -func (issue *Issue) GetLastComment() (*Comment, error) { +func (issue *Issue) GetLastComment(ctx context.Context) (*Comment, error) { var c Comment - exist, err := db.GetEngine(db.DefaultContext).Where("type = ?", CommentTypeComment). + exist, err := db.GetEngine(ctx).Where("type = ?", CommentTypeComment). And("issue_id = ?", issue.ID).Desc("created_unix").Get(&c) if err != nil { return nil, err @@ -543,12 +543,12 @@ func GetIssueByID(ctx context.Context, id int64) (*Issue, error) { } // GetIssueWithAttrsByID returns an issue with attributes by given ID. -func GetIssueWithAttrsByID(id int64) (*Issue, error) { - issue, err := GetIssueByID(db.DefaultContext, id) +func GetIssueWithAttrsByID(ctx context.Context, id int64) (*Issue, error) { + issue, err := GetIssueByID(ctx, id) if err != nil { return nil, err } - return issue, issue.LoadAttributes(db.DefaultContext) + return issue, issue.LoadAttributes(ctx) } // GetIssuesByIDs return issues with the given IDs. @@ -600,8 +600,8 @@ func GetParticipantsIDsByIssueID(ctx context.Context, issueID int64) ([]int64, e } // IsUserParticipantsOfIssue return true if user is participants of an issue -func IsUserParticipantsOfIssue(user *user_model.User, issue *Issue) bool { - userIDs, err := issue.GetParticipantIDsByIssue(db.DefaultContext) +func IsUserParticipantsOfIssue(ctx context.Context, user *user_model.User, issue *Issue) bool { + userIDs, err := issue.GetParticipantIDsByIssue(ctx) if err != nil { log.Error(err.Error()) return false @@ -894,8 +894,8 @@ func IsErrIssueMaxPinReached(err error) bool { } // InsertIssues insert issues to database -func InsertIssues(issues ...*Issue) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func InsertIssues(ctx context.Context, issues ...*Issue) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/issues/issue_index.go b/models/issues/issue_index.go index b480cc683f5..16274d0ef09 100644 --- a/models/issues/issue_index.go +++ b/models/issues/issue_index.go @@ -3,12 +3,16 @@ package issues -import "code.gitea.io/gitea/models/db" +import ( + "context" + + "code.gitea.io/gitea/models/db" +) // RecalculateIssueIndexForRepo create issue_index for repo if not exist and // update it based on highest index of existing issues assigned to a repo -func RecalculateIssueIndexForRepo(repoID int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func RecalculateIssueIndexForRepo(ctx context.Context, repoID int64) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 5d40b447042..5c05ead6879 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -362,14 +362,21 @@ func applyReviewRequestedCondition(sess *xorm.Session, reviewRequestedID int64) From("team_user"). Where(builder.Eq{"team_user.uid": reviewRequestedID}) + // if the review is approved or rejected, it should not be shown in the review requested list + maxReview := builder.Select("MAX(r.id)"). + From("review as r"). + Where(builder.In("r.type", []ReviewType{ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest})). + GroupBy("r.issue_id, r.reviewer_id, r.reviewer_team_id") + subQuery := builder.Select("review.issue_id"). From("review"). Where(builder.And( - builder.In("review.type", []ReviewType{ReviewTypeRequest, ReviewTypeReject, ReviewTypeApprove}), + builder.Eq{"review.type": ReviewTypeRequest}, builder.Or( builder.Eq{"review.reviewer_id": reviewRequestedID}, builder.In("review.reviewer_team_id", existInTeamQuery), ), + builder.In("review.id", maxReview), )) return sess.Where("issue.poster_id <> ?", reviewRequestedID). And(builder.In("issue.id", subQuery)) diff --git a/models/issues/issue_stats.go b/models/issues/issue_stats.go index 1654e6ce756..99ca19f8044 100644 --- a/models/issues/issue_stats.go +++ b/models/issues/issue_stats.go @@ -5,7 +5,6 @@ package issues import ( "context" - "errors" "fmt" "code.gitea.io/gitea/models/db" @@ -81,9 +80,9 @@ func CountIssues(ctx context.Context, opts *IssuesOptions) (int64, error) { } // GetIssueStats returns issue statistic information by given conditions. -func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) { +func GetIssueStats(ctx context.Context, opts *IssuesOptions) (*IssueStats, error) { if len(opts.IssueIDs) <= MaxQueryParameters { - return getIssueStatsChunk(opts, opts.IssueIDs) + return getIssueStatsChunk(ctx, opts, opts.IssueIDs) } // If too long a list of IDs is provided, we get the statistics in @@ -96,7 +95,7 @@ func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) { if chunk > len(opts.IssueIDs) { chunk = len(opts.IssueIDs) } - stats, err := getIssueStatsChunk(opts, opts.IssueIDs[i:chunk]) + stats, err := getIssueStatsChunk(ctx, opts, opts.IssueIDs[i:chunk]) if err != nil { return nil, err } @@ -113,10 +112,10 @@ func GetIssueStats(opts *IssuesOptions) (*IssueStats, error) { return accum, nil } -func getIssueStatsChunk(opts *IssuesOptions, issueIDs []int64) (*IssueStats, error) { +func getIssueStatsChunk(ctx context.Context, opts *IssuesOptions, issueIDs []int64) (*IssueStats, error) { stats := &IssueStats{} - sess := db.GetEngine(db.DefaultContext). + sess := db.GetEngine(ctx). Join("INNER", "repository", "`issue`.repo_id = `repository`.id") var err error @@ -181,195 +180,6 @@ func applyIssuesOptions(sess *xorm.Session, opts *IssuesOptions, issueIDs []int6 return sess } -// GetUserIssueStats returns issue statistic information for dashboard by given conditions. -func GetUserIssueStats(filterMode int, opts IssuesOptions) (*IssueStats, error) { - if opts.User == nil { - return nil, errors.New("issue stats without user") - } - if opts.IsPull.IsNone() { - return nil, errors.New("unaccepted ispull option") - } - - var err error - stats := &IssueStats{} - - cond := builder.NewCond() - - cond = cond.And(builder.Eq{"issue.is_pull": opts.IsPull.IsTrue()}) - - if len(opts.RepoIDs) > 0 { - cond = cond.And(builder.In("issue.repo_id", opts.RepoIDs)) - } - if len(opts.IssueIDs) > 0 { - cond = cond.And(builder.In("issue.id", opts.IssueIDs)) - } - if opts.RepoCond != nil { - cond = cond.And(opts.RepoCond) - } - - if opts.User != nil { - cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue())) - } - - sess := func(cond builder.Cond) *xorm.Session { - s := db.GetEngine(db.DefaultContext). - Join("INNER", "repository", "`issue`.repo_id = `repository`.id"). - Where(cond) - if len(opts.LabelIDs) > 0 { - s.Join("INNER", "issue_label", "issue_label.issue_id = issue.id"). - In("issue_label.label_id", opts.LabelIDs) - } - - if opts.IsArchived != util.OptionalBoolNone { - s.And(builder.Eq{"repository.is_archived": opts.IsArchived.IsTrue()}) - } - return s - } - - switch filterMode { - case FilterModeAll, FilterModeYourRepositories: - stats.OpenCount, err = sess(cond). - And("issue.is_closed = ?", false). - Count(new(Issue)) - if err != nil { - return nil, err - } - stats.ClosedCount, err = sess(cond). - And("issue.is_closed = ?", true). - Count(new(Issue)) - if err != nil { - return nil, err - } - case FilterModeAssign: - stats.OpenCount, err = applyAssigneeCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", false). - Count(new(Issue)) - if err != nil { - return nil, err - } - stats.ClosedCount, err = applyAssigneeCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", true). - Count(new(Issue)) - if err != nil { - return nil, err - } - case FilterModeCreate: - stats.OpenCount, err = applyPosterCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", false). - Count(new(Issue)) - if err != nil { - return nil, err - } - stats.ClosedCount, err = applyPosterCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", true). - Count(new(Issue)) - if err != nil { - return nil, err - } - case FilterModeMention: - stats.OpenCount, err = applyMentionedCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", false). - Count(new(Issue)) - if err != nil { - return nil, err - } - stats.ClosedCount, err = applyMentionedCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", true). - Count(new(Issue)) - if err != nil { - return nil, err - } - case FilterModeReviewRequested: - stats.OpenCount, err = applyReviewRequestedCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", false). - Count(new(Issue)) - if err != nil { - return nil, err - } - stats.ClosedCount, err = applyReviewRequestedCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", true). - Count(new(Issue)) - if err != nil { - return nil, err - } - case FilterModeReviewed: - stats.OpenCount, err = applyReviewedCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", false). - Count(new(Issue)) - if err != nil { - return nil, err - } - stats.ClosedCount, err = applyReviewedCondition(sess(cond), opts.User.ID). - And("issue.is_closed = ?", true). - Count(new(Issue)) - if err != nil { - return nil, err - } - } - - cond = cond.And(builder.Eq{"issue.is_closed": opts.IsClosed.IsTrue()}) - stats.AssignCount, err = applyAssigneeCondition(sess(cond), opts.User.ID).Count(new(Issue)) - if err != nil { - return nil, err - } - - stats.CreateCount, err = applyPosterCondition(sess(cond), opts.User.ID).Count(new(Issue)) - if err != nil { - return nil, err - } - - stats.MentionCount, err = applyMentionedCondition(sess(cond), opts.User.ID).Count(new(Issue)) - if err != nil { - return nil, err - } - - stats.YourRepositoriesCount, err = sess(cond).Count(new(Issue)) - if err != nil { - return nil, err - } - - stats.ReviewRequestedCount, err = applyReviewRequestedCondition(sess(cond), opts.User.ID).Count(new(Issue)) - if err != nil { - return nil, err - } - - stats.ReviewedCount, err = applyReviewedCondition(sess(cond), opts.User.ID).Count(new(Issue)) - if err != nil { - return nil, err - } - - return stats, nil -} - -// GetRepoIssueStats returns number of open and closed repository issues by given filter mode. -func GetRepoIssueStats(repoID, uid int64, filterMode int, isPull bool) (numOpen, numClosed int64) { - countSession := func(isClosed, isPull bool, repoID int64) *xorm.Session { - sess := db.GetEngine(db.DefaultContext). - Where("is_closed = ?", isClosed). - And("is_pull = ?", isPull). - And("repo_id = ?", repoID) - - return sess - } - - openCountSession := countSession(false, isPull, repoID) - closedCountSession := countSession(true, isPull, repoID) - - switch filterMode { - case FilterModeAssign: - applyAssigneeCondition(openCountSession, uid) - applyAssigneeCondition(closedCountSession, uid) - case FilterModeCreate: - applyPosterCondition(openCountSession, uid) - applyPosterCondition(closedCountSession, uid) - } - - openResult, _ := openCountSession.Count(new(Issue)) - closedResult, _ := closedCountSession.Count(new(Issue)) - - return openResult, closedResult -} - // CountOrphanedIssues count issues without a repo func CountOrphanedIssues(ctx context.Context) (int64, error) { return db.GetEngine(ctx). diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index b2ff74f0cf5..4e98442c11f 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -13,12 +13,10 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/organization" 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" - "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" "xorm.io/builder" @@ -67,7 +65,7 @@ func TestIssueAPIURL(t *testing.T) { err := issue.LoadAttributes(db.DefaultContext) assert.NoError(t, err) - assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/issues/1", issue.APIURL()) + assert.Equal(t, "https://try.gitea.io/api/v1/repos/user2/repo1/issues/1", issue.APIURL(db.DefaultContext)) } func TestGetIssuesByIDs(t *testing.T) { @@ -204,128 +202,6 @@ func TestIssues(t *testing.T) { } } -func TestGetUserIssueStats(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - for _, test := range []struct { - FilterMode int - Opts issues_model.IssuesOptions - ExpectedIssueStats issues_model.IssueStats - }{ - { - issues_model.FilterModeAll, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}), - RepoIDs: []int64{1}, - IsPull: util.OptionalBoolFalse, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 1, // 6 - AssignCount: 1, // 6 - CreateCount: 1, // 6 - OpenCount: 1, // 6 - ClosedCount: 1, // 1 - }, - }, - { - issues_model.FilterModeAll, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}), - RepoIDs: []int64{1}, - IsPull: util.OptionalBoolFalse, - IsClosed: util.OptionalBoolTrue, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 1, // 6 - AssignCount: 0, - CreateCount: 0, - OpenCount: 1, // 6 - ClosedCount: 1, // 1 - }, - }, - { - issues_model.FilterModeAssign, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}), - IsPull: util.OptionalBoolFalse, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 1, // 6 - AssignCount: 1, // 6 - CreateCount: 1, // 6 - OpenCount: 1, // 6 - ClosedCount: 0, - }, - }, - { - issues_model.FilterModeCreate, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}), - IsPull: util.OptionalBoolFalse, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 1, // 6 - AssignCount: 1, // 6 - CreateCount: 1, // 6 - OpenCount: 1, // 6 - ClosedCount: 0, - }, - }, - { - issues_model.FilterModeMention, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}), - IsPull: util.OptionalBoolFalse, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 1, // 6 - AssignCount: 1, // 6 - CreateCount: 1, // 6 - MentionCount: 0, - OpenCount: 0, - ClosedCount: 0, - }, - }, - { - issues_model.FilterModeCreate, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}), - IssueIDs: []int64{1}, - IsPull: util.OptionalBoolFalse, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 1, // 1 - AssignCount: 1, // 1 - CreateCount: 1, // 1 - OpenCount: 1, // 1 - ClosedCount: 0, - }, - }, - { - issues_model.FilterModeAll, - issues_model.IssuesOptions{ - User: unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}), - Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}), - Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}), - IsPull: util.OptionalBoolFalse, - }, - issues_model.IssueStats{ - YourRepositoriesCount: 2, - AssignCount: 1, - CreateCount: 1, - OpenCount: 2, - }, - }, - } { - t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) { - stats, err := issues_model.GetUserIssueStats(test.FilterMode, test.Opts) - if !assert.NoError(t, err) { - return - } - assert.Equal(t, test.ExpectedIssueStats, *stats) - }) - } -} - func TestIssue_loadTotalTimes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) ms, err := issues_model.GetIssueByID(db.DefaultContext, 2) @@ -377,7 +253,7 @@ func testInsertIssue(t *testing.T, title, content string, expectIndex int64) *is Title: title, Content: content, } - err := issues_model.NewIssue(repo, &issue, nil, nil) + err := issues_model.NewIssue(db.DefaultContext, repo, &issue, nil, nil) assert.NoError(t, err) has, err := db.GetEngine(db.DefaultContext).ID(issue.ID).Get(&newIssue) @@ -493,7 +369,7 @@ func TestCorrectIssueStats(t *testing.T) { // Now we will call the GetIssueStats with these IDs and if working, // get the correct stats back. - issueStats, err := issues_model.GetIssueStats(&issues_model.IssuesOptions{ + issueStats, err := issues_model.GetIssueStats(db.DefaultContext, &issues_model.IssuesOptions{ RepoIDs: []int64{1}, IssueIDs: ids, }) @@ -509,7 +385,7 @@ func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}), } - assert.NoError(t, miles.LoadTotalTrackedTimes()) + assert.NoError(t, miles.LoadTotalTrackedTimes(db.DefaultContext)) assert.Equal(t, int64(3682), miles[0].TotalTrackedTime) } @@ -518,7 +394,7 @@ func TestLoadTotalTrackedTime(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) - assert.NoError(t, milestone.LoadTotalTrackedTime()) + assert.NoError(t, milestone.LoadTotalTrackedTime(db.DefaultContext)) assert.Equal(t, int64(3682), milestone.TotalTrackedTime) } @@ -527,7 +403,7 @@ func TestCountIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) count, err := issues_model.CountIssues(db.DefaultContext, &issues_model.IssuesOptions{}) assert.NoError(t, err) - assert.EqualValues(t, 19, count) + assert.EqualValues(t, 20, count) } func TestIssueLoadAttributes(t *testing.T) { @@ -601,7 +477,7 @@ func assertCreateIssues(t *testing.T, isPull bool) { Labels: []*issues_model.Label{label}, Reactions: []*issues_model.Reaction{reaction}, } - err := issues_model.InsertIssues(is) + err := issues_model.InsertIssues(db.DefaultContext, is) assert.NoError(t, err) i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title}) diff --git a/models/issues/issue_update.go b/models/issues/issue_update.go index 9607b21a675..b258dc882cb 100644 --- a/models/issues/issue_update.go +++ b/models/issues/issue_update.go @@ -165,8 +165,8 @@ func ChangeIssueTitle(ctx context.Context, issue *Issue, doer *user_model.User, } // ChangeIssueRef changes the branch of this issue, as the given user. -func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ChangeIssueRef(ctx context.Context, issue *Issue, doer *user_model.User, oldRef string) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -215,8 +215,8 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo * } // UpdateIssueAttachments update attachments by UUIDs for the issue -func UpdateIssueAttachments(issueID int64, uuids []string) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateIssueAttachments(ctx context.Context, issueID int64, uuids []string) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -235,8 +235,8 @@ func UpdateIssueAttachments(issueID int64, uuids []string) (err error) { } // ChangeIssueContent changes issue content, as the given user. -func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ChangeIssueContent(ctx context.Context, issue *Issue, doer *user_model.User, content string) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -381,8 +381,8 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue } // NewIssue creates new issue with labels for repository. -func NewIssue(repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *Issue, labelIDs []int64, uuids []string) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -432,8 +432,8 @@ func UpdateIssueMentions(ctx context.Context, issueID int64, mentions []*user_mo // UpdateIssueByAPI updates all allowed fields of given issue. // If the issue status is changed a statusChangeComment is returned // similarly if the title is changed the titleChanged bool is set to true -func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateIssueByAPI(ctx context.Context, issue *Issue, doer *user_model.User) (statusChangeComment *Comment, titleChanged bool, err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, false, err } @@ -486,12 +486,12 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment } // UpdateIssueDeadline updates an issue deadline and adds comments. Setting a deadline to 0 means deleting it. -func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) { +func UpdateIssueDeadline(ctx context.Context, issue *Issue, deadlineUnix timeutil.TimeStamp, doer *user_model.User) (err error) { // if the deadline hasn't changed do nothing if issue.DeadlineUnix == deadlineUnix { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -510,17 +510,6 @@ func UpdateIssueDeadline(issue *Issue, deadlineUnix timeutil.TimeStamp, doer *us return committer.Commit() } -// DeleteInIssue delete records in beans with external key issue_id = ? -func DeleteInIssue(ctx context.Context, issueID int64, beans ...any) error { - e := db.GetEngine(ctx) - for _, bean := range beans { - if _, err := e.In("issue_id", issueID).Delete(bean); err != nil { - return err - } - } - return nil -} - // FindAndUpdateIssueMentions finds users mentioned in the given content string, and saves them in the database. func FindAndUpdateIssueMentions(ctx context.Context, issue *Issue, doer *user_model.User, content string) (mentions []*user_model.User, err error) { rawMentions := references.FindAllMentionsMarkdown(content) @@ -669,8 +658,8 @@ func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *u } // UpdateIssuesMigrationsByType updates all migrated repositories' issues from gitServiceType to replace originalAuthorID to posterID -func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, posterID int64) error { - _, err := db.GetEngine(db.DefaultContext).Table("issue"). +func UpdateIssuesMigrationsByType(ctx context.Context, gitServiceType api.GitServiceType, originalAuthorID string, posterID int64) error { + _, err := db.GetEngine(ctx).Table("issue"). Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). And("original_author_id = ?", originalAuthorID). Update(map[string]any{ @@ -682,8 +671,8 @@ func UpdateIssuesMigrationsByType(gitServiceType api.GitServiceType, originalAut } // UpdateReactionsMigrationsByType updates all migrated repositories' reactions from gitServiceType to replace originalAuthorID to posterID -func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error { - _, err := db.GetEngine(db.DefaultContext).Table("reaction"). +func UpdateReactionsMigrationsByType(ctx context.Context, gitServiceType api.GitServiceType, originalAuthorID string, userID int64) error { + _, err := db.GetEngine(ctx).Table("reaction"). Where("original_author_id = ?", originalAuthorID). And(migratedIssueCond(gitServiceType)). Update(map[string]any{ @@ -696,85 +685,100 @@ func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, original // DeleteIssuesByRepoID deletes issues by repositories id func DeleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []string, err error) { - deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID}) - + // MariaDB has a performance bug: https://jira.mariadb.org/browse/MDEV-16289 + // so here it uses "DELETE ... WHERE IN" with pre-queried IDs. sess := db.GetEngine(ctx) - // Delete content histories - if _, err = sess.In("issue_id", deleteCond). - Delete(&ContentHistory{}); err != nil { - return nil, err - } - // Delete comments and attachments - if _, err = sess.In("issue_id", deleteCond). - Delete(&Comment{}); err != nil { - return nil, err - } + for { + issueIDs := make([]int64, 0, db.DefaultMaxInSize) - // Dependencies for issues in this repository - if _, err = sess.In("issue_id", deleteCond). - Delete(&IssueDependency{}); err != nil { - return nil, err - } + err := sess.Table(&Issue{}).Where("repo_id = ?", repoID).OrderBy("id").Limit(db.DefaultMaxInSize).Cols("id").Find(&issueIDs) + if err != nil { + return nil, err + } - // Delete dependencies for issues in other repositories - if _, err = sess.In("dependency_id", deleteCond). - Delete(&IssueDependency{}); err != nil { - return nil, err - } + if len(issueIDs) == 0 { + break + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&IssueUser{}); err != nil { - return nil, err - } + // Delete content histories + _, err = sess.In("issue_id", issueIDs).Delete(&ContentHistory{}) + if err != nil { + return nil, err + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&Reaction{}); err != nil { - return nil, err - } + // Delete comments and attachments + _, err = sess.In("issue_id", issueIDs).Delete(&Comment{}) + if err != nil { + return nil, err + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&IssueWatch{}); err != nil { - return nil, err - } + // Dependencies for issues in this repository + _, err = sess.In("issue_id", issueIDs).Delete(&IssueDependency{}) + if err != nil { + return nil, err + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&Stopwatch{}); err != nil { - return nil, err - } + // Delete dependencies for issues in other repositories + _, err = sess.In("dependency_id", issueIDs).Delete(&IssueDependency{}) + if err != nil { + return nil, err + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&TrackedTime{}); err != nil { - return nil, err - } + _, err = sess.In("issue_id", issueIDs).Delete(&IssueUser{}) + if err != nil { + return nil, err + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&project_model.ProjectIssue{}); err != nil { - return nil, err - } + _, err = sess.In("issue_id", issueIDs).Delete(&Reaction{}) + if err != nil { + return nil, err + } - if _, err = sess.In("dependent_issue_id", deleteCond). - Delete(&Comment{}); err != nil { - return nil, err - } + _, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{}) + if err != nil { + return nil, err + } - var attachments []*repo_model.Attachment - if err = sess.In("issue_id", deleteCond). - Find(&attachments); err != nil { - return nil, err - } + _, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{}) + if err != nil { + return nil, err + } - for j := range attachments { - attachmentPaths = append(attachmentPaths, attachments[j].RelativePath()) - } + _, err = sess.In("issue_id", issueIDs).Delete(&TrackedTime{}) + if err != nil { + return nil, err + } - if _, err = sess.In("issue_id", deleteCond). - Delete(&repo_model.Attachment{}); err != nil { - return nil, err - } + _, err = sess.In("issue_id", issueIDs).Delete(&project_model.ProjectIssue{}) + if err != nil { + return nil, err + } - if _, err = db.DeleteByBean(ctx, &Issue{RepoID: repoID}); err != nil { - return nil, err + _, err = sess.In("dependent_issue_id", issueIDs).Delete(&Comment{}) + if err != nil { + return nil, err + } + + var attachments []*repo_model.Attachment + err = sess.In("issue_id", issueIDs).Find(&attachments) + if err != nil { + return nil, err + } + + for j := range attachments { + attachmentPaths = append(attachmentPaths, attachments[j].RelativePath()) + } + + _, err = sess.In("issue_id", issueIDs).Delete(&repo_model.Attachment{}) + if err != nil { + return nil, err + } + + _, err = sess.In("id", issueIDs).Delete(&Issue{}) + if err != nil { + return nil, err + } } return attachmentPaths, err @@ -809,7 +813,7 @@ func DeleteOrphanedIssues(ctx context.Context) error { // Remove issue attachment files. for i := range attachmentPaths { - system_model.RemoveAllWithNotice(db.DefaultContext, "Delete issue attachment", attachmentPaths[i]) + system_model.RemoveAllWithNotice(ctx, "Delete issue attachment", attachmentPaths[i]) } return nil } diff --git a/models/issues/issue_user.go b/models/issues/issue_user.go index d053b1d5435..24bb74648d9 100644 --- a/models/issues/issue_user.go +++ b/models/issues/issue_user.go @@ -15,7 +15,7 @@ import ( type IssueUser struct { ID int64 `xorm:"pk autoincr"` UID int64 `xorm:"INDEX"` // User ID. - IssueID int64 + IssueID int64 `xorm:"INDEX"` IsRead bool IsMentioned bool } diff --git a/models/issues/issue_watch.go b/models/issues/issue_watch.go index 1efc0ea6871..9e616a0eb13 100644 --- a/models/issues/issue_watch.go +++ b/models/issues/issue_watch.go @@ -30,8 +30,8 @@ func init() { type IssueWatchList []*IssueWatch // CreateOrUpdateIssueWatch set watching for a user and issue -func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error { - iw, exists, err := GetIssueWatch(db.DefaultContext, userID, issueID) +func CreateOrUpdateIssueWatch(ctx context.Context, userID, issueID int64, isWatching bool) error { + iw, exists, err := GetIssueWatch(ctx, userID, issueID) if err != nil { return err } @@ -43,13 +43,13 @@ func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error { IsWatching: isWatching, } - if _, err := db.GetEngine(db.DefaultContext).Insert(iw); err != nil { + if _, err := db.GetEngine(ctx).Insert(iw); err != nil { return err } } else { iw.IsWatching = isWatching - if _, err := db.GetEngine(db.DefaultContext).ID(iw.ID).Cols("is_watching", "updated_unix").Update(iw); err != nil { + if _, err := db.GetEngine(ctx).ID(iw.ID).Cols("is_watching", "updated_unix").Update(iw); err != nil { return err } } @@ -69,19 +69,19 @@ func GetIssueWatch(ctx context.Context, userID, issueID int64) (iw *IssueWatch, // CheckIssueWatch check if an user is watching an issue // it takes participants and repo watch into account -func CheckIssueWatch(user *user_model.User, issue *Issue) (bool, error) { - iw, exist, err := GetIssueWatch(db.DefaultContext, user.ID, issue.ID) +func CheckIssueWatch(ctx context.Context, user *user_model.User, issue *Issue) (bool, error) { + iw, exist, err := GetIssueWatch(ctx, user.ID, issue.ID) if err != nil { return false, err } if exist { return iw.IsWatching, nil } - w, err := repo_model.GetWatch(db.DefaultContext, user.ID, issue.RepoID) + w, err := repo_model.GetWatch(ctx, user.ID, issue.RepoID) if err != nil { return false, err } - return repo_model.IsWatchMode(w.Mode) || IsUserParticipantsOfIssue(user, issue), nil + return repo_model.IsWatchMode(w.Mode) || IsUserParticipantsOfIssue(ctx, user, issue), nil } // GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id diff --git a/models/issues/issue_watch_test.go b/models/issues/issue_watch_test.go index 4f44487f567..d4ce8d8d3d6 100644 --- a/models/issues/issue_watch_test.go +++ b/models/issues/issue_watch_test.go @@ -16,11 +16,11 @@ import ( func TestCreateOrUpdateIssueWatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(3, 1, true)) + assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(db.DefaultContext, 3, 1, true)) 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)) + assert.NoError(t, issues_model.CreateOrUpdateIssueWatch(db.DefaultContext, 1, 1, false)) iw = unittest.AssertExistsAndLoadBean(t, &issues_model.IssueWatch{UserID: 1, IssueID: 1}) assert.False(t, iw.IsWatching) } diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go index a1086f9e812..77ef53a0132 100644 --- a/models/issues/issue_xref.go +++ b/models/issues/issue_xref.go @@ -252,22 +252,22 @@ func (c *Comment) neuterCrossReferences(ctx context.Context) error { } // LoadRefComment loads comment that created this reference from database -func (c *Comment) LoadRefComment() (err error) { +func (c *Comment) LoadRefComment(ctx context.Context) (err error) { if c.RefComment != nil { return nil } - c.RefComment, err = GetCommentByID(db.DefaultContext, c.RefCommentID) + c.RefComment, err = GetCommentByID(ctx, c.RefCommentID) return err } // LoadRefIssue loads comment that created this reference from database -func (c *Comment) LoadRefIssue() (err error) { +func (c *Comment) LoadRefIssue(ctx context.Context) (err error) { if c.RefIssue != nil { return nil } - c.RefIssue, err = GetIssueByID(db.DefaultContext, c.RefIssueID) + c.RefIssue, err = GetIssueByID(ctx, c.RefIssueID) if err == nil { - err = c.RefIssue.LoadRepo(db.DefaultContext) + err = c.RefIssue.LoadRepo(ctx) } return err } @@ -278,21 +278,21 @@ func CommentTypeIsRef(t CommentType) bool { } // RefCommentLink returns the relative URL for the comment that created this reference -func (c *Comment) RefCommentLink() string { +func (c *Comment) RefCommentLink(ctx context.Context) string { // Edge case for when the reference is inside the title or the description of the referring issue if c.RefCommentID == 0 { - return c.RefIssueLink() + return c.RefIssueLink(ctx) } - if err := c.LoadRefComment(); err != nil { // Silently dropping errors :unamused: + if err := c.LoadRefComment(ctx); err != nil { // Silently dropping errors :unamused: log.Error("LoadRefComment(%d): %v", c.RefCommentID, err) return "" } - return c.RefComment.Link() + return c.RefComment.Link(ctx) } // RefIssueLink returns the relative URL of the issue where this reference was created -func (c *Comment) RefIssueLink() string { - if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused: +func (c *Comment) RefIssueLink(ctx context.Context) string { + if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused: log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err) return "" } @@ -300,8 +300,8 @@ func (c *Comment) RefIssueLink() string { } // RefIssueTitle returns the title of the issue where this reference was created -func (c *Comment) RefIssueTitle() string { - if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused: +func (c *Comment) RefIssueTitle(ctx context.Context) string { + if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused: log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err) return "" } @@ -309,8 +309,8 @@ func (c *Comment) RefIssueTitle() string { } // RefIssueIdent returns the user friendly identity (e.g. "#1234") of the issue where this reference was created -func (c *Comment) RefIssueIdent() string { - if err := c.LoadRefIssue(); err != nil { // Silently dropping errors :unamused: +func (c *Comment) RefIssueIdent(ctx context.Context) string { + if err := c.LoadRefIssue(ctx); err != nil { // Silently dropping errors :unamused: log.Error("LoadRefIssue(%d): %v", c.RefCommentID, err) return "" } diff --git a/models/issues/label.go b/models/issues/label.go index 0087c933a6c..f8dbb9e39cd 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -199,8 +199,8 @@ func NewLabel(ctx context.Context, l *Label) error { } // NewLabels creates new labels -func NewLabels(labels ...*Label) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func NewLabels(ctx context.Context, labels ...*Label) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -221,19 +221,19 @@ func NewLabels(labels ...*Label) error { } // UpdateLabel updates label information. -func UpdateLabel(l *Label) error { +func UpdateLabel(ctx context.Context, l *Label) error { color, err := label.NormalizeColor(l.Color) if err != nil { return err } l.Color = color - return updateLabelCols(db.DefaultContext, l, "name", "description", "color", "exclusive", "archived_unix") + return updateLabelCols(ctx, l, "name", "description", "color", "exclusive", "archived_unix") } // DeleteLabel delete a label -func DeleteLabel(id, labelID int64) error { - l, err := GetLabelByID(db.DefaultContext, labelID) +func DeleteLabel(ctx context.Context, id, labelID int64) error { + l, err := GetLabelByID(ctx, labelID) if err != nil { if IsErrLabelNotExist(err) { return nil @@ -241,7 +241,7 @@ func DeleteLabel(id, labelID int64) error { return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -289,9 +289,9 @@ func GetLabelByID(ctx context.Context, labelID int64) (*Label, error) { } // GetLabelsByIDs returns a list of labels by IDs -func GetLabelsByIDs(labelIDs []int64, cols ...string) ([]*Label, error) { +func GetLabelsByIDs(ctx context.Context, labelIDs []int64, cols ...string) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) - return labels, db.GetEngine(db.DefaultContext).Table("label"). + return labels, db.GetEngine(ctx).Table("label"). In("id", labelIDs). Asc("name"). Cols(cols...). @@ -339,9 +339,9 @@ func GetLabelInRepoByID(ctx context.Context, repoID, labelID int64) (*Label, err // GetLabelIDsInRepoByNames returns a list of labelIDs by names in a given // repository. // it silently ignores label names that do not belong to the repository. -func GetLabelIDsInRepoByNames(repoID int64, labelNames []string) ([]int64, error) { +func GetLabelIDsInRepoByNames(ctx context.Context, repoID int64, labelNames []string) ([]int64, error) { labelIDs := make([]int64, 0, len(labelNames)) - return labelIDs, db.GetEngine(db.DefaultContext).Table("label"). + return labelIDs, db.GetEngine(ctx).Table("label"). Where("repo_id = ?", repoID). In("name", labelNames). Asc("name"). @@ -398,8 +398,8 @@ func GetLabelsByRepoID(ctx context.Context, repoID int64, sortType string, listO } // CountLabelsByRepoID count number of all labels that belong to given repository by ID. -func CountLabelsByRepoID(repoID int64) (int64, error) { - return db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).Count(&Label{}) +func CountLabelsByRepoID(ctx context.Context, repoID int64) (int64, error) { + return db.GetEngine(ctx).Where("repo_id = ?", repoID).Count(&Label{}) } // GetLabelInOrgByName returns a label by name in given organization. @@ -442,13 +442,13 @@ func GetLabelInOrgByID(ctx context.Context, orgID, labelID int64) (*Label, error // GetLabelIDsInOrgByNames returns a list of labelIDs by names in a given // organization. -func GetLabelIDsInOrgByNames(orgID int64, labelNames []string) ([]int64, error) { +func GetLabelIDsInOrgByNames(ctx context.Context, orgID int64, labelNames []string) ([]int64, error) { if orgID <= 0 { return nil, ErrOrgLabelNotExist{0, orgID} } labelIDs := make([]int64, 0, len(labelNames)) - return labelIDs, db.GetEngine(db.DefaultContext).Table("label"). + return labelIDs, db.GetEngine(ctx).Table("label"). Where("org_id = ?", orgID). In("name", labelNames). Asc("name"). @@ -506,8 +506,8 @@ func GetLabelIDsByNames(ctx context.Context, labelNames []string) ([]int64, erro } // CountLabelsByOrgID count all labels that belong to given organization by ID. -func CountLabelsByOrgID(orgID int64) (int64, error) { - return db.GetEngine(db.DefaultContext).Where("org_id = ?", orgID).Count(&Label{}) +func CountLabelsByOrgID(ctx context.Context, orgID int64) (int64, error) { + return db.GetEngine(ctx).Where("org_id = ?", orgID).Count(&Label{}) } func updateLabelCols(ctx context.Context, l *Label, cols ...string) error { diff --git a/models/issues/label_test.go b/models/issues/label_test.go index 3f0e980b318..9f44cd3e037 100644 --- a/models/issues/label_test.go +++ b/models/issues/label_test.go @@ -48,7 +48,7 @@ func TestNewLabels(t *testing.T) { for _, label := range labels { unittest.AssertNotExistsBean(t, label) } - assert.NoError(t, issues_model.NewLabels(labels...)) + assert.NoError(t, issues_model.NewLabels(db.DefaultContext, labels...)) for _, label := range labels { unittest.AssertExistsAndLoadBean(t, label, unittest.Cond("id = ?", label.ID)) } @@ -81,7 +81,7 @@ func TestGetLabelInRepoByName(t *testing.T) { func TestGetLabelInRepoByNames(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - labelIDs, err := issues_model.GetLabelIDsInRepoByNames(1, []string{"label1", "label2"}) + labelIDs, err := issues_model.GetLabelIDsInRepoByNames(db.DefaultContext, 1, []string{"label1", "label2"}) assert.NoError(t, err) assert.Len(t, labelIDs, 2) @@ -93,7 +93,7 @@ func TestGetLabelInRepoByNames(t *testing.T) { func TestGetLabelInRepoByNamesDiscardsNonExistentLabels(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // label3 doesn't exists.. See labels.yml - labelIDs, err := issues_model.GetLabelIDsInRepoByNames(1, []string{"label1", "label2", "label3"}) + labelIDs, err := issues_model.GetLabelIDsInRepoByNames(db.DefaultContext, 1, []string{"label1", "label2", "label3"}) assert.NoError(t, err) assert.Len(t, labelIDs, 2) @@ -166,7 +166,7 @@ func TestGetLabelInOrgByName(t *testing.T) { func TestGetLabelInOrgByNames(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - labelIDs, err := issues_model.GetLabelIDsInOrgByNames(3, []string{"orglabel3", "orglabel4"}) + labelIDs, err := issues_model.GetLabelIDsInOrgByNames(db.DefaultContext, 3, []string{"orglabel3", "orglabel4"}) assert.NoError(t, err) assert.Len(t, labelIDs, 2) @@ -178,7 +178,7 @@ func TestGetLabelInOrgByNames(t *testing.T) { func TestGetLabelInOrgByNamesDiscardsNonExistentLabels(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // orglabel99 doesn't exists.. See labels.yml - labelIDs, err := issues_model.GetLabelIDsInOrgByNames(3, []string{"orglabel3", "orglabel4", "orglabel99"}) + labelIDs, err := issues_model.GetLabelIDsInOrgByNames(db.DefaultContext, 3, []string{"orglabel3", "orglabel4", "orglabel99"}) assert.NoError(t, err) assert.Len(t, labelIDs, 2) @@ -269,7 +269,7 @@ func TestUpdateLabel(t *testing.T) { } label.Color = update.Color label.Name = update.Name - assert.NoError(t, issues_model.UpdateLabel(update)) + assert.NoError(t, issues_model.UpdateLabel(db.DefaultContext, update)) newLabel := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) assert.EqualValues(t, label.ID, newLabel.ID) assert.EqualValues(t, label.Color, newLabel.Color) @@ -282,13 +282,13 @@ func TestUpdateLabel(t *testing.T) { func TestDeleteLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) label := unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: 1}) - assert.NoError(t, issues_model.DeleteLabel(label.RepoID, label.ID)) + assert.NoError(t, issues_model.DeleteLabel(db.DefaultContext, label.RepoID, label.ID)) unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID, RepoID: label.RepoID}) - assert.NoError(t, issues_model.DeleteLabel(label.RepoID, label.ID)) + assert.NoError(t, issues_model.DeleteLabel(db.DefaultContext, label.RepoID, label.ID)) unittest.AssertNotExistsBean(t, &issues_model.Label{ID: label.ID}) - assert.NoError(t, issues_model.DeleteLabel(unittest.NonexistentID, unittest.NonexistentID)) + assert.NoError(t, issues_model.DeleteLabel(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)) unittest.CheckConsistencyFor(t, &issues_model.Label{}, &repo_model.Repository{}) } diff --git a/models/issues/main_test.go b/models/issues/main_test.go index 190df027f4f..ba83ca55524 100644 --- a/models/issues/main_test.go +++ b/models/issues/main_test.go @@ -4,7 +4,6 @@ package issues_test import ( - "path/filepath" "testing" issues_model "code.gitea.io/gitea/models/issues" @@ -30,7 +29,5 @@ func TestFixturesAreConsistent(t *testing.T) { } func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/issues/milestone.go b/models/issues/milestone.go index c15b2a41fe3..ad1d5d04532 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -103,8 +103,8 @@ func (m *Milestone) State() api.StateType { } // NewMilestone creates new milestone of repository. -func NewMilestone(m *Milestone) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func NewMilestone(ctx context.Context, m *Milestone) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -140,9 +140,9 @@ func GetMilestoneByRepoID(ctx context.Context, repoID, id int64) (*Milestone, er } // GetMilestoneByRepoIDANDName return a milestone if one exist by name and repo -func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error) { +func GetMilestoneByRepoIDANDName(ctx context.Context, repoID int64, name string) (*Milestone, error) { var mile Milestone - has, err := db.GetEngine(db.DefaultContext).Where("repo_id=? AND name=?", repoID, name).Get(&mile) + has, err := db.GetEngine(ctx).Where("repo_id=? AND name=?", repoID, name).Get(&mile) if err != nil { return nil, err } @@ -153,8 +153,8 @@ func GetMilestoneByRepoIDANDName(repoID int64, name string) (*Milestone, error) } // UpdateMilestone updates information of given milestone. -func UpdateMilestone(m *Milestone, oldIsClosed bool) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateMilestone(ctx context.Context, m *Milestone, oldIsClosed bool) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -211,8 +211,8 @@ func UpdateMilestoneCounters(ctx context.Context, id int64) error { } // ChangeMilestoneStatusByRepoIDAndID changes a milestone open/closed status if the milestone ID is in the repo. -func ChangeMilestoneStatusByRepoIDAndID(repoID, milestoneID int64, isClosed bool) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ChangeMilestoneStatusByRepoIDAndID(ctx context.Context, repoID, milestoneID int64, isClosed bool) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -238,8 +238,8 @@ func ChangeMilestoneStatusByRepoIDAndID(repoID, milestoneID int64, isClosed bool } // ChangeMilestoneStatus changes the milestone open/closed status. -func ChangeMilestoneStatus(m *Milestone, isClosed bool) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ChangeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -269,8 +269,8 @@ func changeMilestoneStatus(ctx context.Context, m *Milestone, isClosed bool) err } // DeleteMilestoneByRepoID deletes a milestone from a repository. -func DeleteMilestoneByRepoID(repoID, id int64) error { - m, err := GetMilestoneByRepoID(db.DefaultContext, repoID, id) +func DeleteMilestoneByRepoID(ctx context.Context, repoID, id int64) error { + m, err := GetMilestoneByRepoID(ctx, repoID, id) if err != nil { if IsErrMilestoneNotExist(err) { return nil @@ -278,12 +278,12 @@ func DeleteMilestoneByRepoID(repoID, id int64) error { return err } - repo, err := repo_model.GetRepositoryByID(db.DefaultContext, m.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, m.RepoID) if err != nil { return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -332,7 +332,8 @@ func updateRepoMilestoneNum(ctx context.Context, repoID int64) error { return err } -func (m *Milestone) loadTotalTrackedTime(ctx context.Context) error { +// LoadTotalTrackedTime loads the tracked time for the milestone +func (m *Milestone) LoadTotalTrackedTime(ctx context.Context) error { type totalTimesByMilestone struct { MilestoneID int64 Time int64 @@ -355,18 +356,13 @@ func (m *Milestone) loadTotalTrackedTime(ctx context.Context) error { return nil } -// LoadTotalTrackedTime loads the tracked time for the milestone -func (m *Milestone) LoadTotalTrackedTime() error { - return m.loadTotalTrackedTime(db.DefaultContext) -} - // InsertMilestones creates milestones of repository. -func InsertMilestones(ms ...*Milestone) (err error) { +func InsertMilestones(ctx context.Context, ms ...*Milestone) (err error) { if len(ms) == 0 { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/issues/milestone_list.go b/models/issues/milestone_list.go index b0c29106a03..d5c9b1358c8 100644 --- a/models/issues/milestone_list.go +++ b/models/issues/milestone_list.go @@ -100,9 +100,9 @@ func GetMilestoneIDsByNames(ctx context.Context, names []string) ([]int64, error } // SearchMilestones search milestones -func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType, keyword string) (MilestoneList, error) { +func SearchMilestones(ctx context.Context, repoCond builder.Cond, page int, isClosed bool, sortType, keyword string) (MilestoneList, error) { miles := make([]*Milestone, 0, setting.UI.IssuePagingNum) - sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed) + sess := db.GetEngine(ctx).Where("is_closed = ?", isClosed) if len(keyword) > 0 { sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)}) } @@ -131,8 +131,9 @@ func SearchMilestones(repoCond builder.Cond, page int, isClosed bool, sortType, } // GetMilestonesByRepoIDs returns a list of milestones of given repositories and status. -func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) { +func GetMilestonesByRepoIDs(ctx context.Context, repoIDs []int64, page int, isClosed bool, sortType string) (MilestoneList, error) { return SearchMilestones( + ctx, builder.In("repo_id", repoIDs), page, isClosed, @@ -141,7 +142,8 @@ func GetMilestonesByRepoIDs(repoIDs []int64, page int, isClosed bool, sortType s ) } -func (milestones MilestoneList) loadTotalTrackedTimes(ctx context.Context) error { +// LoadTotalTrackedTimes loads for every milestone in the list the TotalTrackedTime by a batch request +func (milestones MilestoneList) LoadTotalTrackedTimes(ctx context.Context) error { type totalTimesByMilestone struct { MilestoneID int64 Time int64 @@ -181,11 +183,6 @@ func (milestones MilestoneList) loadTotalTrackedTimes(ctx context.Context) error return nil } -// LoadTotalTrackedTimes loads for every milestone in the list the TotalTrackedTime by a batch request -func (milestones MilestoneList) LoadTotalTrackedTimes() error { - return milestones.loadTotalTrackedTimes(db.DefaultContext) -} - // CountMilestones returns number of milestones in given repository with other options func CountMilestones(ctx context.Context, opts GetMilestonesOption) (int64, error) { return db.GetEngine(ctx). @@ -194,8 +191,8 @@ func CountMilestones(ctx context.Context, opts GetMilestonesOption) (int64, erro } // CountMilestonesByRepoCond map from repo conditions to number of milestones matching the options` -func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64]int64, error) { - sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed) +func CountMilestonesByRepoCond(ctx context.Context, repoCond builder.Cond, isClosed bool) (map[int64]int64, error) { + sess := db.GetEngine(ctx).Where("is_closed = ?", isClosed) if repoCond.IsValid() { sess.In("repo_id", builder.Select("id").From("repository").Where(repoCond)) } @@ -219,8 +216,8 @@ func CountMilestonesByRepoCond(repoCond builder.Cond, isClosed bool) (map[int64] } // CountMilestonesByRepoCondAndKw map from repo conditions and the keyword of milestones' name to number of milestones matching the options` -func CountMilestonesByRepoCondAndKw(repoCond builder.Cond, keyword string, isClosed bool) (map[int64]int64, error) { - sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", isClosed) +func CountMilestonesByRepoCondAndKw(ctx context.Context, repoCond builder.Cond, keyword string, isClosed bool) (map[int64]int64, error) { + sess := db.GetEngine(ctx).Where("is_closed = ?", isClosed) if len(keyword) > 0 { sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)}) } @@ -257,11 +254,11 @@ func (m MilestonesStats) Total() int64 { } // GetMilestonesStatsByRepoCond returns milestone statistic information for dashboard by given conditions. -func GetMilestonesStatsByRepoCond(repoCond builder.Cond) (*MilestonesStats, error) { +func GetMilestonesStatsByRepoCond(ctx context.Context, repoCond builder.Cond) (*MilestonesStats, error) { var err error stats := &MilestonesStats{} - sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", false) + sess := db.GetEngine(ctx).Where("is_closed = ?", false) if repoCond.IsValid() { sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond))) } @@ -270,7 +267,7 @@ func GetMilestonesStatsByRepoCond(repoCond builder.Cond) (*MilestonesStats, erro return nil, err } - sess = db.GetEngine(db.DefaultContext).Where("is_closed = ?", true) + sess = db.GetEngine(ctx).Where("is_closed = ?", true) if repoCond.IsValid() { sess.And(builder.In("repo_id", builder.Select("id").From("repository").Where(repoCond))) } @@ -283,11 +280,11 @@ func GetMilestonesStatsByRepoCond(repoCond builder.Cond) (*MilestonesStats, erro } // GetMilestonesStatsByRepoCondAndKw returns milestone statistic information for dashboard by given repo conditions and name keyword. -func GetMilestonesStatsByRepoCondAndKw(repoCond builder.Cond, keyword string) (*MilestonesStats, error) { +func GetMilestonesStatsByRepoCondAndKw(ctx context.Context, repoCond builder.Cond, keyword string) (*MilestonesStats, error) { var err error stats := &MilestonesStats{} - sess := db.GetEngine(db.DefaultContext).Where("is_closed = ?", false) + sess := db.GetEngine(ctx).Where("is_closed = ?", false) if len(keyword) > 0 { sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)}) } @@ -299,7 +296,7 @@ func GetMilestonesStatsByRepoCondAndKw(repoCond builder.Cond, keyword string) (* return nil, err } - sess = db.GetEngine(db.DefaultContext).Where("is_closed = ?", true) + sess = db.GetEngine(ctx).Where("is_closed = ?", true) if len(keyword) > 0 { sess = sess.And(builder.Like{"UPPER(name)", strings.ToUpper(keyword)}) } diff --git a/models/issues/milestone_test.go b/models/issues/milestone_test.go index e85d77ebc84..403eeaadb32 100644 --- a/models/issues/milestone_test.go +++ b/models/issues/milestone_test.go @@ -201,12 +201,12 @@ func TestCountMilestonesByRepoIDs(t *testing.T) { repo1OpenCount, repo1ClosedCount := milestonesCount(1) repo2OpenCount, repo2ClosedCount := milestonesCount(2) - openCounts, err := issues_model.CountMilestonesByRepoCond(builder.In("repo_id", []int64{1, 2}), false) + openCounts, err := issues_model.CountMilestonesByRepoCond(db.DefaultContext, builder.In("repo_id", []int64{1, 2}), false) assert.NoError(t, err) assert.EqualValues(t, repo1OpenCount, openCounts[1]) assert.EqualValues(t, repo2OpenCount, openCounts[2]) - closedCounts, err := issues_model.CountMilestonesByRepoCond(builder.In("repo_id", []int64{1, 2}), true) + closedCounts, err := issues_model.CountMilestonesByRepoCond(db.DefaultContext, builder.In("repo_id", []int64{1, 2}), true) assert.NoError(t, err) assert.EqualValues(t, repo1ClosedCount, closedCounts[1]) assert.EqualValues(t, repo2ClosedCount, closedCounts[2]) @@ -218,7 +218,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) { 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) + openMilestones, err := issues_model.GetMilestonesByRepoIDs(db.DefaultContext, []int64{repo1.ID, repo2.ID}, page, false, sortType) assert.NoError(t, err) assert.Len(t, openMilestones, repo1.NumOpenMilestones+repo2.NumOpenMilestones) values := make([]int, len(openMilestones)) @@ -227,7 +227,7 @@ func TestGetMilestonesByRepoIDs(t *testing.T) { } assert.True(t, sort.IntsAreSorted(values)) - closedMilestones, err := issues_model.GetMilestonesByRepoIDs([]int64{repo1.ID, repo2.ID}, page, true, sortType) + closedMilestones, err := issues_model.GetMilestonesByRepoIDs(db.DefaultContext, []int64{repo1.ID, repo2.ID}, page, true, sortType) assert.NoError(t, err) assert.Len(t, closedMilestones, repo1.NumClosedMilestones+repo2.NumClosedMilestones) values = make([]int, len(closedMilestones)) @@ -262,7 +262,7 @@ func TestGetMilestonesStats(t *testing.T) { test := func(repoID int64) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) - stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": repoID})) + stats, err := issues_model.GetMilestonesStatsByRepoCond(db.DefaultContext, builder.And(builder.Eq{"repo_id": repoID})) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones-repo.NumClosedMilestones, stats.OpenCount) assert.EqualValues(t, repo.NumClosedMilestones, stats.ClosedCount) @@ -271,7 +271,7 @@ func TestGetMilestonesStats(t *testing.T) { test(2) test(3) - stats, err := issues_model.GetMilestonesStatsByRepoCond(builder.And(builder.Eq{"repo_id": unittest.NonexistentID})) + stats, err := issues_model.GetMilestonesStatsByRepoCond(db.DefaultContext, builder.And(builder.Eq{"repo_id": unittest.NonexistentID})) assert.NoError(t, err) assert.EqualValues(t, 0, stats.OpenCount) assert.EqualValues(t, 0, stats.ClosedCount) @@ -279,7 +279,7 @@ func TestGetMilestonesStats(t *testing.T) { 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})) + milestoneStats, err := issues_model.GetMilestonesStatsByRepoCond(db.DefaultContext, builder.In("repo_id", []int64{repo1.ID, repo2.ID})) assert.NoError(t, err) assert.EqualValues(t, repo1.NumOpenMilestones+repo2.NumOpenMilestones, milestoneStats.OpenCount) assert.EqualValues(t, repo1.NumClosedMilestones+repo2.NumClosedMilestones, milestoneStats.ClosedCount) @@ -293,7 +293,7 @@ func TestNewMilestone(t *testing.T) { Content: "milestoneContent", } - assert.NoError(t, issues_model.NewMilestone(milestone)) + assert.NoError(t, issues_model.NewMilestone(db.DefaultContext, milestone)) unittest.AssertExistsAndLoadBean(t, milestone) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{}) } @@ -302,22 +302,22 @@ func TestChangeMilestoneStatus(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) - assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, true)) + assert.NoError(t, issues_model.ChangeMilestoneStatus(db.DefaultContext, milestone, true)) unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=1") unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{}) - assert.NoError(t, issues_model.ChangeMilestoneStatus(milestone, false)) + assert.NoError(t, issues_model.ChangeMilestoneStatus(db.DefaultContext, milestone, false)) unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}, "is_closed=0") unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: milestone.RepoID}, &issues_model.Milestone{}) } func TestDeleteMilestoneByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.NoError(t, issues_model.DeleteMilestoneByRepoID(1, 1)) + assert.NoError(t, issues_model.DeleteMilestoneByRepoID(db.DefaultContext, 1, 1)) unittest.AssertNotExistsBean(t, &issues_model.Milestone{ID: 1}) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: 1}) - assert.NoError(t, issues_model.DeleteMilestoneByRepoID(unittest.NonexistentID, unittest.NonexistentID)) + assert.NoError(t, issues_model.DeleteMilestoneByRepoID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)) } func TestUpdateMilestone(t *testing.T) { @@ -326,7 +326,7 @@ func TestUpdateMilestone(t *testing.T) { milestone := unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) milestone.Name = " newMilestoneName " milestone.Content = "newMilestoneContent" - assert.NoError(t, issues_model.UpdateMilestone(milestone, milestone.IsClosed)) + assert.NoError(t, issues_model.UpdateMilestone(db.DefaultContext, milestone, milestone.IsClosed)) milestone = unittest.AssertExistsAndLoadBean(t, &issues_model.Milestone{ID: 1}) assert.EqualValues(t, "newMilestoneName", milestone.Name) unittest.CheckConsistencyFor(t, &issues_model.Milestone{}) @@ -361,7 +361,7 @@ func TestMigrate_InsertMilestones(t *testing.T) { RepoID: repo.ID, Name: name, } - err := issues_model.InsertMilestones(ms) + err := issues_model.InsertMilestones(db.DefaultContext, ms) assert.NoError(t, err) unittest.AssertExistsAndLoadBean(t, ms) repoModified := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repo.ID}) diff --git a/models/issues/pull.go b/models/issues/pull.go index 1c163ecca41..9adcaee1a1a 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -311,7 +311,7 @@ func (pr *PullRequest) LoadRequestedReviewers(ctx context.Context) error { return nil } - reviews, err := GetReviewsByIssueID(pr.Issue.ID) + reviews, err := GetReviewsByIssueID(ctx, pr.Issue.ID) if err != nil { return err } @@ -1040,7 +1040,7 @@ func ParseCodeOwnersLine(ctx context.Context, tokens []string) (*CodeOwnerRule, warnings = append(warnings, fmt.Sprintf("incorrect codeowner organization: %s", user)) continue } - teams, err := org.LoadTeams() + teams, err := org.LoadTeams(ctx) if err != nil { warnings = append(warnings, fmt.Sprintf("incorrect codeowner team: %s", user)) continue diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index c4506ef1508..c209386e2e0 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -27,8 +27,8 @@ type PullRequestsOptions struct { MilestoneID int64 } -func listPullRequestStatement(baseRepoID int64, opts *PullRequestsOptions) (*xorm.Session, error) { - sess := db.GetEngine(db.DefaultContext).Where("pull_request.base_repo_id=?", baseRepoID) +func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) (*xorm.Session, error) { + sess := db.GetEngine(ctx).Where("pull_request.base_repo_id=?", baseRepoID) sess.Join("INNER", "issue", "pull_request.issue_id = issue.id") switch opts.State { @@ -115,21 +115,21 @@ func GetUnmergedPullRequestsByBaseInfo(ctx context.Context, repoID int64, branch } // GetPullRequestIDsByCheckStatus returns all pull requests according the special checking status. -func GetPullRequestIDsByCheckStatus(status PullRequestStatus) ([]int64, error) { +func GetPullRequestIDsByCheckStatus(ctx context.Context, status PullRequestStatus) ([]int64, error) { prs := make([]int64, 0, 10) - return prs, db.GetEngine(db.DefaultContext).Table("pull_request"). + return prs, db.GetEngine(ctx).Table("pull_request"). Where("status=?", status). Cols("pull_request.id"). Find(&prs) } // PullRequests returns all pull requests for a base Repo by the given conditions -func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, int64, error) { +func PullRequests(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, int64, error) { if opts.Page <= 0 { opts.Page = 1 } - countSession, err := listPullRequestStatement(baseRepoID, opts) + countSession, err := listPullRequestStatement(ctx, baseRepoID, opts) if err != nil { log.Error("listPullRequestStatement: %v", err) return nil, 0, err @@ -140,7 +140,7 @@ func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, return nil, maxResults, err } - findSession, err := listPullRequestStatement(baseRepoID, opts) + findSession, err := listPullRequestStatement(ctx, baseRepoID, opts) applySorts(findSession, opts.SortType, 0) if err != nil { log.Error("listPullRequestStatement: %v", err) diff --git a/models/issues/pull_test.go b/models/issues/pull_test.go index 1105608858f..3636263c46d 100644 --- a/models/issues/pull_test.go +++ b/models/issues/pull_test.go @@ -60,7 +60,7 @@ func TestPullRequest_LoadHeadRepo(t *testing.T) { func TestPullRequestsNewest(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{ + prs, count, err := issues_model.PullRequests(db.DefaultContext, 1, &issues_model.PullRequestsOptions{ ListOptions: db.ListOptions{ Page: 1, }, @@ -107,7 +107,7 @@ func TestLoadRequestedReviewers(t *testing.T) { func TestPullRequestsOldest(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - prs, count, err := issues_model.PullRequests(1, &issues_model.PullRequestsOptions{ + prs, count, err := issues_model.PullRequests(db.DefaultContext, 1, &issues_model.PullRequestsOptions{ ListOptions: db.ListOptions{ Page: 1, }, diff --git a/models/issues/reaction.go b/models/issues/reaction.go index 28da696366e..bb47cf24cac 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -71,11 +71,11 @@ type Reaction struct { } // LoadUser load user of reaction -func (r *Reaction) LoadUser() (*user_model.User, error) { +func (r *Reaction) LoadUser(ctx context.Context) (*user_model.User, error) { if r.User != nil { return r.User, nil } - user, err := user_model.GetUserByID(db.DefaultContext, r.UserID) + user, err := user_model.GetUserByID(ctx, r.UserID) if err != nil { return nil, err } @@ -141,16 +141,16 @@ func (opts *FindReactionsOptions) toConds() builder.Cond { } // FindCommentReactions returns a ReactionList of all reactions from an comment -func FindCommentReactions(issueID, commentID int64) (ReactionList, int64, error) { - return FindReactions(db.DefaultContext, FindReactionsOptions{ +func FindCommentReactions(ctx context.Context, issueID, commentID int64) (ReactionList, int64, error) { + return FindReactions(ctx, FindReactionsOptions{ IssueID: issueID, CommentID: commentID, }) } // FindIssueReactions returns a ReactionList of all reactions from an issue -func FindIssueReactions(issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) { - return FindReactions(db.DefaultContext, FindReactionsOptions{ +func FindIssueReactions(ctx context.Context, issueID int64, listOptions db.ListOptions) (ReactionList, int64, error) { + return FindReactions(ctx, FindReactionsOptions{ ListOptions: listOptions, IssueID: issueID, CommentID: -1, @@ -218,12 +218,12 @@ type ReactionOptions struct { } // CreateReaction creates reaction for issue or comment. -func CreateReaction(opts *ReactionOptions) (*Reaction, error) { +func CreateReaction(ctx context.Context, opts *ReactionOptions) (*Reaction, error) { if !setting.UI.ReactionsLookup.Contains(opts.Type) { return nil, ErrForbiddenIssueReaction{opts.Type} } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } @@ -241,8 +241,8 @@ func CreateReaction(opts *ReactionOptions) (*Reaction, error) { } // CreateIssueReaction creates a reaction on issue. -func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, error) { - return CreateReaction(&ReactionOptions{ +func CreateIssueReaction(ctx context.Context, doerID, issueID int64, content string) (*Reaction, error) { + return CreateReaction(ctx, &ReactionOptions{ Type: content, DoerID: doerID, IssueID: issueID, @@ -250,8 +250,8 @@ func CreateIssueReaction(doerID, issueID int64, content string) (*Reaction, erro } // CreateCommentReaction creates a reaction on comment. -func CreateCommentReaction(doerID, issueID, commentID int64, content string) (*Reaction, error) { - return CreateReaction(&ReactionOptions{ +func CreateCommentReaction(ctx context.Context, doerID, issueID, commentID int64, content string) (*Reaction, error) { + return CreateReaction(ctx, &ReactionOptions{ Type: content, DoerID: doerID, IssueID: issueID, @@ -279,8 +279,8 @@ func DeleteReaction(ctx context.Context, opts *ReactionOptions) error { } // DeleteIssueReaction deletes a reaction on issue. -func DeleteIssueReaction(doerID, issueID int64, content string) error { - return DeleteReaction(db.DefaultContext, &ReactionOptions{ +func DeleteIssueReaction(ctx context.Context, doerID, issueID int64, content string) error { + return DeleteReaction(ctx, &ReactionOptions{ Type: content, DoerID: doerID, IssueID: issueID, @@ -289,8 +289,8 @@ func DeleteIssueReaction(doerID, issueID int64, content string) error { } // DeleteCommentReaction deletes a reaction on comment. -func DeleteCommentReaction(doerID, issueID, commentID int64, content string) error { - return DeleteReaction(db.DefaultContext, &ReactionOptions{ +func DeleteCommentReaction(ctx context.Context, doerID, issueID, commentID int64, content string) error { + return DeleteReaction(ctx, &ReactionOptions{ Type: content, DoerID: doerID, IssueID: issueID, diff --git a/models/issues/reaction_test.go b/models/issues/reaction_test.go index ceb7f2c2a67..5dc8e1a5f3e 100644 --- a/models/issues/reaction_test.go +++ b/models/issues/reaction_test.go @@ -20,9 +20,9 @@ func addReaction(t *testing.T, doerID, issueID, commentID int64, content string) var reaction *issues_model.Reaction var err error if commentID == 0 { - reaction, err = issues_model.CreateIssueReaction(doerID, issueID, content) + reaction, err = issues_model.CreateIssueReaction(db.DefaultContext, doerID, issueID, content) } else { - reaction, err = issues_model.CreateCommentReaction(doerID, issueID, commentID, content) + reaction, err = issues_model.CreateCommentReaction(db.DefaultContext, doerID, issueID, commentID, content) } assert.NoError(t, err) assert.NotNil(t, reaction) @@ -49,7 +49,7 @@ func TestIssueAddDuplicateReaction(t *testing.T) { addReaction(t, user1.ID, issue1ID, 0, "heart") - reaction, err := issues_model.CreateReaction(&issues_model.ReactionOptions{ + reaction, err := issues_model.CreateReaction(db.DefaultContext, &issues_model.ReactionOptions{ DoerID: user1.ID, IssueID: issue1ID, Type: "heart", @@ -70,7 +70,7 @@ func TestIssueDeleteReaction(t *testing.T) { addReaction(t, user1.ID, issue1ID, 0, "heart") - err := issues_model.DeleteIssueReaction(user1.ID, issue1ID, "heart") + err := issues_model.DeleteIssueReaction(db.DefaultContext, user1.ID, issue1ID, "heart") assert.NoError(t, err) unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID}) @@ -168,7 +168,7 @@ func TestIssueCommentReactionCount(t *testing.T) { var comment1ID int64 = 1 addReaction(t, user1.ID, issue1ID, comment1ID, "heart") - assert.NoError(t, issues_model.DeleteCommentReaction(user1.ID, issue1ID, comment1ID, "heart")) + assert.NoError(t, issues_model.DeleteCommentReaction(db.DefaultContext, user1.ID, issue1ID, comment1ID, "heart")) unittest.AssertNotExistsBean(t, &issues_model.Reaction{Type: "heart", UserID: user1.ID, IssueID: issue1ID, CommentID: comment1ID}) } diff --git a/models/issues/review.go b/models/issues/review.go index 931f1a2ba72..8b64ba80489 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -231,7 +231,7 @@ type CreateReviewOptions struct { } // IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals) -func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_model.User) (bool, error) { +func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewer *user_model.User) (bool, error) { pr, err := GetPullRequestByIssueID(ctx, issue.ID) if err != nil { return false, err @@ -242,14 +242,21 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo return false, err } if rule == nil { - return false, nil + // if no rule is found, then user with write access can make official reviews + err := pr.LoadBaseRepo(ctx) + if err != nil { + return false, err + } + writeAccess, err := access_model.HasAccessUnit(ctx, reviewer, pr.BaseRepo, unit.TypeCode, perm.AccessModeWrite) + if err != nil { + return false, err + } + return writeAccess, nil } - for _, reviewer := range reviewers { - official, err := git_model.IsUserOfficialReviewer(ctx, rule, reviewer) - if official || err != nil { - return official, err - } + official, err := git_model.IsUserOfficialReviewer(ctx, rule, reviewer) + if official || err != nil { + return official, err } return false, nil @@ -322,8 +329,8 @@ func GetCurrentReview(ctx context.Context, reviewer *user_model.User, issue *Iss } // ReviewExists returns whether a review exists for a particular line of code in the PR -func ReviewExists(issue *Issue, treePath string, line int64) (bool, error) { - return db.GetEngine(db.DefaultContext).Cols("id").Exist(&Comment{IssueID: issue.ID, TreePath: treePath, Line: line, Type: CommentTypeCode}) +func ReviewExists(ctx context.Context, issue *Issue, treePath string, line int64) (bool, error) { + return db.GetEngine(ctx).Cols("id").Exist(&Comment{IssueID: issue.ID, TreePath: treePath, Line: line, Type: CommentTypeCode}) } // ContentEmptyErr represents an content empty error @@ -340,8 +347,8 @@ func IsContentEmptyErr(err error) bool { } // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist -func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func SubmitReview(ctx context.Context, doer *user_model.User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, nil, err } @@ -487,15 +494,15 @@ func GetTeamReviewerByIssueIDAndTeamID(ctx context.Context, issueID, teamID int6 } // MarkReviewsAsStale marks existing reviews as stale -func MarkReviewsAsStale(issueID int64) (err error) { - _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `review` SET stale=? WHERE issue_id=?", true, issueID) +func MarkReviewsAsStale(ctx context.Context, issueID int64) (err error) { + _, err = db.GetEngine(ctx).Exec("UPDATE `review` SET stale=? WHERE issue_id=?", true, issueID) return err } // MarkReviewsAsNotStale marks existing reviews as not stale for a giving commit SHA -func MarkReviewsAsNotStale(issueID int64, commitID string) (err error) { - _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `review` SET stale=? WHERE issue_id=? AND commit_id=?", false, issueID, commitID) +func MarkReviewsAsNotStale(ctx context.Context, issueID int64, commitID string) (err error) { + _, err = db.GetEngine(ctx).Exec("UPDATE `review` SET stale=? WHERE issue_id=? AND commit_id=?", false, issueID, commitID) return err } @@ -518,8 +525,8 @@ func DismissReview(ctx context.Context, review *Review, isDismiss bool) (err err } // InsertReviews inserts review and review comments -func InsertReviews(reviews []*Review) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func InsertReviews(ctx context.Context, reviews []*Review) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -578,7 +585,9 @@ func AddReviewRequest(ctx context.Context, issue *Issue, reviewer, doer *user_mo return nil, nil } - official, err := IsOfficialReviewer(ctx, issue, reviewer, doer) + // if the reviewer is an official reviewer, + // remove the official flag in the all previous reviews + official, err := IsOfficialReviewer(ctx, issue, reviewer) if err != nil { return nil, err } else if official { @@ -794,7 +803,7 @@ func RemoveTeamReviewRequest(ctx context.Context, issue *Issue, reviewer *organi } // MarkConversation Add or remove Conversation mark for a code comment -func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) (err error) { +func MarkConversation(ctx context.Context, comment *Comment, doer *user_model.User, isResolve bool) (err error) { if comment.Type != CommentTypeCode { return nil } @@ -804,7 +813,7 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) ( return nil } - if _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", doer.ID, comment.ID); err != nil { + if _, err = db.GetEngine(ctx).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", doer.ID, comment.ID); err != nil { return err } } else { @@ -812,7 +821,7 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) ( return nil } - if _, err = db.GetEngine(db.DefaultContext).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", 0, comment.ID); err != nil { + if _, err = db.GetEngine(ctx).Exec("UPDATE `comment` SET resolve_doer_id=? WHERE id=?", 0, comment.ID); err != nil { return err } } @@ -822,24 +831,24 @@ func MarkConversation(comment *Comment, doer *user_model.User, isResolve bool) ( // CanMarkConversation Add or remove Conversation mark for a code comment permission check // the PR writer , offfcial reviewer and poster can do it -func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, err error) { +func CanMarkConversation(ctx context.Context, issue *Issue, doer *user_model.User) (permResult bool, err error) { if doer == nil || issue == nil { return false, fmt.Errorf("issue or doer is nil") } if doer.ID != issue.PosterID { - if err = issue.LoadRepo(db.DefaultContext); err != nil { + if err = issue.LoadRepo(ctx); err != nil { return false, err } - p, err := access_model.GetUserRepoPermission(db.DefaultContext, issue.Repo, doer) + p, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return false, err } permResult = p.CanAccess(perm.AccessModeWrite, unit.TypePullRequests) if !permResult { - if permResult, err = IsOfficialReviewer(db.DefaultContext, issue, doer); err != nil { + if permResult, err = IsOfficialReviewer(ctx, issue, doer); err != nil { return false, err } } @@ -853,8 +862,8 @@ func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, } // DeleteReview delete a review and it's code comments -func DeleteReview(r *Review) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteReview(ctx context.Context, r *Review) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -903,7 +912,7 @@ func DeleteReview(r *Review) error { } // GetCodeCommentsCount return count of CodeComments a Review has -func (r *Review) GetCodeCommentsCount() int { +func (r *Review) GetCodeCommentsCount(ctx context.Context) int { opts := FindCommentsOptions{ Type: CommentTypeCode, IssueID: r.IssueID, @@ -914,7 +923,7 @@ func (r *Review) GetCodeCommentsCount() int { conds = conds.And(builder.Eq{"invalidated": false}) } - count, err := db.GetEngine(db.DefaultContext).Where(conds).Count(new(Comment)) + count, err := db.GetEngine(ctx).Where(conds).Count(new(Comment)) if err != nil { return 0 } @@ -922,18 +931,18 @@ func (r *Review) GetCodeCommentsCount() int { } // HTMLURL formats a URL-string to the related review issue-comment -func (r *Review) HTMLURL() string { +func (r *Review) HTMLURL(ctx context.Context) string { opts := FindCommentsOptions{ Type: CommentTypeReview, IssueID: r.IssueID, ReviewID: r.ID, } comment := new(Comment) - has, err := db.GetEngine(db.DefaultContext).Where(opts.ToConds()).Get(comment) + has, err := db.GetEngine(ctx).Where(opts.ToConds()).Get(comment) if err != nil || !has { return "" } - return comment.HTMLURL() + return comment.HTMLURL(ctx) } // RemapExternalUser ExternalUserRemappable interface @@ -954,8 +963,8 @@ func (r *Review) GetExternalName() string { return r.OriginalAuthor } func (r *Review) GetExternalID() int64 { return r.OriginalAuthorID } // UpdateReviewsMigrationsByType updates reviews' migrations information via given git service type and original id and poster id -func UpdateReviewsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error { - _, err := db.GetEngine(db.DefaultContext).Table("review"). +func UpdateReviewsMigrationsByType(ctx context.Context, tp structs.GitServiceType, originalAuthorID string, posterID int64) error { + _, err := db.GetEngine(ctx).Table("review"). Where("original_author_id = ?", originalAuthorID). And(migratedIssueCond(tp)). Update(map[string]any{ diff --git a/models/issues/review_list.go b/models/issues/review_list.go index 9f50d8e09d5..ed3d0bd028a 100644 --- a/models/issues/review_list.go +++ b/models/issues/review_list.go @@ -126,16 +126,16 @@ func FindLatestReviews(ctx context.Context, opts FindReviewOptions) (ReviewList, } // CountReviews returns count of reviews passing FindReviewOptions -func CountReviews(opts FindReviewOptions) (int64, error) { - return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{}) +func CountReviews(ctx context.Context, opts FindReviewOptions) (int64, error) { + return db.GetEngine(ctx).Where(opts.toCond()).Count(&Review{}) } // GetReviewersFromOriginalAuthorsByIssueID gets the latest review of each original authors for a pull request -func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) (ReviewList, error) { +func GetReviewersFromOriginalAuthorsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) { reviews := make([]*Review, 0, 10) // Get latest review of each reviewer, sorted in order they were made - if err := db.GetEngine(db.DefaultContext).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC", + if err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND original_author_id <> 0 GROUP BY issue_id, original_author_id) ORDER BY review.updated_unix ASC", issueID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest). Find(&reviews); err != nil { return nil, err @@ -145,10 +145,10 @@ func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) (ReviewList, error) } // GetReviewsByIssueID gets the latest review of each reviewer for a pull request -func GetReviewsByIssueID(issueID int64) (ReviewList, error) { +func GetReviewsByIssueID(ctx context.Context, issueID int64) (ReviewList, error) { reviews := make([]*Review, 0, 10) - sess := db.GetEngine(db.DefaultContext) + sess := db.GetEngine(ctx) // Get latest review of each reviewer, sorted in order they were made if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = 0 AND type in (?, ?, ?) AND dismissed = ? AND original_author_id = 0 GROUP BY issue_id, reviewer_id) ORDER BY review.updated_unix ASC", diff --git a/models/issues/review_test.go b/models/issues/review_test.go index 8f0e773f4cd..63e2aef2cce 100644 --- a/models/issues/review_test.go +++ b/models/issues/review_test.go @@ -144,7 +144,7 @@ func TestGetReviewersByIssueID(t *testing.T) { UpdatedUnix: 946684814, }) - allReviews, err := issues_model.GetReviewsByIssueID(issue.ID) + allReviews, err := issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) for _, review := range allReviews { assert.NoError(t, review.LoadReviewer(db.DefaultContext)) @@ -157,7 +157,7 @@ func TestGetReviewersByIssueID(t *testing.T) { } } - allReviews, err = issues_model.GetReviewsByIssueID(issue.ID) + allReviews, err = issues_model.GetReviewsByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) assert.NoError(t, allReviews.LoadReviewers(db.DefaultContext)) if assert.Len(t, allReviews, 3) { @@ -248,7 +248,7 @@ func TestDeleteReview(t *testing.T) { }) assert.NoError(t, err) - assert.NoError(t, issues_model.DeleteReview(review2)) + assert.NoError(t, issues_model.DeleteReview(db.DefaultContext, review2)) _, err = issues_model.GetReviewByID(db.DefaultContext, review2.ID) assert.Error(t, err) diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index c8cd5ad33f2..2c662bdb06a 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -81,9 +81,9 @@ type UserStopwatch struct { } // GetUIDsAndNotificationCounts between the two provided times -func GetUIDsAndStopwatch() ([]*UserStopwatch, error) { +func GetUIDsAndStopwatch(ctx context.Context) ([]*UserStopwatch, error) { sws := []*Stopwatch{} - if err := db.GetEngine(db.DefaultContext).Where("issue_id != 0").Find(&sws); err != nil { + if err := db.GetEngine(ctx).Where("issue_id != 0").Find(&sws); err != nil { return nil, err } if len(sws) == 0 { @@ -107,9 +107,9 @@ func GetUIDsAndStopwatch() ([]*UserStopwatch, error) { } // GetUserStopwatches return list of all stopwatches of a user -func GetUserStopwatches(userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) { +func GetUserStopwatches(ctx context.Context, userID int64, listOptions db.ListOptions) ([]*Stopwatch, error) { sws := make([]*Stopwatch, 0, 8) - sess := db.GetEngine(db.DefaultContext).Where("stopwatch.user_id = ?", userID) + sess := db.GetEngine(ctx).Where("stopwatch.user_id = ?", userID) if listOptions.Page != 0 { sess = db.SetSessionPagination(sess, &listOptions) } @@ -122,13 +122,13 @@ func GetUserStopwatches(userID int64, listOptions db.ListOptions) ([]*Stopwatch, } // CountUserStopwatches return count of all stopwatches of a user -func CountUserStopwatches(userID int64) (int64, error) { - return db.GetEngine(db.DefaultContext).Where("user_id = ?", userID).Count(&Stopwatch{}) +func CountUserStopwatches(ctx context.Context, userID int64) (int64, error) { + return db.GetEngine(ctx).Where("user_id = ?", userID).Count(&Stopwatch{}) } // StopwatchExists returns true if the stopwatch exists -func StopwatchExists(userID, issueID int64) bool { - _, exists, _ := getStopwatch(db.DefaultContext, userID, issueID) +func StopwatchExists(ctx context.Context, userID, issueID int64) bool { + _, exists, _ := getStopwatch(ctx, userID, issueID) return exists } @@ -168,15 +168,15 @@ func FinishIssueStopwatchIfPossible(ctx context.Context, user *user_model.User, } // CreateOrStopIssueStopwatch create an issue stopwatch if it's not exist, otherwise finish it -func CreateOrStopIssueStopwatch(user *user_model.User, issue *Issue) error { - _, exists, err := getStopwatch(db.DefaultContext, user.ID, issue.ID) +func CreateOrStopIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error { + _, exists, err := getStopwatch(ctx, user.ID, issue.ID) if err != nil { return err } if exists { - return FinishIssueStopwatch(db.DefaultContext, user, issue) + return FinishIssueStopwatch(ctx, user, issue) } - return CreateIssueStopwatch(db.DefaultContext, user, issue) + return CreateIssueStopwatch(ctx, user, issue) } // FinishIssueStopwatch if stopwatch exist then finish it otherwise return an error @@ -269,8 +269,8 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss } // CancelStopwatch removes the given stopwatch and logs it into issue's timeline. -func CancelStopwatch(user *user_model.User, issue *Issue) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func CancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/issues/stopwatch_test.go b/models/issues/stopwatch_test.go index fa937ecbedd..39958a7f36b 100644 --- a/models/issues/stopwatch_test.go +++ b/models/issues/stopwatch_test.go @@ -26,20 +26,20 @@ func TestCancelStopwatch(t *testing.T) { issue2, err := issues_model.GetIssueByID(db.DefaultContext, 2) assert.NoError(t, err) - err = issues_model.CancelStopwatch(user1, issue1) + err = issues_model.CancelStopwatch(db.DefaultContext, user1, issue1) assert.NoError(t, err) unittest.AssertNotExistsBean(t, &issues_model.Stopwatch{UserID: user1.ID, IssueID: issue1.ID}) _ = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{Type: issues_model.CommentTypeCancelTracking, PosterID: user1.ID, IssueID: issue1.ID}) - assert.Nil(t, issues_model.CancelStopwatch(user1, issue2)) + assert.Nil(t, issues_model.CancelStopwatch(db.DefaultContext, user1, issue2)) } func TestStopwatchExists(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.True(t, issues_model.StopwatchExists(1, 1)) - assert.False(t, issues_model.StopwatchExists(1, 2)) + assert.True(t, issues_model.StopwatchExists(db.DefaultContext, 1, 1)) + assert.False(t, issues_model.StopwatchExists(db.DefaultContext, 1, 2)) } func TestHasUserStopwatch(t *testing.T) { @@ -68,11 +68,11 @@ func TestCreateOrStopIssueStopwatch(t *testing.T) { issue2, err := issues_model.GetIssueByID(db.DefaultContext, 2) assert.NoError(t, err) - assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(org3, issue1)) + assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(db.DefaultContext, org3, issue1)) 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)) + assert.NoError(t, issues_model.CreateOrStopIssueStopwatch(db.DefaultContext, user2, issue2)) unittest.AssertNotExistsBean(t, &issues_model.Stopwatch{UserID: 2, IssueID: 2}) unittest.AssertExistsAndLoadBean(t, &issues_model.TrackedTime{UserID: 2, IssueID: 2}) } diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 58c6b775f07..89c99c5cd13 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -198,9 +198,9 @@ func addTime(ctx context.Context, user *user_model.User, issue *Issue, amount in return tt, db.Insert(ctx, tt) } -// TotalTimes returns the spent time in seconds for each user by an issue -func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]int64, error) { - trackedTimes, err := GetTrackedTimes(db.DefaultContext, options) +// TotalTimesForEachUser returns the spent time in seconds for each user by an issue +func TotalTimesForEachUser(ctx context.Context, options *FindTrackedTimesOptions) (map[*user_model.User]int64, error) { + trackedTimes, err := GetTrackedTimes(ctx, options) if err != nil { return nil, err } @@ -213,7 +213,7 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]int64, e totalTimes := make(map[*user_model.User]int64) // Fetching User and making time human readable for userID, total := range totalTimesByUser { - user, err := user_model.GetUserByID(db.DefaultContext, userID) + user, err := user_model.GetUserByID(ctx, userID) if err != nil { if user_model.IsErrUserNotExist(err) { continue @@ -226,8 +226,8 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]int64, e } // DeleteIssueUserTimes deletes times for issue -func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteIssueUserTimes(ctx context.Context, issue *Issue, user *user_model.User) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -265,8 +265,8 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { } // DeleteTime delete a specific Time -func DeleteTime(t *TrackedTime) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteTime(ctx context.Context, t *TrackedTime) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -315,9 +315,9 @@ func deleteTime(ctx context.Context, t *TrackedTime) error { } // GetTrackedTimeByID returns raw TrackedTime without loading attributes by id -func GetTrackedTimeByID(id int64) (*TrackedTime, error) { +func GetTrackedTimeByID(ctx context.Context, id int64) (*TrackedTime, error) { time := new(TrackedTime) - has, err := db.GetEngine(db.DefaultContext).ID(id).Get(time) + has, err := db.GetEngine(ctx).ID(id).Get(time) if err != nil { return nil, err } else if !has { diff --git a/models/issues/tracked_time_test.go b/models/issues/tracked_time_test.go index caced78c9e8..cc2cb918e07 100644 --- a/models/issues/tracked_time_test.go +++ b/models/issues/tracked_time_test.go @@ -79,10 +79,10 @@ func TestGetTrackedTimes(t *testing.T) { assert.Len(t, times, 0) } -func TestTotalTimes(t *testing.T) { +func TestTotalTimesForEachUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - total, err := issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 1}) + total, err := issues_model.TotalTimesForEachUser(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: 1}) assert.NoError(t, err) assert.Len(t, total, 1) for user, time := range total { @@ -90,7 +90,7 @@ func TestTotalTimes(t *testing.T) { assert.EqualValues(t, 400, time) } - total, err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 2}) + total, err = issues_model.TotalTimesForEachUser(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: 2}) assert.NoError(t, err) assert.Len(t, total, 2) for user, time := range total { @@ -103,7 +103,7 @@ func TestTotalTimes(t *testing.T) { } } - total, err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 5}) + total, err = issues_model.TotalTimesForEachUser(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: 5}) assert.NoError(t, err) assert.Len(t, total, 1) for user, time := range total { @@ -111,7 +111,7 @@ func TestTotalTimes(t *testing.T) { assert.EqualValues(t, 1, time) } - total, err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: 4}) + total, err = issues_model.TotalTimesForEachUser(db.DefaultContext, &issues_model.FindTrackedTimesOptions{IssueID: 4}) assert.NoError(t, err) assert.Len(t, total, 2) } diff --git a/models/main_test.go b/models/main_test.go index c09b661d2c2..600dcc889b7 100644 --- a/models/main_test.go +++ b/models/main_test.go @@ -29,7 +29,5 @@ func TestFixturesAreConsistent(t *testing.T) { } func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: "..", - }) + unittest.MainTest(m) } diff --git a/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/issue_label.yml b/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/issue_label.yml index 96104ac04a8..b02cb570ecd 100644 --- a/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/issue_label.yml +++ b/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/issue_label.yml @@ -26,4 +26,3 @@ id: 5 issue_id: 2 label_id: 87 - diff --git a/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/label.yml b/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/label.yml index d651c87d5b0..fa9658aa02a 100644 --- a/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/label.yml +++ b/models/migrations/fixtures/Test_DeleteOrphanedIssueLabels/label.yml @@ -18,7 +18,7 @@ - id: 3 repo_id: 0 - org_id: 3 + org_id: 3 name: orglabel3 color: '#abcdef' num_issues: 0 diff --git a/models/migrations/fixtures/Test_RemoveInvalidLabels/label.yml b/models/migrations/fixtures/Test_RemoveInvalidLabels/label.yml index 094b811d914..0f5a3eb5072 100644 --- a/models/migrations/fixtures/Test_RemoveInvalidLabels/label.yml +++ b/models/migrations/fixtures/Test_RemoveInvalidLabels/label.yml @@ -23,4 +23,3 @@ id: 5 repo_id: 3 org_id: 0 - diff --git a/models/migrations/fixtures/Test_StoreWebauthnCredentialIDAsBytes/webauthn_credential.yml b/models/migrations/fixtures/Test_StoreWebauthnCredentialIDAsBytes/webauthn_credential.yml index c02a76e3742..ebb73f44de7 100644 --- a/models/migrations/fixtures/Test_StoreWebauthnCredentialIDAsBytes/webauthn_credential.yml +++ b/models/migrations/fixtures/Test_StoreWebauthnCredentialIDAsBytes/webauthn_credential.yml @@ -28,4 +28,3 @@ attestation_type: 'fido-u2f' sign_count: 1 clone_warning: false - diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index 1da69c9552c..7738885c97e 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -532,6 +532,14 @@ var migrations = []Migration{ NewMigration("Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable), // v275 -> v276 NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun), + // v276 -> v277 + NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors), + // v277 -> v278 + NewMigration("Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID), + // v278 -> v279 + NewMigration("Add Index to comment.dependent_issue_id", v1_21.AddIndexToCommentDependentIssueID), + // v279 -> v280 + NewMigration("Add Index to action.user_id", v1_21.AddIndexToActionUserID), // to modify later NewMigration("Add size limit on repository", v1_21.AddSizeLimitOnRepo), } diff --git a/models/migrations/v1_21/v276.go b/models/migrations/v1_21/v276.go new file mode 100644 index 00000000000..ed1bc3bda52 --- /dev/null +++ b/models/migrations/v1_21/v276.go @@ -0,0 +1,179 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "context" + "fmt" + "path/filepath" + "strings" + + "code.gitea.io/gitea/modules/git" + giturl "code.gitea.io/gitea/modules/git/url" + "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" +) + +func AddRemoteAddressToMirrors(x *xorm.Engine) error { + type Mirror struct { + RemoteAddress string `xorm:"VARCHAR(2048)"` + } + + type PushMirror struct { + RemoteAddress string `xorm:"VARCHAR(2048)"` + } + + if err := x.Sync(new(Mirror), new(PushMirror)); err != nil { + return err + } + + if err := migratePullMirrors(x); err != nil { + return err + } + + return migratePushMirrors(x) +} + +func migratePullMirrors(x *xorm.Engine) error { + type Mirror struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` + RemoteAddress string `xorm:"VARCHAR(2048)"` + RepoOwner string + RepoName string + } + + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return err + } + + limit := setting.Database.IterateBufferSize + if limit <= 0 { + limit = 50 + } + + start := 0 + + for { + var mirrors []Mirror + if err := sess.Select("mirror.id, mirror.repo_id, mirror.remote_address, repository.owner_name as repo_owner, repository.name as repo_name"). + Join("INNER", "repository", "repository.id = mirror.repo_id"). + Limit(limit, start).Find(&mirrors); err != nil { + return err + } + + if len(mirrors) == 0 { + break + } + start += len(mirrors) + + for _, m := range mirrors { + remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, "origin") + if err != nil { + return err + } + + m.RemoteAddress = remoteAddress + + if _, err = sess.ID(m.ID).Cols("remote_address").Update(m); err != nil { + return err + } + } + + if start%1000 == 0 { // avoid a too big transaction + if err := sess.Commit(); err != nil { + return err + } + if err := sess.Begin(); err != nil { + return err + } + } + } + + return sess.Commit() +} + +func migratePushMirrors(x *xorm.Engine) error { + type PushMirror struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` + RemoteName string + RemoteAddress string `xorm:"VARCHAR(2048)"` + RepoOwner string + RepoName string + } + + sess := x.NewSession() + defer sess.Close() + + if err := sess.Begin(); err != nil { + return err + } + + limit := setting.Database.IterateBufferSize + if limit <= 0 { + limit = 50 + } + + start := 0 + + for { + var mirrors []PushMirror + if err := sess.Select("push_mirror.id, push_mirror.repo_id, push_mirror.remote_name, push_mirror.remote_address, repository.owner_name as repo_owner, repository.name as repo_name"). + Join("INNER", "repository", "repository.id = push_mirror.repo_id"). + Limit(limit, start).Find(&mirrors); err != nil { + return err + } + + if len(mirrors) == 0 { + break + } + start += len(mirrors) + + for _, m := range mirrors { + remoteAddress, err := getRemoteAddress(m.RepoOwner, m.RepoName, m.RemoteName) + if err != nil { + return err + } + + m.RemoteAddress = remoteAddress + + if _, err = sess.ID(m.ID).Cols("remote_address").Update(m); err != nil { + return err + } + } + + if start%1000 == 0 { // avoid a too big transaction + if err := sess.Commit(); err != nil { + return err + } + if err := sess.Begin(); err != nil { + return err + } + } + } + + return sess.Commit() +} + +func getRemoteAddress(ownerName, repoName, remoteName string) (string, error) { + repoPath := filepath.Join(setting.RepoRootPath, strings.ToLower(ownerName), strings.ToLower(repoName)+".git") + + remoteURL, err := git.GetRemoteAddress(context.Background(), repoPath, remoteName) + if err != nil { + return "", fmt.Errorf("get remote %s's address of %s/%s failed: %v", remoteName, ownerName, repoName, err) + } + + u, err := giturl.Parse(remoteURL) + if err != nil { + return "", err + } + u.User = nil + + return u.String(), nil +} diff --git a/models/migrations/v1_21/v277.go b/models/migrations/v1_21/v277.go new file mode 100644 index 00000000000..12529160b75 --- /dev/null +++ b/models/migrations/v1_21/v277.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "xorm.io/xorm" +) + +func AddIndexToIssueUserIssueID(x *xorm.Engine) error { + type IssueUser struct { + IssueID int64 `xorm:"INDEX"` + } + + return x.Sync(new(IssueUser)) +} diff --git a/models/migrations/v1_21/v278.go b/models/migrations/v1_21/v278.go new file mode 100644 index 00000000000..d6a462d1e7e --- /dev/null +++ b/models/migrations/v1_21/v278.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "xorm.io/xorm" +) + +func AddIndexToCommentDependentIssueID(x *xorm.Engine) error { + type Comment struct { + DependentIssueID int64 `xorm:"index"` + } + + return x.Sync(new(Comment)) +} diff --git a/models/migrations/v1_21/v279.go b/models/migrations/v1_21/v279.go new file mode 100644 index 00000000000..19647225c9a --- /dev/null +++ b/models/migrations/v1_21/v279.go @@ -0,0 +1,16 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_21 //nolint + +import ( + "xorm.io/xorm" +) + +func AddIndexToActionUserID(x *xorm.Engine) error { + type Action struct { + UserID int64 `xorm:"INDEX"` + } + + return x.Sync(new(Action)) +} diff --git a/models/org_team.go b/models/org_team.go index cf3680990df..acbab560892 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -73,8 +73,8 @@ func addAllRepositories(ctx context.Context, t *organization.Team) error { } // AddAllRepositories adds all repositories to the team -func AddAllRepositories(t *organization.Team) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func AddAllRepositories(ctx context.Context, t *organization.Team) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -88,12 +88,12 @@ func AddAllRepositories(t *organization.Team) (err error) { } // RemoveAllRepositories removes all repositories from team and recalculates access -func RemoveAllRepositories(t *organization.Team) (err error) { +func RemoveAllRepositories(ctx context.Context, t *organization.Team) (err error) { if t.IncludesAllRepositories { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -153,7 +153,7 @@ func removeAllRepositories(ctx context.Context, t *organization.Team) (err error // NewTeam creates a record of new team. // It's caller's responsibility to assign organization ID. -func NewTeam(t *organization.Team) (err error) { +func NewTeam(ctx context.Context, t *organization.Team) (err error) { if len(t.Name) == 0 { return util.NewInvalidArgumentErrorf("empty team name") } @@ -162,7 +162,7 @@ func NewTeam(t *organization.Team) (err error) { return err } - has, err := db.GetEngine(db.DefaultContext).ID(t.OrgID).Get(new(user_model.User)) + has, err := db.GetEngine(ctx).ID(t.OrgID).Get(new(user_model.User)) if err != nil { return err } @@ -171,7 +171,7 @@ func NewTeam(t *organization.Team) (err error) { } t.LowerName = strings.ToLower(t.Name) - has, err = db.GetEngine(db.DefaultContext). + has, err = db.GetEngine(ctx). Where("org_id=?", t.OrgID). And("lower_name=?", t.LowerName). Get(new(organization.Team)) @@ -182,7 +182,7 @@ func NewTeam(t *organization.Team) (err error) { return organization.ErrTeamAlreadyExist{OrgID: t.OrgID, Name: t.LowerName} } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -218,7 +218,7 @@ func NewTeam(t *organization.Team) (err error) { } // UpdateTeam updates information of team. -func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err error) { +func UpdateTeam(ctx context.Context, t *organization.Team, authChanged, includeAllChanged bool) (err error) { if len(t.Name) == 0 { return util.NewInvalidArgumentErrorf("empty team name") } @@ -227,7 +227,7 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err t.Description = t.Description[:255] } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -293,8 +293,8 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err // DeleteTeam deletes given team. // It's caller's responsibility to assign organization ID. -func DeleteTeam(t *organization.Team) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteTeam(ctx context.Context, t *organization.Team) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -356,85 +356,81 @@ func DeleteTeam(t *organization.Team) error { // AddTeamMember adds new membership of given team to given organization, // the user will have membership to given organization automatically when needed. -func AddTeamMember(team *organization.Team, userID int64) error { - isAlreadyMember, err := organization.IsTeamMember(db.DefaultContext, team.OrgID, team.ID, userID) +func AddTeamMember(ctx context.Context, team *organization.Team, userID int64) error { + isAlreadyMember, err := organization.IsTeamMember(ctx, team.OrgID, team.ID, userID) if err != nil || isAlreadyMember { return err } - if err := organization.AddOrgUser(team.OrgID, userID); err != nil { + if err := organization.AddOrgUser(ctx, team.OrgID, userID); err != nil { return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + err = db.WithTx(ctx, func(ctx context.Context) error { + // check in transaction + isAlreadyMember, err = organization.IsTeamMember(ctx, team.OrgID, team.ID, userID) + if err != nil || isAlreadyMember { + return err + } + + sess := db.GetEngine(ctx) + + if err := db.Insert(ctx, &organization.TeamUser{ + UID: userID, + OrgID: team.OrgID, + TeamID: team.ID, + }); err != nil { + return err + } else if _, err := sess.Incr("num_members").ID(team.ID).Update(new(organization.Team)); err != nil { + return err + } + + team.NumMembers++ + + // Give access to team repositories. + // update exist access if mode become bigger + subQuery := builder.Select("repo_id").From("team_repo"). + Where(builder.Eq{"team_id": team.ID}) + + if _, err := sess.Where("user_id=?", userID). + In("repo_id", subQuery). + And("mode < ?", team.AccessMode). + SetExpr("mode", team.AccessMode). + Update(new(access_model.Access)); err != nil { + return fmt.Errorf("update user accesses: %w", err) + } + + // for not exist access + var repoIDs []int64 + accessSubQuery := builder.Select("repo_id").From("access").Where(builder.Eq{"user_id": userID}) + if err := sess.SQL(subQuery.And(builder.NotIn("repo_id", accessSubQuery))).Find(&repoIDs); err != nil { + return fmt.Errorf("select id accesses: %w", err) + } + + accesses := make([]*access_model.Access, 0, 100) + for i, repoID := range repoIDs { + accesses = append(accesses, &access_model.Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode}) + if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 { + if err = db.Insert(ctx, accesses); err != nil { + return fmt.Errorf("insert new user accesses: %w", err) + } + accesses = accesses[:0] + } + } + return nil + }) if err != nil { return err } - defer committer.Close() - - // check in transaction - isAlreadyMember, err = organization.IsTeamMember(ctx, team.OrgID, team.ID, userID) - if err != nil || isAlreadyMember { - return err - } - - sess := db.GetEngine(ctx) - - if err := db.Insert(ctx, &organization.TeamUser{ - UID: userID, - OrgID: team.OrgID, - TeamID: team.ID, - }); err != nil { - return err - } else if _, err := sess.Incr("num_members").ID(team.ID).Update(new(organization.Team)); err != nil { - return err - } - - team.NumMembers++ - - // Give access to team repositories. - // update exist access if mode become bigger - subQuery := builder.Select("repo_id").From("team_repo"). - Where(builder.Eq{"team_id": team.ID}) - - if _, err := sess.Where("user_id=?", userID). - In("repo_id", subQuery). - And("mode < ?", team.AccessMode). - SetExpr("mode", team.AccessMode). - Update(new(access_model.Access)); err != nil { - return fmt.Errorf("update user accesses: %w", err) - } - - // for not exist access - var repoIDs []int64 - accessSubQuery := builder.Select("repo_id").From("access").Where(builder.Eq{"user_id": userID}) - if err := sess.SQL(subQuery.And(builder.NotIn("repo_id", accessSubQuery))).Find(&repoIDs); err != nil { - return fmt.Errorf("select id accesses: %w", err) - } - - accesses := make([]*access_model.Access, 0, 100) - for i, repoID := range repoIDs { - accesses = append(accesses, &access_model.Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode}) - if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 { - if err = db.Insert(ctx, accesses); err != nil { - return fmt.Errorf("insert new user accesses: %w", err) - } - accesses = accesses[:0] - } - } - - if err := committer.Commit(); err != nil { - return err - } - committer.Close() // this behaviour may spend much time so run it in a goroutine // FIXME: Update watch repos batchly if setting.Service.AutoWatchNewRepos { // Get team and its repositories. - if err := team.LoadRepositories(db.DefaultContext); err != nil { - log.Error("getRepositories failed: %v", err) + if err := team.LoadRepositories(ctx); err != nil { + log.Error("team.LoadRepositories failed: %v", err) } + // FIXME: in the goroutine, it can't access the "ctx", it could only use db.DefaultContext at the moment go func(repos []*repo_model.Repository) { for _, repo := range repos { if err = repo_model.WatchRepo(db.DefaultContext, userID, repo.ID, true); err != nil { @@ -512,8 +508,8 @@ func removeInvalidOrgUser(ctx context.Context, userID, orgID int64) error { } // RemoveTeamMember removes member from given team of given organization. -func RemoveTeamMember(team *organization.Team, userID int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func RemoveTeamMember(ctx context.Context, team *organization.Team, userID int64) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/org_team_test.go b/models/org_team_test.go index 4978f8ef99b..e4b7b917e85 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -23,7 +23,7 @@ func TestTeam_AddMember(t *testing.T) { test := func(teamID, userID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, AddTeamMember(team, userID)) + assert.NoError(t, AddTeamMember(db.DefaultContext, 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) { testSuccess := func(teamID, userID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, RemoveTeamMember(team, userID)) + assert.NoError(t, RemoveTeamMember(db.DefaultContext, 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, unittest.NonexistentID) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) - err := RemoveTeamMember(team, 2) + err := RemoveTeamMember(db.DefaultContext, team, 2) assert.True(t, organization.IsErrLastOrgOwner(err)) } @@ -61,7 +61,7 @@ func TestNewTeam(t *testing.T) { const teamName = "newTeamName" team := &organization.Team{Name: teamName, OrgID: 3} - assert.NoError(t, NewTeam(team)) + assert.NoError(t, NewTeam(db.DefaultContext, team)) unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: teamName}) unittest.CheckConsistencyFor(t, &organization.Team{}, &user_model.User{ID: team.OrgID}) } @@ -75,7 +75,7 @@ func TestUpdateTeam(t *testing.T) { team.Name = "newName" team.Description = strings.Repeat("A long description!", 100) team.AccessMode = perm.AccessModeAdmin - assert.NoError(t, UpdateTeam(team, true, false)) + assert.NoError(t, UpdateTeam(db.DefaultContext, team, true, false)) team = unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: "newName"}) assert.True(t, strings.HasPrefix(team.Description, "A long description!")) @@ -94,7 +94,7 @@ func TestUpdateTeam2(t *testing.T) { team.LowerName = "owners" team.Name = "Owners" team.Description = strings.Repeat("A long description!", 100) - err := UpdateTeam(team, true, false) + err := UpdateTeam(db.DefaultContext, team, true, false) assert.True(t, organization.IsErrTeamAlreadyExist(err)) unittest.CheckConsistencyFor(t, &organization.Team{ID: team.ID}) @@ -104,7 +104,7 @@ func TestDeleteTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) - assert.NoError(t, DeleteTeam(team)) + assert.NoError(t, DeleteTeam(db.DefaultContext, 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}) @@ -122,7 +122,7 @@ func TestAddTeamMember(t *testing.T) { test := func(teamID, userID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, AddTeamMember(team, userID)) + assert.NoError(t, AddTeamMember(db.DefaultContext, team, userID)) unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: userID, TeamID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &user_model.User{ID: team.OrgID}) } @@ -136,7 +136,7 @@ func TestRemoveTeamMember(t *testing.T) { testSuccess := func(teamID, userID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, RemoveTeamMember(team, userID)) + assert.NoError(t, RemoveTeamMember(db.DefaultContext, team, userID)) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID, TeamID: teamID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}) } @@ -146,7 +146,7 @@ func TestRemoveTeamMember(t *testing.T) { testSuccess(3, unittest.NonexistentID) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) - err := RemoveTeamMember(team, 2) + err := RemoveTeamMember(db.DefaultContext, team, 2) assert.True(t, organization.IsErrLastOrgOwner(err)) } @@ -161,7 +161,7 @@ func TestRepository_RecalculateAccesses3(t *testing.T) { // adding user29 to team5 should add an explicit access row for repo 23 // even though repo 23 is public - assert.NoError(t, AddTeamMember(team5, user29.ID)) + assert.NoError(t, AddTeamMember(db.DefaultContext, team5, user29.ID)) has, err = db.GetEngine(db.DefaultContext).Get(&access_model.Access{UserID: 29, RepoID: 23}) assert.NoError(t, err) diff --git a/models/organization/main_test.go b/models/organization/main_test.go index bc5bde2565c..c35898a465d 100644 --- a/models/organization/main_test.go +++ b/models/organization/main_test.go @@ -4,7 +4,6 @@ package organization_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -18,7 +17,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/organization/mini_org.go b/models/organization/mini_org.go index b1627b5e6c6..b1b24624c5a 100644 --- a/models/organization/mini_org.go +++ b/models/organization/mini_org.go @@ -4,6 +4,7 @@ package organization import ( + "context" "fmt" "strings" @@ -19,7 +20,7 @@ import ( type MinimalOrg = Organization // GetUserOrgsList returns all organizations the given user has access to -func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) { +func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg, error) { schema, err := db.TableInfo(new(user_model.User)) if err != nil { return nil, err @@ -42,7 +43,7 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) { groupByStr := groupByCols.String() groupByStr = groupByStr[0 : len(groupByStr)-1] - sess := db.GetEngine(db.DefaultContext) + sess := db.GetEngine(ctx) sess = sess.Select(groupByStr+", count(distinct repo_id) as org_count"). Table("user"). Join("INNER", "team", "`team`.org_id = `user`.id"). diff --git a/models/organization/org.go b/models/organization/org.go index 8fd4ad076bd..07091194ebc 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -96,23 +96,23 @@ func (Organization) TableName() string { } // IsOwnedBy returns true if given user is in the owner team. -func (org *Organization) IsOwnedBy(uid int64) (bool, error) { - return IsOrganizationOwner(db.DefaultContext, org.ID, uid) +func (org *Organization) IsOwnedBy(ctx context.Context, uid int64) (bool, error) { + return IsOrganizationOwner(ctx, org.ID, uid) } // IsOrgAdmin returns true if given user is in the owner team or an admin team. -func (org *Organization) IsOrgAdmin(uid int64) (bool, error) { - return IsOrganizationAdmin(db.DefaultContext, org.ID, uid) +func (org *Organization) IsOrgAdmin(ctx context.Context, uid int64) (bool, error) { + return IsOrganizationAdmin(ctx, org.ID, uid) } // IsOrgMember returns true if given user is member of organization. -func (org *Organization) IsOrgMember(uid int64) (bool, error) { - return IsOrganizationMember(db.DefaultContext, org.ID, uid) +func (org *Organization) IsOrgMember(ctx context.Context, uid int64) (bool, error) { + return IsOrganizationMember(ctx, org.ID, uid) } // CanCreateOrgRepo returns true if given user can create repo in organization -func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) { - return CanCreateOrgRepo(db.DefaultContext, org.ID, uid) +func (org *Organization) CanCreateOrgRepo(ctx context.Context, uid int64) (bool, error) { + return CanCreateOrgRepo(ctx, org.ID, uid) } // GetTeam returns named team of organization. @@ -135,20 +135,20 @@ func FindOrgTeams(ctx context.Context, orgID int64) ([]*Team, error) { } // LoadTeams load teams if not loaded. -func (org *Organization) LoadTeams() ([]*Team, error) { - return FindOrgTeams(db.DefaultContext, org.ID) +func (org *Organization) LoadTeams(ctx context.Context) ([]*Team, error) { + return FindOrgTeams(ctx, org.ID) } // GetMembers returns all members of organization. -func (org *Organization) GetMembers() (user_model.UserList, map[int64]bool, error) { - return FindOrgMembers(&FindOrgMembersOpts{ +func (org *Organization) GetMembers(ctx context.Context) (user_model.UserList, map[int64]bool, error) { + return FindOrgMembers(ctx, &FindOrgMembersOpts{ OrgID: org.ID, }) } // HasMemberWithUserID returns true if user with userID is part of the u organisation. -func (org *Organization) HasMemberWithUserID(userID int64) bool { - return org.hasMemberWithUserID(db.DefaultContext, userID) +func (org *Organization) HasMemberWithUserID(ctx context.Context, userID int64) bool { + return org.hasMemberWithUserID(ctx, userID) } func (org *Organization) hasMemberWithUserID(ctx context.Context, userID int64) bool { @@ -199,8 +199,8 @@ type FindOrgMembersOpts struct { } // CountOrgMembers counts the organization's members -func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) { - sess := db.GetEngine(db.DefaultContext).Where("org_id=?", opts.OrgID) +func CountOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (int64, error) { + sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) if opts.PublicOnly { sess.And("is_public = ?", true) } @@ -208,8 +208,8 @@ func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) { } // FindOrgMembers loads organization members according conditions -func FindOrgMembers(opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) { - ous, err := GetOrgUsersByOrgID(db.DefaultContext, opts) +func FindOrgMembers(ctx context.Context, opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) { + ous, err := GetOrgUsersByOrgID(ctx, opts) if err != nil { return nil, nil, err } @@ -221,7 +221,7 @@ func FindOrgMembers(opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bo idsIsPublic[ou.UID] = ou.IsPublic } - users, err := user_model.GetUsersByIDs(ids) + users, err := user_model.GetUsersByIDs(ctx, ids) if err != nil { return nil, nil, err } @@ -271,7 +271,7 @@ func (org *Organization) UnitPermission(ctx context.Context, doer *user_model.Us } // CreateOrganization creates record of a new organization. -func CreateOrganization(org *Organization, owner *user_model.User) (err error) { +func CreateOrganization(ctx context.Context, org *Organization, owner *user_model.User) (err error) { if !owner.CanCreateOrganization() { return ErrUserNotAllowedCreateOrg{} } @@ -280,7 +280,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) { return err } - isExist, err := user_model.IsUserExist(db.DefaultContext, 0, org.Name) + isExist, err := user_model.IsUserExist(ctx, 0, org.Name) if err != nil { return err } else if isExist { @@ -300,7 +300,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) { org.NumMembers = 1 org.Type = user_model.UserTypeOrganization - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -412,9 +412,9 @@ func DeleteOrganization(ctx context.Context, org *Organization) error { } // GetOrgUserMaxAuthorizeLevel returns highest authorize level of user in an organization -func (org *Organization) GetOrgUserMaxAuthorizeLevel(uid int64) (perm.AccessMode, error) { +func (org *Organization) GetOrgUserMaxAuthorizeLevel(ctx context.Context, uid int64) (perm.AccessMode, error) { var authorize perm.AccessMode - _, err := db.GetEngine(db.DefaultContext). + _, err := db.GetEngine(ctx). Select("max(team.authorize)"). Table("team"). Join("INNER", "team_user", "team_user.team_id = team.id"). @@ -468,9 +468,9 @@ func (opts FindOrgOptions) toConds() builder.Cond { } // FindOrgs returns a list of organizations according given conditions -func FindOrgs(opts FindOrgOptions) ([]*Organization, error) { +func FindOrgs(ctx context.Context, opts FindOrgOptions) ([]*Organization, error) { orgs := make([]*Organization, 0, 10) - sess := db.GetEngine(db.DefaultContext). + sess := db.GetEngine(ctx). Where(opts.toConds()). Asc("`user`.name") if opts.Page > 0 && opts.PageSize > 0 { @@ -480,8 +480,8 @@ func FindOrgs(opts FindOrgOptions) ([]*Organization, error) { } // CountOrgs returns total count organizations according options -func CountOrgs(opts FindOrgOptions) (int64, error) { - return db.GetEngine(db.DefaultContext). +func CountOrgs(ctx context.Context, opts FindOrgOptions) (int64, error) { + return db.GetEngine(ctx). Where(opts.toConds()). Count(new(Organization)) } @@ -505,13 +505,13 @@ func HasOrgOrUserVisible(ctx context.Context, orgOrUser, user *user_model.User) } // HasOrgsVisible tells if the given user can see at least one of the orgs provided -func HasOrgsVisible(orgs []*Organization, user *user_model.User) bool { +func HasOrgsVisible(ctx context.Context, orgs []*Organization, user *user_model.User) bool { if len(orgs) == 0 { return false } for _, org := range orgs { - if HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), user) { + if HasOrgOrUserVisible(ctx, org.AsUser(), user) { return true } } @@ -520,10 +520,10 @@ func HasOrgsVisible(orgs []*Organization, user *user_model.User) bool { // GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID // are allowed to create repos. -func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) { +func GetOrgsCanCreateRepoByUserID(ctx context.Context, userID int64) ([]*Organization, error) { orgs := make([]*Organization, 0, 10) - return orgs, db.GetEngine(db.DefaultContext).Where(builder.In("id", builder.Select("`user`.id").From("`user`"). + return orgs, db.GetEngine(ctx).Where(builder.In("id", builder.Select("`user`.id").From("`user`"). Join("INNER", "`team_user`", "`team_user`.org_id = `user`.id"). Join("INNER", "`team`", "`team`.id = `team_user`.team_id"). Where(builder.Eq{"`team_user`.uid": userID}). @@ -550,9 +550,9 @@ func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUs } // ChangeOrgUserStatus changes public or private membership status. -func ChangeOrgUserStatus(orgID, uid int64, public bool) error { +func ChangeOrgUserStatus(ctx context.Context, orgID, uid int64, public bool) error { ou := new(OrgUser) - has, err := db.GetEngine(db.DefaultContext). + has, err := db.GetEngine(ctx). Where("uid=?", uid). And("org_id=?", orgID). Get(ou) @@ -563,18 +563,18 @@ func ChangeOrgUserStatus(orgID, uid int64, public bool) error { } ou.IsPublic = public - _, err = db.GetEngine(db.DefaultContext).ID(ou.ID).Cols("is_public").Update(ou) + _, err = db.GetEngine(ctx).ID(ou.ID).Cols("is_public").Update(ou) return err } // AddOrgUser adds new user to given organization. -func AddOrgUser(orgID, uid int64) error { - isAlreadyMember, err := IsOrganizationMember(db.DefaultContext, orgID, uid) +func AddOrgUser(ctx context.Context, orgID, uid int64) error { + isAlreadyMember, err := IsOrganizationMember(ctx, orgID, uid) if err != nil || isAlreadyMember { return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -669,19 +669,19 @@ func (org *Organization) getUserTeamIDs(ctx context.Context, userID int64) ([]in } // TeamsWithAccessToRepo returns all teams that have given access level to the repository. -func (org *Organization) TeamsWithAccessToRepo(repoID int64, mode perm.AccessMode) ([]*Team, error) { - return GetTeamsWithAccessToRepo(db.DefaultContext, org.ID, repoID, mode) +func (org *Organization) TeamsWithAccessToRepo(ctx context.Context, repoID int64, mode perm.AccessMode) ([]*Team, error) { + return GetTeamsWithAccessToRepo(ctx, org.ID, repoID, mode) } // GetUserTeamIDs returns of all team IDs of the organization that user is member of. -func (org *Organization) GetUserTeamIDs(userID int64) ([]int64, error) { - return org.getUserTeamIDs(db.DefaultContext, userID) +func (org *Organization) GetUserTeamIDs(ctx context.Context, userID int64) ([]int64, error) { + return org.getUserTeamIDs(ctx, userID) } // GetUserTeams returns all teams that belong to user, // and that the user has joined. -func (org *Organization) GetUserTeams(userID int64) ([]*Team, error) { - return org.getUserTeams(db.DefaultContext, userID) +func (org *Organization) GetUserTeams(ctx context.Context, userID int64) ([]*Team, error) { + return org.getUserTeams(ctx, userID) } // AccessibleReposEnvironment operations involving the repositories that are @@ -733,11 +733,11 @@ func AccessibleReposEnv(ctx context.Context, org *Organization, userID int64) (A // AccessibleTeamReposEnv an AccessibleReposEnvironment for the repositories in `org` // that are accessible to the specified team. -func (org *Organization) AccessibleTeamReposEnv(team *Team) AccessibleReposEnvironment { +func (org *Organization) AccessibleTeamReposEnv(ctx context.Context, team *Team) AccessibleReposEnvironment { return &accessibleReposEnv{ org: org, team: team, - ctx: db.DefaultContext, + ctx: ctx, orderBy: db.SearchOrderByRecentUpdated, } } diff --git a/models/organization/org_test.go b/models/organization/org_test.go index d36736b5c2a..aa72fc467ea 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -31,7 +31,7 @@ func TestUser_IsOwnedBy(t *testing.T) { {2, 3, false}, } { org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: testCase.OrgID}) - isOwner, err := org.IsOwnedBy(testCase.UserID) + isOwner, err := org.IsOwnedBy(db.DefaultContext, testCase.UserID) assert.NoError(t, err) assert.Equal(t, testCase.ExpectedOwner, isOwner) } @@ -52,7 +52,7 @@ func TestUser_IsOrgMember(t *testing.T) { {2, 3, false}, } { org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: testCase.OrgID}) - isMember, err := org.IsOrgMember(testCase.UserID) + isMember, err := org.IsOrgMember(db.DefaultContext, testCase.UserID) assert.NoError(t, err) assert.Equal(t, testCase.ExpectedMember, isMember) } @@ -89,7 +89,7 @@ func TestUser_GetOwnerTeam(t *testing.T) { func TestUser_GetTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) - teams, err := org.LoadTeams() + teams, err := org.LoadTeams(db.DefaultContext) assert.NoError(t, err) if assert.Len(t, teams, 5) { assert.Equal(t, int64(1), teams[0].ID) @@ -103,7 +103,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}) - members, _, err := org.GetMembers() + members, _, err := org.GetMembers(db.DefaultContext) assert.NoError(t, err) if assert.Len(t, members, 3) { assert.Equal(t, int64(2), members[0].ID) @@ -131,7 +131,7 @@ func TestCountOrganizations(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&organization.Organization{}) assert.NoError(t, err) - cnt, err := organization.CountOrgs(organization.FindOrgOptions{IncludePrivate: true}) + cnt, err := organization.CountOrgs(db.DefaultContext, organization.FindOrgOptions{IncludePrivate: true}) assert.NoError(t, err) assert.Equal(t, expected, cnt) } @@ -168,7 +168,7 @@ func TestIsOrganizationMember(t *testing.T) { func TestIsPublicMembership(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(orgID, userID int64, expected bool) { - isMember, err := organization.IsPublicMembership(orgID, userID) + isMember, err := organization.IsPublicMembership(db.DefaultContext, orgID, userID) assert.NoError(t, err) assert.EqualValues(t, expected, isMember) } @@ -183,7 +183,7 @@ func TestIsPublicMembership(t *testing.T) { func TestFindOrgs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - orgs, err := organization.FindOrgs(organization.FindOrgOptions{ + orgs, err := organization.FindOrgs(db.DefaultContext, organization.FindOrgOptions{ UserID: 4, IncludePrivate: true, }) @@ -192,14 +192,14 @@ func TestFindOrgs(t *testing.T) { assert.EqualValues(t, 3, orgs[0].ID) } - orgs, err = organization.FindOrgs(organization.FindOrgOptions{ + orgs, err = organization.FindOrgs(db.DefaultContext, organization.FindOrgOptions{ UserID: 4, IncludePrivate: false, }) assert.NoError(t, err) assert.Len(t, orgs, 0) - total, err := organization.CountOrgs(organization.FindOrgOptions{ + total, err := organization.CountOrgs(db.DefaultContext, organization.FindOrgOptions{ UserID: 4, IncludePrivate: true, }) @@ -250,7 +250,7 @@ func TestChangeOrgUserStatus(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(orgID, userID int64, public bool) { - assert.NoError(t, organization.ChangeOrgUserStatus(orgID, userID, public)) + assert.NoError(t, organization.ChangeOrgUserStatus(db.DefaultContext, orgID, userID, public)) orgUser := unittest.AssertExistsAndLoadBean(t, &organization.OrgUser{OrgID: orgID, UID: userID}) assert.Equal(t, public, orgUser.IsPublic) } @@ -258,14 +258,14 @@ func TestChangeOrgUserStatus(t *testing.T) { testSuccess(3, 2, false) testSuccess(3, 2, false) testSuccess(3, 4, true) - assert.NoError(t, organization.ChangeOrgUserStatus(unittest.NonexistentID, unittest.NonexistentID, true)) + assert.NoError(t, organization.ChangeOrgUserStatus(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID, true)) } func TestUser_GetUserTeamIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) testSuccess := func(userID int64, expected []int64) { - teamIDs, err := org.GetUserTeamIDs(userID) + teamIDs, err := org.GetUserTeamIDs(db.DefaultContext, userID) assert.NoError(t, err) assert.Equal(t, expected, teamIDs) } @@ -352,7 +352,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)) + assert.NoError(t, organization.CreateOrganization(db.DefaultContext, org, owner)) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}) test1 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner) @@ -375,7 +375,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)) + assert.NoError(t, organization.CreateOrganization(db.DefaultContext, org, owner)) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}) test1 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner) @@ -398,7 +398,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)) + assert.NoError(t, organization.CreateOrganization(db.DefaultContext, org, owner)) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{Name: org.Name, Type: user_model.UserTypeOrganization}) test1 := organization.HasOrgOrUserVisible(db.DefaultContext, org.AsUser(), owner) @@ -461,7 +461,7 @@ func TestCreateOrganization(t *testing.T) { } unittest.AssertNotExistsBean(t, &user_model.User{Name: newOrgName, Type: user_model.UserTypeOrganization}) - assert.NoError(t, organization.CreateOrganization(org, owner)) + assert.NoError(t, organization.CreateOrganization(db.DefaultContext, org, owner)) org = unittest.AssertExistsAndLoadBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}) ownerTeam := unittest.AssertExistsAndLoadBean(t, @@ -481,7 +481,7 @@ func TestCreateOrganization2(t *testing.T) { } unittest.AssertNotExistsBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}) - err := organization.CreateOrganization(org, owner) + err := organization.CreateOrganization(db.DefaultContext, org, owner) assert.Error(t, err) assert.True(t, organization.IsErrUserNotAllowedCreateOrg(err)) unittest.AssertNotExistsBean(t, &organization.Organization{Name: newOrgName, Type: user_model.UserTypeOrganization}) @@ -495,7 +495,7 @@ func TestCreateOrganization3(t *testing.T) { owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) org := &organization.Organization{Name: "org3"} // should already exist unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: org.Name}) // sanity check - err := organization.CreateOrganization(org, owner) + err := organization.CreateOrganization(db.DefaultContext, org, owner) assert.Error(t, err) assert.True(t, user_model.IsErrUserAlreadyExist(err)) unittest.CheckConsistencyFor(t, &user_model.User{}, &organization.Team{}) @@ -506,7 +506,7 @@ func TestCreateOrganization4(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - err := organization.CreateOrganization(&organization.Organization{Name: "assets"}, owner) + err := organization.CreateOrganization(db.DefaultContext, &organization.Organization{Name: "assets"}, owner) assert.Error(t, err) assert.True(t, db.IsErrNameReserved(err)) unittest.CheckConsistencyFor(t, &organization.Organization{}, &organization.Team{}) diff --git a/models/organization/org_user.go b/models/organization/org_user.go index d0598ab5d11..5fe3a178d2b 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -78,8 +78,8 @@ func IsOrganizationMember(ctx context.Context, orgID, uid int64) (bool, error) { } // IsPublicMembership returns true if the given user's membership of given org is public. -func IsPublicMembership(orgID, uid int64) (bool, error) { - return db.GetEngine(db.DefaultContext). +func IsPublicMembership(ctx context.Context, orgID, uid int64) (bool, error) { + return db.GetEngine(ctx). Where("uid=?", uid). And("org_id=?", orgID). And("is_public=?", true). @@ -98,12 +98,12 @@ func CanCreateOrgRepo(ctx context.Context, orgID, uid int64) (bool, error) { } // IsUserOrgOwner returns true if user is in the owner team of given organization. -func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool { +func IsUserOrgOwner(ctx context.Context, users user_model.UserList, orgID int64) map[int64]bool { results := make(map[int64]bool, len(users)) for _, user := range users { results[user.ID] = false // Set default to false } - ownerMaps, err := loadOrganizationOwners(db.DefaultContext, users, orgID) + ownerMaps, err := loadOrganizationOwners(ctx, users, orgID) if err == nil { for _, owner := range ownerMaps { results[owner.UID] = true diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go index b6477f859c7..7924517f312 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -39,7 +39,7 @@ func TestUserIsPublicMember(t *testing.T) { func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) { user, err := user_model.GetUserByID(db.DefaultContext, uid) assert.NoError(t, err) - is, err := organization.IsPublicMembership(orgID, user.ID) + is, err := organization.IsPublicMembership(db.DefaultContext, orgID, user.ID) assert.NoError(t, err) assert.Equal(t, expected, is) } @@ -94,7 +94,7 @@ func TestUserListIsPublicMember(t *testing.T) { func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) { org, err := organization.GetOrgByID(db.DefaultContext, orgID) assert.NoError(t, err) - _, membersIsPublic, err := org.GetMembers() + _, membersIsPublic, err := org.GetMembers(db.DefaultContext) assert.NoError(t, err) assert.Equal(t, expected, membersIsPublic) } @@ -121,9 +121,9 @@ func TestUserListIsUserOrgOwner(t *testing.T) { func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) { org, err := organization.GetOrgByID(db.DefaultContext, orgID) assert.NoError(t, err) - members, _, err := org.GetMembers() + members, _, err := org.GetMembers(db.DefaultContext) assert.NoError(t, err) - assert.Equal(t, expected, organization.IsUserOrgOwner(members, orgID)) + assert.Equal(t, expected, organization.IsUserOrgOwner(db.DefaultContext, members, orgID)) } func TestAddOrgUser(t *testing.T) { @@ -134,7 +134,7 @@ func TestAddOrgUser(t *testing.T) { if !unittest.BeanExists(t, &organization.OrgUser{OrgID: orgID, UID: userID}) { expectedNumMembers++ } - assert.NoError(t, organization.AddOrgUser(orgID, userID)) + assert.NoError(t, organization.AddOrgUser(db.DefaultContext, orgID, userID)) ou := &organization.OrgUser{OrgID: orgID, UID: userID} unittest.AssertExistsAndLoadBean(t, ou) assert.Equal(t, isPublic, ou.IsPublic) diff --git a/models/organization/team.go b/models/organization/team.go index 3624fdc4666..72afc673693 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -144,8 +144,8 @@ func (t *Team) IsOwnerTeam() bool { } // IsMember returns true if given user is a member of team. -func (t *Team) IsMember(userID int64) bool { - isMember, err := IsTeamMember(db.DefaultContext, t.OrgID, t.ID, userID) +func (t *Team) IsMember(ctx context.Context, userID int64) bool { + isMember, err := IsTeamMember(ctx, t.OrgID, t.ID, userID) if err != nil { log.Error("IsMember: %v", err) return false @@ -217,10 +217,10 @@ func GetTeam(ctx context.Context, orgID int64, name string) (*Team, error) { } // GetTeamIDsByNames returns a slice of team ids corresponds to names. -func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) { +func GetTeamIDsByNames(ctx context.Context, orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) { ids := make([]int64, 0, len(names)) for _, name := range names { - u, err := GetTeam(db.DefaultContext, orgID, name) + u, err := GetTeam(ctx, orgID, name) if err != nil { if ignoreNonExistent { continue @@ -251,13 +251,13 @@ func GetTeamByID(ctx context.Context, teamID int64) (*Team, error) { } // GetTeamNamesByID returns team's lower name from a list of team ids. -func GetTeamNamesByID(teamIDs []int64) ([]string, error) { +func GetTeamNamesByID(ctx context.Context, teamIDs []int64) ([]string, error) { if len(teamIDs) == 0 { return []string{}, nil } var teamNames []string - err := db.GetEngine(db.DefaultContext).Table("team"). + err := db.GetEngine(ctx).Table("team"). Select("lower_name"). In("id", teamIDs). Asc("name"). diff --git a/models/organization/team_list.go b/models/organization/team_list.go index efb3104ad59..5b45429acf3 100644 --- a/models/organization/team_list.go +++ b/models/organization/team_list.go @@ -77,8 +77,8 @@ func (opts *SearchTeamOptions) toCond() builder.Cond { } // SearchTeam search for teams. Caller is responsible to check permissions. -func SearchTeam(opts *SearchTeamOptions) (TeamList, int64, error) { - sess := db.GetEngine(db.DefaultContext) +func SearchTeam(ctx context.Context, opts *SearchTeamOptions) (TeamList, int64, error) { + sess := db.GetEngine(ctx) opts.SetDefaultValues() cond := opts.toCond() diff --git a/models/organization/team_test.go b/models/organization/team_test.go index c63b83aab77..23a6affe248 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -27,14 +27,14 @@ func TestTeam_IsMember(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) 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)) + assert.True(t, team.IsMember(db.DefaultContext, 2)) + assert.False(t, team.IsMember(db.DefaultContext, 4)) + assert.False(t, team.IsMember(db.DefaultContext, unittest.NonexistentID)) 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)) + assert.True(t, team.IsMember(db.DefaultContext, 2)) + assert.True(t, team.IsMember(db.DefaultContext, 4)) + assert.False(t, team.IsMember(db.DefaultContext, unittest.NonexistentID)) } func TestTeam_GetRepositories(t *testing.T) { @@ -142,7 +142,7 @@ func TestGetTeamMembers(t *testing.T) { func TestGetUserTeams(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(userID int64) { - teams, _, err := organization.SearchTeam(&organization.SearchTeamOptions{UserID: userID}) + teams, _, err := organization.SearchTeam(db.DefaultContext, &organization.SearchTeamOptions{UserID: userID}) assert.NoError(t, err) for _, team := range teams { unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{TeamID: team.ID, UID: userID}) @@ -188,7 +188,7 @@ func TestUsersInTeamsCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(teamIDs, userIDs []int64, expected int64) { - count, err := organization.UsersInTeamsCount(teamIDs, userIDs) + count, err := organization.UsersInTeamsCount(db.DefaultContext, teamIDs, userIDs) assert.NoError(t, err) assert.Equal(t, expected, count) } diff --git a/models/organization/team_unit.go b/models/organization/team_unit.go index 7668ca74835..3087b70770c 100644 --- a/models/organization/team_unit.go +++ b/models/organization/team_unit.go @@ -30,8 +30,8 @@ func getUnitsByTeamID(ctx context.Context, teamID int64) (units []*TeamUnit, err } // UpdateTeamUnits updates a teams's units -func UpdateTeamUnits(team *Team, units []TeamUnit) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateTeamUnits(ctx context.Context, team *Team, units []TeamUnit) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/organization/team_user.go b/models/organization/team_user.go index 768dc24c507..ab767db2000 100644 --- a/models/organization/team_user.go +++ b/models/organization/team_user.go @@ -78,9 +78,9 @@ func IsUserInTeams(ctx context.Context, userID int64, teamIDs []int64) (bool, er } // UsersInTeamsCount counts the number of users which are in userIDs and teamIDs -func UsersInTeamsCount(userIDs, teamIDs []int64) (int64, error) { +func UsersInTeamsCount(ctx context.Context, userIDs, teamIDs []int64) (int64, error) { var ids []int64 - if err := db.GetEngine(db.DefaultContext).In("uid", userIDs).In("team_id", teamIDs). + if err := db.GetEngine(ctx).In("uid", userIDs).In("team_id", teamIDs). Table("team_user"). Cols("uid").GroupBy("uid").Find(&ids); err != nil { return 0, err diff --git a/models/packages/package_test.go b/models/packages/package_test.go index 525a9f08d62..7f03151e774 100644 --- a/models/packages/package_test.go +++ b/models/packages/package_test.go @@ -4,7 +4,6 @@ package packages_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/db" @@ -20,9 +19,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestHasOwnerPackages(t *testing.T) { diff --git a/models/perm/access/main_test.go b/models/perm/access/main_test.go index 8102cae4964..0a350dc41ea 100644 --- a/models/perm/access/main_test.go +++ b/models/perm/access/main_test.go @@ -4,7 +4,6 @@ package access_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -17,7 +16,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 2027b87ecb4..395ecdf1a50 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -261,16 +261,16 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use } // IsUserRealRepoAdmin check if this user is real repo admin -func IsUserRealRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bool, error) { +func IsUserRealRepoAdmin(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (bool, error) { if repo.OwnerID == user.ID { return true, nil } - if err := repo.LoadOwner(db.DefaultContext); err != nil { + if err := repo.LoadOwner(ctx); err != nil { return false, err } - accessMode, err := accessLevel(db.DefaultContext, user, repo) + accessMode, err := accessLevel(ctx, user, repo) if err != nil { return false, err } @@ -394,13 +394,13 @@ func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mo } // GetRepoReaders returns all users that have explicit read access or higher to the repository. -func GetRepoReaders(repo *repo_model.Repository) (_ []*user_model.User, err error) { - return getUsersWithAccessMode(db.DefaultContext, repo, perm_model.AccessModeRead) +func GetRepoReaders(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { + return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeRead) } // GetRepoWriters returns all users that have write access to the repository. -func GetRepoWriters(repo *repo_model.Repository) (_ []*user_model.User, err error) { - return getUsersWithAccessMode(db.DefaultContext, repo, perm_model.AccessModeWrite) +func GetRepoWriters(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { + return getUsersWithAccessMode(ctx, repo, perm_model.AccessModeWrite) } // IsRepoReader returns true if user has explicit read access or higher to the repository. diff --git a/models/project/board.go b/models/project/board.go index 2ab1d5c7b51..3e2d8e0472c 100644 --- a/models/project/board.go +++ b/models/project/board.go @@ -69,8 +69,8 @@ func (Board) TableName() string { } // NumIssues return counter of all issues assigned to the board -func (b *Board) NumIssues() int { - c, err := db.GetEngine(db.DefaultContext).Table("project_issue"). +func (b *Board) NumIssues(ctx context.Context) int { + c, err := db.GetEngine(ctx).Table("project_issue"). Where("project_id=?", b.ProjectID). And("project_board_id=?", b.ID). GroupBy("issue_id"). @@ -142,18 +142,18 @@ func createBoardsForProjectsType(ctx context.Context, project *Project) error { } // NewBoard adds a new project board to a given project -func NewBoard(board *Board) error { +func NewBoard(ctx context.Context, board *Board) error { if len(board.Color) != 0 && !BoardColorPattern.MatchString(board.Color) { return fmt.Errorf("bad color code: %s", board.Color) } - _, err := db.GetEngine(db.DefaultContext).Insert(board) + _, err := db.GetEngine(ctx).Insert(board) return err } // DeleteBoardByID removes all issues references to the project board. -func DeleteBoardByID(boardID int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteBoardByID(ctx context.Context, boardID int64) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -265,8 +265,8 @@ func (p *Project) getDefaultBoard(ctx context.Context) (*Board, error) { // SetDefaultBoard represents a board for issues not assigned to one // if boardID is 0 unset default -func SetDefaultBoard(projectID, boardID int64) error { - _, err := db.GetEngine(db.DefaultContext).Where(builder.Eq{ +func SetDefaultBoard(ctx context.Context, projectID, boardID int64) error { + _, err := db.GetEngine(ctx).Where(builder.Eq{ "project_id": projectID, "`default`": true, }).Cols("`default`").Update(&Board{Default: false}) @@ -275,7 +275,7 @@ func SetDefaultBoard(projectID, boardID int64) error { } if boardID > 0 { - _, err = db.GetEngine(db.DefaultContext).ID(boardID).Where(builder.Eq{"project_id": projectID}). + _, err = db.GetEngine(ctx).ID(boardID).Where(builder.Eq{"project_id": projectID}). Cols("`default`").Update(&Board{Default: true}) } @@ -283,9 +283,9 @@ func SetDefaultBoard(projectID, boardID int64) error { } // UpdateBoardSorting update project board sorting -func UpdateBoardSorting(bs BoardList) error { +func UpdateBoardSorting(ctx context.Context, bs BoardList) error { for i := range bs { - _, err := db.GetEngine(db.DefaultContext).ID(bs[i].ID).Cols( + _, err := db.GetEngine(ctx).ID(bs[i].ID).Cols( "sorting", ).Update(bs[i]) if err != nil { diff --git a/models/project/issue.go b/models/project/issue.go index 3269197d6cd..ebc9719de55 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -34,8 +34,8 @@ func deleteProjectIssuesByProjectID(ctx context.Context, projectID int64) error } // NumIssues return counter of all issues assigned to a project -func (p *Project) NumIssues() int { - c, err := db.GetEngine(db.DefaultContext).Table("project_issue"). +func (p *Project) NumIssues(ctx context.Context) int { + c, err := db.GetEngine(ctx).Table("project_issue"). Where("project_id=?", p.ID). GroupBy("issue_id"). Cols("issue_id"). @@ -48,8 +48,8 @@ func (p *Project) NumIssues() int { } // NumClosedIssues return counter of closed issues assigned to a project -func (p *Project) NumClosedIssues() int { - c, err := db.GetEngine(db.DefaultContext).Table("project_issue"). +func (p *Project) NumClosedIssues(ctx context.Context) int { + c, err := db.GetEngine(ctx).Table("project_issue"). Join("INNER", "issue", "project_issue.issue_id=issue.id"). Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, true). Cols("issue_id"). @@ -62,8 +62,8 @@ func (p *Project) NumClosedIssues() int { } // NumOpenIssues return counter of open issues assigned to a project -func (p *Project) NumOpenIssues() int { - c, err := db.GetEngine(db.DefaultContext).Table("project_issue"). +func (p *Project) NumOpenIssues(ctx context.Context) int { + c, err := db.GetEngine(ctx).Table("project_issue"). Join("INNER", "issue", "project_issue.issue_id=issue.id"). Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false). Cols("issue_id"). @@ -76,8 +76,8 @@ func (p *Project) NumOpenIssues() int { } // MoveIssuesOnProjectBoard moves or keeps issues in a column and sorts them inside that column -func MoveIssuesOnProjectBoard(board *Board, sortedIssueIDs map[int64]int64) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { +func MoveIssuesOnProjectBoard(ctx context.Context, board *Board, sortedIssueIDs map[int64]int64) error { + return db.WithTx(ctx, func(ctx context.Context) error { sess := db.GetEngine(ctx) issueIDs := make([]int64, 0, len(sortedIssueIDs)) diff --git a/models/project/main_test.go b/models/project/main_test.go index 816cbeb94a0..f4b2d6fedac 100644 --- a/models/project/main_test.go +++ b/models/project/main_test.go @@ -4,7 +4,6 @@ package project import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,7 +13,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), FixtureFiles: []string{ "project.yml", "project_board.yml", diff --git a/models/project/project.go b/models/project/project.go index 8056aba252d..3a1bfe1dbd3 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -124,9 +124,9 @@ func (p *Project) LoadRepo(ctx context.Context) (err error) { } // Link returns the project's relative URL. -func (p *Project) Link() string { +func (p *Project) Link(ctx context.Context) string { if p.OwnerID > 0 { - err := p.LoadOwner(db.DefaultContext) + err := p.LoadOwner(ctx) if err != nil { log.Error("LoadOwner: %v", err) return "" @@ -134,7 +134,7 @@ func (p *Project) Link() string { return fmt.Sprintf("%s/-/projects/%d", p.Owner.HomeLink(), p.ID) } if p.RepoID > 0 { - err := p.LoadRepo(db.DefaultContext) + err := p.LoadRepo(ctx) if err != nil { log.Error("LoadRepo: %v", err) return "" @@ -261,7 +261,7 @@ func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, e } // NewProject creates a new Project -func NewProject(p *Project) error { +func NewProject(ctx context.Context, p *Project) error { if !IsBoardTypeValid(p.BoardType) { p.BoardType = BoardTypeNone } @@ -274,7 +274,7 @@ func NewProject(p *Project) error { return util.NewInvalidArgumentErrorf("project type is not valid") } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -348,8 +348,8 @@ func updateRepositoryProjectCount(ctx context.Context, repoID int64) error { } // ChangeProjectStatusByRepoIDAndID toggles a project between opened and closed -func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ChangeProjectStatusByRepoIDAndID(ctx context.Context, repoID, projectID int64, isClosed bool) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -372,8 +372,8 @@ func ChangeProjectStatusByRepoIDAndID(repoID, projectID int64, isClosed bool) er } // ChangeProjectStatus toggle a project between opened and closed -func ChangeProjectStatus(p *Project, isClosed bool) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ChangeProjectStatus(ctx context.Context, p *Project, isClosed bool) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/project/project_test.go b/models/project/project_test.go index d1a47156536..6b5bd5b371d 100644 --- a/models/project/project_test.go +++ b/models/project/project_test.go @@ -60,7 +60,7 @@ func TestProject(t *testing.T) { CreatorID: 2, } - assert.NoError(t, NewProject(project)) + assert.NoError(t, NewProject(db.DefaultContext, project)) _, err := GetProjectByID(db.DefaultContext, project.ID) assert.NoError(t, err) @@ -74,7 +74,7 @@ func TestProject(t *testing.T) { assert.Equal(t, project.Title, projectFromDB.Title) - assert.NoError(t, ChangeProjectStatus(project, true)) + assert.NoError(t, ChangeProjectStatus(db.DefaultContext, project, true)) // Retrieve from DB afresh to check if it is truly closed projectFromDB, err = GetProjectByID(db.DefaultContext, project.ID) diff --git a/models/repo/archiver.go b/models/repo/archiver.go index 70f53cfe158..6d0ed42877f 100644 --- a/models/repo/archiver.go +++ b/models/repo/archiver.go @@ -72,7 +72,7 @@ var delRepoArchiver = new(RepoArchiver) // DeleteRepoArchiver delete archiver func DeleteRepoArchiver(ctx context.Context, archiver *RepoArchiver) error { - _, err := db.GetEngine(db.DefaultContext).ID(archiver.ID).Delete(delRepoArchiver) + _, err := db.GetEngine(ctx).ID(archiver.ID).Delete(delRepoArchiver) return err } @@ -113,8 +113,8 @@ func UpdateRepoArchiverStatus(ctx context.Context, archiver *RepoArchiver) error } // DeleteAllRepoArchives deletes all repo archives records -func DeleteAllRepoArchives() error { - _, err := db.GetEngine(db.DefaultContext).Where("1=1").Delete(new(RepoArchiver)) +func DeleteAllRepoArchives(ctx context.Context) error { + _, err := db.GetEngine(ctx).Where("1=1").Delete(new(RepoArchiver)) return err } @@ -133,10 +133,10 @@ func (opts FindRepoArchiversOption) toConds() builder.Cond { } // FindRepoArchives find repo archivers -func FindRepoArchives(opts FindRepoArchiversOption) ([]*RepoArchiver, error) { +func FindRepoArchives(ctx context.Context, opts FindRepoArchiversOption) ([]*RepoArchiver, error) { archivers := make([]*RepoArchiver, 0, opts.PageSize) start, limit := opts.GetSkipTake() - err := db.GetEngine(db.DefaultContext).Where(opts.toConds()). + err := db.GetEngine(ctx).Where(opts.toConds()). Asc("created_unix"). Limit(limit, start). Find(&archivers) @@ -144,7 +144,7 @@ func FindRepoArchives(opts FindRepoArchiversOption) ([]*RepoArchiver, error) { } // SetArchiveRepoState sets if a repo is archived -func SetArchiveRepoState(repo *Repository, isArchived bool) (err error) { +func SetArchiveRepoState(ctx context.Context, repo *Repository, isArchived bool) (err error) { repo.IsArchived = isArchived if isArchived { @@ -153,6 +153,6 @@ func SetArchiveRepoState(repo *Repository, isArchived bool) (err error) { repo.ArchivedUnix = timeutil.TimeStamp(0) } - _, err = db.GetEngine(db.DefaultContext).ID(repo.ID).Cols("is_archived", "archived_unix").NoAutoTime().Update(repo) + _, err = db.GetEngine(ctx).ID(repo.ID).Cols("is_archived", "archived_unix").NoAutoTime().Update(repo) return err } diff --git a/models/repo/attachment.go b/models/repo/attachment.go index df3b9cd2137..1a588398c1a 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -37,9 +37,9 @@ func init() { } // IncreaseDownloadCount is update download count + 1 -func (a *Attachment) IncreaseDownloadCount() error { +func (a *Attachment) IncreaseDownloadCount(ctx context.Context) error { // Update download count. - if _, err := db.GetEngine(db.DefaultContext).Exec("UPDATE `attachment` SET download_count=download_count+1 WHERE id=?", a.ID); err != nil { + if _, err := db.GetEngine(ctx).Exec("UPDATE `attachment` SET download_count=download_count+1 WHERE id=?", a.ID); err != nil { return fmt.Errorf("increase attachment count: %w", err) } @@ -164,8 +164,8 @@ func GetAttachmentByReleaseIDFileName(ctx context.Context, releaseID int64, file } // DeleteAttachment deletes the given attachment and optionally the associated file. -func DeleteAttachment(a *Attachment, remove bool) error { - _, err := DeleteAttachments(db.DefaultContext, []*Attachment{a}, remove) +func DeleteAttachment(ctx context.Context, a *Attachment, remove bool) error { + _, err := DeleteAttachments(ctx, []*Attachment{a}, remove) return err } @@ -196,23 +196,23 @@ func DeleteAttachments(ctx context.Context, attachments []*Attachment, remove bo } // DeleteAttachmentsByIssue deletes all attachments associated with the given issue. -func DeleteAttachmentsByIssue(issueID int64, remove bool) (int, error) { - attachments, err := GetAttachmentsByIssueID(db.DefaultContext, issueID) +func DeleteAttachmentsByIssue(ctx context.Context, issueID int64, remove bool) (int, error) { + attachments, err := GetAttachmentsByIssueID(ctx, issueID) if err != nil { return 0, err } - return DeleteAttachments(db.DefaultContext, attachments, remove) + return DeleteAttachments(ctx, attachments, remove) } // DeleteAttachmentsByComment deletes all attachments associated with the given comment. -func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) { - attachments, err := GetAttachmentsByCommentID(db.DefaultContext, commentID) +func DeleteAttachmentsByComment(ctx context.Context, commentID int64, remove bool) (int, error) { + attachments, err := GetAttachmentsByCommentID(ctx, commentID) if err != nil { return 0, err } - return DeleteAttachments(db.DefaultContext, attachments, remove) + return DeleteAttachments(ctx, attachments, remove) } // UpdateAttachmentByUUID Updates attachment via uuid diff --git a/models/repo/attachment_test.go b/models/repo/attachment_test.go index 21fba227a5c..c059ffd39a9 100644 --- a/models/repo/attachment_test.go +++ b/models/repo/attachment_test.go @@ -21,7 +21,7 @@ func TestIncreaseDownloadCount(t *testing.T) { assert.Equal(t, int64(0), attachment.DownloadCount) // increase download count - err = attachment.IncreaseDownloadCount() + err = attachment.IncreaseDownloadCount(db.DefaultContext) assert.NoError(t, err) attachment, err = repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") @@ -45,15 +45,15 @@ func TestGetByCommentOrIssueID(t *testing.T) { func TestDeleteAttachments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err := repo_model.DeleteAttachmentsByIssue(4, false) + count, err := repo_model.DeleteAttachmentsByIssue(db.DefaultContext, 4, false) assert.NoError(t, err) assert.Equal(t, 2, count) - count, err = repo_model.DeleteAttachmentsByComment(2, false) + count, err = repo_model.DeleteAttachmentsByComment(db.DefaultContext, 2, false) assert.NoError(t, err) assert.Equal(t, 2, count) - err = repo_model.DeleteAttachment(&repo_model.Attachment{ID: 8}, false) + err = repo_model.DeleteAttachment(db.DefaultContext, &repo_model.Attachment{ID: 8}, false) assert.NoError(t, err) attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18") diff --git a/models/repo/collaboration.go b/models/repo/collaboration.go index 7989e5bdf9c..2018ae2a7db 100644 --- a/models/repo/collaboration.go +++ b/models/repo/collaboration.go @@ -62,8 +62,8 @@ func GetCollaborators(ctx context.Context, repoID int64, listOptions db.ListOpti } // CountCollaborators returns total number of collaborators for a repository -func CountCollaborators(repoID int64) (int64, error) { - return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repoID).Count(&Collaboration{}) +func CountCollaborators(ctx context.Context, repoID int64) (int64, error) { + return db.GetEngine(ctx).Where("repo_id = ? ", repoID).Count(&Collaboration{}) } // GetCollaboration get collaboration for a repository id with a user id @@ -138,11 +138,11 @@ func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid in } // IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository -func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) { +func IsOwnerMemberCollaborator(ctx context.Context, repo *Repository, userID int64) (bool, error) { if repo.OwnerID == userID { return true, nil } - teamMember, err := db.GetEngine(db.DefaultContext).Join("INNER", "team_repo", "team_repo.team_id = team_user.team_id"). + teamMember, err := db.GetEngine(ctx).Join("INNER", "team_repo", "team_repo.team_id = team_user.team_id"). Join("INNER", "team_unit", "team_unit.team_id = team_user.team_id"). Where("team_repo.repo_id = ?", repo.ID). And("team_unit.`type` = ?", unit.TypeCode). @@ -154,5 +154,5 @@ func IsOwnerMemberCollaborator(repo *Repository, userID int64) (bool, error) { return true, nil } - return db.GetEngine(db.DefaultContext).Get(&Collaboration{RepoID: repo.ID, UserID: userID}) + return db.GetEngine(ctx).Get(&Collaboration{RepoID: repo.ID, UserID: userID}) } diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go index a29dfe99a50..38114c307f6 100644 --- a/models/repo/collaboration_test.go +++ b/models/repo/collaboration_test.go @@ -89,17 +89,17 @@ func TestRepository_CountCollaborators(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) - count, err := repo_model.CountCollaborators(repo1.ID) + count, err := repo_model.CountCollaborators(db.DefaultContext, repo1.ID) assert.NoError(t, err) assert.EqualValues(t, 2, count) repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22}) - count, err = repo_model.CountCollaborators(repo2.ID) + count, err = repo_model.CountCollaborators(db.DefaultContext, repo2.ID) assert.NoError(t, err) assert.EqualValues(t, 2, count) // Non-existent repository. - count, err = repo_model.CountCollaborators(unittest.NonexistentID) + count, err = repo_model.CountCollaborators(db.DefaultContext, unittest.NonexistentID) assert.NoError(t, err) assert.EqualValues(t, 0, count) } @@ -110,31 +110,31 @@ func TestRepository_IsOwnerMemberCollaborator(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) // Organisation owner. - actual, err := repo_model.IsOwnerMemberCollaborator(repo1, 2) + actual, err := repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 2) assert.NoError(t, err) assert.True(t, actual) // Team member. - actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 4) + actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 4) assert.NoError(t, err) assert.True(t, actual) // Normal user. - actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 1) + actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo1, 1) assert.NoError(t, err) assert.False(t, actual) repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) // Collaborator. - actual, err = repo_model.IsOwnerMemberCollaborator(repo2, 4) + actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo2, 4) assert.NoError(t, err) assert.True(t, actual) repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15}) // Repository owner. - actual, err = repo_model.IsOwnerMemberCollaborator(repo3, 2) + actual, err = repo_model.IsOwnerMemberCollaborator(db.DefaultContext, repo3, 2) assert.NoError(t, err) assert.True(t, actual) } diff --git a/models/repo/fork.go b/models/repo/fork.go index eafbab0fb17..6be6ebc3f52 100644 --- a/models/repo/fork.go +++ b/models/repo/fork.go @@ -21,9 +21,9 @@ func GetRepositoriesByForkID(ctx context.Context, forkID int64) ([]*Repository, } // GetForkedRepo checks if given user has already forked a repository with given ID. -func GetForkedRepo(ownerID, repoID int64) *Repository { +func GetForkedRepo(ctx context.Context, ownerID, repoID int64) *Repository { repo := new(Repository) - has, _ := db.GetEngine(db.DefaultContext). + has, _ := db.GetEngine(ctx). Where("owner_id=? AND fork_id=?", ownerID, repoID). Get(repo) if has { @@ -33,8 +33,8 @@ func GetForkedRepo(ownerID, repoID int64) *Repository { } // HasForkedRepo checks if given user has already forked a repository with given ID. -func HasForkedRepo(ownerID, repoID int64) bool { - has, _ := db.GetEngine(db.DefaultContext). +func HasForkedRepo(ctx context.Context, ownerID, repoID int64) bool { + has, _ := db.GetEngine(ctx). Table("repository"). Where("owner_id=? AND fork_id=?", ownerID, repoID). Exist() @@ -55,10 +55,10 @@ func GetUserFork(ctx context.Context, repoID, userID int64) (*Repository, error) } // GetForks returns all the forks of the repository -func GetForks(repo *Repository, listOptions db.ListOptions) ([]*Repository, error) { +func GetForks(ctx context.Context, repo *Repository, listOptions db.ListOptions) ([]*Repository, error) { if listOptions.Page == 0 { forks := make([]*Repository, 0, repo.NumForks) - return forks, db.GetEngine(db.DefaultContext).Find(&forks, &Repository{ForkID: repo.ID}) + return forks, db.GetEngine(ctx).Find(&forks, &Repository{ForkID: repo.ID}) } sess := db.GetPaginatedSession(&listOptions) diff --git a/models/repo/git.go b/models/repo/git.go index 2f71128b5aa..610c5542965 100644 --- a/models/repo/git.go +++ b/models/repo/git.go @@ -4,6 +4,8 @@ package repo import ( + "context" + "code.gitea.io/gitea/models/db" ) @@ -26,7 +28,7 @@ const ( ) // UpdateDefaultBranch updates the default branch -func UpdateDefaultBranch(repo *Repository) error { - _, err := db.GetEngine(db.DefaultContext).ID(repo.ID).Cols("default_branch").Update(repo) +func UpdateDefaultBranch(ctx context.Context, repo *Repository) error { + _, err := db.GetEngine(ctx).ID(repo.ID).Cols("default_branch").Update(repo) return err } diff --git a/models/repo/main_test.go b/models/repo/main_test.go index ff97c7ac9ef..b49855f2c86 100644 --- a/models/repo/main_test.go +++ b/models/repo/main_test.go @@ -4,7 +4,6 @@ package repo_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -18,7 +17,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/repo/mirror.go b/models/repo/mirror.go index 39482037b20..be7b7856127 100644 --- a/models/repo/mirror.go +++ b/models/repo/mirror.go @@ -31,7 +31,7 @@ type Mirror struct { LFS bool `xorm:"lfs_enabled NOT NULL DEFAULT false"` LFSEndpoint string `xorm:"lfs_endpoint TEXT"` - Address string `xorm:"-"` + RemoteAddress string `xorm:"VARCHAR(2048)"` } func init() { @@ -47,12 +47,12 @@ func (m *Mirror) BeforeInsert() { } // GetRepository returns the repository. -func (m *Mirror) GetRepository() *Repository { +func (m *Mirror) GetRepository(ctx context.Context) *Repository { if m.Repo != nil { return m.Repo } var err error - m.Repo, err = GetRepositoryByID(db.DefaultContext, m.RepoID) + m.Repo, err = GetRepositoryByID(ctx, m.RepoID) if err != nil { log.Error("getRepositoryByID[%d]: %v", m.ID, err) } @@ -99,14 +99,14 @@ func TouchMirror(ctx context.Context, m *Mirror) error { } // DeleteMirrorByRepoID deletes a mirror by repoID -func DeleteMirrorByRepoID(repoID int64) error { - _, err := db.GetEngine(db.DefaultContext).Delete(&Mirror{RepoID: repoID}) +func DeleteMirrorByRepoID(ctx context.Context, repoID int64) error { + _, err := db.GetEngine(ctx).Delete(&Mirror{RepoID: repoID}) return err } // MirrorsIterate iterates all mirror repositories. -func MirrorsIterate(limit int, f func(idx int, bean any) error) error { - sess := db.GetEngine(db.DefaultContext). +func MirrorsIterate(ctx context.Context, limit int, f func(idx int, bean any) error) error { + sess := db.GetEngine(ctx). Where("next_update_unix<=?", time.Now().Unix()). And("next_update_unix!=0"). OrderBy("updated_unix ASC") diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go index 3edbcceb9b3..61cf1849b00 100644 --- a/models/repo/pushmirror.go +++ b/models/repo/pushmirror.go @@ -20,10 +20,11 @@ var ErrPushMirrorNotExist = util.NewNotExistErrorf("PushMirror does not exist") // PushMirror represents mirror information of a repository. type PushMirror struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"INDEX"` - Repo *Repository `xorm:"-"` - RemoteName string + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"INDEX"` + Repo *Repository `xorm:"-"` + RemoteName string + RemoteAddress string `xorm:"VARCHAR(2048)"` SyncOnCommit bool `xorm:"NOT NULL DEFAULT true"` Interval time.Duration @@ -31,6 +32,7 @@ type PushMirror struct { LastUpdateUnix timeutil.TimeStamp `xorm:"INDEX last_update"` LastError string `xorm:"text"` } + type PushMirrorOptions struct { ID int64 RepoID int64 @@ -56,12 +58,12 @@ func init() { } // GetRepository returns the path of the repository. -func (m *PushMirror) GetRepository() *Repository { +func (m *PushMirror) GetRepository(ctx context.Context) *Repository { if m.Repo != nil { return m.Repo } var err error - m.Repo, err = GetRepositoryByID(db.DefaultContext, m.RepoID) + m.Repo, err = GetRepositoryByID(ctx, m.RepoID) if err != nil { log.Error("getRepositoryByID[%d]: %v", m.ID, err) } diff --git a/models/repo/release.go b/models/repo/release.go index 0e924743659..ff31ec45102 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -181,9 +181,9 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs } // GetRelease returns release by given ID. -func GetRelease(repoID int64, tagName string) (*Release, error) { +func GetRelease(ctx context.Context, repoID int64, tagName string) (*Release, error) { rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)} - has, err := db.GetEngine(db.DefaultContext).Get(rel) + has, err := db.GetEngine(ctx).Get(rel) if err != nil { return nil, err } else if !has { @@ -284,12 +284,12 @@ func GetTagNamesByRepoID(ctx context.Context, repoID int64) ([]string, error) { } // CountReleasesByRepoID returns a number of releases matching FindReleaseOptions and RepoID. -func CountReleasesByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) { - return db.GetEngine(db.DefaultContext).Where(opts.toConds(repoID)).Count(new(Release)) +func CountReleasesByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) { + return db.GetEngine(ctx).Where(opts.toConds(repoID)).Count(new(Release)) } // GetLatestReleaseByRepoID returns the latest release for a repository -func GetLatestReleaseByRepoID(repoID int64) (*Release, error) { +func GetLatestReleaseByRepoID(ctx context.Context, repoID int64) (*Release, error) { cond := builder.NewCond(). And(builder.Eq{"repo_id": repoID}). And(builder.Eq{"is_draft": false}). @@ -297,7 +297,7 @@ func GetLatestReleaseByRepoID(repoID int64) (*Release, error) { And(builder.Eq{"is_tag": false}) rel := new(Release) - has, err := db.GetEngine(db.DefaultContext). + has, err := db.GetEngine(ctx). Desc("created_unix", "id"). Where(cond). Get(rel) @@ -442,8 +442,8 @@ func DeleteReleaseByID(ctx context.Context, id int64) error { } // UpdateReleasesMigrationsByType updates all migrated repositories' releases from gitServiceType to replace originalAuthorID to posterID -func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error { - _, err := db.GetEngine(db.DefaultContext).Table("release"). +func UpdateReleasesMigrationsByType(ctx context.Context, gitServiceType structs.GitServiceType, originalAuthorID string, posterID int64) error { + _, err := db.GetEngine(ctx).Table("release"). Where("repo_id IN (SELECT id FROM repository WHERE original_service_type = ?)", gitServiceType). And("original_author_id = ?", originalAuthorID). Update(map[string]any{ @@ -485,8 +485,8 @@ func PushUpdateDeleteTagsContext(ctx context.Context, repo *Repository, tags []s } // PushUpdateDeleteTag must be called for any push actions to delete tag -func PushUpdateDeleteTag(repo *Repository, tagName string) error { - rel, err := GetRelease(repo.ID, tagName) +func PushUpdateDeleteTag(ctx context.Context, repo *Repository, tagName string) error { + rel, err := GetRelease(ctx, repo.ID, tagName) if err != nil { if IsErrReleaseNotExist(err) { return nil @@ -494,14 +494,14 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error { return fmt.Errorf("GetRelease: %w", err) } if rel.IsTag { - if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).Delete(new(Release)); err != nil { + if _, err = db.GetEngine(ctx).ID(rel.ID).Delete(new(Release)); err != nil { return fmt.Errorf("Delete: %w", err) } } else { rel.IsDraft = true rel.NumCommits = 0 rel.Sha1 = "" - if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil { + if _, err = db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel); err != nil { return fmt.Errorf("Update: %w", err) } } @@ -510,15 +510,15 @@ func PushUpdateDeleteTag(repo *Repository, tagName string) error { } // SaveOrUpdateTag must be called for any push actions to add tag -func SaveOrUpdateTag(repo *Repository, newRel *Release) error { - rel, err := GetRelease(repo.ID, newRel.TagName) +func SaveOrUpdateTag(ctx context.Context, repo *Repository, newRel *Release) error { + rel, err := GetRelease(ctx, repo.ID, newRel.TagName) if err != nil && !IsErrReleaseNotExist(err) { return fmt.Errorf("GetRelease: %w", err) } if rel == nil { rel = newRel - if _, err = db.GetEngine(db.DefaultContext).Insert(rel); err != nil { + if _, err = db.GetEngine(ctx).Insert(rel); err != nil { return fmt.Errorf("InsertOne: %w", err) } } else { @@ -529,7 +529,7 @@ func SaveOrUpdateTag(repo *Repository, newRel *Release) error { if rel.IsTag && newRel.PublisherID > 0 { rel.PublisherID = newRel.PublisherID } - if _, err = db.GetEngine(db.DefaultContext).ID(rel.ID).AllCols().Update(rel); err != nil { + if _, err = db.GetEngine(ctx).ID(rel.ID).AllCols().Update(rel); err != nil { return fmt.Errorf("Update: %w", err) } } @@ -554,8 +554,8 @@ func (r *Release) GetExternalName() string { return r.OriginalAuthor } func (r *Release) GetExternalID() int64 { return r.OriginalAuthorID } // InsertReleases migrates release -func InsertReleases(rels ...*Release) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func InsertReleases(ctx context.Context, rels ...*Release) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/repo/release_test.go b/models/repo/release_test.go index 2a45ab32f35..3643bff7f16 100644 --- a/models/repo/release_test.go +++ b/models/repo/release_test.go @@ -6,6 +6,7 @@ package repo import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -21,6 +22,6 @@ func TestMigrate_InsertReleases(t *testing.T) { Attachments: []*Attachment{a}, } - err := InsertReleases(r) + err := InsertReleases(db.DefaultContext, r) assert.NoError(t, err) } diff --git a/models/repo/repo.go b/models/repo/repo.go index 392dae40eb2..90555887581 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -47,6 +47,14 @@ func (err ErrUserDoesNotHaveAccessToRepo) Unwrap() error { return util.ErrPermissionDenied } +type ErrRepoIsArchived struct { + Repo *Repository +} + +func (err ErrRepoIsArchived) Error() string { + return fmt.Sprintf("%s is archived", err.Repo.LogString()) +} + var ( reservedRepoNames = []string{".", "..", "-"} reservedRepoPatterns = []string{"*.git", "*.wiki", "*.rss", "*.atom"} @@ -193,12 +201,8 @@ func (repo *Repository) SanitizedOriginalURL() string { if repo.OriginalURL == "" { return "" } - u, err := url.Parse(repo.OriginalURL) - if err != nil { - return "" - } - u.User = nil - return u.String() + u, _ := util.SanitizeURL(repo.OriginalURL) + return u } // text representations to be returned in SizeDetail.Name @@ -681,6 +685,14 @@ func (repo *Repository) GetTrustModel() TrustModelType { return trustModel } +// MustNotBeArchived returns ErrRepoIsArchived if the repo is archived +func (repo *Repository) MustNotBeArchived() error { + if repo.IsArchived { + return ErrRepoIsArchived{Repo: repo} + } + return nil +} + // __________ .__ __ // \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index b8804c6df11..89f28b8fcae 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -279,14 +279,14 @@ func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err } // UpdateRepoUnit updates the provided repo unit -func UpdateRepoUnit(unit *RepoUnit) error { - _, err := db.GetEngine(db.DefaultContext).ID(unit.ID).Update(unit) +func UpdateRepoUnit(ctx context.Context, unit *RepoUnit) error { + _, err := db.GetEngine(ctx).ID(unit.ID).Update(unit) return err } // UpdateRepositoryUnits updates a repository's units -func UpdateRepositoryUnits(repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateRepositoryUnits(ctx context.Context, repo *Repository, units []RepoUnit, deleteUnitTypes []unit.Type) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/repo/star.go b/models/repo/star.go index 89bdb7ac05c..60737149da8 100644 --- a/models/repo/star.go +++ b/models/repo/star.go @@ -24,8 +24,8 @@ func init() { } // StarRepo or unstar repository. -func StarRepo(userID, repoID int64, star bool) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func StarRepo(ctx context.Context, userID, repoID int64, star bool) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -72,8 +72,8 @@ func IsStaring(ctx context.Context, userID, repoID int64) bool { } // GetStargazers returns the users that starred the repo. -func GetStargazers(repo *Repository, opts db.ListOptions) ([]*user_model.User, error) { - sess := db.GetEngine(db.DefaultContext).Where("star.repo_id = ?", repo.ID). +func GetStargazers(ctx context.Context, repo *Repository, opts db.ListOptions) ([]*user_model.User, error) { + sess := db.GetEngine(ctx).Where("star.repo_id = ?", repo.ID). Join("LEFT", "star", "`user`.id = star.uid") if opts.Page > 0 { sess = db.SetSessionPagination(sess, &opts) diff --git a/models/repo/star_test.go b/models/repo/star_test.go index f15ac12ebea..62eac4e29a8 100644 --- a/models/repo/star_test.go +++ b/models/repo/star_test.go @@ -18,11 +18,11 @@ func TestStarRepo(t *testing.T) { const userID = 2 const repoID = 1 unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) - assert.NoError(t, repo_model.StarRepo(userID, repoID, true)) + assert.NoError(t, repo_model.StarRepo(db.DefaultContext, userID, repoID, true)) unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) - assert.NoError(t, repo_model.StarRepo(userID, repoID, true)) + assert.NoError(t, repo_model.StarRepo(db.DefaultContext, userID, repoID, true)) unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) - assert.NoError(t, repo_model.StarRepo(userID, repoID, false)) + assert.NoError(t, repo_model.StarRepo(db.DefaultContext, userID, repoID, false)) unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) } @@ -36,7 +36,7 @@ func TestRepository_GetStargazers(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) - gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) + gazers, err := repo_model.GetStargazers(db.DefaultContext, repo, db.ListOptions{Page: 0}) assert.NoError(t, err) if assert.Len(t, gazers, 1) { assert.Equal(t, int64(2), gazers[0].ID) @@ -47,7 +47,7 @@ func TestRepository_GetStargazers2(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) - gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) + gazers, err := repo_model.GetStargazers(db.DefaultContext, repo, db.ListOptions{Page: 0}) assert.NoError(t, err) assert.Len(t, gazers, 0) } @@ -57,15 +57,15 @@ func TestClearRepoStars(t *testing.T) { const userID = 2 const repoID = 1 unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) - assert.NoError(t, repo_model.StarRepo(userID, repoID, true)) + assert.NoError(t, repo_model.StarRepo(db.DefaultContext, userID, repoID, true)) unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) - assert.NoError(t, repo_model.StarRepo(userID, repoID, false)) + assert.NoError(t, repo_model.StarRepo(db.DefaultContext, userID, repoID, false)) unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) assert.NoError(t, repo_model.ClearRepoStars(db.DefaultContext, repoID)) unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) + gazers, err := repo_model.GetStargazers(db.DefaultContext, repo, db.ListOptions{Page: 0}) assert.NoError(t, err) assert.Len(t, gazers, 0) } diff --git a/models/repo/topic.go b/models/repo/topic.go index 71302388b94..ca533fc1e09 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -92,9 +92,9 @@ func SanitizeAndValidateTopics(topics []string) (validTopics, invalidTopics []st } // GetTopicByName retrieves topic by name -func GetTopicByName(name string) (*Topic, error) { +func GetTopicByName(ctx context.Context, name string) (*Topic, error) { var topic Topic - if has, err := db.GetEngine(db.DefaultContext).Where("name = ?", name).Get(&topic); err != nil { + if has, err := db.GetEngine(ctx).Where("name = ?", name).Get(&topic); err != nil { return nil, err } else if !has { return nil, ErrTopicNotExist{name} @@ -192,8 +192,8 @@ func (opts *FindTopicOptions) toConds() builder.Cond { } // FindTopics retrieves the topics via FindTopicOptions -func FindTopics(opts *FindTopicOptions) ([]*Topic, int64, error) { - sess := db.GetEngine(db.DefaultContext).Select("topic.*").Where(opts.toConds()) +func FindTopics(ctx context.Context, opts *FindTopicOptions) ([]*Topic, int64, error) { + sess := db.GetEngine(ctx).Select("topic.*").Where(opts.toConds()) orderBy := "topic.repo_count DESC" if opts.RepoID > 0 { sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") @@ -208,8 +208,8 @@ func FindTopics(opts *FindTopicOptions) ([]*Topic, int64, error) { } // CountTopics counts the number of topics matching the FindTopicOptions -func CountTopics(opts *FindTopicOptions) (int64, error) { - sess := db.GetEngine(db.DefaultContext).Where(opts.toConds()) +func CountTopics(ctx context.Context, opts *FindTopicOptions) (int64, error) { + sess := db.GetEngine(ctx).Where(opts.toConds()) if opts.RepoID > 0 { sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") } @@ -231,8 +231,8 @@ func GetRepoTopicByName(ctx context.Context, repoID int64, topicName string) (*T } // AddTopic adds a topic name to a repository (if it does not already have it) -func AddTopic(repoID int64, topicName string) (*Topic, error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func AddTopic(ctx context.Context, repoID int64, topicName string) (*Topic, error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } @@ -261,8 +261,8 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { } // DeleteTopic removes a topic name from a repository (if it has it) -func DeleteTopic(repoID int64, topicName string) (*Topic, error) { - topic, err := GetRepoTopicByName(db.DefaultContext, repoID, topicName) +func DeleteTopic(ctx context.Context, repoID int64, topicName string) (*Topic, error) { + topic, err := GetRepoTopicByName(ctx, repoID, topicName) if err != nil { return nil, err } @@ -271,26 +271,26 @@ func DeleteTopic(repoID int64, topicName string) (*Topic, error) { return nil, nil } - err = removeTopicFromRepo(db.DefaultContext, repoID, topic) + err = removeTopicFromRepo(ctx, repoID, topic) if err != nil { return nil, err } - err = syncTopicsInRepository(db.GetEngine(db.DefaultContext), repoID) + err = syncTopicsInRepository(db.GetEngine(ctx), repoID) return topic, err } // SaveTopics save topics to a repository -func SaveTopics(repoID int64, topicNames ...string) error { - topics, _, err := FindTopics(&FindTopicOptions{ +func SaveTopics(ctx context.Context, repoID int64, topicNames ...string) error { + topics, _, err := FindTopics(ctx, &FindTopicOptions{ RepoID: repoID, }) if err != nil { return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/repo/topic_test.go b/models/repo/topic_test.go index aaed91bdd3a..2b609e6d667 100644 --- a/models/repo/topic_test.go +++ b/models/repo/topic_test.go @@ -19,47 +19,47 @@ func TestAddTopic(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - topics, _, err := repo_model.FindTopics(&repo_model.FindTopicOptions{}) + topics, _, err := repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{}) assert.NoError(t, err) assert.Len(t, topics, totalNrOfTopics) - topics, total, err := repo_model.FindTopics(&repo_model.FindTopicOptions{ + topics, total, err := repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{ ListOptions: db.ListOptions{Page: 1, PageSize: 2}, }) assert.NoError(t, err) assert.Len(t, topics, 2) assert.EqualValues(t, 6, total) - topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{ + topics, _, err = repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{ RepoID: 1, }) assert.NoError(t, err) assert.Len(t, topics, repo1NrOfTopics) - assert.NoError(t, repo_model.SaveTopics(2, "golang")) + assert.NoError(t, repo_model.SaveTopics(db.DefaultContext, 2, "golang")) repo2NrOfTopics := 1 - topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{}) + topics, _, err = repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{}) assert.NoError(t, err) assert.Len(t, topics, totalNrOfTopics) - topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{ + topics, _, err = repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{ RepoID: 2, }) assert.NoError(t, err) assert.Len(t, topics, repo2NrOfTopics) - assert.NoError(t, repo_model.SaveTopics(2, "golang", "gitea")) + assert.NoError(t, repo_model.SaveTopics(db.DefaultContext, 2, "golang", "gitea")) repo2NrOfTopics = 2 totalNrOfTopics++ - topic, err := repo_model.GetTopicByName("gitea") + topic, err := repo_model.GetTopicByName(db.DefaultContext, "gitea") assert.NoError(t, err) assert.EqualValues(t, 1, topic.RepoCount) - topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{}) + topics, _, err = repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{}) assert.NoError(t, err) assert.Len(t, topics, totalNrOfTopics) - topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{ + topics, _, err = repo_model.FindTopics(db.DefaultContext, &repo_model.FindTopicOptions{ RepoID: 2, }) assert.NoError(t, err) diff --git a/models/repo/update.go b/models/repo/update.go index c4fba32ad20..6ddf1a8905e 100644 --- a/models/repo/update.go +++ b/models/repo/update.go @@ -16,11 +16,11 @@ import ( ) // UpdateRepositoryOwnerNames updates repository owner_names (this should only be used when the ownerName has changed case) -func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error { +func UpdateRepositoryOwnerNames(ctx context.Context, ownerID int64, ownerName string) error { if ownerID == 0 { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -36,8 +36,8 @@ func UpdateRepositoryOwnerNames(ownerID int64, ownerName string) error { } // UpdateRepositoryUpdatedTime updates a repository's updated time -func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error { - _, err := db.GetEngine(db.DefaultContext).Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", updateTime.Unix(), repoID) +func UpdateRepositoryUpdatedTime(ctx context.Context, repoID int64, updateTime time.Time) error { + _, err := db.GetEngine(ctx).Exec("UPDATE repository SET updated_unix = ? WHERE id = ?", updateTime.Unix(), repoID) return err } @@ -107,7 +107,7 @@ func (err ErrRepoFilesAlreadyExist) Unwrap() error { } // CheckCreateRepository check if could created a repository -func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdopt bool) error { +func CheckCreateRepository(ctx context.Context, doer, u *user_model.User, name string, overwriteOrAdopt bool) error { if !doer.CanCreateRepo() { return ErrReachLimitOfRepo{u.MaxRepoCreation} } @@ -116,7 +116,7 @@ func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdo return err } - has, err := IsRepositoryModelOrDirExist(db.DefaultContext, u, name) + has, err := IsRepositoryModelOrDirExist(ctx, u, name) if err != nil { return fmt.Errorf("IsRepositoryExist: %w", err) } else if has { @@ -136,18 +136,18 @@ func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdo } // ChangeRepositoryName changes all corresponding setting from old repository name to new one. -func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName string) (err error) { +func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *Repository, newRepoName string) (err error) { oldRepoName := repo.Name newRepoName = strings.ToLower(newRepoName) if err = IsUsableRepoName(newRepoName); err != nil { return err } - if err := repo.LoadOwner(db.DefaultContext); err != nil { + if err := repo.LoadOwner(ctx); err != nil { return err } - has, err := IsRepositoryModelOrDirExist(db.DefaultContext, repo.Owner, newRepoName) + has, err := IsRepositoryModelOrDirExist(ctx, repo.Owner, newRepoName) if err != nil { return fmt.Errorf("IsRepositoryExist: %w", err) } else if has { @@ -171,7 +171,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s } } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/repo/upload.go b/models/repo/upload.go index 3b1b97c6d61..d96ab21bcde 100644 --- a/models/repo/upload.go +++ b/models/repo/upload.go @@ -5,6 +5,7 @@ package repo import ( + "context" "fmt" "io" "mime/multipart" @@ -61,7 +62,7 @@ func (upload *Upload) LocalPath() string { } // NewUpload creates a new upload object. -func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err error) { +func NewUpload(ctx context.Context, name string, buf []byte, file multipart.File) (_ *Upload, err error) { upload := &Upload{ UUID: gouuid.New().String(), Name: name, @@ -84,7 +85,7 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err return nil, fmt.Errorf("Copy: %w", err) } - if _, err := db.GetEngine(db.DefaultContext).Insert(upload); err != nil { + if _, err := db.GetEngine(ctx).Insert(upload); err != nil { return nil, err } @@ -92,9 +93,9 @@ func NewUpload(name string, buf []byte, file multipart.File) (_ *Upload, err err } // GetUploadByUUID returns the Upload by UUID -func GetUploadByUUID(uuid string) (*Upload, error) { +func GetUploadByUUID(ctx context.Context, uuid string) (*Upload, error) { upload := &Upload{} - has, err := db.GetEngine(db.DefaultContext).Where("uuid=?", uuid).Get(upload) + has, err := db.GetEngine(ctx).Where("uuid=?", uuid).Get(upload) if err != nil { return nil, err } else if !has { @@ -104,23 +105,23 @@ func GetUploadByUUID(uuid string) (*Upload, error) { } // GetUploadsByUUIDs returns multiple uploads by UUIDS -func GetUploadsByUUIDs(uuids []string) ([]*Upload, error) { +func GetUploadsByUUIDs(ctx context.Context, uuids []string) ([]*Upload, error) { if len(uuids) == 0 { return []*Upload{}, nil } // Silently drop invalid uuids. uploads := make([]*Upload, 0, len(uuids)) - return uploads, db.GetEngine(db.DefaultContext).In("uuid", uuids).Find(&uploads) + return uploads, db.GetEngine(ctx).In("uuid", uuids).Find(&uploads) } // DeleteUploads deletes multiple uploads -func DeleteUploads(uploads ...*Upload) (err error) { +func DeleteUploads(ctx context.Context, uploads ...*Upload) (err error) { if len(uploads) == 0 { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -159,8 +160,8 @@ func DeleteUploads(uploads ...*Upload) (err error) { } // DeleteUploadByUUID deletes a upload by UUID -func DeleteUploadByUUID(uuid string) error { - upload, err := GetUploadByUUID(uuid) +func DeleteUploadByUUID(ctx context.Context, uuid string) error { + upload, err := GetUploadByUUID(ctx, uuid) if err != nil { if IsErrUploadNotExist(err) { return nil @@ -168,7 +169,7 @@ func DeleteUploadByUUID(uuid string) error { return fmt.Errorf("GetUploadByUUID: %w", err) } - if err := DeleteUploads(upload); err != nil { + if err := DeleteUploads(ctx, upload); err != nil { return fmt.Errorf("DeleteUpload: %w", err) } diff --git a/models/repo/watch.go b/models/repo/watch.go index 00f313ca7cc..02a94ecac05 100644 --- a/models/repo/watch.go +++ b/models/repo/watch.go @@ -59,8 +59,8 @@ func IsWatchMode(mode WatchMode) bool { } // IsWatching checks if user has watched given repository. -func IsWatching(userID, repoID int64) bool { - watch, err := GetWatch(db.DefaultContext, userID, repoID) +func IsWatching(ctx context.Context, userID, repoID int64) bool { + watch, err := GetWatch(ctx, userID, repoID) return err == nil && IsWatchMode(watch.Mode) } @@ -155,8 +155,8 @@ func GetRepoWatchersIDs(ctx context.Context, repoID int64) ([]int64, error) { } // GetRepoWatchers returns range of users watching given repository. -func GetRepoWatchers(repoID int64, opts db.ListOptions) ([]*user_model.User, error) { - sess := db.GetEngine(db.DefaultContext).Where("watch.repo_id=?", repoID). +func GetRepoWatchers(ctx context.Context, repoID int64, opts db.ListOptions) ([]*user_model.User, error) { + sess := db.GetEngine(ctx).Where("watch.repo_id=?", repoID). Join("LEFT", "watch", "`user`.id=`watch`.user_id"). And("`watch`.mode<>?", WatchModeDont) if opts.Page > 0 { diff --git a/models/repo/watch_test.go b/models/repo/watch_test.go index 8b8c6d6250c..1384d1e1572 100644 --- a/models/repo/watch_test.go +++ b/models/repo/watch_test.go @@ -17,13 +17,13 @@ import ( func TestIsWatching(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.True(t, repo_model.IsWatching(1, 1)) - assert.True(t, repo_model.IsWatching(4, 1)) - assert.True(t, repo_model.IsWatching(11, 1)) + assert.True(t, repo_model.IsWatching(db.DefaultContext, 1, 1)) + assert.True(t, repo_model.IsWatching(db.DefaultContext, 4, 1)) + assert.True(t, repo_model.IsWatching(db.DefaultContext, 11, 1)) - assert.False(t, repo_model.IsWatching(1, 5)) - assert.False(t, repo_model.IsWatching(8, 1)) - assert.False(t, repo_model.IsWatching(unittest.NonexistentID, unittest.NonexistentID)) + assert.False(t, repo_model.IsWatching(db.DefaultContext, 1, 5)) + assert.False(t, repo_model.IsWatching(db.DefaultContext, 8, 1)) + assert.False(t, repo_model.IsWatching(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)) } func TestGetWatchers(t *testing.T) { @@ -47,7 +47,7 @@ func TestRepository_GetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err := repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) for _, watcher := range watchers { @@ -55,7 +55,7 @@ func TestRepository_GetWatchers(t *testing.T) { } repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, 0) } @@ -64,7 +64,7 @@ func TestWatchIfAuto(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err := repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) @@ -74,13 +74,13 @@ func TestWatchIfAuto(t *testing.T) { // Must not add watch assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 8, 1, true)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 10, 1, true)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) @@ -88,31 +88,31 @@ func TestWatchIfAuto(t *testing.T) { // Must not add watch assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 8, 1, true)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, false)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should add watch assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, true)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount+1) // Should remove watch, inhibit from adding auto assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, 12, 1, false)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Must not add watch assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, true)) - watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + watchers, err = repo_model.GetRepoWatchers(db.DefaultContext, repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) } diff --git a/models/repo_transfer.go b/models/repo_transfer.go index 1c873cec576..630c243c8e9 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -79,8 +79,8 @@ func (r *RepoTransfer) LoadAttributes(ctx context.Context) error { // CanUserAcceptTransfer checks if the user has the rights to accept/decline a repo transfer. // For user, it checks if it's himself // For organizations, it checks if the user is able to create repos -func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { - if err := r.LoadAttributes(db.DefaultContext); err != nil { +func (r *RepoTransfer) CanUserAcceptTransfer(ctx context.Context, u *user_model.User) bool { + if err := r.LoadAttributes(ctx); err != nil { log.Error("LoadAttributes: %v", err) return false } @@ -89,7 +89,7 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { return r.RecipientID == u.ID } - allowed, err := organization.CanCreateOrgRepo(db.DefaultContext, r.RecipientID, u.ID) + allowed, err := organization.CanCreateOrgRepo(ctx, r.RecipientID, u.ID) if err != nil { log.Error("CanCreateOrgRepo: %v", err) return false @@ -122,8 +122,8 @@ func deleteRepositoryTransfer(ctx context.Context, repoID int64) error { // CancelRepositoryTransfer marks the repository as ready and remove pending transfer entry, // thus cancel the transfer process. -func CancelRepositoryTransfer(repo *repo_model.Repository) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func CancelRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -199,7 +199,7 @@ func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_m } // TransferOwnership transfers all corresponding repository items from old user to new one. -func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_model.Repository) (err error) { +func TransferOwnership(ctx context.Context, doer *user_model.User, newOwnerName string, repo *repo_model.Repository) (err error) { repoRenamed := false wikiRenamed := false oldOwnerName := doer.Name @@ -234,7 +234,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo } }() - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go index 7364d4d02cd..b55cef94738 100644 --- a/models/repo_transfer_test.go +++ b/models/repo_transfer_test.go @@ -25,7 +25,7 @@ func TestRepositoryTransfer(t *testing.T) { assert.NotNil(t, transfer) // Cancel transfer - assert.NoError(t, CancelRepositoryTransfer(repo)) + assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo)) transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.Error(t, err) @@ -53,5 +53,5 @@ func TestRepositoryTransfer(t *testing.T) { assert.Error(t, err) // Cancel transfer - assert.NoError(t, CancelRepositoryTransfer(repo)) + assert.NoError(t, CancelRepositoryTransfer(db.DefaultContext, repo)) } diff --git a/models/system/main_test.go b/models/system/main_test.go index e074abc1551..6bc27a7cff8 100644 --- a/models/system/main_test.go +++ b/models/system/main_test.go @@ -4,7 +4,6 @@ package system_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -16,7 +15,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/system/notice.go b/models/system/notice.go index 784ad74375b..058b78e6771 100644 --- a/models/system/notice.go +++ b/models/system/notice.go @@ -88,34 +88,34 @@ func RemoveStorageWithNotice(ctx context.Context, bucket storage.ObjectStorage, } // CountNotices returns number of notices. -func CountNotices() int64 { - count, _ := db.GetEngine(db.DefaultContext).Count(new(Notice)) +func CountNotices(ctx context.Context) int64 { + count, _ := db.GetEngine(ctx).Count(new(Notice)) return count } // Notices returns notices in given page. -func Notices(page, pageSize int) ([]*Notice, error) { +func Notices(ctx context.Context, page, pageSize int) ([]*Notice, error) { notices := make([]*Notice, 0, pageSize) - return notices, db.GetEngine(db.DefaultContext). + return notices, db.GetEngine(ctx). Limit(pageSize, (page-1)*pageSize). Desc("created_unix"). Find(¬ices) } // DeleteNotice deletes a system notice by given ID. -func DeleteNotice(id int64) error { - _, err := db.GetEngine(db.DefaultContext).ID(id).Delete(new(Notice)) +func DeleteNotice(ctx context.Context, id int64) error { + _, err := db.GetEngine(ctx).ID(id).Delete(new(Notice)) return err } // DeleteNotices deletes all notices with ID from start to end (inclusive). -func DeleteNotices(start, end int64) error { +func DeleteNotices(ctx context.Context, start, end int64) error { if start == 0 && end == 0 { - _, err := db.GetEngine(db.DefaultContext).Exec("DELETE FROM notice") + _, err := db.GetEngine(ctx).Exec("DELETE FROM notice") return err } - sess := db.GetEngine(db.DefaultContext).Where("id >= ?", start) + sess := db.GetEngine(ctx).Where("id >= ?", start) if end > 0 { sess.And("id <= ?", end) } @@ -124,22 +124,22 @@ func DeleteNotices(start, end int64) error { } // DeleteNoticesByIDs deletes notices by given IDs. -func DeleteNoticesByIDs(ids []int64) error { +func DeleteNoticesByIDs(ctx context.Context, ids []int64) error { if len(ids) == 0 { return nil } - _, err := db.GetEngine(db.DefaultContext). + _, err := db.GetEngine(ctx). In("id", ids). Delete(new(Notice)) return err } // DeleteOldSystemNotices deletes all old system notices from database. -func DeleteOldSystemNotices(olderThan time.Duration) (err error) { +func DeleteOldSystemNotices(ctx context.Context, olderThan time.Duration) (err error) { if olderThan <= 0 { return nil } - _, err = db.GetEngine(db.DefaultContext).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Notice{}) + _, err = db.GetEngine(ctx).Where("created_unix < ?", time.Now().Add(-olderThan).Unix()).Delete(&Notice{}) return err } diff --git a/models/system/notice_test.go b/models/system/notice_test.go index 01eb9b57a51..e8ce05d3324 100644 --- a/models/system/notice_test.go +++ b/models/system/notice_test.go @@ -49,20 +49,20 @@ func TestCreateRepositoryNotice(t *testing.T) { func TestCountNotices(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.Equal(t, int64(3), system.CountNotices()) + assert.Equal(t, int64(3), system.CountNotices(db.DefaultContext)) } func TestNotices(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - notices, err := system.Notices(1, 2) + notices, err := system.Notices(db.DefaultContext, 1, 2) assert.NoError(t, err) if assert.Len(t, notices, 2) { assert.Equal(t, int64(3), notices[0].ID) assert.Equal(t, int64(2), notices[1].ID) } - notices, err = system.Notices(2, 2) + notices, err = system.Notices(db.DefaultContext, 2, 2) assert.NoError(t, err) if assert.Len(t, notices, 1) { assert.Equal(t, int64(1), notices[0].ID) @@ -73,7 +73,7 @@ func TestDeleteNotice(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) - assert.NoError(t, system.DeleteNotice(3)) + assert.NoError(t, system.DeleteNotice(db.DefaultContext, 3)) unittest.AssertNotExistsBean(t, &system.Notice{ID: 3}) } @@ -84,7 +84,7 @@ func TestDeleteNotices(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) - assert.NoError(t, system.DeleteNotices(1, 2)) + assert.NoError(t, system.DeleteNotices(db.DefaultContext, 1, 2)) unittest.AssertNotExistsBean(t, &system.Notice{ID: 1}) unittest.AssertNotExistsBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) @@ -97,7 +97,7 @@ func TestDeleteNotices2(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) - assert.NoError(t, system.DeleteNotices(3, 2)) + assert.NoError(t, system.DeleteNotices(db.DefaultContext, 3, 2)) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) @@ -109,7 +109,7 @@ func TestDeleteNoticesByIDs(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 1}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 3}) - assert.NoError(t, system.DeleteNoticesByIDs([]int64{1, 3})) + assert.NoError(t, system.DeleteNoticesByIDs(db.DefaultContext, []int64{1, 3})) unittest.AssertNotExistsBean(t, &system.Notice{ID: 1}) unittest.AssertExistsAndLoadBean(t, &system.Notice{ID: 2}) unittest.AssertNotExistsBean(t, &system.Notice{ID: 3}) diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go index 1ff0fdc25bd..6db99cd393e 100644 --- a/models/unittest/testdb.go +++ b/models/unittest/testdb.go @@ -62,35 +62,46 @@ func InitSettings(extraConfigs ...string) { // TestOptions represents test options type TestOptions struct { - GiteaRootPath string - FixtureFiles []string - SetUp func() error // SetUp will be executed before all tests in this package - TearDown func() error // TearDown will be executed after all tests in this package + FixtureFiles []string + SetUp func() error // SetUp will be executed before all tests in this package + TearDown func() error // TearDown will be executed after all tests in this package } // MainTest a reusable TestMain(..) function for unit tests that need to use a // test database. Creates the test database, and sets necessary settings. -func MainTest(m *testing.M, testOpts *TestOptions) { - setting.CustomPath = filepath.Join(testOpts.GiteaRootPath, "custom") +func MainTest(m *testing.M, testOpts ...*TestOptions) { + searchDir, _ := os.Getwd() + for searchDir != "" { + if _, err := os.Stat(filepath.Join(searchDir, "go.mod")); err == nil { + break // The "go.mod" should be the one for Gitea repository + } + if dir := filepath.Dir(searchDir); dir == searchDir { + searchDir = "" // reaches the root of filesystem + } else { + searchDir = dir + } + } + if searchDir == "" { + panic("The tests should run in a Gitea repository, there should be a 'go.mod' in the root") + } + + giteaRoot = searchDir + setting.CustomPath = filepath.Join(giteaRoot, "custom") InitSettings() - var err error - - giteaRoot = testOpts.GiteaRootPath - fixturesDir = filepath.Join(testOpts.GiteaRootPath, "models", "fixtures") - + fixturesDir = filepath.Join(giteaRoot, "models", "fixtures") var opts FixturesOptions - if len(testOpts.FixtureFiles) == 0 { + if len(testOpts) == 0 || len(testOpts[0].FixtureFiles) == 0 { opts.Dir = fixturesDir } else { - for _, f := range testOpts.FixtureFiles { + for _, f := range testOpts[0].FixtureFiles { if len(f) != 0 { opts.Files = append(opts.Files, filepath.Join(fixturesDir, f)) } } } - if err = CreateTestEngine(opts); err != nil { + if err := CreateTestEngine(opts); err != nil { fatalTestError("Error creating test engine: %v\n", err) } @@ -112,8 +123,8 @@ func MainTest(m *testing.M, testOpts *TestOptions) { fatalTestError("TempDir: %v\n", err) } setting.AppDataPath = appDataPath - setting.AppWorkPath = testOpts.GiteaRootPath - setting.StaticRootPath = testOpts.GiteaRootPath + setting.AppWorkPath = giteaRoot + setting.StaticRootPath = giteaRoot setting.GravatarSource = "https://secure.gravatar.com/avatar/" setting.Attachment.Storage.Path = filepath.Join(setting.AppDataPath, "attachments") @@ -144,7 +155,7 @@ func MainTest(m *testing.M, testOpts *TestOptions) { if err = util.RemoveAll(repoRootPath); err != nil { fatalTestError("util.RemoveAll: %v\n", err) } - if err = CopyDir(filepath.Join(testOpts.GiteaRootPath, "tests", "gitea-repositories-meta"), setting.RepoRootPath); err != nil { + if err = CopyDir(filepath.Join(giteaRoot, "tests", "gitea-repositories-meta"), setting.RepoRootPath); err != nil { fatalTestError("util.CopyDir: %v\n", err) } @@ -171,16 +182,16 @@ func MainTest(m *testing.M, testOpts *TestOptions) { } } - if testOpts.SetUp != nil { - if err := testOpts.SetUp(); err != nil { + if len(testOpts) > 0 && testOpts[0].SetUp != nil { + if err := testOpts[0].SetUp(); err != nil { fatalTestError("set up failed: %v\n", err) } } exitStatus := m.Run() - if testOpts.TearDown != nil { - if err := testOpts.TearDown(); err != nil { + if len(testOpts) > 0 && testOpts[0].TearDown != nil { + if err := testOpts[0].TearDown(); err != nil { fatalTestError("tear down failed: %v\n", err) } } diff --git a/models/user/email_address.go b/models/user/email_address.go index e916249e30b..f1ed6692cfe 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -178,9 +178,9 @@ func ValidateEmail(email string) error { } // GetEmailAddresses returns all email addresses belongs to given user. -func GetEmailAddresses(uid int64) ([]*EmailAddress, error) { +func GetEmailAddresses(ctx context.Context, uid int64) ([]*EmailAddress, error) { emails := make([]*EmailAddress, 0, 5) - if err := db.GetEngine(db.DefaultContext). + if err := db.GetEngine(ctx). Where("uid=?", uid). Asc("id"). Find(&emails); err != nil { @@ -190,10 +190,10 @@ func GetEmailAddresses(uid int64) ([]*EmailAddress, error) { } // GetEmailAddressByID gets a user's email address by ID -func GetEmailAddressByID(uid, id int64) (*EmailAddress, error) { +func GetEmailAddressByID(ctx context.Context, uid, id int64) (*EmailAddress, error) { // User ID is required for security reasons email := &EmailAddress{UID: uid} - if has, err := db.GetEngine(db.DefaultContext).ID(id).Get(email); err != nil { + if has, err := db.GetEngine(ctx).ID(id).Get(email); err != nil { return nil, err } else if !has { return nil, nil @@ -253,7 +253,7 @@ func AddEmailAddress(ctx context.Context, email *EmailAddress) error { } // AddEmailAddresses adds an email address to given user. -func AddEmailAddresses(emails []*EmailAddress) error { +func AddEmailAddresses(ctx context.Context, emails []*EmailAddress) error { if len(emails) == 0 { return nil } @@ -261,7 +261,7 @@ func AddEmailAddresses(emails []*EmailAddress) error { // Check if any of them has been used for i := range emails { emails[i].Email = strings.TrimSpace(emails[i].Email) - used, err := IsEmailUsed(db.DefaultContext, emails[i].Email) + used, err := IsEmailUsed(ctx, emails[i].Email) if err != nil { return err } else if used { @@ -272,7 +272,7 @@ func AddEmailAddresses(emails []*EmailAddress) error { } } - if err := db.Insert(db.DefaultContext, emails); err != nil { + if err := db.Insert(ctx, emails); err != nil { return fmt.Errorf("Insert: %w", err) } @@ -280,7 +280,7 @@ func AddEmailAddresses(emails []*EmailAddress) error { } // DeleteEmailAddress deletes an email address of given user. -func DeleteEmailAddress(email *EmailAddress) (err error) { +func DeleteEmailAddress(ctx context.Context, email *EmailAddress) (err error) { if email.IsPrimary { return ErrPrimaryEmailCannotDelete{Email: email.Email} } @@ -291,12 +291,12 @@ func DeleteEmailAddress(email *EmailAddress) (err error) { UID: email.UID, } if email.ID > 0 { - deleted, err = db.GetEngine(db.DefaultContext).ID(email.ID).Delete(&address) + deleted, err = db.GetEngine(ctx).ID(email.ID).Delete(&address) } else { if email.Email != "" && email.LowerEmail == "" { email.LowerEmail = strings.ToLower(email.Email) } - deleted, err = db.GetEngine(db.DefaultContext). + deleted, err = db.GetEngine(ctx). Where("lower_email=?", email.LowerEmail). Delete(&address) } @@ -310,9 +310,9 @@ func DeleteEmailAddress(email *EmailAddress) (err error) { } // DeleteEmailAddresses deletes multiple email addresses -func DeleteEmailAddresses(emails []*EmailAddress) (err error) { +func DeleteEmailAddresses(ctx context.Context, emails []*EmailAddress) (err error) { for i := range emails { - if err = DeleteEmailAddress(emails[i]); err != nil { + if err = DeleteEmailAddress(ctx, emails[i]); err != nil { return err } } @@ -329,8 +329,8 @@ func DeleteInactiveEmailAddresses(ctx context.Context) error { } // ActivateEmail activates the email address to given user. -func ActivateEmail(email *EmailAddress) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ActivateEmail(ctx context.Context, email *EmailAddress) error { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -357,8 +357,8 @@ func updateActivation(ctx context.Context, email *EmailAddress, activate bool) e } // MakeEmailPrimary sets primary email address of given user. -func MakeEmailPrimary(email *EmailAddress) error { - has, err := db.GetEngine(db.DefaultContext).Get(email) +func MakeEmailPrimary(ctx context.Context, email *EmailAddress) error { + has, err := db.GetEngine(ctx).Get(email) if err != nil { return err } else if !has { @@ -370,7 +370,7 @@ func MakeEmailPrimary(email *EmailAddress) error { } user := &User{} - has, err = db.GetEngine(db.DefaultContext).ID(email.UID).Get(user) + has, err = db.GetEngine(ctx).ID(email.UID).Get(user) if err != nil { return err } else if !has { @@ -381,7 +381,7 @@ func MakeEmailPrimary(email *EmailAddress) error { } } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -411,17 +411,17 @@ func MakeEmailPrimary(email *EmailAddress) error { } // VerifyActiveEmailCode verifies active email code when active account -func VerifyActiveEmailCode(code, email string) *EmailAddress { +func VerifyActiveEmailCode(ctx context.Context, code, email string) *EmailAddress { minutes := setting.Service.ActiveCodeLives - if user := GetVerifyUser(code); user != nil { + if user := GetVerifyUser(ctx, code); user != nil { // time limit code prefix := code[:base.TimeLimitCodeLength] data := fmt.Sprintf("%d%s%s%s%s", user.ID, email, user.LowerName, user.Passwd, user.Rands) if base.VerifyTimeLimitCode(data, minutes, prefix) { emailAddress := &EmailAddress{UID: user.ID, Email: email} - if has, _ := db.GetEngine(db.DefaultContext).Get(emailAddress); has { + if has, _ := db.GetEngine(ctx).Get(emailAddress); has { return emailAddress } } @@ -466,7 +466,7 @@ type SearchEmailResult struct { // SearchEmails takes options i.e. keyword and part of email name to search, // it returns results in given range and number of total results. -func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) { +func SearchEmails(ctx context.Context, opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) { var cond builder.Cond = builder.Eq{"`user`.`type`": UserTypeIndividual} if len(opts.Keyword) > 0 { likeStr := "%" + strings.ToLower(opts.Keyword) + "%" @@ -491,7 +491,7 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) cond = cond.And(builder.Eq{"email_address.is_activated": false}) } - count, err := db.GetEngine(db.DefaultContext).Join("INNER", "`user`", "`user`.ID = email_address.uid"). + count, err := db.GetEngine(ctx).Join("INNER", "`user`", "`user`.ID = email_address.uid"). Where(cond).Count(new(EmailAddress)) if err != nil { return nil, 0, fmt.Errorf("Count: %w", err) @@ -505,7 +505,7 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) opts.SetDefaultValues() emails := make([]*SearchEmailResult, 0, opts.PageSize) - err = db.GetEngine(db.DefaultContext).Table("email_address"). + err = db.GetEngine(ctx).Table("email_address"). Select("email_address.*, `user`.name, `user`.full_name"). Join("INNER", "`user`", "`user`.ID = email_address.uid"). Where(cond). @@ -518,8 +518,8 @@ func SearchEmails(opts *SearchEmailOptions) ([]*SearchEmailResult, int64, error) // ActivateUserEmail will change the activated state of an email address, // either primary or secondary (all in the email_address table) -func ActivateUserEmail(userID int64, email string, activate bool) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func ActivateUserEmail(ctx context.Context, userID int64, email string, activate bool) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index f2b383fe4b2..7f3ca75cfdc 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -17,14 +17,14 @@ import ( func TestGetEmailAddresses(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - emails, _ := user_model.GetEmailAddresses(int64(1)) + emails, _ := user_model.GetEmailAddresses(db.DefaultContext, int64(1)) if assert.Len(t, emails, 3) { assert.True(t, emails[0].IsPrimary) assert.True(t, emails[2].IsActivated) assert.False(t, emails[2].IsPrimary) } - emails, _ = user_model.GetEmailAddresses(int64(2)) + emails, _ = user_model.GetEmailAddresses(db.DefaultContext, int64(2)) if assert.Len(t, emails, 2) { assert.True(t, emails[0].IsPrimary) assert.True(t, emails[0].IsActivated) @@ -76,10 +76,10 @@ func TestAddEmailAddresses(t *testing.T) { LowerEmail: "user5678@example.com", IsActivated: true, } - assert.NoError(t, user_model.AddEmailAddresses(emails)) + assert.NoError(t, user_model.AddEmailAddresses(db.DefaultContext, emails)) // ErrEmailAlreadyUsed - err := user_model.AddEmailAddresses(emails) + err := user_model.AddEmailAddresses(db.DefaultContext, emails) assert.Error(t, err) assert.True(t, user_model.IsErrEmailAlreadyUsed(err)) } @@ -87,21 +87,21 @@ func TestAddEmailAddresses(t *testing.T) { func TestDeleteEmailAddress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.NoError(t, user_model.DeleteEmailAddress(&user_model.EmailAddress{ + assert.NoError(t, user_model.DeleteEmailAddress(db.DefaultContext, &user_model.EmailAddress{ UID: int64(1), ID: int64(33), Email: "user1-2@example.com", LowerEmail: "user1-2@example.com", })) - assert.NoError(t, user_model.DeleteEmailAddress(&user_model.EmailAddress{ + assert.NoError(t, user_model.DeleteEmailAddress(db.DefaultContext, &user_model.EmailAddress{ UID: int64(1), Email: "user1-3@example.com", LowerEmail: "user1-3@example.com", })) // Email address does not exist - err := user_model.DeleteEmailAddress(&user_model.EmailAddress{ + err := user_model.DeleteEmailAddress(db.DefaultContext, &user_model.EmailAddress{ UID: int64(1), Email: "user1234567890@example.com", LowerEmail: "user1234567890@example.com", @@ -125,10 +125,10 @@ func TestDeleteEmailAddresses(t *testing.T) { Email: "user2-2@example.com", LowerEmail: "user2-2@example.com", } - assert.NoError(t, user_model.DeleteEmailAddresses(emails)) + assert.NoError(t, user_model.DeleteEmailAddresses(db.DefaultContext, emails)) // ErrEmailAlreadyUsed - err := user_model.DeleteEmailAddresses(emails) + err := user_model.DeleteEmailAddresses(db.DefaultContext, emails) assert.Error(t, err) } @@ -138,28 +138,28 @@ func TestMakeEmailPrimary(t *testing.T) { email := &user_model.EmailAddress{ Email: "user567890@example.com", } - err := user_model.MakeEmailPrimary(email) + err := user_model.MakeEmailPrimary(db.DefaultContext, email) assert.Error(t, err) assert.EqualError(t, err, user_model.ErrEmailAddressNotExist{Email: email.Email}.Error()) email = &user_model.EmailAddress{ Email: "user11@example.com", } - err = user_model.MakeEmailPrimary(email) + err = user_model.MakeEmailPrimary(db.DefaultContext, email) assert.Error(t, err) assert.EqualError(t, err, user_model.ErrEmailNotActivated.Error()) email = &user_model.EmailAddress{ Email: "user9999999@example.com", } - err = user_model.MakeEmailPrimary(email) + err = user_model.MakeEmailPrimary(db.DefaultContext, email) assert.Error(t, err) assert.True(t, user_model.IsErrUserNotExist(err)) email = &user_model.EmailAddress{ Email: "user101@example.com", } - err = user_model.MakeEmailPrimary(email) + err = user_model.MakeEmailPrimary(db.DefaultContext, email) assert.NoError(t, err) user, _ := user_model.GetUserByID(db.DefaultContext, int64(10)) @@ -174,9 +174,9 @@ func TestActivate(t *testing.T) { UID: int64(1), Email: "user11@example.com", } - assert.NoError(t, user_model.ActivateEmail(email)) + assert.NoError(t, user_model.ActivateEmail(db.DefaultContext, email)) - emails, _ := user_model.GetEmailAddresses(int64(1)) + emails, _ := user_model.GetEmailAddresses(db.DefaultContext, int64(1)) assert.Len(t, emails, 3) assert.True(t, emails[0].IsActivated) assert.True(t, emails[0].IsPrimary) @@ -194,7 +194,7 @@ func TestListEmails(t *testing.T) { PageSize: 10000, }, } - emails, count, err := user_model.SearchEmails(opts) + emails, count, err := user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.NotEqual(t, int64(0), count) assert.True(t, count > 5) @@ -214,13 +214,13 @@ func TestListEmails(t *testing.T) { // Must find no records opts = &user_model.SearchEmailOptions{Keyword: "NOTFOUND"} - emails, count, err = user_model.SearchEmails(opts) + emails, count, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.Equal(t, int64(0), count) // Must find users 'user2', 'user28', etc. opts = &user_model.SearchEmailOptions{Keyword: "user2"} - emails, count, err = user_model.SearchEmails(opts) + emails, count, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.NotEqual(t, int64(0), count) assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.UID == 2 })) @@ -228,14 +228,14 @@ func TestListEmails(t *testing.T) { // Must find only primary addresses (i.e. from the `user` table) opts = &user_model.SearchEmailOptions{IsPrimary: util.OptionalBoolTrue} - emails, _, err = user_model.SearchEmails(opts) + emails, _, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return s.IsPrimary })) assert.False(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsPrimary })) // Must find only inactive addresses (i.e. not validated) opts = &user_model.SearchEmailOptions{IsActivated: util.OptionalBoolFalse} - emails, _, err = user_model.SearchEmails(opts) + emails, _, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.True(t, contains(func(s *user_model.SearchEmailResult) bool { return !s.IsActivated })) assert.False(t, contains(func(s *user_model.SearchEmailResult) bool { return s.IsActivated })) @@ -247,7 +247,7 @@ func TestListEmails(t *testing.T) { Page: 1, }, } - emails, count, err = user_model.SearchEmails(opts) + emails, count, err = user_model.SearchEmails(db.DefaultContext, opts) assert.NoError(t, err) assert.Len(t, emails, 5) assert.Greater(t, count, int64(len(emails))) diff --git a/models/user/follow.go b/models/user/follow.go index 7efecc26a78..f4dd2891ff4 100644 --- a/models/user/follow.go +++ b/models/user/follow.go @@ -4,6 +4,8 @@ package user import ( + "context" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" ) @@ -21,18 +23,18 @@ func init() { } // IsFollowing returns true if user is following followID. -func IsFollowing(userID, followID int64) bool { - has, _ := db.GetEngine(db.DefaultContext).Get(&Follow{UserID: userID, FollowID: followID}) +func IsFollowing(ctx context.Context, userID, followID int64) bool { + has, _ := db.GetEngine(ctx).Get(&Follow{UserID: userID, FollowID: followID}) return has } // FollowUser marks someone be another's follower. -func FollowUser(userID, followID int64) (err error) { - if userID == followID || IsFollowing(userID, followID) { +func FollowUser(ctx context.Context, userID, followID int64) (err error) { + if userID == followID || IsFollowing(ctx, userID, followID) { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -53,12 +55,12 @@ func FollowUser(userID, followID int64) (err error) { } // UnfollowUser unmarks someone as another's follower. -func UnfollowUser(userID, followID int64) (err error) { - if userID == followID || !IsFollowing(userID, followID) { +func UnfollowUser(ctx context.Context, userID, followID int64) (err error) { + if userID == followID || !IsFollowing(ctx, userID, followID) { return nil } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/models/user/follow_test.go b/models/user/follow_test.go index fc408d5257c..c327d935aee 100644 --- a/models/user/follow_test.go +++ b/models/user/follow_test.go @@ -6,6 +6,7 @@ package user_test import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -14,9 +15,9 @@ import ( func TestIsFollowing(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.True(t, user_model.IsFollowing(4, 2)) - assert.False(t, user_model.IsFollowing(2, 4)) - assert.False(t, user_model.IsFollowing(5, unittest.NonexistentID)) - assert.False(t, user_model.IsFollowing(unittest.NonexistentID, 5)) - assert.False(t, user_model.IsFollowing(unittest.NonexistentID, unittest.NonexistentID)) + assert.True(t, user_model.IsFollowing(db.DefaultContext, 4, 2)) + assert.False(t, user_model.IsFollowing(db.DefaultContext, 2, 4)) + assert.False(t, user_model.IsFollowing(db.DefaultContext, 5, unittest.NonexistentID)) + assert.False(t, user_model.IsFollowing(db.DefaultContext, unittest.NonexistentID, 5)) + assert.False(t, user_model.IsFollowing(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)) } diff --git a/models/user/list.go b/models/user/list.go index 6b3b7bea9ad..ca589d1e020 100644 --- a/models/user/list.go +++ b/models/user/list.go @@ -25,19 +25,19 @@ func (users UserList) GetUserIDs() []int64 { } // GetTwoFaStatus return state of 2FA enrollement -func (users UserList) GetTwoFaStatus() map[int64]bool { +func (users UserList) GetTwoFaStatus(ctx context.Context) map[int64]bool { results := make(map[int64]bool, len(users)) for _, user := range users { results[user.ID] = false // Set default to false } - if tokenMaps, err := users.loadTwoFactorStatus(db.DefaultContext); err == nil { + if tokenMaps, err := users.loadTwoFactorStatus(ctx); err == nil { for _, token := range tokenMaps { results[token.UID] = true } } - if ids, err := users.userIDsWithWebAuthn(db.DefaultContext); err == nil { + if ids, err := users.userIDsWithWebAuthn(ctx); err == nil { for _, id := range ids { results[id] = true } @@ -71,12 +71,12 @@ func (users UserList) userIDsWithWebAuthn(ctx context.Context) ([]int64, error) } // GetUsersByIDs returns all resolved users from a list of Ids. -func GetUsersByIDs(ids []int64) (UserList, error) { +func GetUsersByIDs(ctx context.Context, ids []int64) (UserList, error) { ous := make([]*User, 0, len(ids)) if len(ids) == 0 { return ous, nil } - err := db.GetEngine(db.DefaultContext).In("id", ids). + err := db.GetEngine(ctx).In("id", ids). Asc("name"). Find(&ous) return ous, err diff --git a/models/user/main_test.go b/models/user/main_test.go index 8833cc73862..a626d323a71 100644 --- a/models/user/main_test.go +++ b/models/user/main_test.go @@ -4,7 +4,6 @@ package user_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -16,7 +15,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/models/user/openid.go b/models/user/openid.go index 596ff182bc7..ee4ecabae0b 100644 --- a/models/user/openid.go +++ b/models/user/openid.go @@ -28,9 +28,9 @@ func init() { } // GetUserOpenIDs returns all openid addresses that belongs to given user. -func GetUserOpenIDs(uid int64) ([]*UserOpenID, error) { +func GetUserOpenIDs(ctx context.Context, uid int64) ([]*UserOpenID, error) { openids := make([]*UserOpenID, 0, 5) - if err := db.GetEngine(db.DefaultContext). + if err := db.GetEngine(ctx). Where("uid=?", uid). Asc("id"). Find(&openids); err != nil { @@ -82,16 +82,16 @@ func AddUserOpenID(ctx context.Context, openid *UserOpenID) error { } // DeleteUserOpenID deletes an openid address of given user. -func DeleteUserOpenID(openid *UserOpenID) (err error) { +func DeleteUserOpenID(ctx context.Context, openid *UserOpenID) (err error) { var deleted int64 // ask to check UID address := UserOpenID{ UID: openid.UID, } if openid.ID > 0 { - deleted, err = db.GetEngine(db.DefaultContext).ID(openid.ID).Delete(&address) + deleted, err = db.GetEngine(ctx).ID(openid.ID).Delete(&address) } else { - deleted, err = db.GetEngine(db.DefaultContext). + deleted, err = db.GetEngine(ctx). Where("openid=?", openid.URI). Delete(&address) } @@ -105,7 +105,7 @@ func DeleteUserOpenID(openid *UserOpenID) (err error) { } // ToggleUserOpenIDVisibility toggles visibility of an openid address of given user. -func ToggleUserOpenIDVisibility(id int64) (err error) { - _, err = db.GetEngine(db.DefaultContext).Exec("update `user_open_id` set `show` = not `show` where `id` = ?", id) +func ToggleUserOpenIDVisibility(ctx context.Context, id int64) (err error) { + _, err = db.GetEngine(ctx).Exec("update `user_open_id` set `show` = not `show` where `id` = ?", id) return err } diff --git a/models/user/openid_test.go b/models/user/openid_test.go index 6f0eae55e73..27e6edd1e00 100644 --- a/models/user/openid_test.go +++ b/models/user/openid_test.go @@ -6,6 +6,7 @@ package user_test import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -15,7 +16,7 @@ import ( func TestGetUserOpenIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - oids, err := user_model.GetUserOpenIDs(int64(1)) + oids, err := user_model.GetUserOpenIDs(db.DefaultContext, int64(1)) if assert.NoError(t, err) && assert.Len(t, oids, 2) { assert.Equal(t, "https://user1.domain1.tld/", oids[0].URI) assert.False(t, oids[0].Show) @@ -23,7 +24,7 @@ func TestGetUserOpenIDs(t *testing.T) { assert.True(t, oids[1].Show) } - oids, err = user_model.GetUserOpenIDs(int64(2)) + oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2)) if assert.NoError(t, err) && assert.Len(t, oids, 1) { assert.Equal(t, "https://domain1.tld/user2/", oids[0].URI) assert.True(t, oids[0].Show) @@ -32,28 +33,28 @@ func TestGetUserOpenIDs(t *testing.T) { func TestToggleUserOpenIDVisibility(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - oids, err := user_model.GetUserOpenIDs(int64(2)) + oids, err := user_model.GetUserOpenIDs(db.DefaultContext, int64(2)) if !assert.NoError(t, err) || !assert.Len(t, oids, 1) { return } assert.True(t, oids[0].Show) - err = user_model.ToggleUserOpenIDVisibility(oids[0].ID) + err = user_model.ToggleUserOpenIDVisibility(db.DefaultContext, oids[0].ID) if !assert.NoError(t, err) { return } - oids, err = user_model.GetUserOpenIDs(int64(2)) + oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2)) if !assert.NoError(t, err) || !assert.Len(t, oids, 1) { return } assert.False(t, oids[0].Show) - err = user_model.ToggleUserOpenIDVisibility(oids[0].ID) + err = user_model.ToggleUserOpenIDVisibility(db.DefaultContext, oids[0].ID) if !assert.NoError(t, err) { return } - oids, err = user_model.GetUserOpenIDs(int64(2)) + oids, err = user_model.GetUserOpenIDs(db.DefaultContext, int64(2)) if !assert.NoError(t, err) { return } diff --git a/models/user/redirect.go b/models/user/redirect.go index 42e991888a6..5a40d4df3ba 100644 --- a/models/user/redirect.go +++ b/models/user/redirect.go @@ -48,10 +48,10 @@ func init() { } // LookupUserRedirect look up userID if a user has a redirect name -func LookupUserRedirect(userName string) (int64, error) { +func LookupUserRedirect(ctx context.Context, userName string) (int64, error) { userName = strings.ToLower(userName) redirect := &Redirect{LowerName: userName} - if has, err := db.GetEngine(db.DefaultContext).Get(redirect); err != nil { + if has, err := db.GetEngine(ctx).Get(redirect); err != nil { return 0, err } else if !has { return 0, ErrUserRedirectNotExist{Name: userName} diff --git a/models/user/redirect_test.go b/models/user/redirect_test.go index 3d2ea3aeec7..484c5a663fb 100644 --- a/models/user/redirect_test.go +++ b/models/user/redirect_test.go @@ -6,6 +6,7 @@ package user_test import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -15,10 +16,10 @@ import ( func TestLookupUserRedirect(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - userID, err := user_model.LookupUserRedirect("olduser1") + userID, err := user_model.LookupUserRedirect(db.DefaultContext, "olduser1") assert.NoError(t, err) assert.EqualValues(t, 1, userID) - _, err = user_model.LookupUserRedirect("doesnotexist") + _, err = user_model.LookupUserRedirect(db.DefaultContext, "doesnotexist") assert.True(t, user_model.IsErrUserRedirectNotExist(err)) } diff --git a/models/user/search.go b/models/user/search.go index bf35fcd9eb6..0fa278c2572 100644 --- a/models/user/search.go +++ b/models/user/search.go @@ -4,6 +4,7 @@ package user import ( + "context" "fmt" "strings" @@ -34,12 +35,26 @@ type SearchUserOptions struct { IsRestricted util.OptionalBool IsTwoFactorEnabled util.OptionalBool IsProhibitLogin util.OptionalBool + IncludeReserved bool ExtraParamStrings map[string]string } -func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session { - var cond builder.Cond = builder.Eq{"type": opts.Type} +func (opts *SearchUserOptions) toSearchQueryBase(ctx context.Context) *xorm.Session { + var cond builder.Cond + cond = builder.Eq{"type": opts.Type} + if opts.IncludeReserved { + if opts.Type == UserTypeIndividual { + cond = cond.Or(builder.Eq{"type": UserTypeUserReserved}).Or( + builder.Eq{"type": UserTypeBot}, + ).Or( + builder.Eq{"type": UserTypeRemoteUser}, + ) + } else if opts.Type == UserTypeOrganization { + cond = cond.Or(builder.Eq{"type": UserTypeOrganizationReserved}) + } + } + if len(opts.Keyword) > 0 { lowerKeyword := strings.ToLower(opts.Keyword) keywordCond := builder.Or( @@ -87,7 +102,7 @@ func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session { cond = cond.And(builder.Eq{"prohibit_login": opts.IsProhibitLogin.IsTrue()}) } - e := db.GetEngine(db.DefaultContext) + e := db.GetEngine(ctx) if opts.IsTwoFactorEnabled.IsNone() { return e.Where(cond) } @@ -108,8 +123,8 @@ func (opts *SearchUserOptions) toSearchQueryBase() *xorm.Session { // SearchUsers takes options i.e. keyword and part of user name to search, // it returns results in given range and number of total results. -func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) { - sessCount := opts.toSearchQueryBase() +func SearchUsers(ctx context.Context, opts *SearchUserOptions) (users []*User, _ int64, _ error) { + sessCount := opts.toSearchQueryBase(ctx) defer sessCount.Close() count, err := sessCount.Count(new(User)) if err != nil { @@ -120,7 +135,7 @@ func SearchUsers(opts *SearchUserOptions) (users []*User, _ int64, _ error) { opts.OrderBy = db.SearchOrderByAlphabetically } - sessQuery := opts.toSearchQueryBase().OrderBy(opts.OrderBy.String()) + sessQuery := opts.toSearchQueryBase(ctx).OrderBy(opts.OrderBy.String()) defer sessQuery.Close() if opts.Page != 0 { sessQuery = db.SetSessionPagination(sessQuery, opts) diff --git a/models/user/setting.go b/models/user/setting.go index a41e494db9b..b4af0e5ccd6 100644 --- a/models/user/setting.go +++ b/models/user/setting.go @@ -59,9 +59,9 @@ func genSettingCacheKey(userID int64, key string) string { } // GetSetting returns the setting value via the key -func GetSetting(uid int64, key string) (string, error) { +func GetSetting(ctx context.Context, uid int64, key string) (string, error) { return cache.GetString(genSettingCacheKey(uid, key), func() (string, error) { - res, err := GetSettingNoCache(uid, key) + res, err := GetSettingNoCache(ctx, uid, key) if err != nil { return "", err } @@ -70,8 +70,8 @@ func GetSetting(uid int64, key string) (string, error) { } // GetSettingNoCache returns specific setting without using the cache -func GetSettingNoCache(uid int64, key string) (*Setting, error) { - v, err := GetSettings(uid, []string{key}) +func GetSettingNoCache(ctx context.Context, uid int64, key string) (*Setting, error) { + v, err := GetSettings(ctx, uid, []string{key}) if err != nil { return nil, err } @@ -82,9 +82,9 @@ func GetSettingNoCache(uid int64, key string) (*Setting, error) { } // GetSettings returns specific settings from user -func GetSettings(uid int64, keys []string) (map[string]*Setting, error) { +func GetSettings(ctx context.Context, uid int64, keys []string) (map[string]*Setting, error) { settings := make([]*Setting, 0, len(keys)) - if err := db.GetEngine(db.DefaultContext). + if err := db.GetEngine(ctx). Where("user_id=?", uid). And(builder.In("setting_key", keys)). Find(&settings); err != nil { @@ -98,9 +98,9 @@ func GetSettings(uid int64, keys []string) (map[string]*Setting, error) { } // GetUserAllSettings returns all settings from user -func GetUserAllSettings(uid int64) (map[string]*Setting, error) { +func GetUserAllSettings(ctx context.Context, uid int64) (map[string]*Setting, error) { settings := make([]*Setting, 0, 5) - if err := db.GetEngine(db.DefaultContext). + if err := db.GetEngine(ctx). Where("user_id=?", uid). Find(&settings); err != nil { return nil, err @@ -123,13 +123,13 @@ func validateUserSettingKey(key string) error { } // GetUserSetting gets a specific setting for a user -func GetUserSetting(userID int64, key string, def ...string) (string, error) { +func GetUserSetting(ctx context.Context, userID int64, key string, def ...string) (string, error) { if err := validateUserSettingKey(key); err != nil { return "", err } setting := &Setting{UserID: userID, SettingKey: key} - has, err := db.GetEngine(db.DefaultContext).Get(setting) + has, err := db.GetEngine(ctx).Get(setting) if err != nil { return "", err } @@ -143,24 +143,24 @@ func GetUserSetting(userID int64, key string, def ...string) (string, error) { } // DeleteUserSetting deletes a specific setting for a user -func DeleteUserSetting(userID int64, key string) error { +func DeleteUserSetting(ctx context.Context, userID int64, key string) error { if err := validateUserSettingKey(key); err != nil { return err } cache.Remove(genSettingCacheKey(userID, key)) - _, err := db.GetEngine(db.DefaultContext).Delete(&Setting{UserID: userID, SettingKey: key}) + _, err := db.GetEngine(ctx).Delete(&Setting{UserID: userID, SettingKey: key}) return err } // SetUserSetting updates a users' setting for a specific key -func SetUserSetting(userID int64, key, value string) error { +func SetUserSetting(ctx context.Context, userID int64, key, value string) error { if err := validateUserSettingKey(key); err != nil { return err } - if err := upsertUserSettingValue(userID, key, value); err != nil { + if err := upsertUserSettingValue(ctx, userID, key, value); err != nil { return err } @@ -172,8 +172,8 @@ func SetUserSetting(userID int64, key, value string) error { return nil } -func upsertUserSettingValue(userID int64, key, value string) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { +func upsertUserSettingValue(ctx context.Context, userID int64, key, value string) error { + return db.WithTx(ctx, func(ctx context.Context) error { e := db.GetEngine(ctx) // here we use a general method to do a safe upsert for different databases (and most transaction levels) diff --git a/models/user/setting_test.go b/models/user/setting_test.go index d0d612d25da..c56fe930750 100644 --- a/models/user/setting_test.go +++ b/models/user/setting_test.go @@ -6,6 +6,7 @@ package user_test import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -19,41 +20,41 @@ func TestSettings(t *testing.T) { newSetting := &user_model.Setting{UserID: 99, SettingKey: keyName, SettingValue: "Gitea User Setting Test"} // create setting - err := user_model.SetUserSetting(newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue) + err := user_model.SetUserSetting(db.DefaultContext, newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue) assert.NoError(t, err) // test about saving unchanged values - err = user_model.SetUserSetting(newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue) + err = user_model.SetUserSetting(db.DefaultContext, newSetting.UserID, newSetting.SettingKey, newSetting.SettingValue) assert.NoError(t, err) // get specific setting - settings, err := user_model.GetSettings(99, []string{keyName}) + settings, err := user_model.GetSettings(db.DefaultContext, 99, []string{keyName}) assert.NoError(t, err) assert.Len(t, settings, 1) assert.EqualValues(t, newSetting.SettingValue, settings[keyName].SettingValue) - settingValue, err := user_model.GetUserSetting(99, keyName) + settingValue, err := user_model.GetUserSetting(db.DefaultContext, 99, keyName) assert.NoError(t, err) assert.EqualValues(t, newSetting.SettingValue, settingValue) - settingValue, err = user_model.GetUserSetting(99, "no_such") + settingValue, err = user_model.GetUserSetting(db.DefaultContext, 99, "no_such") assert.NoError(t, err) assert.EqualValues(t, "", settingValue) // updated setting updatedSetting := &user_model.Setting{UserID: 99, SettingKey: keyName, SettingValue: "Updated"} - err = user_model.SetUserSetting(updatedSetting.UserID, updatedSetting.SettingKey, updatedSetting.SettingValue) + err = user_model.SetUserSetting(db.DefaultContext, updatedSetting.UserID, updatedSetting.SettingKey, updatedSetting.SettingValue) assert.NoError(t, err) // get all settings - settings, err = user_model.GetUserAllSettings(99) + settings, err = user_model.GetUserAllSettings(db.DefaultContext, 99) assert.NoError(t, err) assert.Len(t, settings, 1) assert.EqualValues(t, updatedSetting.SettingValue, settings[updatedSetting.SettingKey].SettingValue) // delete setting - err = user_model.DeleteUserSetting(99, keyName) + err = user_model.DeleteUserSetting(db.DefaultContext, 99, keyName) assert.NoError(t, err) - settings, err = user_model.GetUserAllSettings(99) + settings, err = user_model.GetUserAllSettings(db.DefaultContext, 99) assert.NoError(t, err) assert.Len(t, settings, 0) } diff --git a/models/user/user.go b/models/user/user.go index 86cf2ad2806..60aa6b9a6f5 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -42,7 +42,7 @@ const ( // UserTypeOrganization defines an organization UserTypeOrganization - // UserTypeReserved reserves a (non-existing) user, i.e. to prevent a spam user from re-registering after being deleted, or to reserve the name until the user is actually created later on + // UserTypeUserReserved reserves a (non-existing) user, i.e. to prevent a spam user from re-registering after being deleted, or to reserve the name until the user is actually created later on UserTypeUserReserved // UserTypeOrganizationReserved reserves a (non-existing) organization, to be used in combination with UserTypeUserReserved @@ -192,15 +192,15 @@ func (u *User) SetLastLogin() { } // UpdateUserDiffViewStyle updates the users diff view style -func UpdateUserDiffViewStyle(u *User, style string) error { +func UpdateUserDiffViewStyle(ctx context.Context, u *User, style string) error { u.DiffViewStyle = style - return UpdateUserCols(db.DefaultContext, u, "diff_view_style") + return UpdateUserCols(ctx, u, "diff_view_style") } // UpdateUserTheme updates a users' theme irrespective of the site wide theme -func UpdateUserTheme(u *User, themeName string) error { +func UpdateUserTheme(ctx context.Context, u *User, themeName string) error { u.Theme = themeName - return UpdateUserCols(db.DefaultContext, u, "theme") + return UpdateUserCols(ctx, u, "theme") } // GetPlaceholderEmail returns an noreply email @@ -218,9 +218,9 @@ func (u *User) GetEmail() string { } // GetAllUsers returns a slice of all individual users found in DB. -func GetAllUsers() ([]*User, error) { +func GetAllUsers(ctx context.Context) ([]*User, error) { users := make([]*User, 0) - return users, db.GetEngine(db.DefaultContext).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users) + return users, db.GetEngine(ctx).OrderBy("id").Where("type = ?", UserTypeIndividual).Find(&users) } // IsLocal returns true if user login type is LoginPlain. @@ -478,9 +478,9 @@ func (u *User) EmailNotifications() string { } // SetEmailNotifications sets the user's email notification preference -func SetEmailNotifications(u *User, set string) error { +func SetEmailNotifications(ctx context.Context, u *User, set string) error { u.EmailNotificationsPreference = set - if err := UpdateUserCols(db.DefaultContext, u, "email_notifications_preference"); err != nil { + if err := UpdateUserCols(ctx, u, "email_notifications_preference"); err != nil { log.Error("SetEmailNotifications: %v", err) return err } @@ -582,7 +582,7 @@ type CreateUserOverwriteOptions struct { } // CreateUser creates record of a new user. -func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) { +func CreateUser(ctx context.Context, u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err error) { if err = IsUsableUsername(u.Name); err != nil { return err } @@ -640,7 +640,7 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e return err } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -711,8 +711,8 @@ type CountUserFilter struct { } // CountUsers returns number of users. -func CountUsers(opts *CountUserFilter) int64 { - return countUsers(db.DefaultContext, opts) +func CountUsers(ctx context.Context, opts *CountUserFilter) int64 { + return countUsers(ctx, opts) } func countUsers(ctx context.Context, opts *CountUserFilter) int64 { @@ -727,7 +727,7 @@ func countUsers(ctx context.Context, opts *CountUserFilter) int64 { } // GetVerifyUser get user by verify code -func GetVerifyUser(code string) (user *User) { +func GetVerifyUser(ctx context.Context, code string) (user *User) { if len(code) <= base.TimeLimitCodeLength { return nil } @@ -735,7 +735,7 @@ func GetVerifyUser(code string) (user *User) { // use tail hex username query user hexStr := code[base.TimeLimitCodeLength:] if b, err := hex.DecodeString(hexStr); err == nil { - if user, err = GetUserByName(db.DefaultContext, string(b)); user != nil { + if user, err = GetUserByName(ctx, string(b)); user != nil { return user } log.Error("user.getVerifyUser: %v", err) @@ -745,10 +745,10 @@ func GetVerifyUser(code string) (user *User) { } // VerifyUserActiveCode verifies active code when active account -func VerifyUserActiveCode(code string) (user *User) { +func VerifyUserActiveCode(ctx context.Context, code string) (user *User) { minutes := setting.Service.ActiveCodeLives - if user = GetVerifyUser(code); user != nil { + if user = GetVerifyUser(ctx, code); user != nil { // time limit code prefix := code[:base.TimeLimitCodeLength] data := fmt.Sprintf("%d%s%s%s%s", user.ID, user.Email, user.LowerName, user.Passwd, user.Rands) @@ -872,8 +872,8 @@ func UpdateUserCols(ctx context.Context, u *User, cols ...string) error { } // UpdateUserSetting updates user's settings. -func UpdateUserSetting(u *User) (err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func UpdateUserSetting(ctx context.Context, u *User) (err error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } @@ -1021,9 +1021,9 @@ func GetMaileableUsersByIDs(ctx context.Context, ids []int64, isMention bool) ([ } // GetUserNamesByIDs returns usernames for all resolved users from a list of Ids. -func GetUserNamesByIDs(ids []int64) ([]string, error) { +func GetUserNamesByIDs(ctx context.Context, ids []int64) ([]string, error) { unames := make([]string, 0, len(ids)) - err := db.GetEngine(db.DefaultContext).In("id", ids). + err := db.GetEngine(ctx).In("id", ids). Table("user"). Asc("name"). Cols("name"). @@ -1062,9 +1062,9 @@ func GetUserIDsByNames(ctx context.Context, names []string, ignoreNonExistent bo } // GetUsersBySource returns a list of Users for a login source -func GetUsersBySource(s *auth.Source) ([]*User, error) { +func GetUsersBySource(ctx context.Context, s *auth.Source) ([]*User, error) { var users []*User - err := db.GetEngine(db.DefaultContext).Where("login_type = ? AND login_source = ?", s.Type, s.ID).Find(&users) + err := db.GetEngine(ctx).Where("login_type = ? AND login_source = ?", s.Type, s.ID).Find(&users) return users, err } @@ -1145,12 +1145,12 @@ func GetUserByEmail(ctx context.Context, email string) (*User, error) { } // GetUser checks if a user already exists -func GetUser(user *User) (bool, error) { - return db.GetEngine(db.DefaultContext).Get(user) +func GetUser(ctx context.Context, user *User) (bool, error) { + return db.GetEngine(ctx).Get(user) } // GetUserByOpenID returns the user object by given OpenID if exists. -func GetUserByOpenID(uri string) (*User, error) { +func GetUserByOpenID(ctx context.Context, uri string) (*User, error) { if len(uri) == 0 { return nil, ErrUserNotExist{0, uri, 0} } @@ -1164,12 +1164,12 @@ func GetUserByOpenID(uri string) (*User, error) { // Otherwise, check in openid table oid := &UserOpenID{} - has, err := db.GetEngine(db.DefaultContext).Where("uri=?", uri).Get(oid) + has, err := db.GetEngine(ctx).Where("uri=?", uri).Get(oid) if err != nil { return nil, err } if has { - return GetUserByID(db.DefaultContext, oid.UID) + return GetUserByID(ctx, oid.UID) } return nil, ErrUserNotExist{0, uri, 0} @@ -1246,7 +1246,7 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { } // If they follow - they see each over - follower := IsFollowing(u.ID, viewer.ID) + follower := IsFollowing(ctx, u.ID, viewer.ID) if follower { return true } @@ -1279,13 +1279,13 @@ func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { } // CountWrongUserType count OrgUser who have wrong type -func CountWrongUserType() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(User)) +func CountWrongUserType(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Count(new(User)) } // FixWrongUserType fix OrgUser who have wrong type -func FixWrongUserType() (int64, error) { - return db.GetEngine(db.DefaultContext).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&User{Type: 1}) +func FixWrongUserType(ctx context.Context) (int64, error) { + return db.GetEngine(ctx).Where(builder.Eq{"type": 0}.And(builder.Neq{"num_teams": 0})).Cols("type").NoAutoTime().Update(&User{Type: 1}) } func GetOrderByName() string { diff --git a/models/user/user_test.go b/models/user/user_test.go index 032dcba676e..971117482c2 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -63,7 +63,7 @@ func TestCanCreateOrganization(t *testing.T) { func TestSearchUsers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(opts *user_model.SearchUserOptions, expectedUserOrOrgIDs []int64) { - users, _, err := user_model.SearchUsers(opts) + users, _, err := user_model.SearchUsers(db.DefaultContext, opts) assert.NoError(t, err) cassText := fmt.Sprintf("ids: %v, opts: %v", expectedUserOrOrgIDs, opts) if assert.Len(t, users, len(expectedUserOrOrgIDs), "case: %s", cassText) { @@ -150,16 +150,16 @@ func TestEmailNotificationPreferences(t *testing.T) { assert.Equal(t, test.expected, user.EmailNotifications()) // Try all possible settings - assert.NoError(t, user_model.SetEmailNotifications(user, user_model.EmailNotificationsEnabled)) + assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsEnabled)) assert.Equal(t, user_model.EmailNotificationsEnabled, user.EmailNotifications()) - assert.NoError(t, user_model.SetEmailNotifications(user, user_model.EmailNotificationsOnMention)) + assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsOnMention)) assert.Equal(t, user_model.EmailNotificationsOnMention, user.EmailNotifications()) - assert.NoError(t, user_model.SetEmailNotifications(user, user_model.EmailNotificationsDisabled)) + assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsDisabled)) assert.Equal(t, user_model.EmailNotificationsDisabled, user.EmailNotifications()) - assert.NoError(t, user_model.SetEmailNotifications(user, user_model.EmailNotificationsAndYourOwn)) + assert.NoError(t, user_model.SetEmailNotifications(db.DefaultContext, user, user_model.EmailNotificationsAndYourOwn)) assert.Equal(t, user_model.EmailNotificationsAndYourOwn, user.EmailNotifications()) } } @@ -239,7 +239,7 @@ func TestCreateUserInvalidEmail(t *testing.T) { MustChangePassword: false, } - err := user_model.CreateUser(user) + err := user_model.CreateUser(db.DefaultContext, user) assert.Error(t, err) assert.True(t, user_model.IsErrEmailCharIsNotSupported(err)) } @@ -253,7 +253,7 @@ func TestCreateUserEmailAlreadyUsed(t *testing.T) { user.Name = "testuser" user.LowerName = strings.ToLower(user.Name) user.ID = 0 - err := user_model.CreateUser(user) + err := user_model.CreateUser(db.DefaultContext, user) assert.Error(t, err) assert.True(t, user_model.IsErrEmailAlreadyUsed(err)) } @@ -270,7 +270,7 @@ func TestCreateUserCustomTimestamps(t *testing.T) { user.ID = 0 user.Email = "unique@example.com" user.CreatedUnix = creationTimestamp - err := user_model.CreateUser(user) + err := user_model.CreateUser(db.DefaultContext, user) assert.NoError(t, err) fetched, err := user_model.GetUserByID(context.Background(), user.ID) @@ -295,7 +295,7 @@ func TestCreateUserWithoutCustomTimestamps(t *testing.T) { user.Email = "unique@example.com" user.CreatedUnix = 0 user.UpdatedUnix = 0 - err := user_model.CreateUser(user) + err := user_model.CreateUser(db.DefaultContext, user) assert.NoError(t, err) timestampEnd := time.Now().Unix() @@ -429,17 +429,17 @@ func TestNewUserRedirect3(t *testing.T) { func TestGetUserByOpenID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - _, err := user_model.GetUserByOpenID("https://unknown") + _, err := user_model.GetUserByOpenID(db.DefaultContext, "https://unknown") if assert.Error(t, err) { assert.True(t, user_model.IsErrUserNotExist(err)) } - user, err := user_model.GetUserByOpenID("https://user1.domain1.tld") + user, err := user_model.GetUserByOpenID(db.DefaultContext, "https://user1.domain1.tld") if assert.NoError(t, err) { assert.Equal(t, int64(1), user.ID) } - user, err = user_model.GetUserByOpenID("https://domain1.tld/user2/") + user, err = user_model.GetUserByOpenID(db.DefaultContext, "https://domain1.tld/user2/") if assert.NoError(t, err) { assert.Equal(t, int64(2), user.ID) } @@ -449,13 +449,13 @@ func TestFollowUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(followerID, followedID int64) { - assert.NoError(t, user_model.FollowUser(followerID, followedID)) + assert.NoError(t, user_model.FollowUser(db.DefaultContext, followerID, followedID)) unittest.AssertExistsAndLoadBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID}) } testSuccess(4, 2) testSuccess(5, 2) - assert.NoError(t, user_model.FollowUser(2, 2)) + assert.NoError(t, user_model.FollowUser(db.DefaultContext, 2, 2)) unittest.CheckConsistencyFor(t, &user_model.User{}) } @@ -464,7 +464,7 @@ func TestUnfollowUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(followerID, followedID int64) { - assert.NoError(t, user_model.UnfollowUser(followerID, followedID)) + assert.NoError(t, user_model.UnfollowUser(db.DefaultContext, followerID, followedID)) unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: followerID, FollowID: followedID}) } testSuccess(4, 2) diff --git a/models/webhook/main_test.go b/models/webhook/main_test.go index 8df569a3ccf..f19465d5053 100644 --- a/models/webhook/main_test.go +++ b/models/webhook/main_test.go @@ -4,7 +4,6 @@ package webhook import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -12,7 +11,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), FixtureFiles: []string{ "webhook.yml", "hook_task.yml", diff --git a/modules/activitypub/client.go b/modules/activitypub/client.go index fa1b57638f3..66b977c01fb 100644 --- a/modules/activitypub/client.go +++ b/modules/activitypub/client.go @@ -5,6 +5,7 @@ package activitypub import ( "bytes" + "context" "crypto/rsa" "crypto/x509" "encoding/pem" @@ -61,14 +62,14 @@ type Client struct { } // NewClient function -func NewClient(user *user_model.User, pubID string) (c *Client, err error) { +func NewClient(ctx context.Context, user *user_model.User, pubID string) (c *Client, err error) { if err = containsRequiredHTTPHeaders(http.MethodGet, setting.Federation.GetHeaders); err != nil { return nil, err } else if err = containsRequiredHTTPHeaders(http.MethodPost, setting.Federation.PostHeaders); err != nil { return nil, err } - priv, err := GetPrivateKey(user) + priv, err := GetPrivateKey(ctx, user) if err != nil { return nil, err } diff --git a/modules/activitypub/client_test.go b/modules/activitypub/client_test.go index 83000b96d5b..65ea8d4d5bf 100644 --- a/modules/activitypub/client_test.go +++ b/modules/activitypub/client_test.go @@ -11,6 +11,7 @@ import ( "regexp" "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" @@ -22,7 +23,7 @@ func TestActivityPubSignedPost(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) pubID := "https://example.com/pubID" - c, err := NewClient(user, pubID) + c, err := NewClient(db.DefaultContext, user, pubID) assert.NoError(t, err) expected := "BODY" diff --git a/modules/activitypub/main_test.go b/modules/activitypub/main_test.go index dcd57bb59e5..4591f1fa555 100644 --- a/modules/activitypub/main_test.go +++ b/modules/activitypub/main_test.go @@ -4,7 +4,6 @@ package activitypub import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -15,7 +14,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go index ef9bc0a864b..d196a3806e7 100644 --- a/modules/activitypub/user_settings.go +++ b/modules/activitypub/user_settings.go @@ -4,6 +4,8 @@ package activitypub import ( + "context" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/util" ) @@ -11,19 +13,19 @@ import ( const rsaBits = 3072 // GetKeyPair function returns a user's private and public keys -func GetKeyPair(user *user_model.User) (pub, priv string, err error) { +func GetKeyPair(ctx context.Context, user *user_model.User) (pub, priv string, err error) { var settings map[string]*user_model.Setting - settings, err = user_model.GetSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) + settings, err = user_model.GetSettings(ctx, user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) if err != nil { return pub, priv, err } else if len(settings) == 0 { if priv, pub, err = util.GenerateKeyPair(rsaBits); err != nil { return pub, priv, err } - if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, priv); err != nil { + if err = user_model.SetUserSetting(ctx, user.ID, user_model.UserActivityPubPrivPem, priv); err != nil { return pub, priv, err } - if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, pub); err != nil { + if err = user_model.SetUserSetting(ctx, user.ID, user_model.UserActivityPubPubPem, pub); err != nil { return pub, priv, err } return pub, priv, err @@ -35,13 +37,13 @@ func GetKeyPair(user *user_model.User) (pub, priv string, err error) { } // GetPublicKey function returns a user's public key -func GetPublicKey(user *user_model.User) (pub string, err error) { - pub, _, err = GetKeyPair(user) +func GetPublicKey(ctx context.Context, user *user_model.User) (pub string, err error) { + pub, _, err = GetKeyPair(ctx, user) return pub, err } // GetPrivateKey function returns a user's private key -func GetPrivateKey(user *user_model.User) (priv string, err error) { - _, priv, err = GetKeyPair(user) +func GetPrivateKey(ctx context.Context, user *user_model.User) (priv string, err error) { + _, priv, err = GetKeyPair(ctx, user) return priv, err } diff --git a/modules/activitypub/user_settings_test.go b/modules/activitypub/user_settings_test.go index 78ebf8e824e..2d77906521b 100644 --- a/modules/activitypub/user_settings_test.go +++ b/modules/activitypub/user_settings_test.go @@ -6,6 +6,7 @@ package activitypub import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -17,12 +18,12 @@ import ( func TestUserSettings(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - pub, priv, err := GetKeyPair(user1) + pub, priv, err := GetKeyPair(db.DefaultContext, user1) assert.NoError(t, err) - pub1, err := GetPublicKey(user1) + pub1, err := GetPublicKey(db.DefaultContext, user1) assert.NoError(t, err) assert.Equal(t, pub, pub1) - priv1, err := GetPrivateKey(user1) + priv1, err := GetPrivateKey(db.DefaultContext, user1) assert.NoError(t, err) assert.Equal(t, priv, priv1) } diff --git a/modules/auth/webauthn/webauthn.go b/modules/auth/webauthn/webauthn.go index e732878f859..189d197333e 100644 --- a/modules/auth/webauthn/webauthn.go +++ b/modules/auth/webauthn/webauthn.go @@ -68,7 +68,7 @@ func (u *User) WebAuthnIcon() string { // WebAuthnCredentials implementns the webauthn.User interface func (u *User) WebAuthnCredentials() []webauthn.Credential { - dbCreds, err := auth.GetWebAuthnCredentialsByUID(u.ID) + dbCreds, err := auth.GetWebAuthnCredentialsByUID(db.DefaultContext, u.ID) if err != nil { return nil } diff --git a/modules/context/api.go b/modules/context/api.go index 58532b883dd..a46af6ed782 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -101,6 +101,12 @@ type APIRedirect struct{} // swagger:response string type APIString string +// APIRepoArchivedError is an error that is raised when an archived repo should be modified +// swagger:response repoArchivedError +type APIRepoArchivedError struct { + APIError +} + // ServerError responds with error message, status is 500 func (ctx *APIContext) ServerError(title string, err error) { ctx.Error(http.StatusInternalServerError, title, err) @@ -212,7 +218,7 @@ func (ctx *APIContext) CheckForOTP() { } otpHeader := ctx.Req.Header.Get("X-Gitea-OTP") - twofa, err := auth.GetTwoFactorByUID(ctx.Doer.ID) + twofa, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID) if err != nil { if auth.IsErrTwoFactorNotEnrolled(err) { return // No 2FA enrollment for this user diff --git a/modules/context/org.go b/modules/context/org.go index 7638ffdd3f1..d068646577e 100644 --- a/modules/context/org.go +++ b/modules/context/org.go @@ -46,7 +46,7 @@ func GetOrganizationByParams(ctx *Context) { ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName) if err != nil { if organization.IsErrOrgNotExist(err) { - redirectUserID, err := user_model.LookupUserRedirect(orgName) + redirectUserID, err := user_model.LookupUserRedirect(ctx, orgName) if err == nil { RedirectToUser(ctx.Base, orgName, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { @@ -128,7 +128,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { ctx.Org.IsTeamAdmin = true ctx.Org.CanCreateOrgRepo = true } else if ctx.IsSigned { - ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.Doer.ID) + ctx.Org.IsOwner, err = org.IsOwnedBy(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("IsOwnedBy", err) return @@ -140,12 +140,12 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { ctx.Org.IsTeamAdmin = true ctx.Org.CanCreateOrgRepo = true } else { - ctx.Org.IsMember, err = org.IsOrgMember(ctx.Doer.ID) + ctx.Org.IsMember, err = org.IsOrgMember(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("IsOrgMember", err) return } - ctx.Org.CanCreateOrgRepo, err = org.CanCreateOrgRepo(ctx.Doer.ID) + ctx.Org.CanCreateOrgRepo, err = org.CanCreateOrgRepo(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("CanCreateOrgRepo", err) return @@ -165,7 +165,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsPublicMember"] = func(uid int64) bool { - is, _ := organization.IsPublicMembership(ctx.Org.Organization.ID, uid) + is, _ := organization.IsPublicMembership(ctx, ctx.Org.Organization.ID, uid) return is } ctx.Data["CanCreateOrgRepo"] = ctx.Org.CanCreateOrgRepo @@ -179,7 +179,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { OrgID: org.ID, PublicOnly: ctx.Org.PublicMemberOnly, } - ctx.Data["NumMembers"], err = organization.CountOrgMembers(opts) + ctx.Data["NumMembers"], err = organization.CountOrgMembers(ctx, opts) if err != nil { ctx.ServerError("CountOrgMembers", err) return @@ -191,7 +191,7 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { if ctx.Org.IsOwner { shouldSeeAllTeams = true } else { - teams, err := org.GetUserTeams(ctx.Doer.ID) + teams, err := org.GetUserTeams(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetUserTeams", err) return @@ -204,13 +204,13 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { } } if shouldSeeAllTeams { - ctx.Org.Teams, err = org.LoadTeams() + ctx.Org.Teams, err = org.LoadTeams(ctx) if err != nil { ctx.ServerError("LoadTeams", err) return } } else { - ctx.Org.Teams, err = org.GetUserTeams(ctx.Doer.ID) + ctx.Org.Teams, err = org.GetUserTeams(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetUserTeams", err) return diff --git a/modules/context/package.go b/modules/context/package.go index c0813fb2da6..87e817c1cd6 100644 --- a/modules/context/package.go +++ b/modules/context/package.go @@ -109,7 +109,7 @@ func determineAccessMode(ctx *Base, pkg *Package, doer *user_model.User) (perm.A if doer != nil && !doer.IsGhost() { // 1. If user is logged in, check all team packages permissions var err error - accessMode, err = org.GetOrgUserMaxAuthorizeLevel(doer.ID) + accessMode, err = org.GetOrgUserMaxAuthorizeLevel(ctx, doer.ID) if err != nil { return accessMode, err } diff --git a/modules/context/repo.go b/modules/context/repo.go index 8a16d311b14..18b6650b6ef 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -456,7 +456,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { return nil } - if redirectUserID, err := user_model.LookupUserRedirect(userName); err == nil { + if redirectUserID, err := user_model.LookupUserRedirect(ctx, userName); err == nil { RedirectToUser(ctx.Base, userName, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { ctx.NotFound("GetUserByName", nil) @@ -545,7 +545,10 @@ func RepoAssignment(ctx *Context) context.CancelFunc { ctx.ServerError("GetReleaseCountByRepoID", err) return nil } - ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{}) + ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ + // only show draft releases for users who can write, read-only users shouldn't see draft releases. + IncludeDrafts: ctx.Repo.CanWrite(unit_model.TypeReleases), + }) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) return nil @@ -561,7 +564,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues) ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests) - canSignedUserFork, err := repo_module.CanUserForkRepo(ctx.Doer, ctx.Repo.Repository) + canSignedUserFork, err := repo_module.CanUserForkRepo(ctx, ctx.Doer, ctx.Repo.Repository) if err != nil { ctx.ServerError("CanUserForkRepo", err) return nil @@ -598,7 +601,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { } if ctx.IsSigned { - ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx.Doer.ID, repo.ID) + ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx, ctx.Doer.ID, repo.ID) ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, repo.ID) } @@ -703,7 +706,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { // People who have push access or have forked repository can propose a new pull request. canPush := ctx.Repo.CanWrite(unit_model.TypeCode) || - (ctx.IsSigned && repo_model.HasForkedRepo(ctx.Doer.ID, ctx.Repo.Repository.ID)) + (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)) canCompare := false // Pull request is allowed if this is a fork repository @@ -740,7 +743,7 @@ func RepoAssignment(ctx *Context) context.CancelFunc { ctx.Data["RepoTransfer"] = repoTransfer if ctx.Doer != nil { - ctx.Data["CanUserAcceptTransfer"] = repoTransfer.CanUserAcceptTransfer(ctx.Doer) + ctx.Data["CanUserAcceptTransfer"] = repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer) } } @@ -773,6 +776,8 @@ const ( RepoRefBlob ) +const headRefName = "HEAD" + // RepoRef handles repository reference names when the ref name is not // explicitly given func RepoRef() func(*Context) context.CancelFunc { @@ -833,6 +838,14 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { case RepoRefBranch: ref := getRefNameFromPath(ctx, repo, path, repo.GitRepo.IsBranchExist) if len(ref) == 0 { + + // check if ref is HEAD + parts := strings.Split(path, "/") + if parts[0] == headRefName { + repo.TreePath = strings.Join(parts[1:], "/") + return repo.Repository.DefaultBranch + } + // maybe it's a renamed branch return getRefNameFromPath(ctx, repo, path, func(s string) bool { b, exist, err := git_model.FindRenamedBranch(ctx, repo.Repository.ID, s) @@ -861,6 +874,16 @@ func getRefName(ctx *Base, repo *Repository, pathType RepoRefType) string { repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } + + if len(parts) > 0 && parts[0] == headRefName { + // HEAD ref points to last default branch commit + commit, err := repo.GitRepo.GetBranchCommit(repo.Repository.DefaultBranch) + if err != nil { + return "" + } + repo.TreePath = strings.Join(parts[1:], "/") + return commit.ID.String() + } case RepoRefBlob: _, err := repo.GitRepo.GetBlob(path) if err != nil { diff --git a/modules/doctor/authorizedkeys.go b/modules/doctor/authorizedkeys.go index e4d85c4a18d..050a4e79742 100644 --- a/modules/doctor/authorizedkeys.go +++ b/modules/doctor/authorizedkeys.go @@ -33,7 +33,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e return fmt.Errorf("Unable to open authorized_keys file. ERROR: %w", err) } logger.Warn("Unable to open authorized_keys. (ERROR: %v). Attempting to rewrite...", err) - if err = asymkey_model.RewriteAllPublicKeys(); err != nil { + if err = asymkey_model.RewriteAllPublicKeys(ctx); err != nil { logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err) } @@ -76,7 +76,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e return fmt.Errorf(`authorized_keys is out of date and should be regenerated with "gitea admin regenerate keys" or "gitea doctor --run authorized-keys --fix"`) } logger.Warn("authorized_keys is out of date. Attempting rewrite...") - err = asymkey_model.RewriteAllPublicKeys() + err = asymkey_model.RewriteAllPublicKeys(ctx) if err != nil { logger.Critical("Unable to rewrite authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to rewrite authorized_keys file. ERROR: %w", err) diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go index 541fc736f44..e5fc5785e82 100644 --- a/modules/doctor/dbconsistency.go +++ b/modules/doctor/dbconsistency.go @@ -101,7 +101,7 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er }, // find releases without existing repository genericOrphanCheck("Orphaned Releases without existing repository", - "release", "repository", "release.repo_id=repository.id"), + "release", "repository", "`release`.repo_id=repository.id"), // find pulls without existing issues genericOrphanCheck("Orphaned PullRequests without existing issue", "pull_request", "issue", "pull_request.issue_id=issue.id"), @@ -168,9 +168,9 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er // find protected branches without existing repository genericOrphanCheck("Protected Branches without existing repository", "protected_branch", "repository", "protected_branch.repo_id=repository.id"), - // find deleted branches without existing repository - genericOrphanCheck("Deleted Branches without existing repository", - "deleted_branch", "repository", "deleted_branch.repo_id=repository.id"), + // find branches without existing repository + genericOrphanCheck("Branches without existing repository", + "branch", "repository", "branch.repo_id=repository.id"), // find LFS locks without existing repository genericOrphanCheck("LFS locks without existing repository", "lfs_lock", "repository", "lfs_lock.repo_id=repository.id"), @@ -189,6 +189,9 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er // find action without repository genericOrphanCheck("Action entries without existing repository", "action", "repository", "action.repo_id=repository.id"), + // find action without user + genericOrphanCheck("Action entries without existing user", + "action", "user", "action.act_user_id=`user`.id"), // find OAuth2Grant without existing user genericOrphanCheck("Orphaned OAuth2Grant without existing User", "oauth2_grant", "user", "oauth2_grant.user_id=`user`.id"), diff --git a/modules/doctor/fix16961.go b/modules/doctor/fix16961.go index 562c78dd765..d3f36d8d5cd 100644 --- a/modules/doctor/fix16961.go +++ b/modules/doctor/fix16961.go @@ -290,7 +290,7 @@ func fixBrokenRepoUnits16961(ctx context.Context, logger log.Logger, autofix boo return nil } - return repo_model.UpdateRepoUnit(repoUnit) + return repo_model.UpdateRepoUnit(ctx, repoUnit) }, ) if err != nil { diff --git a/modules/doctor/fix8312.go b/modules/doctor/fix8312.go index 8de3113663b..4fc049873ad 100644 --- a/modules/doctor/fix8312.go +++ b/modules/doctor/fix8312.go @@ -29,7 +29,7 @@ func fixOwnerTeamCreateOrgRepo(ctx context.Context, logger log.Logger, autofix b return nil } - return models.UpdateTeam(team, false, false) + return models.UpdateTeam(ctx, team, false, false) }, ) if err != nil { diff --git a/modules/doctor/usertype.go b/modules/doctor/usertype.go index 550e536cbd8..ab32b78e62f 100644 --- a/modules/doctor/usertype.go +++ b/modules/doctor/usertype.go @@ -11,14 +11,14 @@ import ( ) func checkUserType(ctx context.Context, logger log.Logger, autofix bool) error { - count, err := user_model.CountWrongUserType() + count, err := user_model.CountWrongUserType(ctx) if err != nil { logger.Critical("Error: %v whilst counting wrong user types") return err } if count > 0 { if autofix { - if count, err = user_model.FixWrongUserType(); err != nil { + if count, err = user_model.FixWrongUserType(ctx); err != nil { logger.Critical("Error: %v whilst fixing wrong user types") return err } diff --git a/modules/eventsource/manager_run.go b/modules/eventsource/manager_run.go index 35dfc62f1ed..bef1a00c5b9 100644 --- a/modules/eventsource/manager_run.go +++ b/modules/eventsource/manager_run.go @@ -71,7 +71,7 @@ loop: now := timeutil.TimeStampNow().Add(-2) - uidCounts, err := activities_model.GetUIDsAndNotificationCounts(then, now) + uidCounts, err := activities_model.GetUIDsAndNotificationCounts(ctx, then, now) if err != nil { log.Error("Unable to get UIDcounts: %v", err) } @@ -84,7 +84,7 @@ loop: then = now if setting.Service.EnableTimetracking { - usersStopwatches, err := issues_model.GetUIDsAndStopwatch() + usersStopwatches, err := issues_model.GetUIDsAndStopwatch(ctx) if err != nil { log.Error("Unable to get GetUIDsAndStopwatch: %v", err) return diff --git a/modules/git/blame.go b/modules/git/blame.go index 4bd13dc32d2..6728a6bed85 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -13,6 +13,7 @@ import ( "regexp" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ) // BlamePart represents block of blame - continuous lines with one sha @@ -23,12 +24,16 @@ type BlamePart struct { // BlameReader returns part of file blame one by one type BlameReader struct { - cmd *Command output io.WriteCloser reader io.ReadCloser bufferedReader *bufio.Reader done chan error lastSha *string + ignoreRevsFile *string +} + +func (r *BlameReader) UsesIgnoreRevs() bool { + return r.ignoreRevsFile != nil } var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})") @@ -101,28 +106,44 @@ func (r *BlameReader) Close() error { r.bufferedReader = nil _ = r.reader.Close() _ = r.output.Close() + if r.ignoreRevsFile != nil { + _ = util.Remove(*r.ignoreRevsFile) + } return err } // CreateBlameReader creates reader for given repository, commit and file -func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) { - cmd := NewCommandContextNoGlobals(ctx, "blame", "--porcelain"). - AddDynamicArguments(commitID). +func CreateBlameReader(ctx context.Context, repoPath string, commit *Commit, file string, bypassBlameIgnore bool) (*BlameReader, error) { + var ignoreRevsFile *string + if CheckGitVersionAtLeast("2.23") == nil && !bypassBlameIgnore { + ignoreRevsFile = tryCreateBlameIgnoreRevsFile(commit) + } + + cmd := NewCommandContextNoGlobals(ctx, "blame", "--porcelain") + if ignoreRevsFile != nil { + // Possible improvement: use --ignore-revs-file /dev/stdin on unix + // There is no equivalent on Windows. May be implemented if Gitea uses an external git backend. + cmd.AddOptionValues("--ignore-revs-file", *ignoreRevsFile) + } + cmd.AddDynamicArguments(commit.ID.String()). AddDashesAndList(file). SetDescription(fmt.Sprintf("GetBlame [repo_path: %s]", repoPath)) reader, stdout, err := os.Pipe() if err != nil { + if ignoreRevsFile != nil { + _ = util.Remove(*ignoreRevsFile) + } return nil, err } done := make(chan error, 1) - go func(cmd *Command, dir string, stdout io.WriteCloser, done chan error) { + go func() { stderr := bytes.Buffer{} // TODO: it doesn't work for directories (the directories shouldn't be "blamed"), and the "err" should be returned by "Read" but not by "Close" err := cmd.Run(&RunOpts{ UseContextTimeout: true, - Dir: dir, + Dir: repoPath, Stdout: stdout, Stderr: &stderr, }) @@ -131,15 +152,42 @@ func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*B if err != nil { log.Error("Error running git blame (dir: %v): %v, stderr: %v", repoPath, err, stderr.String()) } - }(cmd, repoPath, stdout, done) + }() bufferedReader := bufio.NewReader(reader) return &BlameReader{ - cmd: cmd, output: stdout, reader: reader, bufferedReader: bufferedReader, done: done, + ignoreRevsFile: ignoreRevsFile, }, nil } + +func tryCreateBlameIgnoreRevsFile(commit *Commit) *string { + entry, err := commit.GetTreeEntryByPath(".git-blame-ignore-revs") + if err != nil { + return nil + } + + r, err := entry.Blob().DataAsync() + if err != nil { + return nil + } + defer r.Close() + + f, err := os.CreateTemp("", "gitea_git-blame-ignore-revs") + if err != nil { + return nil + } + + _, err = io.Copy(f, r) + _ = f.Close() + if err != nil { + _ = util.Remove(f.Name()) + return nil + } + + return util.ToPointer(f.Name()) +} diff --git a/modules/git/blame_test.go b/modules/git/blame_test.go index 1c0cd5c4aa2..013350ac2f4 100644 --- a/modules/git/blame_test.go +++ b/modules/git/blame_test.go @@ -14,27 +14,127 @@ func TestReadingBlameOutput(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", "f32b0a9dfd09a60f616f29158f772cedd89942d2", "README.md") - assert.NoError(t, err) - defer blameReader.Close() - - parts := []*BlamePart{ - { - "72866af952e98d02a73003501836074b286a78f6", - []string{ - "# test_repo", - "Test repository for testing migration from github to gitea", - }, - }, - { - "f32b0a9dfd09a60f616f29158f772cedd89942d2", - []string{"", "Do not make any changes to this repo it is used for unit testing"}, - }, - } - - for _, part := range parts { - actualPart, err := blameReader.NextPart() + t.Run("Without .git-blame-ignore-revs", func(t *testing.T) { + repo, err := OpenRepository(ctx, "./tests/repos/repo5_pulls") assert.NoError(t, err) - assert.Equal(t, part, actualPart) - } + defer repo.Close() + + commit, err := repo.GetCommit("f32b0a9dfd09a60f616f29158f772cedd89942d2") + assert.NoError(t, err) + + parts := []*BlamePart{ + { + "72866af952e98d02a73003501836074b286a78f6", + []string{ + "# test_repo", + "Test repository for testing migration from github to gitea", + }, + }, + { + "f32b0a9dfd09a60f616f29158f772cedd89942d2", + []string{"", "Do not make any changes to this repo it is used for unit testing"}, + }, + } + + for _, bypass := range []bool{false, true} { + blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo5_pulls", commit, "README.md", bypass) + assert.NoError(t, err) + assert.NotNil(t, blameReader) + defer blameReader.Close() + + assert.False(t, blameReader.UsesIgnoreRevs()) + + for _, part := range parts { + actualPart, err := blameReader.NextPart() + assert.NoError(t, err) + assert.Equal(t, part, actualPart) + } + + // make sure all parts have been read + actualPart, err := blameReader.NextPart() + assert.Nil(t, actualPart) + assert.NoError(t, err) + } + }) + + t.Run("With .git-blame-ignore-revs", func(t *testing.T) { + repo, err := OpenRepository(ctx, "./tests/repos/repo6_blame") + assert.NoError(t, err) + defer repo.Close() + + full := []*BlamePart{ + { + "af7486bd54cfc39eea97207ca666aa69c9d6df93", + []string{"line", "line"}, + }, + { + "45fb6cbc12f970b04eacd5cd4165edd11c8d7376", + []string{"changed line"}, + }, + { + "af7486bd54cfc39eea97207ca666aa69c9d6df93", + []string{"line", "line", ""}, + }, + } + + cases := []struct { + CommitID string + UsesIgnoreRevs bool + Bypass bool + Parts []*BlamePart + }{ + { + CommitID: "544d8f7a3b15927cddf2299b4b562d6ebd71b6a7", + UsesIgnoreRevs: true, + Bypass: false, + Parts: []*BlamePart{ + { + "af7486bd54cfc39eea97207ca666aa69c9d6df93", + []string{"line", "line", "changed line", "line", "line", ""}, + }, + }, + }, + { + CommitID: "544d8f7a3b15927cddf2299b4b562d6ebd71b6a7", + UsesIgnoreRevs: false, + Bypass: true, + Parts: full, + }, + { + CommitID: "45fb6cbc12f970b04eacd5cd4165edd11c8d7376", + UsesIgnoreRevs: false, + Bypass: false, + Parts: full, + }, + { + CommitID: "45fb6cbc12f970b04eacd5cd4165edd11c8d7376", + UsesIgnoreRevs: false, + Bypass: false, + Parts: full, + }, + } + + for _, c := range cases { + commit, err := repo.GetCommit(c.CommitID) + assert.NoError(t, err) + + blameReader, err := CreateBlameReader(ctx, "./tests/repos/repo6_blame", commit, "blame.txt", c.Bypass) + assert.NoError(t, err) + assert.NotNil(t, blameReader) + defer blameReader.Close() + + assert.Equal(t, c.UsesIgnoreRevs, blameReader.UsesIgnoreRevs()) + + for _, part := range c.Parts { + actualPart, err := blameReader.NextPart() + assert.NoError(t, err) + assert.Equal(t, part, actualPart) + } + + // make sure all parts have been read + actualPart, err := blameReader.NextPart() + assert.Nil(t, actualPart) + assert.NoError(t, err) + } + }) } diff --git a/modules/git/repo.go b/modules/git/repo.go index 5aa57fd0658..2557aca8c69 100644 --- a/modules/git/repo.go +++ b/modules/git/repo.go @@ -86,7 +86,8 @@ func (repo *Repository) IsEmpty() (bool, error) { Stdout: &output, Stderr: &errbuf, }); err != nil { - if err.Error() == "exit status 1" && errbuf.String() == "" { + if (err.Error() == "exit status 1" && strings.TrimSpace(errbuf.String()) == "") || err.Error() == "exit status 129" { + // git 2.11 exits with 129 if the repo is empty return true, nil } return true, fmt.Errorf("check empty: %w - %s", err, errbuf.String()) diff --git a/modules/git/tests/repos/repo6_blame/HEAD b/modules/git/tests/repos/repo6_blame/HEAD new file mode 100644 index 00000000000..cb089cd89a7 --- /dev/null +++ b/modules/git/tests/repos/repo6_blame/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/modules/git/tests/repos/repo6_blame/config b/modules/git/tests/repos/repo6_blame/config new file mode 100644 index 00000000000..07d359d07cf --- /dev/null +++ b/modules/git/tests/repos/repo6_blame/config @@ -0,0 +1,4 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = true diff --git a/modules/git/tests/repos/repo6_blame/objects/31/bb4b42cecf0a98fc9a32fc5aaeaf53ec52643c b/modules/git/tests/repos/repo6_blame/objects/31/bb4b42cecf0a98fc9a32fc5aaeaf53ec52643c new file mode 100644 index 00000000000..6cde9108e7a Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/31/bb4b42cecf0a98fc9a32fc5aaeaf53ec52643c differ diff --git a/modules/git/tests/repos/repo6_blame/objects/3b/0f66d8b065f8adbf2fef7d986528c655b98cb1 b/modules/git/tests/repos/repo6_blame/objects/3b/0f66d8b065f8adbf2fef7d986528c655b98cb1 new file mode 100644 index 00000000000..b8db01dc357 Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/3b/0f66d8b065f8adbf2fef7d986528c655b98cb1 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/45/fb6cbc12f970b04eacd5cd4165edd11c8d7376 b/modules/git/tests/repos/repo6_blame/objects/45/fb6cbc12f970b04eacd5cd4165edd11c8d7376 new file mode 100644 index 00000000000..6c0ae4723fd Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/45/fb6cbc12f970b04eacd5cd4165edd11c8d7376 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/49/7701e5bb8676e419b93875d8f0808c7b31aed9 b/modules/git/tests/repos/repo6_blame/objects/49/7701e5bb8676e419b93875d8f0808c7b31aed9 new file mode 100644 index 00000000000..5c2b5641cf2 Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/49/7701e5bb8676e419b93875d8f0808c7b31aed9 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/54/4d8f7a3b15927cddf2299b4b562d6ebd71b6a7 b/modules/git/tests/repos/repo6_blame/objects/54/4d8f7a3b15927cddf2299b4b562d6ebd71b6a7 new file mode 100644 index 00000000000..3c6471864cb Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/54/4d8f7a3b15927cddf2299b4b562d6ebd71b6a7 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/a8/9199e8dea077e4a8ba0bc01bc155275cfdd044 b/modules/git/tests/repos/repo6_blame/objects/a8/9199e8dea077e4a8ba0bc01bc155275cfdd044 new file mode 100644 index 00000000000..847b7bc305b Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/a8/9199e8dea077e4a8ba0bc01bc155275cfdd044 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/af/7486bd54cfc39eea97207ca666aa69c9d6df93 b/modules/git/tests/repos/repo6_blame/objects/af/7486bd54cfc39eea97207ca666aa69c9d6df93 new file mode 100644 index 00000000000..206ef1efb75 Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/af/7486bd54cfc39eea97207ca666aa69c9d6df93 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/b8/d1ba1ccb58ee3744b3d1434aae7d26ce2d9421 b/modules/git/tests/repos/repo6_blame/objects/b8/d1ba1ccb58ee3744b3d1434aae7d26ce2d9421 new file mode 100644 index 00000000000..bb26889ed3f Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/b8/d1ba1ccb58ee3744b3d1434aae7d26ce2d9421 differ diff --git a/modules/git/tests/repos/repo6_blame/objects/ca/411a3b842c3caec045772da42de16b3ffdafe8 b/modules/git/tests/repos/repo6_blame/objects/ca/411a3b842c3caec045772da42de16b3ffdafe8 new file mode 100644 index 00000000000..1653ed95446 Binary files /dev/null and b/modules/git/tests/repos/repo6_blame/objects/ca/411a3b842c3caec045772da42de16b3ffdafe8 differ diff --git a/modules/git/tests/repos/repo6_blame/refs/heads/master b/modules/git/tests/repos/repo6_blame/refs/heads/master new file mode 100644 index 00000000000..01c9922c5f5 --- /dev/null +++ b/modules/git/tests/repos/repo6_blame/refs/heads/master @@ -0,0 +1 @@ +544d8f7a3b15927cddf2299b4b562d6ebd71b6a7 diff --git a/modules/gitgraph/graph_models.go b/modules/gitgraph/graph_models.go index 748f7f30757..e48fef8b9d0 100644 --- a/modules/gitgraph/graph_models.go +++ b/modules/gitgraph/graph_models.go @@ -116,10 +116,10 @@ func (graph *Graph) LoadAndProcessCommits(ctx context.Context, repository *repo_ c.Verification = asymkey_model.ParseCommitWithSignature(ctx, c.Commit) _ = asymkey_model.CalculateTrustStatus(c.Verification, repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return repo_model.IsOwnerMemberCollaborator(repository, user.ID) + return repo_model.IsOwnerMemberCollaborator(ctx, repository, user.ID) }, &keyMap) - statuses, _, err := git_model.GetLatestCommitStatus(db.DefaultContext, repository.ID, c.Commit.ID.String(), db.ListOptions{}) + statuses, _, err := git_model.GetLatestCommitStatus(ctx, repository.ID, c.Commit.ID.String(), db.ListOptions{}) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } else { diff --git a/modules/indexer/code/indexer_test.go b/modules/indexer/code/indexer_test.go index 2a650646bd9..5b2a97d3d5f 100644 --- a/modules/indexer/code/indexer_test.go +++ b/modules/indexer/code/indexer_test.go @@ -6,7 +6,6 @@ package code import ( "context" "os" - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -23,9 +22,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } func testIndexer(name string, t *testing.T, indexer internal.Indexer) { diff --git a/modules/indexer/issues/db/options.go b/modules/indexer/issues/db/options.go index 0d6a8406d3b..4d3fa44ca6c 100644 --- a/modules/indexer/issues/db/options.go +++ b/modules/indexer/issues/db/options.go @@ -97,7 +97,7 @@ func ToDBOptions(ctx context.Context, options *internal.SearchOptions) (*issue_m if len(options.IncludedLabelIDs) == 0 && len(options.IncludedAnyLabelIDs) > 0 { _ = ctx // issue_model.GetLabelsByIDs should be called with ctx, this line can be removed when it's done. - labels, err := issue_model.GetLabelsByIDs(options.IncludedAnyLabelIDs, "name") + labels, err := issue_model.GetLabelsByIDs(ctx, options.IncludedAnyLabelIDs, "name") if err != nil { return nil, fmt.Errorf("GetLabelsByIDs: %v", err) } diff --git a/modules/indexer/issues/indexer_test.go b/modules/indexer/issues/indexer_test.go index a4e1c899fc1..0ec23164c28 100644 --- a/modules/indexer/issues/indexer_test.go +++ b/modules/indexer/issues/indexer_test.go @@ -5,14 +5,13 @@ package issues import ( "context" - "path" - "path/filepath" "testing" - "time" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" - "code.gitea.io/gitea/modules/indexer/issues/bleve" + "code.gitea.io/gitea/modules/indexer/issues/internal" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/util" _ "code.gitea.io/gitea/models" _ "code.gitea.io/gitea/models/actions" @@ -22,71 +21,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) -} - -func TestBleveSearchIssues(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - setting.CfgProvider, _ = setting.NewConfigProviderFromData("") - - tmpIndexerDir := t.TempDir() - - setting.CfgProvider.Section("queue.issue_indexer").Key("DATADIR").MustString(path.Join(tmpIndexerDir, "issues.queue")) - - oldIssuePath := setting.Indexer.IssuePath - setting.Indexer.IssuePath = path.Join(tmpIndexerDir, "issues.queue") - defer func() { - setting.Indexer.IssuePath = oldIssuePath - }() - - setting.Indexer.IssueType = "bleve" - setting.LoadQueueSettings() - InitIssueIndexer(true) - defer func() { - if bleveIndexer, ok := (*globalIndexer.Load()).(*bleve.Indexer); ok { - bleveIndexer.Close() - } - }() - - time.Sleep(5 * time.Second) - - t.Run("issue2", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "issue2", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.EqualValues(t, []int64{2}, ids) - }) - - t.Run("first", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "first", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.EqualValues(t, []int64{1}, ids) - }) - - t.Run("for", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "for", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids) - }) - - t.Run("good", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "good", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.EqualValues(t, []int64{1}, ids) - }) + unittest.MainTest(m) } func TestDBSearchIssues(t *testing.T) { @@ -95,39 +30,390 @@ func TestDBSearchIssues(t *testing.T) { setting.Indexer.IssueType = "db" InitIssueIndexer(true) - t.Run("issue2", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "issue2", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.EqualValues(t, []int64{2}, ids) - }) - - t.Run("first", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "first", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.EqualValues(t, []int64{1}, ids) - }) - - t.Run("for", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "for", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.ElementsMatch(t, []int64{1, 2, 3, 5, 11}, ids) - }) - - t.Run("good", func(t *testing.T) { - ids, _, err := SearchIssues(context.TODO(), &SearchOptions{ - Keyword: "good", - RepoIDs: []int64{1}, - }) - assert.NoError(t, err) - assert.EqualValues(t, []int64{1}, ids) - }) + t.Run("search issues with keyword", searchIssueWithKeyword) + t.Run("search issues in repo", searchIssueInRepo) + t.Run("search issues by ID", searchIssueByID) + t.Run("search issues is pr", searchIssueIsPull) + t.Run("search issues is closed", searchIssueIsClosed) + t.Run("search issues by milestone", searchIssueByMilestoneID) + t.Run("search issues by label", searchIssueByLabelID) + t.Run("search issues by time", searchIssueByTime) + t.Run("search issues with order", searchIssueWithOrder) + t.Run("search issues in project", searchIssueInProject) + t.Run("search issues with paginator", searchIssueWithPaginator) +} + +func searchIssueWithKeyword(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + Keyword: "issue2", + RepoIDs: []int64{1}, + }, + []int64{2}, + }, + { + SearchOptions{ + Keyword: "first", + RepoIDs: []int64{1}, + }, + []int64{1}, + }, + { + SearchOptions{ + Keyword: "for", + RepoIDs: []int64{1}, + }, + []int64{11, 5, 3, 2, 1}, + }, + { + SearchOptions{ + Keyword: "good", + RepoIDs: []int64{1}, + }, + []int64{1}, + }, + } + + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueInRepo(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + RepoIDs: []int64{1}, + }, + []int64{11, 5, 3, 2, 1}, + }, + { + SearchOptions{ + RepoIDs: []int64{2}, + }, + []int64{7, 4}, + }, + { + SearchOptions{ + RepoIDs: []int64{3}, + }, + []int64{12, 6}, + }, + { + SearchOptions{ + RepoIDs: []int64{4}, + }, + []int64{}, + }, + { + SearchOptions{ + RepoIDs: []int64{5}, + }, + []int64{15}, + }, + } + + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueByID(t *testing.T) { + int64Pointer := func(x int64) *int64 { + return &x + } + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + PosterID: int64Pointer(1), + }, + []int64{11, 6, 3, 2, 1}, + }, + { + SearchOptions{ + AssigneeID: int64Pointer(1), + }, + []int64{6, 1}, + }, + { + SearchOptions{ + MentionID: int64Pointer(4), + }, + []int64{1}, + }, + { + SearchOptions{ + ReviewedID: int64Pointer(1), + }, + []int64{}, + }, + { + SearchOptions{ + ReviewRequestedID: int64Pointer(1), + }, + []int64{12}, + }, + { + SearchOptions{ + SubscriberID: int64Pointer(1), + }, + []int64{11, 6, 5, 3, 2, 1}, + }, + { + // issue 20 request user 15 and team 5 which user 15 belongs to + // the review request number of issue 20 should be 1 + SearchOptions{ + ReviewRequestedID: int64Pointer(15), + }, + []int64{12, 20}, + }, + { + // user 20 approved the issue 20, so return nothing + SearchOptions{ + ReviewRequestedID: int64Pointer(20), + }, + []int64{}, + }, + } + + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueIsPull(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + IsPull: util.OptionalBoolFalse, + }, + []int64{17, 16, 15, 14, 13, 6, 5, 18, 10, 7, 4, 1}, + }, + { + SearchOptions{ + IsPull: util.OptionalBoolTrue, + }, + []int64{12, 11, 20, 19, 9, 8, 3, 2}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueIsClosed(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + IsClosed: util.OptionalBoolFalse, + }, + []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 19, 18, 10, 7, 9, 8, 3, 2, 1}, + }, + { + SearchOptions{ + IsClosed: util.OptionalBoolTrue, + }, + []int64{5, 4}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueByMilestoneID(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + MilestoneIDs: []int64{1}, + }, + []int64{2}, + }, + { + SearchOptions{ + MilestoneIDs: []int64{3}, + }, + []int64{3}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueByLabelID(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + IncludedLabelIDs: []int64{1}, + }, + []int64{2, 1}, + }, + { + SearchOptions{ + IncludedLabelIDs: []int64{4}, + }, + []int64{2}, + }, + { + SearchOptions{ + ExcludedLabelIDs: []int64{1}, + }, + []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueByTime(t *testing.T) { + int64Pointer := func(i int64) *int64 { + return &i + } + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + UpdatedAfterUnix: int64Pointer(0), + }, + []int64{17, 16, 15, 14, 13, 12, 11, 20, 6, 5, 19, 18, 10, 7, 4, 9, 8, 3, 2, 1}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueWithOrder(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + SortBy: internal.SortByCreatedAsc, + }, + []int64{1, 2, 3, 8, 9, 4, 7, 10, 18, 19, 5, 6, 20, 11, 12, 13, 14, 15, 16, 17}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueInProject(t *testing.T) { + int64Pointer := func(i int64) *int64 { + return &i + } + tests := []struct { + opts SearchOptions + expectedIDs []int64 + }{ + { + SearchOptions{ + ProjectID: int64Pointer(1), + }, + []int64{5, 3, 2, 1}, + }, + { + SearchOptions{ + ProjectBoardID: int64Pointer(1), + }, + []int64{1}, + }, + } + for _, test := range tests { + issueIDs, _, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + } +} + +func searchIssueWithPaginator(t *testing.T) { + tests := []struct { + opts SearchOptions + expectedIDs []int64 + expectedTotal int64 + }{ + { + SearchOptions{ + Paginator: &db.ListOptions{ + PageSize: 5, + }, + }, + []int64{17, 16, 15, 14, 13}, + 20, + }, + } + for _, test := range tests { + issueIDs, total, err := SearchIssues(context.TODO(), &test.opts) + if !assert.NoError(t, err) { + return + } + assert.Equal(t, test.expectedIDs, issueIDs) + assert.Equal(t, test.expectedTotal, total) + } } diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index c0315154340..6f935a20de3 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -5,7 +5,6 @@ package stats import ( "context" - "path/filepath" "testing" "time" @@ -23,9 +22,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } func TestRepoStatsIndex(t *testing.T) { diff --git a/modules/lfs/filesystem_client.go b/modules/lfs/filesystem_client.go index 835551e00c6..3503a9effc4 100644 --- a/modules/lfs/filesystem_client.go +++ b/modules/lfs/filesystem_client.go @@ -15,7 +15,7 @@ import ( // FilesystemClient is used to read LFS data from a filesystem path type FilesystemClient struct { - lfsdir string + lfsDir string } // BatchSize returns the preferred size of batchs to process @@ -25,16 +25,12 @@ func (c *FilesystemClient) BatchSize() int { func newFilesystemClient(endpoint *url.URL) *FilesystemClient { path, _ := util.FileURLToPath(endpoint) - - lfsdir := filepath.Join(path, "lfs", "objects") - - client := &FilesystemClient{lfsdir} - - return client + lfsDir := filepath.Join(path, "lfs", "objects") + return &FilesystemClient{lfsDir} } func (c *FilesystemClient) objectPath(oid string) string { - return filepath.Join(c.lfsdir, oid[0:2], oid[2:4], oid) + return filepath.Join(c.lfsDir, oid[0:2], oid[2:4], oid) } // Download reads the specific LFS object from the target path diff --git a/modules/lfs/http_client.go b/modules/lfs/http_client.go index ec0d6269bd5..de0b1e4fede 100644 --- a/modules/lfs/http_client.go +++ b/modules/lfs/http_client.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "io" "net/http" "net/url" "strings" @@ -17,7 +18,7 @@ import ( "code.gitea.io/gitea/modules/proxy" ) -const batchSize = 20 +const httpBatchSize = 20 // HTTPClient is used to communicate with the LFS server // https://github.com/git-lfs/git-lfs/blob/main/docs/api/batch.md @@ -29,7 +30,7 @@ type HTTPClient struct { // BatchSize returns the preferred size of batchs to process func (c *HTTPClient) BatchSize() int { - return batchSize + return httpBatchSize } func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient { @@ -43,28 +44,25 @@ func newHTTPClient(endpoint *url.URL, httpTransport *http.Transport) *HTTPClient Transport: httpTransport, } - client := &HTTPClient{ - client: hc, - endpoint: strings.TrimSuffix(endpoint.String(), "/"), - transfers: make(map[string]TransferAdapter), - } - basic := &BasicTransferAdapter{hc} - - client.transfers[basic.Name()] = basic + client := &HTTPClient{ + client: hc, + endpoint: strings.TrimSuffix(endpoint.String(), "/"), + transfers: map[string]TransferAdapter{ + basic.Name(): basic, + }, + } return client } func (c *HTTPClient) transferNames() []string { keys := make([]string, len(c.transfers)) - i := 0 for k := range c.transfers { keys[i] = k i++ } - return keys } @@ -74,7 +72,6 @@ func (c *HTTPClient) batch(ctx context.Context, operation string, objects []Poin url := fmt.Sprintf("%s/objects/batch", c.endpoint) request := &BatchRequest{operation, c.transferNames(), nil, objects} - payload := new(bytes.Buffer) err := json.NewEncoder(payload).Encode(request) if err != nil { @@ -82,32 +79,17 @@ func (c *HTTPClient) batch(ctx context.Context, operation string, objects []Poin return nil, err } - log.Trace("Calling: %s", url) - - req, err := http.NewRequestWithContext(ctx, "POST", url, payload) + req, err := createRequest(ctx, http.MethodPost, url, map[string]string{"Content-Type": MediaType}, payload) if err != nil { - log.Error("Error creating request: %v", err) return nil, err } - req.Header.Set("Content-type", MediaType) - req.Header.Set("Accept", MediaType) - res, err := c.client.Do(req) + res, err := performRequest(ctx, c.client, req) if err != nil { - select { - case <-ctx.Done(): - return nil, ctx.Err() - default: - } - log.Error("Error while processing request: %v", err) return nil, err } defer res.Body.Close() - if res.StatusCode != http.StatusOK { - return nil, fmt.Errorf("Unexpected server response: %s", res.Status) - } - var response BatchResponse err = json.NewDecoder(res.Body).Decode(&response) if err != nil { @@ -177,7 +159,7 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc link, ok := object.Actions["upload"] if !ok { log.Debug("%+v", object) - return errors.New("Missing action 'upload'") + return errors.New("missing action 'upload'") } content, err := uc(object.Pointer, nil) @@ -187,8 +169,6 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc err = transferAdapter.Upload(ctx, link, object.Pointer, content) - content.Close() - if err != nil { return err } @@ -203,7 +183,7 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc link, ok := object.Actions["download"] if !ok { log.Debug("%+v", object) - return errors.New("Missing action 'download'") + return errors.New("missing action 'download'") } content, err := transferAdapter.Download(ctx, link) @@ -219,3 +199,59 @@ func (c *HTTPClient) performOperation(ctx context.Context, objects []Pointer, dc return nil } + +// createRequest creates a new request, and sets the headers. +func createRequest(ctx context.Context, method, url string, headers map[string]string, body io.Reader) (*http.Request, error) { + log.Trace("createRequest: %s", url) + req, err := http.NewRequestWithContext(ctx, method, url, body) + if err != nil { + log.Error("Error creating request: %v", err) + return nil, err + } + + for key, value := range headers { + req.Header.Set(key, value) + } + req.Header.Set("Accept", MediaType) + + return req, nil +} + +// performRequest sends a request, optionally performs a callback on the request and returns the response. +// If the status code is 200, the response is returned, and it will contain a non-nil Body. +// Otherwise, it will return an error, and the Body will be nil or closed. +func performRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) { + log.Trace("performRequest: %s", req.URL) + res, err := client.Do(req) + if err != nil { + select { + case <-ctx.Done(): + return res, ctx.Err() + default: + } + log.Error("Error while processing request: %v", err) + return res, err + } + + if res.StatusCode != http.StatusOK { + defer res.Body.Close() + return res, handleErrorResponse(res) + } + + return res, nil +} + +func handleErrorResponse(resp *http.Response) error { + var er ErrorResponse + err := json.NewDecoder(resp.Body).Decode(&er) + if err != nil { + if err == io.EOF { + return io.ErrUnexpectedEOF + } + log.Error("Error decoding json: %v", err) + return err + } + + log.Trace("ErrorResponse: %v", er) + return errors.New(er.Message) +} diff --git a/modules/lfs/http_client_test.go b/modules/lfs/http_client_test.go index cb71b9008a9..7459d9c0c97 100644 --- a/modules/lfs/http_client_test.go +++ b/modules/lfs/http_client_test.go @@ -177,7 +177,7 @@ func TestHTTPClientDownload(t *testing.T) { // case 0 { endpoint: "https://status-not-ok.io", - expectederror: "Unexpected server response: ", + expectederror: io.ErrUnexpectedEOF.Error(), }, // case 1 { @@ -207,7 +207,7 @@ func TestHTTPClientDownload(t *testing.T) { // case 6 { endpoint: "https://empty-actions-map.io", - expectederror: "Missing action 'download'", + expectederror: "missing action 'download'", }, // case 7 { @@ -217,27 +217,28 @@ func TestHTTPClientDownload(t *testing.T) { // case 8 { endpoint: "https://upload-actions-map.io", - expectederror: "Missing action 'download'", + expectederror: "missing action 'download'", }, // case 9 { endpoint: "https://verify-actions-map.io", - expectederror: "Missing action 'download'", + expectederror: "missing action 'download'", }, // case 10 { endpoint: "https://unknown-actions-map.io", - expectederror: "Missing action 'download'", + expectederror: "missing action 'download'", }, } for n, c := range cases { client := &HTTPClient{ - client: hc, - endpoint: c.endpoint, - transfers: make(map[string]TransferAdapter), + client: hc, + endpoint: c.endpoint, + transfers: map[string]TransferAdapter{ + "dummy": dummy, + }, } - client.transfers["dummy"] = dummy err := client.Download(context.Background(), []Pointer{p}, func(p Pointer, content io.ReadCloser, objectError error) error { if objectError != nil { @@ -284,7 +285,7 @@ func TestHTTPClientUpload(t *testing.T) { // case 0 { endpoint: "https://status-not-ok.io", - expectederror: "Unexpected server response: ", + expectederror: io.ErrUnexpectedEOF.Error(), }, // case 1 { @@ -319,7 +320,7 @@ func TestHTTPClientUpload(t *testing.T) { // case 7 { endpoint: "https://download-actions-map.io", - expectederror: "Missing action 'upload'", + expectederror: "missing action 'upload'", }, // case 8 { @@ -329,22 +330,23 @@ func TestHTTPClientUpload(t *testing.T) { // case 9 { endpoint: "https://verify-actions-map.io", - expectederror: "Missing action 'upload'", + expectederror: "missing action 'upload'", }, // case 10 { endpoint: "https://unknown-actions-map.io", - expectederror: "Missing action 'upload'", + expectederror: "missing action 'upload'", }, } for n, c := range cases { client := &HTTPClient{ - client: hc, - endpoint: c.endpoint, - transfers: make(map[string]TransferAdapter), + client: hc, + endpoint: c.endpoint, + transfers: map[string]TransferAdapter{ + "dummy": dummy, + }, } - client.transfers["dummy"] = dummy err := client.Upload(context.Background(), []Pointer{p}, func(p Pointer, objectError error) (io.ReadCloser, error) { return io.NopCloser(new(bytes.Buffer)), objectError diff --git a/modules/lfs/pointer.go b/modules/lfs/pointer.go index d7653e836c9..3e5bb8f91d2 100644 --- a/modules/lfs/pointer.go +++ b/modules/lfs/pointer.go @@ -29,10 +29,10 @@ const ( var ( // ErrMissingPrefix occurs if the content lacks the LFS prefix - ErrMissingPrefix = errors.New("Content lacks the LFS prefix") + ErrMissingPrefix = errors.New("content lacks the LFS prefix") // ErrInvalidStructure occurs if the content has an invalid structure - ErrInvalidStructure = errors.New("Content has an invalid structure") + ErrInvalidStructure = errors.New("content has an invalid structure") // ErrInvalidOIDFormat occurs if the oid has an invalid format ErrInvalidOIDFormat = errors.New("OID has an invalid format") diff --git a/modules/lfs/transferadapter.go b/modules/lfs/transferadapter.go index 649497aabb3..d425b91946d 100644 --- a/modules/lfs/transferadapter.go +++ b/modules/lfs/transferadapter.go @@ -6,8 +6,6 @@ package lfs import ( "bytes" "context" - "errors" - "fmt" "io" "net/http" @@ -15,7 +13,7 @@ import ( "code.gitea.io/gitea/modules/log" ) -// TransferAdapter represents an adapter for downloading/uploading LFS objects +// TransferAdapter represents an adapter for downloading/uploading LFS objects. type TransferAdapter interface { Name() string Download(ctx context.Context, l *Link) (io.ReadCloser, error) @@ -23,41 +21,48 @@ type TransferAdapter interface { Verify(ctx context.Context, l *Link, p Pointer) error } -// BasicTransferAdapter implements the "basic" adapter +// BasicTransferAdapter implements the "basic" adapter. type BasicTransferAdapter struct { client *http.Client } -// Name returns the name of the adapter +// Name returns the name of the adapter. func (a *BasicTransferAdapter) Name() string { return "basic" } -// Download reads the download location and downloads the data +// Download reads the download location and downloads the data. func (a *BasicTransferAdapter) Download(ctx context.Context, l *Link) (io.ReadCloser, error) { - resp, err := a.performRequest(ctx, "GET", l, nil, nil) + req, err := createRequest(ctx, http.MethodGet, l.Href, l.Header, nil) + if err != nil { + return nil, err + } + resp, err := performRequest(ctx, a.client, req) if err != nil { return nil, err } return resp.Body, nil } -// Upload sends the content to the LFS server +// Upload sends the content to the LFS server. func (a *BasicTransferAdapter) Upload(ctx context.Context, l *Link, p Pointer, r io.Reader) error { - _, err := a.performRequest(ctx, "PUT", l, r, func(req *http.Request) { - if len(req.Header.Get("Content-Type")) == 0 { - req.Header.Set("Content-Type", "application/octet-stream") - } - - if req.Header.Get("Transfer-Encoding") == "chunked" { - req.TransferEncoding = []string{"chunked"} - } - - req.ContentLength = p.Size - }) + req, err := createRequest(ctx, http.MethodPut, l.Href, l.Header, r) if err != nil { return err } + if req.Header.Get("Content-Type") == "" { + req.Header.Set("Content-Type", "application/octet-stream") + } + if req.Header.Get("Transfer-Encoding") == "chunked" { + req.TransferEncoding = []string{"chunked"} + } + req.ContentLength = p.Size + + res, err := performRequest(ctx, a.client, req) + if err != nil { + return err + } + defer res.Body.Close() return nil } @@ -69,66 +74,15 @@ func (a *BasicTransferAdapter) Verify(ctx context.Context, l *Link, p Pointer) e return err } - _, err = a.performRequest(ctx, "POST", l, bytes.NewReader(b), func(req *http.Request) { - req.Header.Set("Content-Type", MediaType) - }) + req, err := createRequest(ctx, http.MethodPost, l.Href, l.Header, bytes.NewReader(b)) if err != nil { return err } + req.Header.Set("Content-Type", MediaType) + res, err := performRequest(ctx, a.client, req) + if err != nil { + return err + } + defer res.Body.Close() return nil } - -func (a *BasicTransferAdapter) performRequest(ctx context.Context, method string, l *Link, body io.Reader, callback func(*http.Request)) (*http.Response, error) { - log.Trace("Calling: %s %s", method, l.Href) - - req, err := http.NewRequestWithContext(ctx, method, l.Href, body) - if err != nil { - log.Error("Error creating request: %v", err) - return nil, err - } - for key, value := range l.Header { - req.Header.Set(key, value) - } - req.Header.Set("Accept", MediaType) - - if callback != nil { - callback(req) - } - - res, err := a.client.Do(req) - if err != nil { - select { - case <-ctx.Done(): - return res, ctx.Err() - default: - } - log.Error("Error while processing request: %v", err) - return res, err - } - - if res.StatusCode != http.StatusOK { - return res, handleErrorResponse(res) - } - - return res, nil -} - -func handleErrorResponse(resp *http.Response) error { - defer resp.Body.Close() - - er, err := decodeResponseError(resp.Body) - if err != nil { - return fmt.Errorf("Request failed with status %s", resp.Status) - } - log.Trace("ErrorRespone: %v", er) - return errors.New(er.Message) -} - -func decodeResponseError(r io.Reader) (ErrorResponse, error) { - var er ErrorResponse - err := json.NewDecoder(r).Decode(&er) - if err != nil { - log.Error("Error decoding json: %v", err) - } - return er, err -} diff --git a/modules/metrics/collector.go b/modules/metrics/collector.go index 33678256c3c..1bf8f58b93a 100755 --- a/modules/metrics/collector.go +++ b/modules/metrics/collector.go @@ -7,6 +7,7 @@ import ( "runtime" activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/setting" "github.com/prometheus/client_golang/prometheus" @@ -232,7 +233,7 @@ func (c Collector) Describe(ch chan<- *prometheus.Desc) { // Collect returns the metrics with values func (c Collector) Collect(ch chan<- prometheus.Metric) { - stats := activities_model.GetStatistic() + stats := activities_model.GetStatistic(db.DefaultContext) ch <- prometheus.MustNewConstMetric( c.Accesses, diff --git a/modules/queue/queue.go b/modules/queue/queue.go index 1ad7320e31f..577fd4d4981 100644 --- a/modules/queue/queue.go +++ b/modules/queue/queue.go @@ -9,6 +9,8 @@ // - An item can be a simple value, such as an integer, or a more complex structure that has multiple fields. // Usually a item serves as a task or a message. Sets of items will be sent to a queue handler to be processed. // - It's represented as a JSON-marshaled binary slice in the queue +// - Since the item is marshaled by JSON, and JSON doesn't have stable key-order/type support, +// so the decoded handler item may not be the same as the original "pushed" one if you use map/any types, // // 2. Batch: // - A collection of items that are grouped together for processing. Each worker receives a batch of items. diff --git a/modules/repository/collaborator_test.go b/modules/repository/collaborator_test.go index c7728068193..622f6abce47 100644 --- a/modules/repository/collaborator_test.go +++ b/modules/repository/collaborator_test.go @@ -244,7 +244,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // update team information and then check permission team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}) - err = organization.UpdateTeamUnits(team, nil) + err = organization.UpdateTeamUnits(db.DefaultContext, team, nil) assert.NoError(t, err) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) diff --git a/modules/repository/delete.go b/modules/repository/delete.go index 72c0dc91355..04af98beefe 100644 --- a/modules/repository/delete.go +++ b/modules/repository/delete.go @@ -4,24 +4,25 @@ package repository import ( - "code.gitea.io/gitea/models/db" + "context" + "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" ) // CanUserDelete returns true if user could delete the repository -func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, error) { +func CanUserDelete(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (bool, error) { if user.IsAdmin || user.ID == repo.OwnerID { return true, nil } - if err := repo.LoadOwner(db.DefaultContext); err != nil { + if err := repo.LoadOwner(ctx); err != nil { return false, err } if repo.Owner.IsOrganization() { - isAdmin, err := organization.OrgFromUser(repo.Owner).IsOrgAdmin(user.ID) + isAdmin, err := organization.OrgFromUser(repo.Owner).IsOrgAdmin(ctx, user.ID) if err != nil { return false, err } diff --git a/modules/repository/fork.go b/modules/repository/fork.go index 8e9f3a8976f..fbf00087167 100644 --- a/modules/repository/fork.go +++ b/modules/repository/fork.go @@ -4,25 +4,27 @@ package repository import ( + "context" + "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" ) // CanUserForkRepo returns true if specified user can fork repository. -func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool, error) { +func CanUserForkRepo(ctx context.Context, user *user_model.User, repo *repo_model.Repository) (bool, error) { if user == nil { return false, nil } - if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) { + if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(ctx, user.ID, repo.ID) { return true, nil } - ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID) + ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx, user.ID) if err != nil { return false, err } for _, org := range ownedOrgs { - if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, repo.ID) { + if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(ctx, org.ID, repo.ID) { return true, nil } } diff --git a/modules/repository/main_test.go b/modules/repository/main_test.go index abaae698663..f81dfcdafbc 100644 --- a/modules/repository/main_test.go +++ b/modules/repository/main_test.go @@ -4,7 +4,6 @@ package repository import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -13,7 +12,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 6bf88e77526..974449112f3 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -159,7 +159,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, // note: this will greatly improve release (tag) sync // for pull-mirrors with many tags repo.IsMirror = opts.Mirror - if err = SyncReleasesWithTags(repo, gitRepo); err != nil { + if err = SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { log.Error("Failed to synchronize tags to releases for repository: %v", err) } } @@ -180,12 +180,17 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, defer committer.Close() if opts.Mirror { + remoteAddress, err := util.SanitizeURL(opts.CloneAddr) + if err != nil { + return repo, err + } mirrorModel := repo_model.Mirror{ RepoID: repo.ID, Interval: setting.Mirror.DefaultInterval, EnablePrune: true, NextUpdateUnix: timeutil.TimeStampNow().AddDuration(setting.Mirror.DefaultInterval), LFS: opts.LFS, + RemoteAddress: remoteAddress, } if opts.LFS { mirrorModel.LFSEndpoint = opts.LFSEndpoint @@ -280,13 +285,13 @@ func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo } // SyncReleasesWithTags synchronizes release table with repository tags -func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository) error { +func SyncReleasesWithTags(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { log.Debug("SyncReleasesWithTags: in Repo[%d:%s/%s]", repo.ID, repo.OwnerName, repo.Name) // optimized procedure for pull-mirrors which saves a lot of time (in // particular for repos with many tags). if repo.IsMirror { - return pullMirrorReleaseSync(repo, gitRepo) + return pullMirrorReleaseSync(ctx, repo, gitRepo) } existingRelTags := make(container.Set[string]) @@ -313,7 +318,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository) return fmt.Errorf("unable to GetTagCommitID for %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err) } if git.IsErrNotExist(err) || commitID != rel.Sha1 { - if err := repo_model.PushUpdateDeleteTag(repo, rel.TagName); err != nil { + if err := repo_model.PushUpdateDeleteTag(ctx, repo, rel.TagName); err != nil { return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err) } } else { @@ -328,7 +333,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository) return nil } - if err := PushUpdateAddTag(db.DefaultContext, repo, gitRepo, tagName, sha1, refname); err != nil { + if err := PushUpdateAddTag(ctx, repo, gitRepo, tagName, sha1, refname); err != nil { return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err) } @@ -385,7 +390,7 @@ func PushUpdateAddTag(ctx context.Context, repo *repo_model.Repository, gitRepo rel.PublisherID = author.ID } - return repo_model.SaveOrUpdateTag(repo, &rel) + return repo_model.SaveOrUpdateTag(ctx, repo, &rel) } // StoreMissingLfsObjectsInRepository downloads missing LFS objects @@ -492,13 +497,13 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re // upstream. Hence, after each sync we want the pull-mirror release set to be // identical to the upstream tag set. This is much more efficient for // repositories like https://github.com/vim/vim (with over 13000 tags). -func pullMirrorReleaseSync(repo *repo_model.Repository, gitRepo *git.Repository) error { +func pullMirrorReleaseSync(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository) error { log.Trace("pullMirrorReleaseSync: rebuilding releases for pull-mirror Repo[%d:%s/%s]", repo.ID, repo.OwnerName, repo.Name) tags, numTags, err := gitRepo.GetTagInfos(0, 0) if err != nil { return fmt.Errorf("unable to GetTagInfos in pull-mirror Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err) } - err = db.WithTx(db.DefaultContext, func(ctx context.Context) error { + err = db.WithTx(ctx, func(ctx context.Context) error { // // clear out existing releases // diff --git a/modules/session/db.go b/modules/session/db.go index f86f7d1e9cf..9909f2dc1e9 100644 --- a/modules/session/db.go +++ b/modules/session/db.go @@ -8,6 +8,7 @@ import ( "sync" "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" "gitea.com/go-chi/session" @@ -71,7 +72,7 @@ func (s *DBStore) Release() error { return err } - return auth.UpdateSession(s.sid, data) + return auth.UpdateSession(db.DefaultContext, s.sid, data) } // Flush deletes all session data. @@ -97,7 +98,7 @@ func (p *DBProvider) Init(maxLifetime int64, connStr string) error { // Read returns raw session store by session ID. func (p *DBProvider) Read(sid string) (session.RawStore, error) { - s, err := auth.ReadSession(sid) + s, err := auth.ReadSession(db.DefaultContext, sid) if err != nil { return nil, err } @@ -117,7 +118,7 @@ func (p *DBProvider) Read(sid string) (session.RawStore, error) { // Exist returns true if session with given ID exists. func (p *DBProvider) Exist(sid string) bool { - has, err := auth.ExistSession(sid) + has, err := auth.ExistSession(db.DefaultContext, sid) if err != nil { panic("session/DB: error checking existence: " + err.Error()) } @@ -126,12 +127,12 @@ func (p *DBProvider) Exist(sid string) bool { // Destroy deletes a session by session ID. func (p *DBProvider) Destroy(sid string) error { - return auth.DestroySession(sid) + return auth.DestroySession(db.DefaultContext, sid) } // Regenerate regenerates a session store from old session ID to new one. func (p *DBProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err error) { - s, err := auth.RegenerateSession(oldsid, sid) + s, err := auth.RegenerateSession(db.DefaultContext, oldsid, sid) if err != nil { return nil, err } @@ -151,7 +152,7 @@ func (p *DBProvider) Regenerate(oldsid, sid string) (_ session.RawStore, err err // Count counts and returns number of sessions. func (p *DBProvider) Count() int { - total, err := auth.CountSessions() + total, err := auth.CountSessions(db.DefaultContext) if err != nil { panic("session/DB: error counting records: " + err.Error()) } @@ -160,7 +161,7 @@ func (p *DBProvider) Count() int { // GC calls GC to clean expired sessions. func (p *DBProvider) GC() { - if err := auth.CleanupSessions(p.maxLifetime); err != nil { + if err := auth.CleanupSessions(db.DefaultContext, p.maxLifetime); err != nil { log.Printf("session/DB: error garbage collecting: %v", err) } } diff --git a/modules/setting/actions.go b/modules/setting/actions.go index bfc502c0cbe..026bab4bfcf 100644 --- a/modules/setting/actions.go +++ b/modules/setting/actions.go @@ -6,6 +6,7 @@ package setting import ( "fmt" "strings" + "time" "code.gitea.io/gitea/modules/log" ) @@ -18,8 +19,11 @@ var ( ArtifactRetentionDays int64 `ini:"ARTIFACT_RETENTION_DAYS"` Enabled bool DefaultActionsURL defaultActionsURL `ini:"DEFAULT_ACTIONS_URL"` + ZombieTaskTimeout time.Duration `ini:"ZOMBIE_TASK_TIMEOUT"` + EndlessTaskTimeout time.Duration `ini:"ENDLESS_TASK_TIMEOUT"` + AbandonedJobTimeout time.Duration `ini:"ABANDONED_JOB_TIMEOUT"` }{ - Enabled: false, + Enabled: true, DefaultActionsURL: defaultActionsURLGitHub, } ) @@ -82,5 +86,9 @@ func loadActionsFrom(rootCfg ConfigProvider) error { Actions.ArtifactRetentionDays = 90 } + Actions.ZombieTaskTimeout = sec.Key("ZOMBIE_TASK_TIMEOUT").MustDuration(10 * time.Minute) + Actions.EndlessTaskTimeout = sec.Key("ENDLESS_TASK_TIMEOUT").MustDuration(3 * time.Hour) + Actions.AbandonedJobTimeout = sec.Key("ABANDONED_JOB_TIMEOUT").MustDuration(24 * time.Hour) + return err } diff --git a/modules/setting/server.go b/modules/setting/server.go index 08eb82fb3de..d053fee5e76 100644 --- a/modules/setting/server.go +++ b/modules/setting/server.go @@ -81,7 +81,6 @@ var ( StaticCacheTime time.Duration EnableGzip bool LandingPageURL LandingPage - LandingPageCustom string UnixSocketPermission uint32 EnablePprof bool PprofDataPath string @@ -103,7 +102,6 @@ var ( StaticURLPrefix string AbsoluteAssetURL string - HasRobotsTxt bool ManifestData string ) diff --git a/modules/structs/mirror.go b/modules/structs/mirror.go index 55cd133a4fc..8259583cded 100644 --- a/modules/structs/mirror.go +++ b/modules/structs/mirror.go @@ -3,6 +3,8 @@ package structs +import "time" + // CreatePushMirrorOption represents need information to create a push mirror of a repository. type CreatePushMirrorOption struct { RemoteAddress string `json:"remote_address"` @@ -15,12 +17,14 @@ type CreatePushMirrorOption struct { // PushMirror represents information of a push mirror // swagger:model type PushMirror struct { - RepoName string `json:"repo_name"` - RemoteName string `json:"remote_name"` - RemoteAddress string `json:"remote_address"` - CreatedUnix string `json:"created"` - LastUpdateUnix string `json:"last_update"` - LastError string `json:"last_error"` - Interval string `json:"interval"` - SyncOnCommit bool `json:"sync_on_commit"` + RepoName string `json:"repo_name"` + RemoteName string `json:"remote_name"` + RemoteAddress string `json:"remote_address"` + // swagger:strfmt date-time + CreatedUnix time.Time `json:"created"` + // swagger:strfmt date-time + LastUpdateUnix *time.Time `json:"last_update"` + LastError string `json:"last_error"` + Interval string `json:"interval"` + SyncOnCommit bool `json:"sync_on_commit"` } diff --git a/modules/structs/repo.go b/modules/structs/repo.go index 556607323d6..4fb0b338e42 100644 --- a/modules/structs/repo.go +++ b/modules/structs/repo.go @@ -63,6 +63,7 @@ type Repository struct { Language string `json:"language"` LanguagesURL string `json:"languages_url"` HTMLURL string `json:"html_url"` + URL string `json:"url"` Link string `json:"link"` SSHURL string `json:"ssh_url"` CloneURL string `json:"clone_url"` diff --git a/modules/system/appstate_test.go b/modules/system/appstate_test.go index 65a6e500033..232362cf0c8 100644 --- a/modules/system/appstate_test.go +++ b/modules/system/appstate_test.go @@ -4,7 +4,6 @@ package system import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,8 +13,7 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - FixtureFiles: []string{""}, // load nothing + FixtureFiles: []string{""}, // load nothing }) } diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go index 7700a13932b..fe02e4b0c31 100644 --- a/modules/templates/util_misc.go +++ b/modules/templates/util_misc.go @@ -58,11 +58,11 @@ func IsMultilineCommitMessage(msg string) bool { // Actioner describes an action type Actioner interface { GetOpType() activities_model.ActionType - GetActUserName() string - GetRepoUserName() string - GetRepoName() string - GetRepoPath() string - GetRepoLink() string + GetActUserName(ctx context.Context) string + GetRepoUserName(ctx context.Context) string + GetRepoName(ctx context.Context) string + GetRepoPath(ctx context.Context) string + GetRepoLink(ctx context.Context) string GetBranch() string GetContent() string GetCreate() time.Time diff --git a/modules/util/path.go b/modules/util/path.go index 58258560dde..e8537fb6b9b 100644 --- a/modules/util/path.go +++ b/modules/util/path.go @@ -225,6 +225,7 @@ func isOSWindows() bool { var driveLetterRegexp = regexp.MustCompile("/[A-Za-z]:/") // FileURLToPath extracts the path information from a file://... url. +// It returns an error only if the URL is not a file URL. func FileURLToPath(u *url.URL) (string, error) { if u.Scheme != "file" { return "", errors.New("URL scheme is not 'file': " + u.String()) diff --git a/modules/util/url.go b/modules/util/url.go index 75fcf634a96..62370339c8d 100644 --- a/modules/util/url.go +++ b/modules/util/url.go @@ -39,3 +39,12 @@ func URLJoin(base string, elems ...string) string { } return joinedURL } + +func SanitizeURL(s string) (string, error) { + u, err := url.Parse(s) + if err != nil { + return "", err + } + u.User = nil + return u.String(), nil +} diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index 9497dc02e23..08d83f94be7 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -47,8 +47,6 @@ func GetContextData(c context.Context) ContextData { func CommonTemplateContextData() ContextData { return ContextData{ - "IsLandingPageHome": setting.LandingPageURL == setting.LandingPageHome, - "IsLandingPageExplore": setting.LandingPageURL == setting.LandingPageExplore, "IsLandingPageOrganizations": setting.LandingPageURL == setting.LandingPageOrganizations, "ShowRegistrationButton": setting.Service.ShowRegistrationButton, diff --git a/options/license/Adobe-Utopia b/options/license/Adobe-Utopia new file mode 100644 index 00000000000..4aa04503b54 --- /dev/null +++ b/options/license/Adobe-Utopia @@ -0,0 +1,12 @@ +Permission to use, reproduce, display and distribute the listed typefaces +is hereby granted, provided that the Adobe Copyright notice appears in all +whole and partial copies of the software and that the following trademark +symbol and attribution appear in all unmodified copies of the software: + +The Adobe typefaces (Type 1 font program, bitmaps and Adobe Font Metric +files) donated are: + + Utopia Regular + Utopia Italic + Utopia Bold + Utopia Bold Italic diff --git a/options/license/BSD-3-Clause-HP b/options/license/BSD-3-Clause-HP new file mode 100644 index 00000000000..e16195729ad --- /dev/null +++ b/options/license/BSD-3-Clause-HP @@ -0,0 +1,23 @@ +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the HP nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +NOT LIMITED TO, PATENT INFRINGEMENT; PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING +IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/options/license/BSD-3-Clause-Sun b/options/license/BSD-3-Clause-Sun new file mode 100644 index 00000000000..1d86449d90a --- /dev/null +++ b/options/license/BSD-3-Clause-Sun @@ -0,0 +1,29 @@ +Copyright (c) 2001-2013 Oracle and/or its affiliates. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +- Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistribution in binary form must reproduct the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +Neither the name of Sun Microsystems, Inc. or the names of +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +This software is provided "AS IS," without a warranty of any kind. ALL +EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, +INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND +ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES OR LIABILITIES +SUFFERED BY LICENSEE AS A RESULT OF OR RELATING TO USE, MODIFICATION +OR DISTRIBUTION OF THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL +SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, +OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR +PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF +LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE SOFTWARE, +EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/options/license/BSD-Inferno-Nettverk b/options/license/BSD-Inferno-Nettverk new file mode 100644 index 00000000000..d10fe158a11 --- /dev/null +++ b/options/license/BSD-Inferno-Nettverk @@ -0,0 +1,41 @@ + Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, + 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016 + 2017, 2018, 2019, 2020 + Inferno Nettverk A/S, Norway. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. The above copyright notice, this list of conditions and the following + disclaimer must appear in all copies of the software, derivative works + or modified versions, and any portions thereof, aswell as in all + supporting documentation. + 2. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by + Inferno Nettverk A/S, Norway. + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + Inferno Nettverk A/S requests users of this software to return to + + Software Distribution Coordinator or sdc@inet.no + Inferno Nettverk A/S + Oslo Research Park + Gaustadalléen 21 + NO-0349 Oslo + Norway + + any improvements or extensions that they make and grant Inferno Nettverk A/S + the rights to redistribute these changes. diff --git a/options/license/BSD-Systemics b/options/license/BSD-Systemics new file mode 100644 index 00000000000..6ca8a26c330 --- /dev/null +++ b/options/license/BSD-Systemics @@ -0,0 +1,39 @@ +Copyright (C) 1995, 1996 Systemics Ltd (http://www.systemics.com/) +All rights reserved. + +This library and applications are FREE FOR COMMERCIAL AND NON-COMMERCIAL USE +as long as the following conditions are adhered to. + +Copyright remains with Systemics Ltd, and as such any Copyright notices +in the code are not to be removed. If this code is used in a product, +Systemics should be given attribution as the author of the parts used. +This can be in the form of a textual message at program startup or +in documentation (online or textual) provided with the package. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by Systemics Ltd (http://www.systemics.com/) + +THIS SOFTWARE IS PROVIDED BY SYSTEMICS LTD ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +The licence and distribution terms for any publically available version or +derivative of this code cannot be changed. i.e. this code cannot simply be +copied and put under another distribution licence [including the GNU Public Licence.] diff --git a/options/license/Cronyx b/options/license/Cronyx new file mode 100644 index 00000000000..10fa8e70673 --- /dev/null +++ b/options/license/Cronyx @@ -0,0 +1,11 @@ +This package contains a set of Russian fonts for X11 Release 6. +Copyright (C) 1994-1995 Cronyx Ltd. +Changes Copyright (C) 1996 by Sergey Vovk +Changes Copyright (C) 1999-2000 by Serge Winitzki +Changes Copyright (C) 1996-2000 by Andrey A. Chernov, Moscow, Russia. + +This software may be used, modified, copied, distributed, and sold, +in both source and binary form provided that the copyright +and these terms are retained. Under no circumstances is the author +responsible for the proper functioning of this software, nor does +the author assume any responsibility for damages incurred with its use. diff --git a/options/license/Crossword b/options/license/Crossword index 6be940c33bb..35d95a79d71 100644 --- a/options/license/Crossword +++ b/options/license/Crossword @@ -1,5 +1,5 @@ Copyright (C) 1995-2009 Gerd Neugebauer cwpuzzle.dtx is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. -. + Everyone is granted permission to copy, modify and redistribute cwpuzzle.dtx, provided this copyright notice is preserved and any modifications are indicated. diff --git a/options/license/DL-DE-ZERO-2.0 b/options/license/DL-DE-ZERO-2.0 new file mode 100644 index 00000000000..7daacde13d3 --- /dev/null +++ b/options/license/DL-DE-ZERO-2.0 @@ -0,0 +1,25 @@ +DL-DE->Zero-2.0 +Datenlizenz Deutschland – Zero – Version 2.0 + +Jede Nutzung ist ohne Einschränkungen oder Bedingungen zulässig. + +Die bereitgestellten Daten und Metadaten dürfen für die kommerzielle und nicht kommerzielle Nutzung insbesondere + + vervielfältigt, ausgedruckt, präsentiert, verändert, bearbeitet sowie an Dritte übermittelt werden; + mit eigenen Daten und Daten Anderer zusammengeführt und zu selbständigen neuen Datensätzen verbunden werden; + in interne und externe Geschäftsprozesse, Produkte und Anwendungen in öffentlichen und nicht öffentlichen elektronischen Netzwerken eingebunden werden. + + +Data licence Germany – Zero – version 2.0 + +Any use is permitted without restrictions or conditions. + +The data and meta-data provided may, for commercial and non-commercial use, in particular + + be copied, printed, presented, altered, processed and transmitted to third parties; + be merged with own data and with the data of others and be combined to form new and independent datasets; + be integrated in internal and external business processes, products and applications in public and non-public electronic networks. + + + +URL: https://www.govdata.de/dl-de/zero-2-0 diff --git a/options/license/FBM b/options/license/FBM new file mode 100644 index 00000000000..68d9149b903 --- /dev/null +++ b/options/license/FBM @@ -0,0 +1,6 @@ +Portions of this code Copyright (C) 1989 by Michael Mauldin. +Permission is granted to use this file in whole or in +part for any purpose, educational, recreational or commercial, +provided that this copyright notice is retained unchanged. +This software is available to all free of charge by anonymous +FTP and in the UUNET archives. diff --git a/options/license/Ferguson-Twofish b/options/license/Ferguson-Twofish new file mode 100644 index 00000000000..43bb00c3ee7 --- /dev/null +++ b/options/license/Ferguson-Twofish @@ -0,0 +1,15 @@ + The author hereby grants a perpetual license to everybody to + use this code for any purpose as long as the copyright message is included + in the source code of this or any derived work. + + Yes, this means that you, your company, your club, and anyone else + can use this code anywhere you want. You can change it and distribute it + under the GPL, include it in your commercial product without releasing + the source code, put it on the web, etc. + The only thing you cannot do is remove my copyright message, + or distribute any source code based on this implementation that does not + include my copyright message. + + I appreciate a mention in the documentation or credits, + but I understand if that is difficult to do. + I also appreciate it if you tell me where and why you used my code. diff --git a/options/license/Furuseth b/options/license/Furuseth new file mode 100644 index 00000000000..55feeef90b8 --- /dev/null +++ b/options/license/Furuseth @@ -0,0 +1,13 @@ +Portions Copyright 1999-2008 Howard Y.H. Chu. +Portions Copyright 1999-2008 Symas Corporation. +Portions Copyright 1998-2003 Hallvard B. Furuseth. +Portions Copyright 2007-2011 Gavin Henry. +Portions Copyright 2007-2011 Suretec Systems Ltd. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that this notice is preserved. +The names of the copyright holders may not be used to endorse or +promote products derived from this software without their specific +prior written permission. This software is provided ``as is'' +without express or implied warranty. diff --git a/options/license/HPND b/options/license/HPND index 74abede5f6b..ff9ae1b7134 100644 --- a/options/license/HPND +++ b/options/license/HPND @@ -1,7 +1,7 @@ Historical Permission Notice and Disclaimer - +Copyright -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 the copyright notice and this permission notice appear in supporting documentation, and that the name of or not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. +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 or not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,. IN NO EVENT SHALL 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. diff --git a/options/license/HPND-DEC b/options/license/HPND-DEC new file mode 100644 index 00000000000..d014f1fabce --- /dev/null +++ b/options/license/HPND-DEC @@ -0,0 +1,22 @@ +COPYRIGHT 1990 +DIGITAL EQUIPMENT CORPORATION +MAYNARD, MASSACHUSETTS +ALL RIGHTS RESERVED. + +THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION. +DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE +FOR ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED +WARRANTY. + +IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT +RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN +ADDITION TO THAT SET FORTH ABOVE. + +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 Digital Equipment Corporation not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. diff --git a/options/license/HPND-Pbmplus b/options/license/HPND-Pbmplus new file mode 100644 index 00000000000..5627d2646f8 --- /dev/null +++ b/options/license/HPND-Pbmplus @@ -0,0 +1,8 @@ +Copyright (C) 1991 by Jef Poskanzer. + +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. This software is provided "as is" without express or +implied warranty. diff --git a/options/license/HPND-UC b/options/license/HPND-UC new file mode 100644 index 00000000000..adfbd238628 --- /dev/null +++ b/options/license/HPND-UC @@ -0,0 +1,8 @@ +Copyright 1989 Regents of the University of California + +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. The University of California makes +no representations about the suitability of this software for any purpose. +It is provided "as is" without express or implied warranty. diff --git a/options/license/HPND-doc b/options/license/HPND-doc new file mode 100644 index 00000000000..bd85a2816e5 --- /dev/null +++ b/options/license/HPND-doc @@ -0,0 +1,8 @@ +Copyright + +Permission to use, copy, modify, and distribute this documentation for +any purpose and without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + makes no representations about the suitability for +any purpose of the information in this document. This documentation is +provided ``as is'' without express or implied warranty. diff --git a/options/license/HPND-doc-sell b/options/license/HPND-doc-sell new file mode 100644 index 00000000000..ad4aed3e608 --- /dev/null +++ b/options/license/HPND-doc-sell @@ -0,0 +1,9 @@ +Copyright + +Permission to use, copy, modify, distribute, and sell this +documentation for any purpose is hereby granted without fee, +provided that the above copyright notice and this permission +notice appear in all copies. +makes no representations about the suitability for any purpose +of the information in this document. This documentation +is provided "as is" without express or implied warranty. diff --git a/options/license/HPND-export-US-modify b/options/license/HPND-export-US-modify new file mode 100644 index 00000000000..3c62651c0f4 --- /dev/null +++ b/options/license/HPND-export-US-modify @@ -0,0 +1,24 @@ +Copyright (C) 1994 CyberSAFE Corporation. +Copyright 1990,1991,2007,2008 by the Massachusetts +Institute of Technology. +All Rights Reserved. + +Export of this software from the United States of America may +require a specific license from the United States Government. It +is the responsibility of any person or organization +contemplating export to obtain such a license before exporting. + +WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +distribute this software and its documentation for any purpose and +without fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright notice and +this permission notice appear in supporting documentation, and that +the name of M.I.T. not be used in advertising or publicity +pertaining to distribution of the software without specific, +written prior permission. Furthermore if you modify this software +you must label your software as modified software and not +distribute it in such a fashion that it might be confused with the +original M.I.T. software. Neither M.I.T., the Open Computing +Security Group, nor CyberSAFE Corporation make any representations +about the suitability of this software for any purpose. It is +provided "as is" without express or implied warranty. diff --git a/options/license/HPND-sell-regexpr b/options/license/HPND-sell-regexpr new file mode 100644 index 00000000000..b0cd0fb1126 --- /dev/null +++ b/options/license/HPND-sell-regexpr @@ -0,0 +1,9 @@ +Author: Tatu Ylonen + +Copyright (c) 1991 Tatu Ylonen, Espoo, Finland + +Permission to use, copy, modify, distribute, and sell this software +and its documentation for any purpose is hereby granted without +fee, provided that the above copyright notice appear in all copies. +This software is provided "as is" without express or implied +warranty. diff --git a/options/license/Kastrup b/options/license/Kastrup new file mode 100644 index 00000000000..46d1e9e0e49 --- /dev/null +++ b/options/license/Kastrup @@ -0,0 +1,3 @@ +Copyright(c) 2001 by David Kastrup +Any use of the code is permitted as long as this copyright +notice is preserved in the code. diff --git a/options/license/Lucida-Bitmap-Fonts b/options/license/Lucida-Bitmap-Fonts new file mode 100644 index 00000000000..35be63ed33d --- /dev/null +++ b/options/license/Lucida-Bitmap-Fonts @@ -0,0 +1,53 @@ +This is the LEGAL NOTICE pertaining to the Lucida fonts from Bigelow & Holmes: + + NOTICE TO USER: The source code, including the glyphs or icons + forming a par of the OPEN LOOK TM Graphic User Interface, on this + tape and in these files is copyrighted under U.S. and international + laws. Sun Microsystems, Inc. of Mountain View, California owns + the copyright and has design patents pending on many of the icons. + AT&T is the owner of the OPEN LOOK trademark associated with the + materials on this tape. Users and possessors of this source code + are hereby granted a nonexclusive, royalty-free copyright and + design patent license to use this code in individual and + commercial software. A royalty-free, nonexclusive trademark + license to refer to the code and output as "OPEN LOOK" compatible + is available from AT&T if, and only if, the appearance of the + icons or glyphs is not changed in any manner except as absolutely + necessary to accommodate the standard resolution of the screen or + other output device, the code and output is not changed except as + authorized herein, and the code and output is validated by AT&T. + Bigelow & Holmes is the owner of the Lucida (R) trademark for the + fonts and bit-mapped images associated with the materials on this + tape. Users are granted a royalty-free, nonexclusive license to use + the trademark only to identify the fonts and bit-mapped images if, + and only if, the fonts and bit-mapped images are not modified in any + way by the user. + + Any use of this source code must include, in the user documentation + and internal comments to the code, notices to the end user as + follows: + + (c) Copyright 1989 Sun Microsystems, Inc. Sun design patents + pending in the U.S. and foreign countries. OPEN LOOK is a + trademark of AT&T. Used by written permission of the owners. + + (c) Copyright Bigelow & Holmes 1986, 1985. Lucida is a registered + trademark of Bigelow & Holmes. Permission to use the Lucida + trademark is hereby granted only in association with the images + and fonts described in this file. + + SUN MICROSYSTEMS, INC., AT&T, AND BIGELOW & HOLMES + MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY OF + THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" + WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. + SUN MICROSYSTEMS, INC., AT&T AND BIGELOW & HOLMES, + SEVERALLY AND INDIVIDUALLY, DISCLAIM ALL WARRANTIES + WITH REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE. IN NO EVENT SHALL SUN MICROSYSTEMS, + INC., AT&T OR BIGELOW & HOLMES BE LIABLE FOR ANY + SPECIAL, INDIRECT, INCIDENTAL, 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 SOURCE CODE. diff --git a/options/license/MPEG-SSG b/options/license/MPEG-SSG new file mode 100644 index 00000000000..a0b6f4ffff5 --- /dev/null +++ b/options/license/MPEG-SSG @@ -0,0 +1,23 @@ +Copyright (C) 1994, MPEG Software Simulation Group. All Rights Reserved. */ + +Disclaimer of Warranty + +These software programs are available to the user without any license fee or +royalty on an "as is" basis. The MPEG Software Simulation Group disclaims +any and all warranties, whether express, implied, or statuary, including any +implied warranties or merchantability or of fitness for a particular +purpose. In no event shall the copyright-holder be liable for any +incidental, punitive, or consequential damages of any kind whatsoever +arising from the use of these programs. + +This disclaimer of warranty extends to the user of these programs and user's +customers, employees, agents, transferees, successors, and assigns. + +The MPEG Software Simulation Group does not represent or warrant that the +programs furnished hereunder are free of infringement of any third-party +patents. + +Commercial implementations of MPEG-1 and MPEG-2 video, including shareware, +are subject to royalty fees to patent holders. Many of these patents are +general enough such that they are unavoidable regardless of implementation +design. diff --git a/options/license/McPhee-slideshow b/options/license/McPhee-slideshow new file mode 100644 index 00000000000..0ddf7ba3506 --- /dev/null +++ b/options/license/McPhee-slideshow @@ -0,0 +1,6 @@ +Copyright 2001, Patrick TJ McPhee +everyone is welcome to use this code for any purpose, to modify it, and +to copy it in whole or in part for use in other macro sets, with the +conditions that this copyright notice be preserved with any significant +portion of the code, and that modifications to this file be clearly +marked. diff --git a/options/license/NPL-1.0 b/options/license/NPL-1.0 index 7a5030e9f71..65983791a2c 100644 --- a/options/license/NPL-1.0 +++ b/options/license/NPL-1.0 @@ -8,20 +8,20 @@ NETSCAPE PUBLIC LICENSE Version 1.0 1.3. ``Covered Code'' means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. ``Electronic Distribution Mechanism'' means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. ``Executable'' means Covered Code in any form other than Source Code. - 1.6. ``Initial Developer'' means the individual or entity identified as the Initial Developer in the Source Code notice required byExhibit A. + 1.6. ``Initial Developer'' means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. ``Larger Work'' means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. ``License'' means this document. 1.9. ``Modifications'' means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. - 1.10. ``Original Code'' means Source Code of computer software code which is described in the Source Code notice required byExhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. + 1.10. ``Original Code'' means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.11. ``Source Code'' means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or a list of source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. ``You'' means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, ``You'' includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, ``control'' means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of fifty percent (50%) or more of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: - a) to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, or as part of a Larger Work; and + (a) to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, or as part of a Larger Work; and (b) under patents now or hereafter owned or controlled by Initial Developer, to make, have made, use and sell (``Utilize'') the Original Code (or portions thereof), but solely to the extent that any such patent is reasonably necessary to enable You to Utilize the Original Code (or portions thereof) and not to any greater extent that may be necessary to Utilize further Modifications or combinations. 2.2. Contributor Grant. Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: diff --git a/options/license/PADL b/options/license/PADL new file mode 100644 index 00000000000..84ba0b4db99 --- /dev/null +++ b/options/license/PADL @@ -0,0 +1,6 @@ +Portions (C) Copyright PADL Software Pty Ltd. 1999 + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that this notice is preserved +and that due credit is given to PADL Software Pty Ltd. This software +is provided ``as is'' without express or implied warranty. diff --git a/options/license/SGI-OpenGL b/options/license/SGI-OpenGL new file mode 100644 index 00000000000..2b4c542aa03 --- /dev/null +++ b/options/license/SGI-OpenGL @@ -0,0 +1,34 @@ +(c) Copyright 1993, Silicon Graphics, Inc. +ALL RIGHTS RESERVED +Permission to use, copy, modify, and distribute this software for +any purpose and without fee is hereby granted, provided that the above +copyright notice appear in all copies and that both the copyright notice +and this permission notice appear in supporting documentation, and that +the name of Silicon Graphics, Inc. not be used in advertising +or publicity pertaining to distribution of the software without specific, +written prior permission. + +THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" +AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, +INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR +FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON +GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT, +SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY +KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, +LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF +THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN +ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE +POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE. + +US Government Users Restricted Rights +Use, duplication, or disclosure by the Government is subject to +restrictions set forth in FAR 52.227.19(c)(2) or subparagraph +(c)(1)(ii) of the Rights in Technical Data and Computer Software +clause at DFARS 252.227-7013 and/or in similar or successor +clauses in the FAR or the DOD or NASA FAR Supplement. +Unpublished-- rights reserved under the copyright laws of the +United States. Contractor/manufacturer is Silicon Graphics, +Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311. + +OpenGL(TM) is a trademark of Silicon Graphics, Inc. diff --git a/options/license/UBDL-exception b/options/license/UBDL-exception new file mode 100644 index 00000000000..780ddcd775a --- /dev/null +++ b/options/license/UBDL-exception @@ -0,0 +1,59 @@ +UNMODIFIED BINARY DISTRIBUTION LICENCE + + +PREAMBLE + +The GNU General Public License provides a legal guarantee that +software covered by it remains free (in the sense of freedom, not +price). It achieves this guarantee by imposing obligations on anyone +who chooses to distribute the software. + +Some of these obligations may be seen as unnecessarily burdensome. In +particular, when the source code for the software is already publicly +and freely available, there is minimal value in imposing upon each +distributor the obligation to provide the complete source code (or an +equivalent written offer to provide the complete source code). + +This Licence allows for the distribution of unmodified binaries built +from publicly available source code, without imposing the obligations +of the GNU General Public License upon anyone who chooses to +distribute only the unmodified binaries built from that source code. + +The extra permissions granted by this Licence apply only to unmodified +binaries built from source code which has already been made available +to the public in accordance with the terms of the GNU General Public +Licence. Nothing in this Licence allows for the creation of +closed-source modified versions of the Program. Any modified versions +of the Program are subject to the usual terms and conditions of the +GNU General Public License. + + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +This Licence applies to any Program or other work which contains a +notice placed by the copyright holder saying it may be distributed +under the terms of this Unmodified Binary Distribution Licence. All +terms used in the text of this Licence are to be interpreted as they +are used in version 2 of the GNU General Public License as published +by the Free Software Foundation. + +If you have made this Program available to the public in both source +code and executable form in accordance with the terms of the GNU +General Public License as published by the Free Software Foundation; +either version 2 of the License, or (at your option) any later +version, then you are hereby granted an additional permission to use, +copy, and distribute the unmodified executable form of this Program +(the "Unmodified Binary") without restriction, including the right to +permit persons to whom the Unmodified Binary is furnished to do +likewise, subject to the following conditions: + +- when started running, the Program must display an announcement which + includes the details of your existing publication of the Program + made in accordance with the terms of the GNU General Public License. + For example, the Program could display the URL of the publicly + available source code from which the Unmodified Binary was built. + +- when exercising your right to grant permissions under this Licence, + you do not need to refer directly to the text of this Licence, but + you may not grant permissions beyond those granted to you by this + Licence. diff --git a/options/license/fwlw b/options/license/fwlw new file mode 100644 index 00000000000..472a85a5644 --- /dev/null +++ b/options/license/fwlw @@ -0,0 +1,5 @@ +Copyright (C) 1993,1995 by Donald Arseneau +Vancouver, Canada, email asnd@triumf.ca + +This software package may be freely used, transmitted, reproduced, or modified provided that +this notice is left intact. diff --git a/options/license/lsof b/options/license/lsof new file mode 100644 index 00000000000..279721a90a6 --- /dev/null +++ b/options/license/lsof @@ -0,0 +1,26 @@ +Copyright 2002 Purdue Research Foundation, West Lafayette, +Indiana 47907. All rights reserved. + +Written by Victor A. Abell + +This software is not subject to any license of the American +Telephone and Telegraph Company or the Regents of the +University of California. + +Permission is granted to anyone to use this software for +any purpose on any computer system, and to alter it and +redistribute it freely, subject to the following +restrictions: + +1. Neither the authors nor Purdue University are responsible + for any consequences of the use of this software. + +2. The origin of this software must not be misrepresented, + either by explicit claim or by omission. Credit to the + authors and Purdue University must appear in documentation + and sources. + +3. Altered versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. This notice may not be removed or altered. diff --git a/options/license/magaz b/options/license/magaz new file mode 100644 index 00000000000..34d033c03eb --- /dev/null +++ b/options/license/magaz @@ -0,0 +1,4 @@ +Copyright 1999-2011, Donald Arseneau, asnd@triumf.ca, Vancouver, Canada + +This software may be freely used, transmitted, reproduced, or modified provided that +the copyright notice and this permission is retained. diff --git a/options/license/pnmstitch b/options/license/pnmstitch new file mode 100644 index 00000000000..cb9dc762d91 --- /dev/null +++ b/options/license/pnmstitch @@ -0,0 +1,23 @@ +Copyright (c) 2002 Mark Salyzyn +All rights reserved. + +TERMS AND CONDITIONS OF USE + +Redistribution and use in source form, with or without modification, are +permitted provided that redistributions of source code must retain the +above copyright notice, this list of conditions and the following +disclaimer. + +This software is provided `as is' by Mark Salyzyn and any express or implied +warranties, including, but not limited to, the implied warranties of +merchantability and fitness for a particular purpose, are disclaimed. In no +event shall Mark Salyzyn be liable for any direct, indirect, incidental, +special, exemplary or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or profits; +or business interruptions) however caused and on any theory of liability, +whether in contract, strict liability, or tort (including negligence or +otherwise) arising in any way out of the use of this software, even if +advised of the possibility of such damage. + +Any restrictions or encumberances added to this source code or derivitives, +is prohibited. diff --git a/options/license/python-ldap b/options/license/python-ldap new file mode 100644 index 00000000000..733e8cfc0af --- /dev/null +++ b/options/license/python-ldap @@ -0,0 +1,10 @@ +The python-ldap package is distributed under Python-style license. + +Standard disclaimer: + This software is made available by the author(s) to the public for free + and "as is". All users of this free software are solely and entirely + responsible for their own choice and use of this software for their + own purposes. By using this software, each user agrees that the + author(s) shall not be liable for damages of any kind in relation to + its use or performance. The author(s) do not warrant that this software + is fit for any purpose. diff --git a/options/license/ssh-keyscan b/options/license/ssh-keyscan new file mode 100644 index 00000000000..6c97472c1eb --- /dev/null +++ b/options/license/ssh-keyscan @@ -0,0 +1,5 @@ +* Copyright 1995, 1996 by David Mazieres . +* +* Modification and redistribution in source and binary forms is +* permitted provided that due credit is given to the author and the +* OpenBSD project by leaving this copyright notice intact. diff --git a/options/license/swrule b/options/license/swrule new file mode 100644 index 00000000000..aebc5fd6d3d --- /dev/null +++ b/options/license/swrule @@ -0,0 +1 @@ +The style package is copyrighted but may be used and extended in any way, as long as a pointer to the original author is maintained. The author is not liable for any problem that may or may not result from using this package. Use at your own risk. diff --git a/options/license/ulem b/options/license/ulem new file mode 100644 index 00000000000..ee49efe8dd2 --- /dev/null +++ b/options/license/ulem @@ -0,0 +1,4 @@ +Copyright 1989-2019 by Donald Arseneau (Vancouver, Canada, asnd@triumf.ca) + +This software may be freely transmitted, reproduced, or modified +for any purpose provided that this copyright notice is left intact. diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 819e3e85e87..57c1635c1cd 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -175,7 +175,6 @@ network_error=Chyba sítě [startpage] app_desc=Snadno přístupný vlastní Git install=Jednoduchá na instalaci -install_desc=Jednoduše spusťte binárku pro vaši platformu, nasaďte ji pomocí Docker, nebo ji získejte zbalíčku. platform=Multiplatformní platform_desc=Gitea běží všude, kde Go může kompilovat: Windows, macOS, Linux, ARM, atd. Vyberte si ten, který milujete! lightweight=Lehká @@ -308,6 +307,7 @@ filter_by_team_repositories=Filtrovat podle repozitářů týmu feed_of=Kanál z „%s“ show_archived=Archivováno +archived=Archivováno show_both_archived_unarchived=Zobrazeny jak archivované tak nearchivované show_only_archived=Zobrazeny pouze archivované show_only_unarchived=Zobrazeny pouze nearchivované @@ -574,7 +574,6 @@ overview=Přehled following=Sledovaní follow=Sledovat unfollow=Přestat sledovat -heatmap.loading=Načítání teplotní mapy… user_bio=Životopis disabled_public_activity=Tento uživatel zakázal veřejnou viditelnost aktivity. email_visibility.limited=Vaše e-mailová adresa je viditelná pro všechny ověřené uživatele @@ -644,7 +643,6 @@ choose_new_avatar=Vybrat nový avatar update_avatar=Aktualizovat avatar delete_current_avatar=Smazat aktuální avatar uploaded_avatar_not_a_image=Nahraný soubor není obrázek. -uploaded_avatar_is_too_big=Nahraný soubor překročil maximální velikost. update_avatar_success=Vaše avatar byl aktualizován. update_user_avatar_success=Uživatelův avatar byl aktualizován. @@ -1192,6 +1190,11 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=Vyberte větev pro Cherry-pick na: +commitstatus.error=Chyba +commitstatus.failure=Chyba +commitstatus.pending=Čekající +commitstatus.success=Úspěch + ext_issues=Přístup k externím úkolům ext_issues.desc=Odkaz na externí systém úkolů. @@ -1379,9 +1382,9 @@ issues.ref_reopening_from=`odkazoval/a na požadavek na natažen issues.ref_closed_from=`uzavřel/a tento úkol %[4]s %[2]s` issues.ref_reopened_from=`znovu otevřel/a tento úkol %[4]s %[2]s` issues.ref_from=`z %[1]s` -issues.poster=Autor -issues.collaborator=Spolupracovník -issues.owner=Vlastník +issues.author=Autor +issues.role.owner=Vlastník +issues.role.member=Člen issues.re_request_review=Znovu požádat o posouzení issues.is_stale=Od tohoto posouzení došlo ke změnám v tomto požadavku na natažení issues.remove_request_review=Odstranit žádost o posouzení @@ -1685,8 +1688,6 @@ milestones.modify=Aktualizovat milník milestones.deletion=Smazat milník milestones.deletion_desc=Odstranění milníku jej smaže ze všech souvisejících úkolů. Pokračovat? milestones.deletion_success=Milník byl odstraněn. -milestones.filter_sort.closest_due_date=Nejbližší datum dokončení -milestones.filter_sort.furthest_due_date=Nejvzdálenější datum dokončení milestones.filter_sort.least_complete=Nejméně dokončené milestones.filter_sort.most_complete=Nejvíce dokončené milestones.filter_sort.most_issues=Nejvíce úkolů @@ -2127,7 +2128,6 @@ settings.tags.protection.allowed.teams=Povolené týmy settings.tags.protection.allowed.noone=Nikdo settings.tags.protection.create=Chránit značku settings.tags.protection.none=Neexistují žádné chráněné značky. -settings.tags.protection.pattern.description=Můžete použít jediné jméno nebo vzor glob nebo regulární výraz, který bude odpovídat více značek. Přečtěte si více v průvodci chráněnými značkami. settings.bot_token=Token pro robota settings.chat_id=ID chatu settings.matrix.homeserver_url=URL adresa Homeserveru @@ -2605,12 +2605,10 @@ packages.size=Velikost packages.published=Publikováno defaulthooks=Výchozí webové háčky -defaulthooks.desc=Webové háčky automaticky vytvářejí HTTP POST dotazy na server při určitých Gitea událostech. Webové háčky definované zde jsou výchozí a budou zkopírovány do všech nových repozitářů. Přečtěte si více v průvodci webovými háčky. defaulthooks.add_webhook=Přidat výchozí webový háček defaulthooks.update_webhook=Aktualizovat výchozí webový háček systemhooks=Systémové webové háčky -systemhooks.desc=Webové háčky automaticky vytvářejí HTTP POST dotazy na server při určitých Gitea událostech. Webové háčky definované zde budou vykonány na všech repozitářích systému, proto prosím zvažte jakékoli důsledky, které to může mít na výkon. Přečtěte si více v průvodci webovými háčky. systemhooks.add_webhook=Přidat systémový webový háček systemhooks.update_webhook=Aktualizovat systémový webový háček @@ -2713,7 +2711,6 @@ auths.tip.google_plus=Získejte klientské pověření OAuth2 z Google API konzo auths.tip.openid_connect=Použijte OpenID URL pro objevování spojení (/.well-known/openid-configuration) k nastavení koncových bodů auths.tip.twitter=Jděte na https://dev.twitter.com/apps, vytvořte aplikaci a ujistěte se, že volba „Allow this application to be used to Sign in with Twitter“ je povolená auths.tip.discord=Registrujte novou aplikaci na https://discordapp.com/developers/applications/me -auths.tip.gitea=Registrovat novou Oauth2 aplikaci. Návod naleznete na https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=Vytvořte novou aplikaci na https://oauth.yandex.com/client/new. Vyberte následující oprávnění z „Yandex.Passport API“ sekce: „Přístup k e-mailové adrese“, „Přístup k uživatelskému avataru“ a „Přístup k uživatelskému jménu, jménu a příjmení, pohlaví“ auths.tip.mastodon=Vložte vlastní URL instance pro mastodon, kterou se chcete autentizovat (nebo použijte výchozí) auths.edit=Upravit zdroj ověřování @@ -2885,8 +2882,6 @@ monitor.queue.exemplar=Typ vzoru monitor.queue.numberworkers=Počet workerů monitor.queue.maxnumberworkers=Maximální počet workerů monitor.queue.numberinqueue=Číslo ve frontě -monitor.queue.review=Konfigurace posouzení -monitor.queue.review_add=Posoudit/přidat workery monitor.queue.settings.title=Nastavení fondu monitor.queue.settings.maxnumberworkers=Maximální počet workerů monitor.queue.settings.maxnumberworkers.placeholder=V současné době %[1]d diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index d9773c0f5ee..e3ee15a873c 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -181,7 +181,6 @@ network_error=Netzwerkfehler [startpage] app_desc=Ein einfacher, selbst gehosteter Git-Service install=Einfach zu installieren -install_desc=Starte einfach die Anwendung für deine Plattform. Oder nutze Docker. Es existieren auch paketierte Versionen. platform=Plattformübergreifend platform_desc=Gitea läuft überall, wo Go kompiliert: Windows, macOS, Linux, ARM, etc. Wähle das System, das dir am meisten gefällt! lightweight=Leichtgewicht @@ -317,6 +316,7 @@ filter_by_team_repositories=Nach Team-Repositories filtern feed_of=`Feed von "%s"` show_archived=Archiviert +archived=Archiviert show_both_archived_unarchived=Archivierte und nicht archivierte anzeigen show_only_archived=Nur archivierte anzeigen show_only_unarchived=Nur nicht archivierte anzeigen @@ -592,7 +592,6 @@ overview=Übersicht following=Folge ich follow=Folgen unfollow=Nicht mehr folgen -heatmap.loading=Heatmap wird geladen… user_bio=Biografie disabled_public_activity=Dieser Benutzer hat die öffentliche Sichtbarkeit der Aktivität deaktiviert. email_visibility.limited=Ihre E-Mail-Adresse ist für alle authentifizierten Benutzer sichtbar @@ -666,7 +665,6 @@ choose_new_avatar=Neues Profilbild auswählen update_avatar=Profilbild aktualisieren delete_current_avatar=Aktuelles Profilbild löschen uploaded_avatar_not_a_image=Die hochgeladene Datei ist kein Bild. -uploaded_avatar_is_too_big=Die hochgeladene Datei hat die maximale Größe überschritten. update_avatar_success=Dein Profilbild wurde geändert. update_user_avatar_success=Der Avatar des Benutzers wurde aktualisiert. @@ -1229,6 +1227,11 @@ commit.cherry-pick=Cherry-Pick commit.cherry-pick-header=Cherry-Picke: %s commit.cherry-pick-content=Branch auswählen, auf dem Cherry-Picked werden soll: +commitstatus.error=Fehler +commitstatus.failure=Fehler +commitstatus.pending=Ausstehend +commitstatus.success=Erfolg + ext_issues=Zugriff auf Externe Issues ext_issues.desc=Link zu externem Issuetracker. @@ -1423,9 +1426,9 @@ issues.ref_reopening_from=`hat auf einen Pull Request %[4]s verw issues.ref_closed_from=`hat dieses Issue %[4]s geschlossen %[2]s` issues.ref_reopened_from=`hat dieses Issue %[4]s %[2]s wieder geöffnet` issues.ref_from=`von %[1]s` -issues.poster=Ersteller -issues.collaborator=Mitarbeiter -issues.owner=Besitzer +issues.author=Autor +issues.role.owner=Besitzer +issues.role.member=Mitglied issues.re_request_review=Review erneut anfordern issues.is_stale=Seit diesem Review gab es Änderungen an diesem PR issues.remove_request_review=Review-Anfrage entfernen @@ -1743,8 +1746,6 @@ milestones.edit_success=Meilenstein "%s" wurde aktualisiert. milestones.deletion=Meilenstein löschen milestones.deletion_desc=Das Löschen des Meilensteins entfernt ihn von allen Issues. Fortfahren? milestones.deletion_success=Der Meilenstein wurde gelöscht. -milestones.filter_sort.closest_due_date=Nächster Stichtag -milestones.filter_sort.furthest_due_date=Fernster Stichtag milestones.filter_sort.least_complete=Am wenigsten vollständig milestones.filter_sort.most_complete=Vollständigste milestones.filter_sort.most_issues=Meiste Issues @@ -2225,7 +2226,6 @@ settings.tags.protection.allowed.teams=Erlaubte Teams settings.tags.protection.allowed.noone=Niemand settings.tags.protection.create=Tag schützen settings.tags.protection.none=Es gibt keine geschützten Tags. -settings.tags.protection.pattern.description=Du kannst einen einzigen Namen oder ein globales Schema oder einen regulären Ausdruck verwenden, um mehrere Tags zu schützen. Mehr dazu im geschützte Tags Guide (Englisch). settings.bot_token=Bot-Token settings.chat_id=Chat-ID settings.matrix.homeserver_url=Homeserver-URL @@ -2740,12 +2740,10 @@ packages.size=Größe packages.published=Veröffentlicht defaulthooks=Standard-Webhooks -defaulthooks.desc=Webhooks senden automatisch eine HTTP-POST-Anfrage an einen Server, wenn bestimmte Gitea-Events ausgelöst werden. Hier definierte Webhooks sind die Standardwerte, die in alle neuen Repositories kopiert werden. Mehr Infos findest du in der Webhooks-Anleitung (auf Englisch). defaulthooks.add_webhook=Standard-Webhook hinzufügen defaulthooks.update_webhook=Standard-Webhook aktualisieren systemhooks=System-Webhooks -systemhooks.desc=Webhooks senden automatisch HTTP-POST-Anfragen an einen Server, wenn bestimmte Gitea-Events ausgelöst werden. Hier definierte Webhooks werden auf alle Repositories des Systems übertragen, beachte daher mögliche Performance-Einbrüche. Mehr Infos findest du in der Webhooks-Anleitung (auf Englisch). systemhooks.add_webhook=System-Webhook hinzufügen systemhooks.update_webhook=System-Webhook aktualisieren @@ -2849,7 +2847,6 @@ auths.tip.google_plus=Du erhältst die OAuth2-Client-Zugangsdaten in der Google- auths.tip.openid_connect=Benutze die OpenID-Connect-Discovery-URL (/.well-known/openid-configuration), um die Endpunkte zu spezifizieren auths.tip.twitter=Gehe auf https://dev.twitter.com/apps, erstelle eine Anwendung und stelle sicher, dass die Option „Allow this application to be used to Sign in with Twitter“ aktiviert ist auths.tip.discord=Erstelle unter https://discordapp.com/developers/applications/me eine neue Anwendung. -auths.tip.gitea=Registriere eine neue OAuth2-Anwendung. Eine Anleitung findest du unter https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Erstelle eine neue Anwendung auf https://oauth.yandex.com/client/new. Wähle folgende Berechtigungen aus dem "Yandex.Passport API" Bereich: "Zugriff auf E-Mail-Adresse", "Zugriff auf Benutzeravatar" und "Zugriff auf Benutzername, Vor- und Nachname, Geschlecht"` auths.tip.mastodon=Gebe eine benutzerdefinierte URL für die Mastodon-Instanz ein, mit der du dich authentifizieren möchtest (oder benutze die standardmäßige) auths.edit=Authentifikationsquelle bearbeiten @@ -3032,8 +3029,6 @@ monitor.queue.exemplar=Beispieltyp monitor.queue.numberworkers=Anzahl der Worker monitor.queue.maxnumberworkers=Maximale Anzahl der Worker monitor.queue.numberinqueue=Nummer in der Warteschlange -monitor.queue.review=Konfiguration überprüfen -monitor.queue.review_add=Worker hinzufügen/prüfen monitor.queue.settings.title=Pool-Einstellungen monitor.queue.settings.desc=Pools wachsen dynamisch basierend auf der Blockierung der Arbeitswarteschlange. monitor.queue.settings.maxnumberworkers=Maximale Anzahl an Workern diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index a07db7132bf..9db3e318f8c 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -175,7 +175,6 @@ network_error=Σφάλμα δικτύου [startpage] app_desc=Μια ανώδυνη, αυτο-φιλοξενούμενη υπηρεσία Git install=Εύκολο στην εγκατάσταση -install_desc=Απλά εκτελέστε το δυαδικό για την πλατφόρμα σας, στείλτε το με Docker, ή πάρτε το πακέτο. platform=Πολυπλατφορμικό platform_desc=Ο Gitea τρέχει οπουδήποτε Go μπορεί να γίνει compile για: Windows, macOS, Linux, ARM, κλπ. Επιλέξτε αυτό που αγαπάτε! lightweight=Ελαφρύ @@ -291,6 +290,7 @@ invalid_password_algorithm=Μη έγκυρος αλγόριθμος κωδικο password_algorithm_helper=Ορίστε τον αλγόριθμο κατακερματισμού για το κωδικό πρόσβασης. Οι αλγόριθμοι διαφέρουν σε απαιτήσεις και αντοχή. Ο αλγόριθμος argon2 είναι αρκετά ασφαλής, αλλά χρησιμοποιεί πολλή μνήμη και μπορεί να είναι ακατάλληλος για μικρά συστήματα. enable_update_checker=Ενεργοποίηση Ελεγκτή Ενημερώσεων enable_update_checker_helper=Ελέγχει περιοδικά για νέες εκδόσεις κάνοντας σύνδεση στο gitea.io. +env_config_keys=Ρυθμίσεις Περιβάλλοντος [home] uname_holder=Όνομα Χρήστη ή Διεύθυνση Email @@ -308,6 +308,7 @@ filter_by_team_repositories=Φιλτράρισμα ανά αποθετήρια feed_of=`Τροφοδοσία του "%s"` show_archived=Αρχειοθετήθηκε +archived=Αρχειοθετήθηκε show_both_archived_unarchived=Εμφάνιση και αρχειοθετημένων και μη αρχειοθετημένων show_only_archived=Εμφάνιση μόνο αρχειοθετημένων show_only_unarchived=Εμφάνιση μόνο μη αρχειοθετημένων @@ -582,7 +583,6 @@ overview=Επισκόπηση following=Ακολουθεί follow=Ακολουθήστε unfollow=Να μην ακολουθώ -heatmap.loading=Φόρτωση heatmap… user_bio=Βιογραφικό disabled_public_activity=Αυτός ο χρήστης έχει απενεργοποιήσει τη δημόσια προβολή της δραστηριότητας. email_visibility.limited=Η διεύθυνση email σας είναι ορατή σε όλους τους ταυτοποιημένους χρήστες @@ -655,7 +655,6 @@ choose_new_avatar=Επιλέξτε νέα εικόνα update_avatar=Ενημέρωση Εικόνας delete_current_avatar=Διαγραφή Τρέχουσας Εικόνας uploaded_avatar_not_a_image=Το αρχείο που ανεβάσατε δεν είναι εικόνα. -uploaded_avatar_is_too_big=Το αρχείο έχει υπερβεί το μέγιστο μέγεθος. update_avatar_success=Η εικόνα σας έχει ενημερωθεί. update_user_avatar_success=Το avatar του χρήστη ενημερώθηκε. @@ -1217,6 +1216,11 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Ανθολόγηση: %s commit.cherry-pick-content=Επιλέξτε κλάδο για να κάνετε ανθολόγηση σε αυτό: +commitstatus.error=Σφάλμα +commitstatus.failure=Αποτυχία +commitstatus.pending=Εκκρεμεί +commitstatus.success=Επιτυχές + ext_issues=Πρόσβαση στα Εξωτερικά Ζητήματα ext_issues.desc=Σύνδεση σε εξωτερικό εφαρμογή ζητημάτων. @@ -1408,9 +1412,9 @@ issues.ref_reopening_from=`αναφέρθηκε σε ένα pull issues.ref_closed_from=`έκλεισε αυτό το ζήτημα %[4]s %[2]s` issues.ref_reopened_from=`άνοιξε ξανά αυτό το ζήτημα %[4]s %[2]s` issues.ref_from=`από %[1]s` -issues.poster=Συντάκτης -issues.collaborator=Συνεργάτης -issues.owner=Ιδιοκτήτης +issues.author=Συγγραφέας +issues.role.owner=Ιδιοκτήτης +issues.role.member=Μέλος issues.re_request_review=Επαναίτηση ανασκόπησης issues.is_stale=Έχουν υπάρξει αλλαγές σε αυτό το PR από αυτή την αναθεώρηση issues.remove_request_review=Αφαίρεση αιτήματος αναθεώρησης @@ -1725,8 +1729,6 @@ milestones.edit_success=Το ορόσημο "%s" ενημερώθηκε. milestones.deletion=Διαγραφή Ορόσημου milestones.deletion_desc=Η διαγραφή ενός ορόσημου το αφαιρεί από όλα τα συναφή ζητήματα. Συνέχεια; milestones.deletion_success=Το ορόσημο έχει διαγραφεί. -milestones.filter_sort.closest_due_date=Πλησιέστερη παράδοση -milestones.filter_sort.furthest_due_date=Απώτερη παράδοση milestones.filter_sort.least_complete=Λιγότερο πλήρη milestones.filter_sort.most_complete=Περισσότερο πλήρη milestones.filter_sort.most_issues=Περισσότερα ζητήματα @@ -2207,7 +2209,6 @@ settings.tags.protection.allowed.teams=Επιτρεπόμενες ομάδες settings.tags.protection.allowed.noone=Καμία settings.tags.protection.create=Προστασία Ετικέτας settings.tags.protection.none=Δεν υπάρχουν προστατευμένες ετικέτες. -settings.tags.protection.pattern.description=Μπορείτε να χρησιμοποιήσετε ένα μόνο όνομα ή ένα μοτίβο glob ή μια κανονική έκφραση για να ταιριάξετε πολλαπλές ετικέτες. Διαβάστε περισσότερα στον οδηγό προστατευμένων ετικετών. settings.bot_token=Διακριτικό Bot settings.chat_id=ID Συνομιλίας settings.matrix.homeserver_url=Homeserver URL @@ -2722,12 +2723,10 @@ packages.size=Μέγεθος packages.published=Δημοσιευμένα defaulthooks=Προεπιλεγμένα Webhooks -defaulthooks.desc=Τα Webhooks κάνουν αυτόματα αιτήσεις HTTP POST σε ένα διακομιστή όταν συμβαίνουν ορισμένα γεγονότα στο Gitea. Τα Webhooks που ορίζονται εδώ είναι προεπιλογή και θα αντιγραφούν σε όλα τα νέα αποθετήρια. Διαβάστε περισσότερα στον οδηγό webhooks. defaulthooks.add_webhook=Προσθήκη Προεπιλεγμένου Webhook defaulthooks.update_webhook=Ενημέρωση Προεπιλεγμένου Webhook systemhooks=Webhooks Συστήματος -systemhooks.desc=Τα Webhooks κάνουν αυτόματα αιτήσεις HTTP POST σε ένα διακομιστή όταν συμβαίνουν ορισμένα γεγονότα στο Gitea. Τα Webhooks που ορίζονται εδώ θα ενεργούν σε όλα τα αποθετήρια του συστήματος, γι 'αυτό παρακαλώ εξετάστε τυχόν επιπτώσεις απόδοσης που μπορεί να υπάρξουν. Διαβάστε περισσότερα στον οδηγό webhooks. systemhooks.add_webhook=Προσθήκη Webhook Συστήματος systemhooks.update_webhook=Ενημέρωση Webhook Συστήματος @@ -2831,7 +2830,6 @@ auths.tip.google_plus=Αποκτήστε τα διαπιστευτήρια πε auths.tip.openid_connect=Χρησιμοποιήστε το OpenID Connect Discovery URL (/.well known/openid-configuration) για να καθορίσετε τα τελικά σημεία auths.tip.twitter=Πηγαίνετε στο https://dev.twitter.com/apps, δημιουργήστε μια εφαρμογή και βεβαιωθείτε ότι η επιλογή “Allow this application to be used to Sign in with Twitter” είναι ενεργοποιημένη auths.tip.discord=Καταχωρήστε μια νέα εφαρμογή στο https://discordapp.com/developers/applications/me -auths.tip.gitea=Καταχωρήστε μια νέα εφαρμογή OAuth2. Ο οδηγός μπορεί να βρεθεί στο https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Δημιουργήστε μια νέα εφαρμογή στο https://oauth.yandex.com/client/new. Επιλέξτε τα ακόλουθα δικαιώματα από την ενότητα "Yandex.Passport API": "Access to email address", "Access to user avatar" και "Access to username, first name and surname, gender"` auths.tip.mastodon=Εισαγάγετε ένα προσαρμομένο URL για την υπηρεσία mastodon με την οποία θέλετε να πιστοποιήσετε (ή να χρησιμοποιήσετε την προεπιλεγμένη) auths.edit=Επεξεργασία Πηγής Ταυτοποίησης @@ -3014,8 +3012,6 @@ monitor.queue.exemplar=Τύπος Υποδείγματος monitor.queue.numberworkers=Αριθμός Εργατών monitor.queue.maxnumberworkers=Μέγιστος Αριθμός Εργατών monitor.queue.numberinqueue=Πλήθος Ουράς -monitor.queue.review=Εξέταση Ρυθμίσεων -monitor.queue.review_add=Εξέταση/Προσθήκη Εργατών monitor.queue.settings.title=Ρυθμίσεις Δεξαμενής monitor.queue.settings.desc=Οι δεξαμενές αυξάνονται δυναμικά όταν υπάρχει φραγή της ουράς των εργατών τους. monitor.queue.settings.maxnumberworkers=Μέγιστος Αριθμός Εργατών diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 18290ec21e2..de07d4beadc 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -97,6 +97,7 @@ locked = Locked copy = Copy copy_url = Copy URL +copy_hash = Copy hash copy_content = Copy content copy_branch = Copy branch name copy_success = Copied! @@ -112,6 +113,7 @@ step2 = Step 2: error = Error error404 = The page you are trying to reach either does not exist or you are not authorized to view it. +go_back = Go Back never = Never unknown = Unknown @@ -123,6 +125,8 @@ unpin = Unpin artifacts = Artifacts +archived = Archived + concept_system_global = Global concept_user_individual = Individual concept_code_repository = Repository @@ -317,7 +321,6 @@ filter_by_team_repositories = Filter by team repositories feed_of = Feed of "%s" show_archived = Archived -archived = Archived show_both_archived_unarchived = Showing both archived and unarchived show_only_archived = Showing only archived show_only_unarchived = Showing only unarchived @@ -943,6 +946,8 @@ fork_from = Fork From already_forked = You've already forked %s fork_to_different_account = Fork to a different account fork_visibility_helper = The visibility of a forked repository cannot be changed. +fork_branch = Branch to be cloned to the fork +all_branches = All branches fork_no_valid_owners = This repository can not be forked because there are no valid owners. use_template = Use this template clone_in_vsc = Clone in VS Code @@ -1008,8 +1013,14 @@ delete_preexisting = Delete pre-existing files delete_preexisting_content = Delete files in %s delete_preexisting_success = Deleted unadopted files in %s blame_prior = View blame prior to this change +blame.ignore_revs = Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view. +blame.ignore_revs.failed = Failed to ignore revisions in .git-blame-ignore-revs. author_search_tooltip = Shows a maximum of 30 users +tree_path_not_found_commit = Path %[1]s doesn't exist in commit %[2]s +tree_path_not_found_branch = Path %[1]s doesn't exist in branch %[2]s +tree_path_not_found_tag = Path %[1]s doesn't exist in tag %[2]s + transfer.accept = Accept Transfer transfer.accept_desc = Transfer to "%s" transfer.reject = Reject Transfer @@ -1276,6 +1287,7 @@ commits.signed_by_untrusted_user = Signed by untrusted user commits.signed_by_untrusted_user_unmatched = Signed by untrusted user who does not match committer commits.gpg_key_id = GPG Key ID commits.ssh_key_fingerprint = SSH Key Fingerprint +commits.view_path=View at this point in history commit.operations = Operations commit.revert = Revert @@ -1512,7 +1524,8 @@ issues.label_description = Description issues.label_color = Color issues.label_exclusive = Exclusive issues.label_archive = Archive Label -issues.label_archive_tooltip= Archived labels are excluded from the label search when applying labels to an issue. Existing labels on issues remain unaffected, allowing you to retire obsolete labels without losing information. +issues.label_archived_filter = Show archived labels +issues.label_archive_tooltip = Archived labels are excluded by default from the suggestions when searching by label. issues.label_exclusive_desc = Name the label scope/item to make it mutually exclusive with other scope/ labels. issues.label_exclusive_warning = Any conflicting scoped labels will be removed when editing the labels of an issue or pull request. issues.label_count = %d labels @@ -1999,7 +2012,8 @@ settings.mirror_settings.push_mirror.add = Add Push Mirror settings.mirror_settings.push_mirror.edit_sync_time = Edit mirror sync interval settings.sync_mirror = Synchronize Now -settings.mirror_sync_in_progress = Mirror synchronization is in progress. Check back in a minute. +settings.pull_mirror_sync_in_progress = Pulling changes from the remote %s at the moment. +settings.push_mirror_sync_in_progress = Pushing changes to the remote %s at the moment. settings.site = Website settings.update_settings = Update Settings settings.update_mirror_settings = Update Mirror Settings @@ -2133,12 +2147,14 @@ settings.webhook_deletion_desc = Removing a webhook deletes its settings and del settings.webhook_deletion_success = The webhook has been removed. settings.webhook.test_delivery = Test Delivery settings.webhook.test_delivery_desc = Test this webhook with a fake event. +settings.webhook.test_delivery_desc_disabled = To test this webhook with a fake event, activate it. settings.webhook.request = Request settings.webhook.response = Response settings.webhook.headers = Headers settings.webhook.payload = Content settings.webhook.body = Body settings.webhook.replay.description = Replay this webhook. +settings.webhook.replay.description_disabled = To replay this webhook, activate it. settings.webhook.delivery.success = An event has been added to the delivery queue. It may take few seconds before it shows up in the delivery history. settings.githooks_desc = "Git Hooks are powered by Git itself. You can edit hook files below to set up custom operations." settings.githook_edit_desc = If the hook is inactive, sample content will be presented. Leaving content to an empty value will disable this hook. @@ -2298,6 +2314,7 @@ settings.dismiss_stale_approvals_desc = When new commits that change the content settings.require_signed_commits = Require Signed Commits settings.require_signed_commits_desc = Reject pushes to this branch if they are unsigned or unverifiable. settings.protect_branch_name_pattern = Protected Branch Name Pattern +settings.protect_branch_name_pattern_desc = "Protected branch name patterns. See the documentation for pattern syntax. Examples: main, release/**" settings.protect_patterns = Patterns settings.protect_protected_file_patterns = "Protected file patterns (separated using semicolon ';'):" settings.protect_protected_file_patterns_desc = "Protected files are not allowed to be changed directly even if user has rights to add, edit, or delete files in this branch. Multiple patterns can be separated using semicolon (';'). See github.com/gobwas/glob documentation for pattern syntax. Examples: .drone.yml, /docs/**/*.txt." @@ -2516,6 +2533,7 @@ branch.default_deletion_failed = Branch "%s" is the default branch. It cannot be branch.restore = Restore Branch "%s" branch.download = Download Branch "%s" branch.rename = Rename Branch "%s" +branch.search = Search Branch branch.included_desc = This branch is part of the default branch branch.included = Included branch.create_new_branch = Create branch from branch: @@ -2783,6 +2801,9 @@ users.full_name = Full Name users.activated = Activated users.admin = Admin users.restricted = Restricted +users.reserved = Reserved +users.bot = Bot +users.remote = Remote users.2fa = 2FA users.repos = Repos users.created = Created @@ -3510,6 +3531,7 @@ runners.status.idle = Idle runners.status.active = Active runners.status.offline = Offline runners.version = Version +runners.reset_registration_token = Reset registration token runners.reset_registration_token_success = Runner registration token reset successfully runs.all_workflows = All Workflows diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index ff6175cf019..c8ff04c1574 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -137,7 +137,6 @@ network_error=Error de red [startpage] app_desc=Un servicio de Git autoalojado y sin complicaciones install=Fácil de instalar -install_desc=Simplemente arranca el binario para su plataforma. O utilice Gitea con Docker, o utilice el paquete. platform=Multiplataforma platform_desc=Gitea funciona en cualquier platforma Go puede compilarlo en: Windows, macOS, Linux, ARM, etc. ¡Elige tu favorita! lightweight=Ligero @@ -264,6 +263,7 @@ filter_by_team_repositories=Filtrar por repositorios de equipo feed_of=`Suministro de noticias de "%s"` show_archived=Archivado +archived=Archivado show_both_archived_unarchived=Mostrar respositorios archivados y desarchivados show_only_archived=Mostrar sólo repositorios archivados show_only_unarchived=Mostrar sólo repositorios desarchivados @@ -518,7 +518,6 @@ overview=Resumen following=Siguiendo follow=Seguir unfollow=Dejar de seguir -heatmap.loading=Cargando mapa de calor… user_bio=Biografía disabled_public_activity=Este usuario ha desactivado la visibilidad pública de la actividad. @@ -582,7 +581,6 @@ choose_new_avatar=Selecciona nuevo avatar update_avatar=Actualizar Avatar delete_current_avatar=Eliminar avatar uploaded_avatar_not_a_image=El archivo subido no es una imagen. -uploaded_avatar_is_too_big=El archivo subido ha excedido el tamaño máximo. update_avatar_success=Su avatar ha sido actualizado. update_user_avatar_success=El avatar del usuario se ha actualizado. @@ -1090,6 +1088,9 @@ commit.cherry-pick=Hacer Cherry-pick commit.cherry-pick-header=Hacer Cherry-pick: %s commit.cherry-pick-content=Seleccionar rama en la que hacer cherry-pick: +commitstatus.error=Error +commitstatus.pending=Pendiente + ext_issues=Acceso a incidencias externas ext_issues.desc=Enlace a un gestor de incidencias externo. @@ -1253,9 +1254,9 @@ issues.ref_reopening_from=`referenció un pull request %[4]s que issues.ref_closed_from=`cerró esta incidencia %[4]s %[2]s` issues.ref_reopened_from=`reabrió esta incidencia %[4]s %[2]s` issues.ref_from=`de %[1]s` -issues.poster=Autor -issues.collaborator=Colaborador -issues.owner=Propietario +issues.author=Autoría +issues.role.owner=Propietario +issues.role.member=Miembro issues.re_request_review=Solicitar revisión de nuevo issues.is_stale=Ha habido cambios en este PR desde esta revisión issues.remove_request_review=Eliminar solicitud de revisión @@ -1547,8 +1548,6 @@ milestones.modify=Actualizar hito milestones.deletion=Eliminar hito milestones.deletion_desc=Eliminando un hito lo elimina de todos los problemas relacionados. ¿Continuar? milestones.deletion_success=El hito se ha eliminado. -milestones.filter_sort.closest_due_date=Más cerca de la fecha de vencimiento -milestones.filter_sort.furthest_due_date=Más lejos de la fecha de vencimiento milestones.filter_sort.least_complete=Menos completa milestones.filter_sort.most_complete=Más completa milestones.filter_sort.most_issues=Mayoría de los problemas @@ -1980,7 +1979,6 @@ settings.tags.protection.allowed.teams=Equipos permitidos settings.tags.protection.allowed.noone=Ningún settings.tags.protection.create=Proteger Etiqueta settings.tags.protection.none=No hay etiquetas protegidas. -settings.tags.protection.pattern.description=Puede usar un solo nombre o un patrón de glob o expresión regular para que coincida con varias etiquetas. Lea más en la guía de etiquetas protegida. settings.bot_token=Token del Bot settings.chat_id=ID Chat settings.matrix.homeserver_url=URL de Homeserver @@ -2449,12 +2447,10 @@ packages.size=Tamaño packages.published=Publicado defaulthooks=Webhooks por defecto -defaulthooks.desc=Los Webhooks automáticamente hacen peticiones HTTP POST a un servidor cuando ciertos eventos de Gitea se activan. Los ganchos definidos aquí son predeterminados y serán copiados en todos los nuevos repositorios. Leer más en la guía webhooks. defaulthooks.add_webhook=Añadir Webhook por defecto defaulthooks.update_webhook=Actualizar Webhook por defecto systemhooks=Webhooks del sistema -systemhooks.desc=Los webhooks automáticamente hacen peticiones HTTP POST a un servidor cuando ciertos eventos de Gitea se activan. Los webhooks definidos actuarán en todos los repositorios del sistema, así que por favor considere las implicaciones de rendimiento que esto pueda tener. Lea más en la guía de webhooks. systemhooks.add_webhook=Añadir Webhook del Sistema systemhooks.update_webhook=Actualizar Webhook del Sistema @@ -2556,7 +2552,6 @@ auths.tip.google_plus=Obtener credenciales de cliente OAuth2 desde la consola AP auths.tip.openid_connect=Use el OpenID Connect Discovery URL (/.well-known/openid-configuration) para especificar los puntos finales auths.tip.twitter=Ir a https://dev.twitter.com/apps, crear una aplicación y asegurarse de que la opción "Permitir que esta aplicación sea usada para iniciar sesión con Twitter" está activada auths.tip.discord=Registrar una nueva aplicación en https://discordapp.com/developers/applications/me -auths.tip.gitea=Registra una nueva aplicación OAuth2. La guía puede ser encontrada en https://docs.gitea.io/es-us/oauth2-provider/ auths.tip.yandex=`Crear una nueva aplicación en https://oauth.yandex.com/client/new. Seleccione los siguientes permisos del "Yandex.Passport API": "Access to email address", "Access to user avatar" y "Access to username, first name and surname, gender"` auths.tip.mastodon=Introduzca una URL de instancia personalizada para la instancia mastodon con la que desea autenticarse (o utilice la predeterminada) auths.edit=Editar origen de autenticación @@ -2727,8 +2722,6 @@ monitor.queue.exemplar=Ejemplo monitor.queue.numberworkers=Número de trabajadores monitor.queue.maxnumberworkers=Número máximo de trabajadores monitor.queue.numberinqueue=Número en cola -monitor.queue.review=Revisar configuración -monitor.queue.review_add=Revisar/Añadir trabajadores monitor.queue.settings.title=Ajustes del grupo monitor.queue.settings.maxnumberworkers=Número máximo de trabajadores monitor.queue.settings.maxnumberworkers.placeholder=Actualmente %[1]d diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index b451eae8092..46601a8cc70 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -115,7 +115,6 @@ missing_csrf=درخواست بد: بلیط CSRF ندارد [startpage] app_desc=یک سرویس گیت بی‌درد سر و راحت install=راه‌اندازی ساده -install_desc=به سادگی فایل اجرایی را برای پلتفرم موردنظر خود اجرا کنید یا آن را در قالب یک کانتینر Docker آماده کنید و یا بصورت یک بسته دریافت کنید. platform=مستقل از سکو platform_desc=گیت همه جا اجرا می‌شود بریم! می‌توانید Windows, macOS, Linux, ARM و ... هر کدام را دوست داشتید انتخاب کنید! lightweight=ابزارک سبک @@ -241,6 +240,7 @@ filter_by_team_repositories=فیلتر کردن با مخازن تیم‌ها feed_of=`خوراک از "%s"` show_archived=بایگانی شده +archived=بایگانی شده show_both_archived_unarchived=نمایش دادن موارد بایگانی شده و غیر بایگانی نشده show_only_archived=نمایش دادن موارد بایگانی شده show_only_unarchived=نمایش دادن موارد بایگانی نشده @@ -478,7 +478,6 @@ overview=مرور following=دنبال میکنید follow=دنبال کردن unfollow=عدم دنبال کردن -heatmap.loading=بارگذاری Heatmap… user_bio=زندگی‌نامه disabled_public_activity=این کاربر نمایش عمومی فعالیت های خود را غیرفعال کرده است. @@ -526,7 +525,6 @@ choose_new_avatar=انتخاب آواتار جدید update_avatar=بروزرسانی آواتار delete_current_avatar=حذف آواتار فعلی uploaded_avatar_not_a_image=فایل بار‌گذاری شده تصویر نمی‌باشد. -uploaded_avatar_is_too_big=حجم فایل بارگزاری بیش از حد مجاز است. update_avatar_success=آواتار شما تغییر کرد. update_user_avatar_success=آواتار کاربر بروز رسانی شده است. @@ -991,6 +989,9 @@ commits.signed_by_untrusted_user_unmatched=امضا شده توسط یک کار commits.gpg_key_id=شناسه کلید GPG +commitstatus.error=خطا +commitstatus.pending=در انتظار + ext_issues.desc=پیوند به ردیاب خارجی برای موضوع. projects=پروژه‌ها @@ -1144,9 +1145,8 @@ issues.ref_reopening_from=` تقاضای واکشی ارجاع issues.ref_closed_from=` بسته شده این مسائله %[4] %[2]s` issues.ref_reopened_from=` بازگشایی این مسائله %[4] %[2]s` issues.ref_from=`از %[1]` -issues.poster=نویسنده -issues.collaborator=همكار -issues.owner=مالک +issues.role.owner=مالک +issues.role.member=عضو issues.re_request_review=درخواست دوباره برای بازبینی issues.is_stale=از زمان این بررسی تغییراتی در این پروژه ایجاد شده است issues.remove_request_review=حذف درخواست بازبینی @@ -1409,8 +1409,6 @@ milestones.modify=به روزرسانی نقطه عطف milestones.deletion=حذف نقطه عطف milestones.deletion_desc=نقاط عطف از تمام مسائل مرتبط حذف میشوند. آیا ادامه میدهید؟ milestones.deletion_success=نقطه عطف حذف شد. -milestones.filter_sort.closest_due_date=نزدیکترین موعد مقرر -milestones.filter_sort.furthest_due_date=دورترین موعد مقرر milestones.filter_sort.least_complete=حداقل کامل شده milestones.filter_sort.most_complete=بیشترین کامل شده milestones.filter_sort.most_issues=بیشترین مسائل @@ -1800,7 +1798,6 @@ settings.tags.protection.allowed.teams=تیم‌های مجاز settings.tags.protection.allowed.noone=هیچیک settings.tags.protection.create=تگ حفاظتی settings.tags.protection.none=هیچ تگ حفاظتی وجود ندارد. -settings.tags.protection.pattern.description=می توانید از یک نام واحد یا یک الگوی glob یا عبارت منظم برای تطبیق چندین برچسب استفاده کنید. در راهنمای برچسب های محافظت شده بیشتر بخوانید. settings.bot_token=Token ربات settings.chat_id=شناسه گپ settings.matrix.homeserver_url=URL سرورخانه @@ -2243,12 +2240,10 @@ packages.repository=مخزن packages.size=اندازه defaulthooks=وب هوک های پیش فرض -defaulthooks.desc=هنگامی که برخی رویدادهای Gitea فعال می شوند، Webhook ها به طور خودکار درخواست های HTTP POST را به سرور ارسال می کنند. هوک های تعریف شده در اینجا پیش فرض هستند و در تمام مخازن جدید کپی می شوند. در راهنمای هوک‌های وب بیشتر بخوانید. defaulthooks.add_webhook=اضافه کردن Webhook پیش فرض defaulthooks.update_webhook=Webhook پیش فرض را به روز کنید systemhooks=وب هوک های سیستم -systemhooks.desc=هنگامی که برخی رویدادهای Gitea فعال می شوند، Webhook ها به طور خودکار درخواست های HTTP POST را به سرور ارسال می کنند. وب هوک های تعریف شده در اینجا بر روی تمام انبارها سیستم عمل می کنند، بنابراین لطفاً هر گونه پیامدهای عملکردی که ممکن است داشته باشد را در نظر بگیرید. در راهنمای هوک‌های وب بیشتر بخوانید. systemhooks.add_webhook=System Webhook را اضافه کنید systemhooks.update_webhook=به روز رسانی Webhook سیستم @@ -2338,7 +2333,6 @@ auths.tip.google_plus=اطلاعات مربوط به مشتری OAuth2 را از auths.tip.openid_connect=برای مشخص کردن نقاط پایانی از آدرس OpenID Connect Discovery URL ( /.well-known/openid-configuration) استفاده کنید. auths.tip.twitter=به https://dev.twitter.com/apps بروید ، برنامه ای ایجاد کنید و اطمینان حاصل کنید که گزینه "اجازه استفاده از این برنامه برای ورود به سیستم با Twitter" را فعال کنید auths.tip.discord=یک برنامه جدید را در https://discordapp.com/developers/applications/me ثبت کنید -auths.tip.gitea=یک برنامه OAuth2 ثبت کنید. راهنمایی بیشتر https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`یک برنامه جدید در https://oauth.yandex.com/client/new ایجاد کنید. مجوزهای زیر را از بخش "Yandex.Passport API" انتخاب کنید: "دسترسی به آدرس ایمیل"، "دسترسی به آواتار کاربر" و "دسترسی به نام کاربری، نام و نام خانوادگی، جنسیت"` auths.tip.mastodon=یک URL نمونه سفارشی برای نمونه ماستودون که می خواهید با آن احراز هویت کنید وارد کنید (یا از یک پیش فرض استفاده کنید) auths.edit=ویرایش منبع احراز هویت @@ -2499,8 +2493,6 @@ monitor.queue.type=نوع monitor.queue.exemplar=نوع نمونه monitor.queue.numberworkers=تعداد کارگران monitor.queue.maxnumberworkers=بیشینه تعداد کارگران -monitor.queue.review=بررسی پیکربندی -monitor.queue.review_add=بررسی/افزودن کارگران monitor.queue.settings.title=تنظیمات استخر monitor.queue.settings.maxnumberworkers=بیشینه تعداد کارگران monitor.queue.settings.maxnumberworkers.placeholder=در حال حاضر %[1]v diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index d9a6cd5dec7..cce13fb88a3 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -133,7 +133,6 @@ 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 @@ -251,6 +250,7 @@ filter_by_team_repositories=Suodata tiimin repojen mukaan feed_of=`Syöte "%s"` show_archived=Arkistoidut +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 @@ -439,7 +439,6 @@ overview=Yleiskatsaus following=Seurataan follow=Seuraa unfollow=Lopeta seuraaminen -heatmap.loading=Ladataan lämpökarttaa… user_bio=Elämäkerta @@ -794,6 +793,9 @@ commits.gpg_key_id=GPG avaimen ID commits.ssh_key_fingerprint=SSH avaimen sormenjälki +commitstatus.error=Virhe +commitstatus.pending=Odottaa + projects=Projektit projects.description_placeholder=Kuvaus @@ -900,9 +902,9 @@ issues.create_comment=Kommentoi issues.closed_at=`sulki tämän ongelman %[2]s` issues.reopened_at=`uudelleenavasi tämän ongelman %[2]s` issues.commit_ref_at=`viittasi tähän ongelmaan commitissa %[2]s` -issues.poster=Tekijä -issues.collaborator=Yhteistyökumppani -issues.owner=Omistaja +issues.author=Tekijä +issues.role.owner=Omistaja +issues.role.member=Jäsen issues.edit=Muokkaa issues.cancel=Peruuta issues.save=Tallenna @@ -1108,7 +1110,6 @@ 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.trust_model.collaborator=Yhteistyökumppani settings.wiki_delete=Poista Wiki data settings.wiki_delete_desc=Repon wikin data poistaminen on pysyvä eikä voi peruuttaa. settings.confirm_wiki_delete=Wiki datan poistaminen @@ -1220,7 +1221,6 @@ settings.tags.protection.allowed.teams=Sallitut tiimit settings.tags.protection.allowed.noone=Ei kukaan settings.tags.protection.create=Suojaa tagi settings.tags.protection.none=Suojattuja tageja ei ole. -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.archive.button=Arkistoi repo diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index ec1babb1765..139a463a94f 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -181,7 +181,6 @@ network_error=Erreur réseau [startpage] app_desc=Un service Git auto-hébergé sans prise de tête install=Facile à installer -install_desc=Il suffit de lancer l’exécutable pour votre plateforme, le déployer avec Docker, ou l’installer depuis un paquet. platform=Multi-plateforme platform_desc=Gitea tourne partout où Go peut être compilé : Windows, macOS, Linux, ARM, etc. Choisissez votre préféré ! lightweight=Léger @@ -317,6 +316,7 @@ filter_by_team_repositories=Dépôts filtrés par équipe feed_of=Flux de « %s » show_archived=Archivé +archived=Archivé show_both_archived_unarchived=Afficher à la fois archivé et non archivé show_only_archived=Afficher uniquement les archivés show_only_unarchived=Afficher uniquement les non archivés @@ -378,6 +378,7 @@ email_not_associate=L’adresse courriel n’est associée à aucun compte. send_reset_mail=Envoyer un courriel de récupération du compte reset_password=Récupération du compte invalid_code=Votre code de confirmation est invalide ou a expiré. +invalid_code_forgot_password=Votre code de confirmation est invalide ou a expiré. Cliquez ici pour démarrer une nouvelle session. invalid_password=Votre mot de passe ne correspond pas à celui utilisé pour créer le compte. reset_password_helper=Récupérer un compte reset_password_wrong_user=Vous êtes connecté en tant que %s, mais le lien de récupération est pour %s @@ -598,7 +599,6 @@ overview=Vue d'ensemble following=Abonnements follow=Suivre unfollow=Ne plus suivre -heatmap.loading=Chargement de la Heatmap… user_bio=Biographie disabled_public_activity=Cet utilisateur a désactivé la visibilité publique de l'activité. email_visibility.limited=Votre adresse courriel est visible pour tous les utilisateurs authentifiés @@ -680,7 +680,7 @@ choose_new_avatar=Sélectionner un nouvel avatar update_avatar=Modifier l’avatar delete_current_avatar=Supprimer l'avatar actuel uploaded_avatar_not_a_image=Le fichier téléchargé n'est pas une image. -uploaded_avatar_is_too_big=Le fichier téléchargé dépasse la taille limite. +uploaded_avatar_is_too_big=La taille du fichier téléversé (%d Kio) dépasse la taille maximale (%d Kio). update_avatar_success=Votre avatar a été mis à jour. update_user_avatar_success=L'avatar de l'utilisateur a été mis à jour. @@ -970,6 +970,7 @@ trust_model_helper_collaborator_committer=Collaborateur et Auteur : ne se fier q trust_model_helper_default=Par défaut : valeur configurée par défaut pour cette instance Gitea create_repo=Créer un dépôt default_branch=Branche par défaut +default_branch_label=défaut default_branch_helper=La branche par défaut est la branche de base pour les demandes d'ajout et les révisions de code. mirror_prune=Purger mirror_prune_desc=Supprimer les références externes obsolètes @@ -1280,6 +1281,11 @@ commit.cherry-pick=Picorer commit.cherry-pick-header=Picorer : %s commit.cherry-pick-content=Sélectionner la branche à picorer : +commitstatus.error=Erreur +commitstatus.failure=Échec +commitstatus.pending=En attente +commitstatus.success=Succès + ext_issues=Accès aux tickets externes ext_issues.desc=Lien vers un gestionnaire de tickets externe. @@ -1475,9 +1481,18 @@ issues.ref_reopening_from=`a référencé une pull request %[4]s issues.ref_closed_from=`a fermé ce ticket %[4]s %[2]s` issues.ref_reopened_from=`a rouvert ce ticket %[4]s %[2]s.` issues.ref_from=`de %[1]s` -issues.poster=Éditeur -issues.collaborator=Collaborateur -issues.owner=Propriétaire +issues.author=Auteur +issues.author_helper=Cet utilisateur est l’auteur. +issues.role.owner=Propriétaire +issues.role.owner_helper=Cet utilisateur est le propriétaire de ce dépôt. +issues.role.member=Membre +issues.role.member_helper=Cet utilisateur est membre de l’organisation propriétaire de ce dépôt. +issues.role.collaborator=Collaborateur +issues.role.collaborator_helper=Cet utilisateur a été invité à collaborer sur le dépôt. +issues.role.first_time_contributor=Première contribution +issues.role.first_time_contributor_helper=C'est la première contribution de cet utilisateur au dépôt. +issues.role.contributor=Contributeur +issues.role.contributor_helper=Cet utilisateur a déjà des révisions dans le dépôt. issues.re_request_review=Redemander une évaluation issues.is_stale=Cette demande d’ajout a été corrigée depuis sa dernière évaluation. issues.remove_request_review=Retirer la demande d’évaluation @@ -1815,8 +1830,8 @@ milestones.edit_success=Le jalon "%s" a été mis à jour. milestones.deletion=Supprimer un Jalon milestones.deletion_desc=Supprimer un jalon le retire de tous les tickets. Continuer ? milestones.deletion_success=Le jalon a été supprimé. -milestones.filter_sort.closest_due_date=Date d'échéance la plus proche -milestones.filter_sort.furthest_due_date=Date d'échéance la plus éloignée +milestones.filter_sort.earliest_due_data=Date d’échéance la plus ancienne +milestones.filter_sort.latest_due_date=Date d’échéance la plus récente milestones.filter_sort.least_complete=Le moins complété milestones.filter_sort.most_complete=Le plus complété milestones.filter_sort.most_issues=Le plus de tickets @@ -1976,7 +1991,7 @@ settings.mirror_settings.last_update=Dernière mise à jour settings.mirror_settings.push_mirror.none=Aucun miroir push configuré settings.mirror_settings.push_mirror.remote_url=URL du dépôt distant Git settings.mirror_settings.push_mirror.add=Ajouter un miroir push -settings.mirror_settings.push_mirror.edit_sync_time=Modifier la fréquence de réflexion +settings.mirror_settings.push_mirror.edit_sync_time=Modifier la fréquence de synchronisation du miroir settings.sync_mirror=Synchroniser maintenant settings.mirror_sync_in_progress=La synchronisation est en cours. Revenez dans une minute. @@ -2314,7 +2329,7 @@ settings.tags.protection.allowed.teams=Équipes autorisées settings.tags.protection.allowed.noone=Personne settings.tags.protection.create=Protéger l'étiquette settings.tags.protection.none=Il n'y a pas d'étiquettes protégées. -settings.tags.protection.pattern.description=Vous pouvez utiliser soit un nom unique, soit un motif de glob ou une expression régulière qui correspondront à plusieurs étiquettes. Pour plus d'informations, veuillez vous reporter au guide sur les étiquettes protégées. +settings.tags.protection.pattern.description=Vous pouvez utiliser soit un nom unique, soit un motif de glob ou une expresion régulière qui correspondront à plusieurs étiquettes. Pour plus d'informations, veuillez vous reporter au guide sur les étiquettes protégées. settings.bot_token=Jeton de Bot settings.chat_id=ID de conversation settings.thread_id=ID du fil @@ -2712,6 +2727,7 @@ dashboard.reinit_missing_repos=Réinitialiser tous les dépôts Git manquants po dashboard.sync_external_users=Synchroniser les données de l’utilisateur externe dashboard.cleanup_hook_task_table=Nettoyer la table hook_task dashboard.cleanup_packages=Nettoyer des paquets expirés +dashboard.cleanup_actions=Nettoyer les journaux et les artefacts des actions obsolètes dashboard.server_uptime=Uptime du serveur dashboard.current_goroutine=Goroutines actuelles dashboard.current_memory_usage=Utilisation Mémoire actuelle @@ -2749,7 +2765,9 @@ dashboard.gc_lfs=Épousseter les métaobjets LFS dashboard.stop_zombie_tasks=Arrêter les tâches zombies dashboard.stop_endless_tasks=Arrêter les tâches sans fin dashboard.cancel_abandoned_jobs=Annuler les jobs abandonnés +dashboard.start_schedule_tasks=Démarrer les tâches planifiées dashboard.sync_branch.started=Début de la synchronisation des branches +dashboard.rebuild_issue_indexer=Reconstruire l’indexeur des tickets users.user_manage_panel=Gestion du compte utilisateur users.new_account=Créer un compte @@ -2758,6 +2776,9 @@ users.full_name=Non Complet users.activated=Activé users.admin=Administrateur users.restricted=Restreint +users.reserved=Réservé +users.bot=Robot +users.remote=Distant users.2fa=2FA users.repos=Dépôts users.created=Créés @@ -2804,6 +2825,7 @@ users.list_status_filter.is_prohibit_login=Interdit de connexion users.list_status_filter.not_prohibit_login=Autorisé à se connecter users.list_status_filter.is_2fa_enabled=2FA Activé users.list_status_filter.not_2fa_enabled=2FA désactivé +users.details=Informations de l’utilisateur emails.email_manage_panel=Gestion des emails des utilisateurs emails.primary=Principale @@ -2851,12 +2873,10 @@ packages.size=Taille packages.published=Publiés defaulthooks=Déclencheurs web par défaut -defaulthooks.desc=Les Déclencheurs Web font des requêtes HTTP POST à un serveur lorsque certains événements Gitea se produisent. Les Déclencheurs déclarés ici seront prédéfinit dans tous nouveaux dépôts. Consultez le guide sur les Déclencheurs Web. defaulthooks.add_webhook=Ajouter un déclencheur web par défaut defaulthooks.update_webhook=Mettre à jour le déclencheur web par défaut systemhooks=Rappels système -systemhooks.desc=Les Webhooks font automatiquement des requêtes HTTP POST à un serveur lorsque certains événements Gitea se déclenchent. Les Webhooks définis ici agiront sur tous les dépots du système, donc veuillez prendre en compte les implications en termes de performances que cela peut avoir. Lire la suite dans le guide des Webhooks. systemhooks.add_webhook=Ajouter un rappel système systemhooks.update_webhook=Mettre à jour un rappel système @@ -2961,7 +2981,7 @@ auths.tip.google_plus=Obtenez des identifiants OAuth2 sur la console API de Goog auths.tip.openid_connect=Utilisez l'URL de découvert OpenID (/.well-known/openid-configuration) pour spécifier les points d'accès auths.tip.twitter=Rendez-vous sur https://dev.twitter.com/apps, créez une application et assurez-vous que l'option "Autoriser l'application à être utilisée avec Twitter Connect" est activée auths.tip.discord=Enregistrer une nouvelle application sur https://discordapp.com/developers/applications/me -auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Un guide peut être trouvé sur https://docs.gitea.io/en-us/oauth2-provider/ +auths.tip.gitea=Enregistrez une nouvelle application OAuth2. Le guide peut être trouvé sur https://docs.gitea.com/development/oauth2-provider auths.tip.yandex=`Créez une nouvelle application sur https://oauth.yandex.com/client/new. Sélectionnez les autorisations suivantes dans la section "Yandex API passport" : "Accès à l'adresse e-mail", "Accès à l'avatar de l'utilisateur" et "Accès au nom d'utilisateur, prénom et prénom, genre"` auths.tip.mastodon=Entrez une URL d'instance personnalisée pour l'instance mastodon avec laquelle vous voulez vous authentifier (ou utiliser celle par défaut) auths.edit=Mettre à jour la source d'authentification @@ -3143,10 +3163,10 @@ monitor.queue.name=Nom monitor.queue.type=Type monitor.queue.exemplar=Type d'exemple monitor.queue.numberworkers=Nombre de processus +monitor.queue.activeworkers=Processus actifs monitor.queue.maxnumberworkers=Nombre maximale de processus monitor.queue.numberinqueue=Position dans la queue -monitor.queue.review=Revoir la configuration -monitor.queue.review_add=Réviser/Ajouter des processus +monitor.queue.review_add=Examiner / ajouter des processus monitor.queue.settings.title=Paramètres du réservoir monitor.queue.settings.desc=Les bassins croissent proportionnellement au besoin de leurs exécuteurs. monitor.queue.settings.maxnumberworkers=Nombre maximale de processus @@ -3481,6 +3501,7 @@ runners.reset_registration_token_success=Le jeton d’inscription de l’exécut runs.all_workflows=Tous les flux de travail runs.commit=Révision +runs.scheduled=Planifié runs.pushed_by=soumis par runs.invalid_workflow_helper=La configuration du flux de travail est invalide. Veuillez vérifier votre fichier %s. runs.no_matching_runner_helper=Aucun exécuteur correspondant : %s @@ -3495,6 +3516,7 @@ workflow.disable=Désactiver le flux de travail workflow.disable_success=Le flux de travail « %s » a bien été désactivé. workflow.enable=Activer le flux de travail workflow.enable_success=Le flux de travail « %s » a bien été activé. +workflow.disabled=Le flux de travail est désactivé. need_approval_desc=Besoin d’approbation pour exécuter des flux de travail pour une demande d’ajout de bifurcation. diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index ee94e3d40b6..b53d34f1a2f 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -211,6 +211,7 @@ view_home=Nézet %s search_repos=Tároló keresés… show_archived=Archivált +archived=Archivált show_private=Privát show_both_private_public=Publikus és privát mutatása @@ -382,7 +383,6 @@ overview=Áttekintés following=Követve follow=Követés unfollow=Követés törlése -heatmap.loading=Hőtérkép betöltése… user_bio=Életrajz @@ -425,7 +425,6 @@ choose_new_avatar=Új profilkép kiválasztása update_avatar=Profilkép Frissítése delete_current_avatar=Jelenlegi profilkép törlése uploaded_avatar_not_a_image=A feltöltött fájl nem kép. -uploaded_avatar_is_too_big=A feltöltött file mérete meghaladta a maximumot. update_avatar_success=A profilképe frissítve lett. change_password=Jelszó frissítése @@ -737,6 +736,8 @@ commits.signed_by=Aláírta commits.gpg_key_id=GPG kulcs azonosító +commitstatus.pending=Függőben + ext_issues.desc=Külső hibakövető csatlakoztatás. projects=Projektek @@ -835,9 +836,8 @@ issues.reopen_issue=Újranyitás issues.reopen_comment_issue=Hozzászólás és újranyitás issues.create_comment=Hozzászólás issues.commit_ref_at=`hivatkozott erre a hibajegyre egy commit-ból %[2]s` -issues.poster=Posztoló -issues.collaborator=Közreműködő -issues.owner=Tulajdonos +issues.role.owner=Tulajdonos +issues.role.member=Tag issues.re_request_review=Véleményezés újrakérése issues.sign_in_require_desc=Jelentkezz be hogy csatlakozz a beszélgetéshez. issues.edit=Szerkesztés @@ -973,8 +973,6 @@ milestones.modify=Mérföldkő frissítése milestones.deletion=Mérföldkő törlése milestones.deletion_desc=A mérföldkő törlése eltávolítja az összes hozzárendelt hibajegyet. Biztosan folytatja? milestones.deletion_success=A mérföldkő törölve. -milestones.filter_sort.closest_due_date=Legközelebbi határidő -milestones.filter_sort.furthest_due_date=Legtávolabbi határidő milestones.filter_sort.least_complete=Legkevésbé befejezve milestones.filter_sort.most_complete=Leginkább befejezve milestones.filter_sort.most_issues=Legtöbb hibajegy @@ -1072,7 +1070,6 @@ settings.githooks=Git Hook-ok settings.site=Webhely settings.update_settings=Beállítások frissítése settings.enable_timetracker=Időmérés bekapcsolása -settings.trust_model.collaborator=Közreműködő settings.delete_collaborator=Eltávolítás settings.teams=Csoportok settings.webhook_deletion=Webhook törlése @@ -1423,7 +1420,6 @@ auths.tip.openid_connect=Használja az OpenID kapcsolódás felfedező URL-t (%[2]s` -issues.poster=Poster -issues.collaborator=Kalaborator -issues.owner=Pemilik +issues.role.owner=Pemilik +issues.role.member=Anggota issues.sign_in_require_desc=Masuk untuk bergabung dengan percakapan ini. issues.edit=Sunting issues.cancel=Batal @@ -780,8 +778,6 @@ milestones.due_date=Jatuh Tempo (opsional) milestones.clear=Bersihkan milestones.edit=Ubah Milestone milestones.cancel=Batal -milestones.filter_sort.closest_due_date=Jatuh tempo terdekat -milestones.filter_sort.furthest_due_date=Jatuh tempo terjauh milestones.filter_sort.least_complete=Paling tidak lengkap milestones.filter_sort.most_complete=Paling lengkap milestones.filter_sort.most_issues=Paling banyak masalah @@ -871,7 +867,6 @@ settings.danger_zone=Zona Bahaya settings.new_owner_has_same_repo=Pemilik baru sudah memiliki repositori dengan nama yang sama. Silakan pilih nama lain. settings.transfer=Transfer Kepemilikan settings.transfer_owner=Pemilik Baru -settings.trust_model.collaborator=Kalaborator settings.delete=Menghapus Repositori Ini settings.delete_notices_1=- Operasi ini TIDAK BISA dibatalkan. settings.delete_collaborator=Menghapus @@ -1250,8 +1245,6 @@ monitor.queue.type=Tipe monitor.queue.exemplar=Contoh Tipe monitor.queue.numberworkers=Jumlah Worker monitor.queue.maxnumberworkers=Jumlah Maks. Worker -monitor.queue.review=Tinjau Konfigurasi -monitor.queue.review_add=Tinjau/Tambah Worker monitor.queue.settings.title=Pengaturan Kelompok monitor.queue.settings.maxnumberworkers=Jumlah Maks. Worker monitor.queue.settings.maxnumberworkers.error=Jumlah maks. worker haruslah sebuah angka diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 5c9c4a040a3..d0031dd6550 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -130,7 +130,6 @@ network_error=Netkerfisvilla [startpage] app_desc=Þrautalaus og sjálfhýst Git þjónusta install=Einföld uppsetning -install_desc=Einfaldlega keyrðu forritiðfyrir vettvanginn þinn, Docker, eða fáðu það í pakka. platform=Fjölvettvangur platform_desc=Gitea virkar hvar sem að Go gerir: Linux, macOS, Windows, ARM o. s. frv. Veldu það sem þú vilt! lightweight=Létt @@ -230,6 +229,7 @@ search_repos=Finna hugbúnaðarsafn… filter=Aðrar Síur show_archived=Safnvistað +archived=Safnvistað show_private=Einka show_only_private=Að sýna aðeins einka @@ -416,7 +416,6 @@ overview=Yfirlit following=Fylgir follow=Fylgja unfollow=Affylgja -heatmap.loading=Hleð Hitakorti… user_bio=Lífssaga disabled_public_activity=Þessi notandi hefur slökkt á opinberum sýnileika virkninnar. @@ -472,7 +471,6 @@ choose_new_avatar=Veldu nýja notandamynd update_avatar=Uppfæra Notandamynd delete_current_avatar=Eyða Núverandi Notandamynd uploaded_avatar_not_a_image=Skráin sem hlaðin var upp er ekki mynd. -uploaded_avatar_is_too_big=Skráin sem hlaðin var upp er yfir hámarksstærð. update_avatar_success=Notandamynd þín hefur verið uppfærð. update_user_avatar_success=Notandamynd þessara notanda hefur verið uppfærð. @@ -717,6 +715,9 @@ commits.older=Eldri commits.newer=Nýrri +commitstatus.error=Villa +commitstatus.pending=Í bið + projects=Verkefni projects.description=Lýsing (valfrjálst) @@ -804,7 +805,9 @@ issues.create_comment=Senda Ummæli issues.closed_at=`lokaði þessu vandamáli %[2]s` issues.reopened_at=`enduropnaði þetta vandamál %[2]s` issues.ref_reopened_from=`enduropnaði þetta vandamál %[4]s %[2]s` -issues.owner=Eigandi +issues.author=Höfundur +issues.role.owner=Eigandi +issues.role.member=Meðlimur issues.edit=Breyta issues.cancel=Hætta við issues.save=Vista @@ -1211,7 +1214,6 @@ packages.type=Tegund packages.repository=Hugbúnaðarsafn packages.size=Stærð -defaulthooks.desc=Vefkrókar senda sjálfkrafa HTTP POST beiðnir til netþjóns þegar ákveðnir Gitea atburðir koma af stað. Vefkrókar sem eru skilgreindir hér eru sjálfgefnir og verða afritaðir í allar nýjar geymslur. Frekari upplýsingar eru í handbókini. auths.name=Heiti diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 42d19e1f1d3..95a3f5dee4c 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -135,7 +135,6 @@ network_error=Errore di rete [startpage] app_desc=Un servizio auto-ospitato per Git pronto all'uso install=Facile da installare -install_desc=Semplicemente avvia l'eseguibile per la tua piattaforma. Oppure avvia Gitea con Docker, oppure ottienilo pacchettizzato. platform=Multipiattaforma platform_desc=Gitea funziona ovunque Go possa essere compilato: Windows, macOS, Linux, ARM, etc. Scegli ciò che ami! lightweight=Leggero @@ -262,6 +261,7 @@ filter_by_team_repositories=Filtra per repository del team feed_of=`Feed di "%s"` show_archived=Archiviato +archived=Archiviato show_both_archived_unarchived=Mostra sia gli archiviati che i non archiviati show_only_archived=Visualizzazione solo archiviati show_only_unarchived=Visualizzazione solo non archiviati @@ -505,7 +505,6 @@ overview=Riepilogo following=Seguiti follow=Segui unfollow=Non seguire più -heatmap.loading=Caricamento della Heatmap… user_bio=Biografia disabled_public_activity=L'utente ha disabilitato la vista pubblica dell'attività. @@ -569,7 +568,6 @@ choose_new_avatar=Scegli un nuovo avatar update_avatar=Aggiorna Avatar delete_current_avatar=Elimina Avatar attuale uploaded_avatar_not_a_image=Il file caricato non è un'immagine. -uploaded_avatar_is_too_big=Il file inviato eccede le dimensioni massime. update_avatar_success=Il tuo avatar è stato aggiornato. update_user_avatar_success=L'avatar dell'utente è stato aggiornato. @@ -1077,6 +1075,9 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=Seleziona il ramo su cui scegliere: +commitstatus.error=Errore +commitstatus.pending=In sospeso + ext_issues=Accesso ai Problemi Esterni ext_issues.desc=Collegamento al puntatore di una issue esterna. @@ -1238,9 +1239,9 @@ issues.ref_reopening_from=`ha fatto riferimento ad una pull requ issues.ref_closed_from=`chiuso questo problema %[4]s %[2]s` issues.ref_reopened_from=`riaperto questo problema %[4]s %[2]s` issues.ref_from=`da %[1]s` -issues.poster=Autore -issues.collaborator=Collaboratori -issues.owner=Proprietario +issues.author=Autore +issues.role.owner=Proprietario +issues.role.member=Membro issues.re_request_review=Revisione ri-richiesta issues.is_stale=Ci sono stati cambiamenti a questa PR da questa revisione issues.remove_request_review=Elimina richiesta revisione @@ -1532,8 +1533,6 @@ milestones.modify=Aggiorna pietra miliare milestones.deletion=Elimina pietra miliare milestones.deletion_desc=Eliminare una pietra miliare la rimuove da tutte le relative issue. Continuare? milestones.deletion_success=La pietra miliare è stata eliminata. -milestones.filter_sort.closest_due_date=Data di scadenza più vicina -milestones.filter_sort.furthest_due_date=Data di scadenza più lontana milestones.filter_sort.least_complete=Meno completato milestones.filter_sort.most_complete=Più completato milestones.filter_sort.most_issues=Più problemi @@ -1958,7 +1957,6 @@ settings.tags.protection.allowed.teams=Squadre ammesse settings.tags.protection.allowed.noone=Nessuno settings.tags.protection.create=Proteggi Etichetta settings.tags.protection.none=Non ci sono etichette protette. -settings.tags.protection.pattern.description=È possibile utilizzare un singolo nome o un modello globo o un'espressione regolare per abbinare più tag. Leggi di più nella guida per i tag protetti. settings.bot_token=Token del Bot settings.chat_id=ID chat settings.matrix.homeserver_url=URL Homeserver @@ -2424,12 +2422,10 @@ packages.size=Dimensione packages.published=Pubblicata defaulthooks=Webhook predefiniti -defaulthooks.desc=I Webhooks effettuano automaticamente richieste HTTP POST ad un server quando si verificano determinati eventi Gitea. I Webhooks definiti qui sono predefiniti e verranno copiati in tutti i nuovi repository. Per saperne di più leggi la guida ai webhooks. defaulthooks.add_webhook=Aggiungi Webhook predefinito defaulthooks.update_webhook=Aggiorna Webhook predefinito systemhooks=Webhooks di Sistema -systemhooks.desc=I Webhooks effettuano automaticamente richieste HTTP POST ad un server quando si verificano determinati eventi Gitea. I Webhooks definiti qui agiranno su tutti i repository del sistema, quindi considera le eventuali implicazioni sulle performance che potrebbero avere. Per saperne di più leggi la guida ai webhooks. systemhooks.add_webhook=Aggiungi Webhook di Sistema systemhooks.update_webhook=Aggiorna Webhook di Sistema @@ -2531,7 +2527,6 @@ auths.tip.google_plus=Ottieni le credenziali del client OAuth2 dalla console API auths.tip.openid_connect=Utilizza l'OpenID Connect Discovery URL (/.well-known/openid-configuration) per specificare gli endpoint auths.tip.twitter=Vai su https://dev.twitter.com/apps, crea una applicazione e assicurati che l'opzione "Allow this application to be used to Sign In with Twitter" sia abilitata auths.tip.discord=Registra una nuova applicazione su https://discordapp.com/developers/applications/me -auths.tip.gitea=Registra una nuova applicazione OAuth2. La guida può essere trovata a https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Crea una nuova applicazione su https://oauth.yandex.com/client/new. Seleziona i seguenti permessi da "Yandex. assport API": "Access to email address", "Access to user avatar" e "Access to username, name and surname, gender"` auths.tip.mastodon=Inserisci un URL di istanza personalizzato per l'istanza mastodon con cui vuoi autenticarti (o usa quella predefinita) auths.edit=Modifica fonte di autenticazione @@ -2700,8 +2695,6 @@ monitor.queue.exemplar=Tipo di esemplare monitor.queue.numberworkers=Numero di workers monitor.queue.maxnumberworkers=Massimo numero di Workers monitor.queue.numberinqueue=Numero in coda -monitor.queue.review=Rivedi configurazione -monitor.queue.review_add=Rivedi/aggiungi Workers monitor.queue.settings.title=Impostazioni pool monitor.queue.settings.maxnumberworkers=Massimo numero di workers monitor.queue.settings.maxnumberworkers.placeholder=Attualmente %[1]d diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index aed68018bd1..b05b63e5ad7 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -80,6 +80,7 @@ milestones=マイルストーン ok=OK cancel=キャンセル +retry=再試行 rerun=再実行 rerun_all=すべてのジョブを再実行 save=保存 @@ -180,7 +181,7 @@ network_error=ネットワークエラー [startpage] app_desc=自分で立てる、超簡単 Git サービス install=簡単インストール -install_desc=シンプルに、プラットフォームに応じてバイナリを実行したり、Dockerで動かしたり、パッケージを使うだけ。 +install_desc=シンプルに、プラットフォームに応じてバイナリを実行したり、Dockerで動かしたり、パッケージを使うだけ。 platform=クロスプラットフォーム platform_desc=GiteaはGoでコンパイルできる環境ならどこでも動きます: Windows、macOS、Linux、ARM等々、好きなものを選んでください! lightweight=軽量 @@ -316,6 +317,7 @@ filter_by_team_repositories=チームリポジトリで絞り込み feed_of=`"%s" のフィード` show_archived=アーカイブ +archived=アーカイブ show_both_archived_unarchived=アーカイブと非アーカイブの両方を表示 show_only_archived=アーカイブのみ表示 show_only_unarchived=非アーカイブのみ表示 @@ -377,6 +379,7 @@ email_not_associate=このメールアドレスは、どのアカウントにも send_reset_mail=アカウント回復メールを送信 reset_password=アカウントの回復 invalid_code=確認コードが無効か期限切れです。 +invalid_code_forgot_password=確認コードは無効または期限切れです。 新しいセッションを開始するにはここをクリックしてください。 invalid_password=アカウントの作成に使用されたパスワードと一致しません。 reset_password_helper=アカウント回復 reset_password_wrong_user=あなたは %s でサインイン中ですが、アカウント回復のリンクは %s のものです。 @@ -597,7 +600,6 @@ overview=概要 following=フォロー中 follow=フォロー unfollow=フォロー解除 -heatmap.loading=ヒートマップを読み込み中… user_bio=経歴 disabled_public_activity=このユーザーはアクティビティ表示を公開していません。 email_visibility.limited=あなたのメールアドレスはすべての認証済みユーザーに表示されています @@ -679,7 +681,7 @@ choose_new_avatar=新しいアバターを選択 update_avatar=アバターを更新 delete_current_avatar=現在のアバターを削除 uploaded_avatar_not_a_image=アップロードしたファイルは画像ファイルではありません。 -uploaded_avatar_is_too_big=アップロードしたファイルは最大サイズを超えています。 +uploaded_avatar_is_too_big=アップロードされたファイルサイズ(%d KiB) が最大サイズ(%d KiB) を超えています。 update_avatar_success=アバターを更新しました。 update_user_avatar_success=ユーザーのアバターを更新しました。 @@ -969,6 +971,7 @@ trust_model_helper_collaborator_committer=共同作業者+コミッター: 共 trust_model_helper_default=デフォルト: このシステムのデフォルトのトラストモデルを使用します create_repo=リポジトリを作成 default_branch=デフォルトブランチ +default_branch_label=デフォルト default_branch_helper=デフォルトブランチはプルリクエストとコードコミットのベースブランチとなります。 mirror_prune=Prune mirror_prune_desc=不要になった古いリモートトラッキング参照を削除 @@ -1153,6 +1156,10 @@ file_view_rendered=レンダリング表示 file_view_raw=Rawデータを見る file_permalink=パーマリンク file_too_large=このファイルは大きすぎるため、表示できません。 +invisible_runes_header=このファイルには不可視のUnicode文字が含まれています +invisible_runes_description=このファイルには人間が識別できない不可視のUnicode文字が含まれており、コンピューターによって特殊な処理が行われる可能性があります。 それが意図的なものと考えられる場合は、この警告を無視して構いません。 不可視文字を表示するにはエスケープボタンを使用します。 +ambiguous_runes_header=このファイルには曖昧(ambiguous)なUnicode文字が含まれています +ambiguous_runes_description=このファイルには、他の文字と見間違える可能性があるUnicode文字が含まれています。 それが意図的なものと考えられる場合は、この警告を無視して構いません。 それらの文字を表示するにはエスケープボタンを使用します。 invisible_runes_line=`この行には不可視のUnicode文字があります` ambiguous_runes_line=`この行には曖昧(ambiguous)なUnicode文字があります` ambiguous_character=`%[1]c [U+%04[1]X] は %[2]c [U+%04[2]X] と混同するおそれがあります` @@ -1165,11 +1172,15 @@ video_not_supported_in_browser=このブラウザはHTML5のvideoタグをサポ audio_not_supported_in_browser=このブラウザーはHTML5のaudioタグをサポートしていません。 stored_lfs=Git LFSで保管されています symbolic_link=シンボリック リンク +executable_file=実行ファイル commit_graph=コミットグラフ commit_graph.select=ブランチを選択 commit_graph.hide_pr_refs=プルリクエストを非表示 commit_graph.monochrome=モノクロ commit_graph.color=カラー +commit.contained_in=このコミットが含まれているのは: +commit.contained_in_default_branch=このコミットはデフォルトブランチに含まれています +commit.load_referencing_branches_and_tags=このコミットを参照しているブランチやタグを取得 blame=Blame download_file=ファイルをダウンロード normal_view=通常表示 @@ -1271,6 +1282,11 @@ commit.cherry-pick=チェリーピック commit.cherry-pick-header=チェリーピック: %s commit.cherry-pick-content=チェリーピック先のブランチを選択: +commitstatus.error=エラー +commitstatus.failure=失敗 +commitstatus.pending=保留 +commitstatus.success=成功 + ext_issues=外部イシューへのアクセス ext_issues.desc=外部のイシュートラッカーへのリンク。 @@ -1384,6 +1400,7 @@ issues.delete_branch_at=`がブランチ %[1]s を削除 %[2]s` issues.filter_label=ラベル issues.filter_label_exclude=`ラベルで除外するには alt + click/enter` issues.filter_label_no_select=すべてのラベル +issues.filter_label_select_no_label=ラベルなし issues.filter_milestone=マイルストーン issues.filter_milestone_all=すべてのマイルストーン issues.filter_milestone_none=マイルストーンなし @@ -1438,6 +1455,7 @@ issues.next=次ページ issues.open_title=オープン issues.closed_title=クローズ issues.draft_title=ドラフト +issues.num_comments_1=%d件のコメント issues.num_comments=%d件のコメント issues.commented_at=`がコメント %s` issues.delete_comment_confirm=このコメントを削除してよろしいですか? @@ -1446,6 +1464,7 @@ issues.context.quote_reply=引用して返信 issues.context.reference_issue=新しいイシューから参照 issues.context.edit=編集 issues.context.delete=削除 +issues.no_content=説明はありません。 issues.close=イシューをクローズ issues.comment_pull_merged_at=がコミット %[1]s を %[2]s にマージ %[3]s issues.comment_manually_pull_merged_at=がコミット %[1]s を %[2]s に手動マージ %[3]s @@ -1463,9 +1482,18 @@ issues.ref_reopening_from=`が%[4]s、プルリクエストが issues.ref_closed_from=`が%[4]s、このイシューをクローズ %[2]s` issues.ref_reopened_from=`が%[4]s、このイシューを再オープン %[2]s` issues.ref_from=` %[1]s にて` -issues.poster=投稿者 -issues.collaborator=共同作業者 -issues.owner=オーナー +issues.author=作成者 +issues.author_helper=このユーザーは作成者です。 +issues.role.owner=オーナー +issues.role.owner_helper=このユーザーはこのリポジトリの所有者です。 +issues.role.member=メンバー +issues.role.member_helper=このユーザーはこのリポジトリを所有している組織のメンバーです。 +issues.role.collaborator=共同作業者 +issues.role.collaborator_helper=このユーザーはリポジトリ上で共同作業するように招待されています。 +issues.role.first_time_contributor=初めての貢献者 +issues.role.first_time_contributor_helper=これは、このユーザーのリポジトリへの最初の貢献です。 +issues.role.contributor=貢献者 +issues.role.contributor_helper=このユーザーは以前にリポジトリにコミットしています。 issues.re_request_review=レビューを再依頼 issues.is_stale=このレビューのあと、このPRに変更がありました issues.remove_request_review=レビュー依頼を取り消し @@ -1480,6 +1508,8 @@ issues.label_title=名前 issues.label_description=説明 issues.label_color=カラー issues.label_exclusive=排他 +issues.label_archive=アーカイブ ラベル +issues.label_archive_tooltip=アーカイブ ラベルはイシューにラベルをつけるときにラベル検索から除外されます。 イシュー上の既存のラベルは影響を受けないため、情報を失わずに古くなったラベルを使用停止にすることができます。 issues.label_exclusive_desc=ラベル名を スコープ/アイテム の形にすることで、他の スコープ/ ラベルと排他的になります。 issues.label_exclusive_warning=イシューやプルリクエストのラベル編集では、競合するスコープ付きラベルは解除されます。 issues.label_count=ラベル %d件 @@ -1614,6 +1644,9 @@ issues.review.pending.tooltip=このコメントは現在他のユーザーに issues.review.review=レビュー issues.review.reviewers=レビューア issues.review.outdated=古い内容 +issues.review.outdated_description=このコメントが作成されたあとにコンテンツが変更されています +issues.review.option.show_outdated_comments=古い内容のコメントも表示 +issues.review.option.hide_outdated_comments=古い内容のコメントを隠す issues.review.show_outdated=古い内容を表示 issues.review.hide_outdated=古い内容を隠す issues.review.show_resolved=解決済みを表示 @@ -1653,6 +1686,13 @@ pulls.switch_comparison_type=比較の種類を切り替える pulls.switch_head_and_base=ヘッドとベースを切り替える pulls.filter_branch=ブランチの絞り込み pulls.no_results=結果が見つかりませんでした。 +pulls.show_all_commits=すべてのコミットを表示 +pulls.show_changes_since_your_last_review=前回の自分のレビューからの変更を表示 +pulls.showing_only_single_commit=コミット %[1]s の変更だけを表示しています +pulls.showing_specified_commit_range=%[1]s..%[2]s の変更だけを表示しています +pulls.select_commit_hold_shift_for_range=コミットを選択。シフトを押しながらクリックで範囲選択 +pulls.review_only_possible_for_full_diff=すべての差分を表示しているときだけレビューが可能です +pulls.filter_changes_by_commit=コミットで絞り込み pulls.nothing_to_compare=同じブランチ同士のため、 プルリクエストを作成する必要がありません。 pulls.nothing_to_compare_and_allow_empty_pr=これらのブランチは内容が同じです。 空のプルリクエストになります。 pulls.has_pull_request=`同じブランチのプルリクエストはすでに存在します: %[2]s#%[3]d` @@ -1724,6 +1764,7 @@ pulls.rebase_conflict_summary=エラーメッセージ pulls.unrelated_histories=マージ失敗: マージHEADとベースには共通する履歴がありません。 ヒント: 別のストラテジーを試してみてください pulls.merge_out_of_date=マージ失敗: マージの生成中にベースが更新されました。 ヒント: もう一度試してみてください pulls.head_out_of_date=マージ失敗: マージの生成中に head が更新されました。 ヒント: もう一度試してみてください +pulls.has_merged=失敗: プルリクエストはマージされていました。再度マージしたり、ターゲットブランチを変更することはできません。 pulls.push_rejected=マージ失敗: プッシュは拒否されました。 このリポジトリのGitフックを見直してください。 pulls.push_rejected_summary=拒否メッセージ全体: pulls.push_rejected_no_message=マージ失敗: プッシュは拒否され、リモートからのメッセージはありません。
このリポジトリのGitフックを見直してください @@ -1764,7 +1805,9 @@ pulls.auto_merge_canceled_schedule_comment=`が、すべてのチェックが成 pulls.delete.title=このプルリクエストを削除しますか? pulls.delete.text=本当にこのプルリクエストを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください) +pulls.recently_pushed_new_branches=%[2]s 、あなたはブランチ %[1]s にプッシュしました +pull.deleted_branch=(削除済み):%s milestones.new=新しいマイルストーン milestones.closed=%s にクローズ @@ -1789,8 +1832,8 @@ milestones.edit_success=マイルストーン "%s" を更新しました。 milestones.deletion=マイルストーンの削除 milestones.deletion_desc=マイルストーンを削除すると、関連するすべてのイシューから除去されます。 続行しますか? milestones.deletion_success=マイルストーンを削除しました。 -milestones.filter_sort.closest_due_date=期日が近い順 -milestones.filter_sort.furthest_due_date=期日が遠い順 +milestones.filter_sort.earliest_due_data=期日が早い順 +milestones.filter_sort.latest_due_date=期日が遅い順 milestones.filter_sort.least_complete=消化率の低い順 milestones.filter_sort.most_complete=消化率の高い順 milestones.filter_sort.most_issues=イシューの多い順 @@ -2288,9 +2331,10 @@ settings.tags.protection.allowed.teams=許可するチーム settings.tags.protection.allowed.noone=なし settings.tags.protection.create=タグを保護 settings.tags.protection.none=タグは保護されていません。 -settings.tags.protection.pattern.description=ひとつのタグ名か、複数のタグにマッチするglobパターンまたは正規表現を使用できます。 詳しくは タグの保護ガイド をご覧ください。 +settings.tags.protection.pattern.description=ひとつのタグ名か、複数のタグにマッチするglobパターンまたは正規表現を使用できます。 詳しくはタグの保護ガイド をご覧ください。 settings.bot_token=Botトークン settings.chat_id=チャットID +settings.thread_id=スレッドID settings.matrix.homeserver_url=ホームサーバー URL settings.matrix.room_id=ルーム ID settings.matrix.message_type=メッセージ種別 @@ -2373,6 +2417,7 @@ diff.show_more=さらに表示 diff.load=差分を読み込み diff.generated=generated diff.vendored=vendored +diff.comment.add_line_comment=行コメントを追加 diff.comment.placeholder=コメントを残す diff.comment.markdown_info=Markdownによる書式設定をサポートしています。 diff.comment.add_single_comment=単独のコメントを追加 @@ -2490,6 +2535,7 @@ tag.create_success=タグ "%s" を作成しました。 topic.manage_topics=トピックの管理 topic.done=完了 topic.count_prompt=選択できるのは25トピックまでです。 +topic.format_prompt=トピック名は英字または数字で始め、ダッシュ('-')やドット('.')を含めることができます。最大35文字までです。文字は小文字でなければなりません。 find_file.go_to_file=ファイルへ移動 find_file.no_matching=一致するファイルが見つかりません @@ -2528,6 +2574,7 @@ form.create_org_not_allowed=組織を作成する権限がありません。 settings=設定 settings.options=組織 settings.full_name=フルネーム +settings.email=連絡先メールアドレス settings.website=Webサイト settings.location=場所 settings.permission=許可 @@ -2623,10 +2670,13 @@ teams.invite.description=下のボタンをクリックしてチームに参加 [admin] dashboard=ダッシュボード +identity_access=アイデンティティとアクセス users=ユーザーアカウント organizations=組織 +assets=コード アセット repositories=リポジトリ hooks=Webhook +integrations=連携 authentication=認証ソース emails=ユーザーメールアドレス config=設定 @@ -2664,6 +2714,7 @@ dashboard.delete_repo_archives.started=リポジトリアーカイブをすべ dashboard.delete_missing_repos=Gitファイルが存在しないリポジトリをすべて削除 dashboard.delete_missing_repos.started=Gitファイルが存在しないリポジトリをすべて削除するタスクを開始しました。 dashboard.delete_generated_repository_avatars=自動生成したリポジトリアバターを削除 +dashboard.sync_repo_branches=Gitデータからデータベースへ不足しているブランチを同期 dashboard.update_mirrors=ミラーの更新 dashboard.repo_health_check=全リポジトリのヘルスチェック dashboard.check_repo_stats=全リポジトリの統計情報を更新 @@ -2680,6 +2731,7 @@ dashboard.reinit_missing_repos=レコードが存在するが見当たらない dashboard.sync_external_users=外部ユーザーデータの同期 dashboard.cleanup_hook_task_table=hook_taskテーブルのクリーンアップ dashboard.cleanup_packages=期限切れパッケージのクリーンアップ +dashboard.cleanup_actions=Actionsの期限切れのログとアーティファクトのクリーンアップ dashboard.server_uptime=サーバーの稼働時間 dashboard.current_goroutine=現在のGoroutine数 dashboard.current_memory_usage=現在のメモリ使用量 @@ -2717,6 +2769,9 @@ dashboard.gc_lfs=LFSメタオブジェクトのガベージコレクション dashboard.stop_zombie_tasks=ゾンビタスクを停止 dashboard.stop_endless_tasks=終わらないタスクを停止 dashboard.cancel_abandoned_jobs=放置されたままのジョブをキャンセル +dashboard.start_schedule_tasks=スケジュールタスクを開始 +dashboard.sync_branch.started=ブランチの同期を開始しました +dashboard.rebuild_issue_indexer=イシューインデクサーの再構築 users.user_manage_panel=ユーザーアカウント管理 users.new_account=ユーザーアカウントを作成 @@ -2725,6 +2780,9 @@ users.full_name=フルネーム users.activated=アクティベート済み users.admin=管理者 users.restricted=制限あり +users.reserved=予約済み +users.bot=Bot +users.remote=リモート users.2fa=2FA users.repos=リポジトリ users.created=作成日 @@ -2771,6 +2829,7 @@ users.list_status_filter.is_prohibit_login=ログインを禁止 users.list_status_filter.not_prohibit_login=ログインを許可 users.list_status_filter.is_2fa_enabled=2要素認証有効 users.list_status_filter.not_2fa_enabled=2要素認証無効 +users.details=ユーザーの詳細 emails.email_manage_panel=ユーザーメールアドレスの管理 emails.primary=プライマリー @@ -2802,10 +2861,12 @@ repos.stars=スター repos.forks=フォーク repos.issues=イシュー repos.size=サイズ +repos.lfs_size=LFSサイズ packages.package_manage_panel=パッケージ管理 packages.total_size=合計サイズ: %s packages.unreferenced_size=非参照サイズ: %s +packages.cleanup=期限切れデータを掃除する packages.owner=オーナー packages.creator=作成者 packages.name=名前 @@ -2816,12 +2877,12 @@ packages.size=サイズ packages.published=配布 defaulthooks=デフォルトWebhook -defaulthooks.desc=Webhookは、特定のGiteaイベントトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはwebhooks guideをご覧下さい。 +defaulthooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義されたWebhookはデフォルトとなり、全ての新規リポジトリにコピーされます。 詳しくはWebhooksガイドをご覧下さい。 defaulthooks.add_webhook=デフォルトWebhookの追加 defaulthooks.update_webhook=デフォルトWebhookの更新 systemhooks=システムWebhook -systemhooks.desc=Webhookは、特定のGiteaイベントトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはwebhooks guideをご覧下さい。 +systemhooks.desc=Webhookは、特定のGiteaイベントのトリガーが発生した際に、自動的にHTTP POSTリクエストをサーバーへ送信するものです。 ここで定義したWebhookはシステム内のすべてのリポジトリで呼び出されます。 そのため、パフォーマンスに及ぼす影響を考慮したうえで設定してください。 詳しくはWebhooksガイドをご覧下さい。 systemhooks.add_webhook=システムWebhookを追加 systemhooks.update_webhook=システムWebhookを更新 @@ -2914,6 +2975,7 @@ auths.sspi_default_language=ユーザーのデフォルトの言語 auths.sspi_default_language_helper=SSPI認証処理によって自動的に作成されるユーザーのデフォルトの言語です。 言語を自動検出する方が良い場合は空のままにしてください。 auths.tips=ヒント auths.tips.oauth2.general=OAuth2認証 +auths.tips.oauth2.general.tip=新しいOAuth2認証を登録するときは、コールバック/リダイレクトURLは以下になります: auths.tip.oauth2_provider=OAuth2プロバイダー auths.tip.bitbucket=新しいOAuthコンシューマーを https://bitbucket.org/account/user/<あなたのユーザー名>/oauth-consumers/new から登録し、"アカウント" に "読み取り" 権限を追加してください。 auths.tip.nextcloud=新しいOAuthコンシューマーを、インスタンスのメニュー "Settings -> Security -> OAuth 2.0 client" から登録してください。 @@ -2925,7 +2987,7 @@ auths.tip.google_plus=OAuth2クライアント資格情報を、Google APIコン auths.tip.openid_connect=OpenID Connect DiscoveryのURL (/.well-known/openid-configuration) をエンドポイントとして指定してください auths.tip.twitter=https://dev.twitter.com/apps へアクセスしてアプリケーションを作成し、“Allow this application to be used to Sign in with Twitter”オプションを有効にしてください。 auths.tip.discord=新しいアプリケーションを https://discordapp.com/developers/applications/me から登録してください。 -auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.io/en-us/oauth2-provider/ +auths.tip.gitea=新しいOAuthアプリケーションを登録してください。 利用ガイドは https://docs.gitea.com/development/oauth2-provider にあります auths.tip.yandex=`https://oauth.yandex.com/client/new で新しいアプリケーションを作成してください。 "Yandex.Passport API" セクションで次の項目を許可します: "Access to email address"、"Access to user avatar"、"Access to username, first name and surname, gender"` auths.tip.mastodon=認証したいMastodonインスタンスのカスタムURLを入力してください (入力しない場合はデフォルトのURLを使用します) auths.edit=認証ソースの編集 @@ -2955,6 +3017,7 @@ config.disable_router_log=ルーターのログが無効 config.run_user=実行ユーザー名 config.run_mode=実行モード config.git_version=Gitバージョン +config.app_data_path=Appデータパス config.repo_root_path=リポジトリのルートパス config.lfs_root_path=LFSルートパス config.log_file_root_path=ログの保存先パス @@ -3106,10 +3169,10 @@ monitor.queue.name=キュー名 monitor.queue.type=種類 monitor.queue.exemplar=要素の型 monitor.queue.numberworkers=ワーカー数 +monitor.queue.activeworkers=使用ワーカー数 monitor.queue.maxnumberworkers=ワーカー数上限 monitor.queue.numberinqueue=キュー内の数 -monitor.queue.review=設定確認 -monitor.queue.review_add=確認/ワーカー追加 +monitor.queue.review_add=ワーカーの確認 / 追加 monitor.queue.settings.title=プール設定 monitor.queue.settings.desc=プールはワーカーキューの待機状態に応じて動的に大きくなります。 monitor.queue.settings.maxnumberworkers=ワーカー数上限 @@ -3230,6 +3293,7 @@ desc=リポジトリ パッケージを管理します。 empty=パッケージはまだありません。 empty.documentation=パッケージレジストリの詳細については、 ドキュメント を参照してください。 empty.repo=パッケージはアップロードしたけども、ここに表示されない? パッケージ設定を開いて、パッケージをこのリポジトリにリンクしてください。 +registry.documentation=%sレジストリの詳細については、 ドキュメント を参照してください。 filter.type=タイプ filter.type.all=すべて filter.no_result=フィルタの結果、空になりました。 @@ -3319,6 +3383,8 @@ pub.install=Dart を使用してパッケージをインストールするには pypi.requires=必要なPython pypi.install=pip を使用してパッケージをインストールするには、次のコマンドを実行します: rpm.registry=このレジストリをコマンドラインからセットアップします: +rpm.distros.redhat=RedHat系ディストリビューションの場合 +rpm.distros.suse=SUSE系ディストリビューションの場合 rpm.install=パッケージをインストールするには、次のコマンドを実行します: rubygems.install=gem を使用してパッケージをインストールするには、次のコマンドを実行します: rubygems.install2=または Gemfile に追加します: @@ -3416,6 +3482,7 @@ runners.labels=ラベル runners.last_online=最終オンライン時刻 runners.runner_title=ランナー runners.task_list=このランナーの最近のタスク +runners.task_list.no_tasks=タスクはまだありません。 runners.task_list.run=実行 runners.task_list.status=ステータス runners.task_list.repository=リポジトリ @@ -3440,6 +3507,7 @@ runners.reset_registration_token_success=ランナー登録トークンをリセ runs.all_workflows=すべてのワークフロー runs.commit=コミット +runs.scheduled=スケジュール済み runs.pushed_by=pushed by runs.invalid_workflow_helper=ワークフロー設定ファイルは無効です。あなたの設定ファイルを確認してください: %s runs.no_matching_runner_helper=一致するランナーがありません: %s @@ -3454,6 +3522,7 @@ workflow.disable=ワークフローを無効にする workflow.disable_success=ワークフロー '%s' が無効になりました。 workflow.enable=ワークフローを有効にする workflow.enable_success=ワークフロー '%s' が有効になりました。 +workflow.disabled=ワークフローは無効です。 need_approval_desc=フォークプルリクエストのワークフローを実行するには承認が必要です。 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index e8ed4b96957..b9fd36e83d8 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -360,7 +360,6 @@ overview=개요 following=팔로우 중 follow=추적하기 unfollow=추적해제 -heatmap.loading=Heatmap 불러오는 중... user_bio=소개 @@ -402,7 +401,6 @@ choose_new_avatar=새로운 아바타 선택 update_avatar=아바타 변경하기 delete_current_avatar=현재 아바타 삭제 uploaded_avatar_not_a_image=업로드 된 파일은 이미지가 아닙니다. -uploaded_avatar_is_too_big=업로드된 파일이 최대 크기를 넘습니다. update_avatar_success=아바타가 변경되었습니다. change_password=비밀번호 변경 @@ -674,6 +672,8 @@ commits.signed_by=로그인 계정 commits.gpg_key_id=GPG 키 ID +commitstatus.pending=보류 + ext_issues.desc=외부 이슈 트래커 연결. projects.description_placeholder=설명 @@ -761,9 +761,8 @@ issues.reopen_issue=다시 열기 issues.reopen_comment_issue=다시 오픈 및 코멘트 issues.create_comment=코멘트 issues.commit_ref_at=` 커밋 %[2]s에서 이 이슈 언급` -issues.poster=포스터 -issues.collaborator=협업자 -issues.owner=소유자 +issues.role.owner=소유자 +issues.role.member=멤버 issues.sign_in_require_desc="로그인하여 이 대화에 참여" issues.edit=수정 issues.cancel=취소 @@ -884,8 +883,6 @@ milestones.modify=마일스톤 갱신 milestones.deletion=마일스톤 삭제 milestones.deletion_desc=마일스톤을 삭제하면 연관된 모든 이슈에서 삭제됩니다. 계속 하시겠습니까? milestones.deletion_success=마일스톤이 삭제되었습니다. -milestones.filter_sort.closest_due_date=마감일이 가까운 순 -milestones.filter_sort.furthest_due_date=마감일이 먼 순 milestones.filter_sort.least_complete=완료율이 낮은 순 milestones.filter_sort.most_complete=완료율이 높은 순 milestones.filter_sort.most_issues=이슈 많은 순 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 25e1371329b..2cc8085c187 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -175,7 +175,6 @@ network_error=Tīkla kļūda [startpage] app_desc=Viegli uzstādāms Git serviss install=Vienkārši instalējams -install_desc=Nepieciešams tikai palaist izpildāmo failu vajadzīgajai platformai. Izmantot Docker vai izmantot pakotni. platform=Pieejama dažādām platformām platform_desc=Gitea iespējams uzstādīt jebkur, kam Go var nokompilēt: Windows, macOS, Linux, ARM utt. Izvēlies to, kas tev patīk! lightweight=Viegla @@ -308,6 +307,7 @@ filter_by_team_repositories=Filtrēt pēc komandas repozitorijiem feed_of=`"%s" plūsma` show_archived=Arhivētie +archived=Arhivētie show_both_archived_unarchived=Attēlot gan arhivētos, gan nearhivētos show_only_archived=Attēlot tikai arhivētos show_only_unarchived=Attēlot tikai nearhivētos @@ -582,7 +582,6 @@ overview=Pārskats following=Seko follow=Sekot unfollow=Nesekot -heatmap.loading=Ielādē intensitātes karti… user_bio=Biogrāfija disabled_public_activity=Šis lietotājs ir atslēdzies iespēju aplūkot tā aktivitāti. email_visibility.limited=E-pasta adrese ir redzama visiem autentificētajiem lietotājiem @@ -655,7 +654,6 @@ choose_new_avatar=Izvēlēties jaunu profila attēlu update_avatar=Saglabāt profila bildi delete_current_avatar=Dzēst pašreizējo profila bildi uploaded_avatar_not_a_image=Augšupielādētais fails nav attēls. -uploaded_avatar_is_too_big=Augšupielādētais fails parsniedz maksimālo izmēru. update_avatar_success=Profila attēls tika saglabāts. update_user_avatar_success=Lietotāja profila attēls tika atjaunots. @@ -1217,6 +1215,11 @@ commit.cherry-pick=Izlasīt commit.cherry-pick-header=Izlasīt: %s commit.cherry-pick-content=Norādiet atzaru uz kuru izlasīt: +commitstatus.error=Kļūda +commitstatus.failure=Neveiksmīgs +commitstatus.pending=Nav iesūtīts +commitstatus.success=Pabeigts + ext_issues=Piekļuve ārējām problēmām ext_issues.desc=Saite uz ārējo problēmu sekotāju. @@ -1408,9 +1411,9 @@ issues.ref_reopening_from=`atsaucās uz izmaiņu pieprasījumu % issues.ref_closed_from=`aizvēra problēmu %[4]s %[2]s` issues.ref_reopened_from=`atkārtoti atvēra problēmu %[4]s %[2]s` issues.ref_from=`no %[1]s` -issues.poster=Autors -issues.collaborator=Līdzstrādnieks -issues.owner=Īpašnieks +issues.author=Autors +issues.role.owner=Īpašnieks +issues.role.member=Biedri issues.re_request_review=Pieprasīt atkārtotu recenziju issues.is_stale=Šajā izmaiņu pieprasījumā ir notikušas izmaiņās, kopš veicāt tā recenziju issues.remove_request_review=Noņemt recenzijas pieprasījumu @@ -1725,8 +1728,6 @@ milestones.edit_success=Izmaiņas atskaites punktā "%s" tika veiksmīgi saglab milestones.deletion=Dzēst atskaites punktu milestones.deletion_desc=Dzēšot šo atskaites punktu, tas tiks noņemts no visām saistītajām problēmām un izmaiņu pieprasījumiem. Vai turpināt? milestones.deletion_success=Atskaites punkts tika veiksmīgi izdzēsts. -milestones.filter_sort.closest_due_date=Tuvākais termiņš -milestones.filter_sort.furthest_due_date=Tālākais termiņš milestones.filter_sort.least_complete=Vismazāk pabeigtais milestones.filter_sort.most_complete=Visvairāk pabeigtais milestones.filter_sort.most_issues=Visvairāk problēmu @@ -2207,7 +2208,6 @@ settings.tags.protection.allowed.teams=Atļauts komandām settings.tags.protection.allowed.noone=Nevienam settings.tags.protection.create=Aizsargāt tagus settings.tags.protection.none=Nav uzstādīta tagu aizsargāšana. -settings.tags.protection.pattern.description=Var izmantot pilnu nosaukumu, glob šablonu vai regulāro izteiksmi, lai aizsargātu vairākus tagus. Detalizētāk var izlasīt tagu aizsargāšanas pamācībā. settings.bot_token=Bota pilnvara settings.chat_id=Tērzēšanas ID settings.matrix.homeserver_url=Mājas servera URL @@ -2722,12 +2722,10 @@ packages.size=Izmērs packages.published=Publicēts defaulthooks=Noklusētie tīmekļa āķi -defaulthooks.desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikumiem, kas notiek Gitea. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Šeit izveidotie tīmekļa āķi tiks pievienoti visiem jaunajajiem repozitorijiem. Lai uzzinātu sīkāk skatieties tīmekļa āķu rokasgrāmatā. defaulthooks.add_webhook=Pievienot noklusēto tīmekļa āķi defaulthooks.update_webhook=Mainīt noklusēto tīmekļa āķi systemhooks=Sistēmas tīmekļa āķi -systemhooks.desc=Tīmekļa āķi automātiski veic HTTP POST pieprasījumus uz serveri, kad notiek noteikti Gitea notikumi. Tīmekļa āķi izpildīsies uz visu servera repozitoriju notikumiem, tāpēc būtu jāņem vērā, ka tas var radīt ātrdarbības problēmas. Vairāk par tiem var uzzināt tīmekļa āķu dokumentācijā. systemhooks.add_webhook=Pievienot sistēmas tīmekļa āķi systemhooks.update_webhook=Mainīt sistēmas tīmekļa āķi @@ -2831,7 +2829,6 @@ auths.tip.google_plus=Iegūstiet OAuth2 klienta pilnvaru no Google API konsoles auths.tip.openid_connect=Izmantojiet OpenID pieslēgšanās atklāšanas URL (/.well-known/openid-configuration), lai norādītu galapunktus auths.tip.twitter=Dodieties uz adresi https://dev.twitter.com/apps, izveidojiet aplikāciju un pārliecinieties, ka ir atzīmēts “Allow this application to be used to Sign in with Twitter” auths.tip.discord=Reģistrējiet jaunu aplikāciju adresē https://discordapp.com/developers/applications/me -auths.tip.gitea=Reģistrēt jaunu OAuth2 lietojumprogrammu. Pamācību iespējams atrast https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Izveidojiet jaunu lietotni adresē https://oauth.yandex.com/client/new. Izvēlieties sekojošas tiesības "Yandex.Passport API" sadaļā: "Access to email address", "Access to user avatar" un "Access to username, first name and surname, gender"` auths.tip.mastodon=Norādiet pielāgotu mastodon instances URL, ar kuru vēlaties autorizēties (vai izmantojiet noklusēto) auths.edit=Labot autentifikācijas avotu @@ -3014,8 +3011,6 @@ monitor.queue.exemplar=Eksemplāra veids monitor.queue.numberworkers=Strādņu skaits monitor.queue.maxnumberworkers=Maksimālais strādņu skaits monitor.queue.numberinqueue=Skaits rindā -monitor.queue.review=Pārbaudīt konfigurāciju -monitor.queue.review_add=Pārbaudīt/Pievienot strādņus monitor.queue.settings.title=Pūla iestatījumi monitor.queue.settings.desc=Pūls dinamiski tiek palielināts atkarībā no bloķētiem darbiem rindā. monitor.queue.settings.maxnumberworkers=Maksimālais strādņu skaits diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 0ad219f2833..aa94a542f18 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -134,7 +134,6 @@ network_error=Netwerk fout [startpage] app_desc=Een eenvoudige, self-hosted Git service install=Makkelijk te installeren -install_desc=Je hoeft alleen maar de binary uit te voeren, gebruik het met Docker, of download een installatiepakket. platform=Cross-platform platform_desc=Gitea werkt op alles waar Go op kan compileren: Windows, macOS, Linux, ARM, etc. Kies het platform dat bij je past! lightweight=Lichtgewicht @@ -261,6 +260,7 @@ filter_by_team_repositories=Filter op team repositories feed_of=`Feed van "%s"` show_archived=Gearchiveerd +archived=Gearchiveerd show_both_archived_unarchived=Toont zowel gearchiveerd als niet-gearchiveerd show_only_archived=Toon alleen gearchiveerd show_only_unarchived=Toon alleen niet gearchiveerd @@ -504,7 +504,6 @@ overview=Overzicht following=Volgt follow=Volg unfollow=Niet meer volgen -heatmap.loading=Heatmap wordt geladen… user_bio=Biografie disabled_public_activity=Deze gebruiker heeft de publieke zichtbaarheid van de activiteit uitgeschakeld. @@ -568,7 +567,6 @@ choose_new_avatar=Kies een nieuwe avatar update_avatar=Update Avatar delete_current_avatar=Verwijder huidige avatar uploaded_avatar_not_a_image=Het geüploade bestand is geen afbeelding. -uploaded_avatar_is_too_big=Het geüploade bestand heeft de maximale grootte overschreden. update_avatar_success=Je avatar is bijgewerkt. update_user_avatar_success=De avatar van de gebruiker is bijgewerkt. @@ -1075,6 +1073,9 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=Selecteer een branch om te cherry-pick op: +commitstatus.error=Fout +commitstatus.pending=In behandeling + ext_issues=Toegang tot Externe Issues ext_issues.desc=Koppelen aan een externe kwestie-tracker. @@ -1236,9 +1237,8 @@ issues.ref_reopening_from=`verwees naar een pull request %[4]s d issues.ref_closed_from=`sloot dit issue %[4]s %[2]s` issues.ref_reopened_from=`heropende dit issue %[4]s %[2]s` issues.ref_from=`van %[1]s` -issues.poster=Poster -issues.collaborator=Medewerker -issues.owner=Eigenaar +issues.role.owner=Eigenaar +issues.role.member=Lid 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 @@ -1528,8 +1528,6 @@ milestones.modify=Mijlpaal bijwerken milestones.deletion=Mijlpaal verwijderen milestones.deletion_desc=Als je een mijlpaal verwijdert, wordt hij van alle gerelateerde kwesties verwijderd. Doorgaan? milestones.deletion_success=De mijlpaal is verwijderd. -milestones.filter_sort.closest_due_date=Dichtstbijzijnde deadline -milestones.filter_sort.furthest_due_date=Verste deadline milestones.filter_sort.least_complete=Minst compleet milestones.filter_sort.most_complete=Meest compleet milestones.filter_sort.most_issues=Meeste problemen @@ -1686,7 +1684,6 @@ settings.enable_timetracker=Tijdregistratie inschakelen settings.allow_only_contributors_to_track_time=Sta alleen bijdragers toe tijdregistratie te gebruiken settings.pulls_desc=Repository-pull-aanvragen inschakelen settings.pulls.ignore_whitespace=Witruimte negeren voor conflicten -settings.trust_model.collaborator=Medewerker settings.trust_model.collaborator.long=Medewerker: Vertrouw handtekeningen door medewerkers settings.trust_model.committer=Committer settings.trust_model.committer.long=Committer: Vertrouw handtekeningen die overeenkomen met committers (Dit komt overeen met GitHub en zal Gitea ondertekende commits dwingen om Gitea als de committer te hebben) @@ -1898,7 +1895,6 @@ settings.tags.protection.allowed.teams=Toegestane teams settings.tags.protection.allowed.noone=Niemand settings.tags.protection.create=Beveilig Label settings.tags.protection.none=Er zijn geen beveiligde labels. -settings.tags.protection.pattern.description=U kunt een enkele naam gebruiken of een glob patroon of reguliere expressie om meerdere labels te matchen. Lees meer in de beschermde labels gids. settings.bot_token=Bot Token settings.chat_id=Chat-ID settings.matrix.homeserver_url=Homeserver URL @@ -2533,8 +2529,6 @@ monitor.queue.type=Type monitor.queue.exemplar=Type voorbeeld monitor.queue.numberworkers=Aantal workers monitor.queue.maxnumberworkers=Maximum aantal workers -monitor.queue.review=Configuratie herzien -monitor.queue.review_add=Beoordeel/Voeg workers toe monitor.queue.settings.title=Pool instellingen monitor.queue.settings.maxnumberworkers=Maximum aantal workers monitor.queue.settings.maxnumberworkers.placeholder=Momenteel %[1]d diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 9a97b53c837..255f36598c9 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -132,7 +132,6 @@ network_error=Błąd sieci [startpage] app_desc=Bezbolesna usługa Git na własnym serwerze install=Łatwa instalacja -install_desc=Po prostu odpal plik binarny dla swojej platformy, uruchom przy pomocy Dockera, lub zainstaluj z paczki. platform=Wieloplatformowość platform_desc=Gitea ruszy gdziekolwiek Go jest możliwe do skompilowania: Windows, macOS, Linux, ARM, itd. Wybierz swój ulubiony system! lightweight=Niskie wymagania @@ -259,6 +258,7 @@ filter_by_team_repositories=Filtruj według repozytoriów zespołu feed_of=`Kanał "%s"` show_archived=Zarchiwizowane +archived=Zarchiwizowane show_both_archived_unarchived=Wyświetlanie zarchiwizowanych i niezarchiwizowanych show_only_archived=Wyświetlanie tylko zarchiwizowanych show_only_unarchived=Wyświetlanie tylko niezarchiwizowanych @@ -489,7 +489,6 @@ overview=Przegląd following=Obserwowani follow=Obserwuj unfollow=Przestań obserwować -heatmap.loading=Ładowanie mapy cieplnej… user_bio=Biografia disabled_public_activity=Ten użytkownik wyłączył publiczne wyświetlanie jego aktywności. @@ -537,7 +536,6 @@ choose_new_avatar=Wybierz nowy avatar update_avatar=Aktualizuj awatar delete_current_avatar=Usuń obecny Avatar uploaded_avatar_not_a_image=Załadowany plik nie jest obrazem. -uploaded_avatar_is_too_big=Przesłany plik przekroczył maksymalny rozmiar. update_avatar_success=Twój awatar został zmieniony. change_password=Aktualizuj hasło @@ -993,6 +991,9 @@ commits.signed_by_untrusted_user_unmatched=Podpisane przez niezaufanego użytkow commits.gpg_key_id=ID klucza GPG +commitstatus.error=Błąd +commitstatus.pending=Oczekująca + ext_issues.desc=Link do zewnętrznego systemu śledzenia zgłoszeń. projects=Projekty @@ -1139,9 +1140,8 @@ issues.ref_reopening_from=`odwołał(-a) się do Pull Requesta % issues.ref_closed_from=`zamknął(-ęła) to zgłoszenie %[4]s %[2]s` issues.ref_reopened_from=`ponownie otworzył(-a) to zgłoszenie %[4]s %[2]s` issues.ref_from=`z %[1]s` -issues.poster=Autor -issues.collaborator=Współpracownik -issues.owner=Właściciel +issues.role.owner=Właściciel +issues.role.member=Członek issues.re_request_review=Poproś o ponowną recenzję issues.remove_request_review=Usuń prośbę o recenzję issues.remove_request_review_block=Nie można usunąć prośby o recenzję @@ -1380,8 +1380,6 @@ milestones.modify=Zaktualizuj cel milestones.deletion=Usuń kamień milowy milestones.deletion_desc=Usunięcie celu usuwa go z wszystkich pozostałych zagadnień. Kontynuować? milestones.deletion_success=Cel został usunięty. -milestones.filter_sort.closest_due_date=Najbliżej daty realizacji -milestones.filter_sort.furthest_due_date=Najdalej daty realizacji milestones.filter_sort.least_complete=Najmniej kompletne milestones.filter_sort.most_complete=Najbardziej kompletne milestones.filter_sort.most_issues=Najwięcej zgłoszeń @@ -1761,7 +1759,6 @@ settings.tags.protection.allowed.teams=Dozwolone zespoły settings.tags.protection.allowed.noone=Brak settings.tags.protection.create=Chroń tag settings.tags.protection.none=Brak chronionych tagów. -settings.tags.protection.pattern.description=Możesz użyć pojedynczej nazwy lub wzoru glob lub wyrażenia regularnego, aby dopasować wiele tagów. Dowiedz się więcej w przewodniku tagów. settings.bot_token=Token bota settings.chat_id=ID czatu settings.matrix.homeserver_url=Adres URL serwera domowego @@ -2180,12 +2177,10 @@ packages.repository=Repozytorium packages.size=Rozmiar defaulthooks=Domyślne Webhooki -defaulthooks.desc=Webhooki automatycznie wysyłają zapytania HTTP POST na serwer, gdy niektóre zdarzenia Gitea je wyzwalają. Webhooki zdefiniowane tutaj są domyślne i zostaną skopiowane do wszystkich nowych repozytoriów. Przeczytaj więcej w przewodniku webhooków. defaulthooks.add_webhook=Dodaj domyślny Webhook defaulthooks.update_webhook=Zaktualizuj domyślny Webhook systemhooks=Webhooki Systemowe -systemhooks.desc=Webhooki automatycznie tworzą zapytania HTTP POST do serwera, kiedy następują pewne zdarzenia w Gitea. Webhooki zdefiniowane w tym miejscu będą wykonywane dla wszystkich repozytoriów, więc rozważ ewentualne konsekwencje pod względem wydajności. Przeczytaj o tym więcej w przewodniku o Webhookach. systemhooks.add_webhook=Dodaj Webhook Systemowy systemhooks.update_webhook=Aktualizuj Webhook Systemowy @@ -2265,7 +2260,6 @@ auths.tip.google_plus=Uzyskaj dane uwierzytelniające klienta OAuth2 z konsoli G auths.tip.openid_connect=Użyj adresu URL OpenID Connect Discovery (/.well-known/openid-configuration), aby określić punkty końcowe auths.tip.twitter=Przejdź na https://dev.twitter.com/apps, stwórz aplikację i upewnij się, że opcja “Allow this application to be used to Sign in with Twitter” jest włączona auths.tip.discord=Zarejestruj nową aplikację na https://discordapp.com/developers/applications/me -auths.tip.gitea=Zarejestruj nową aplikację OAuth2. Przewodnik można znaleźć na https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Utwórz nową aplikację na https://oauth.yandex.com/client/new. Wybierz następujące uprawnienia z "Yandex.Passport API": "Access to email address", "Access to user avatar" and "Access to username, first name and surname, gender"` auths.tip.mastodon=Wprowadź niestandardowy adres URL instancji mastodona, którą chcesz uwierzytelnić (lub użyj domyślnego) auths.edit=Edytuj źródło uwierzytelniania @@ -2423,8 +2417,6 @@ monitor.queue.type=Typ monitor.queue.exemplar=Przykładowy typ monitor.queue.numberworkers=Liczba procesów pracujących monitor.queue.maxnumberworkers=Maksymalna liczba procesów pracujących -monitor.queue.review=Przejrzyj konfigurację -monitor.queue.review_add=Przejrzyj/Dodaj procesy pracujące monitor.queue.settings.title=Ustawienia Puli monitor.queue.settings.maxnumberworkers=Maksymalna liczba procesów pracujących monitor.queue.settings.maxnumberworkers.placeholder=Obecnie %[1]d diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 777805d8dc6..91881310778 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -175,7 +175,6 @@ network_error=Erro de rede [startpage] app_desc=Um serviço de hospedagem Git amigável install=Fácil de instalar -install_desc=Simplesmente execute o binário para seu sistema operacional, instale com o Docker ou faça download do pacote. platform=Multi-plataforma platform_desc=Gitea roda em qualquer sistema operacional em que Go consegue compilar: Windows, macOS, Linux, ARM, etc. Escolha qual você gosta mais! lightweight=Leve e rápido @@ -308,6 +307,7 @@ filter_by_team_repositories=Filtrar por repositórios da equipe feed_of=`Feed de "%s"` show_archived=Arquivado +archived=Arquivado show_both_archived_unarchived=Mostrando arquivados e não arquivados show_only_archived=Mostrando somente arquivados show_only_unarchived=Mostrando somente não arquivados @@ -582,7 +582,6 @@ overview=Visão geral following=Seguindo follow=Seguir unfollow=Deixar de seguir -heatmap.loading=Carregando mapa de calor... user_bio=Biografia disabled_public_activity=Este usuário desativou a visibilidade pública da atividade. email_visibility.limited=Seu endereço de e-mail está visível para todos os usuários autenticados @@ -655,7 +654,6 @@ choose_new_avatar=Escolha um novo avatar update_avatar=Atualizar o avatar delete_current_avatar=Excluir o avatar atual uploaded_avatar_not_a_image=O arquivo enviado não é uma imagem. -uploaded_avatar_is_too_big=O arquivo enviado excedeu o tamanho máximo. update_avatar_success=Seu avatar foi atualizado. update_user_avatar_success=O avatar do usuário foi atualizado. @@ -1216,6 +1214,11 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=Selecione o branch para receber o cherry-pick: +commitstatus.error=Erro +commitstatus.failure=Falha +commitstatus.pending=Pendente +commitstatus.success=Sucesso + ext_issues=Acesso a Issues Externos ext_issues.desc=Link para o issue tracker externo. @@ -1404,9 +1407,9 @@ issues.ref_reopening_from=`referenciado um pull request %[4]s qu issues.ref_closed_from=`fechou esta issue %[4]s %[2]s` issues.ref_reopened_from=`reabriu esta issue %[4]s %[2]s` issues.ref_from=`de %[1]s` -issues.poster=Autor -issues.collaborator=Colaborador -issues.owner=Proprietário +issues.author=Autor +issues.role.owner=Proprietário +issues.role.member=Membro issues.re_request_review=Re-solicitar revisão issues.is_stale=Houve alterações nessa PR desde essa revisão issues.remove_request_review=Remover solicitação de revisão @@ -1720,8 +1723,6 @@ milestones.edit_success=O marco "%s" foi atualizado. milestones.deletion=Excluir marco milestones.deletion_desc=A exclusão deste marco irá removê-lo de todas as issues. Tem certeza que deseja continuar? milestones.deletion_success=O marco foi excluído. -milestones.filter_sort.closest_due_date=Data limite mais próxima -milestones.filter_sort.furthest_due_date=Data limite mais distante milestones.filter_sort.least_complete=Menos completo milestones.filter_sort.most_complete=Mais completo milestones.filter_sort.most_issues=Com mais issues @@ -2181,7 +2182,6 @@ settings.tags.protection.allowed.teams=Equipes permitidas settings.tags.protection.allowed.noone=Ninguém settings.tags.protection.create=Proteger tag settings.tags.protection.none=Não há tags protegidas. -settings.tags.protection.pattern.description=Você pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias tags. Para mais informações leia o guia das tags protegidas. settings.bot_token=Token do Bot settings.chat_id=ID do Chat settings.matrix.homeserver_url=URL do Homeserver @@ -2693,12 +2693,10 @@ packages.size=Tamanho packages.published=Publicado defaulthooks=Webhooks Padrões -defaulthooks.desc=Webhooks automaticamente fazem requisições HTTP POST para um servidor quando acionados por determinados eventos do Gitea. Webhooks definidos aqui são os padrões e serão copiados para todos os novos repositórios. Leia mais no guia de webhooks. defaulthooks.add_webhook=Adicionar Webhook Padrão defaulthooks.update_webhook=Atualizar Webhook Padrão systemhooks=Webhooks do Sistema -systemhooks.desc=Webhooks automaticamente fazem requisições HTTP POST para um servidor quando acionados por determinados eventos do Gitea. Webhooks definidos aqui agirão em todos os repositórios do sistema, então, por favor, considere quaisquer implicações de desempenho que isso possa ter. Leia mais no guia de webhooks. systemhooks.add_webhook=Adicionar Webhook do Sistema systemhooks.update_webhook=Atualizar Webhook do Sistema @@ -2802,7 +2800,6 @@ auths.tip.google_plus=Obter credenciais de cliente OAuth2 do console de API do G auths.tip.openid_connect=Use o OpenID Connect Discovery URL (/.well-known/openid-configuration) para especificar os endpoints auths.tip.twitter=Vá em https://dev.twitter.com/apps, crie um aplicativo e certifique-se de que está habilitada a opção “Allow this application to be used to Sign in with Twitter“ auths.tip.discord=Cadastrar um novo aplicativo em https://discordapp.com/developers/applications/me -auths.tip.gitea=Cadastrar um novo aplicativo OAuth2. Guia pode ser encontrado em https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Crie um novo aplicativo em https://oauth.yandex.com/client/new. Selecione as seguintes permissões da seção "Yandex.Passport API": "Access to email address", "Access to user avatar" and "Access to username, first name and surname, gender"` auths.tip.mastodon=Insira a URL da instância personalizada do mastodon que você deseja usar para autenticar (ou use o padrão) auths.edit=Editar fonte de autenticação @@ -2983,8 +2980,6 @@ monitor.queue.exemplar=Tipo de modelo monitor.queue.numberworkers=Número de executores monitor.queue.maxnumberworkers=Número máximo de executores monitor.queue.numberinqueue=Número na Fila -monitor.queue.review=Revisar configuração -monitor.queue.review_add=Revisar/Adicionar executores monitor.queue.settings.title=Configurações do conjunto monitor.queue.settings.maxnumberworkers=Número máximo de executores monitor.queue.settings.maxnumberworkers.placeholder=Atualmente %[1]d diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 2fb17ada739..eeb2a3ce8bf 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -181,7 +181,7 @@ network_error=Erro de rede [startpage] app_desc=Um serviço Git auto-hospedado e fácil de usar install=Fácil de instalar -install_desc=Corra, simplesmente, o ficheiro binário executável para a sua plataforma, despache-o com o Docker, ou obtenha-o sob a forma de pacote. +install_desc=Corra, simplesmente, o ficheiro binário executável para a sua plataforma, despache-o com o Docker, ou obtenha-o sob a forma de pacote. platform=Multiplataforma platform_desc=Gitea corre em qualquer plataforma onde possa compilar em linguagem Go: Windows, macOS, Linux, ARM, etc. Escolha a sua preferida! lightweight=Leve @@ -203,7 +203,7 @@ db_name=Nome da base de dados db_schema=Esquema db_schema_helper=Deixe em branco para ficar o predefinido da base de dados ("público"). ssl_mode=SSL -path=Caminho +path=Localização sqlite_helper=Localização do ficheiro da base de dados em SQLite3.
Insira um caminho absoluto se corre o Gitea como um serviço. reinstall_error=Está a tentar instalar numa base de dados do Gitea já existente reinstall_confirm_message=Reinstalar com uma base de dados do Gitea já existente pode causar múltiplos problemas. Na maioria dos casos deve usar o seu "app.ini" existente para correr o Gitea. Se souber o que está a fazer, confirme o seguinte: @@ -278,7 +278,7 @@ sqlite3_not_available=Esta versão do Gitea não suporta o SQLite3. Descarregue invalid_db_setting=As configurações da base de dados são inválidas: %v invalid_db_table=A tabela "%s" da base de dados é inválida: %v invalid_repo_path=A localização base dos repositórios é inválida: %v -invalid_app_data_path=O caminho dos dados da aplicação é inválido: %v +invalid_app_data_path=A localização dos dados da aplicação é inválido: %v run_user_not_match=O nome de utilizador para 'executar como' não é o nome de utilizador corrente: %s → %s internal_token_failed=Falha ao gerar o código interno: %v secret_key_failed=Falha ao gerar a chave secreta: %v @@ -317,6 +317,7 @@ filter_by_team_repositories=Filtrar por repositórios da equipa feed_of=`Fonte de "%s"` show_archived=Arquivado +archived=Arquivado show_both_archived_unarchived=Apresentando arquivados e não arquivados show_only_archived=Apresentando somente os arquivados show_only_unarchived=Apresentando somente os não arquivados @@ -378,6 +379,7 @@ email_not_associate=O endereço de email não está associado a qualquer conta. send_reset_mail=Enviar email de recuperação da conta reset_password=Recuperação de conta invalid_code=O seu código de confirmação é inválido ou expirou. +invalid_code_forgot_password=O seu código de confirmação é inválido ou já expirou. Clique aqui para iniciar uma nova sessão. invalid_password=A sua senha não corresponde à senha que foi usada para criar a conta. reset_password_helper=Recuperar conta reset_password_wrong_user=Tem conta iniciada como %s, mas a ligação de recuperação de conta é para %s @@ -510,7 +512,7 @@ NewBranchName=Novo nome de ramo CommitSummary=Sumário do cometimento CommitMessage=Mensagem do cometimento CommitChoice=Escolha do cometimento -TreeName=Caminho do ficheiro +TreeName=Localização do ficheiro Content=Conteúdo SSPISeparatorReplacement=Separador @@ -598,7 +600,6 @@ overview=Panorama geral following=Que segue follow=Seguir unfollow=Deixar de seguir -heatmap.loading=Carregando mapa de laboração… user_bio=Biografia disabled_public_activity=Este utilizador desabilitou a visibilidade pública do trabalho. email_visibility.limited=O seu endereço de email é visível para todos os utilizadores autenticados @@ -680,7 +681,7 @@ choose_new_avatar=Escolher um novo avatar update_avatar=Substituir avatar delete_current_avatar=Eliminar o avatar corrente uploaded_avatar_not_a_image=O ficheiro carregado não é uma imagem. -uploaded_avatar_is_too_big=O ficheiro carregado excedeu o tamanho máximo. +uploaded_avatar_is_too_big=O tamanho do ficheiro carregado (%d KiB) excede o tamanho máximo (%d KiB). update_avatar_success=O seu avatar foi substituído. update_user_avatar_success=O avatar do utilizador foi modificado. @@ -841,7 +842,7 @@ create_oauth2_application_button=Criar aplicação create_oauth2_application_success=Criou com sucesso uma nova aplicação OAuth2. update_oauth2_application_success=Modificou com sucesso a aplicação OAuth2. oauth2_application_name=Nome da aplicação -oauth2_confidential_client=Cliente confidencial. Escolha para aplicações que mantêm o segredo confidencial, tais como aplicações web. Não escolha para aplicações nativas, incluindo aplicações para computador e aplicações móveis. +oauth2_confidential_client=Cliente confidencial. Escolha esta opção para aplicações que mantêm o segredo confidencial, tais como aplicações web. Não escolha esta opção para aplicações nativas, incluindo aplicações para computador e aplicações móveis. oauth2_redirect_uris=URIs de reencaminhamento. Use uma linha por URI. save_application=Guardar oauth2_client_id=ID do cliente @@ -970,6 +971,7 @@ trust_model_helper_collaborator_committer=Colaborador + Autor do cometimento: Co trust_model_helper_default=Padrão: Usar o modelo de confiança padrão para esta instalação create_repo=Criar repositório default_branch=Ramo principal +default_branch_label=predefinido default_branch_helper=O ramo principal é o ramo base para pedidos de integração e cometimentos. mirror_prune=Podar mirror_prune_desc=Remover referências obsoletas de seguimento remoto @@ -1050,7 +1052,7 @@ migrate_options_mirror_helper=Este repositório irá ser uma réplica migrate_options_lfs=Migrar ficheiros LFS migrate_options_lfs_endpoint.label=Destino LFS migrate_options_lfs_endpoint.description=A migração irá tentar usar o seu controlo remoto do Git para determinar o servidor LFS. Também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados noutro lugar. -migrate_options_lfs_endpoint.description.local=Um caminho de servidor local também é suportado. +migrate_options_lfs_endpoint.description.local=Uma localização de servidor local também é suportada. migrate_options_lfs_endpoint.placeholder=Se for deixado em branco, o destino será determinado a partir do URL do clone migrate_items=Itens da migração migrate_items_wiki=Wiki @@ -1064,10 +1066,10 @@ migrate_repo=Migrar o repositório migrate.clone_address=Migrar / clonar a partir do URL migrate.clone_address_desc=O URL de clonagem HTTP(S) ou Git de um repositório existente migrate.github_token_desc=Pode colocar aqui um ou mais códigos separados por vírgulas para tornar mais rápida a migração, para compensar a limitação de velocidade da API do GitHub. AVISO: O abuso desta funcionalidade poderá violar a política do seu fornecedor de serviço e levar ao bloqueio da conta. -migrate.clone_local_path=ou um caminho no servidor local +migrate.clone_local_path=ou uma localização no servidor local migrate.permission_denied=Não está autorizado a importar repositórios locais. migrate.permission_denied_blocked=Não pode importar de servidores não permitidos, por favor peça ao administrador para verificar as configurações ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS. -migrate.invalid_local_path=O caminho local é inválido. Não existe ou não é uma pasta. +migrate.invalid_local_path=A localização local é inválida. Não existe ou não é uma pasta. migrate.invalid_lfs_endpoint=O destino LFS não é válido. migrate.failed=A migração falhou: %v migrate.migrate_items_options=É necessário um código de acesso para migrar itens adicionais @@ -1280,6 +1282,11 @@ commit.cherry-pick=Escolher a dedo commit.cherry-pick-header=Escolher a dedo: %s commit.cherry-pick-content=Escolha o ramo para onde vai escolher a dedo: +commitstatus.error=Erro +commitstatus.failure=Falha +commitstatus.pending=Pendente +commitstatus.success=Sucesso + ext_issues=Acesso a questões externas ext_issues.desc=Ligação para um rastreador de questões externo. @@ -1475,9 +1482,18 @@ issues.ref_reopening_from=`referiu um pedido de integração %[4 issues.ref_closed_from=`encerrou esta questão %[4]s %[2]s` issues.ref_reopened_from=`reabriu esta questão %[4]s %[2]s` issues.ref_from=`de %[1]s` -issues.poster=Remetente -issues.collaborator=Colaborador(a) -issues.owner=Proprietário(a) +issues.author=Autor(a) +issues.author_helper=Este utilizador é o autor. +issues.role.owner=Proprietário(a) +issues.role.owner_helper=Este utilizador é o proprietário deste repositório. +issues.role.member=Membro +issues.role.member_helper=Este utilizador é um membro da organização que é proprietária deste repositório. +issues.role.collaborator=Colaborador +issues.role.collaborator_helper=Este utilizador foi convidado a colaborar neste repositório. +issues.role.first_time_contributor=Contribuidor pela primeira vez +issues.role.first_time_contributor_helper=Esta é a primeira contribuição deste utilizador para o repositório. +issues.role.contributor=Contribuidor +issues.role.contributor_helper=Este utilizador cometeu anteriormente para o repositório. issues.re_request_review=Voltar a solicitar revisão issues.is_stale=Houve modificações neste pedido de integração posteriormente a esta revisão issues.remove_request_review=Remover solicitação de revisão @@ -1748,6 +1764,7 @@ pulls.rebase_conflict_summary=Mensagem de erro pulls.unrelated_histories=A integração falhou: O topo da integração e a base não partilham um histórico comum. Dica: Tente uma estratégia diferente pulls.merge_out_of_date=Falhou a integração: Enquanto estava a gerar a integração, a base foi modificada. Dica: Tente de novo. pulls.head_out_of_date=Falhou a integração: Enquanto estava a gerar a integração, o topo foi modificado. Dica: Tente de novo. +pulls.has_merged=Falhou: A integração constante do pedido foi executada, não pode integrar novamente nem modificar o ramo alvo. pulls.push_rejected=A integração falhou: O envio foi rejeitado. Reveja os Automatismos do Git neste repositório. pulls.push_rejected_summary=Mensagem completa de rejeição pulls.push_rejected_no_message=A integração falhou: O envio foi rejeitado mas não houve qualquer mensagem remota.
Reveja os Automatismos do Git para este repositório @@ -1815,8 +1832,8 @@ milestones.edit_success=A etapa "%s" foi modificada. milestones.deletion=Eliminar etapa milestones.deletion_desc=Se eliminar uma etapa, irá removê-la de todas as questões relacionadas. Quer continuar? milestones.deletion_success=A etapa foi eliminada. -milestones.filter_sort.closest_due_date=Data de vencimento mais próxima -milestones.filter_sort.furthest_due_date=Data de vencimento mais distante +milestones.filter_sort.earliest_due_data=Data de vencimento mais próxima +milestones.filter_sort.latest_due_date=Data de vencimento mais distante milestones.filter_sort.least_complete=Menos completo milestones.filter_sort.most_complete=Mais completo milestones.filter_sort.most_issues=Mais questões @@ -2314,7 +2331,7 @@ settings.tags.protection.allowed.teams=Equipas com permissão settings.tags.protection.allowed.noone=Ninguém settings.tags.protection.create=Proteger etiqueta settings.tags.protection.none=Não há etiquetas protegidas. -settings.tags.protection.pattern.description=Pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias etiquetas. Para mais informações leia o guia das etiquetas protegidas. +settings.tags.protection.pattern.description=Pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias etiquetas. Para mais informações leia o guia das etiquetas protegidas. settings.bot_token=Código do bot settings.chat_id=ID do diálogo settings.thread_id=ID da discussão @@ -2340,16 +2357,16 @@ settings.lfs_filelist=Ficheiros LFS armazenados neste repositório settings.lfs_no_lfs_files=Não existem quaisquer ficheiros LFS armazenados neste repositório settings.lfs_findcommits=Procurar cometimentos settings.lfs_lfs_file_no_commits=Não foram encontrados quaisquer cometimentos para este ficheiro LFS -settings.lfs_noattribute=Este caminho não tem o atributo bloqueável no ramo principal +settings.lfs_noattribute=Esta localização não tem o atributo bloqueável no ramo principal settings.lfs_delete=Eliminar ficheiro LFS com o OID %s settings.lfs_delete_warning=Eliminar um ficheiro LFS pode causar erros do tipo 'elemento não existe' no checkout. Tem a certeza? settings.lfs_findpointerfiles=Procurar ficheiros apontadores settings.lfs_locks=Bloqueios -settings.lfs_invalid_locking_path=Caminho inválido: %s +settings.lfs_invalid_locking_path=Localização inválida: %s settings.lfs_invalid_lock_directory=Não foi possível bloquear a pasta: %s settings.lfs_lock_already_exists=Já existe um bloqueio: %s settings.lfs_lock=Bloquear -settings.lfs_lock_path=Caminho de ficheiro a bloquear... +settings.lfs_lock_path=Localização do ficheiro a bloquear... settings.lfs_locks_no_locks=Sem bloqueios settings.lfs_lock_file_no_exist=O ficheiro bloqueado não existe no ramo principal settings.lfs_force_unlock=Forçar desbloqueio @@ -2714,6 +2731,7 @@ dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git em falta dashboard.sync_external_users=Sincronizar dados externos do utilizador dashboard.cleanup_hook_task_table=Limpar tabela hook_task dashboard.cleanup_packages=Limpar pacotes expirados +dashboard.cleanup_actions=Registos expirados e artefactos das operações de limpeza dashboard.server_uptime=Tempo em funcionamento contínuo do servidor dashboard.current_goroutine=Goroutines em execução dashboard.current_memory_usage=Utilização de memória corrente @@ -2751,7 +2769,9 @@ dashboard.gc_lfs=Recolher lixo dos meta-elementos LFS dashboard.stop_zombie_tasks=Parar tarefas zombies dashboard.stop_endless_tasks=Parar tarefas intermináveis dashboard.cancel_abandoned_jobs=Cancelar trabalhos abandonados +dashboard.start_schedule_tasks=Iniciar tarefas de agendamento dashboard.sync_branch.started=Sincronização de ramos iniciada +dashboard.rebuild_issue_indexer=Reconstruir indexador de questões users.user_manage_panel=Gestão das contas de utilizadores users.new_account=Criar conta de utilizador @@ -2760,6 +2780,9 @@ users.full_name=Nome completo users.activated=Em uso users.admin=Admin. users.restricted=Restrita +users.reserved=Reservado +users.bot=Bot +users.remote=Remoto users.2fa=Autenticação em dois passos users.repos=Repos. users.created=Criada @@ -2806,6 +2829,7 @@ users.list_status_filter.is_prohibit_login=Proibir início de sessão users.list_status_filter.not_prohibit_login=Permitir início de sessão users.list_status_filter.is_2fa_enabled=Autenticação em dois passos habilitada users.list_status_filter.not_2fa_enabled=Autenticação em dois passos desabilitada +users.details=Detalhes do utilizador emails.email_manage_panel=Gestão de endereços de email do utilizador emails.primary=Principal @@ -2853,12 +2877,12 @@ packages.size=Tamanho packages.published=Publicado defaulthooks=Automatismos web predefinidos -defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os predefinidos e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web. +defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os predefinidos e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web. defaulthooks.add_webhook=Adicionar automatismo web predefinido defaulthooks.update_webhook=Modificar automatismo web predefinido systemhooks=Automatismos web do sistema -systemhooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui irão operar em todos os repositórios deste sistema, por isso tenha em consideração quaisquer implicações de desempenho que isso possa ter. Leia mais no guia de automatismos web. +systemhooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui irão operar em todos os repositórios deste sistema, por isso tenha em consideração quaisquer implicações de desempenho que isso possa ter. Leia mais no guia de automatismos web. systemhooks.add_webhook=Adicionar automatismo web do sistema systemhooks.update_webhook=Modificar automatismo web do sistema @@ -2963,7 +2987,7 @@ auths.tip.google_plus=Obtenha credenciais de cliente OAuth2 a partir da consola auths.tip.openid_connect=Use o URL da descoberta de conexão OpenID (/.well-known/openid-configuration) para especificar os extremos auths.tip.twitter=`Vá a https://dev.twitter.com/apps, crie uma aplicação e certifique-se de que está habilitada a opção "Allow this application to be used to Sign in with Twitter"` auths.tip.discord=Registe uma nova aplicação em https://discordapp.com/developers/applications/me -auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em https://docs.gitea.io/en-us/oauth2-provider/ +auths.tip.gitea=Registe uma nova aplicação OAuth2. O guia pode ser encontrado em https://docs.gitea.com/development/oauth2-provider auths.tip.yandex=`Crie uma nova aplicação em https://oauth.yandex.com/client/new. Escolha as seguintes permissões da secção "Yandex.Passport API": "Acesso ao endereço de email", "Acesso ao avatar do utilizador" e "Acesso ao nome de utilizador, nome e sobrenome, género"` auths.tip.mastodon=Insira o URL de uma instância personalizada para a instância do mastodon com que se pretende autenticar (ou então use a predefinida) auths.edit=Editar fonte de autenticação @@ -2985,7 +3009,7 @@ config.server_config=Configuração do servidor config.app_name=Título do sítio config.app_ver=Versão do Gitea config.app_url=URL base do Gitea -config.custom_conf=Caminho do ficheiro de configuração +config.custom_conf=Localização do ficheiro de configuração config.custom_file_root_path=Localização dos ficheiros personalizados config.domain=Domínio do servidor config.offline_mode=Modo local @@ -2993,7 +3017,7 @@ config.disable_router_log=Desabilitar registos do encaminhador config.run_user=Executa com este nome de utilizador config.run_mode=Modo de execução config.git_version=Versão do Git -config.app_data_path=Adicionar caminho dos dados +config.app_data_path=Localização dos dados da aplicação config.repo_root_path=Localização dos repositórios config.lfs_root_path=Localização dos LFS config.log_file_root_path=Localização dos registos @@ -3024,7 +3048,7 @@ config.db_name=Nome config.db_user=Nome de utilizador config.db_schema=Esquema config.db_ssl_mode=SSL -config.db_path=Caminho +config.db_path=Localização config.service_config=Configuração do serviço config.register_email_confirm=Exigir confirmação de email para se inscrever @@ -3063,7 +3087,7 @@ 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_path=Localização 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 @@ -3145,10 +3169,10 @@ monitor.queue.name=Nome monitor.queue.type=Tipo monitor.queue.exemplar=Tipo de exemplar monitor.queue.numberworkers=Número de trabalhadores +monitor.queue.activeworkers=Trabalhadores operantes monitor.queue.maxnumberworkers=Número máximo de trabalhadores monitor.queue.numberinqueue=Número na fila -monitor.queue.review=Rever configuração -monitor.queue.review_add=Rever/Adicionar trabalhadores +monitor.queue.review_add=Rever / Adicionar trabalhadores monitor.queue.settings.title=Configurações do agregado monitor.queue.settings.desc=Agregados crescem dinamicamente em resposta aos bloqueios da sua fila de trabalhadores. monitor.queue.settings.maxnumberworkers=Número máximo de trabalhadores @@ -3177,7 +3201,7 @@ notices.delete_success=As notificações do sistema foram eliminadas. [action] create_repo=criou o repositório %s rename_repo=renomeou o repositório de %[1]s para %[3]s -commit_repo=enviado para %[3]s em %[4]s +commit_repo=enviou para %[3]s em %[4]s create_issue=`abriu a questão %[3]s#%[2]s` close_issue=`fechou a questão %[3]s#%[2]s` reopen_issue=`reabriu a questão %[3]s#%[2]s` @@ -3483,6 +3507,7 @@ runners.reset_registration_token_success=O código de incrição do executor foi runs.all_workflows=Todas as sequências de trabalho runs.commit=Cometimento +runs.scheduled=Agendadas runs.pushed_by=enviado por runs.invalid_workflow_helper=O ficheiro de configuração da sequência de trabalho é inválido. Verifique o seu ficheiro de configuração: %s runs.no_matching_runner_helper=Não há qualquer executor que corresponda: %s @@ -3497,6 +3522,7 @@ workflow.disable=Desabilitar sequência de trabalho workflow.disable_success=A sequência de trabalho '%s' foi desabilitada com sucesso. workflow.enable=Habilitar sequência de trabalho workflow.enable_success=A sequência de trabalho '%s' foi habilitada com sucesso. +workflow.disabled=A sequência de trabalho está desabilitada. need_approval_desc=É necessária aprovação para executar sequências de trabalho para a derivação do pedido de integração. diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index edf3b0b981c..709a173df3d 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -175,7 +175,6 @@ network_error=Ошибка сети [startpage] app_desc=Удобный сервис собственного хостинга репозиториев Git install=Простой в установке -install_desc=Просто запустите исполняемый файл для вашей платформы, разверните через Docker, или установите с помощью менеджера пакетов. platform=Кроссплатформенный platform_desc=Gitea работает на любой платформе, поддерживаемой Go: Windows, macOS, Linux, ARM и т. д. Выбирайте, что вам больше нравится! lightweight=Легковесный @@ -308,6 +307,7 @@ filter_by_team_repositories=Фильтровать по репозиториям feed_of=Лента «%s» show_archived=Архивировано +archived=Архивировано show_both_archived_unarchived=Показаны архивированные и разархивированные show_only_archived=Показаны только архивированные show_only_unarchived=Показаны только разархивированные @@ -582,7 +582,6 @@ overview=Обзор following=Подписки follow=Подписаться unfollow=Отписаться -heatmap.loading=Загрузка карты активности… user_bio=О себе disabled_public_activity=Этот пользователь отключил публичную видимость активности. email_visibility.limited=Ваш адрес электронной почты виден всем выполнившим вход пользователям @@ -655,7 +654,6 @@ choose_new_avatar=Выбрать новый аватар update_avatar=Обновить аватар delete_current_avatar=Удалить текущий аватар uploaded_avatar_not_a_image=Загружаемый файл не является изображением. -uploaded_avatar_is_too_big=Загруженный файл превысил максимальный размер. update_avatar_success=Ваш аватар был изменен. update_user_avatar_success=Аватар пользователя обновлён. @@ -1216,6 +1214,11 @@ commit.cherry-pick=Перенос commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=Выбрать ветку для переноса: +commitstatus.error=Ошибка +commitstatus.failure=Неудача +commitstatus.pending=Ожидание +commitstatus.success=Успешно + ext_issues=Доступ к внешним задачам ext_issues.desc=Ссылка на внешнюю систему отслеживания ошибок. @@ -1407,9 +1410,9 @@ issues.ref_reopening_from=`сослался(ась) на зап issues.ref_closed_from=`закрыл этот запрос %[4]s %[2]s` issues.ref_reopened_from=`переоткрыл эту задачу %[4]s %[2]s` issues.ref_from=`из %[1]s` -issues.poster=Автор -issues.collaborator=Соавтор -issues.owner=Владелец +issues.author=Автор +issues.role.owner=Владелец +issues.role.member=Участник issues.re_request_review=Повторить запрос на отзыв issues.is_stale=Со времени этого обзора в этот PR были внесены некоторые изменения issues.remove_request_review=Удалить запрос на отзыв @@ -1724,8 +1727,6 @@ milestones.edit_success=Этап «%s» обновлён. milestones.deletion=Удалить этап milestones.deletion_desc=Удаление этапа приведет к его удалению из всех связанных задач. Продолжить? milestones.deletion_success=Этап успешно удалён. -milestones.filter_sort.closest_due_date=Ближайшее по дате -milestones.filter_sort.furthest_due_date=Дальнее по дате milestones.filter_sort.least_complete=Менее полное milestones.filter_sort.most_complete=Более полное milestones.filter_sort.most_issues=Большинство задач @@ -2196,7 +2197,6 @@ settings.tags.protection.allowed.teams=Разрешенные команды settings.tags.protection.allowed.noone=Ни один settings.tags.protection.create=Защитить тег settings.tags.protection.none=Нет защищенных тегов. -settings.tags.protection.pattern.description=Вы можете использовать одно имя или глоб-шаблон или регулярное выражение, для выбора нескольких тегов. Подробнее о защищенных тэгах. settings.bot_token=Токен для бота settings.chat_id=ID чата settings.matrix.homeserver_url=URL домашнего сервера @@ -2710,12 +2710,10 @@ packages.size=Размер packages.published=Опубликовано defaulthooks=Стандартные Веб-хуки -defaulthooks.desc=Веб-хуки автоматически делают HTTP-POST запросы на сервер, когда вызываются определенные события Gitea. Веб-хуки, определённые здесь, по умолчанию и будут скопированы во все новые репозитории. Подробнее читайте в руководстве по веб-хукам. defaulthooks.add_webhook=Добавить стандартный Веб-хук defaulthooks.update_webhook=Обновить стандартный Веб-хук systemhooks=Системные веб-хуки -systemhooks.desc=Веб-хуки автоматически делают HTTP-POST запросы на сервер, когда вызываются определённые события Gitea. Определённые веб-хуки будут действовать на всех репозиториях системы, поэтому пожалуйста, учитывайте любые последствия для производительности. Подробнее читайте в руководстве по веб-хукам. systemhooks.add_webhook=Добавить системный веб-хук systemhooks.update_webhook=Обновить системный веб-хук @@ -2819,7 +2817,6 @@ auths.tip.google_plus=Получите учётные данные клиент auths.tip.openid_connect=Используйте OpenID Connect Discovery URL (/.well-known/openid-configuration) для автоматической настройки входа OAuth auths.tip.twitter=Перейдите на https://dev.twitter.com/apps, создайте приложение и убедитесь, что включена опция «Разрешить это приложение для входа в систему с помощью Twitter» auths.tip.discord=Добавьте новое приложение на https://discordapp.com/developers/applications/me -auths.tip.gitea=Зарегистрировать новое приложение OAuth2. Руководство можно найти на https://docs.gitea.io/ru-us/oauth2-provider/ auths.tip.yandex=`Создайте новое приложение по адресу https://oauth.yandex.com/client/new. В разделе "API Яндекс.Паспорта" выберите следующие разрешения: "Доступ к адресу электронной почты", "Доступ к аватару пользователя" и "Доступ к имени пользователя, фамилии и полу"` auths.tip.mastodon=Введите пользовательский URL экземпляра для экземпляра mastodon, с которым вы хотите аутентифицироваться (или использовать его по умолчанию) auths.edit=Обновить параметры аутентификации @@ -3002,8 +2999,6 @@ monitor.queue.exemplar=Тип образца monitor.queue.numberworkers=Количество рабочих monitor.queue.maxnumberworkers=Максимальное количество рабочих monitor.queue.numberinqueue=Позиция в очереди -monitor.queue.review=Просмотр конфигурации -monitor.queue.review_add=Просмотреть/добавить рабочих monitor.queue.settings.title=Настройки пула monitor.queue.settings.desc=Пулы увеличиваются динамически в ответ на блокировку очередей своих рабочих. monitor.queue.settings.maxnumberworkers=Максимальное количество рабочих diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index ad209591526..fd790b14ccf 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -115,7 +115,6 @@ missing_csrf=නරක ඉල්ලීම: CSRF ටෝකන් නොමැත [startpage] app_desc=වේදනාකාරී, ස්වයං-සත්කාරක Git සේවාවක් install=ස්ථාපනයට පහසුය -install_desc=සරලවම ඔබේ වේදිකාව සඳහා ද්විමය ධාවනය කරන්න, ඩොකර්සමඟ නැව්ගත කරන්න, නැතහොත් එය ලබා ගන්න ඇසුරුම්. platform=හරස් වේදිකාව platform_desc=Gitea ඕනෑම තැනක ධාවනය Go සඳහා සම්පාදනය කළ හැකිය: වින්ඩෝස්, මැකෝස්, ලිනක්ස්, ARM, ආදිය ඔබ ආදරය කරන එකක් තෝරන්න! lightweight=සැහැල්ලු @@ -230,6 +229,7 @@ filter=වෙනත් පෙරහන් filter_by_team_repositories=කණ්ඩායම් කෝෂ්ඨ අනුව පෙරන්න show_archived=සංරක්ෂිත +archived=සංරක්ෂිත show_both_archived_unarchived=සංරක්ෂිත සහ අක්රීය දෙකම පෙන්වීම show_only_archived=සංරක්ෂිත පමණක් පෙන්වයි show_only_unarchived=සංරක්ෂිත පමණක් පෙන්වීම @@ -465,7 +465,6 @@ overview=දළ විශ්ලේෂණය following=පහත සඳහන් follow=අනුගමනය කරන්න unfollow=අනුගමනය නොකරන්න -heatmap.loading=තාප සිතියම් පූරණය… user_bio=චරිතාපදානය disabled_public_activity=මෙම පරිශීලකයා ක්රියාකාරකම්වල මහජන දෘශ්යතාව අක්රීය කර ඇත. @@ -513,7 +512,6 @@ choose_new_avatar=නව අවතාරය තෝරන්න update_avatar=යාවත්කාලීන අවතාර් delete_current_avatar=වත්මන් අවතාරය මකන්න uploaded_avatar_not_a_image=උඩුගත කරන ලද ගොනුව රූපයක් නොවේ. -uploaded_avatar_is_too_big=උඩුගත කරන ලද ගොනුව උපරිම ප්රමාණය ඉක්මවා ඇත. update_avatar_success=ඔබගේ අවතාරය යාවත්කාලීන කර ඇත. update_user_avatar_success=පරිශීලකයාගේ අවතාරය යාවත්කාලීන කර ඇත. @@ -960,6 +958,9 @@ commits.signed_by_untrusted_user_unmatched=කමිටුව නොගැලප commits.gpg_key_id=ජීපීජී යතුරෙහි හැඳු. +commitstatus.error=දෝෂයකි +commitstatus.pending=වංගු + ext_issues.desc=බාහිර නිකුතුවකට සම්බන්ධ වන්න ට්රැකර්. projects=ව්‍යාපෘති @@ -1104,9 +1105,8 @@ issues.ref_reopening_from=මෙම ගැටළුව නැව issues.ref_closed_from=මෙම නිකුතුව%[4]s %[2]s issues.ref_reopened_from=මෙම නිකුතුව%[4]s %[2]sනැවත විවෘත කරන ලදි issues.ref_from=`හිම%[1]s` -issues.poster=පෝස්ටර් -issues.collaborator=සහයෝගීතාව -issues.owner=හිමිකරු +issues.role.owner=හිමිකරු +issues.role.member=සාමාජික issues.re_request_review=නැවත ඉල්ලීම සමාලෝචනය issues.is_stale=මෙම සමාලෝචනයේ සිට මෙම මහජන සම්බන්ධතා සඳහා වෙනස්කම් සිදුවී ඇත issues.remove_request_review=සමාලෝචන ඉල්ලීම ඉවත් කරන්න @@ -1369,8 +1369,6 @@ milestones.modify=සන්ධිස්ථානයක් යාවත්කා milestones.deletion=සන්ධිස්ථානය මකන්න milestones.deletion_desc=සන්ධිස්ථානයක් මකා දැමීම සම්බන්ධ සියලු ගැටළු වලින් එය ඉවත් කරයි. දිගටම? milestones.deletion_success=සන්ධිස්ථානය මකා දමා ඇත. -milestones.filter_sort.closest_due_date=ආසන්නතම නියමිත දිනය -milestones.filter_sort.furthest_due_date=වඩාත්ම නියමිත දිනය milestones.filter_sort.least_complete=අවම වශයෙන් සම්පූර්ණයි milestones.filter_sort.most_complete=වඩාත්ම සම්පූර්ණයි milestones.filter_sort.most_issues=බොහෝ ප්රශ්න @@ -1759,7 +1757,6 @@ settings.tags.protection.allowed.teams=ඉඩ දී ඇති කණ්ඩා settings.tags.protection.allowed.noone=එකක් නැත settings.tags.protection.create=ටැග ආරක්ෂා settings.tags.protection.none=ආරක්ෂිත ටැග් නොමැත. -settings.tags.protection.pattern.description=බහු ටැග් වලට ගැලපෙන පරිදි ඔබට තනි නමක් හෝ ග්ලෝබ් රටාවක් හෝ සාමාන්ය ප්රකාශනයක් භාවිතා කළ හැකිය. තව දුරටත් කියවන්න ආරක්ෂිත ටැග් මාර්ගෝපදේශය. settings.bot_token=බොට් ටෝකනය settings.chat_id=චැට් හැඳුනුම්පත settings.matrix.homeserver_url=හෝම්සර්වර් URL @@ -2199,12 +2196,10 @@ packages.repository=කෝෂ්ඨය packages.size=ප්‍රමාණය defaulthooks=පෙරනිමි වෙබ් කොකු -defaulthooks.desc=ඇතැම් Gitea සිදුවීම් අවුලුවාලන විට වෙබ් හූක්ස් ස්වයංක්රීයව සේවාදායකයකට HTTP පෝස්ට් ඉල්ලීම් කරයි. මෙහි අර්ථ දක්වා ඇති වෙබ්කොකු පැහැර හැරීම් වන අතර සියලු නව ගබඩාවන් වෙත පිටපත් කරනු ලැබේ. තව දුරටත් කියවන්න වෙබ් කොකු මාර්ගෝපදේශය. defaulthooks.add_webhook=පෙරනිමි වෙබ් හූක් එකතු කරන්න defaulthooks.update_webhook=පෙරනිමි වෙබ් හූක් යාවත්කාලීන කරන්න systemhooks=වෙබ් කොකු පද්ධතිය -systemhooks.desc=ඇතැම් Gitea සිදුවීම් අවුලුවාලන විට වෙබ් හූක්ස් ස්වයංක්රීයව සේවාදායකයකට HTTP පෝස්ට් ඉල්ලීම් කරයි. මෙහි අර්ථ Webhooks පද්ධතිය මත සියලු ගබඩාවන් මත ක්රියා කරනු ඇත, ඒ නිසා මෙම ඇති විය හැකි ඕනෑම කාර්ය සාධන ඇඟවුම් සලකා බලන්න. තව දුරටත් කියවන්න වෙබ් කොකු මාර්ගෝපදේශය. systemhooks.add_webhook=පද්ධතිය වෙබ්හූක් එකතු කරන්න systemhooks.update_webhook=වෙබ්හූක් පද්ධතිය යාවත්කාලීන @@ -2293,7 +2288,6 @@ auths.tip.google_plus=ගූගල් API කොන්සෝලය වෙති auths.tip.openid_connect=අන්ත ලක්ෂ්ය නියම කිරීම සඳහා OpenID Connect ඩිස්කවරි URL (/.හොඳින් දැන /openid-වින්යාසය) භාවිතා කරන්න auths.tip.twitter=https://dev.twitter.com/apps වෙත යන්න, යෙදුමක් සාදන්න සහ “මෙම යෙදුම ට්විටර් සමඟ පුරනය වීමට භාවිතා කිරීමට ඉඩ දෙන්න” විකල්පය සක්රීය කර ඇති බවට සහතික වන්න auths.tip.discord=https://discordapp.com/developers/applications/me හි නව අයදුම්පතක් ලියාපදිංචි කරන්න -auths.tip.gitea=නව OUTU2 අයදුම්පතක් ලියාපදිංචි කරන්න. මාර්ගෝපදේශය https://docs.gitea.io/en-us/oauth2-provider/ හි සොයාගත හැකිය auths.tip.yandex=https://oauth.yandex.com/client/new හි නව යෙදුමක් සාදන්න. “Yandex.Passport API” කොටසේ පහත සඳහන් අවසරයන් තෝරන්න: “විද්යුත් තැපැල් ලිපිනය වෙත ප්රවේශය”, “පරිශීලක අවතාර් වෙත ප්රවේශය” සහ “පරිශීලක නාමය, මුල් නම සහ වාසගම, ස්ත්රී පුරුෂ භාවය” auths.tip.mastodon=ඔබට සත්යාපනය කිරීමට අවශ්ය mastodon උදාහරණයක් සඳහා අභිරුචි උදාහරණයක් URL එකක් ආදාන කරන්න (හෝ පෙරනිමි එකක් භාවිතා කරන්න) auths.edit=සත්යාපන මූලාශ්රය සංස්කරණය කරන්න @@ -2452,8 +2446,6 @@ monitor.queue.type=වර්ගය monitor.queue.exemplar=ආදර්ශ වර්ගය monitor.queue.numberworkers=කම්කරුවන් සංඛ්යාව monitor.queue.maxnumberworkers=මැක්ස් කම්කරු සංඛ්යාව -monitor.queue.review=සමාලෝචන වින්යාසය -monitor.queue.review_add=සමාලෝචනය/කම්කරුවන් එකතු කරන්න monitor.queue.settings.title=තටාකය සැකසුම් monitor.queue.settings.maxnumberworkers=මැක්ස් කම්කරුවන් සංඛ්යාව monitor.queue.settings.maxnumberworkers.placeholder=වත්මන්%[1]d diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index 9eea6c4039e..4dfb27e7daf 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -130,7 +130,6 @@ network_error=Chyba siete [startpage] app_desc=Jednoducho prístupný vlastný Git install=Jednoduchá inštalácia -install_desc=Jednoducho spusťte binárku pre vašu platformu, dodávanú ako Docker, alebo ju získajte ako balík. platform=Multiplatformový platform_desc=Gitea beží všade kde je možné preložiť Go: Windows, macOS, Linux, ARM, a podobne. Vyberte si! lightweight=Ľahká @@ -257,6 +256,7 @@ filter_by_team_repositories=Filtrovať podľa tímových repozitárov feed_of=Informačný kanál „%s“ show_archived=Archivované +archived=Archivované show_both_archived_unarchived=Zobrazujú sa archivované aj nearchivované show_only_archived=Zobrazuje sa iba archivované show_only_unarchived=Zobrazuje sa iba nearchivované @@ -501,7 +501,6 @@ projects=Projekty following=Sledovaní follow=Sledovať unfollow=Zrušiť sledovanie -heatmap.loading=Načítanie teplotnej mapy… user_bio=Životopis disabled_public_activity=Tento používateľ zákázal verejnú viditeľnosť aktivity. @@ -565,7 +564,6 @@ choose_new_avatar=Vybrať nový avatar update_avatar=Aktualizovať avatar delete_current_avatar=Odstrániť aktuálny avatar uploaded_avatar_not_a_image=Nahraný súbor nieje obrázok. -uploaded_avatar_is_too_big=Nahraný súbor prekročil maximálnu veľkosť. update_avatar_success=Váš avatar sa aktualizoval. update_user_avatar_success=Užívateľov avatar bol aktualizovaný. @@ -951,6 +949,8 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=Vyberte vetvu pre cherry-pick na: +commitstatus.error=Chyba + ext_issues=Prístup k externým úkolom ext_issues.desc=Odkaz na externé sledovanie úkolov. @@ -996,7 +996,7 @@ issues.ref_closing_from=`odkazoval/a na pull request %[4]s, ktor issues.ref_reopening_from=`odkazoval/a na pull request %[4]s, ktorý znovu otvorí tento úkol %[2]s` issues.ref_closed_from=`uzavrel/a tento úkol %[4]s %[2]s` issues.ref_reopened_from=`znovu otvoril/a tento úkol %[4]s %[2]s` -issues.owner=Vlastník +issues.role.owner=Vlastník issues.re_request_review=Znovu požiadať o revíziu issues.is_stale=Od tejto kontroly došlo k zmenám v tomto pull requeste issues.remove_request_review=Odstrániť žiadosť o revíziu @@ -1213,12 +1213,10 @@ packages.owner=Vlastník packages.repository=Repozitár defaulthooks=Defaultné webhooky -defaulthooks.desc=Webhooky automaticky odosielajú požiadavky HTTP POST na server, keď sa spustia určité udalosti Gitea. Tu definované webhooky sú predvolené a skopírujú sa do všetkých nových repozitárov. Prečítajte si viac v sprievodcovi webhookmi. defaulthooks.add_webhook=Pridať defaultný webhook defaulthooks.update_webhook=Aktualizovať defaultný webhook systemhooks=Systémové webhooky -systemhooks.desc=Webhooky automaticky odosielajú požiadavky HTTP POST na server, keď sa spustia určité udalosti Gitea. Tu definované webhooky budú pôsobiť na všetky repozitáre v systéme, takže zvážte akékoľvek dôsledky na výkon, ktoré to môže mať. Prečítajte si viac v sprievodcovi webhookmi. systemhooks.add_webhook=Pridať systémový webhook systemhooks.update_webhook=Aktualizovať defaultný webhook @@ -1253,8 +1251,6 @@ config.oauth_enabled=Povolené monitor.process.cancel=Zrušiť proces -monitor.queue.review=Konfigurácia revidovania -monitor.queue.review_add=Revidovať/Pridať revidentov [action] diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 2ae499b3ca8..f87f22b806f 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -103,7 +103,6 @@ name=Namn [startpage] app_desc=En smidig, självhostad Git-tjänst install=Lätt att installera -install_desc=Helt enkelt kör binären för din plattform, skicka den med Docker, eller få den paketerad. platform=Plattformsoberoende platform_desc=Gitea kan köra överallt där Go kan kompileras: Windows, macOS, Linux, ARM, etc. Välj den du gillar! lightweight=Lättviktig @@ -216,6 +215,7 @@ search_repos=Hitta en utvecklingskatalog… filter=Övriga Filter show_archived=Arkiverade +archived=Arkiverade show_both_archived_unarchived=Visar både arkiverade och icke arkiverade show_only_archived=Visar endast arkiverade show_only_unarchived=Visa endast icke arkiverade @@ -402,7 +402,6 @@ overview=Översikt following=Följer follow=Följ unfollow=Sluta följa -heatmap.loading=Laddar färgdiagram… user_bio=Biografi disabled_public_activity=Den här användaren har inaktiverat den publika synligheten av aktiviteten. @@ -447,7 +446,6 @@ choose_new_avatar=Välj ny avatar update_avatar=Uppdatera Avatar delete_current_avatar=Tag bort aktuell avatar uploaded_avatar_not_a_image=Den uppladdade filen är inte en bild. -uploaded_avatar_is_too_big=Den uppladdade filen överstiger den maximala filstorleken. update_avatar_success=Din avatar har blivit uppdaterad. change_password=Ändra Lösenordet @@ -815,6 +813,8 @@ commits.signed_by_untrusted_user_unmatched=Signerad av opålitlig användare som commits.gpg_key_id=GPG-nyckel ID +commitstatus.pending=Väntande + ext_issues.desc=Länk till externt ärendehanteringssystem. projects=Projekt @@ -948,9 +948,8 @@ issues.ref_reopening_from=`refererade till en pull-förfrågan % issues.ref_closed_from=`stängde detta ärende %[4]s %[2]s` issues.ref_reopened_from=`öpnnade detta ärende igen %[4]s %[2]s` issues.ref_from=`från %[1]s` -issues.poster=Skapare -issues.collaborator=Deltagare -issues.owner=Ägare +issues.role.owner=Ägare +issues.role.member=Medlem issues.re_request_review=Begär omgranskning issues.remove_request_review=Ta bort granskningsbegäran issues.remove_request_review_block=Kan inte ta bort granskningsbegäran @@ -1144,8 +1143,6 @@ milestones.modify=Uppdatera milstolpe milestones.deletion=Ta bort milstolpe milestones.deletion_desc=Borttagning av en milstolpe tar bort den från samtliga relaterade ärende. Fortsätta? milestones.deletion_success=Milstolpen har blivit borttagen. -milestones.filter_sort.closest_due_date=Närmaste förfallodatum -milestones.filter_sort.furthest_due_date=Mest avlägsna förfallodatum milestones.filter_sort.least_complete=Minst klar milestones.filter_sort.most_complete=Mest klar milestones.filter_sort.most_issues=Mest ärenden @@ -1962,8 +1959,6 @@ monitor.queue.name=Namn monitor.queue.type=Typ monitor.queue.numberworkers=Antal arbetare monitor.queue.maxnumberworkers=Max antal arbetare -monitor.queue.review=Granska konfiguration -monitor.queue.review_add=Granska/Lägg till arbetare monitor.queue.settings.submit=Uppdatera inställningar monitor.queue.settings.changed=Inställningar uppdaterade diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index d0250b5b347..e35564ee535 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -181,7 +181,6 @@ network_error=Ağ hatası [startpage] app_desc=Zahmetsiz, kendi sunucunuzda barındırabileceğiniz Git servisi install=Kurulumu kolay -install_desc=Platformunuz için ikili dosyayı çalıştırın, Docker ile gönderin veya paketleyin. platform=Farklı platformlarda çalışablir platform_desc=Gitea Go ile derleme yapılabilecek her yerde çalışmaktadır: Windows, macOS, Linux, ARM, vb. Hangisini seviyorsanız onu seçin! lightweight=Hafif @@ -317,6 +316,7 @@ filter_by_team_repositories=Takım depolarına göre süz feed_of=`"%s" beslemesi` show_archived=Arşivlenmiş +archived=Arşivlenmiş show_both_archived_unarchived=Arşivlenenlerin ve arşivlenmeyenlerin tümü gösteriliyor show_only_archived=Yalnızca arşivlenenler gösteriliyor show_only_unarchived=Yalnızca arşivlenmeyenler gösteriliyor @@ -598,7 +598,6 @@ overview=Genel Bakış following=Takip Edilenler follow=Takip Et unfollow=Takibi Bırak -heatmap.loading=Isı haritası yükleniyor… user_bio=Biyografi disabled_public_activity=Bu kullanıcı, etkinliğin herkese görünür olmasını devre dışı bıraktı. email_visibility.limited=E-posta adresiniz giriş yapmış tüm kullanıcılar tarafından görünür @@ -680,7 +679,6 @@ choose_new_avatar=Yeni Avatar Seç update_avatar=Profil Resmini Güncelle delete_current_avatar=Güncel Avatarı Sil uploaded_avatar_not_a_image=Yüklenen dosya bir resim dosyası değil. -uploaded_avatar_is_too_big=Yüklenen dosya maksimum boyutu aştı. update_avatar_success=Profil resminiz değiştirildi. update_user_avatar_success=Kullanıcının avatarı güncellendi. @@ -1280,6 +1278,11 @@ 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: +commitstatus.error=Hata +commitstatus.failure=Başarısız +commitstatus.pending=Beklemede +commitstatus.success=Başarılı + ext_issues=Harici Konulara Erişim ext_issues.desc=Dışsal konu takip sistemine bağla. @@ -1475,9 +1478,9 @@ issues.ref_reopening_from=`bir değişiklik isteğine referansta issues.ref_closed_from=`bu konuyu kapat%[4]s %[2]s` issues.ref_reopened_from=`konuyu yeniden aç%[4]s %[2]s` issues.ref_from=`%[1]s'den` -issues.poster=Poster -issues.collaborator=Katkıcı -issues.owner=Sahibi +issues.author=Yazar +issues.role.owner=Sahibi +issues.role.member=Üye issues.re_request_review=İncelemeyi yeniden iste issues.is_stale=Bu incelemeden bu yana bu istekte değişiklikler oldu issues.remove_request_review=İnceleme isteğini kaldır @@ -1815,8 +1818,6 @@ milestones.edit_success=`"%s" dönüm noktası güncellendi.` milestones.deletion=Kilometre Taşını Sil milestones.deletion_desc=Bir kilometre taşını silmek, onu ilgili tüm sorunlardan kaldırır. Devam edilsin mi? milestones.deletion_success=Kilometre taşı silindi. -milestones.filter_sort.closest_due_date=En yakın zamanı gelmiş tarih -milestones.filter_sort.furthest_due_date=En uzak zamanı gelmiş tarih milestones.filter_sort.least_complete=En az tamamlama milestones.filter_sort.most_complete=En çok tamamlama milestones.filter_sort.most_issues=En çok konu @@ -2314,7 +2315,6 @@ settings.tags.protection.allowed.teams=İzin verilen takımlar settings.tags.protection.allowed.noone=Hiç kimse settings.tags.protection.create=Etiketi Koru settings.tags.protection.none=Korumalı etiket yok. -settings.tags.protection.pattern.description=Birden çok etiketi eşleştirmek için tek bir ad, glob deseni veya normal ifade kullanabilirsiniz. Daha fazlası için korumalı etiketler rehberini okuyun. settings.bot_token=Bot Jetonu settings.chat_id=Sohbet Kimliği settings.thread_id=İş Parçacığı ID @@ -2853,12 +2853,10 @@ 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. defaulthooks.add_webhook=Varsayılan Web İstemcisi Ekle defaulthooks.update_webhook=Varsayılan Web İstemcisini Güncelle systemhooks=Sistem Web İstemcileri -systemhooks.desc=Belirli Gitea olayları tetiklendiğinde Web istemcileri otomatik olarak bir sunucuya HTTP POST istekleri yapar. Burada tanımlanan web istemcileri sistemdeki tüm depolar üzerinde çalışır, bu yüzden lütfen bunun olabilecek tüm performans sonuçlarını göz önünde bulundurun. web istemcileri kılavuzunda daha fazla bilgi edinin. systemhooks.add_webhook=Sistem Web İstemcisi Ekle systemhooks.update_webhook=Sistem Web İstemcisi Güncelle @@ -2963,7 +2961,6 @@ auths.tip.google_plus=OAuth2 istemci kimlik bilgilerini https://console.develope auths.tip.openid_connect=Bitiş noktalarını belirlemek için OpenID Connect Discovery URL'sini kullanın (/.well-known/openid-configuration) auths.tip.twitter=https://dev.twitter.com/apps adresine gidin, bir uygulama oluşturun ve “Bu uygulamanın Twitter ile oturum açmak için kullanılmasına izin ver” seçeneğinin etkin olduğundan emin olun auths.tip.discord=https://discordapp.com/developers/applications/me adresinde yeni bir uygulama kaydedin -auths.tip.gitea=Yeni bir OAuth2 uygulaması kaydedin. Rehber https://docs.gitea.io/en-us/oauth2-provider/ adresinde bulunabilir auths.tip.yandex=`https://oauth.yandex.com/client/new adresinde yeni bir uygulama oluşturun. "Yandex.Passport API'sı" bölümünden aşağıdaki izinleri seçin: "E-posta adresine erişim", "Kullanıcı avatarına erişim" ve "Kullanıcı adına, ad ve soyadına, cinsiyete erişim"` auths.tip.mastodon=Kimlik doğrulaması yapmak istediğiniz mastodon örneği için özel bir örnek URL girin (veya varsayılan olanı kullanın) auths.edit=Kimlik Doğrulama Kaynağı Düzenle @@ -3147,8 +3144,6 @@ 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.settings.title=Havuz Ayarları monitor.queue.settings.desc=Havuzlar, çalışan kuyruğu tıkanmasına bir yanıt olarak dinamik olarak büyürler. monitor.queue.settings.maxnumberworkers=En fazla çalışan Sayısı diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 85f34881d32..be686dcdcc2 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -118,7 +118,6 @@ network_error=Помилка мережі [startpage] app_desc=Зручний власний сервіс хостингу репозиторіїв Git install=Легко встановити -install_desc=Просто запустіть виконуваний файл для вашої платформи, розміщуйте в Docker або встановіть пакунок. platform=Платформонезалежність platform_desc=Gitea виконується на платформі, для якої можливо скомпілювати Go: Windows, macOS, Linux, ARM, та інших. Оберіть ту, яка вам до вподоби! lightweight=Невибагливість @@ -244,6 +243,7 @@ filter_by_team_repositories=Фільтрувати за репозиторіям feed_of=`Стрічка "%s"` show_archived=Архівовані +archived=Архівовані show_both_archived_unarchived=Показано архівовані і не архівовані show_only_archived=Показано тільки архівовані show_only_unarchived=Показано тільки не архівовані @@ -481,7 +481,6 @@ overview=Огляд following=Читає follow=Підписатися unfollow=Відписатися -heatmap.loading=Завантаження карти активності… user_bio=Біографія disabled_public_activity=Цей користувач вимкнув публічний показ діяльності. @@ -534,7 +533,6 @@ choose_new_avatar=Оберіть новий аватар update_avatar=Оновити аватар delete_current_avatar=Видалити поточний аватар uploaded_avatar_not_a_image=Завантажений файл не є зображенням. -uploaded_avatar_is_too_big=Файл, що завантажувався, перевищив максимальний розмір. update_avatar_success=Ваш аватар був змінений. update_user_avatar_success=Аватар користувача оновлено. @@ -999,6 +997,9 @@ commits.signed_by_untrusted_user_unmatched=Підписаний недовіре commits.gpg_key_id=Ідентифікатор GPG ключа +commitstatus.error=Помилка +commitstatus.pending=Очікування + ext_issues=Доступ до зовнішніх задач ext_issues.desc=Посилання на зовнішню систему відстеження задач. @@ -1154,9 +1155,8 @@ issues.ref_reopening_from=`згадав запит на злит issues.ref_closed_from=`закрив цю задачу %[4]s %[2]s` issues.ref_reopened_from=`повторно відкрито цю задачу %[4]s %[2]s` issues.ref_from=`із %[1]s` -issues.poster=Автор -issues.collaborator=Співавтор -issues.owner=Власник +issues.role.owner=Власник +issues.role.member=Учасник issues.re_request_review=Повторно попросити рецензію issues.is_stale=З часу останньої перевірки в цей PR було внесено деякі зміни issues.remove_request_review=Видалити запит рецензування @@ -1419,8 +1419,6 @@ milestones.modify=Оновити етап milestones.deletion=Видалити етап milestones.deletion_desc=Видалення етапу призведе до його видалення з усіх пов'язаних задач. Продовжити? milestones.deletion_success=Етап успішно видалено. -milestones.filter_sort.closest_due_date=Найближче за датою -milestones.filter_sort.furthest_due_date=Далі за датою milestones.filter_sort.least_complete=Менш повне milestones.filter_sort.most_complete=Більш повне milestones.filter_sort.most_issues=Найбільш задач @@ -1810,7 +1808,6 @@ settings.tags.protection.allowed.teams=Дозволені команди settings.tags.protection.allowed.noone=Ніхто settings.tags.protection.create=Захистна мітка settings.tags.protection.none=Там не немає захищених міток. -settings.tags.protection.pattern.description=Ви можете використовувати одне ім'я або глобальний шаблон або регулярний вираз для декількох тегів.. Детальніше в посібнику із захищених тегів. settings.bot_token=Токен для бота settings.chat_id=Чат ID settings.matrix.homeserver_url=URL домашньої сторінки @@ -2253,12 +2250,10 @@ packages.repository=Репозиторій packages.size=Розмір defaulthooks=Веб-хуки за замовчуванням -defaulthooks.desc=Веб-хуки автоматично створюють HTTP POST-запити до сервера, коли виконуються певні події Gitea. Визначені тут веб-хуки є типовими і копіюються у всі нові сховища. Детальніше читайте в інструкції по використанню web-хуків. defaulthooks.add_webhook=Додати веб-хук за замовчуванням defaulthooks.update_webhook=Змінити веб-хук за замовчуванням systemhooks=Системні вебхуки -systemhooks.desc=Веб-хуки автоматично створюють HTTP POST-запити до сервера, коли виконуються певні тригери в Gitea. Визначені веб-хуки є типовими і копіюються у всі нові сховища. Детальніше читайте в інструкції по використанню web-хуків. systemhooks.add_webhook=Додати системний вебхук systemhooks.update_webhook=Оновити системний вебхук @@ -2347,7 +2342,6 @@ auths.tip.google_plus=Отримайте облікові дані клієнт auths.tip.openid_connect=Використовуйте OpenID Connect Discovery URL (/.well-known/openid-configuration) для автоматичної настройки входу OAuth auths.tip.twitter=Перейдіть на https://dev.twitter.com/apps, створіть програму і переконайтеся, що включена опція «Дозволити цю програму для входу в систему за допомогою Twitter» auths.tip.discord=Зареєструйте новий додаток на https://discordapp.com/developers/applications/me -auths.tip.gitea=Зареєструйте новий додаток OAuth2. Керівництво можна знайти на https://docs.gitea.io/en-us/oauth2-provider/ auths.tip.yandex=`Створіть нову програму в https://oauth.yandex.com/client/new. Виберіть наступні дозволи з "Yandex. assport API": "Доступ до адреси електронної пошти", "Доступ до аватара" і "Доступ до імені користувача, імені та прізвища, статі"` auths.tip.mastodon=Введіть URL спеціального екземпляра для екземпляра mastodon, який ви хочете автентифікувати за допомогою (або використовувати за замовчуванням) auths.edit=Редагувати джерело автентифікації @@ -2508,8 +2502,6 @@ monitor.queue.type=Тип monitor.queue.exemplar=Приклад типу monitor.queue.numberworkers=Кількість робочих потоків monitor.queue.maxnumberworkers=Максимальна кількість робочих потоків -monitor.queue.review=Переглянути налаштування -monitor.queue.review_add=Перевірка/додавання потоків monitor.queue.settings.title=Налаштування пулу monitor.queue.settings.maxnumberworkers=Максимальна кількість робочих потоків monitor.queue.settings.maxnumberworkers.placeholder=Поточний %[1]d diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 58d1e80a37d..0cd71af7107 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -166,7 +166,6 @@ network_error=网络错误 [startpage] app_desc=一款极易搭建的自助 Git 服务 install=易安装 -install_desc=您除了可以根据操作系统平台通过 二进制运行,还可以通过 DockerVagrant,以及 包管理 安装。 platform=跨平台 platform_desc=任何 Go 语言 支持的平台都可以运行 Gitea,包括 Windows、Mac、Linux 以及 ARM。挑一个您喜欢的就行! lightweight=轻量级 @@ -299,6 +298,7 @@ filter_by_team_repositories=按团队仓库筛选 feed_of=`"%s"的源` show_archived=已归档 +archived=已归档 show_both_archived_unarchived=显示已归档和未归档的 show_only_archived=只显示已归档的 show_only_unarchived=只显示未归档的 @@ -570,7 +570,6 @@ overview=概览 following=关注中 follow=关注 unfollow=取消关注 -heatmap.loading=正在加载热图... user_bio=简历 disabled_public_activity=该用户已隐藏活动记录。 email_visibility.limited=所有已认证用户均可看到您的电子邮件地址 @@ -643,7 +642,6 @@ choose_new_avatar=选择新的头像 update_avatar=更新头像 delete_current_avatar=删除当前头像 uploaded_avatar_not_a_image=上传的文件不是一张图片。 -uploaded_avatar_is_too_big=上传的文件超过了最大大小。 update_avatar_success=您的头像已更新。 update_user_avatar_success=用户头像已更新。 @@ -1190,6 +1188,11 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=选择 cherry-pick 的目标分支: +commitstatus.error=错误 +commitstatus.failure=失败 +commitstatus.pending=待定 +commitstatus.success=成功 + ext_issues=访问外部工单 ext_issues.desc=链接到外部工单跟踪系统。 @@ -1375,9 +1378,9 @@ issues.ref_reopening_from=`于 %[2]s 关闭了这个工单 %[4]s %[2]s` issues.ref_reopened_from=`重新打开这个工单 %[4]s %[2]s` issues.ref_from=`来自 %[1]s` -issues.poster=发布者 -issues.collaborator=协作者 -issues.owner=所有者 +issues.author=作者 +issues.role.owner=管理员 +issues.role.member=普通成员 issues.re_request_review=再次请求审核 issues.is_stale=此评审之后代码有更新 issues.remove_request_review=移除审核请求 @@ -1687,8 +1690,6 @@ milestones.edit_success=里程碑 %s 已经更新。 milestones.deletion=删除里程碑 milestones.deletion_desc=删除该里程碑将会移除所有工单中相关的信息。是否继续? milestones.deletion_success=里程碑已被删除。 -milestones.filter_sort.closest_due_date=到期日从近到远 -milestones.filter_sort.furthest_due_date=到期日从远到近 milestones.filter_sort.least_complete=完成度从低到高 milestones.filter_sort.most_complete=完成度从高到低 milestones.filter_sort.most_issues=工单从多到少 @@ -2144,7 +2145,6 @@ settings.tags.protection.allowed.teams=允许的团队 settings.tags.protection.allowed.noone=无 settings.tags.protection.create=保护Git标签 settings.tags.protection.none=没有受保护的Git标签 -settings.tags.protection.pattern.description=你可以使用单个名称或 glob 模式匹配或正则表达式来匹配多个标签。了解更多请阅读 受保护Git标签指南 settings.bot_token=Bot 令牌 settings.chat_id=聊天 ID settings.matrix.homeserver_url=主服务器网址 @@ -2656,12 +2656,10 @@ packages.size=大小 packages.published=已发布 defaulthooks=默认Web钩子 -defaulthooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出 HTTP POST 请求。这里定义的 Web 钩子是默认配置,将被复制到所有新的仓库中。详情请访问 Web 钩子指南。 defaulthooks.add_webhook=添加默认Web 钩子 defaulthooks.update_webhook=更新默认 Web 钩子 systemhooks=系统 Web 钩子 -systemhooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出HTTP POST请求。这里定义的 Web 钩子将作用于系统上的所有仓库,所以请考虑这可能带来的任何性能影响。了解详情请访问 Web 钩子指南。 systemhooks.add_webhook=添加系统 Web 钩子 systemhooks.update_webhook=更新系统 Web 钩子 @@ -2765,7 +2763,6 @@ auths.tip.google_plus=从谷歌 API 控制台 (https://console.developers.google auths.tip.openid_connect=使用 OpenID 连接发现 URL (/.well-known/openid-configuration) 来指定终点 auths.tip.twitter=访问 https://dev.twitter.com/apps,创建应用并确保启用了"允许此应用程序用于登录 Twitter"的选项。 auths.tip.discord=在 https://discordapp.com/developers/applications/me 上注册新应用程序 -auths.tip.gitea=注册一个新的 OAuth2 应用程序,可以访问 https://docs.gitea.io/en-us/oauth2-provider/ 查看帮助 。 auths.tip.yandex=在 https://oauth.yandex.com/client/new 上创建一个新的应用程序。在“ Yandex.Passport API”这部分中选择以下权限:“访问电子邮件地址(Access to email address)”,“访问用户头像(Access to user avatar)”和“访问用户名,名字和姓氏,性别(Access to username, first name and surname, genderAccess to username, first name and surname, gender)” auths.tip.mastodon=输入您想要认证的 mastodon 实例的自定义 URL (或使用默认值) auths.edit=修改认证源 @@ -2942,8 +2939,6 @@ monitor.queue.exemplar=数据类型 monitor.queue.numberworkers=工作者数量 monitor.queue.maxnumberworkers=最大工作者数量 monitor.queue.numberinqueue=队列中的数量 -monitor.queue.review=查看配置 -monitor.queue.review_add=查看/添加工作者 monitor.queue.settings.title=池设置 monitor.queue.settings.maxnumberworkers=最大工作者数量 monitor.queue.settings.maxnumberworkers.placeholder=当前 %[1]d diff --git a/options/locale/locale_zh-HK.ini b/options/locale/locale_zh-HK.ini index 8ec1051916c..2cdea9feadc 100644 --- a/options/locale/locale_zh-HK.ini +++ b/options/locale/locale_zh-HK.ini @@ -384,6 +384,7 @@ commits.signed_by=簽署人 + projects.description_placeholder=組織描述 projects.title=標題 projects.template.desc=樣板 @@ -449,9 +450,8 @@ issues.context.edit=編輯 issues.reopen_issue=重新開啟 issues.create_comment=評論 issues.commit_ref_at=`在代碼提交 %[2]s 中引用了該問題` -issues.poster=發佈者 -issues.collaborator=協同者 -issues.owner=所有者 +issues.role.owner=管理員 +issues.role.member=普通成員 issues.sign_in_require_desc= 登入 才能加入這對話。 issues.edit=編輯 issues.cancel=取消 @@ -509,8 +509,6 @@ milestones.due_date=截止日期(可選) milestones.clear=清除 milestones.edit=編輯里程碑 milestones.cancel=取消 -milestones.filter_sort.closest_due_date=到期日由近到遠 -milestones.filter_sort.furthest_due_date=到期日由遠到近 milestones.filter_sort.least_complete=完成度由低到高 milestones.filter_sort.most_complete=完成度由高到低 milestones.filter_sort.most_issues=問題由多到少 @@ -565,7 +563,6 @@ settings.danger_zone=危險操作區 settings.new_owner_has_same_repo=新的儲存庫擁有者已經存在同名儲存庫! settings.transfer=轉移儲存庫所有權 settings.transfer_owner=新擁有者 -settings.trust_model.collaborator=協同者 settings.delete=刪除本儲存庫 settings.delete_notices_1=- 此操作 不可以 被回滾。 settings.delete_collaborator=移除成員 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 1d0342a48d9..3c23f9eb203 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -167,7 +167,6 @@ network_error=網路錯誤 [startpage] app_desc=一套極易架設的 Git 服務 install=安裝容易 -install_desc=簡單地執行您平台的二進位檔,或是使用 Docker,你也可以從套件管理員安裝。 platform=跨平台 platform_desc=Gitea 可以在所有能編譯 Go 語言的平台上執行: Windows, macOS, Linux, ARM 等等。挑一個您喜歡的吧! lightweight=輕量級 @@ -300,6 +299,7 @@ filter_by_team_repositories=以團隊儲存庫篩選 feed_of=「%s」的訊息來源 show_archived=已封存 +archived=已封存 show_both_archived_unarchived=顯示已封存和未封存 show_only_archived=只顯示已封存 show_only_unarchived=只顯示未封存 @@ -571,7 +571,6 @@ overview=概覽 following=追蹤中 follow=追蹤 unfollow=取消追蹤 -heatmap.loading=正在載入熱點圖... user_bio=個人簡介 disabled_public_activity=這個使用者已對外隱藏動態 email_visibility.limited=所有已驗證的使用者都可以看到您的電子信箱地址 @@ -641,7 +640,6 @@ choose_new_avatar=選擇新的大頭貼 update_avatar=更新大頭貼 delete_current_avatar=刪除目前的大頭貼 uploaded_avatar_not_a_image=上傳的檔案不是圖片 -uploaded_avatar_is_too_big=上傳的檔案大小超過了最大限制 update_avatar_success=您的大頭貼已更新 update_user_avatar_success=已更新使用者的大頭貼。 @@ -1183,6 +1181,11 @@ commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s commit.cherry-pick-content=選擇 Cherry-pick 的目標分支: +commitstatus.error=錯誤 +commitstatus.failure=失敗 +commitstatus.pending=待處理 +commitstatus.success=成功 + ext_issues=存取外部問題 ext_issues.desc=連結到外部問題追蹤器。 @@ -1367,9 +1370,9 @@ issues.ref_reopening_from=`關聯了合併請求 %[4]s 將重新 issues.ref_closed_from=`關閉了這個問題 %[4]s %[2]s` issues.ref_reopened_from=`重新開放了這個問題 %[4]s %[2]s` issues.ref_from=`自 %[1]s` -issues.poster=發布者 -issues.collaborator=協作者 -issues.owner=擁有者 +issues.author=作者 +issues.role.owner=擁有者 +issues.role.member=普通成員 issues.re_request_review=再次請求審核 issues.is_stale=經過此審核以後,此合併請求有被修改 issues.remove_request_review=移除審核請求 @@ -1679,8 +1682,6 @@ milestones.edit_success=已更新里程碑「%s」。 milestones.deletion=刪除里程碑 milestones.deletion_desc=刪除里程碑會從所有相關的問題移除它。是否繼續? milestones.deletion_success=里程碑已刪除 -milestones.filter_sort.closest_due_date=截止日期由近到遠 -milestones.filter_sort.furthest_due_date=截止日期由遠到近 milestones.filter_sort.least_complete=完成度由低到高 milestones.filter_sort.most_complete=完成度由高到低 milestones.filter_sort.most_issues=問題由多到少 @@ -2134,7 +2135,6 @@ settings.tags.protection.allowed.teams=允許的團隊 settings.tags.protection.allowed.noone=無 settings.tags.protection.create=保護標籤 settings.tags.protection.none=沒有受保護的標籤。 -settings.tags.protection.pattern.description=您可以使用單一名稱、Glob 模式、正規表示式來配對多個標籤。在受保護的標籤指南閱讀更多內容。 settings.bot_token=Bot Token settings.chat_id=Chat ID settings.matrix.homeserver_url=Homeserver 網址 @@ -2642,12 +2642,10 @@ packages.size=大小 packages.published=已發布 defaulthooks=預設 Webhook -defaulthooks.desc=當觸發某些 Gitea 事件時,Webhook 會自動發出 HTTP POST 請求到指定的伺服器。這裡所定義的 Webhook 是預設的,並且會複製到所有新儲存庫。在 Webhook 指南閱讀更多內容。 defaulthooks.add_webhook=新增預設 Webhook defaulthooks.update_webhook=更新預設 Webhook systemhooks=系統 Webhook -systemhooks.desc=當觸發某些 Gitea 事件時,Webhook 會自動發出 HTTP POST 請求到指定的伺服器。由於這裡所定義的 Webhook 會影響此系統上的所有儲存庫,因此請評估這會對效能造成多少影響。在 Webhook 指南閱讀更多內容。 systemhooks.add_webhook=新增系統 Webhook systemhooks.update_webhook=更新系統 Webhook @@ -2751,7 +2749,6 @@ auths.tip.google_plus=從 Google API 控制台取得 OAuth2 用戶端憑證。 auths.tip.openid_connect=使用 OpenID 連接探索 URL (/.well-known/openid-configuration) 來指定節點 auths.tip.twitter=建立應用程式並確保有啟用「Allow this application to be used to Sign in with Twitter」。網址:https://dev.twitter.com/apps auths.tip.discord=註冊新的應用程式。網址:https://discordapp.com/developers/applications/me -auths.tip.gitea=註冊新的 OAuth2 應用程式。到 https://docs.gitea.io/en-us/oauth2-provider/ 觀看指南 auths.tip.yandex=建立新的應用程式,從「Yandex.Passport API」區塊選擇「Access to email address」、「Access to user avatar」和「Access to username, first name and surname, gender」。網址:https://oauth.yandex.com/client/new auths.tip.mastodon=輸入您欲認證的 Mastodon 執行個體的自訂網址 (或使用預設值) auths.edit=修改認證來源 @@ -2928,8 +2925,6 @@ monitor.queue.exemplar=型別 monitor.queue.numberworkers=工作者數量 monitor.queue.maxnumberworkers=最大工作者數量 monitor.queue.numberinqueue=佇列中的數量 -monitor.queue.review=檢視組態 -monitor.queue.review_add=檢視/新增工作者 monitor.queue.settings.title=集區設定 monitor.queue.settings.maxnumberworkers=最大工作者數量 monitor.queue.settings.maxnumberworkers.placeholder=目前 %[1]d diff --git a/package-lock.json b/package-lock.json index db0480a5e8d..e5fec6aa965 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,20 +5,20 @@ "packages": { "": { "dependencies": { - "@citation-js/core": "0.6.8", - "@citation-js/plugin-bibtex": "0.6.8", - "@citation-js/plugin-csl": "0.6.8", + "@citation-js/core": "0.6.9", + "@citation-js/plugin-bibtex": "0.6.9", + "@citation-js/plugin-csl": "0.6.9", "@citation-js/plugin-software-formats": "0.6.1", "@claviska/jquery-minicolors": "2.3.6", - "@github/markdown-toolbar-element": "2.2.0", + "@github/markdown-toolbar-element": "2.2.1", "@github/relative-time-element": "4.3.0", "@github/text-expander-element": "2.5.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.6.0", + "@primer/octicons": "19.8.0", "@webcomponents/custom-elements": "1.6.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", - "asciinema-player": "3.5.0", + "asciinema-player": "3.6.1", "clippie": "4.0.6", "css-loader": "6.8.1", "dropzone": "6.0.0-beta.2", @@ -33,12 +33,12 @@ "mermaid": "10.4.0", "mini-css-extract-plugin": "2.7.6", "minimatch": "9.0.3", - "monaco-editor": "0.41.0", + "monaco-editor": "0.43.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.2.12", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "5.4.2", + "swagger-ui-dist": "5.7.2", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -55,12 +55,11 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", - "@playwright/test": "1.37.1", - "@stoplight/spectral-cli": "6.10.1", + "@playwright/test": "1.38.1", + "@stoplight/spectral-cli": "6.11.0", "@vitejs/plugin-vue": "4.3.4", - "eslint": "8.48.0", - "eslint-plugin-array-func": "3.1.8", - "eslint-plugin-custom-elements": "0.0.8", + "eslint": "8.49.0", + "eslint-plugin-array-func": "4.0.0", "eslint-plugin-import": "2.28.1", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", @@ -68,23 +67,24 @@ "eslint-plugin-regexp": "1.15.0", "eslint-plugin-sonarjs": "0.21.0", "eslint-plugin-unicorn": "48.0.1", + "eslint-plugin-vitest-globals": "1.4.0", "eslint-plugin-vue": "9.17.0", "eslint-plugin-vue-scoped-css": "2.5.0", - "eslint-plugin-wc": "1.5.0", + "eslint-plugin-wc": "2.0.3", "jsdom": "22.1.0", - "markdownlint-cli": "0.35.0", + "markdownlint-cli": "0.37.0", "postcss-html": "1.5.0", "stylelint": "15.10.3", "stylelint-declaration-block-no-ignored-properties": "2.7.0", "stylelint-declaration-strict-value": "1.9.2", "stylelint-stylistic": "0.4.3", "svgo": "3.0.2", - "updates": "14.4.0", + "updates": "15.0.2", "vite-string-plugin": "1.1.2", - "vitest": "0.34.3" + "vitest": "0.34.5" }, "engines": { - "node": ">= 16.0.0" + "node": ">= 18.0.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -106,12 +106,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.22.13", "chalk": "^2.4.2" }, "engines": { @@ -190,21 +190,21 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -290,9 +290,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", + "version": "7.22.16", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", + "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -301,9 +301,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.10.tgz", - "integrity": "sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", + "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -317,9 +317,9 @@ "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==" }, "node_modules/@citation-js/core": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.8.tgz", - "integrity": "sha512-EqnEj+0OR9t0pU0d/CQ4TKNSxxALTSm5gXxg56dQ2nnod9esIwNVDWztX5LXstiHj7k8VjUSo/TZw7O2AXFdBQ==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.9.tgz", + "integrity": "sha512-ElG4cvedkaRm/a40yhWXOUPUzAImwqI7ZmIyL55GIR4EmfQ5PkaSEcFhA3dekMa66l52ddn4lQaNVO+/yECq9A==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -347,9 +347,9 @@ } }, "node_modules/@citation-js/plugin-bibtex": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.8.tgz", - "integrity": "sha512-ERCHi4TTZ/8TM/Y6lul/pcLHfMltcZqn0BrATCXwVrndwXdUfj8Z6bQdXgaOAhHjo7ngp9T0DC7skgofEGBSTA==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.9.tgz", + "integrity": "sha512-35xHut8rbDAN2ffYt+BPn+DChxXhbVnN86fu2DHDQNWlCqCrUJhQTMRMlD0L1uuyHTDrkTvgLPtcs14WC+xKzA==", "dependencies": { "@citation-js/date": "^0.5.0", "@citation-js/name": "^0.4.2", @@ -375,9 +375,9 @@ } }, "node_modules/@citation-js/plugin-csl": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.8.tgz", - "integrity": "sha512-X3cTCKWvhD580YSVcS55XhwVgPppzDIiaYgiJopAa/MAvzogt1ODqy6dbBPtb07ttdVQm8VG8FHRD2LsGViTGg==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.9.tgz", + "integrity": "sha512-W8AYDK5o6qgkdBWgXPXmpzbTUxyfoADDbiGf1BqMdeD0IH3kSmgvXcsyeh8NMxiaM6B5VDg0k0pHaaxbTm5POA==", "dependencies": { "@citation-js/date": "^0.5.0", "citeproc": "^2.4.6" @@ -554,9 +554,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.2.tgz", - "integrity": "sha512-tM8yLeYVe7pRyAu9VMi/Q7aunpLwD139EY1S99xbQkT4/q2qa6eA4ige/WJQYdJ8GBL1K33pPFhPfPdJ/WzT8Q==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.3.tgz", + "integrity": "sha512-Lemgw4io4VZl9GHJmjiBGzQ7ONXRfRPHcUEerndjwiSkbxzrpq0Uggku5MxxrXdwJ+pTj1qyw4jwTu7hkPsgIA==", "cpu": [ "arm" ], @@ -569,9 +569,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.2.tgz", - "integrity": "sha512-lsB65vAbe90I/Qe10OjkmrdxSX4UJDjosDgb8sZUKcg3oefEuW2OT2Vozz8ef7wrJbMcmhvCC+hciF8jY/uAkw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.3.tgz", + "integrity": "sha512-w+Akc0vv5leog550kjJV9Ru+MXMR2VuMrui3C61mnysim0gkFCPOUTAfzTP0qX+HpN9Syu3YA3p1hf3EPqObRw==", "cpu": [ "arm64" ], @@ -584,9 +584,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.2.tgz", - "integrity": "sha512-qK/TpmHt2M/Hg82WXHRc/W/2SGo/l1thtDHZWqFq7oi24AjZ4O/CpPSu6ZuYKFkEgmZlFoa7CooAyYmuvnaG8w==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.3.tgz", + "integrity": "sha512-FKQJKkK5MXcBHoNZMDNUAg1+WcZlV/cuXrWCoGF/TvdRiYS4znA0m5Il5idUwfxrE20bG/vU1Cr5e1AD6IEIjQ==", "cpu": [ "x64" ], @@ -599,9 +599,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.2.tgz", - "integrity": "sha512-Ora8JokrvrzEPEpZO18ZYXkH4asCdc1DLdcVy8TGf5eWtPO1Ie4WroEJzwI52ZGtpODy3+m0a2yEX9l+KUn0tA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.3.tgz", + "integrity": "sha512-kw7e3FXU+VsJSSSl2nMKvACYlwtvZB8RUIeVShIEY6PVnuZ3c9+L9lWB2nWeeKWNNYDdtL19foCQ0ZyUL7nqGw==", "cpu": [ "arm64" ], @@ -614,9 +614,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.2.tgz", - "integrity": "sha512-tP+B5UuIbbFMj2hQaUr6EALlHOIOmlLM2FK7jeFBobPy2ERdohI4Ka6ZFjZ1ZYsrHE/hZimGuU90jusRE0pwDw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.3.tgz", + "integrity": "sha512-tPfZiwF9rO0jW6Jh9ipi58N5ZLoSjdxXeSrAYypy4psA2Yl1dAMhM71KxVfmjZhJmxRjSnb29YlRXXhh3GqzYw==", "cpu": [ "x64" ], @@ -629,9 +629,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.2.tgz", - "integrity": "sha512-YbPY2kc0acfzL1VPVK6EnAlig4f+l8xmq36OZkU0jzBVHcOTyQDhnKQaLzZudNJQyymd9OqQezeaBgkTGdTGeQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.3.tgz", + "integrity": "sha512-ERDyjOgYeKe0Vrlr1iLrqTByB026YLPzTytDTz1DRCYM+JI92Dw2dbpRHYmdqn6VBnQ9Bor6J8ZlNwdZdxjlSg==", "cpu": [ "arm64" ], @@ -644,9 +644,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.2.tgz", - "integrity": "sha512-nSO5uZT2clM6hosjWHAsS15hLrwCvIWx+b2e3lZ3MwbYSaXwvfO528OF+dLjas1g3bZonciivI8qKR/Hm7IWGw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.3.tgz", + "integrity": "sha512-nXesBZ2Ad1qL+Rm3crN7NmEVJ5uvfLFPLJev3x1j3feCQXfAhoYrojC681RhpdOph8NsvKBBwpYZHR7W0ifTTA==", "cpu": [ "x64" ], @@ -659,9 +659,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.2.tgz", - "integrity": "sha512-Odalh8hICg7SOD7XCj0YLpYCEc+6mkoq63UnExDCiRA2wXEmGlK5JVrW50vZR9Qz4qkvqnHcpH+OFEggO3PgTg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.3.tgz", + "integrity": "sha512-zr48Cg/8zkzZCzDHNxXO/89bf9e+r4HtzNUPoz4GmgAkF1gFAFmfgOdCbR8zMbzFDGb1FqBBhdXUpcTQRYS1cQ==", "cpu": [ "arm" ], @@ -674,9 +674,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.2.tgz", - "integrity": "sha512-ig2P7GeG//zWlU0AggA3pV1h5gdix0MA3wgB+NsnBXViwiGgY77fuN9Wr5uoCrs2YzaYfogXgsWZbm+HGr09xg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.3.tgz", + "integrity": "sha512-qXvYKmXj8GcJgWq3aGvxL/JG1ZM3UR272SdPU4QSTzD0eymrM7leiZH77pvY3UetCy0k1xuXZ+VPvoJNdtrsWQ==", "cpu": [ "arm64" ], @@ -689,9 +689,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.2.tgz", - "integrity": "sha512-mLfp0ziRPOLSTek0Gd9T5B8AtzKAkoZE70fneiiyPlSnUKKI4lp+mGEnQXcQEHLJAcIYDPSyBvsUbKUG2ri/XQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.3.tgz", + "integrity": "sha512-7XlCKCA0nWcbvYpusARWkFjRQNWNGlt45S+Q18UeS///K6Aw8bB2FKYe9mhVWy/XLShvCweOLZPrnMswIaDXQA==", "cpu": [ "ia32" ], @@ -704,9 +704,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.2.tgz", - "integrity": "sha512-hn28+JNDTxxCpnYjdDYVMNTR3SKavyLlCHHkufHV91fkewpIyQchS1d8wSbmXhs1fiYDpNww8KTFlJ1dHsxeSw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.3.tgz", + "integrity": "sha512-qGTgjweER5xqweiWtUIDl9OKz338EQqCwbS9c2Bh5jgEH19xQ1yhgGPNesugmDFq+UUSDtWgZ264st26b3de8A==", "cpu": [ "loong64" ], @@ -719,9 +719,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.2.tgz", - "integrity": "sha512-KbXaC0Sejt7vD2fEgPoIKb6nxkfYW9OmFUK9XQE4//PvGIxNIfPk1NmlHmMg6f25x57rpmEFrn1OotASYIAaTg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.3.tgz", + "integrity": "sha512-gy1bFskwEyxVMFRNYSvBauDIWNggD6pyxUksc0MV9UOBD138dKTzr8XnM2R4mBsHwVzeuIH8X5JhmNs2Pzrx+A==", "cpu": [ "mips64el" ], @@ -734,9 +734,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.2.tgz", - "integrity": "sha512-dJ0kE8KTqbiHtA3Fc/zn7lCd7pqVr4JcT0JqOnbj4LLzYnp+7h8Qi4yjfq42ZlHfhOCM42rBh0EwHYLL6LEzcw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.3.tgz", + "integrity": "sha512-UrYLFu62x1MmmIe85rpR3qou92wB9lEXluwMB/STDzPF9k8mi/9UvNsG07Tt9AqwPQXluMQ6bZbTzYt01+Ue5g==", "cpu": [ "ppc64" ], @@ -749,9 +749,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.2.tgz", - "integrity": "sha512-7Z/jKNFufZ/bbu4INqqCN6DDlrmOTmdw6D0gH+6Y7auok2r02Ur661qPuXidPOJ+FSgbEeQnnAGgsVynfLuOEw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.3.tgz", + "integrity": "sha512-9E73TfyMCbE+1AwFOg3glnzZ5fBAFK4aawssvuMgCRqCYzE0ylVxxzjEfut8xjmKkR320BEoMui4o/t9KA96gA==", "cpu": [ "riscv64" ], @@ -764,9 +764,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.2.tgz", - "integrity": "sha512-U+RinR6aXXABFCcAY4gSlv4CL1oOVvSSCdseQmGO66H+XyuQGZIUdhG56SZaDJQcLmrSfRmx5XZOWyCJPRqS7g==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.3.tgz", + "integrity": "sha512-LlmsbuBdm1/D66TJ3HW6URY8wO6IlYHf+ChOUz8SUAjVTuaisfuwCOAgcxo3Zsu3BZGxmI7yt//yGOxV+lHcEA==", "cpu": [ "s390x" ], @@ -779,9 +779,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.2.tgz", - "integrity": "sha512-oxzHTEv6VPm3XXNaHPyUTTte+3wGv7qVQtqaZCrgstI16gCuhNOtBXLEBkBREP57YTd68P0VgDgG73jSD8bwXQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.3.tgz", + "integrity": "sha512-ogV0+GwEmvwg/8ZbsyfkYGaLACBQWDvO0Kkh8LKBGKj9Ru8VM39zssrnu9Sxn1wbapA2qNS6BiLdwJZGouyCwQ==", "cpu": [ "x64" ], @@ -794,9 +794,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.2.tgz", - "integrity": "sha512-WNa5zZk1XpTTwMDompZmvQLHszDDDN7lYjEHCUmAGB83Bgs20EMs7ICD+oKeT6xt4phV4NDdSi/8OfjPbSbZfQ==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.3.tgz", + "integrity": "sha512-o1jLNe4uzQv2DKXMlmEzf66Wd8MoIhLNO2nlQBHLtWyh2MitDG7sMpfCO3NTcoTMuqHjfufgUQDFRI5C+xsXQw==", "cpu": [ "x64" ], @@ -809,9 +809,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.2.tgz", - "integrity": "sha512-S6kI1aT3S++Dedb7vxIuUOb3oAxqxk2Rh5rOXOTYnzN8JzW1VzBd+IqPiSpgitu45042SYD3HCoEyhLKQcDFDw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.3.tgz", + "integrity": "sha512-AZJCnr5CZgZOdhouLcfRdnk9Zv6HbaBxjcyhq0StNcvAdVZJSKIdOiPB9az2zc06ywl0ePYJz60CjdKsQacp5Q==", "cpu": [ "x64" ], @@ -824,9 +824,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.2.tgz", - "integrity": "sha512-VXSSMsmb+Z8LbsQGcBMiM+fYObDNRm8p7tkUDMPG/g4fhFX5DEFmjxIEa3N8Zr96SjsJ1woAhF0DUnS3MF3ARw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.3.tgz", + "integrity": "sha512-Acsujgeqg9InR4glTRvLKGZ+1HMtDm94ehTIHKhJjFpgVzZG9/pIcWW/HA/DoMfEyXmANLDuDZ2sNrWcjq1lxw==", "cpu": [ "x64" ], @@ -839,9 +839,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.2.tgz", - "integrity": "sha512-5NayUlSAyb5PQYFAU9x3bHdsqB88RC3aM9lKDAz4X1mo/EchMIT1Q+pSeBXNgkfNmRecLXA0O8xP+x8V+g/LKg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.3.tgz", + "integrity": "sha512-FSrAfjVVy7TifFgYgliiJOyYynhQmqgPj15pzLyJk8BUsnlWNwP/IAy6GAiB1LqtoivowRgidZsfpoYLZH586A==", "cpu": [ "arm64" ], @@ -854,9 +854,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.2.tgz", - "integrity": "sha512-47gL/ek1v36iN0wL9L4Q2MFdujR0poLZMJwhO2/N3gA89jgHp4MR8DKCmwYtGNksbfJb9JoTtbkoe6sDhg2QTA==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.3.tgz", + "integrity": "sha512-xTScXYi12xLOWZ/sc5RBmMN99BcXp/eEf7scUC0oeiRoiT5Vvo9AycuqCp+xdpDyAU+LkrCqEpUS9fCSZF8J3Q==", "cpu": [ "ia32" ], @@ -869,9 +869,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.2.tgz", - "integrity": "sha512-tcuhV7ncXBqbt/Ybf0IyrMcwVOAPDckMK9rXNHtF17UTK18OKLpg08glminN06pt2WCoALhXdLfSPbVvK/6fxw==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.3.tgz", + "integrity": "sha512-FbUN+0ZRXsypPyWE2IwIkVjDkDnJoMJARWOcFZn4KPPli+QnKqF0z1anvfaYe3ev5HFCpRDLLBDHyOALLppWHw==", "cpu": [ "x64" ], @@ -915,9 +915,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", + "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" @@ -991,23 +991,23 @@ } }, "node_modules/@eslint/js": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.48.0.tgz", - "integrity": "sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@github/combobox-nav": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.1.7.tgz", - "integrity": "sha512-Webx0W5iTpkk5Chy9dB/1BEUORQ0qrwui8HaaVBiy75W2VOJg96WTuKj1rXENAJ3XTMhdEF53bn0LYfvP0EKvg==" + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@github/combobox-nav/-/combobox-nav-2.2.0.tgz", + "integrity": "sha512-28kJUfzzPDYNyYsFCP/be8aXvEpjcEuciVENZlopcaUynS/4Pt9ll88Kl9l1D1Vy6a9+k+Km/YGJQ1e+gzG7SQ==" }, "node_modules/@github/markdown-toolbar-element": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-2.2.0.tgz", - "integrity": "sha512-/IHUYo1qEJVF9RXdf/Ay1KsJXoDTbHroVwCKhBHbfKTcvg1JgkyBvInxyERxaSAXsBdJXzEQbLB02UG17TMNww==" + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-2.2.1.tgz", + "integrity": "sha512-ap+ulyqzG3aVqwKsKjbDdYwM75TQXZpPtmIuPwm+54OTgcC96267oX3cEqd1wSqGsH7O5PonZ//fE9jH7Q4JkA==" }, "node_modules/@github/relative-time-element": { "version": "4.3.0", @@ -1023,9 +1023,9 @@ } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -1324,22 +1324,18 @@ } }, "node_modules/@playwright/test": { - "version": "1.37.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.37.1.tgz", - "integrity": "sha512-bq9zTli3vWJo8S3LwB91U0qDNQDpEXnw7knhxLM0nwDvexQAwx9tO8iKDZSqqneVq+URd/WIoz+BALMqUTgdSg==", + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", "dev": true, "dependencies": { - "@types/node": "*", - "playwright-core": "1.37.1" + "playwright": "1.38.1" }, "bin": { "playwright": "cli.js" }, "engines": { "node": ">=16" - }, - "optionalDependencies": { - "fsevents": "2.3.2" } }, "node_modules/@popperjs/core": { @@ -1352,9 +1348,9 @@ } }, "node_modules/@primer/octicons": { - "version": "19.6.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.6.0.tgz", - "integrity": "sha512-/10tz0hyJijS9hCLKw5Wb3LfRmVSQjtiUDPfvf582bhe+/xZDybgf3VLJncD5SZaetC4zNhz31VwV8nnG2PdSQ==", + "version": "19.8.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-19.8.0.tgz", + "integrity": "sha512-Imze/fyW41Io5fN+27T5EAeXJrgBjMbz6nzU+wYbRylXvIAjLPUvaJPVoStiFlgSU+TjTUJqg5A9rgMDzTyMCg==", "dependencies": { "object-assign": "^4.1.1" } @@ -1501,15 +1497,15 @@ } }, "node_modules/@stoplight/spectral-cli": { - "version": "6.10.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.10.1.tgz", - "integrity": "sha512-yjal3WE42buthVnqfwppw2YmjeXZJ8rmMaHjpx9/94xbbfS79RsReExH9sj1QZam6A9XPGWtjLdWSrklqydpYg==", + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-cli/-/spectral-cli-6.11.0.tgz", + "integrity": "sha512-IURDN47BPIf3q4ZyUPujGpBzuHWFE5yT34w9rTJ1GKA4SgdscEdQO9KoTjOPT4G4cvDlEV3bNxwQ3uRm7+wRlA==", "dev": true, "dependencies": { "@stoplight/json": "~3.21.0", "@stoplight/path": "1.3.2", "@stoplight/spectral-core": "^1.18.3", - "@stoplight/spectral-formatters": "^1.2.0", + "@stoplight/spectral-formatters": "^1.3.0", "@stoplight/spectral-parsers": "^1.0.3", "@stoplight/spectral-ref-resolver": "^1.0.4", "@stoplight/spectral-ruleset-bundler": "^1.5.2", @@ -1644,9 +1640,9 @@ } }, "node_modules/@stoplight/spectral-formatters": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-formatters/-/spectral-formatters-1.2.0.tgz", - "integrity": "sha512-1IrQksU1fpuvK7oT8t0jk419vkvzHbwqKYtnyoF9yZa+MV1AcSsieD5I6wBFL0WlgFr6iCg23s1V99VXlrFelw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-formatters/-/spectral-formatters-1.3.0.tgz", + "integrity": "sha512-ryuMwlzbPUuyn7ybSEbFYsljYmvTaTyD51wyCQs4ROzgfm3Yo5QDD0IsiJUzUpKK/Ml61ZX8ebgiPiRFEJtBpg==", "dev": true, "dependencies": { "@stoplight/path": "^1.3.2", @@ -1656,6 +1652,7 @@ "chalk": "4.1.2", "cliui": "7.0.4", "lodash": "^4.17.21", + "node-sarif-builder": "^2.0.3", "strip-ansi": "6.0", "text-table": "^0.2.0", "tslib": "^2.5.0" @@ -1770,9 +1767,9 @@ } }, "node_modules/@stoplight/spectral-rulesets": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.16.0.tgz", - "integrity": "sha512-vHnQ50zZARymT+LkLD1l0sXoe76iUf0FWFyTp3xSRFvMIvoqFlUHONjKqFUUQzLaidSWWVah3repmAibHTdaSA==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-rulesets/-/spectral-rulesets-1.17.0.tgz", + "integrity": "sha512-fRWunqvtP9k0vRonwqXQ663Xt1UfmOZRdaO+S02zA3mlKdA5a1vBQjVV9QYK70TXWmqUfmabc1G35FHNT+7iRw==", "dev": true, "dependencies": { "@asyncapi/specs": "^4.1.0", @@ -1826,9 +1823,9 @@ } }, "node_modules/@stoplight/types": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.19.0.tgz", - "integrity": "sha512-HvbH6fbvNcTJZVRGV1Xb87cwnXXuc94XYTg4SOvKOL4F9cc4UMw7Q40oaIgJ8iewkMnOSIlLExdmTkjF/QH2pg==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/@stoplight/types/-/types-13.20.0.tgz", + "integrity": "sha512-2FNTv05If7ib79VPDA/r9eUet76jewXFH2y2K5vuge6SXbRHtWBhcaRmu+6QpF4/WRNoJj5XYRSwLGXDxysBGA==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.4", @@ -1883,9 +1880,9 @@ } }, "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-VOVRLM1mBxIRxydiViqPcKn6MIxZytrbMpd6RJLIWKxUNr3zux8no0Oc7kJx0WAPIitgZ0gkrDS+btlqQpubpw==", "dev": true }, "node_modules/@types/chai-subset": { @@ -1898,17 +1895,17 @@ } }, "node_modules/@types/codemirror": { - "version": "5.60.8", - "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.8.tgz", - "integrity": "sha512-VjFgDF/eB+Aklcy15TtOTLQeMjTo07k7KAjql8OK5Dirr7a6sJY4T1uVBDuTVG9VEmn1uUsohOpYnVfgC6/jyw==", + "version": "5.60.10", + "resolved": "https://registry.npmjs.org/@types/codemirror/-/codemirror-5.60.10.tgz", + "integrity": "sha512-ZTA3teiCWKT8HUUofqlGPlShu5ojdIajizsS0HpH6GL0/iEdjRt7fXbCLHHqKYP5k7dC/HnnWIjZAiELUwBdjQ==", "dependencies": { "@types/tern": "*" } }, "node_modules/@types/d3-scale": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.3.tgz", - "integrity": "sha512-PATBiMCpvHJSMtZAMEhc2WyL+hnzarKzI6wAHYjhsonjWJYGq5BXTzQjv4l8m2jO183/4wZ90rKvSeT7o72xNQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.4.tgz", + "integrity": "sha512-eq1ZeTj0yr72L8MQk6N6heP603ubnywSDRfNpi5enouR112HzGLS6RIvExCzZTraFF4HdzNpJMwA/zGiMoHUUw==", "dependencies": { "@types/d3-time": "*" } @@ -1964,9 +1961,9 @@ "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==" }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==" + "version": "7.0.13", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", + "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -1999,9 +1996,9 @@ "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" }, "node_modules/@types/node": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.0.tgz", - "integrity": "sha512-Mgq7eCtoTjT89FqNoTzzXg2XvCi5VMhRV6+I2aYanc6kQCBImeNaAYRs/DyoVqk1YEUJK5gN9VO7HRIdz4Wo3Q==" + "version": "20.6.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.3.tgz", + "integrity": "sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -2009,23 +2006,29 @@ "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, + "node_modules/@types/sarif": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.4.tgz", + "integrity": "sha512-4xKHMdg3foh3Va1fxTzY1qt8QVqmaJpGWsVvtjQrJBn+/bkig2pWFKJ4FPI2yLI4PAj0SUKiPO4Vd7ggYIMZjQ==", + "dev": true + }, "node_modules/@types/tern": { - "version": "0.23.4", - "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.4.tgz", - "integrity": "sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@types/tern/-/tern-0.23.5.tgz", + "integrity": "sha512-POau56wDk3TQ0mQ0qG7XDzv96U5whSENZ9lC0htDvEH+9YUREo+J2U+apWcVRgR2UydEE70JXZo44goG+akTNQ==", "dependencies": { "@types/estree": "*" } }, "node_modules/@types/unist": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.7.tgz", - "integrity": "sha512-cputDpIbFgLUaGQn6Vqg3/YsJwxUwHLO13v3i5ouxT4lat0khip9AEWxtERujXV9wxIB1EyF97BSJFt6vpdI8g==" + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz", + "integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==" }, "node_modules/@types/urijs": { - "version": "1.19.19", - "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.19.tgz", - "integrity": "sha512-FDJNkyhmKLw7uEvTxx5tSXfPeQpO0iy73Ry+PmYZJvQy0QIWX8a7kJ4kLWRf+EbTPJEPDSgPXHaM7pzr5lmvCg==", + "version": "1.19.20", + "resolved": "https://registry.npmjs.org/@types/urijs/-/urijs-1.19.20.tgz", + "integrity": "sha512-77Mq/2BeHU894J364dUv9tSwxxyCLtcX228Pc8TwZpP5bvOoMns+gZoftp3LYl3FBH8vChpWbuagKGiMki2c1A==", "dev": true }, "node_modules/@vitejs/plugin-vue": { @@ -2042,13 +2045,13 @@ } }, "node_modules/@vitest/expect": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.3.tgz", - "integrity": "sha512-F8MTXZUYRBVsYL1uoIft1HHWhwDbSzwAU9Zgh8S6WFC3YgVb4AnFV2GXO3P5Em8FjEYaZtTnQYoNwwBrlOMXgg==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.5.tgz", + "integrity": "sha512-/3RBIV9XEH+nRpRMqDJBufKIOQaYUH2X6bt0rKSCW0MfKhXFLYsR5ivHifeajRSTsln0FwJbitxLKHSQz/Xwkw==", "dev": true, "dependencies": { - "@vitest/spy": "0.34.3", - "@vitest/utils": "0.34.3", + "@vitest/spy": "0.34.5", + "@vitest/utils": "0.34.5", "chai": "^4.3.7" }, "funding": { @@ -2056,12 +2059,12 @@ } }, "node_modules/@vitest/runner": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.3.tgz", - "integrity": "sha512-lYNq7N3vR57VMKMPLVvmJoiN4bqwzZ1euTW+XXYH5kzr3W/+xQG3b41xJn9ChJ3AhYOSoweu974S1V3qDcFESA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.5.tgz", + "integrity": "sha512-RDEE3ViVvl7jFSCbnBRyYuu23XxmvRTSZWW6W4M7eC5dOsK75d5LIf6uhE5Fqf809DQ1+9ICZZNxhIolWHU4og==", "dev": true, "dependencies": { - "@vitest/utils": "0.34.3", + "@vitest/utils": "0.34.5", "p-limit": "^4.0.0", "pathe": "^1.1.1" }, @@ -2097,9 +2100,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.3.tgz", - "integrity": "sha512-QyPaE15DQwbnIBp/yNJ8lbvXTZxS00kRly0kfFgAD5EYmCbYcA+1EEyRalc93M0gosL/xHeg3lKAClIXYpmUiQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.5.tgz", + "integrity": "sha512-+ikwSbhu6z2yOdtKmk/aeoDZ9QPm2g/ZO5rXT58RR9Vmu/kB2MamyDSx77dctqdZfP3Diqv4mbc/yw2kPT8rmA==", "dev": true, "dependencies": { "magic-string": "^0.30.1", @@ -2123,9 +2126,9 @@ } }, "node_modules/@vitest/spy": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.3.tgz", - "integrity": "sha512-N1V0RFQ6AI7CPgzBq9kzjRdPIgThC340DGjdKdPSE8r86aUSmeliTUgkTqLSgtEwWWsGfBQ+UetZWhK0BgJmkQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.5.tgz", + "integrity": "sha512-epsicsfhvBjRjCMOC/3k00mP/TBGQy8/P0DxOFiWyLt55gnZ99dqCfCiAsKO17BWVjn4eZRIjKvcqNmSz8gvmg==", "dev": true, "dependencies": { "tinyspy": "^2.1.1" @@ -2135,9 +2138,9 @@ } }, "node_modules/@vitest/utils": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.3.tgz", - "integrity": "sha512-kiSnzLG6m/tiT0XEl4U2H8JDBjFtwVlaE8I3QfGiMFR0QvnRDfYfdP3YvTBWM/6iJDAyaPY6yVQiCTUc7ZzTHA==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.5.tgz", + "integrity": "sha512-ur6CmmYQoeHMwmGb0v+qwkwN3yopZuZyf4xt1DBBSGBed8Hf9Gmbm/5dEWqgpLPdRx6Av6jcWXrjcKfkTzg/pw==", "dev": true, "dependencies": { "diff-sequences": "^29.4.3", @@ -2186,9 +2189,9 @@ } }, "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", + "integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -2226,9 +2229,9 @@ } }, "node_modules/@vue/reactivity-transform/node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", + "integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, @@ -2662,15 +2665,15 @@ } }, "node_modules/array-includes": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", - "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", - "get-intrinsic": "^1.1.3", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", "is-string": "^1.0.7" }, "engines": { @@ -2690,16 +2693,16 @@ } }, "node_modules/array.prototype.findlastindex": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.2.tgz", - "integrity": "sha512-tb5thFFlUcp7NdNF6/MpDk/1r/4awWG1FIz3YqDf+/zJSTezBb+/5WViH41obXULHVpDzoiCLpJ/ZO9YbJMsdw==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", + "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.1.3" + "get-intrinsic": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -2709,14 +2712,14 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", - "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -2727,14 +2730,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", - "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "es-shim-unscopables": "^1.0.0" }, "engines": { @@ -2745,14 +2748,15 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz", - "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", + "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.2", "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", "get-intrinsic": "^1.2.1", "is-array-buffer": "^3.0.2", "is-shared-array-buffer": "^1.0.2" @@ -2783,9 +2787,9 @@ } }, "node_modules/asciinema-player": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.5.0.tgz", - "integrity": "sha512-o4B2AscBuCZo4+JB9TBGrfZ7GQL99wsbm08WwmuNJTPd1lyLQJq8wgacnBsdvb2sC0K875ScYr8T5XmfeH/6dg==", + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/asciinema-player/-/asciinema-player-3.6.1.tgz", + "integrity": "sha512-FfTABH/N6pjG74A6cCfsrirTSM4UAOLMzcFXb0zS34T5czvg3CyUy2TAqa3WEs5owUFHcuN1Y2y8o0n2yjeMvQ==", "dependencies": { "@babel/runtime": "^7.21.0", "solid-js": "^1.3.0" @@ -2918,9 +2922,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.21.11", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.11.tgz", + "integrity": "sha512-xn1UXOKUz7DjdGlg9RrUr0GGiWzI97UQJnugHtH0OLDfJB7jMgoIkYvRIEO1l9EeEERVqeqLYOcFBW9ldjypbQ==", "funding": [ { "type": "opencollective", @@ -2936,10 +2940,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", + "caniuse-lite": "^1.0.30001538", + "electron-to-chromium": "^1.4.526", "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -3068,9 +3072,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001521", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001521.tgz", - "integrity": "sha512-fnx1grfpEOvDGH+V17eccmNjucGUnCbP6KL+l5KqBIerp26WK/+RQ7CIDE37KGJjaPyqWXXlFUyKiWmvdNNKmQ==", + "version": "1.0.30001538", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz", + "integrity": "sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw==", "funding": [ { "type": "opencollective", @@ -3244,9 +3248,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.14", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.14.tgz", - "integrity": "sha512-VSNugIBDGt0OU9gDjeVr6fNkoFQznrWEUdAApMlXQNbfE8gGO19776D6MwSqF/V/w/sDwonsQ0z7KmmI9guScg==" + "version": "5.65.15", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.15.tgz", + "integrity": "sha512-YC4EHbbwQeubZzxLl5G4nlbLc1T21QTrKGaOal/Pkm9dVDMZXMH7+ieSPEOZCtO9I68i8/oteJKOxzHC2zR+0g==" }, "node_modules/codemirror-spell-checker": { "version": "1.1.2", @@ -3332,14 +3336,14 @@ } }, "node_modules/cosmiconfig": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", - "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "dependencies": { - "import-fresh": "^3.2.1", + "import-fresh": "^3.3.0", "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", + "parse-json": "^5.2.0", "path-type": "^4.0.0" }, "engines": { @@ -3347,6 +3351,14 @@ }, "funding": { "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/cross-spawn": { @@ -4031,9 +4043,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.9", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", - "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==" + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" }, "node_modules/debug": { "version": "4.3.4", @@ -4151,12 +4163,27 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/define-properties": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", - "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "node_modules/define-data-property": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz", + "integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==", "dev": true, "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" }, @@ -4364,9 +4391,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.495", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.495.tgz", - "integrity": "sha512-mwknuemBZnoOCths4GtpU/SDuVMp3uQHKa2UNJT9/aVD6WVRjGpXOxRGX7lm6ILIenTdGXPSTCTDaWos5tEU8Q==" + "version": "1.4.527", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.527.tgz", + "integrity": "sha512-EafxEiEDzk2aLrdbtVczylHflHdHkNrpGNHIgDyA63sUQLQVS2ayj2hPw3RsVB42qkwURH+T2OxV7kGPUuYszA==" }, "node_modules/elkjs": { "version": "0.8.2", @@ -4440,18 +4467,18 @@ } }, "node_modules/es-abstract": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz", - "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==", + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz", + "integrity": "sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.2", "available-typed-arrays": "^1.0.5", "call-bind": "^1.0.2", "es-set-tostringtag": "^2.0.1", "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.5", + "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.1", "get-symbol-description": "^1.0.0", "globalthis": "^1.0.3", @@ -4467,23 +4494,23 @@ "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-typed-array": "^1.1.10", + "is-typed-array": "^1.1.12", "is-weakref": "^1.0.2", "object-inspect": "^1.12.3", "object-keys": "^1.1.1", "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.0", - "safe-array-concat": "^1.0.0", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.7", - "string.prototype.trimend": "^1.0.6", - "string.prototype.trimstart": "^1.0.6", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", "typed-array-buffer": "^1.0.0", "typed-array-byte-length": "^1.0.0", "typed-array-byte-offset": "^1.0.0", "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.10" + "which-typed-array": "^1.1.11" }, "engines": { "node": ">= 0.4" @@ -4493,18 +4520,19 @@ } }, "node_modules/es-aggregate-error": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.9.tgz", - "integrity": "sha512-fvnX40sb538wdU6r4s35cq4EY6Lr09Upj40BEVem4LEsuW8XgQep9yD5Q1U2KftokNp1rWODFJ2qwZSsAjFpbg==", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/es-aggregate-error/-/es-aggregate-error-1.0.11.tgz", + "integrity": "sha512-DCiZiNlMlbvofET/cE55My387NiLvuGToBEZDdK9U2G3svDCjL8WOgO5Il6lO83nQ8qmag/R9nArdpaFQ/m3lA==", "dev": true, "dependencies": { - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4", + "define-data-property": "^1.1.0", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.1", "function-bind": "^1.1.1", - "functions-have-names": "^1.2.3", - "get-intrinsic": "^1.1.3", + "get-intrinsic": "^1.2.1", "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.0", + "set-function-name": "^2.0.1" }, "engines": { "node": ">= 0.4" @@ -4514,9 +4542,9 @@ } }, "node_modules/es-module-lexer": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", - "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.1.tgz", + "integrity": "sha512-JUFAyicQV9mXc3YRxPnDlrfBKpqt6hUYzz9/boprUJHs4e4KVr3XwOF70doO6gwXUor6EWZJAyWAfKki84t20Q==" }, "node_modules/es-set-tostringtag": { "version": "2.0.1", @@ -4559,9 +4587,9 @@ } }, "node_modules/esbuild": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.2.tgz", - "integrity": "sha512-G6hPax8UbFakEj3hWO0Vs52LQ8k3lnBhxZWomUJDxfz3rZTLqF5k/FCzuNdLx2RbpBiQQF9H9onlDDH1lZsnjg==", + "version": "0.19.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.3.tgz", + "integrity": "sha512-UlJ1qUUA2jL2nNib1JTSkifQTcYTroFqRjwCFW4QYEKEsixXD5Tik9xML7zh2gTxkYTBKGHNH9y7txMwVyPbjw==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -4570,28 +4598,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.19.2", - "@esbuild/android-arm64": "0.19.2", - "@esbuild/android-x64": "0.19.2", - "@esbuild/darwin-arm64": "0.19.2", - "@esbuild/darwin-x64": "0.19.2", - "@esbuild/freebsd-arm64": "0.19.2", - "@esbuild/freebsd-x64": "0.19.2", - "@esbuild/linux-arm": "0.19.2", - "@esbuild/linux-arm64": "0.19.2", - "@esbuild/linux-ia32": "0.19.2", - "@esbuild/linux-loong64": "0.19.2", - "@esbuild/linux-mips64el": "0.19.2", - "@esbuild/linux-ppc64": "0.19.2", - "@esbuild/linux-riscv64": "0.19.2", - "@esbuild/linux-s390x": "0.19.2", - "@esbuild/linux-x64": "0.19.2", - "@esbuild/netbsd-x64": "0.19.2", - "@esbuild/openbsd-x64": "0.19.2", - "@esbuild/sunos-x64": "0.19.2", - "@esbuild/win32-arm64": "0.19.2", - "@esbuild/win32-ia32": "0.19.2", - "@esbuild/win32-x64": "0.19.2" + "@esbuild/android-arm": "0.19.3", + "@esbuild/android-arm64": "0.19.3", + "@esbuild/android-x64": "0.19.3", + "@esbuild/darwin-arm64": "0.19.3", + "@esbuild/darwin-x64": "0.19.3", + "@esbuild/freebsd-arm64": "0.19.3", + "@esbuild/freebsd-x64": "0.19.3", + "@esbuild/linux-arm": "0.19.3", + "@esbuild/linux-arm64": "0.19.3", + "@esbuild/linux-ia32": "0.19.3", + "@esbuild/linux-loong64": "0.19.3", + "@esbuild/linux-mips64el": "0.19.3", + "@esbuild/linux-ppc64": "0.19.3", + "@esbuild/linux-riscv64": "0.19.3", + "@esbuild/linux-s390x": "0.19.3", + "@esbuild/linux-x64": "0.19.3", + "@esbuild/netbsd-x64": "0.19.3", + "@esbuild/openbsd-x64": "0.19.3", + "@esbuild/sunos-x64": "0.19.3", + "@esbuild/win32-arm64": "0.19.3", + "@esbuild/win32-ia32": "0.19.3", + "@esbuild/win32-x64": "0.19.3" } }, "node_modules/esbuild-loader": { @@ -4643,16 +4671,16 @@ } }, "node_modules/eslint": { - "version": "8.48.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.48.0.tgz", - "integrity": "sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg==", + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.48.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.12.4", @@ -4743,24 +4771,15 @@ } }, "node_modules/eslint-plugin-array-func": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-array-func/-/eslint-plugin-array-func-3.1.8.tgz", - "integrity": "sha512-BjnbJvw+knaHgVddIL3q5xYcoqAZoK8wOdT7QF+mkvSAjXdZCdhL0z71Y7oRtgXA8BpN9QLJ2uHgD3I6ymlbOw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-array-func/-/eslint-plugin-array-func-4.0.0.tgz", + "integrity": "sha512-p3NY2idNIvgmQLF2/62ZskYt8gOuUgQ51smRc3Lh7FtSozpNc2sg+lniz9VaCagLZHEZTl8qGJKqE7xy8O/D/g==", "dev": true, "engines": { - "node": ">= 6.8.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "peerDependencies": { - "eslint": ">=3.0.0" - } - }, - "node_modules/eslint-plugin-custom-elements": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-custom-elements/-/eslint-plugin-custom-elements-0.0.8.tgz", - "integrity": "sha512-726XMAabRLKKm6/yjvYfvY4MKBwX9C4x8yPjj/ap470KhSIBHm+xHbm3P7cKlsFz/4cxq6YrBeSwKmwlacF1jg==", - "dev": true, - "peerDependencies": { - "eslint": ">=4.19.0" + "eslint": ">=8.40.0" } }, "node_modules/eslint-plugin-import": { @@ -4945,6 +4964,12 @@ "eslint": ">=8.44.0" } }, + "node_modules/eslint-plugin-vitest-globals": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vitest-globals/-/eslint-plugin-vitest-globals-1.4.0.tgz", + "integrity": "sha512-WE+YlK9X9s4vf5EaYRU0Scw7WItDZStm+PapFSYlg2ABNtaQ4zIG7wEqpoUB3SlfM+SgkhgmzR0TeJOO5k3/Nw==", + "dev": true + }, "node_modules/eslint-plugin-vue": { "version": "9.17.0", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.17.0.tgz", @@ -4992,9 +5017,9 @@ } }, "node_modules/eslint-plugin-wc": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-1.5.0.tgz", - "integrity": "sha512-KFSfiHDol/LeV7U6IX8GdgpGf/s3wG8FTG120Rml/hGNB/DkCuGYQhlf0VgdBdf7gweem8Nlsh5o64HNdj+qPA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-wc/-/eslint-plugin-wc-2.0.3.tgz", + "integrity": "sha512-O3i71FodYMArf8DBs+OuDQ8SH8SMiNaJ4GIcXRDsGURPdvBrVDNS9+GQ0xwmzhqUWV0df5xq8irpceA6YBdJmg==", "dev": true, "dependencies": { "is-valid-element-name": "^1.0.0", @@ -5260,6 +5285,44 @@ "node-fetch": "~2.6.1" } }, + "node_modules/fetch-ponyfill/node_modules/node-fetch": { + "version": "2.6.13", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz", + "integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/fetch-ponyfill/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/fetch-ponyfill/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/fetch-ponyfill/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5300,22 +5363,23 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", + "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.7", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/for-each": { @@ -5357,6 +5421,20 @@ "node": ">= 6" } }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -5382,15 +5460,15 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", - "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "functions-have-names": "^1.2.2" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" }, "engines": { "node": ">= 0.4" @@ -5489,9 +5567,9 @@ } }, "node_modules/get-tsconfig": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.0.tgz", - "integrity": "sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==", + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, @@ -5600,9 +5678,9 @@ } }, "node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.22.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.22.0.tgz", + "integrity": "sha512-H1Ddc/PbZHTDVJSnj8kWptIRSD6AM3pK+mKytuIVF4uoBV7rshFlhhvA58ceJ5wp3Er58w6zj7bykMpYXt3ETw==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -6020,12 +6098,12 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.1.tgz", - "integrity": "sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", "dev": true, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/internal-slot": { @@ -6416,9 +6494,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.0.tgz", - "integrity": "sha512-uKmsITSsF4rUWQHzqaRUuyAir3fZfW3f202Ee34lz/gZCi970CPZwyQXLGNgWJvvZbvFyzeyGq0+4fcG/mBKZg==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.3.tgz", + "integrity": "sha512-R2bUw+kVZFS/h1AZqBKrSgDmdmjApzgY0AlCPumopFiAlbUxE2gf+SCuBzQ0cP5hHmUmFYF5yw55T97Th5Kstg==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -6472,9 +6550,9 @@ "dev": true }, "node_modules/js-tokens": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.1.tgz", - "integrity": "sha512-3AGrZT6tuMm1ZWWn9mLXh7XMfi2YtiLNPALCVxBCiUVq0LD1OQMxV/AdS/s7rLJU5o9i/jBZw/N4vXXL5dm29A==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.2.tgz", + "integrity": "sha512-Olnt+V7xYdvGze9YTbGFZIfQXuGV4R3nQwwl8BrtgaPE/wq8UFpUHWuTNc05saowhSr1ZO6tx+V6RjE9D5YQog==", "dev": true }, "node_modules/js-types": { @@ -6572,6 +6650,12 @@ "node": ">=6" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -6605,6 +6689,18 @@ "integrity": "sha512-o6/yDBYccGvTz1+QFevz6l6OBZ2+fMVu2JZ9CIhzsYRX4mjaK5IyX9eldUdCmga16zlgQxyrj5pt9kzuj2C02w==", "dev": true }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonpath-plus": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/jsonpath-plus/-/jsonpath-plus-7.1.0.tgz", @@ -6643,6 +6739,15 @@ "katex": "cli.js" } }, + "node_modules/keyv": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", + "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/khroma": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", @@ -6758,9 +6863,9 @@ } }, "node_modules/lightningcss": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.5.tgz", - "integrity": "sha512-/pEUPeih2EwIx9n4T82aOG6CInN83tl/mWlw6B5gWLf36UplQi1L+5p3FUHsdt4fXVfOkkh9KIaM3owoq7ss8A==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.22.0.tgz", + "integrity": "sha512-+z0qvwRVzs4XGRXelnWRNwqsXUx8k3bSkbP8vD42kYKSk3z9OM2P3e/gagT7ei/gwh8DTS80LZOFZV6lm8Z8Fg==", "dependencies": { "detect-libc": "^1.0.3" }, @@ -6772,20 +6877,21 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.21.5", - "lightningcss-darwin-x64": "1.21.5", - "lightningcss-linux-arm-gnueabihf": "1.21.5", - "lightningcss-linux-arm64-gnu": "1.21.5", - "lightningcss-linux-arm64-musl": "1.21.5", - "lightningcss-linux-x64-gnu": "1.21.5", - "lightningcss-linux-x64-musl": "1.21.5", - "lightningcss-win32-x64-msvc": "1.21.5" + "lightningcss-darwin-arm64": "1.22.0", + "lightningcss-darwin-x64": "1.22.0", + "lightningcss-freebsd-x64": "1.22.0", + "lightningcss-linux-arm-gnueabihf": "1.22.0", + "lightningcss-linux-arm64-gnu": "1.22.0", + "lightningcss-linux-arm64-musl": "1.22.0", + "lightningcss-linux-x64-gnu": "1.22.0", + "lightningcss-linux-x64-musl": "1.22.0", + "lightningcss-win32-x64-msvc": "1.22.0" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.5.tgz", - "integrity": "sha512-z05hyLX85WY0UfhkFUOrWEFqD69lpVAmgl3aDzMKlIZJGygbhbegqb4PV8qfUrKKNBauut/qVNPKZglhTaDDxA==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.22.0.tgz", + "integrity": "sha512-aH2be3nNny+It5YEVm8tBSSdRlBVWQV8m2oJ7dESiYRzyY/E/bQUe2xlw5caaMuhlM9aoTMtOH25yzMhir0qPg==", "cpu": [ "arm64" ], @@ -6802,9 +6908,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.5.tgz", - "integrity": "sha512-MSJhmej/U9MrdPxDk7+FWhO8+UqVoZUHG4VvKT5RQ4RJtqtANTiWiI97LvoVNMtdMnHaKs1Pkji6wHUFxjJsHQ==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.22.0.tgz", + "integrity": "sha512-9KHRFA0Y6mNxRHeoQMp0YaI0R0O2kOgUlYPRjuasU4d+pI8NRhVn9bt0yX9VPs5ibWX1RbDViSPtGJvYYrfVAQ==", "cpu": [ "x64" ], @@ -6820,10 +6926,29 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.22.0.tgz", + "integrity": "sha512-xaYL3xperGwD85rQioDb52ozF3NAJb+9wrge3jD9lxGffplu0Mn35rXMptB8Uc2N9Mw1i3Bvl7+z1evlqVl7ww==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.5.tgz", - "integrity": "sha512-xN6+5/JsMrbZHL1lPl+MiNJ3Xza12ueBKPepiyDCFQzlhFRTj7D0LG+cfNTzPBTO8KcYQynLpl1iBB8LGp3Xtw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.22.0.tgz", + "integrity": "sha512-epQGvXIjOuxrZpMpMnRjK54ZqzhiHhCPLtHvw2fb6NeK2kK9YtF0wqmeTBiQ1AkbWfnnXGTstYaFNiadNK+StQ==", "cpu": [ "arm" ], @@ -6840,9 +6965,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.5.tgz", - "integrity": "sha512-KfzFNhC4XTbmG3ma/xcTs/IhCwieW89XALIusKmnV0N618ZDXEB0XjWOYQRCXeK9mfqPdbTBpurEHV/XZtkniQ==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.22.0.tgz", + "integrity": "sha512-AArGtKSY4DGTA8xP8SDyNyKtpsUl1Rzq6FW4JomeyUQ4nBrR71uPChksTpj3gmWuGhZeRKLeCUI1DBid/zhChg==", "cpu": [ "arm64" ], @@ -6859,9 +6984,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.5.tgz", - "integrity": "sha512-bc0GytQO5Mn9QM6szaZ+31fQHNdidgpM1sSCwzPItz8hg3wOvKl8039rU0veMJV3ZgC9z0ypNRceLrSHeRHmXw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.22.0.tgz", + "integrity": "sha512-RRraNgP8hnBPhInTTUdlFm+z16C/ghbxBG51Sw00hd7HUyKmEUKRozyc5od+/N6pOrX/bIh5vIbtMXIxsos0lg==", "cpu": [ "arm64" ], @@ -6878,9 +7003,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.5.tgz", - "integrity": "sha512-JwMbgypPQgc2kW2av3OwzZ8cbrEuIiDiXPJdXRE6aVxu67yHauJawQLqJKTGUhiAhy6iLDG8Wg0a3/ziL+m+Kw==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.22.0.tgz", + "integrity": "sha512-grdrhYGRi2KrR+bsXJVI0myRADqyA7ekprGxiuK5QRNkv7kj3Yq1fERDNyzZvjisHwKUi29sYMClscbtl+/Zpw==", "cpu": [ "x64" ], @@ -6897,9 +7022,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.5.tgz", - "integrity": "sha512-Ib8b6IQ/OR/VrPU6YBgy4T3QnuHY7DUa95O+nz+cwrTkMSN6fuHcTcIaz4t8TJ6HI5pl3uxUOZjmtls2pyQWow==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.22.0.tgz", + "integrity": "sha512-t5f90X+iQUtIyR56oXIHMBUyQFX/zwmPt72E6Dane3P8KNGlkijTg2I75XVQS860gNoEFzV7Mm5ArRRA7u5CAQ==", "cpu": [ "x64" ], @@ -6937,9 +7062,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.21.5", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.5.tgz", - "integrity": "sha512-A8cSi8lUpBeVmoF+DqqW7cd0FemDbCuKr490IXdjyeI+KL8adpSKUs8tcqO0OXPh1EoDqK7JNkD/dELmd4Iz5g==", + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.22.0.tgz", + "integrity": "sha512-64HTDtOOZE9PUCZJiZZQpyqXBbdby1lnztBccnqh+NtbKxjnGzP92R2ngcgeuqMPecMNqNWxgoWgTGpC+yN5Sw==", "cpu": [ "x64" ], @@ -7141,33 +7266,33 @@ } }, "node_modules/markdownlint": { - "version": "0.29.0", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.29.0.tgz", - "integrity": "sha512-ASAzqpODstu/Qsk0xW5BPgWnK/qjpBQ4e7IpsSvvFXcfYIjanLTdwFRJK1SIEEh0fGSMKXcJf/qhaZYHyME0wA==", + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.31.1.tgz", + "integrity": "sha512-CKMR2hgcIBrYlIUccDCOvi966PZ0kJExDrUi1R+oF9PvqQmCrTqjOsgIvf2403OmJ+CWomuzDoylr6KbuMyvHA==", "dev": true, "dependencies": { "markdown-it": "13.0.1", - "markdownlint-micromark": "0.1.5" + "markdownlint-micromark": "0.1.7" }, "engines": { "node": ">=16" } }, "node_modules/markdownlint-cli": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.35.0.tgz", - "integrity": "sha512-lVIIIV1MrUtjoocgDqXLxUCxlRbn7Ve8rsWppfwciUNwLlNS28AhNiyQ3PU7jjj4Qvj+rWTTvwkqg7AcdG988g==", + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/markdownlint-cli/-/markdownlint-cli-0.37.0.tgz", + "integrity": "sha512-hNKAc0bWBBuVhJbSWbUhRzavstiB4o1jh3JeSpwC4/dt6eJ54lRfYHRxVdzVp4qGWBKbeE6Pg490PFEfrKjqSg==", "dev": true, "dependencies": { "commander": "~11.0.0", "get-stdin": "~9.0.0", - "glob": "~10.2.7", + "glob": "~10.3.4", "ignore": "~5.2.4", "js-yaml": "^4.1.0", "jsonc-parser": "~3.2.0", - "markdownlint": "~0.29.0", - "minimatch": "~9.0.1", - "run-con": "~1.2.11" + "markdownlint": "~0.31.1", + "minimatch": "~9.0.3", + "run-con": "~1.3.2" }, "bin": { "markdownlint": "markdownlint.js" @@ -7186,16 +7311,16 @@ } }, "node_modules/markdownlint-cli/node_modules/glob": { - "version": "10.2.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.7.tgz", - "integrity": "sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==", + "version": "10.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.5.tgz", + "integrity": "sha512-bYUpUD7XDEHI4Q2O5a7PXGvyw4deKR70kHiDxzQbe925wbZknhOzUt2xBgTkYL6RBcVeXYuD9iNYeqoWbBZQnA==", "dev": true, "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^2.0.3", "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2", - "path-scurry": "^1.7.0" + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" }, "bin": { "glob": "dist/cjs/src/bin.js" @@ -7214,9 +7339,9 @@ "dev": true }, "node_modules/markdownlint-micromark": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.5.tgz", - "integrity": "sha512-HvofNU4QCvfUCWnocQP1IAWaqop5wpWrB0mKB6SSh0fcpV0PdmQNS6tdUuFew1utpYlUvYYzz84oDkrD76GB9A==", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz", + "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==", "dev": true, "engines": { "node": ">=16" @@ -7947,18 +8072,18 @@ } }, "node_modules/minipass": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", - "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.3.tgz", + "integrity": "sha512-LhbbwCfz3vsb12j/WkWQPZfKTsgqIe1Nf/ti1pKjYESGLHIVjWU96G9/ljLH4F9mWNVhlQOm0VySdAWzf05dpg==", "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } }, "node_modules/mlly": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.1.tgz", - "integrity": "sha512-SCDs78Q2o09jiZiE2WziwVBEqXQ02XkGdUy45cbJf+BpYRIjArXRJ1Wbowxkb+NaM9DWvS3UC9GiO/6eqvQ/pg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", + "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", "dev": true, "dependencies": { "acorn": "^8.10.0", @@ -7968,9 +8093,9 @@ } }, "node_modules/monaco-editor": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.41.0.tgz", - "integrity": "sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA==" + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.43.0.tgz", + "integrity": "sha512-cnoqwQi/9fml2Szamv1XbSJieGJ1Dc8tENVMD26Kcfl7xGQWp7OBKMjlwKVGYFJ3/AXJjSOGvcqK7Ry/j9BM1Q==" }, "node_modules/monaco-editor-webpack-plugin": { "version": "7.1.0", @@ -8060,9 +8185,9 @@ } }, "node_modules/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -8102,6 +8227,19 @@ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" }, + "node_modules/node-sarif-builder": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-2.0.3.tgz", + "integrity": "sha512-Pzr3rol8fvhG/oJjIq2NTVB0vmdNNlz22FENhhPojYRZ4/ee08CfK4YuKmuL54V9MLhI1kpzxfOJ/63LzmZzDg==", + "dev": true, + "dependencies": { + "@types/sarif": "^2.1.4", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/non-layered-tidy-tree-layout": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", @@ -8209,14 +8347,14 @@ } }, "node_modules/object.fromentries": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", - "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -8226,26 +8364,26 @@ } }, "node_modules/object.groupby": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.0.tgz", - "integrity": "sha512-70MWG6NfRH9GnbZOikuhPPYzpUpof9iW2J9E4dW7FXTqPNb6rllE6u39SKwwiNh8lCwX3DDb5OgcKGiEBrTTyw==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", + "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "es-abstract": "^1.21.2", + "es-abstract": "^1.22.1", "get-intrinsic": "^1.2.1" } }, "node_modules/object.values": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", - "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -8557,10 +8695,28 @@ "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", "dev": true }, + "node_modules/playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "dev": true, + "dependencies": { + "playwright-core": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, "node_modules/playwright-core": { - "version": "1.37.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.37.1.tgz", - "integrity": "sha512-17EuQxlSIYCmEMwzMqusJ2ztDgJePjrbttaefgdsiqeLWidjYz9BxXaTaZWxH1J95SHGk6tjE+dwgWILJoUZfA==", + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -8588,9 +8744,9 @@ } }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.30", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.30.tgz", + "integrity": "sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g==", "funding": [ { "type": "opencollective", @@ -8713,9 +8869,9 @@ } }, "node_modules/postcss-scss": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.7.tgz", - "integrity": "sha512-xPv2GseoyXPa58Nro7M73ZntttusuCmZdeOojUFR5PZDz2BR62vfYx1w9TyOnp1+nYFowgOMipsCBhxzVkAEPw==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.8.tgz", + "integrity": "sha512-Cr0X8Eu7xMhE96PJck6ses/uVVXDtE5ghUTKNUYgm8ozgP2TkgV3LWs3WgLV1xaSSLq8ZFiXaUrj0LVgG1fGEA==", "dev": true, "funding": [ { @@ -8735,7 +8891,7 @@ "node": ">=12.0" }, "peerDependencies": { - "postcss": "^8.4.19" + "postcss": "^8.4.29" } }, "node_modules/postcss-selector-parser": { @@ -8784,9 +8940,9 @@ } }, "node_modules/pretty-format": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz", - "integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", @@ -9099,14 +9255,14 @@ } }, "node_modules/regexp.prototype.flags": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", - "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "set-function-name": "^2.0.0" }, "engines": { "node": ">= 0.4" @@ -9169,9 +9325,9 @@ } }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.6", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz", + "integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -9271,13 +9427,13 @@ "dev": true }, "node_modules/run-con": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.2.12.tgz", - "integrity": "sha512-5257ILMYIF4RztL9uoZ7V9Q97zHtNHn5bN3NobeAnzB1P3ASLgg8qocM2u+R18ttp+VEM78N2LK8XcNVtnSRrg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/run-con/-/run-con-1.3.2.tgz", + "integrity": "sha512-CcfE+mYiTcKEzg0IqS08+efdnH0oJ3zV0wSUFBNrMHMuxCtXvBCLzCJHatwuXDcu/RlhjTziTo/a1ruQik6/Yg==", "dev": true, "dependencies": { "deep-extend": "^0.6.0", - "ini": "~3.0.0", + "ini": "~4.1.0", "minimist": "^1.2.8", "strip-json-comments": "~3.1.1" }, @@ -9324,13 +9480,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz", - "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", + "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", + "get-intrinsic": "^1.2.1", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -9462,6 +9618,20 @@ "node": ">=10" } }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -9572,9 +9742,9 @@ } }, "node_modules/solid-js": { - "version": "1.7.11", - "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.7.11.tgz", - "integrity": "sha512-JkuvsHt8jqy7USsy9xJtT18aF9r2pFO+GB8JQ2XGTvtF49rGTObB46iebD25sE3qVNvIbwglXOXdALnJq9IHtQ==", + "version": "1.7.12", + "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.7.12.tgz", + "integrity": "sha512-QoyoOUKu14iLoGxjxWFIU8+/1kLT4edQ7mZESFPonsEXZ//VJtPKD8Ud1aTKzotj+MNWmSs9YzK6TdY+fO9Eww==", "dependencies": { "csstype": "^3.1.0", "seroval": "^0.5.0" @@ -9676,9 +9846,9 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.15.tgz", + "integrity": "sha512-lpT8hSQp9jAKp9mhtBU4Xjon8LPGBvLIuBiSVhMEtmLecTh2mO0tlqrAMp47tBXzMr13NJMQ2lf7RpQGLJ3HsQ==" }, "node_modules/spdx-ranges": { "version": "2.1.1", @@ -9712,9 +9882,9 @@ } }, "node_modules/std-env": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.0.tgz", - "integrity": "sha512-YqHeQIIQ8r1VtUZOTOyjsAXAsjr369SplZ5rlQaiJTBsvodvPSCME7vuz8pnQltbQ0Cw0lyFo5Q8uyNwYQ58Xw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.3.tgz", + "integrity": "sha512-f9aPhy8fYBuMN+sNfakZV18U39PbalgjXG3lLB9WkaYTxijru61wb57V9wxxNthXM5Sd88ETBWi29qLAsHO52Q==", "dev": true }, "node_modules/string-width": { @@ -9746,14 +9916,14 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", - "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "engines": { "node": ">= 0.4" @@ -9763,28 +9933,28 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", - "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", - "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10093,9 +10263,9 @@ } }, "node_modules/swagger-ui-dist": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.4.2.tgz", - "integrity": "sha512-vT5QxP/NOr9m4gLZl+SpavWI3M9Fdh30+Sdw9rEtZbkqNmNNEPhjXas2xTD9rsJYYdLzAiMfwXvtooWH3xbLJA==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-5.7.2.tgz", + "integrity": "sha512-mVZc9QVQ6pTCV5crli3+Ng+DoMPwdtMHK8QLk2oX8Mtamp4D/hV+uYdC3lV0JZrDgpNEcjs0RrWTqMwwosuLPQ==" }, "node_modules/symbol-tree": { "version": "3.2.4", @@ -10140,9 +10310,9 @@ } }, "node_modules/terser": { - "version": "5.19.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz", - "integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.20.0.tgz", + "integrity": "sha512-e56ETryaQDyebBwJIWYB2TT6f2EZ0fL0sW/JRXNMN26zZdKi2u/E/5my5lG6jNxym6qsrVXfFRmOdV42zlAgLQ==", "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -10254,9 +10424,9 @@ } }, "node_modules/tinybench": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", - "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", + "integrity": "sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==", "dev": true }, "node_modules/tinycolor2": { @@ -10321,6 +10491,15 @@ "node": ">=6" } }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/tr46": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", @@ -10383,9 +10562,9 @@ } }, "node_modules/tslib": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", - "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, "node_modules/type-check": { @@ -10536,18 +10715,18 @@ } }, "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", "dev": true, "engines": { - "node": ">= 4.0.0" + "node": ">= 10.0.0" } }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -10574,15 +10753,15 @@ } }, "node_modules/updates": { - "version": "14.4.0", - "resolved": "https://registry.npmjs.org/updates/-/updates-14.4.0.tgz", - "integrity": "sha512-fAB49LEq46XlJfQmLDWHt3Yt7XpSAxj1GwO6MxgEMHlGbhyGLSNu2hPYuSzipNRhO7phJNp8UDi0kikn/RAwwQ==", + "version": "15.0.2", + "resolved": "https://registry.npmjs.org/updates/-/updates-15.0.2.tgz", + "integrity": "sha512-bdVZgJ2lr4Ke3pWyq7bT9ynJ5L4J69xERSvMMlt96nWlzVhB5kG8tYzicqI3I5Bpyj7cAv9MLBxDWaj/mB+nfg==", "dev": true, "bin": { "updates": "bin/updates.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/uri-js": { @@ -10624,9 +10803,13 @@ } }, "node_modules/uuid": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", - "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], "bin": { "uuid": "dist/bin/uuid" } @@ -10723,9 +10906,9 @@ } }, "node_modules/vite-node": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.3.tgz", - "integrity": "sha512-+0TzJf1g0tYXj6tR2vEyiA42OPq68QkRZCu/ERSo2PtsDJfBpDyEfuKbRvLmZqi/CgC7SCBtyC+WjTGNMRIaig==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.5.tgz", + "integrity": "sha512-RNZ+DwbCvDoI5CbCSQSyRyzDTfFvFauvMs6Yq4ObJROKlIKuat1KgSX/Ako5rlDMfVCyMcpMRMTkJBxd6z8YRA==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -10733,7 +10916,7 @@ "mlly": "^1.4.0", "pathe": "^1.1.1", "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" @@ -11144,9 +11327,9 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "3.28.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.0.tgz", - "integrity": "sha512-d7zhvo1OUY2SXSM6pfNjgD5+d0Nz87CUp4mt8l/GgVP3oBsPwzNvSzyu1me6BSG9JIgWNTVcafIXBIyM8yQ3yw==", + "version": "3.29.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.2.tgz", + "integrity": "sha512-CJouHoZ27v6siztc21eEQGo0kIcE5D1gVPA571ez0mMYb25LGYGKnVNXpEj5MGlepmDWGXNjDB5q7uNiPHC11A==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -11160,19 +11343,19 @@ } }, "node_modules/vitest": { - "version": "0.34.3", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.3.tgz", - "integrity": "sha512-7+VA5Iw4S3USYk+qwPxHl8plCMhA5rtfwMjgoQXMT7rO5ldWcdsdo3U1QD289JgglGK4WeOzgoLTsGFu6VISyQ==", + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.5.tgz", + "integrity": "sha512-CPI68mmnr2DThSB3frSuE5RLm9wo5wU4fbDrDwWQQB1CWgq9jQVoQwnQSzYAjdoBOPoH2UtXpOgHVge/uScfZg==", "dev": true, "dependencies": { "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.34.3", - "@vitest/runner": "0.34.3", - "@vitest/snapshot": "0.34.3", - "@vitest/spy": "0.34.3", - "@vitest/utils": "0.34.3", + "@vitest/expect": "0.34.5", + "@vitest/runner": "0.34.5", + "@vitest/snapshot": "0.34.5", + "@vitest/spy": "0.34.5", + "@vitest/utils": "0.34.5", "acorn": "^8.9.0", "acorn-walk": "^8.2.0", "cac": "^6.7.14", @@ -11186,8 +11369,8 @@ "strip-literal": "^1.0.1", "tinybench": "^2.5.0", "tinypool": "^0.7.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.34.3", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.5", "why-is-node-running": "^2.2.2" }, "bin": { @@ -11237,9 +11420,9 @@ } }, "node_modules/vitest/node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.3", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz", + "integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -11775,9 +11958,9 @@ } }, "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index 224a1422ec8..fb0ee33998b 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,23 @@ { "type": "module", "engines": { - "node": ">= 16.0.0" + "node": ">= 18.0.0" }, "dependencies": { - "@citation-js/core": "0.6.8", - "@citation-js/plugin-bibtex": "0.6.8", - "@citation-js/plugin-csl": "0.6.8", + "@citation-js/core": "0.6.9", + "@citation-js/plugin-bibtex": "0.6.9", + "@citation-js/plugin-csl": "0.6.9", "@citation-js/plugin-software-formats": "0.6.1", "@claviska/jquery-minicolors": "2.3.6", - "@github/markdown-toolbar-element": "2.2.0", + "@github/markdown-toolbar-element": "2.2.1", "@github/relative-time-element": "4.3.0", "@github/text-expander-element": "2.5.0", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "19.6.0", + "@primer/octicons": "19.8.0", "@webcomponents/custom-elements": "1.6.0", "add-asset-webpack-plugin": "2.0.1", "ansi_up": "6.0.2", - "asciinema-player": "3.5.0", + "asciinema-player": "3.6.1", "clippie": "4.0.6", "css-loader": "6.8.1", "dropzone": "6.0.0-beta.2", @@ -32,12 +32,12 @@ "mermaid": "10.4.0", "mini-css-extract-plugin": "2.7.6", "minimatch": "9.0.3", - "monaco-editor": "0.41.0", + "monaco-editor": "0.43.0", "monaco-editor-webpack-plugin": "7.1.0", "pdfobject": "2.2.12", "pretty-ms": "8.0.0", "sortablejs": "1.15.0", - "swagger-ui-dist": "5.4.2", + "swagger-ui-dist": "5.7.2", "throttle-debounce": "5.0.0", "tinycolor2": "1.6.0", "tippy.js": "6.3.7", @@ -54,12 +54,11 @@ }, "devDependencies": { "@eslint-community/eslint-plugin-eslint-comments": "4.1.0", - "@playwright/test": "1.37.1", - "@stoplight/spectral-cli": "6.10.1", + "@playwright/test": "1.38.1", + "@stoplight/spectral-cli": "6.11.0", "@vitejs/plugin-vue": "4.3.4", - "eslint": "8.48.0", - "eslint-plugin-array-func": "3.1.8", - "eslint-plugin-custom-elements": "0.0.8", + "eslint": "8.49.0", + "eslint-plugin-array-func": "4.0.0", "eslint-plugin-import": "2.28.1", "eslint-plugin-jquery": "1.5.1", "eslint-plugin-no-jquery": "2.7.0", @@ -67,20 +66,21 @@ "eslint-plugin-regexp": "1.15.0", "eslint-plugin-sonarjs": "0.21.0", "eslint-plugin-unicorn": "48.0.1", + "eslint-plugin-vitest-globals": "1.4.0", "eslint-plugin-vue": "9.17.0", "eslint-plugin-vue-scoped-css": "2.5.0", - "eslint-plugin-wc": "1.5.0", + "eslint-plugin-wc": "2.0.3", "jsdom": "22.1.0", - "markdownlint-cli": "0.35.0", + "markdownlint-cli": "0.37.0", "postcss-html": "1.5.0", "stylelint": "15.10.3", "stylelint-declaration-block-no-ignored-properties": "2.7.0", "stylelint-declaration-strict-value": "1.9.2", "stylelint-stylistic": "0.4.3", "svgo": "3.0.2", - "updates": "14.4.0", + "updates": "15.0.2", "vite-string-plugin": "1.1.2", - "vitest": "0.34.3" + "vitest": "0.34.5" }, "browserslist": [ "defaults", diff --git a/poetry.lock b/poetry.lock index c8f6cd04ea0..2b15fa5ad6e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -42,13 +42,13 @@ six = ">=1.13.0" [[package]] name = "djlint" -version = "1.32.1" +version = "1.34.0" description = "HTML Template Linter and Formatter" optional = false python-versions = ">=3.8.0,<4.0.0" files = [ - {file = "djlint-1.32.1-py3-none-any.whl", hash = "sha256:8aaec6776376cfd41f3e742ed9f5e3c46dc7c6cd7646abf9e99860fb1ec9f19a"}, - {file = "djlint-1.32.1.tar.gz", hash = "sha256:c1e2141acf1547d244af7ef8abd15fbbae2abcc7a03e2bf31f8a491de69a6c72"}, + {file = "djlint-1.34.0-py3-none-any.whl", hash = "sha256:bdc26cc607dee8b46e262654eb0fbac7862c34d68172c8adc25a0b56fc7d8173"}, + {file = "djlint-1.34.0.tar.gz", hash = "sha256:60b4f4ca99fd83106603bdd466f35314fda33776f3a6e70ea9d674da9d0ad053"}, ] [package.dependencies] @@ -149,7 +149,6 @@ files = [ {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, @@ -157,15 +156,8 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, @@ -182,7 +174,6 @@ files = [ {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, @@ -190,7 +181,6 @@ files = [ {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, @@ -356,4 +346,4 @@ dev = ["doc8", "flake8", "flake8-import-order", "rstcheck[sphinx]", "sphinx"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "d2c60da5736ff899675088560244f086265a777e8057eed9e347367373e1937c" +content-hash = "a2e2a44801f0da2cc5cc1d1a3f707853f51a4346fef725f98c67a074dcb223d6" diff --git a/public/assets/img/svg/octicon-feed-issue-closed.svg b/public/assets/img/svg/octicon-feed-issue-closed.svg index 4fea50bac65..f31776e661f 100644 --- a/public/assets/img/svg/octicon-feed-issue-closed.svg +++ b/public/assets/img/svg/octicon-feed-issue-closed.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-issue-draft.svg b/public/assets/img/svg/octicon-feed-issue-draft.svg index 3720b5d9b3a..b50504935eb 100644 --- a/public/assets/img/svg/octicon-feed-issue-draft.svg +++ b/public/assets/img/svg/octicon-feed-issue-draft.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-issue-open.svg b/public/assets/img/svg/octicon-feed-issue-open.svg index 4e497682e56..6a6697a31ab 100644 --- a/public/assets/img/svg/octicon-feed-issue-open.svg +++ b/public/assets/img/svg/octicon-feed-issue-open.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-issue-reopen.svg b/public/assets/img/svg/octicon-feed-issue-reopen.svg new file mode 100644 index 00000000000..6cac76da581 --- /dev/null +++ b/public/assets/img/svg/octicon-feed-issue-reopen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-plus.svg b/public/assets/img/svg/octicon-feed-plus.svg index a453bf11e99..8606bdef203 100644 --- a/public/assets/img/svg/octicon-feed-plus.svg +++ b/public/assets/img/svg/octicon-feed-plus.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-public.svg b/public/assets/img/svg/octicon-feed-public.svg index 4decd913004..7c6c5b2529a 100644 --- a/public/assets/img/svg/octicon-feed-public.svg +++ b/public/assets/img/svg/octicon-feed-public.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-pull-request-closed.svg b/public/assets/img/svg/octicon-feed-pull-request-closed.svg index 824a4e06ab3..10f89d48552 100644 --- a/public/assets/img/svg/octicon-feed-pull-request-closed.svg +++ b/public/assets/img/svg/octicon-feed-pull-request-closed.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-pull-request-draft.svg b/public/assets/img/svg/octicon-feed-pull-request-draft.svg index 5091a4a0a9f..78596ff7888 100644 --- a/public/assets/img/svg/octicon-feed-pull-request-draft.svg +++ b/public/assets/img/svg/octicon-feed-pull-request-draft.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-feed-pull-request-open.svg b/public/assets/img/svg/octicon-feed-pull-request-open.svg index 276e02f925c..82dd8e0aea5 100644 --- a/public/assets/img/svg/octicon-feed-pull-request-open.svg +++ b/public/assets/img/svg/octicon-feed-pull-request-open.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/assets/img/svg/octicon-filter-remove.svg b/public/assets/img/svg/octicon-filter-remove.svg new file mode 100644 index 00000000000..e4394f4453e --- /dev/null +++ b/public/assets/img/svg/octicon-filter-remove.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 0c7e782a97e..b4f1a06a345 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ authors = [] python = "^3.8" [tool.poetry.group.dev.dependencies] -djlint = "1.32.1" +djlint = "1.34.0" yamllint = "1.32.0" [tool.djlint] diff --git a/routers/api/actions/runner/runner.go b/routers/api/actions/runner/runner.go index cb206f56851..8df6f297ceb 100644 --- a/routers/api/actions/runner/runner.go +++ b/routers/api/actions/runner/runner.go @@ -47,11 +47,11 @@ func (s *Service) Register( runnerToken, err := actions_model.GetRunnerToken(ctx, req.Msg.Token) if err != nil { - return nil, errors.New("runner token not found") + return nil, errors.New("runner registration token not found") } - if runnerToken.IsActive { - return nil, errors.New("runner token has already been activated") + if !runnerToken.IsActive { + return nil, errors.New("runner registration token has been invalidated, please use the latest one") } labels := req.Msg.Labels diff --git a/routers/api/packages/alpine/alpine.go b/routers/api/packages/alpine/alpine.go index 51a5c784e02..c261eee2d22 100644 --- a/routers/api/packages/alpine/alpine.go +++ b/routers/api/packages/alpine/alpine.go @@ -31,7 +31,7 @@ func apiError(ctx *context.Context, status int, obj any) { } func GetRepositoryKey(ctx *context.Context) { - _, pub, err := alpine_service.GetOrCreateKeyPair(ctx.Package.Owner.ID) + _, pub, err := alpine_service.GetOrCreateKeyPair(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -62,7 +62,7 @@ func GetRepositoryKey(ctx *context.Context) { } func GetRepositoryFile(ctx *context.Context) { - pv, err := alpine_service.GetOrCreateRepositoryVersion(ctx.Package.Owner.ID) + pv, err := alpine_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -134,6 +134,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -227,7 +228,7 @@ func DeletePackageFile(ctx *context.Context) { return } - if err := packages_service.RemovePackageFileAndVersionIfUnreferenced(ctx.Doer, pfs[0]); err != nil { + if err := packages_service.RemovePackageFileAndVersionIfUnreferenced(ctx, ctx.Doer, pfs[0]); err != nil { if errors.Is(err, util.ErrNotExist) { apiError(ctx, http.StatusNotFound, err) } else { diff --git a/routers/api/packages/cargo/cargo.go b/routers/api/packages/cargo/cargo.go index 8c370339cd5..225b6b5ade0 100644 --- a/routers/api/packages/cargo/cargo.go +++ b/routers/api/packages/cargo/cargo.go @@ -214,6 +214,7 @@ func UploadPackage(ctx *context.Context) { } pv, _, err := packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/chef/auth.go b/routers/api/packages/chef/auth.go index 53055bb6829..3aef8281a4e 100644 --- a/routers/api/packages/chef/auth.go +++ b/routers/api/packages/chef/auth.go @@ -4,6 +4,7 @@ package chef import ( + "context" "crypto" "crypto/rsa" "crypto/sha1" @@ -63,7 +64,7 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS return nil, nil } - pub, err := getUserPublicKey(u) + pub, err := getUserPublicKey(req.Context(), u) if err != nil { return nil, err } @@ -93,8 +94,8 @@ func getUserFromRequest(req *http.Request) (*user_model.User, error) { return user_model.GetUserByName(req.Context(), username) } -func getUserPublicKey(u *user_model.User) (crypto.PublicKey, error) { - pubKey, err := user_model.GetSetting(u.ID, chef_module.SettingPublicPem) +func getUserPublicKey(ctx context.Context, u *user_model.User) (crypto.PublicKey, error) { + pubKey, err := user_model.GetSetting(ctx, u.ID, chef_module.SettingPublicPem) if err != nil { return nil, err } diff --git a/routers/api/packages/chef/chef.go b/routers/api/packages/chef/chef.go index 908f9fc4be1..a1f5f49bd8a 100644 --- a/routers/api/packages/chef/chef.go +++ b/routers/api/packages/chef/chef.go @@ -286,6 +286,7 @@ func UploadPackage(ctx *context.Context) { } _, _, err = packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -356,6 +357,7 @@ func DeletePackageVersion(ctx *context.Context) { packageVersion := ctx.Params("version") err := packages_service.RemovePackageVersionByNameAndVersion( + ctx, ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -390,7 +392,7 @@ func DeletePackage(ctx *context.Context) { } for _, pv := range pvs { - if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 75bbfdf4d3b..313631d7d77 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -220,6 +220,7 @@ func UploadPackage(ctx *context.Context) { } _, _, err = packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/conan/conan.go b/routers/api/packages/conan/conan.go index 58e16424422..f440f83b243 100644 --- a/routers/api/packages/conan/conan.go +++ b/routers/api/packages/conan/conan.go @@ -326,13 +326,8 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey } defer buf.Close() - if buf.Size() == 0 { - // ignore empty uploads, second request contains content - jsonResponse(ctx, http.StatusOK, nil) - return - } - isConanfileFile := filename == conanfileFile + isConaninfoFile := filename == conaninfoFile pci := &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ @@ -364,7 +359,7 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey pfci.Properties[conan_module.PropertyPackageRevision] = pref.RevisionOrDefault() } - if isConanfileFile || filename == conaninfoFile { + if isConanfileFile || isConaninfoFile { if isConanfileFile { metadata, err := conan_module.ParseConanfile(buf) if err != nil { @@ -413,6 +408,7 @@ func uploadFile(ctx *context.Context, fileFilter container.Set[string], fileKey } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, pci, pfci, ) diff --git a/routers/api/packages/conda/conda.go b/routers/api/packages/conda/conda.go index 0bf0fc1f625..0bee7baa96f 100644 --- a/routers/api/packages/conda/conda.go +++ b/routers/api/packages/conda/conda.go @@ -229,6 +229,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 7bd5cadaaf6..62eec3064cd 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -653,7 +653,7 @@ func DeleteManifest(ctx *context.Context) { } for _, pv := range pvs { - if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/cran/cran.go b/routers/api/packages/cran/cran.go index 0ef6eff88d6..ae43df7c9aa 100644 --- a/routers/api/packages/cran/cran.go +++ b/routers/api/packages/cran/cran.go @@ -183,6 +183,7 @@ func uploadPackageFile(ctx *context.Context, compositeKey string, properties map } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/debian/debian.go b/routers/api/packages/debian/debian.go index 04ca2ed977c..dc7ebab0968 100644 --- a/routers/api/packages/debian/debian.go +++ b/routers/api/packages/debian/debian.go @@ -30,7 +30,7 @@ func apiError(ctx *context.Context, status int, obj any) { } func GetRepositoryKey(ctx *context.Context) { - _, pub, err := debian_service.GetOrCreateKeyPair(ctx.Package.Owner.ID) + _, pub, err := debian_service.GetOrCreateKeyPair(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -45,7 +45,7 @@ func GetRepositoryKey(ctx *context.Context) { // https://wiki.debian.org/DebianRepository/Format#A.22Release.22_files // https://wiki.debian.org/DebianRepository/Format#A.22Packages.22_Indices func GetRepositoryFile(ctx *context.Context) { - pv, err := debian_service.GetOrCreateRepositoryVersion(ctx.Package.Owner.ID) + pv, err := debian_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -81,7 +81,7 @@ func GetRepositoryFile(ctx *context.Context) { // https://wiki.debian.org/DebianRepository/Format#indices_acquisition_via_hashsums_.28by-hash.29 func GetRepositoryFileByHash(ctx *context.Context) { - pv, err := debian_service.GetOrCreateRepositoryVersion(ctx.Package.Owner.ID) + pv, err := debian_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -159,6 +159,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/generic/generic.go b/routers/api/packages/generic/generic.go index c5866ef9c35..30854335c09 100644 --- a/routers/api/packages/generic/generic.go +++ b/routers/api/packages/generic/generic.go @@ -89,6 +89,7 @@ func UploadPackage(ctx *context.Context) { defer buf.Close() _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -125,6 +126,7 @@ func UploadPackage(ctx *context.Context) { // DeletePackage deletes the specific generic package. func DeletePackage(ctx *context.Context) { err := packages_service.RemovePackageVersionByNameAndVersion( + ctx, ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -176,7 +178,7 @@ func DeletePackageFile(ctx *context.Context) { } if len(pfs) == 1 { - if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/goproxy/goproxy.go b/routers/api/packages/goproxy/goproxy.go index bacdc4ec62f..18e0074ab4d 100644 --- a/routers/api/packages/goproxy/goproxy.go +++ b/routers/api/packages/goproxy/goproxy.go @@ -185,6 +185,7 @@ func UploadPackage(ctx *context.Context) { } _, _, err = packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/helm/helm.go b/routers/api/packages/helm/helm.go index 9097adf29e7..a8daa69dc3a 100644 --- a/routers/api/packages/helm/helm.go +++ b/routers/api/packages/helm/helm.go @@ -174,6 +174,7 @@ func UploadPackage(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index 6328e226ab6..52e31e80338 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -356,6 +356,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, pvci, pfci, ) diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index d1e271f23ff..dd6b3f148b5 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -190,6 +190,7 @@ func UploadPackage(ctx *context.Context) { defer buf.Close() pv, _, err := packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -255,6 +256,7 @@ func DeletePackageVersion(ctx *context.Context) { packageVersion := ctx.Params("version") err := packages_service.RemovePackageVersionByNameAndVersion( + ctx, ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -291,7 +293,7 @@ func DeletePackage(ctx *context.Context) { } for _, pv := range pvs { - if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil { apiError(ctx, http.StatusInternalServerError, err) return } diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go index 60b81b8d4b3..1bb68d059b2 100644 --- a/routers/api/packages/nuget/auth.go +++ b/routers/api/packages/nuget/auth.go @@ -23,7 +23,7 @@ func (a *Auth) Name() string { // 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, error) { - token, err := auth_model.GetAccessTokenBySHA(req.Header.Get("X-NuGet-ApiKey")) + token, err := auth_model.GetAccessTokenBySHA(req.Context(), req.Header.Get("X-NuGet-ApiKey")) if err != nil { if !(auth_model.IsErrAccessTokenNotExist(err) || auth_model.IsErrAccessTokenEmpty(err)) { log.Error("GetAccessTokenBySHA: %v", err) @@ -39,7 +39,7 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS } token.UpdatedUnix = timeutil.TimeStampNow() - if err := auth_model.UpdateAccessToken(token); err != nil { + if err := auth_model.UpdateAccessToken(req.Context(), token); err != nil { log.Error("UpdateAccessToken: %v", err) } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index 6f63c1d4c21..769c4c18245 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -431,6 +431,7 @@ func UploadPackage(ctx *context.Context) { } _, _, err := packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -503,6 +504,7 @@ func UploadSymbolPackage(ctx *context.Context) { } _, err = packages_service.AddFileToExistingPackage( + ctx, pi, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ @@ -529,6 +531,7 @@ func UploadSymbolPackage(ctx *context.Context) { for _, pdb := range pdbs { _, err := packages_service.AddFileToExistingPackage( + ctx, pi, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ @@ -647,6 +650,7 @@ func DeletePackage(ctx *context.Context) { packageVersion := ctx.Params("version") err := packages_service.RemovePackageVersionByNameAndVersion( + ctx, ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/pub/pub.go b/routers/api/packages/pub/pub.go index ef07836b886..8460f861cb7 100644 --- a/routers/api/packages/pub/pub.go +++ b/routers/api/packages/pub/pub.go @@ -189,6 +189,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index d97b894bbed..8c7f9bbf38b 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -145,6 +145,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/rpm/rpm.go b/routers/api/packages/rpm/rpm.go index 1e462bb9080..f5d8b67e16d 100644 --- a/routers/api/packages/rpm/rpm.go +++ b/routers/api/packages/rpm/rpm.go @@ -45,7 +45,7 @@ gpgkey=`+url+`/repository.key`) // Gets or creates the PGP public key used to sign repository metadata files func GetRepositoryKey(ctx *context.Context) { - _, pub, err := rpm_service.GetOrCreateKeyPair(ctx.Package.Owner.ID) + _, pub, err := rpm_service.GetOrCreateKeyPair(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -59,7 +59,7 @@ func GetRepositoryKey(ctx *context.Context) { // Gets a pre-generated repository metadata file func GetRepositoryFile(ctx *context.Context) { - pv, err := rpm_service.GetOrCreateRepositoryVersion(ctx.Package.Owner.ID) + pv, err := rpm_service.GetOrCreateRepositoryVersion(ctx, ctx.Package.Owner.ID) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -123,6 +123,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index 88d70f10bdc..061fb0871b1 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -234,6 +234,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, @@ -280,6 +281,7 @@ func DeletePackage(ctx *context.Context) { packageVersion := ctx.FormString("version") err := packages_service.RemovePackageVersionByNameAndVersion( + ctx, ctx.Doer, &packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/swift/swift.go b/routers/api/packages/swift/swift.go index bd4b8095c2c..427e262d063 100644 --- a/routers/api/packages/swift/swift.go +++ b/routers/api/packages/swift/swift.go @@ -329,6 +329,7 @@ func UploadPackageFile(ctx *context.Context) { } pv, _, err := packages_service.CreatePackageAndAddFile( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/packages/vagrant/vagrant.go b/routers/api/packages/vagrant/vagrant.go index 9fe7ab56f66..af9cd08a629 100644 --- a/routers/api/packages/vagrant/vagrant.go +++ b/routers/api/packages/vagrant/vagrant.go @@ -177,6 +177,7 @@ func UploadPackageFile(ctx *context.Context) { } _, _, err = packages_service.CreatePackageOrAddFileToExisting( + ctx, &packages_service.PackageCreationInfo{ PackageInfo: packages_service.PackageInfo{ Owner: ctx.Package.Owner, diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index bc6b82b1799..cad5032d103 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -66,7 +66,7 @@ func Person(ctx *context.APIContext) { person.PublicKey.ID = ap.IRI(link + "#main-key") person.PublicKey.Owner = ap.IRI(link) - publicKeyPem, err := activitypub.GetPublicKey(ctx.ContextUser) + publicKeyPem, err := activitypub.GetPublicKey(ctx, ctx.ContextUser) if err != nil { ctx.ServerError("GetPublicKey", err) return diff --git a/routers/api/v1/admin/email.go b/routers/api/v1/admin/email.go index 8d0491e0702..5914215bc2a 100644 --- a/routers/api/v1/admin/email.go +++ b/routers/api/v1/admin/email.go @@ -37,7 +37,7 @@ func GetAllEmails(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - emails, maxResults, err := user_model.SearchEmails(&user_model.SearchEmailOptions{ + emails, maxResults, err := user_model.SearchEmails(ctx, &user_model.SearchEmailOptions{ Keyword: ctx.Params(":email"), ListOptions: listOptions, }) diff --git a/routers/api/v1/admin/org.go b/routers/api/v1/admin/org.go index 6d50a12674a..bf68942a9ca 100644 --- a/routers/api/v1/admin/org.go +++ b/routers/api/v1/admin/org.go @@ -62,7 +62,7 @@ func CreateOrg(ctx *context.APIContext) { Visibility: visibility, } - if err := organization.CreateOrganization(org, ctx.ContextUser); err != nil { + if err := organization.CreateOrganization(ctx, org, ctx.ContextUser); err != nil { if user_model.IsErrUserAlreadyExist(err) || db.IsErrNameReserved(err) || db.IsErrNameCharsNotAllowed(err) || @@ -101,7 +101,7 @@ func GetAllOrgs(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - users, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Type: user_model.UserTypeOrganization, OrderBy: db.SearchOrderByAlphabetically, diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 4f1e9a3f537..610eba17499 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -128,7 +128,7 @@ func CreateUser(ctx *context.APIContext) { u.UpdatedUnix = u.CreatedUnix } - if err := user_model.CreateUser(u, overwriteDefault); err != nil { + if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil { if user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err) || db.IsErrNameReserved(err) || @@ -402,7 +402,7 @@ func DeleteUserPublicKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := asymkey_service.DeletePublicKey(ctx.ContextUser, ctx.ParamsInt64(":id")); err != nil { + if err := asymkey_service.DeletePublicKey(ctx, ctx.ContextUser, ctx.ParamsInt64(":id")); err != nil { if asymkey_model.IsErrKeyNotExist(err) { ctx.NotFound() } else if asymkey_model.IsErrKeyAccessDenied(err) { @@ -450,7 +450,7 @@ func SearchUsers(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - users, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Type: user_model.UserTypeIndividual, LoginName: ctx.FormTrim("login_name"), diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index fd7d3687acb..441801885f6 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -148,7 +148,7 @@ func repoAssignment() func(ctx *context.APIContext) { owner, err = user_model.GetUserByName(ctx, userName) if err != nil { if user_model.IsErrUserNotExist(err) { - if redirectUserID, err := user_model.LookupUserRedirect(userName); err == nil { + if redirectUserID, err := user_model.LookupUserRedirect(ctx, userName); err == nil { context.RedirectToUser(ctx.Base, userName, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { ctx.NotFound("GetUserByName", err) @@ -367,6 +367,16 @@ func reqOwner() func(ctx *context.APIContext) { } } +// reqSelfOrAdmin doer should be the same as the contextUser or site admin +func reqSelfOrAdmin() func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + if !ctx.IsUserSiteAdmin() && ctx.ContextUser != ctx.Doer { + ctx.Error(http.StatusForbidden, "reqSelfOrAdmin", "doer should be the site admin or be same as the contextUser") + return + } + } +} + // reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin func reqAdmin() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { @@ -554,7 +564,7 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) { ctx.Org.Organization, err = organization.GetOrgByName(ctx, ctx.Params(":org")) if err != nil { if organization.IsErrOrgNotExist(err) { - redirectUserID, err := user_model.LookupUserRedirect(ctx.Params(":org")) + redirectUserID, err := user_model.LookupUserRedirect(ctx, ctx.Params(":org")) if err == nil { context.RedirectToUser(ctx.Base, ctx.Params(":org"), redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { @@ -665,7 +675,7 @@ func mustEnableWiki(ctx *context.APIContext) { func mustNotBeArchived(ctx *context.APIContext) { if ctx.Repo.Repository.IsArchived { - ctx.NotFound() + ctx.Error(http.StatusLocked, "RepoArchived", fmt.Errorf("%s is archived", ctx.Repo.Repository.LogString())) return } } @@ -705,7 +715,10 @@ func buildAuthGroup() *auth.Group { if setting.Service.EnableReverseProxyAuthAPI { group.Add(&auth.ReverseProxy{}) } - specialAdd(group) + + if setting.IsWindows && auth_model.IsSSPIEnabled() { + group.Add(&auth.SSPI{}) // it MUST be the last, see the comment of SSPI + } return group } @@ -776,7 +789,7 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC if skip, ok := ctx.Data["SkipLocalTwoFA"]; ok && skip.(bool) { return // Skip 2FA } - twofa, err := auth_model.GetTwoFactorByUID(ctx.Doer.ID) + twofa, err := auth_model.GetTwoFactorByUID(ctx, ctx.Doer.ID) if err != nil { if auth_model.IsErrTwoFactorNotEnrolled(err) { return // No 2FA enrollment for this user @@ -907,7 +920,7 @@ func Routes() *web.Route { m.Combo("").Get(user.ListAccessTokens). Post(bind(api.CreateAccessTokenOption{}), reqToken(), user.CreateAccessToken) m.Combo("/{id}").Delete(reqToken(), user.DeleteAccessToken) - }, reqBasicOrRevProxyAuth()) + }, reqSelfOrAdmin(), reqBasicOrRevProxyAuth()) m.Get("/activities/feeds", user.ListUserActivityFeeds) }, context_service.UserAssignmentAPI()) @@ -1095,23 +1108,23 @@ func Routes() *web.Route { m.Group("/branches", func() { m.Get("", repo.ListBranches) m.Get("/*", repo.GetBranch) - m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), repo.DeleteBranch) - m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateBranchRepoOption{}), repo.CreateBranch) + m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteBranch) + m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateBranchRepoOption{}), repo.CreateBranch) }, context.ReferencesGitRepo(), reqRepoReader(unit.TypeCode)) m.Group("/branch_protections", func() { m.Get("", repo.ListBranchProtections) - m.Post("", bind(api.CreateBranchProtectionOption{}), repo.CreateBranchProtection) + m.Post("", bind(api.CreateBranchProtectionOption{}), mustNotBeArchived, repo.CreateBranchProtection) m.Group("/{name}", func() { m.Get("", repo.GetBranchProtection) - m.Patch("", bind(api.EditBranchProtectionOption{}), repo.EditBranchProtection) + m.Patch("", bind(api.EditBranchProtectionOption{}), mustNotBeArchived, repo.EditBranchProtection) m.Delete("", repo.DeleteBranchProtection) }) }, reqToken(), reqAdmin()) m.Group("/tags", func() { m.Get("", repo.ListTags) m.Get("/*", repo.GetTag) - m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), bind(api.CreateTagOption{}), repo.CreateTag) - m.Delete("/*", reqToken(), repo.DeleteTag) + m.Post("", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, bind(api.CreateTagOption{}), repo.CreateTag) + m.Delete("/*", reqToken(), reqRepoWriter(unit.TypeCode), mustNotBeArchived, repo.DeleteTag) }, reqRepoReader(unit.TypeCode), context.ReferencesGitRepo(true)) m.Group("/keys", func() { m.Combo("").Get(repo.ListDeployKeys). @@ -1232,15 +1245,15 @@ func Routes() *web.Route { m.Get("/tags/{sha}", repo.GetAnnotatedTag) m.Get("/notes/{sha}", repo.GetNote) }, context.ReferencesGitRepo(true), reqRepoReader(unit.TypeCode)) - m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), repo.ApplyDiffPatch) + m.Post("/diffpatch", reqRepoWriter(unit.TypeCode), reqToken(), bind(api.ApplyDiffPatchFileOptions{}), mustNotBeArchived, repo.ApplyDiffPatch) m.Group("/contents", func() { m.Get("", repo.GetContentsList) - m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, repo.ChangeFiles) + m.Post("", reqToken(), bind(api.ChangeFilesOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.ChangeFiles) m.Get("/*", repo.GetContents) m.Group("/*", func() { - m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, repo.CreateFile) - m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, repo.UpdateFile) - m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, repo.DeleteFile) + m.Post("", bind(api.CreateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.CreateFile) + m.Put("", bind(api.UpdateFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.UpdateFile) + m.Delete("", bind(api.DeleteFileOptions{}), reqRepoBranchWriter, mustNotBeArchived, repo.DeleteFile) }, reqToken()) }, reqRepoReader(unit.TypeCode)) m.Get("/signing-key.gpg", misc.SigningKey) diff --git a/routers/api/v1/auth.go b/routers/api/v1/auth.go deleted file mode 100644 index e44271ba148..00000000000 --- a/routers/api/v1/auth.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build !windows - -package v1 - -import auth_service "code.gitea.io/gitea/services/auth" - -func specialAdd(group *auth_service.Group) {} diff --git a/routers/api/v1/auth_windows.go b/routers/api/v1/auth_windows.go deleted file mode 100644 index 3514e21baac..00000000000 --- a/routers/api/v1/auth_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package v1 - -import ( - "code.gitea.io/gitea/models/auth" - auth_service "code.gitea.io/gitea/services/auth" -) - -// specialAdd registers the SSPI auth method as the last method in the list. -// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation -// fails (or if negotiation should continue), which would prevent other authentication methods -// to execute at all. -func specialAdd(group *auth_service.Group) { - if auth.IsSSPIEnabled() { - group.Add(&auth_service.SSPI{}) - } -} diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go index 319c3483e10..f0d8d80dd4e 100644 --- a/routers/api/v1/misc/nodeinfo.go +++ b/routers/api/v1/misc/nodeinfo.go @@ -34,15 +34,15 @@ func NodeInfo(ctx *context.APIContext) { nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage) } if !cached { - usersTotal := int(user_model.CountUsers(nil)) + usersTotal := int(user_model.CountUsers(ctx, nil)) now := time.Now() timeOneMonthAgo := now.AddDate(0, -1, 0).Unix() timeHaveYearAgo := now.AddDate(0, -6, 0).Unix() - usersActiveMonth := int(user_model.CountUsers(&user_model.CountUserFilter{LastLoginSince: &timeOneMonthAgo})) - usersActiveHalfyear := int(user_model.CountUsers(&user_model.CountUserFilter{LastLoginSince: &timeHaveYearAgo})) + usersActiveMonth := int(user_model.CountUsers(ctx, &user_model.CountUserFilter{LastLoginSince: &timeOneMonthAgo})) + usersActiveHalfyear := int(user_model.CountUsers(ctx, &user_model.CountUserFilter{LastLoginSince: &timeHaveYearAgo})) allIssues, _ := issues_model.CountIssues(ctx, &issues_model.IssuesOptions{}) - allComments, _ := issues_model.CountComments(&issues_model.FindCommentsOptions{}) + allComments, _ := issues_model.CountComments(ctx, &issues_model.FindCommentsOptions{}) nodeInfoUsage = structs.NodeInfoUsage{ Users: structs.NodeInfoUsageUsers{ diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index e16c54a2c0b..0e4efcc640f 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -127,7 +127,7 @@ func ListRepoNotifications(ctx *context.APIContext) { ctx.SetTotalCountHeader(totalCount) - ctx.JSON(http.StatusOK, convert.ToNotifications(nl)) + ctx.JSON(http.StatusOK, convert.ToNotifications(ctx, nl)) } // ReadRepoNotifications mark notification threads as read on a specific repo @@ -222,7 +222,7 @@ func ReadRepoNotifications(ctx *context.APIContext) { return } _ = notif.LoadAttributes(ctx) - changed = append(changed, convert.ToNotificationThread(notif)) + changed = append(changed, convert.ToNotificationThread(ctx, notif)) } ctx.JSON(http.StatusResetContent, changed) } diff --git a/routers/api/v1/notify/threads.go b/routers/api/v1/notify/threads.go index 6a1bce4de41..919e52952dc 100644 --- a/routers/api/v1/notify/threads.go +++ b/routers/api/v1/notify/threads.go @@ -46,7 +46,7 @@ func GetThread(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToNotificationThread(n)) + ctx.JSON(http.StatusOK, convert.ToNotificationThread(ctx, n)) } // ReadThread mark notification as read by ID @@ -97,7 +97,7 @@ func ReadThread(ctx *context.APIContext) { ctx.InternalServerError(err) return } - ctx.JSON(http.StatusResetContent, convert.ToNotificationThread(notif)) + ctx.JSON(http.StatusResetContent, convert.ToNotificationThread(ctx, notif)) } func getThread(ctx *context.APIContext) *activities_model.Notification { diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index a9c6b436179..267b7d8ea8c 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -86,7 +86,7 @@ func ListNotifications(ctx *context.APIContext) { } ctx.SetTotalCountHeader(totalCount) - ctx.JSON(http.StatusOK, convert.ToNotifications(nl)) + ctx.JSON(http.StatusOK, convert.ToNotifications(ctx, nl)) } // ReadNotifications mark notification threads as read, unread, or pinned @@ -167,7 +167,7 @@ func ReadNotifications(ctx *context.APIContext) { return } _ = notif.LoadAttributes(ctx) - changed = append(changed, convert.ToNotificationThread(notif)) + changed = append(changed, convert.ToNotificationThread(ctx, notif)) } ctx.JSON(http.StatusResetContent, changed) diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go index 2dd4505a91d..5a03059deda 100644 --- a/routers/api/v1/org/label.go +++ b/routers/api/v1/org/label.go @@ -50,7 +50,7 @@ func ListLabels(ctx *context.APIContext) { return } - count, err := issues_model.CountLabelsByOrgID(ctx.Org.Organization.ID) + count, err := issues_model.CountLabelsByOrgID(ctx, ctx.Org.Organization.ID) if err != nil { ctx.InternalServerError(err) return @@ -218,7 +218,7 @@ func EditLabel(ctx *context.APIContext) { l.Description = *form.Description } l.SetArchived(form.IsArchived != nil && *form.IsArchived) - if err := issues_model.UpdateLabel(l); err != nil { + if err := issues_model.UpdateLabel(ctx, l); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateLabel", err) return } @@ -249,7 +249,7 @@ func DeleteLabel(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := issues_model.DeleteLabel(ctx.Org.Organization.ID, ctx.ParamsInt64(":id")); err != nil { + if err := issues_model.DeleteLabel(ctx, ctx.Org.Organization.ID, ctx.ParamsInt64(":id")); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteLabel", err) return } diff --git a/routers/api/v1/org/member.go b/routers/api/v1/org/member.go index e5ea584d5d7..139e01e1f98 100644 --- a/routers/api/v1/org/member.go +++ b/routers/api/v1/org/member.go @@ -25,13 +25,13 @@ func listMembers(ctx *context.APIContext, publicOnly bool) { ListOptions: utils.GetListOptions(ctx), } - count, err := organization.CountOrgMembers(opts) + count, err := organization.CountOrgMembers(ctx, opts) if err != nil { ctx.InternalServerError(err) return } - members, _, err := organization.FindOrgMembers(opts) + members, _, err := organization.FindOrgMembers(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -75,7 +75,7 @@ func ListMembers(ctx *context.APIContext) { publicOnly := true if ctx.Doer != nil { - isMember, err := ctx.Org.Organization.IsOrgMember(ctx.Doer.ID) + isMember, err := ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) return @@ -144,12 +144,12 @@ func IsMember(ctx *context.APIContext) { return } if ctx.Doer != nil { - userIsMember, err := ctx.Org.Organization.IsOrgMember(ctx.Doer.ID) + userIsMember, err := ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) return } else if userIsMember || ctx.Doer.IsAdmin { - userToCheckIsMember, err := ctx.Org.Organization.IsOrgMember(userToCheck.ID) + userToCheckIsMember, err := ctx.Org.Organization.IsOrgMember(ctx, userToCheck.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) } else if userToCheckIsMember { @@ -194,7 +194,7 @@ func IsPublicMember(ctx *context.APIContext) { if ctx.Written() { return } - is, err := organization.IsPublicMembership(ctx.Org.Organization.ID, userToCheck.ID) + is, err := organization.IsPublicMembership(ctx, ctx.Org.Organization.ID, userToCheck.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsPublicMembership", err) return @@ -240,7 +240,7 @@ func PublicizeMember(ctx *context.APIContext) { ctx.Error(http.StatusForbidden, "", "Cannot publicize another member") return } - err := organization.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToPublicize.ID, true) + err := organization.ChangeOrgUserStatus(ctx, ctx.Org.Organization.ID, userToPublicize.ID, true) if err != nil { ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err) return @@ -282,7 +282,7 @@ func ConcealMember(ctx *context.APIContext) { ctx.Error(http.StatusForbidden, "", "Cannot conceal another member") return } - err := organization.ChangeOrgUserStatus(ctx.Org.Organization.ID, userToConceal.ID, false) + err := organization.ChangeOrgUserStatus(ctx, ctx.Org.Organization.ID, userToConceal.ID, false) if err != nil { ctx.Error(http.StatusInternalServerError, "ChangeOrgUserStatus", err) return diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index 0216b623520..2594e4afbb3 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -30,12 +30,12 @@ func listUserOrgs(ctx *context.APIContext, u *user_model.User) { UserID: u.ID, IncludePrivate: showPrivate, } - orgs, err := organization.FindOrgs(opts) + orgs, err := organization.FindOrgs(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "FindOrgs", err) return } - maxResults, err := organization.CountOrgs(opts) + maxResults, err := organization.CountOrgs(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "CountOrgs", err) return @@ -145,7 +145,7 @@ func GetUserOrgsPermissions(ctx *context.APIContext) { } org := organization.OrgFromUser(o) - authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx.ContextUser.ID) + authorizeLevel, err := org.GetOrgUserMaxAuthorizeLevel(ctx, ctx.ContextUser.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetOrgUserAuthorizeLevel", err) return @@ -164,7 +164,7 @@ func GetUserOrgsPermissions(ctx *context.APIContext) { op.IsOwner = true } - op.CanCreateRepository, err = org.CanCreateOrgRepo(ctx.ContextUser.ID) + op.CanCreateRepository, err = org.CanCreateOrgRepo(ctx, ctx.ContextUser.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err) return @@ -203,7 +203,7 @@ func GetAll(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - publicOrgs, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + publicOrgs, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, ListOptions: listOptions, Type: user_model.UserTypeOrganization, @@ -268,7 +268,7 @@ func Create(ctx *context.APIContext) { Visibility: visibility, RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess, } - if err := organization.CreateOrganization(org, ctx.Doer); err != nil { + if err := organization.CreateOrganization(ctx, org, ctx.Doer); err != nil { if user_model.IsErrUserAlreadyExist(err) || db.IsErrNameReserved(err) || db.IsErrNameCharsNotAllowed(err) || @@ -429,7 +429,7 @@ func ListOrgActivityFeeds(ctx *context.APIContext) { includePrivate = true } else { org := organization.OrgFromUser(ctx.ContextUser) - isMember, err := org.IsOrgMember(ctx.Doer.ID) + isMember, err := org.IsOrgMember(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) return diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index abb5381a70d..9b68253623f 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -53,7 +53,7 @@ func ListTeams(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - teams, count, err := organization.SearchTeam(&organization.SearchTeamOptions{ + teams, count, err := organization.SearchTeam(ctx, &organization.SearchTeamOptions{ ListOptions: utils.GetListOptions(ctx), OrgID: ctx.Org.Organization.ID, }) @@ -92,7 +92,7 @@ func ListUserTeams(ctx *context.APIContext) { // "200": // "$ref": "#/responses/TeamList" - teams, count, err := organization.SearchTeam(&organization.SearchTeamOptions{ + teams, count, err := organization.SearchTeam(ctx, &organization.SearchTeamOptions{ ListOptions: utils.GetListOptions(ctx), UserID: ctx.Doer.ID, }) @@ -239,7 +239,7 @@ func CreateTeam(ctx *context.APIContext) { attachAdminTeamUnits(team) } - if err := models.NewTeam(team); err != nil { + if err := models.NewTeam(ctx, team); err != nil { if organization.IsErrTeamAlreadyExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) } else { @@ -248,7 +248,7 @@ func CreateTeam(ctx *context.APIContext) { return } - apiTeam, err := convert.ToTeam(ctx, team) + apiTeam, err := convert.ToTeam(ctx, team, true) if err != nil { ctx.InternalServerError(err) return @@ -330,7 +330,7 @@ func EditTeam(ctx *context.APIContext) { attachAdminTeamUnits(team) } - if err := models.UpdateTeam(team, isAuthChanged, isIncludeAllChanged); err != nil { + if err := models.UpdateTeam(ctx, team, isAuthChanged, isIncludeAllChanged); err != nil { ctx.Error(http.StatusInternalServerError, "EditTeam", err) return } @@ -361,7 +361,7 @@ func DeleteTeam(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := models.DeleteTeam(ctx.Org.Team); err != nil { + if err := models.DeleteTeam(ctx, ctx.Org.Team); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteTeam", err) return } @@ -493,7 +493,7 @@ func AddTeamMember(ctx *context.APIContext) { if ctx.Written() { return } - if err := models.AddTeamMember(ctx.Org.Team, u.ID); err != nil { + if err := models.AddTeamMember(ctx, ctx.Org.Team, u.ID); err != nil { ctx.Error(http.StatusInternalServerError, "AddMember", err) return } @@ -530,7 +530,7 @@ func RemoveTeamMember(ctx *context.APIContext) { return } - if err := models.RemoveTeamMember(ctx.Org.Team, u.ID); err != nil { + if err := models.RemoveTeamMember(ctx, ctx.Org.Team, u.ID); err != nil { ctx.Error(http.StatusInternalServerError, "RemoveTeamMember", err) return } @@ -693,7 +693,7 @@ func AddTeamRepository(ctx *context.APIContext) { ctx.Error(http.StatusForbidden, "", "Must have admin-level access to the repository") return } - if err := org_service.TeamAddRepository(ctx.Org.Team, repo); err != nil { + if err := org_service.TeamAddRepository(ctx, ctx.Org.Team, repo); err != nil { ctx.Error(http.StatusInternalServerError, "TeamAddRepository", err) return } @@ -810,7 +810,7 @@ func SearchTeam(ctx *context.APIContext) { opts.UserID = ctx.Doer.ID } - teams, maxResults, err := organization.SearchTeam(opts) + teams, maxResults, err := organization.SearchTeam(ctx, opts) if err != nil { log.Error("SearchTeam failed: %v", err) ctx.JSON(http.StatusInternalServerError, map[string]any{ diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index 53724179a2c..a79ba315be2 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -164,7 +164,7 @@ func DeletePackage(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - err := packages_service.RemovePackageVersion(ctx.Doer, ctx.Package.Descriptor.Version) + err := packages_service.RemovePackageVersion(ctx, ctx.Doer, ctx.Package.Descriptor.Version) if err != nil { ctx.Error(http.StatusInternalServerError, "RemovePackageVersion", err) return diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index cdc176b8e45..f2386a607e6 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -117,17 +117,13 @@ func DeleteBranch(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/notFound" - + // "423": + // "$ref": "#/responses/repoArchivedError" if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") return } - if ctx.Repo.Repository.IsArchived { - ctx.Error(http.StatusForbidden, "", "Git Repository is archived.") - return - } - if ctx.Repo.Repository.IsMirror { ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.") return @@ -157,10 +153,6 @@ func DeleteBranch(ctx *context.APIContext) { } } - if ctx.Repo.Repository.IsArchived { - ctx.Error(http.StatusForbidden, "IsArchived", fmt.Errorf("can not delete branch of an archived repository")) - return - } if ctx.Repo.Repository.IsMirror { ctx.Error(http.StatusForbidden, "IsMirrored", fmt.Errorf("can not delete branch of an mirror repository")) return @@ -216,17 +208,14 @@ func CreateBranch(ctx *context.APIContext) { // description: The old branch does not exist. // "409": // description: The branch with the same name already exists. + // "423": + // "$ref": "#/responses/repoArchivedError" if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusNotFound, "", "Git Repository is empty.") return } - if ctx.Repo.Repository.IsArchived { - ctx.Error(http.StatusForbidden, "", "Git Repository is archived.") - return - } - if ctx.Repo.Repository.IsMirror { ctx.Error(http.StatusForbidden, "", "Git Repository is a mirror.") return @@ -447,7 +436,7 @@ func GetBranchProtection(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToBranchProtection(bp)) + ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp)) } // ListBranchProtections list branch protections for a repo @@ -480,7 +469,7 @@ func ListBranchProtections(ctx *context.APIContext) { } apiBps := make([]*api.BranchProtection, len(bps)) for i := range bps { - apiBps[i] = convert.ToBranchProtection(bps[i]) + apiBps[i] = convert.ToBranchProtection(ctx, bps[i]) } ctx.JSON(http.StatusOK, apiBps) @@ -519,6 +508,8 @@ func CreateBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateBranchProtectionOption) repo := ctx.Repo.Repository @@ -581,7 +572,7 @@ func CreateBranchProtection(ctx *context.APIContext) { } var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64 if repo.Owner.IsOrganization() { - whitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false) + whitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.PushWhitelistTeams, false) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) @@ -590,7 +581,7 @@ func CreateBranchProtection(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err) return } - mergeWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false) + mergeWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.MergeWhitelistTeams, false) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) @@ -599,7 +590,7 @@ func CreateBranchProtection(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetTeamIDsByNames", err) return } - approvalsWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false) + approvalsWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.ApprovalsWhitelistTeams, false) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) @@ -688,7 +679,7 @@ func CreateBranchProtection(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToBranchProtection(bp)) + ctx.JSON(http.StatusCreated, convert.ToBranchProtection(ctx, bp)) } // EditBranchProtection edits a branch protection for a repo @@ -727,6 +718,8 @@ func EditBranchProtection(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.EditBranchProtectionOption) repo := ctx.Repo.Repository bpName := ctx.Params(":name") @@ -855,7 +848,7 @@ func EditBranchProtection(ctx *context.APIContext) { var whitelistTeams, mergeWhitelistTeams, approvalsWhitelistTeams []int64 if repo.Owner.IsOrganization() { if form.PushWhitelistTeams != nil { - whitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.PushWhitelistTeams, false) + whitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.PushWhitelistTeams, false) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) @@ -868,7 +861,7 @@ func EditBranchProtection(ctx *context.APIContext) { whitelistTeams = protectBranch.WhitelistTeamIDs } if form.MergeWhitelistTeams != nil { - mergeWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.MergeWhitelistTeams, false) + mergeWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.MergeWhitelistTeams, false) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) @@ -881,7 +874,7 @@ func EditBranchProtection(ctx *context.APIContext) { mergeWhitelistTeams = protectBranch.MergeWhitelistTeamIDs } if form.ApprovalsWhitelistTeams != nil { - approvalsWhitelistTeams, err = organization.GetTeamIDsByNames(repo.OwnerID, form.ApprovalsWhitelistTeams, false) + approvalsWhitelistTeams, err = organization.GetTeamIDsByNames(ctx, repo.OwnerID, form.ApprovalsWhitelistTeams, false) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "Team does not exist", err) @@ -960,7 +953,7 @@ func EditBranchProtection(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToBranchProtection(bp)) + ctx.JSON(http.StatusOK, convert.ToBranchProtection(ctx, bp)) } // DeleteBranchProtection deletes a branch protection for a repo @@ -1004,7 +997,7 @@ func DeleteBranchProtection(ctx *context.APIContext) { return } - if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository.ID, bp.ID); err != nil { + if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, bp.ID); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteProtectedBranch", err) return } diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 4be43d46adf..2538bcdbc62 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -53,7 +53,7 @@ func ListCollaborators(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - count, err := repo_model.CountCollaborators(ctx.Repo.Repository.ID) + count, err := repo_model.CountCollaborators(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.InternalServerError(err) return @@ -234,7 +234,7 @@ func DeleteCollaborator(ctx *context.APIContext) { return } - if err := repo_service.DeleteCollaboration(ctx.Repo.Repository, collaborator.ID); err != nil { + if err := repo_service.DeleteCollaboration(ctx, ctx.Repo.Repository, collaborator.ID); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteCollaboration", err) return } diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index ea311c32029..94e634461c2 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -450,6 +450,8 @@ func ChangeFiles(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.ChangeFilesOptions) @@ -550,6 +552,8 @@ func CreateFile(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.CreateFileOptions) @@ -646,6 +650,8 @@ func UpdateFile(ctx *context.APIContext) { // "$ref": "#/responses/notFound" // "422": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.UpdateFileOptions) if ctx.Repo.Repository.IsEmpty { ctx.Error(http.StatusUnprocessableEntity, "RepoIsEmpty", fmt.Errorf("repo is empty")) @@ -806,6 +812,8 @@ func DeleteFile(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.DeleteFileOptions) if !canWriteFiles(ctx, apiOpts.BranchName) { diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index 7ae43562043..69433bf4cc4 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -55,7 +55,7 @@ func ListForks(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - forks, err := repo_model.GetForks(ctx.Repo.Repository, utils.GetListOptions(ctx)) + forks, err := repo_model.GetForks(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetForks", err) return @@ -123,7 +123,7 @@ func CreateFork(ctx *context.APIContext) { } return } - isMember, err := org.IsOrgMember(ctx.Doer.ID) + isMember, err := org.IsOrgMember(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOrgMember", err) return diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index c6248bacecd..58689b72a6c 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -413,7 +413,7 @@ func ListIssues(ctx *context.APIContext) { var labelIDs []int64 if splitted := strings.Split(ctx.FormString("labels"), ","); len(splitted) > 0 { - labelIDs, err = issues_model.GetLabelIDsInRepoByNames(ctx.Repo.Repository.ID, splitted) + labelIDs, err = issues_model.GetLabelIDsInRepoByNames(ctx, ctx.Repo.Repository.ID, splitted) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelIDsInRepoByNames", err) return @@ -425,7 +425,7 @@ func ListIssues(ctx *context.APIContext) { for i := range part { // uses names and fall back to ids // non existent milestones are discarded - mile, err := issues_model.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, part[i]) + mile, err := issues_model.GetMilestoneByRepoIDANDName(ctx, ctx.Repo.Repository.ID, part[i]) if err == nil { mileIDs = append(mileIDs, mile.ID) continue @@ -631,6 +631,8 @@ func CreateIssue(ctx *context.APIContext) { // "$ref": "#/responses/error" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateIssueOption) var deadlineUnix timeutil.TimeStamp if form.Deadline != nil && ctx.Repo.CanWrite(unit.TypeIssues) { @@ -803,7 +805,7 @@ func EditIssue(ctx *context.APIContext) { deadlineUnix = timeutil.TimeStamp(deadline.Unix()) } - if err := issues_model.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil { + if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err) return } @@ -842,7 +844,7 @@ func EditIssue(ctx *context.APIContext) { } if form.State != nil { if issue.IsPull { - if pr, err := issue.GetPullRequest(); err != nil { + if pr, err := issue.GetPullRequest(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "GetPullRequest", err) return } else if pr.HasMerged { @@ -852,7 +854,7 @@ func EditIssue(ctx *context.APIContext) { } issue.IsClosed = api.StateClosed == api.StateType(*form.State) } - statusChangeComment, titleChanged, err := issues_model.UpdateIssueByAPI(issue, ctx.Doer) + statusChangeComment, titleChanged, err := issues_model.UpdateIssueByAPI(ctx, issue, ctx.Doer) if err != nil { if issues_model.IsErrDependenciesLeft(err) { ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this issue because it still has open dependencies") @@ -990,7 +992,7 @@ func UpdateIssueDeadline(ctx *context.APIContext) { deadlineUnix = timeutil.TimeStamp(deadline.Unix()) } - if err := issues_model.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil { + if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err) return } diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go index c689e70a085..11d19b21ff5 100644 --- a/routers/api/v1/repo/issue_attachment.go +++ b/routers/api/v1/repo/issue_attachment.go @@ -153,6 +153,8 @@ func CreateIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" issue := getIssueFromContext(ctx) if issue == nil { @@ -176,7 +178,7 @@ func CreateIssueAttachment(ctx *context.APIContext) { filename = query } - attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{ + attachment, err := attachment.UploadAttachment(ctx, file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{ Name: filename, UploaderID: ctx.Doer.ID, RepoID: ctx.Repo.Repository.ID, @@ -189,7 +191,7 @@ func CreateIssueAttachment(ctx *context.APIContext) { issue.Attachments = append(issue.Attachments, attachment) - if err := issue_service.ChangeContent(issue, ctx.Doer, issue.Content); err != nil { + if err := issue_service.ChangeContent(ctx, issue, ctx.Doer, issue.Content); err != nil { ctx.Error(http.StatusInternalServerError, "ChangeContent", err) return } @@ -238,6 +240,8 @@ func EditIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/Attachment" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" attachment := getIssueAttachmentSafeWrite(ctx) if attachment == nil { @@ -292,13 +296,15 @@ func DeleteIssueAttachment(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" attachment := getIssueAttachmentSafeWrite(ctx) if attachment == nil { return } - if err := repo_model.DeleteAttachment(attachment, true); err != nil { + if err := repo_model.DeleteAttachment(ctx, attachment, true); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err) return } diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index c9179e69db6..c718424f7eb 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -86,7 +86,7 @@ func ListIssueComments(ctx *context.APIContext) { return } - totalCount, err := issues_model.CountComments(opts) + totalCount, err := issues_model.CountComments(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -285,7 +285,7 @@ func ListRepoIssueComments(ctx *context.APIContext) { return } - totalCount, err := issues_model.CountComments(opts) + totalCount, err := issues_model.CountComments(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -358,6 +358,8 @@ func CreateIssueComment(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateIssueCommentOption) issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { @@ -486,7 +488,8 @@ func EditIssueComment(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" - + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.EditIssueCommentOption) editIssueComment(ctx, *form) } diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go index 121e3f10e0d..c327c54d101 100644 --- a/routers/api/v1/repo/issue_comment_attachment.go +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -156,6 +156,8 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/error" // "404": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" // Check if comment exists and load comment comment := getIssueCommentSafe(ctx) @@ -180,7 +182,7 @@ func CreateIssueCommentAttachment(ctx *context.APIContext) { filename = query } - attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{ + attachment, err := attachment.UploadAttachment(ctx, file, setting.Attachment.AllowedTypes, header.Size, &repo_model.Attachment{ Name: filename, UploaderID: ctx.Doer.ID, RepoID: ctx.Repo.Repository.ID, @@ -245,7 +247,8 @@ func EditIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/Attachment" // "404": // "$ref": "#/responses/error" - + // "423": + // "$ref": "#/responses/repoArchivedError" attach := getIssueCommentAttachmentSafeWrite(ctx) if attach == nil { return @@ -297,13 +300,14 @@ func DeleteIssueCommentAttachment(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "404": // "$ref": "#/responses/error" - + // "423": + // "$ref": "#/responses/repoArchivedError" attach := getIssueCommentAttachmentSafeWrite(ctx) if attach == nil { return } - if err := repo_model.DeleteAttachment(attach, true); err != nil { + if err := repo_model.DeleteAttachment(ctx, attach, true); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err) return } diff --git a/routers/api/v1/repo/issue_dependency.go b/routers/api/v1/repo/issue_dependency.go index 5ea3836da1a..9571532800d 100644 --- a/routers/api/v1/repo/issue_dependency.go +++ b/routers/api/v1/repo/issue_dependency.go @@ -187,6 +187,8 @@ func CreateIssueDependency(ctx *context.APIContext) { // "$ref": "#/responses/Issue" // "404": // description: the issue does not exist + // "423": + // "$ref": "#/responses/repoArchivedError" // We want to make <:index> depend on
, i.e. <:index> is the target target := getParamsIssue(ctx) @@ -246,6 +248,8 @@ func RemoveIssueDependency(ctx *context.APIContext) { // "$ref": "#/responses/Issue" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" // We want to make <:index> depend on , i.e. <:index> is the target target := getParamsIssue(ctx) diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index b050a397f2b..2f9ad7060ce 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -107,7 +107,7 @@ func AddIssueLabels(ctx *context.APIContext) { return } - if err = issue_service.AddLabels(issue, ctx.Doer, labels); err != nil { + if err = issue_service.AddLabels(ctx, issue, ctx.Doer, labels); err != nil { ctx.Error(http.StatusInternalServerError, "AddLabels", err) return } @@ -186,7 +186,7 @@ func DeleteIssueLabel(ctx *context.APIContext) { return } - if err := issue_service.RemoveLabel(issue, ctx.Doer, label); err != nil { + if err := issue_service.RemoveLabel(ctx, issue, ctx.Doer, label); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteIssueLabel", err) return } @@ -237,7 +237,7 @@ func ReplaceIssueLabels(ctx *context.APIContext) { return } - if err := issue_service.ReplaceLabels(issue, ctx.Doer, labels); err != nil { + if err := issue_service.ReplaceLabels(ctx, issue, ctx.Doer, labels); err != nil { ctx.Error(http.StatusInternalServerError, "ReplaceLabels", err) return } @@ -298,7 +298,7 @@ func ClearIssueLabels(ctx *context.APIContext) { return } - if err := issue_service.ClearLabels(issue, ctx.Doer); err != nil { + if err := issue_service.ClearLabels(ctx, issue, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "ClearLabels", err) return } @@ -317,7 +317,7 @@ func prepareForReplaceOrAdd(ctx *context.APIContext, form api.IssueLabelsOption) return nil, nil, err } - labels, err := issues_model.GetLabelsByIDs(form.Labels, "id", "repo_id", "org_id") + labels, err := issues_model.GetLabelsByIDs(ctx, form.Labels, "id", "repo_id", "org_id") if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsByIDs", err) return nil, nil, err diff --git a/routers/api/v1/repo/issue_pin.go b/routers/api/v1/repo/issue_pin.go index d9b1bcc8940..61f88de34eb 100644 --- a/routers/api/v1/repo/issue_pin.go +++ b/routers/api/v1/repo/issue_pin.go @@ -241,7 +241,7 @@ func ListPinnedPullRequests(ctx *context.APIContext) { apiPrs := make([]*api.PullRequest, len(issues)) for i, currentIssue := range issues { - pr, err := currentIssue.GetPullRequest() + pr, err := currentIssue.GetPullRequest(ctx) if err != nil { ctx.Error(http.StatusInternalServerError, "GetPullRequest", err) return diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 5210d4ccedb..29c99184e76 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -68,7 +68,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) { return } - reactions, _, err := issues_model.FindCommentReactions(comment.IssueID, comment.ID) + reactions, _, err := issues_model.FindCommentReactions(ctx, comment.IssueID, comment.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "FindCommentReactions", err) return @@ -202,7 +202,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp if isCreateType { // PostIssueCommentReaction part - reaction, err := issues_model.CreateCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction) + reaction, err := issues_model.CreateCommentReaction(ctx, ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction) if err != nil { if issues_model.IsErrForbiddenIssueReaction(err) { ctx.Error(http.StatusForbidden, err.Error(), err) @@ -225,7 +225,7 @@ func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOp }) } else { // DeleteIssueCommentReaction part - err = issues_model.DeleteCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction) + err = issues_model.DeleteCommentReaction(ctx, ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Reaction) if err != nil { ctx.Error(http.StatusInternalServerError, "DeleteCommentReaction", err) return @@ -292,7 +292,7 @@ func GetIssueReactions(ctx *context.APIContext) { return } - reactions, count, err := issues_model.FindIssueReactions(issue.ID, utils.GetListOptions(ctx)) + reactions, count, err := issues_model.FindIssueReactions(ctx, issue.ID, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "FindIssueReactions", err) return @@ -418,7 +418,7 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i if isCreateType { // PostIssueReaction part - reaction, err := issues_model.CreateIssueReaction(ctx.Doer.ID, issue.ID, form.Reaction) + reaction, err := issues_model.CreateIssueReaction(ctx, ctx.Doer.ID, issue.ID, form.Reaction) if err != nil { if issues_model.IsErrForbiddenIssueReaction(err) { ctx.Error(http.StatusForbidden, err.Error(), err) @@ -441,7 +441,7 @@ func changeIssueReaction(ctx *context.APIContext, form api.EditReactionOption, i }) } else { // DeleteIssueReaction part - err = issues_model.DeleteIssueReaction(ctx.Doer.ID, issue.ID, form.Reaction) + err = issues_model.DeleteIssueReaction(ctx, ctx.Doer.ID, issue.ID, form.Reaction) if err != nil { ctx.Error(http.StatusInternalServerError, "DeleteIssueReaction", err) return diff --git a/routers/api/v1/repo/issue_stopwatch.go b/routers/api/v1/repo/issue_stopwatch.go index 75fa8631385..384532ab879 100644 --- a/routers/api/v1/repo/issue_stopwatch.go +++ b/routers/api/v1/repo/issue_stopwatch.go @@ -152,7 +152,7 @@ func DeleteIssueStopwatch(ctx *context.APIContext) { return } - if err := issues_model.CancelStopwatch(ctx.Doer, issue); err != nil { + if err := issues_model.CancelStopwatch(ctx, ctx.Doer, issue); err != nil { ctx.Error(http.StatusInternalServerError, "CancelStopwatch", err) return } @@ -182,7 +182,7 @@ func prepareIssueStopwatch(ctx *context.APIContext, shouldExist bool) (*issues_m return nil, errors.New("Cannot use time tracker") } - if issues_model.StopwatchExists(ctx.Doer.ID, issue.ID) != shouldExist { + if issues_model.StopwatchExists(ctx, ctx.Doer.ID, issue.ID) != shouldExist { if shouldExist { ctx.Error(http.StatusConflict, "StopwatchExists", "cannot stop/cancel a non existent stopwatch") err = errors.New("cannot stop/cancel a non existent stopwatch") @@ -218,13 +218,13 @@ func GetStopwatches(ctx *context.APIContext) { // "200": // "$ref": "#/responses/StopWatchList" - sws, err := issues_model.GetUserStopwatches(ctx.Doer.ID, utils.GetListOptions(ctx)) + sws, err := issues_model.GetUserStopwatches(ctx, ctx.Doer.ID, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserStopwatches", err) return } - count, err := issues_model.CountUserStopwatches(ctx.Doer.ID) + count, err := issues_model.CountUserStopwatches(ctx, ctx.Doer.ID) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 5a054712646..ece880c03e1 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -132,7 +132,7 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - current, err := issues_model.CheckIssueWatch(user, issue) + current, err := issues_model.CheckIssueWatch(ctx, user, issue) if err != nil { ctx.Error(http.StatusInternalServerError, "CheckIssueWatch", err) return @@ -145,7 +145,7 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { } // Update watch state - if err := issues_model.CreateOrUpdateIssueWatch(user.ID, issue.ID, watch); err != nil { + if err := issues_model.CreateOrUpdateIssueWatch(ctx, user.ID, issue.ID, watch); err != nil { ctx.Error(http.StatusInternalServerError, "CreateOrUpdateIssueWatch", err) return } @@ -196,7 +196,7 @@ func CheckIssueSubscription(ctx *context.APIContext) { return } - watching, err := issues_model.CheckIssueWatch(ctx.Doer, issue) + watching, err := issues_model.CheckIssueWatch(ctx, ctx.Doer, issue) if err != nil { ctx.InternalServerError(err) return @@ -206,7 +206,7 @@ func CheckIssueSubscription(ctx *context.APIContext) { Ignored: !watching, Reason: nil, CreatedAt: issue.CreatedUnix.AsTime(), - URL: issue.APIURL() + "/subscriptions", + URL: issue.APIURL(ctx) + "/subscriptions", RepositoryURL: ctx.Repo.Repository.APIURL(), }) } @@ -273,7 +273,7 @@ func GetIssueSubscribers(ctx *context.APIContext) { userIDs = append(userIDs, iw.UserID) } - users, err := user_model.GetUsersByIDs(userIDs) + users, err := user_model.GetUsersByIDs(ctx, userIDs) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUsersByIDs", err) return diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index ecbc5cf00f8..06cd411ea1e 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -283,7 +283,7 @@ func ResetIssueTime(ctx *context.APIContext) { return } - err = issues_model.DeleteIssueUserTimes(issue, ctx.Doer) + err = issues_model.DeleteIssueUserTimes(ctx, issue, ctx.Doer) if err != nil { if db.IsErrNotExist(err) { ctx.Error(http.StatusNotFound, "DeleteIssueUserTimes", err) @@ -356,7 +356,7 @@ func DeleteTime(ctx *context.APIContext) { return } - time, err := issues_model.GetTrackedTimeByID(ctx.ParamsInt64(":id")) + time, err := issues_model.GetTrackedTimeByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if db.IsErrNotExist(err) { ctx.NotFound(err) @@ -376,7 +376,7 @@ func DeleteTime(ctx *context.APIContext) { return } - err = issues_model.DeleteTime(time) + err = issues_model.DeleteTime(ctx, time) if err != nil { ctx.Error(http.StatusInternalServerError, "DeleteTime", err) return diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index b7d820d1d83..7d97f5f5e20 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -279,7 +279,7 @@ func DeleteDeploykey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := asymkey_service.DeleteDeployKey(ctx.Doer, ctx.ParamsInt64(":id")); err != nil { + if err := asymkey_service.DeleteDeployKey(ctx, ctx.Doer, ctx.ParamsInt64(":id")); err != nil { if asymkey_model.IsErrKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") } else { diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index e93c72a9f5f..420d3ab5b49 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -55,7 +55,7 @@ func ListLabels(ctx *context.APIContext) { return } - count, err := issues_model.CountLabelsByRepoID(ctx.Repo.Repository.ID) + count, err := issues_model.CountLabelsByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.InternalServerError(err) return @@ -240,7 +240,7 @@ func EditLabel(ctx *context.APIContext) { l.Description = *form.Description } l.SetArchived(form.IsArchived != nil && *form.IsArchived) - if err := issues_model.UpdateLabel(l); err != nil { + if err := issues_model.UpdateLabel(ctx, l); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateLabel", err) return } @@ -276,7 +276,7 @@ func DeleteLabel(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := issues_model.DeleteLabel(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")); err != nil { + if err := issues_model.DeleteLabel(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteLabel", err) return } diff --git a/routers/api/v1/repo/main_test.go b/routers/api/v1/repo/main_test.go index bc048505f47..451f34d72ff 100644 --- a/routers/api/v1/repo/main_test.go +++ b/routers/api/v1/repo/main_test.go @@ -4,7 +4,6 @@ package repo import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,7 +13,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", "..", ".."), SetUp: func() error { setting.LoadQueueSettings() return webhook_service.Init() diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 4ddd4523729..14ff04e7bf7 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -93,7 +93,7 @@ func Migrate(ctx *context.APIContext) { if repoOwner.IsOrganization() { // Check ownership of organization. - isOwner, err := organization.OrgFromUser(repoOwner).IsOwnedBy(ctx.Doer.ID) + isOwner, err := organization.OrgFromUser(repoOwner).IsOwnedBy(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOwnedBy", err) return diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index fff9493a237..1a86444660a 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -163,7 +163,7 @@ func CreateMilestone(ctx *context.APIContext) { milestone.ClosedDateUnix = timeutil.TimeStampNow() } - if err := issues_model.NewMilestone(milestone); err != nil { + if err := issues_model.NewMilestone(ctx, milestone); err != nil { ctx.Error(http.StatusInternalServerError, "NewMilestone", err) return } @@ -225,7 +225,7 @@ func EditMilestone(ctx *context.APIContext) { milestone.IsClosed = *form.State == string(api.StateClosed) } - if err := issues_model.UpdateMilestone(milestone, oldIsClosed); err != nil { + if err := issues_model.UpdateMilestone(ctx, milestone, oldIsClosed); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateMilestone", err) return } @@ -264,7 +264,7 @@ func DeleteMilestone(ctx *context.APIContext) { return } - if err := issues_model.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, m.ID); err != nil { + if err := issues_model.DeleteMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, m.ID); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteMilestoneByRepoID", err) return } @@ -286,7 +286,7 @@ func getMilestoneByIDOrName(ctx *context.APIContext) *issues_model.Milestone { } } - milestone, err := issues_model.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, mile) + milestone, err := issues_model.GetMilestoneByRepoIDANDName(ctx, ctx.Repo.Repository.ID, mile) if err != nil { if issues_model.IsErrMilestoneNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index 12542c808f6..72ddc758dce 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -176,7 +176,7 @@ func ListPushMirrors(ctx *context.APIContext) { responsePushMirrors := make([]*api.PushMirror, 0, len(pushMirrors)) for _, mirror := range pushMirrors { - m, err := convert.ToPushMirror(mirror) + m, err := convert.ToPushMirror(ctx, mirror) if err == nil { responsePushMirrors = append(responsePushMirrors, m) } @@ -232,7 +232,7 @@ func GetPushMirrorByName(ctx *context.APIContext) { ctx.Error(http.StatusNotFound, "GetPushMirrors", err) return } - m, err := convert.ToPushMirror(pushMirror) + m, err := convert.ToPushMirror(ctx, pushMirror) if err != nil { ctx.ServerError("GetPushMirrorByRemoteName", err) return @@ -353,12 +353,19 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro return } + remoteAddress, err := util.SanitizeURL(mirrorOption.RemoteAddress) + if err != nil { + ctx.ServerError("SanitizeURL", err) + return + } + pushMirror := &repo_model.PushMirror{ - RepoID: repo.ID, - Repo: repo, - RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix), - Interval: interval, - SyncOnCommit: mirrorOption.SyncOnCommit, + RepoID: repo.ID, + Repo: repo, + RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix), + Interval: interval, + SyncOnCommit: mirrorOption.SyncOnCommit, + RemoteAddress: remoteAddress, } if err = repo_model.InsertPushMirror(ctx, pushMirror); err != nil { @@ -374,7 +381,7 @@ func CreatePushMirror(ctx *context.APIContext, mirrorOption *api.CreatePushMirro ctx.ServerError("AddPushMirrorRemote", err) return } - m, err := convert.ToPushMirror(pushMirror) + m, err := convert.ToPushMirror(ctx, pushMirror) if err != nil { ctx.ServerError("ToPushMirror", err) return diff --git a/routers/api/v1/repo/patch.go b/routers/api/v1/repo/patch.go index 080908ab7ed..9b5635d245a 100644 --- a/routers/api/v1/repo/patch.go +++ b/routers/api/v1/repo/patch.go @@ -47,6 +47,8 @@ func ApplyDiffPatch(ctx *context.APIContext) { // "$ref": "#/responses/FileResponse" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" apiOpts := web.GetForm(ctx).(*api.ApplyDiffPatchFileOptions) opts := &files.ApplyDiffPatchOptions{ diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 01ce754c74a..586f3385b18 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -97,7 +97,7 @@ func ListPullRequests(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - prs, maxResults, err := issues_model.PullRequests(ctx.Repo.Repository.ID, &issues_model.PullRequestsOptions{ + prs, maxResults, err := issues_model.PullRequests(ctx, ctx.Repo.Repository.ID, &issues_model.PullRequestsOptions{ ListOptions: listOptions, State: ctx.FormTrim("state"), SortType: ctx.FormTrim("sort"), @@ -282,6 +282,8 @@ func CreatePullRequest(ctx *context.APIContext) { // "$ref": "#/responses/error" // "422": // "$ref": "#/responses/validationError" + // "423": + // "$ref": "#/responses/repoArchivedError" form := *web.GetForm(ctx).(*api.CreatePullRequestOption) if form.Head == form.Base { @@ -522,7 +524,7 @@ func EditPullRequest(ctx *context.APIContext) { deadlineUnix = timeutil.TimeStamp(deadline.Unix()) } - if err := issues_model.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil { + if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err) return } @@ -589,7 +591,7 @@ func EditPullRequest(ctx *context.APIContext) { } issue.IsClosed = api.StateClosed == api.StateType(*form.State) } - statusChangeComment, titleChanged, err := issues_model.UpdateIssueByAPI(issue, ctx.Doer) + statusChangeComment, titleChanged, err := issues_model.UpdateIssueByAPI(ctx, issue, ctx.Doer) if err != nil { if issues_model.IsErrDependenciesLeft(err) { ctx.Error(http.StatusPreconditionFailed, "DependenciesLeft", "cannot close this pull request because it still has open dependencies") @@ -741,6 +743,8 @@ func MergePullRequest(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/error" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*forms.MergePullRequestForm) @@ -985,7 +989,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // Check if current user has fork of repository or in the same repository. - headRepo := repo_model.GetForkedRepo(headUser.ID, baseRepo.ID) + headRepo := repo_model.GetForkedRepo(ctx, headUser.ID, baseRepo.ID) if headRepo == nil && !isSameRepo { log.Trace("parseCompareInfo[%d]: does not have fork or in same repository", baseRepo.ID) ctx.NotFound("GetForkedRepo") @@ -1196,6 +1200,8 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" pullIndex := ctx.ParamsInt64(":index") pull, err := issues_model.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex) @@ -1436,7 +1442,7 @@ func GetPullRequestFiles(ctx *context.APIContext) { maxLines := setting.Git.MaxGitDiffLines // FIXME: If there are too many files in the repo, may cause some unpredictable issues. - diff, err := gitdiff.GetDiff(baseGitRepo, + diff, err := gitdiff.GetDiff(ctx, baseGitRepo, &gitdiff.DiffOptions{ BeforeCommitID: startCommitID, AfterCommitID: endCommitID, diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index 82cbb3e763c..7b9445be4c0 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -92,7 +92,7 @@ func ListPullReviews(ctx *context.APIContext) { return } - count, err := issues_model.CountReviews(opts) + count, err := issues_model.CountReviews(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -260,7 +260,7 @@ func DeletePullReview(ctx *context.APIContext) { return } - if err := issues_model.DeleteReview(review); err != nil { + if err := issues_model.DeleteReview(ctx, review); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteReview", fmt.Errorf("can not delete ReviewID: %d", review.ID)) return } @@ -713,7 +713,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions } if comment != nil && isAdd { - if err = comment.LoadReview(); err != nil { + if err = comment.LoadReview(ctx); err != nil { ctx.ServerError("ReviewRequest", err) return } @@ -757,7 +757,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions } if comment != nil && isAdd { - if err = comment.LoadReview(); err != nil { + if err = comment.LoadReview(ctx); err != nil { ctx.ServerError("ReviewRequest", err) return } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index be9c0cd00ac..61e5bdd6794 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -90,7 +90,7 @@ func GetLatestRelease(ctx *context.APIContext) { // "$ref": "#/responses/Release" // "404": // "$ref": "#/responses/notFound" - release, err := repo_model.GetLatestReleaseByRepoID(ctx.Repo.Repository.ID) + release, err := repo_model.GetLatestReleaseByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil && !repo_model.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetLatestRelease", err) return @@ -179,7 +179,7 @@ func ListReleases(ctx *context.APIContext) { rels[i] = convert.ToAPIRelease(ctx, ctx.Repo.Repository, release) } - filteredCount, err := repo_model.CountReleasesByRepoID(ctx.Repo.Repository.ID, opts) + filteredCount, err := repo_model.CountReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts) if err != nil { ctx.InternalServerError(err) return @@ -222,7 +222,7 @@ func CreateRelease(ctx *context.APIContext) { // "409": // "$ref": "#/responses/error" form := web.GetForm(ctx).(*api.CreateReleaseOption) - rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, form.TagName) + rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName) if err != nil { if !repo_model.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetRelease", err) @@ -269,7 +269,7 @@ func CreateRelease(ctx *context.APIContext) { rel.Publisher = ctx.Doer rel.Target = form.Target - if err = release_service.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { + if err = release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateRelease", err) return } @@ -344,7 +344,7 @@ func EditRelease(ctx *context.APIContext) { if form.IsPrerelease != nil { rel.IsPrerelease = *form.IsPrerelease } - if err := release_service.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { + if err := release_service.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateRelease", err) return } diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index 9571c8ebb90..168ef550c5e 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -200,7 +200,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) { } // Create a new attachment and save the file - attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{ + attach, err := attachment.UploadAttachment(ctx, file, setting.Repository.Release.AllowedTypes, header.Size, &repo_model.Attachment{ Name: filename, UploaderID: ctx.Doer.ID, RepoID: release.RepoID, @@ -345,7 +345,7 @@ func DeleteReleaseAttachment(ctx *context.APIContext) { } // FIXME Should prove the existence of the given repo, but results in unnecessary database requests - if err := repo_model.DeleteAttachment(attach, true); err != nil { + if err := repo_model.DeleteAttachment(ctx, attach, true); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err) return } diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index a03edfafcf5..926a713c947 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -44,7 +44,7 @@ func GetReleaseByTag(ctx *context.APIContext) { tag := ctx.Params(":tag") - release, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tag) + release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tag) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound() @@ -97,7 +97,7 @@ func DeleteReleaseByTag(ctx *context.APIContext) { tag := ctx.Params(":tag") - release, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tag) + release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tag) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 9a08596a26b..3ce39069bb7 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -397,7 +397,7 @@ func Generate(ctx *context.APIContext) { } if !ctx.Doer.IsAdmin { - canCreate, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID) + canCreate, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("CanCreateOrgRepo", err) return @@ -503,7 +503,7 @@ func CreateOrgRepo(ctx *context.APIContext) { } if !ctx.Doer.IsAdmin { - canCreate, err := org.CanCreateOrgRepo(ctx.Doer.ID) + canCreate, err := org.CanCreateOrgRepo(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "CanCreateOrgRepo", err) return @@ -987,7 +987,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { } if len(units)+len(deleteUnitTypes) > 0 { - if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil { + if err := repo_model.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err) return err } @@ -1008,14 +1008,14 @@ func updateRepoArchivedState(ctx *context.APIContext, opts api.EditRepoOption) e return err } if *opts.Archived { - if err := repo_model.SetArchiveRepoState(repo, *opts.Archived); err != nil { + if err := repo_model.SetArchiveRepoState(ctx, repo, *opts.Archived); err != nil { log.Error("Tried to archive a repo: %s", err) ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err } log.Trace("Repository was archived: %s/%s", ctx.Repo.Owner.Name, repo.Name) } else { - if err := repo_model.SetArchiveRepoState(repo, *opts.Archived); err != nil { + if err := repo_model.SetArchiveRepoState(ctx, repo, *opts.Archived); err != nil { log.Error("Tried to un-archive a repo: %s", err) ctx.Error(http.StatusInternalServerError, "ArchiveRepoState", err) return err @@ -1119,7 +1119,7 @@ func Delete(ctx *context.APIContext) { owner := ctx.Repo.Owner repo := ctx.Repo.Repository - canDelete, err := repo_module.CanUserDelete(repo, ctx.Doer) + canDelete, err := repo_module.CanUserDelete(ctx, repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "CanUserDelete", err) return diff --git a/routers/api/v1/repo/star.go b/routers/api/v1/repo/star.go index fccc76b5187..05227e33a0c 100644 --- a/routers/api/v1/repo/star.go +++ b/routers/api/v1/repo/star.go @@ -45,7 +45,7 @@ func ListStargazers(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - stargazers, err := repo_model.GetStargazers(ctx.Repo.Repository, utils.GetListOptions(ctx)) + stargazers, err := repo_model.GetStargazers(ctx, ctx.Repo.Repository, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetStargazers", err) return diff --git a/routers/api/v1/repo/subscriber.go b/routers/api/v1/repo/subscriber.go index 61d9470707f..05509fc4435 100644 --- a/routers/api/v1/repo/subscriber.go +++ b/routers/api/v1/repo/subscriber.go @@ -45,7 +45,7 @@ func ListSubscribers(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - subscribers, err := repo_model.GetRepoWatchers(ctx.Repo.Repository.ID, utils.GetListOptions(ctx)) + subscribers, err := repo_model.GetRepoWatchers(ctx, ctx.Repo.Repository.ID, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetRepoWatchers", err) return diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index 0c0a73698f7..dbc8df0ef81 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -184,6 +184,8 @@ func CreateTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateTagOption) // If target is not provided use default branch @@ -251,9 +253,11 @@ func DeleteTag(ctx *context.APIContext) { // "$ref": "#/responses/empty" // "409": // "$ref": "#/responses/conflict" + // "423": + // "$ref": "#/responses/repoArchivedError" tagName := ctx.Params("*") - tag, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName) + tag, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/teams.go b/routers/api/v1/repo/teams.go index 2887e896036..1bacc712118 100644 --- a/routers/api/v1/repo/teams.go +++ b/routers/api/v1/repo/teams.go @@ -99,7 +99,7 @@ func IsTeam(ctx *context.APIContext) { return } - if repo_service.HasRepository(team, ctx.Repo.Repository.ID) { + if repo_service.HasRepository(ctx, team, ctx.Repo.Repository.ID) { apiTeam, err := convert.ToTeam(ctx, team) if err != nil { ctx.InternalServerError(err) @@ -198,14 +198,14 @@ func changeRepoTeam(ctx *context.APIContext, add bool) { return } - repoHasTeam := repo_service.HasRepository(team, ctx.Repo.Repository.ID) + repoHasTeam := repo_service.HasRepository(ctx, team, ctx.Repo.Repository.ID) var err error if add { if repoHasTeam { ctx.Error(http.StatusUnprocessableEntity, "alreadyAdded", fmt.Errorf("team '%s' is already added to repo", team.Name)) return } - err = org_service.TeamAddRepository(team, ctx.Repo.Repository) + err = org_service.TeamAddRepository(ctx, team, ctx.Repo.Repository) } else { if !repoHasTeam { ctx.Error(http.StatusUnprocessableEntity, "notAdded", fmt.Errorf("team '%s' was not added to repo", team.Name)) diff --git a/routers/api/v1/repo/topic.go b/routers/api/v1/repo/topic.go index c0c05154c47..d662b9b5832 100644 --- a/routers/api/v1/repo/topic.go +++ b/routers/api/v1/repo/topic.go @@ -53,7 +53,7 @@ func ListTopics(ctx *context.APIContext) { RepoID: ctx.Repo.Repository.ID, } - topics, total, err := repo_model.FindTopics(opts) + topics, total, err := repo_model.FindTopics(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -120,7 +120,7 @@ func UpdateTopics(ctx *context.APIContext) { return } - err := repo_model.SaveTopics(ctx.Repo.Repository.ID, validTopics...) + err := repo_model.SaveTopics(ctx, ctx.Repo.Repository.ID, validTopics...) if err != nil { log.Error("SaveTopics failed: %v", err) ctx.InternalServerError(err) @@ -172,7 +172,7 @@ func AddTopic(ctx *context.APIContext) { } // Prevent adding more topics than allowed to repo - count, err := repo_model.CountTopics(&repo_model.FindTopicOptions{ + count, err := repo_model.CountTopics(ctx, &repo_model.FindTopicOptions{ RepoID: ctx.Repo.Repository.ID, }) if err != nil { @@ -187,7 +187,7 @@ func AddTopic(ctx *context.APIContext) { return } - _, err = repo_model.AddTopic(ctx.Repo.Repository.ID, topicName) + _, err = repo_model.AddTopic(ctx, ctx.Repo.Repository.ID, topicName) if err != nil { log.Error("AddTopic failed: %v", err) ctx.InternalServerError(err) @@ -238,7 +238,7 @@ func DeleteTopic(ctx *context.APIContext) { return } - topic, err := repo_model.DeleteTopic(ctx.Repo.Repository.ID, topicName) + topic, err := repo_model.DeleteTopic(ctx, ctx.Repo.Repository.ID, topicName) if err != nil { log.Error("DeleteTopic failed: %v", err) ctx.InternalServerError(err) @@ -287,7 +287,7 @@ func TopicSearch(ctx *context.APIContext) { ListOptions: utils.GetListOptions(ctx), } - topics, total, err := repo_model.FindTopics(opts) + topics, total, err := repo_model.FindTopics(ctx, opts) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index 8ff22a1193f..b3120f4be08 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -68,7 +68,7 @@ func Transfer(ctx *context.APIContext) { } if newOwner.Type == user_model.UserTypeOrganization { - if !ctx.Doer.IsAdmin && newOwner.Visibility == api.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) { + if !ctx.Doer.IsAdmin && newOwner.Visibility == api.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) { // The user shouldn't know about this organization ctx.Error(http.StatusNotFound, "", "The new owner does not exist or cannot be found") return @@ -221,7 +221,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { return err } - if !repoTransfer.CanUserAcceptTransfer(ctx.Doer) { + if !repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer) { ctx.Error(http.StatusForbidden, "CanUserAcceptTransfer", nil) return fmt.Errorf("user does not have permissions to do this") } @@ -230,5 +230,5 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { return repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams) } - return models.CancelRepositoryTransfer(ctx.Repo.Repository) + return models.CancelRepositoryTransfer(ctx, ctx.Repo.Repository) } diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 4ea3fbd11d6..8e5ecce310e 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -52,6 +52,8 @@ func NewWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateWikiPageOptions) @@ -128,6 +130,8 @@ func EditWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" form := web.GetForm(ctx).(*api.CreateWikiPageOptions) @@ -234,6 +238,8 @@ func DeleteWikiPage(ctx *context.APIContext) { // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" + // "423": + // "$ref": "#/responses/repoArchivedError" wikiName := wiki_service.WebPathFromRequest(ctx.PathParamRaw(":pageName")) diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index f89d53945fa..6972931abc6 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -43,15 +43,17 @@ func ListAccessTokens(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/AccessTokenList" + // "403": + // "$ref": "#/responses/forbidden" - opts := auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID, ListOptions: utils.GetListOptions(ctx)} + opts := auth_model.ListAccessTokensOptions{UserID: ctx.ContextUser.ID, ListOptions: utils.GetListOptions(ctx)} - count, err := auth_model.CountAccessTokens(opts) + count, err := auth_model.CountAccessTokens(ctx, opts) if err != nil { ctx.InternalServerError(err) return } - tokens, err := auth_model.ListAccessTokens(opts) + tokens, err := auth_model.ListAccessTokens(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -95,15 +97,17 @@ func CreateAccessToken(ctx *context.APIContext) { // "$ref": "#/responses/AccessToken" // "400": // "$ref": "#/responses/error" + // "403": + // "$ref": "#/responses/forbidden" form := web.GetForm(ctx).(*api.CreateAccessTokenOption) t := &auth_model.AccessToken{ - UID: ctx.Doer.ID, + UID: ctx.ContextUser.ID, Name: form.Name, } - exist, err := auth_model.AccessTokenByNameExists(t) + exist, err := auth_model.AccessTokenByNameExists(ctx, t) if err != nil { ctx.InternalServerError(err) return @@ -120,7 +124,7 @@ func CreateAccessToken(ctx *context.APIContext) { } t.Scope = scope - if err := auth_model.NewAccessToken(t); err != nil { + if err := auth_model.NewAccessToken(ctx, t); err != nil { ctx.Error(http.StatusInternalServerError, "NewAccessToken", err) return } @@ -153,6 +157,8 @@ func DeleteAccessToken(ctx *context.APIContext) { // responses: // "204": // "$ref": "#/responses/empty" + // "403": + // "$ref": "#/responses/forbidden" // "404": // "$ref": "#/responses/notFound" // "422": @@ -162,9 +168,9 @@ func DeleteAccessToken(ctx *context.APIContext) { tokenID, _ := strconv.ParseInt(token, 0, 64) if tokenID == 0 { - tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{ + tokens, err := auth_model.ListAccessTokens(ctx, auth_model.ListAccessTokensOptions{ Name: token, - UserID: ctx.Doer.ID, + UserID: ctx.ContextUser.ID, }) if err != nil { ctx.Error(http.StatusInternalServerError, "ListAccessTokens", err) @@ -187,7 +193,7 @@ func DeleteAccessToken(ctx *context.APIContext) { return } - if err := auth_model.DeleteAccessTokenByID(tokenID, ctx.Doer.ID); err != nil { + if err := auth_model.DeleteAccessTokenByID(ctx, tokenID, ctx.Doer.ID); err != nil { if auth_model.IsErrAccessTokenNotExist(err) { ctx.NotFound() } else { diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go index fc74c8d1484..68f6c974a59 100644 --- a/routers/api/v1/user/email.go +++ b/routers/api/v1/user/email.go @@ -27,7 +27,7 @@ func ListEmails(ctx *context.APIContext) { // "200": // "$ref": "#/responses/EmailList" - emails, err := user_model.GetEmailAddresses(ctx.Doer.ID) + emails, err := user_model.GetEmailAddresses(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetEmailAddresses", err) return @@ -71,7 +71,7 @@ func AddEmail(ctx *context.APIContext) { } } - if err := user_model.AddEmailAddresses(emails); err != nil { + if err := user_model.AddEmailAddresses(ctx, emails); err != nil { if user_model.IsErrEmailAlreadyUsed(err) { ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email) } else if user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) { @@ -129,7 +129,7 @@ func DeleteEmail(ctx *context.APIContext) { } } - if err := user_model.DeleteEmailAddresses(emails); err != nil { + if err := user_model.DeleteEmailAddresses(ctx, emails); err != nil { if user_model.IsErrEmailAddressNotExist(err) { ctx.Error(http.StatusNotFound, "DeleteEmailAddresses", err) return diff --git a/routers/api/v1/user/follower.go b/routers/api/v1/user/follower.go index 1aa906ccb11..5815ed4f0b4 100644 --- a/routers/api/v1/user/follower.go +++ b/routers/api/v1/user/follower.go @@ -151,7 +151,7 @@ func ListFollowing(ctx *context.APIContext) { } func checkUserFollowing(ctx *context.APIContext, u *user_model.User, followID int64) { - if user_model.IsFollowing(u.ID, followID) { + if user_model.IsFollowing(ctx, u.ID, followID) { ctx.Status(http.StatusNoContent) } else { ctx.NotFound() @@ -224,7 +224,7 @@ func Follow(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID); err != nil { + if err := user_model.FollowUser(ctx, ctx.Doer.ID, ctx.ContextUser.ID); err != nil { ctx.Error(http.StatusInternalServerError, "FollowUser", err) return } @@ -248,7 +248,7 @@ func Unfollow(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID); err != nil { + if err := user_model.UnfollowUser(ctx, ctx.Doer.ID, ctx.ContextUser.ID); err != nil { ctx.Error(http.StatusInternalServerError, "UnfollowUser", err) return } diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index 4aebbaf3142..8578e090545 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -29,7 +29,7 @@ func listGPGKeys(ctx *context.APIContext, uid int64, listOptions db.ListOptions) apiKeys[i] = convert.ToGPGKey(keys[i]) } - total, err := asymkey_model.CountUserGPGKeys(uid) + total, err := asymkey_model.CountUserGPGKeys(ctx, uid) if err != nil { ctx.InternalServerError(err) return @@ -112,7 +112,7 @@ func GetGPGKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - key, err := asymkey_model.GetGPGKeyByID(ctx.ParamsInt64(":id")) + key, err := asymkey_model.GetGPGKeyByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if asymkey_model.IsErrGPGKeyNotExist(err) { ctx.NotFound() @@ -129,9 +129,9 @@ func CreateUserGPGKey(ctx *context.APIContext, form api.CreateGPGKeyOption, uid token := asymkey_model.VerificationToken(ctx.Doer, 1) lastToken := asymkey_model.VerificationToken(ctx.Doer, 0) - keys, err := asymkey_model.AddGPGKey(uid, form.ArmoredKey, token, form.Signature) + keys, err := asymkey_model.AddGPGKey(ctx, uid, form.ArmoredKey, token, form.Signature) if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) { - keys, err = asymkey_model.AddGPGKey(uid, form.ArmoredKey, lastToken, form.Signature) + keys, err = asymkey_model.AddGPGKey(ctx, uid, form.ArmoredKey, lastToken, form.Signature) } if err != nil { HandleAddGPGKeyError(ctx, err, token) @@ -198,7 +198,7 @@ func VerifyUserGPGKey(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "VerifyUserGPGKey", err) } - key, err := asymkey_model.GetGPGKeysByKeyID(form.KeyID) + key, err := asymkey_model.GetGPGKeysByKeyID(ctx, form.KeyID) if err != nil { if asymkey_model.IsErrGPGKeyNotExist(err) { ctx.NotFound() @@ -259,7 +259,7 @@ func DeleteGPGKey(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if err := asymkey_model.DeleteGPGKey(ctx.Doer, ctx.ParamsInt64(":id")); err != nil { + if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.ParamsInt64(":id")); err != nil { if asymkey_model.IsErrGPGKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") } else { diff --git a/routers/api/v1/user/helper.go b/routers/api/v1/user/helper.go index 4b642910b19..392b266ebd8 100644 --- a/routers/api/v1/user/helper.go +++ b/routers/api/v1/user/helper.go @@ -16,7 +16,7 @@ func GetUserByParamsName(ctx *context.APIContext, name string) *user_model.User user, err := user_model.GetUserByName(ctx, username) if err != nil { if user_model.IsErrUserNotExist(err) { - if redirectUserID, err2 := user_model.LookupUserRedirect(username); err2 == nil { + if redirectUserID, err2 := user_model.LookupUserRedirect(ctx, username); err2 == nil { context.RedirectToUser(ctx.Base, username, redirectUserID) } else { ctx.NotFound("GetUserByName", err) diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index 21cc560847b..7fc10e82f25 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -277,7 +277,7 @@ func DeletePublicKey(ctx *context.APIContext) { return } - if err := asymkey_service.DeletePublicKey(ctx.Doer, id); err != nil { + if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, id); err != nil { if asymkey_model.IsErrKeyAccessDenied(err) { ctx.Error(http.StatusForbidden, "", "You do not have access to this key") } else { diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index 09f799cc6ab..2659789ddd9 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -155,7 +155,7 @@ func Star(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - err := repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true) + err := repo_model.StarRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, true) if err != nil { ctx.Error(http.StatusInternalServerError, "StarRepo", err) return @@ -185,7 +185,7 @@ func Unstar(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - err := repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, false) + err := repo_model.StarRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, false) if err != nil { ctx.Error(http.StatusInternalServerError, "StarRepo", err) return diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 2a2361be678..63591383695 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -54,7 +54,7 @@ func Search(ctx *context.APIContext) { listOptions := utils.GetListOptions(ctx) - users, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Keyword: ctx.FormTrim("q"), UID: ctx.FormInt64("uid"), @@ -138,7 +138,7 @@ func GetUserHeatmapData(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - heatmap, err := activities_model.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer) + heatmap, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserHeatmapDataByUser", err) return diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index b5899baa937..7f531eafaa6 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -124,7 +124,7 @@ func IsWatching(ctx *context.APIContext) { // "404": // description: User is not watching this repo or repo do not exist - if repo_model.IsWatching(ctx.Doer.ID, ctx.Repo.Repository.ID) { + if repo_model.IsWatching(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) { ctx.JSON(http.StatusOK, api.WatchInfo{ Subscribed: true, Ignored: false, diff --git a/routers/common/errpage_test.go b/routers/common/errpage_test.go index ea9a9e745c1..58a633b2a45 100644 --- a/routers/common/errpage_test.go +++ b/routers/common/errpage_test.go @@ -9,7 +9,6 @@ import ( "net/http" "net/http/httptest" "net/url" - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -35,7 +34,5 @@ func TestRenderPanicErrorPage(t *testing.T) { } func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/init.go b/routers/init.go index 6369a39754b..3cd63eb9ae1 100644 --- a/routers/init.go +++ b/routers/init.go @@ -93,7 +93,7 @@ func syncAppConfForGit(ctx context.Context) error { mustInitCtx(ctx, repo_service.SyncRepositoryHooks) log.Info("re-write ssh public keys ...") - mustInit(asymkey_model.RewriteAllPublicKeys) + mustInitCtx(ctx, asymkey_model.RewriteAllPublicKeys) return system.AppState.Set(runtimeState) } @@ -140,7 +140,7 @@ func InitWebInstalled(ctx context.Context) { mustInitCtx(ctx, models.Init) mustInitCtx(ctx, authmodel.Init) - mustInit(repo_service.Init) + mustInitCtx(ctx, repo_service.Init) // Booting long running goroutines. mustInit(indexer_service.Init) diff --git a/routers/install/install.go b/routers/install/install.go index 6d60dfdca39..3eb16b9ce85 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -536,7 +536,7 @@ func SubmitInstall(ctx *context.Context) { IsActive: util.OptionalBoolTrue, } - if err = user_model.CreateUser(u, overwriteDefault); err != nil { + if err = user_model.CreateUser(ctx, u, overwriteDefault); err != nil { if !user_model.IsErrUserAlreadyExist(err) { setting.InstallLock = false ctx.Data["Err_AdminName"] = true diff --git a/routers/install/routes_test.go b/routers/install/routes_test.go index fcbd0529774..2aa7f5d7b73 100644 --- a/routers/install/routes_test.go +++ b/routers/install/routes_test.go @@ -5,7 +5,6 @@ package install import ( "net/http/httptest" - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -35,7 +34,5 @@ func TestRoutes(t *testing.T) { } func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/private/actions.go b/routers/private/actions.go index 2403b9c41a0..74515256da9 100644 --- a/routers/private/actions.go +++ b/routers/private/actions.go @@ -41,8 +41,8 @@ func GenerateActionsRunnerToken(ctx *context.PrivateContext) { }) } - token, err := actions_model.GetUnactivatedRunnerToken(ctx, owner, repo) - if errors.Is(err, util.ErrNotExist) { + token, err := actions_model.GetLastestRunnerToken(ctx, owner, repo) + if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { token, err = actions_model.NewRunnerToken(ctx, owner, repo) if err != nil { err := fmt.Sprintf("error while creating runner token: %v", err) diff --git a/routers/private/default_branch.go b/routers/private/default_branch.go index b15d6ba33a4..a23e101e9d1 100644 --- a/routers/private/default_branch.go +++ b/routers/private/default_branch.go @@ -29,7 +29,7 @@ func SetDefaultBranch(ctx *gitea_context.PrivateContext) { } } - if err := repo_model.UpdateDefaultBranch(ctx.Repo.Repository); err != nil { + if err := repo_model.UpdateDefaultBranch(ctx, ctx.Repo.Repository); err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: fmt.Sprintf("Unable to set default branch on repository: %s/%s Error: %v", ownerName, repoName, err), }) diff --git a/routers/private/main_test.go b/routers/private/main_test.go index 700af6ec8d4..a6bec72b41d 100644 --- a/routers/private/main_test.go +++ b/routers/private/main_test.go @@ -4,14 +4,11 @@ package private import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index fe3e1d2206a..e34124049e7 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -182,7 +182,7 @@ func CronTasks(ctx *context.Context) { func MonitorStats(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.monitor.stats") ctx.Data["PageIsAdminMonitorStats"] = true - bs, err := json.Marshal(activities_model.GetStatistic().Counter) + bs, err := json.Marshal(activities_model.GetStatistic(ctx).Counter) if err != nil { ctx.ServerError("MonitorStats", err) return diff --git a/routers/web/admin/emails.go b/routers/web/admin/emails.go index 4618a78c3a7..59f80035d89 100644 --- a/routers/web/admin/emails.go +++ b/routers/web/admin/emails.go @@ -75,7 +75,7 @@ func Emails(ctx *context.Context) { } if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) { - baseEmails, count, err = user_model.SearchEmails(opts) + baseEmails, count, err = user_model.SearchEmails(ctx, opts) if err != nil { ctx.ServerError("SearchEmails", err) return @@ -121,7 +121,7 @@ func ActivateEmail(ctx *context.Context) { log.Info("Changing activation for User ID: %d, email: %s, primary: %v to %v", uid, email, primary, activate) - if err := user_model.ActivateUserEmail(uid, email, activate); err != nil { + if err := user_model.ActivateUserEmail(ctx, uid, email, activate); err != nil { log.Error("ActivateUserEmail(%v,%v,%v): %v", uid, email, activate, err) if user_model.IsErrEmailAlreadyUsed(err) { ctx.Flash.Error(ctx.Tr("admin.emails.duplicate_active")) diff --git a/routers/web/admin/main_test.go b/routers/web/admin/main_test.go index ea79830fa13..e1294ddbb40 100644 --- a/routers/web/admin/main_test.go +++ b/routers/web/admin/main_test.go @@ -4,14 +4,11 @@ package admin import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/admin/notice.go b/routers/web/admin/notice.go index 9e4588dd757..99039a2a9f9 100644 --- a/routers/web/admin/notice.go +++ b/routers/web/admin/notice.go @@ -24,13 +24,13 @@ func Notices(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("admin.notices") ctx.Data["PageIsAdminNotices"] = true - total := system_model.CountNotices() + total := system_model.CountNotices(ctx) page := ctx.FormInt("page") if page <= 1 { page = 1 } - notices, err := system_model.Notices(page, setting.UI.Admin.NoticePagingNum) + notices, err := system_model.Notices(ctx, page, setting.UI.Admin.NoticePagingNum) if err != nil { ctx.ServerError("Notices", err) return @@ -55,7 +55,7 @@ func DeleteNotices(ctx *context.Context) { } } - if err := system_model.DeleteNoticesByIDs(ids); err != nil { + if err := system_model.DeleteNoticesByIDs(ctx, ids); err != nil { ctx.Flash.Error("DeleteNoticesByIDs: " + err.Error()) ctx.Status(http.StatusInternalServerError) } else { @@ -66,7 +66,7 @@ func DeleteNotices(ctx *context.Context) { // EmptyNotices delete all the notices func EmptyNotices(ctx *context.Context) { - if err := system_model.DeleteNotices(0, 0); err != nil { + if err := system_model.DeleteNotices(ctx, 0, 0); err != nil { ctx.ServerError("DeleteNotices", err) return } diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index d0fd0d50025..ab44f8048bf 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -28,8 +28,9 @@ func Organizations(ctx *context.Context) { } explore.RenderUserSearch(ctx, &user_model.SearchUserOptions{ - Actor: ctx.Doer, - Type: user_model.UserTypeOrganization, + Actor: ctx.Doer, + Type: user_model.UserTypeOrganization, + IncludeReserved: true, // administrator needs to list all acounts include reserved ListOptions: db.ListOptions{ PageSize: setting.UI.Admin.OrgPagingNum, }, diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 8d4c29813ef..f4e1a93a22f 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -93,7 +93,7 @@ func DeletePackageVersion(ctx *context.Context) { return } - if err := packages_service.RemovePackageVersion(ctx.Doer, pv); err != nil { + if err := packages_service.RemovePackageVersion(ctx, ctx.Doer, pv); err != nil { ctx.ServerError("RemovePackageVersion", err) return } diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 47dff6e8520..4c6551501e4 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -77,6 +77,7 @@ func Users(ctx *context.Context) { IsRestricted: util.OptionalBoolParse(statusFilterMap["is_restricted"]), IsTwoFactorEnabled: util.OptionalBoolParse(statusFilterMap["is_2fa_enabled"]), IsProhibitLogin: util.OptionalBoolParse(statusFilterMap["is_prohibit_login"]), + IncludeReserved: true, // administrator needs to list all acounts include reserved, bot, remote ones ExtraParamStrings: extraParamStrings, }, tplUsers) } @@ -169,7 +170,7 @@ func NewUserPost(ctx *context.Context) { u.MustChangePassword = form.MustChangePassword } - if err := user_model.CreateUser(u, overwriteDefault); err != nil { + if err := user_model.CreateUser(ctx, u, overwriteDefault); err != nil { switch { case user_model.IsErrUserAlreadyExist(err): ctx.Data["Err_UserName"] = true @@ -237,12 +238,12 @@ func prepareUserInfo(ctx *context.Context) *user_model.User { } ctx.Data["Sources"] = sources - hasTOTP, err := auth.HasTwoFactorByUID(u.ID) + hasTOTP, err := auth.HasTwoFactorByUID(ctx, u.ID) if err != nil { ctx.ServerError("auth.HasTwoFactorByUID", err) return nil } - hasWebAuthn, err := auth.HasWebAuthnRegistrationsByUID(u.ID) + hasWebAuthn, err := auth.HasWebAuthnRegistrationsByUID(ctx, u.ID) if err != nil { ctx.ServerError("auth.HasWebAuthnRegistrationsByUID", err) return nil @@ -281,7 +282,7 @@ func ViewUser(ctx *context.Context) { ctx.Data["Repos"] = repos ctx.Data["ReposTotal"] = int(count) - emails, err := user_model.GetEmailAddresses(u.ID) + emails, err := user_model.GetEmailAddresses(ctx, u.ID) if err != nil { ctx.ServerError("GetEmailAddresses", err) return @@ -289,7 +290,7 @@ func ViewUser(ctx *context.Context) { ctx.Data["Emails"] = emails ctx.Data["EmailsTotal"] = len(emails) - orgs, err := org_model.FindOrgs(org_model.FindOrgOptions{ + orgs, err := org_model.FindOrgs(ctx, org_model.FindOrgOptions{ ListOptions: db.ListOptions{ ListAll: true, }, @@ -409,24 +410,24 @@ func EditUserPost(ctx *context.Context) { } if form.Reset2FA { - tf, err := auth.GetTwoFactorByUID(u.ID) + tf, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { ctx.ServerError("auth.GetTwoFactorByUID", err) return } else if tf != nil { - if err := auth.DeleteTwoFactorByID(tf.ID, u.ID); err != nil { + if err := auth.DeleteTwoFactorByID(ctx, tf.ID, u.ID); err != nil { ctx.ServerError("auth.DeleteTwoFactorByID", err) return } } - wn, err := auth.GetWebAuthnCredentialsByUID(u.ID) + wn, err := auth.GetWebAuthnCredentialsByUID(ctx, u.ID) if err != nil { ctx.ServerError("auth.GetTwoFactorByUID", err) return } for _, cred := range wn { - if _, err := auth.DeleteCredential(cred.ID, u.ID); err != nil { + if _, err := auth.DeleteCredential(ctx, cred.ID, u.ID); err != nil { ctx.ServerError("auth.DeleteCredential", err) return } diff --git a/routers/web/auth.go b/routers/web/auth.go deleted file mode 100644 index 1ca860ecc8d..00000000000 --- a/routers/web/auth.go +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -//go:build !windows - -package web - -import auth_service "code.gitea.io/gitea/services/auth" - -func specialAdd(group *auth_service.Group) {} diff --git a/routers/web/auth/2fa.go b/routers/web/auth/2fa.go index 4791b043131..bc3cb4907c7 100644 --- a/routers/web/auth/2fa.go +++ b/routers/web/auth/2fa.go @@ -53,7 +53,7 @@ func TwoFactorPost(ctx *context.Context) { } id := idSess.(int64) - twofa, err := auth.GetTwoFactorByUID(id) + twofa, err := auth.GetTwoFactorByUID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -75,7 +75,7 @@ func TwoFactorPost(ctx *context.Context) { } if ctx.Session.Get("linkAccount") != nil { - err = externalaccount.LinkAccountFromStore(ctx.Session, u) + err = externalaccount.LinkAccountFromStore(ctx, ctx.Session, u) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -83,7 +83,7 @@ func TwoFactorPost(ctx *context.Context) { } twofa.LastUsedPasscode = form.Passcode - if err = auth.UpdateTwoFactor(twofa); err != nil { + if err = auth.UpdateTwoFactor(ctx, twofa); err != nil { ctx.ServerError("UserSignIn", err) return } @@ -126,7 +126,7 @@ func TwoFactorScratchPost(ctx *context.Context) { } id := idSess.(int64) - twofa, err := auth.GetTwoFactorByUID(id) + twofa, err := auth.GetTwoFactorByUID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -140,7 +140,7 @@ func TwoFactorScratchPost(ctx *context.Context) { ctx.ServerError("UserSignIn", err) return } - if err = auth.UpdateTwoFactor(twofa); err != nil { + if err = auth.UpdateTwoFactor(ctx, twofa); err != nil { ctx.ServerError("UserSignIn", err) return } diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index dac8eb7afbb..8017602d990 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -199,7 +199,7 @@ func SignInPost(ctx *context.Context) { } } - u, source, err := auth_service.UserSignIn(form.UserName, form.Password) + u, source, err := auth_service.UserSignIn(ctx, form.UserName, form.Password) if err != nil { if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) { ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form) @@ -236,14 +236,14 @@ func SignInPost(ctx *context.Context) { // If this user is enrolled in 2FA TOTP, we can't sign the user in just yet. // Instead, redirect them to the 2FA authentication page. - hasTOTPtwofa, err := auth.HasTwoFactorByUID(u.ID) + hasTOTPtwofa, err := auth.HasTwoFactorByUID(ctx, u.ID) if err != nil { ctx.ServerError("UserSignIn", err) return } // Check if the user has webauthn registration - hasWebAuthnTwofa, err := auth.HasWebAuthnRegistrationsByUID(u.ID) + hasWebAuthnTwofa, err := auth.HasWebAuthnRegistrationsByUID(ctx, u.ID) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -509,15 +509,15 @@ func createAndHandleCreatedUser(ctx *context.Context, tpl base.TplName, form any // createUserInContext creates a user and handles errors within a given context. // Optionally a template can be specified. func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *user_model.User, overwrites *user_model.CreateUserOverwriteOptions, gothUser *goth.User, allowLink bool) (ok bool) { - if err := user_model.CreateUser(u, overwrites); err != nil { + if err := user_model.CreateUser(ctx, u, overwrites); err != nil { if allowLink && (user_model.IsErrUserAlreadyExist(err) || user_model.IsErrEmailAlreadyUsed(err)) { if setting.OAuth2Client.AccountLinking == setting.OAuth2AccountLinkingAuto { var user *user_model.User user = &user_model.User{Name: u.Name} - hasUser, err := user_model.GetUser(user) + hasUser, err := user_model.GetUser(ctx, user) if !hasUser || err != nil { user = &user_model.User{Email: u.Email} - hasUser, err = user_model.GetUser(user) + hasUser, err = user_model.GetUser(ctx, user) if !hasUser || err != nil { ctx.ServerError("UserLinkAccount", err) return false @@ -576,7 +576,7 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form any, u *us // sends a confirmation email if required. func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.User) (ok bool) { // Auto-set admin for the only user. - if user_model.CountUsers(nil) == 1 { + if user_model.CountUsers(ctx, nil) == 1 { u.IsAdmin = true u.IsActive = true u.SetLastLogin() @@ -652,7 +652,7 @@ func Activate(ctx *context.Context) { return } - user := user_model.VerifyUserActiveCode(code) + user := user_model.VerifyUserActiveCode(ctx, code) // if code is wrong if user == nil { ctx.Data["IsCodeInvalid"] = true @@ -679,7 +679,7 @@ func ActivatePost(ctx *context.Context) { return } - user := user_model.VerifyUserActiveCode(code) + user := user_model.VerifyUserActiveCode(ctx, code) // if code is wrong if user == nil { ctx.Data["IsCodeInvalid"] = true @@ -722,7 +722,7 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) { return } - if err := user_model.ActivateUserEmail(user.ID, user.Email, true); err != nil { + if err := user_model.ActivateUserEmail(ctx, user.ID, user.Email, true); err != nil { log.Error("Unable to activate email for user: %-v with email: %s: %v", user, user.Email, err) ctx.ServerError("ActivateUserEmail", err) return @@ -767,8 +767,8 @@ func ActivateEmail(ctx *context.Context) { emailStr := ctx.FormString("email") // Verify code. - if email := user_model.VerifyActiveEmailCode(code, emailStr); email != nil { - if err := user_model.ActivateEmail(email); err != nil { + if email := user_model.VerifyActiveEmailCode(ctx, code, emailStr); email != nil { + if err := user_model.ActivateEmail(ctx, email); err != nil { ctx.ServerError("ActivateEmail", err) } diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index 0f7ecf1af49..42d846180d6 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -142,7 +142,7 @@ func LinkAccountPostSignIn(ctx *context.Context) { return } - u, _, err := auth_service.UserSignIn(signInForm.UserName, signInForm.Password) + u, _, err := auth_service.UserSignIn(ctx, signInForm.UserName, signInForm.Password) if err != nil { handleSignInError(ctx, signInForm.UserName, &signInForm, tplLinkAccount, "UserLinkAccount", err) return @@ -157,14 +157,14 @@ func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, r // If this user is enrolled in 2FA, we can't sign the user in just yet. // Instead, redirect them to the 2FA authentication page. // We deliberately ignore the skip local 2fa setting here because we are linking to a previous user here - _, err := auth.GetTwoFactorByUID(u.ID) + _, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil { if !auth.IsErrTwoFactorNotEnrolled(err) { ctx.ServerError("UserLinkAccount", err) return } - err = externalaccount.LinkAccountToUser(u, gothUser) + err = externalaccount.LinkAccountToUser(ctx, u, gothUser) if err != nil { ctx.ServerError("UserLinkAccount", err) return @@ -185,7 +185,7 @@ func linkAccount(ctx *context.Context, u *user_model.User, gothUser goth.User, r } // If WebAuthn is enrolled -> Redirect to WebAuthn instead - regs, err := auth.GetWebAuthnCredentialsByUID(u.ID) + regs, err := auth.GetWebAuthnCredentialsByUID(ctx, u.ID) if err == nil && len(regs) > 0 { ctx.Redirect(setting.AppSubURL + "/user/webauthn") return diff --git a/routers/web/auth/main_test.go b/routers/web/auth/main_test.go index 8295515ba95..b438e5d5188 100644 --- a/routers/web/auth/main_test.go +++ b/routers/web/auth/main_test.go @@ -4,14 +4,11 @@ package auth import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 78dc84472a1..ce58cbdef99 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -237,7 +237,7 @@ func newAccessTokenResponse(ctx go_context.Context, grant *auth.OAuth2Grant, ser idToken.EmailVerified = user.IsActive } if grant.ScopeContains("groups") { - groups, err := getOAuthGroupsForUser(user) + groups, err := getOAuthGroupsForUser(ctx, user) if err != nil { log.Error("Error getting groups: %v", err) return nil, &AccessTokenError{ @@ -291,7 +291,7 @@ func InfoOAuth(ctx *context.Context) { Picture: ctx.Doer.AvatarLink(ctx), } - groups, err := getOAuthGroupsForUser(ctx.Doer) + groups, err := getOAuthGroupsForUser(ctx, ctx.Doer) if err != nil { ctx.ServerError("Oauth groups for user", err) return @@ -303,8 +303,8 @@ func InfoOAuth(ctx *context.Context) { // returns a list of "org" and "org:team" strings, // that the given user is a part of. -func getOAuthGroupsForUser(user *user_model.User) ([]string, error) { - orgs, err := org_model.GetUserOrgsList(user) +func getOAuthGroupsForUser(ctx go_context.Context, user *user_model.User) ([]string, error) { + orgs, err := org_model.GetUserOrgsList(ctx, user) if err != nil { return nil, fmt.Errorf("GetUserOrgList: %w", err) } @@ -312,12 +312,12 @@ func getOAuthGroupsForUser(user *user_model.User) ([]string, error) { var groups []string for _, org := range orgs { groups = append(groups, org.Name) - teams, err := org.LoadTeams() + teams, err := org.LoadTeams(ctx) if err != nil { return nil, fmt.Errorf("LoadTeams: %w", err) } for _, team := range teams { - if team.IsMember(user.ID) { + if team.IsMember(ctx, user.ID) { groups = append(groups, org.Name+":"+team.LowerName) } } @@ -859,7 +859,7 @@ func SignInOAuth(ctx *context.Context) { } // try to do a direct callback flow, so we don't authenticate the user again but use the valid accesstoken to get the user - user, gothUser, err := oAuth2UserLoginCallback(authSource, ctx.Req, ctx.Resp) + user, gothUser, err := oAuth2UserLoginCallback(ctx, authSource, ctx.Req, ctx.Resp) if err == nil && user != nil { // we got the user without going through the whole OAuth2 authentication flow again handleOAuth2SignIn(ctx, authSource, user, gothUser) @@ -909,7 +909,7 @@ func SignInOAuthCallback(ctx *context.Context) { return } - u, gothUser, err := oAuth2UserLoginCallback(authSource, ctx.Req, ctx.Resp) + u, gothUser, err := oAuth2UserLoginCallback(ctx, authSource, ctx.Req, ctx.Resp) if err != nil { if user_model.IsErrUserProhibitLogin(err) { uplerr := err.(user_model.ErrUserProhibitLogin) @@ -941,7 +941,7 @@ func SignInOAuthCallback(ctx *context.Context) { if u == nil { if ctx.Doer != nil { // attach user to already logged in user - err = externalaccount.LinkAccountToUser(ctx.Doer, gothUser) + err = externalaccount.LinkAccountToUser(ctx, ctx.Doer, gothUser) if err != nil { ctx.ServerError("UserLinkAccount", err) return @@ -1097,7 +1097,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model needs2FA := false if !source.Cfg.(*oauth2.Source).SkipLocalTwoFA { - _, err := auth.GetTwoFactorByUID(u.ID) + _, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { ctx.ServerError("UserSignIn", err) return @@ -1197,7 +1197,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model } // If WebAuthn is enrolled -> Redirect to WebAuthn instead - regs, err := auth.GetWebAuthnCredentialsByUID(u.ID) + regs, err := auth.GetWebAuthnCredentialsByUID(ctx, u.ID) if err == nil && len(regs) > 0 { ctx.Redirect(setting.AppSubURL + "/user/webauthn") return @@ -1208,7 +1208,7 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model // OAuth2UserLoginCallback attempts to handle the callback from the OAuth2 provider and if successful // login the user -func oAuth2UserLoginCallback(authSource *auth.Source, request *http.Request, response http.ResponseWriter) (*user_model.User, goth.User, error) { +func oAuth2UserLoginCallback(ctx *context.Context, authSource *auth.Source, request *http.Request, response http.ResponseWriter) (*user_model.User, goth.User, error) { oauth2Source := authSource.Cfg.(*oauth2.Source) // Make sure that the response is not an error response. @@ -1260,7 +1260,7 @@ func oAuth2UserLoginCallback(authSource *auth.Source, request *http.Request, res LoginSource: authSource.ID, } - hasUser, err := user_model.GetUser(user) + hasUser, err := user_model.GetUser(ctx, user) if err != nil { return nil, goth.User{}, err } diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 00fc17f0980..aa071296325 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -157,7 +157,7 @@ func signInOpenIDVerify(ctx *context.Context) { /* Now we should seek for the user and log him in, or prompt * to register if not found */ - u, err := user_model.GetUserByOpenID(id) + u, err := user_model.GetUserByOpenID(ctx, id) if err != nil { if !user_model.IsErrUserNotExist(err) { ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ @@ -280,7 +280,7 @@ func ConnectOpenIDPost(ctx *context.Context) { ctx.Data["EnableOpenIDSignUp"] = setting.Service.EnableOpenIDSignUp ctx.Data["OpenID"] = oid - u, _, err := auth.UserSignIn(form.UserName, form.Password) + u, _, err := auth.UserSignIn(ctx, form.UserName, form.Password) if err != nil { handleSignInError(ctx, form.UserName, &form, tplConnectOID, "ConnectOpenIDPost", err) return diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index 1432338e708..bdfa8c40258 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -114,13 +114,13 @@ func commonResetPassword(ctx *context.Context) (*user_model.User, *auth.TwoFacto } // Fail early, don't frustrate the user - u := user_model.VerifyUserActiveCode(code) + u := user_model.VerifyUserActiveCode(ctx, code) if u == nil { ctx.Flash.Error(ctx.Tr("auth.invalid_code_forgot_password", fmt.Sprintf("%s/user/forgot_password", setting.AppSubURL)), true) return nil, nil } - twofa, err := auth.GetTwoFactorByUID(u.ID) + twofa, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil { if !auth.IsErrTwoFactorNotEnrolled(err) { ctx.Error(http.StatusInternalServerError, "CommonResetPassword", err.Error()) @@ -217,7 +217,7 @@ func ResetPasswdPost(ctx *context.Context) { } twofa.LastUsedPasscode = passcode - if err = auth.UpdateTwoFactor(twofa); err != nil { + if err = auth.UpdateTwoFactor(ctx, twofa); err != nil { ctx.ServerError("ResetPasswdPost: UpdateTwoFactor", err) return } @@ -249,7 +249,7 @@ func ResetPasswdPost(ctx *context.Context) { ctx.ServerError("UserSignIn", err) return } - if err = auth.UpdateTwoFactor(twofa); err != nil { + if err = auth.UpdateTwoFactor(ctx, twofa); err != nil { ctx.ServerError("UserSignIn", err) return } diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go index 013e11eacce..88413caea69 100644 --- a/routers/web/auth/webauthn.go +++ b/routers/web/auth/webauthn.go @@ -55,7 +55,7 @@ func WebAuthnLoginAssertion(ctx *context.Context) { return } - exists, err := auth.ExistsWebAuthnCredentialsForUID(user.ID) + exists, err := auth.ExistsWebAuthnCredentialsForUID(ctx, user.ID) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -127,21 +127,21 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) { } // Success! Get the credential and update the sign count with the new value we received. - dbCred, err := auth.GetWebAuthnCredentialByCredID(user.ID, cred.ID) + dbCred, err := auth.GetWebAuthnCredentialByCredID(ctx, user.ID, cred.ID) if err != nil { ctx.ServerError("GetWebAuthnCredentialByCredID", err) return } dbCred.SignCount = cred.Authenticator.SignCount - if err := dbCred.UpdateSignCount(); err != nil { + if err := dbCred.UpdateSignCount(ctx); err != nil { ctx.ServerError("UpdateSignCount", err) return } // Now handle account linking if that's requested if ctx.Session.Get("linkAccount") != nil { - if err := externalaccount.LinkAccountFromStore(ctx.Session, user); err != nil { + if err := externalaccount.LinkAccountFromStore(ctx, ctx.Session, user); err != nil { ctx.ServerError("LinkAccountFromStore", err) return } diff --git a/routers/web/auth_windows.go b/routers/web/auth_windows.go deleted file mode 100644 index 3125d7ce9a7..00000000000 --- a/routers/web/auth_windows.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2022 The Gitea Authors. All rights reserved. -// SPDX-License-Identifier: MIT - -package web - -import ( - "code.gitea.io/gitea/models/auth" - auth_service "code.gitea.io/gitea/services/auth" -) - -// specialAdd registers the SSPI auth method as the last method in the list. -// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation -// fails (or if negotiation should continue), which would prevent other authentication methods -// to execute at all. -func specialAdd(group *auth_service.Group) { - if auth.IsSSPIEnabled() { - group.Add(&auth_service.SSPI{}) - } -} diff --git a/routers/web/explore/topic.go b/routers/web/explore/topic.go index 132ef23fa75..bb1be310de7 100644 --- a/routers/web/explore/topic.go +++ b/routers/web/explore/topic.go @@ -23,7 +23,7 @@ func TopicSearch(ctx *context.Context) { }, } - topics, total, err := repo_model.FindTopics(opts) + topics, total, err := repo_model.FindTopics(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError) return diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index a2b5f800994..c760004088e 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -87,7 +87,7 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, opts.Keyword = ctx.FormTrim("q") opts.OrderBy = orderBy if len(opts.Keyword) == 0 || isKeywordValid(opts.Keyword) { - users, count, err = user_model.SearchUsers(opts) + users, count, err = user_model.SearchUsers(ctx, opts) if err != nil { ctx.ServerError("SearchUsers", err) return @@ -108,7 +108,7 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, ctx.Data["Keyword"] = opts.Keyword ctx.Data["Total"] = count ctx.Data["Users"] = users - ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus() + ctx.Data["UsersTwoFaStatus"] = user_model.UserList(users).GetTwoFaStatus(ctx) ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go index 3775ba495a0..04078955bbd 100644 --- a/routers/web/feed/convert.go +++ b/routers/web/feed/convert.go @@ -23,28 +23,28 @@ import ( "github.com/gorilla/feeds" ) -func toBranchLink(act *activities_model.Action) string { - return act.GetRepoAbsoluteLink() + "/src/branch/" + util.PathEscapeSegments(act.GetBranch()) +func toBranchLink(ctx *context.Context, act *activities_model.Action) string { + return act.GetRepoAbsoluteLink(ctx) + "/src/branch/" + util.PathEscapeSegments(act.GetBranch()) } -func toTagLink(act *activities_model.Action) string { - return act.GetRepoAbsoluteLink() + "/src/tag/" + util.PathEscapeSegments(act.GetTag()) +func toTagLink(ctx *context.Context, act *activities_model.Action) string { + return act.GetRepoAbsoluteLink(ctx) + "/src/tag/" + util.PathEscapeSegments(act.GetTag()) } -func toIssueLink(act *activities_model.Action) string { - return act.GetRepoAbsoluteLink() + "/issues/" + url.PathEscape(act.GetIssueInfos()[0]) +func toIssueLink(ctx *context.Context, act *activities_model.Action) string { + return act.GetRepoAbsoluteLink(ctx) + "/issues/" + url.PathEscape(act.GetIssueInfos()[0]) } -func toPullLink(act *activities_model.Action) string { - return act.GetRepoAbsoluteLink() + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0]) +func toPullLink(ctx *context.Context, act *activities_model.Action) string { + return act.GetRepoAbsoluteLink(ctx) + "/pulls/" + url.PathEscape(act.GetIssueInfos()[0]) } -func toSrcLink(act *activities_model.Action) string { - return act.GetRepoAbsoluteLink() + "/src/" + util.PathEscapeSegments(act.GetBranch()) +func toSrcLink(ctx *context.Context, act *activities_model.Action) string { + return act.GetRepoAbsoluteLink(ctx) + "/src/" + util.PathEscapeSegments(act.GetBranch()) } -func toReleaseLink(act *activities_model.Action) string { - return act.GetRepoAbsoluteLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch()) +func toReleaseLink(ctx *context.Context, act *activities_model.Action) string { + return act.GetRepoAbsoluteLink(ctx) + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch()) } // renderMarkdown creates a minimal markdown render context from an action. @@ -52,11 +52,11 @@ func toReleaseLink(act *activities_model.Action) string { func renderMarkdown(ctx *context.Context, act *activities_model.Action, content string) string { markdownCtx := &markup.RenderContext{ Ctx: ctx, - URLPrefix: act.GetRepoLink(), + URLPrefix: act.GetRepoLink(ctx), Type: markdown.MarkupName, Metas: map[string]string{ - "user": act.GetRepoUserName(), - "repo": act.GetRepoName(), + "user": act.GetRepoUserName(ctx), + "repo": act.GetRepoName(ctx), }, } markdown, err := markdown.RenderString(markdownCtx, content) @@ -73,123 +73,123 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio var content, desc, title string - link := &feeds.Link{Href: act.GetCommentHTMLURL()} + link := &feeds.Link{Href: act.GetCommentHTMLURL(ctx)} // title title = act.ActUser.DisplayName() + " " switch act.OpType { case activities_model.ActionCreateRepo: - title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoAbsoluteLink(), act.ShortRepoPath()) - link.Href = act.GetRepoAbsoluteLink() + title += ctx.TrHTMLEscapeArgs("action.create_repo", act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx)) + link.Href = act.GetRepoAbsoluteLink(ctx) case activities_model.ActionRenameRepo: - title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(), act.ShortRepoPath()) - link.Href = act.GetRepoAbsoluteLink() + title += ctx.TrHTMLEscapeArgs("action.rename_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx)) + link.Href = act.GetRepoAbsoluteLink(ctx) case activities_model.ActionCommitRepo: - link.Href = toBranchLink(act) + link.Href = toBranchLink(ctx, act) if len(act.Content) != 0 { - title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoAbsoluteLink(), link.Href, act.GetBranch(), act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.commit_repo", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx)) } else { - title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoAbsoluteLink(), link.Href, act.GetBranch(), act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.create_branch", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetBranch(), act.ShortRepoPath(ctx)) } case activities_model.ActionCreateIssue: - link.Href = toIssueLink(act) - title += ctx.TrHTMLEscapeArgs("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath()) + link.Href = toIssueLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.create_issue", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionCreatePullRequest: - link.Href = toPullLink(act) - title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath()) + link.Href = toPullLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.create_pull_request", link.Href, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionTransferRepo: - link.Href = act.GetRepoAbsoluteLink() - title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(), act.ShortRepoPath()) + link.Href = act.GetRepoAbsoluteLink(ctx) + title += ctx.TrHTMLEscapeArgs("action.transfer_repo", act.GetContent(), act.GetRepoAbsoluteLink(ctx), act.ShortRepoPath(ctx)) case activities_model.ActionPushTag: - link.Href = toTagLink(act) - title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoAbsoluteLink(), link.Href, act.GetTag(), act.ShortRepoPath()) + link.Href = toTagLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.push_tag", act.GetRepoAbsoluteLink(ctx), link.Href, act.GetTag(), act.ShortRepoPath(ctx)) case activities_model.ActionCommentIssue: - issueLink := toIssueLink(act) + issueLink := toIssueLink(ctx, act) if link.Href == "#" { link.Href = issueLink } - title += ctx.TrHTMLEscapeArgs("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.comment_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionMergePullRequest: - pullLink := toPullLink(act) + pullLink := toPullLink(ctx, act) if link.Href == "#" { link.Href = pullLink } - title += ctx.TrHTMLEscapeArgs("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionAutoMergePullRequest: - pullLink := toPullLink(act) + pullLink := toPullLink(ctx, act) if link.Href == "#" { link.Href = pullLink } - title += ctx.TrHTMLEscapeArgs("action.auto_merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.auto_merge_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionCloseIssue: - issueLink := toIssueLink(act) + issueLink := toIssueLink(ctx, act) if link.Href == "#" { link.Href = issueLink } - title += ctx.TrHTMLEscapeArgs("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.close_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionReopenIssue: - issueLink := toIssueLink(act) + issueLink := toIssueLink(ctx, act) if link.Href == "#" { link.Href = issueLink } - title += ctx.TrHTMLEscapeArgs("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.reopen_issue", issueLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionClosePullRequest: - pullLink := toPullLink(act) + pullLink := toPullLink(ctx, act) if link.Href == "#" { link.Href = pullLink } - title += ctx.TrHTMLEscapeArgs("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.close_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionReopenPullRequest: - pullLink := toPullLink(act) + pullLink := toPullLink(ctx, act) if link.Href == "#" { link.Href = pullLink } - title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.reopen_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionDeleteTag: - link.Href = act.GetRepoAbsoluteLink() - title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoAbsoluteLink(), act.GetTag(), act.ShortRepoPath()) + link.Href = act.GetRepoAbsoluteLink(ctx) + title += ctx.TrHTMLEscapeArgs("action.delete_tag", act.GetRepoAbsoluteLink(ctx), act.GetTag(), act.ShortRepoPath(ctx)) case activities_model.ActionDeleteBranch: - link.Href = act.GetRepoAbsoluteLink() - title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoAbsoluteLink(), html.EscapeString(act.GetBranch()), act.ShortRepoPath()) + link.Href = act.GetRepoAbsoluteLink(ctx) + title += ctx.TrHTMLEscapeArgs("action.delete_branch", act.GetRepoAbsoluteLink(ctx), html.EscapeString(act.GetBranch()), act.ShortRepoPath(ctx)) case activities_model.ActionMirrorSyncPush: - srcLink := toSrcLink(act) + srcLink := toSrcLink(ctx, act) if link.Href == "#" { link.Href = srcLink } - title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoAbsoluteLink(), srcLink, act.GetBranch(), act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.mirror_sync_push", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx)) case activities_model.ActionMirrorSyncCreate: - srcLink := toSrcLink(act) + srcLink := toSrcLink(ctx, act) if link.Href == "#" { link.Href = srcLink } - title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoAbsoluteLink(), srcLink, act.GetBranch(), act.ShortRepoPath()) + title += ctx.TrHTMLEscapeArgs("action.mirror_sync_create", act.GetRepoAbsoluteLink(ctx), srcLink, act.GetBranch(), act.ShortRepoPath(ctx)) case activities_model.ActionMirrorSyncDelete: - link.Href = act.GetRepoAbsoluteLink() - title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoAbsoluteLink(), act.GetBranch(), act.ShortRepoPath()) + link.Href = act.GetRepoAbsoluteLink(ctx) + title += ctx.TrHTMLEscapeArgs("action.mirror_sync_delete", act.GetRepoAbsoluteLink(ctx), act.GetBranch(), act.ShortRepoPath(ctx)) case activities_model.ActionApprovePullRequest: - pullLink := toPullLink(act) - title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + pullLink := toPullLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.approve_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionRejectPullRequest: - pullLink := toPullLink(act) - title += ctx.TrHTMLEscapeArgs("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + pullLink := toPullLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.reject_pull_request", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionCommentPull: - pullLink := toPullLink(act) - title += ctx.TrHTMLEscapeArgs("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath()) + pullLink := toPullLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.comment_pull", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx)) case activities_model.ActionPublishRelease: - releaseLink := toReleaseLink(act) + releaseLink := toReleaseLink(ctx, act) if link.Href == "#" { link.Href = releaseLink } - title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoAbsoluteLink(), releaseLink, act.ShortRepoPath(), act.Content) + title += ctx.TrHTMLEscapeArgs("action.publish_release", act.GetRepoAbsoluteLink(ctx), releaseLink, act.ShortRepoPath(ctx), act.Content) case activities_model.ActionPullReviewDismissed: - pullLink := toPullLink(act) - title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(), act.GetIssueInfos()[1]) + pullLink := toPullLink(ctx, act) + title += ctx.TrHTMLEscapeArgs("action.review_dismissed", pullLink, act.GetIssueInfos()[0], act.ShortRepoPath(ctx), act.GetIssueInfos()[1]) case activities_model.ActionStarRepo: - link.Href = act.GetRepoAbsoluteLink() - title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoAbsoluteLink(), act.GetRepoPath()) + link.Href = act.GetRepoAbsoluteLink(ctx) + title += ctx.TrHTMLEscapeArgs("action.starred_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx)) case activities_model.ActionWatchRepo: - link.Href = act.GetRepoAbsoluteLink() - title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoAbsoluteLink(), act.GetRepoPath()) + link.Href = act.GetRepoAbsoluteLink(ctx) + title += ctx.TrHTMLEscapeArgs("action.watched_repo", act.GetRepoAbsoluteLink(ctx), act.GetRepoPath(ctx)) default: return nil, fmt.Errorf("unknown action type: %v", act.OpType) } @@ -199,14 +199,14 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio switch act.OpType { case activities_model.ActionCommitRepo, activities_model.ActionMirrorSyncPush: push := templates.ActionContent2Commits(act) - repoLink := act.GetRepoAbsoluteLink() + repoLink := act.GetRepoAbsoluteLink(ctx) for _, commit := range push.Commits { if len(desc) != 0 { desc += "\n\n" } desc += fmt.Sprintf("%s\n%s", - html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(), commit.Sha1)), + html.EscapeString(fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(ctx), commit.Sha1)), commit.Sha1, templates.RenderCommitMessage(ctx, commit.Message, repoLink, nil), ) @@ -215,14 +215,14 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio if push.Len > 1 { link = &feeds.Link{Href: fmt.Sprintf("%s/%s", setting.AppSubURL, push.CompareURL)} } else if push.Len == 1 { - link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(), push.Commits[0].Sha1)} + link = &feeds.Link{Href: fmt.Sprintf("%s/commit/%s", act.GetRepoAbsoluteLink(ctx), push.Commits[0].Sha1)} } case activities_model.ActionCreateIssue, activities_model.ActionCreatePullRequest: desc = strings.Join(act.GetIssueInfos(), "#") content = renderMarkdown(ctx, act, act.GetIssueContent(ctx)) case activities_model.ActionCommentIssue, activities_model.ActionApprovePullRequest, activities_model.ActionRejectPullRequest, activities_model.ActionCommentPull: - desc = act.GetIssueTitle() + desc = act.GetIssueTitle(ctx) comment := act.GetIssueInfos()[1] if len(comment) != 0 { desc += "\n\n" + renderMarkdown(ctx, act, comment) @@ -230,7 +230,7 @@ func feedActionsToFeedItems(ctx *context.Context, actions activities_model.Actio case activities_model.ActionMergePullRequest, activities_model.ActionAutoMergePullRequest: desc = act.GetIssueInfos()[1] case activities_model.ActionCloseIssue, activities_model.ActionReopenIssue, activities_model.ActionClosePullRequest, activities_model.ActionReopenPullRequest: - desc = act.GetIssueTitle() + desc = act.GetIssueTitle(ctx) case activities_model.ActionPullReviewDismissed: desc = ctx.Tr("action.review_dismissed_reason") + "\n\n" + act.GetIssueInfos()[2] } diff --git a/routers/web/home.go b/routers/web/home.go index b94e3e9eb59..ab3fbde2c9a 100644 --- a/routers/web/home.go +++ b/routers/web/home.go @@ -69,7 +69,7 @@ func Home(ctx *context.Context) { func HomeSitemap(ctx *context.Context) { m := sitemap.NewSitemapIndex() if !setting.Service.Explore.DisableUsersPage { - _, cnt, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + _, cnt, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Type: user_model.UserTypeIndividual, ListOptions: db.ListOptions{PageSize: 1}, IsActive: util.OptionalBoolTrue, diff --git a/routers/web/org/home.go b/routers/web/org/home.go index a69fdedba46..ec866eb6b3b 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -123,7 +123,7 @@ func Home(ctx *context.Context) { PublicOnly: ctx.Org.PublicMemberOnly, ListOptions: db.ListOptions{Page: 1, PageSize: 25}, } - members, _, err := organization.FindOrgMembers(opts) + members, _, err := organization.FindOrgMembers(ctx, opts) if err != nil { ctx.ServerError("FindOrgMembers", err) return @@ -131,7 +131,7 @@ func Home(ctx *context.Context) { var isFollowing bool if ctx.Doer != nil { - isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID) + isFollowing = user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) } ctx.Data["Repos"] = repos diff --git a/routers/web/org/main_test.go b/routers/web/org/main_test.go index 41323a3601e..92237d6e884 100644 --- a/routers/web/org/main_test.go +++ b/routers/web/org/main_test.go @@ -4,14 +4,11 @@ package org_test import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/org/members.go b/routers/web/org/members.go index f963ad55efd..247025a7cb7 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -38,7 +38,7 @@ func Members(ctx *context.Context) { } if ctx.Doer != nil { - isMember, err := ctx.Org.Organization.IsOrgMember(ctx.Doer.ID) + isMember, err := ctx.Org.Organization.IsOrgMember(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsOrgMember") return @@ -47,7 +47,7 @@ func Members(ctx *context.Context) { } ctx.Data["PublicOnly"] = opts.PublicOnly - total, err := organization.CountOrgMembers(opts) + total, err := organization.CountOrgMembers(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "CountOrgMembers") return @@ -62,7 +62,7 @@ func Members(ctx *context.Context) { pager := context.NewPagination(int(total), setting.UI.MembersPagingNum, page, 5) opts.ListOptions.Page = page opts.ListOptions.PageSize = setting.UI.MembersPagingNum - members, membersIsPublic, err := organization.FindOrgMembers(opts) + members, membersIsPublic, err := organization.FindOrgMembers(ctx, opts) if err != nil { ctx.ServerError("GetMembers", err) return @@ -70,8 +70,8 @@ func Members(ctx *context.Context) { ctx.Data["Page"] = pager ctx.Data["Members"] = members ctx.Data["MembersIsPublicMember"] = membersIsPublic - ctx.Data["MembersIsUserOrgOwner"] = organization.IsUserOrgOwner(members, org.ID) - ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus() + ctx.Data["MembersIsUserOrgOwner"] = organization.IsUserOrgOwner(ctx, members, org.ID) + ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus(ctx) ctx.HTML(http.StatusOK, tplMembers) } @@ -92,13 +92,13 @@ func MembersAction(ctx *context.Context) { ctx.Error(http.StatusNotFound) return } - err = organization.ChangeOrgUserStatus(org.ID, uid, false) + err = organization.ChangeOrgUserStatus(ctx, org.ID, uid, false) case "public": if ctx.Doer.ID != uid && !ctx.Org.IsOwner { ctx.Error(http.StatusNotFound) return } - err = organization.ChangeOrgUserStatus(org.ID, uid, true) + err = organization.ChangeOrgUserStatus(ctx, org.ID, uid, true) case "remove": if !ctx.Org.IsOwner { ctx.Error(http.StatusNotFound) diff --git a/routers/web/org/org.go b/routers/web/org/org.go index f67e7edb4c7..52f8df8a1c7 100644 --- a/routers/web/org/org.go +++ b/routers/web/org/org.go @@ -58,7 +58,7 @@ func CreatePost(ctx *context.Context) { RepoAdminChangeTeamAccess: form.RepoAdminChangeTeamAccess, } - if err := organization.CreateOrganization(org, ctx.Doer); err != nil { + if err := organization.CreateOrganization(ctx, org, ctx.Doer); err != nil { ctx.Data["Err_OrgName"] = true switch { case user_model.IsErrUserAlreadyExist(err): diff --git a/routers/web/org/org_labels.go b/routers/web/org/org_labels.go index 2c7725e38da..f78bd002742 100644 --- a/routers/web/org/org_labels.go +++ b/routers/web/org/org_labels.go @@ -76,7 +76,7 @@ func UpdateLabel(ctx *context.Context) { l.Description = form.Description l.Color = form.Color l.SetArchived(form.IsArchived) - if err := issues_model.UpdateLabel(l); err != nil { + if err := issues_model.UpdateLabel(ctx, l); err != nil { ctx.ServerError("UpdateLabel", err) return } @@ -85,7 +85,7 @@ func UpdateLabel(ctx *context.Context) { // DeleteLabel delete a label func DeleteLabel(ctx *context.Context) { - if err := issues_model.DeleteLabel(ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil { + if err := issues_model.DeleteLabel(ctx, ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteLabel: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success")) diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 4032162b5cf..19d3682f518 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -179,7 +179,7 @@ func NewProjectPost(ctx *context.Context) { newProject.Type = project_model.TypeIndividual } - if err := project_model.NewProject(&newProject); err != nil { + if err := project_model.NewProject(ctx, &newProject); err != nil { ctx.ServerError("NewProject", err) return } @@ -201,7 +201,7 @@ func ChangeProjectStatus(ctx *context.Context) { } id := ctx.ParamsInt64(":id") - if err := project_model.ChangeProjectStatusByRepoIDAndID(0, id, toClose); err != nil { + if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, 0, id, toClose); err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", err) } else { @@ -320,7 +320,7 @@ func EditProjectPost(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("repo.projects.edit_success", p.Title)) if ctx.FormString("redirect") == "project" { - ctx.Redirect(p.Link()) + ctx.Redirect(p.Link(ctx)) } else { ctx.Redirect(ctx.ContextUser.HomeLink() + "/-/projects") } @@ -515,7 +515,7 @@ func DeleteProjectBoard(ctx *context.Context) { return } - if err := project_model.DeleteBoardByID(ctx.ParamsInt64(":boardID")); err != nil { + if err := project_model.DeleteBoardByID(ctx, ctx.ParamsInt64(":boardID")); err != nil { ctx.ServerError("DeleteProjectBoardByID", err) return } @@ -537,7 +537,7 @@ func AddBoardToProjectPost(ctx *context.Context) { return } - if err := project_model.NewBoard(&project_model.Board{ + if err := project_model.NewBoard(ctx, &project_model.Board{ ProjectID: project.ID, Title: form.Title, Color: form.Color, @@ -623,7 +623,7 @@ func SetDefaultProjectBoard(ctx *context.Context) { return } - if err := project_model.SetDefaultBoard(project.ID, board.ID); err != nil { + if err := project_model.SetDefaultBoard(ctx, project.ID, board.ID); err != nil { ctx.ServerError("SetDefaultBoard", err) return } @@ -638,7 +638,7 @@ func UnsetDefaultProjectBoard(ctx *context.Context) { return } - if err := project_model.SetDefaultBoard(project.ID, 0); err != nil { + if err := project_model.SetDefaultBoard(ctx, project.ID, 0); err != nil { ctx.ServerError("SetDefaultBoard", err) return } @@ -738,7 +738,7 @@ func MoveIssues(ctx *context.Context) { } } - if err = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil { + if err = project_model.MoveIssuesOnProjectBoard(ctx, board, sortedIssueIDs); err != nil { ctx.ServerError("MoveIssuesOnProjectBoard", err) return } diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 2fd2a681af4..98014d99a6f 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -78,9 +78,9 @@ func TeamsAction(ctx *context.Context) { ctx.Error(http.StatusNotFound) return } - err = models.AddTeamMember(ctx.Org.Team, ctx.Doer.ID) + err = models.AddTeamMember(ctx, ctx.Org.Team, ctx.Doer.ID) case "leave": - err = models.RemoveTeamMember(ctx.Org.Team, ctx.Doer.ID) + err = models.RemoveTeamMember(ctx, ctx.Org.Team, ctx.Doer.ID) if err != nil { if org_model.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) @@ -107,7 +107,7 @@ func TeamsAction(ctx *context.Context) { return } - err = models.RemoveTeamMember(ctx.Org.Team, uid) + err = models.RemoveTeamMember(ctx, ctx.Org.Team, uid) if err != nil { if org_model.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) @@ -159,10 +159,10 @@ func TeamsAction(ctx *context.Context) { return } - if ctx.Org.Team.IsMember(u.ID) { + if ctx.Org.Team.IsMember(ctx, u.ID) { ctx.Flash.Error(ctx.Tr("org.teams.add_duplicate_users")) } else { - err = models.AddTeamMember(ctx.Org.Team, u.ID) + err = models.AddTeamMember(ctx, ctx.Org.Team, u.ID) } page = "team" @@ -247,13 +247,13 @@ func TeamsRepoAction(ctx *context.Context) { ctx.ServerError("GetRepositoryByName", err) return } - err = org_service.TeamAddRepository(ctx.Org.Team, repo) + err = org_service.TeamAddRepository(ctx, ctx.Org.Team, repo) case "remove": err = repo_service.RemoveRepositoryFromTeam(ctx, ctx.Org.Team, ctx.FormInt64("repoid")) case "addall": - err = models.AddAllRepositories(ctx.Org.Team) + err = models.AddAllRepositories(ctx, ctx.Org.Team) case "removeall": - err = models.RemoveAllRepositories(ctx.Org.Team) + err = models.RemoveAllRepositories(ctx, ctx.Org.Team) } if err != nil { @@ -352,7 +352,7 @@ func NewTeamPost(ctx *context.Context) { return } - if err := models.NewTeam(t); err != nil { + if err := models.NewTeam(ctx, t); err != nil { ctx.Data["Err_TeamName"] = true switch { case org_model.IsErrTeamAlreadyExist(err): @@ -428,7 +428,7 @@ func SearchTeam(ctx *context.Context) { ListOptions: listOptions, } - teams, maxResults, err := org_model.SearchTeam(opts) + teams, maxResults, err := org_model.SearchTeam(ctx, opts) if err != nil { log.Error("SearchTeam failed: %v", err) ctx.JSON(http.StatusInternalServerError, map[string]any{ @@ -526,7 +526,7 @@ func EditTeamPost(ctx *context.Context) { return } - if err := models.UpdateTeam(t, isAuthChanged, isIncludeAllChanged); err != nil { + if err := models.UpdateTeam(ctx, t, isAuthChanged, isIncludeAllChanged); err != nil { ctx.Data["Err_TeamName"] = true switch { case org_model.IsErrTeamAlreadyExist(err): @@ -541,7 +541,7 @@ func EditTeamPost(ctx *context.Context) { // DeleteTeam response for the delete team request func DeleteTeam(ctx *context.Context) { - if err := models.DeleteTeam(ctx.Org.Team); err != nil { + if err := models.DeleteTeam(ctx, ctx.Org.Team); err != nil { ctx.Flash.Error("DeleteTeam: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("org.teams.delete_team_success")) @@ -583,7 +583,7 @@ func TeamInvitePost(ctx *context.Context) { return } - if err := models.AddTeamMember(team, ctx.Doer.ID); err != nil { + if err := models.AddTeamMember(ctx, team, ctx.Doer.ID); err != nil { ctx.ServerError("AddTeamMember", err) return } diff --git a/routers/web/repo/actions/view.go b/routers/web/repo/actions/view.go index a9c2858303a..2c69b136161 100644 --- a/routers/web/repo/actions/view.go +++ b/routers/web/repo/actions/view.go @@ -608,7 +608,7 @@ func disableOrEnableWorkflowFile(ctx *context_module.Context, isEnable bool) { cfg.DisableWorkflow(workflow) } - if err := repo_model.UpdateRepoUnit(cfgUnit); err != nil { + if err := repo_model.UpdateRepoUnit(ctx, cfgUnit); err != nil { ctx.ServerError("UpdateRepoUnit", err) return } diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index b7be77914f0..8c322b45e5e 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -45,7 +45,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) { } defer file.Close() - attach, err := attachment.UploadAttachment(file, allowedTypes, header.Size, &repo_model.Attachment{ + attach, err := attachment.UploadAttachment(ctx, file, allowedTypes, header.Size, &repo_model.Attachment{ Name: header.Filename, UploaderID: ctx.Doer.ID, RepoID: repoID, @@ -77,7 +77,7 @@ func DeleteAttachment(ctx *context.Context) { ctx.Error(http.StatusForbidden) return } - err = repo_model.DeleteAttachment(attach, true) + err = repo_model.DeleteAttachment(ctx, attach, true) if err != nil { ctx.Error(http.StatusInternalServerError, fmt.Sprintf("DeleteAttachment: %v", err)) return @@ -122,7 +122,7 @@ func ServeAttachment(ctx *context.Context, uuid string) { } } - if err := attach.IncreaseDownloadCount(); err != nil { + if err := attach.IncreaseDownloadCount(ctx); err != nil { ctx.ServerError("IncreaseDownloadCount", err) return } diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go index b1cb42297c1..1f1cca897ef 100644 --- a/routers/web/repo/blame.go +++ b/routers/web/repo/blame.go @@ -8,9 +8,9 @@ import ( gotemplate "html/template" "net/http" "net/url" + "strconv" "strings" - repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/charset" "code.gitea.io/gitea/modules/context" @@ -45,10 +45,6 @@ func RefBlame(ctx *context.Context) { return } - userName := ctx.Repo.Owner.Name - repoName := ctx.Repo.Repository.Name - commitID := ctx.Repo.CommitID - branchLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL() treeLink := branchLink rawLink := ctx.Repo.RepoLink + "/raw/" + ctx.Repo.BranchNameSubURL() @@ -74,7 +70,7 @@ func RefBlame(ctx *context.Context) { // Get current entry user currently looking at. entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { - ctx.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) return } @@ -101,26 +97,16 @@ func RefBlame(ctx *context.Context) { return } - blameReader, err := git.CreateBlameReader(ctx, repo_model.RepoPath(userName, repoName), commitID, fileName) + bypassBlameIgnore, _ := strconv.ParseBool(ctx.FormString("bypass-blame-ignore")) + + result, err := performBlame(ctx, ctx.Repo.Repository.RepoPath(), ctx.Repo.Commit, fileName, bypassBlameIgnore) if err != nil { ctx.NotFound("CreateBlameReader", err) return } - defer blameReader.Close() - blameParts := make([]git.BlamePart, 0) - - for { - blamePart, err := blameReader.NextPart() - if err != nil { - ctx.NotFound("NextPart", err) - return - } - if blamePart == nil { - break - } - blameParts = append(blameParts, *blamePart) - } + ctx.Data["UsesIgnoreRevs"] = result.UsesIgnoreRevs + ctx.Data["FaultyIgnoreRevsFile"] = result.FaultyIgnoreRevsFile // Get Topics of this repo renderRepoTopics(ctx) @@ -128,16 +114,77 @@ func RefBlame(ctx *context.Context) { return } - commitNames, previousCommits := processBlameParts(ctx, blameParts) + commitNames, previousCommits := processBlameParts(ctx, result.Parts) if ctx.Written() { return } - renderBlame(ctx, blameParts, commitNames, previousCommits) + renderBlame(ctx, result.Parts, commitNames, previousCommits) ctx.HTML(http.StatusOK, tplRepoHome) } +type blameResult struct { + Parts []git.BlamePart + UsesIgnoreRevs bool + FaultyIgnoreRevsFile bool +} + +func performBlame(ctx *context.Context, repoPath string, commit *git.Commit, file string, bypassBlameIgnore bool) (*blameResult, error) { + blameReader, err := git.CreateBlameReader(ctx, repoPath, commit, file, bypassBlameIgnore) + if err != nil { + return nil, err + } + + r := &blameResult{} + if err := fillBlameResult(blameReader, r); err != nil { + _ = blameReader.Close() + return nil, err + } + + err = blameReader.Close() + if err != nil { + if len(r.Parts) == 0 && r.UsesIgnoreRevs { + // try again without ignored revs + + blameReader, err = git.CreateBlameReader(ctx, repoPath, commit, file, true) + if err != nil { + return nil, err + } + + r := &blameResult{ + FaultyIgnoreRevsFile: true, + } + if err := fillBlameResult(blameReader, r); err != nil { + _ = blameReader.Close() + return nil, err + } + + return r, blameReader.Close() + } + return nil, err + } + return r, nil +} + +func fillBlameResult(br *git.BlameReader, r *blameResult) error { + r.UsesIgnoreRevs = br.UsesIgnoreRevs() + + r.Parts = make([]git.BlamePart, 0, 5) + for { + blamePart, err := br.NextPart() + if err != nil { + return fmt.Errorf("BlameReader.NextPart failed: %w", err) + } + if blamePart == nil { + break + } + r.Parts = append(r.Parts, *blamePart) + } + + return nil +} + func processBlameParts(ctx *context.Context, blameParts []git.BlamePart) (map[string]*user_model.UserCommit, map[string]string) { // store commit data by SHA to look up avatar info etc commitNames := make(map[string]*user_model.UserCommit) diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index d71d555bc2b..e0e27fd4823 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -41,7 +41,7 @@ func Branches(ctx *context.Context) { ctx.Data["IsWriter"] = ctx.Repo.CanWrite(unit.TypeCode) ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror ctx.Data["CanPull"] = ctx.Repo.CanWrite(unit.TypeCode) || - (ctx.IsSigned && repo_model.HasForkedRepo(ctx.Doer.ID, ctx.Repo.Repository.ID)) + (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)) ctx.Data["PageIsViewCode"] = true ctx.Data["PageIsBranches"] = true @@ -51,7 +51,9 @@ func Branches(ctx *context.Context) { } pageSize := setting.Git.BranchesRangeSize - defaultBranch, branches, branchesCount, err := repo_service.LoadBranches(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, util.OptionalBoolNone, page, pageSize) + kw := ctx.FormString("q") + + defaultBranch, branches, branchesCount, err := repo_service.LoadBranches(ctx, ctx.Repo.Repository, ctx.Repo.GitRepo, util.OptionalBoolNone, kw, page, pageSize) if err != nil { ctx.ServerError("LoadBranches", err) return @@ -73,6 +75,7 @@ func Branches(ctx *context.Context) { commitStatus[commitID] = git_model.CalcCommitStatus(cs) } + ctx.Data["Keyword"] = kw ctx.Data["Branches"] = branches ctx.Data["CommitStatus"] = commitStatus ctx.Data["CommitStatuses"] = commitStatuses diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 9a620f6d372..3587d287fc5 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -305,7 +305,7 @@ func Diff(ctx *context.Context) { maxLines, maxFiles = -1, -1 } - diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{ + diff, err := gitdiff.GetDiff(ctx, gitRepo, &gitdiff.DiffOptions{ AfterCommitID: commitID, SkipTo: ctx.FormString("skip-to"), MaxLines: maxLines, @@ -361,7 +361,7 @@ func Diff(ctx *context.Context) { ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0 if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return repo_model.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID) + return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID) }, nil); err != nil { ctx.ServerError("CalculateTrustStatus", err) return diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index aee34956124..d66dd582a15 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -252,7 +252,6 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { isSameRepo = true ci.HeadUser = ctx.Repo.Owner ci.HeadBranch = headInfos[0] - } else if len(headInfos) == 2 { headInfosSplit := strings.Split(headInfos[0], "/") if len(headInfosSplit) == 1 { @@ -357,7 +356,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // "OwnForkRepo" var ownForkRepo *repo_model.Repository if ctx.Doer != nil && baseRepo.OwnerID != ctx.Doer.ID { - repo := repo_model.GetForkedRepo(ctx.Doer.ID, baseRepo.ID) + repo := repo_model.GetForkedRepo(ctx, ctx.Doer.ID, baseRepo.ID) if repo != nil { ownForkRepo = repo ctx.Data["OwnForkRepo"] = ownForkRepo @@ -381,13 +380,13 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // 5. If the headOwner has a fork of the baseRepo - use that if !has { - ci.HeadRepo = repo_model.GetForkedRepo(ci.HeadUser.ID, baseRepo.ID) + ci.HeadRepo = repo_model.GetForkedRepo(ctx, ci.HeadUser.ID, baseRepo.ID) has = ci.HeadRepo != nil } // 6. If the baseRepo is a fork and the headUser has a fork of that use that if !has && baseRepo.IsFork { - ci.HeadRepo = repo_model.GetForkedRepo(ci.HeadUser.ID, baseRepo.ForkID) + ci.HeadRepo = repo_model.GetForkedRepo(ctx, ci.HeadUser.ID, baseRepo.ForkID) has = ci.HeadRepo != nil } @@ -407,6 +406,9 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { return nil } defer ci.HeadGitRepo.Close() + } else { + ctx.NotFound("ParseCompareInfo", nil) + return nil } ctx.Data["HeadRepo"] = ci.HeadRepo @@ -609,7 +611,7 @@ func PrepareCompareDiff( maxLines, maxFiles = -1, -1 } - diff, err := gitdiff.GetDiff(ci.HeadGitRepo, + diff, err := gitdiff.GetDiff(ctx, ci.HeadGitRepo, &gitdiff.DiffOptions{ BeforeCommitID: beforeCommitID, AfterCommitID: headCommitID, @@ -804,7 +806,7 @@ func CompareDiff(ctx *context.Context) { ctx.Data["IsRepoToolbarCommits"] = true ctx.Data["IsDiffCompare"] = true - templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) + _, templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates) if len(templateErrs) > 0 { ctx.Flash.Warning(renderErrorOfTemplates(ctx, templateErrs), true) diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index b053e3c63f4..1ad091b70fd 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -123,7 +123,7 @@ func editFile(ctx *context.Context, isNewFile bool) { if !isNewFile { entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { - ctx.NotFoundOrServerError("GetTreeEntryByPath", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) return } @@ -287,7 +287,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b Operation: operation, FromTreePath: ctx.Repo.TreePath, TreePath: form.TreePath, - ContentReader: strings.NewReader(strings.ReplaceAll(form.Content, "\r", "")), + ContentReader: strings.NewReader(form.Content), }, }, Signoff: form.Signoff, @@ -812,7 +812,7 @@ func UploadFileToServer(ctx *context.Context) { return } - upload, err := repo_model.NewUpload(name, buf, file) + upload, err := repo_model.NewUpload(ctx, name, buf, file) if err != nil { ctx.Error(http.StatusInternalServerError, fmt.Sprintf("NewUpload: %v", err)) return @@ -832,7 +832,7 @@ func RemoveUploadFileFromServer(ctx *context.Context) { return } - if err := repo_model.DeleteUploadByUUID(form.File); err != nil { + if err := repo_model.DeleteUploadByUUID(ctx, form.File); err != nil { ctx.Error(http.StatusInternalServerError, fmt.Sprintf("DeleteUploadByUUID: %v", err)) return } diff --git a/routers/web/repo/helper.go b/routers/web/repo/helper.go index f8cdefdc8ef..a98abe566f8 100644 --- a/routers/web/repo/helper.go +++ b/routers/web/repo/helper.go @@ -4,9 +4,12 @@ package repo import ( + "net/url" "sort" "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/git" ) func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User { @@ -20,3 +23,22 @@ func MakeSelfOnTop(doer *user.User, users []*user.User) []*user.User { } return users } + +func HandleGitError(ctx *context.Context, msg string, err error) { + if git.IsErrNotExist(err) { + refType := "" + switch { + case ctx.Repo.IsViewBranch: + refType = "branch" + case ctx.Repo.IsViewTag: + refType = "tag" + case ctx.Repo.IsViewCommit: + refType = "commit" + } + ctx.Data["NotFoundPrompt"] = ctx.Locale.Tr("repo.tree_path_not_found_"+refType, ctx.Repo.TreePath, url.PathEscape(ctx.Repo.RefName)) + ctx.Data["NotFoundGoBackURL"] = ctx.Repo.RepoLink + "/src/" + refType + "/" + url.PathEscape(ctx.Repo.RefName) + ctx.NotFound(msg, err) + } else { + ctx.ServerError(msg, err) + } +} diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index c8ecb3b1d8a..1fd784a40a0 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -158,7 +158,7 @@ func httpBase(ctx *context.Context) *serviceHandler { } if ctx.IsBasicAuth && ctx.Data["IsApiToken"] != true && ctx.Data["IsActionsToken"] != true { - _, err = auth_model.GetTwoFactorByUID(ctx.Doer.ID) + _, err = auth_model.GetTwoFactorByUID(ctx, ctx.Doer.ID) if err == nil { // TODO: This response should be changed to "invalid credentials" for security reasons once the expectation behind it (creating an app token to authenticate) is properly documented ctx.PlainText(http.StatusUnauthorized, "Users with two-factor authentication enabled cannot perform HTTP/HTTPS operations via plain username and password. Please create and use a personal access token on the user settings page") diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index c95d54532aa..b6e6cef6d29 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -130,7 +130,7 @@ func MustAllowPulls(ctx *context.Context) { } // User can send pull request if owns a forked repository. - if ctx.IsSigned && repo_model.HasForkedRepo(ctx.Doer.ID, ctx.Repo.Repository.ID) { + if ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) { ctx.Repo.PullRequest.Allowed = true ctx.Repo.PullRequest.HeadInfoSubURL = url.PathEscape(ctx.Doer.Name) + ":" + util.PathEscapeSegments(ctx.Repo.BranchName) } @@ -231,7 +231,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti } else { // So it did search with the keyword, and found some issues. It needs to get issueStats of these issues. // Or the keyword is empty, so it doesn't need issueIDs as filter, just get issueStats with statsOpts. - issueStats, err = issues_model.GetIssueStats(statsOpts) + issueStats, err = issues_model.GetIssueStats(ctx, statsOpts) if err != nil { ctx.ServerError("GetIssueStats", err) return @@ -305,7 +305,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti // Check read status if !ctx.IsSigned { issues[i].IsRead = true - } else if err = issues[i].GetIsRead(ctx.Doer.ID); err != nil { + } else if err = issues[i].GetIsRead(ctx, ctx.Doer.ID); err != nil { ctx.ServerError("GetIsRead", err) return } @@ -442,6 +442,11 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti pager.AddParam(ctx, "project", "ProjectID") pager.AddParam(ctx, "assignee", "AssigneeID") pager.AddParam(ctx, "poster", "PosterID") + + if ctx.FormBool("archived") { + ctx.Data["ShowArchivedLabels"] = true + pager.AddParam(ctx, "archived", "ShowArchivedLabels") + } ctx.Data["Page"] = pager } @@ -611,14 +616,14 @@ type repoReviewerSelection struct { func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, issue *issues_model.Issue, canChooseReviewer bool) { ctx.Data["CanChooseReviewer"] = canChooseReviewer - originalAuthorReviews, err := issues_model.GetReviewersFromOriginalAuthorsByIssueID(issue.ID) + originalAuthorReviews, err := issues_model.GetReviewersFromOriginalAuthorsByIssueID(ctx, issue.ID) if err != nil { ctx.ServerError("GetReviewersFromOriginalAuthorsByIssueID", err) return } ctx.Data["OriginalReviews"] = originalAuthorReviews - reviews, err := issues_model.GetReviewsByIssueID(issue.ID) + reviews, err := issues_model.GetReviewsByIssueID(ctx, issue.ID) if err != nil { ctx.ServerError("GetReviewersByIssueID", err) return @@ -830,10 +835,11 @@ func RetrieveRepoMetas(ctx *context.Context, repo *repo_model.Repository, isPull return labels } -func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles []string) map[string]error { +// Tries to load and set an issue template. The first return value indicates if a template was loaded. +func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles []string) (bool, map[string]error) { commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) if err != nil { - return nil + return false, nil } templateCandidates := make([]string, 0, 1+len(possibleFiles)) @@ -896,20 +902,15 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleFiles ctx.Data["label_ids"] = strings.Join(labelIDs, ",") ctx.Data["Reference"] = template.Ref ctx.Data["RefEndName"] = git.RefName(template.Ref).ShortName() - return templateErrs + return true, templateErrs } - return templateErrs + return false, templateErrs } // NewIssue render creating issue page func NewIssue(ctx *context.Context) { issueConfig, _ := issue_service.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) hasTemplates := issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo) - if !issueConfig.BlankIssuesEnabled && hasTemplates { - // The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if blank issues are disabled, just redirect to the "issues/choose" page with these parameters. - ctx.Redirect(fmt.Sprintf("%s/issues/new/choose?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther) - return - } ctx.Data["Title"] = ctx.Tr("repo.issues.new") ctx.Data["PageIsIssueList"] = true @@ -963,7 +964,8 @@ func NewIssue(ctx *context.Context) { ctx.Data["Tags"] = tags _, templateErrs := issue_service.GetTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) - if errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates); len(errs) > 0 { + templateLoaded, errs := setTemplateIfExists(ctx, issueTemplateKey, IssueTemplateCandidates) + if len(errs) > 0 { for k, v := range errs { templateErrs[k] = v } @@ -978,6 +980,12 @@ func NewIssue(ctx *context.Context) { ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWrite(unit.TypeIssues) + if !issueConfig.BlankIssuesEnabled && hasTemplates && !templateLoaded { + // The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if blank issues are disabled, just redirect to the "issues/choose" page with these parameters. + ctx.Redirect(fmt.Sprintf("%s/issues/new/choose?%s", ctx.Repo.Repository.Link(), ctx.Req.URL.RawQuery), http.StatusSeeOther) + return + } + ctx.HTML(http.StatusOK, tplIssueNew) } @@ -1262,7 +1270,7 @@ func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *use } // Otherwise check if poster is the real repo admin. - ok, err := access_model.IsUserRealRepoAdmin(repo, poster) + ok, err := access_model.IsUserRealRepoAdmin(ctx, repo, poster) if err != nil { return roleDescriptor, err } @@ -1409,7 +1417,7 @@ func ViewIssue(ctx *context.Context) { if ctx.Doer != nil { iw.UserID = ctx.Doer.ID iw.IssueID = issue.ID - iw.IsWatching, err = issues_model.CheckIssueWatch(ctx.Doer, issue) + iw.IsWatching, err = issues_model.CheckIssueWatch(ctx, ctx.Doer, issue) if err != nil { ctx.ServerError("CheckIssueWatch", err) return @@ -1527,7 +1535,7 @@ func ViewIssue(ctx *context.Context) { if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { if ctx.IsSigned { // Deal with the stopwatch - ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx.Doer.ID, issue.ID) + ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx, ctx.Doer.ID, issue.ID) if !ctx.Data["IsStopwatchRunning"].(bool) { var exists bool var swIssue *issues_model.Issue @@ -1546,8 +1554,8 @@ func ViewIssue(ctx *context.Context) { } else { ctx.Data["CanUseTimetracker"] = false } - if ctx.Data["WorkingUsers"], err = issues_model.TotalTimes(&issues_model.FindTrackedTimesOptions{IssueID: issue.ID}); err != nil { - ctx.ServerError("TotalTimes", err) + if ctx.Data["WorkingUsers"], err = issues_model.TotalTimesForEachUser(ctx, &issues_model.FindTrackedTimesOptions{IssueID: issue.ID}); err != nil { + ctx.ServerError("TotalTimesForEachUser", err) return } } @@ -1605,7 +1613,7 @@ func ViewIssue(ctx *context.Context) { marked[comment.PosterID] = comment.ShowRole participants = addParticipant(comment.Poster, participants) } else if comment.Type == issues_model.CommentTypeLabel { - if err = comment.LoadLabel(); err != nil { + if err = comment.LoadLabel(ctx); err != nil { ctx.ServerError("LoadLabel", err) return } @@ -1626,7 +1634,7 @@ func ViewIssue(ctx *context.Context) { } } else if comment.Type == issues_model.CommentTypeProject { - if err = comment.LoadProject(); err != nil { + if err = comment.LoadProject(ctx); err != nil { ctx.ServerError("LoadProject", err) return } @@ -1645,12 +1653,12 @@ func ViewIssue(ctx *context.Context) { } } else if comment.Type == issues_model.CommentTypeAssignees || comment.Type == issues_model.CommentTypeReviewRequest { - if err = comment.LoadAssigneeUserAndTeam(); err != nil { + if err = comment.LoadAssigneeUserAndTeam(ctx); err != nil { ctx.ServerError("LoadAssigneeUserAndTeam", err) return } } else if comment.Type == issues_model.CommentTypeRemoveDependency || comment.Type == issues_model.CommentTypeAddDependency { - if err = comment.LoadDepIssueDetails(); err != nil { + if err = comment.LoadDepIssueDetails(ctx); err != nil { if !issues_model.IsErrIssueNotExist(err) { ctx.ServerError("LoadDepIssueDetails", err) return @@ -1667,7 +1675,7 @@ func ViewIssue(ctx *context.Context) { ctx.ServerError("RenderString", err) return } - if err = comment.LoadReview(); err != nil && !issues_model.IsErrReviewNotExist(err) { + if err = comment.LoadReview(ctx); err != nil && !issues_model.IsErrReviewNotExist(err) { ctx.ServerError("LoadReview", err) return } @@ -1706,7 +1714,7 @@ func ViewIssue(ctx *context.Context) { } } } - if err = comment.LoadResolveDoer(); err != nil { + if err = comment.LoadResolveDoer(ctx); err != nil { ctx.ServerError("LoadResolveDoer", err) return } @@ -1720,7 +1728,7 @@ func ViewIssue(ctx *context.Context) { comment.Type == issues_model.CommentTypeStopTracking || comment.Type == issues_model.CommentTypeDeleteTimeManual { // drop error since times could be pruned from DB.. - _ = comment.LoadTime() + _ = comment.LoadTime(ctx) if comment.Content != "" { // Content before v1.21 did store the formated string instead of seconds, // so "|" is used as delimeter to mark the new format @@ -1791,7 +1799,7 @@ func ViewIssue(ctx *context.Context) { return } - if ctx.Data["CanMarkConversation"], err = issues_model.CanMarkConversation(issue, ctx.Doer); err != nil { + if ctx.Data["CanMarkConversation"], err = issues_model.CanMarkConversation(ctx, issue, ctx.Doer); err != nil { ctx.ServerError("CanMarkConversation", err) return } @@ -1972,7 +1980,7 @@ func ViewIssue(ctx *context.Context) { var hiddenCommentTypes *big.Int if ctx.IsSigned { - val, err := user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes) + val, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes) if err != nil { ctx.ServerError("GetUserSetting", err) return @@ -2202,7 +2210,7 @@ func UpdateIssueContent(ctx *context.Context) { return } - if err := issue_service.ChangeContent(issue, ctx.Doer, ctx.Req.FormValue("content")); err != nil { + if err := issue_service.ChangeContent(ctx, issue, ctx.Doer, ctx.Req.FormValue("content")); err != nil { ctx.ServerError("ChangeContent", err) return } @@ -2258,7 +2266,7 @@ func UpdateIssueDeadline(ctx *context.Context) { deadlineUnix = timeutil.TimeStamp(deadline.Unix()) } - if err := issues_model.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil { + if err := issues_model.UpdateIssueDeadline(ctx, issue, deadlineUnix, ctx.Doer); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err.Error()) return } @@ -2705,7 +2713,7 @@ func ListIssues(ctx *context.Context) { var labelIDs []int64 if splitted := strings.Split(ctx.FormString("labels"), ","); len(splitted) > 0 { - labelIDs, err = issues_model.GetLabelIDsInRepoByNames(ctx.Repo.Repository.ID, splitted) + labelIDs, err = issues_model.GetLabelIDsInRepoByNames(ctx, ctx.Repo.Repository.ID, splitted) if err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return @@ -2717,7 +2725,7 @@ func ListIssues(ctx *context.Context) { for i := range part { // uses names and fall back to ids // non existent milestones are discarded - mile, err := issues_model.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, part[i]) + mile, err := issues_model.GetMilestoneByRepoIDANDName(ctx, ctx.Repo.Repository.ID, part[i]) if err == nil { mileIDs = append(mileIDs, mile.ID) continue @@ -3034,7 +3042,7 @@ func NewComment(ctx *context.Context) { return } } else { - if err := stopTimerIfAvailable(ctx.Doer, issue); err != nil { + if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil { ctx.ServerError("CreateOrStopIssueStopwatch", err) return } @@ -3203,7 +3211,7 @@ func ChangeIssueReaction(ctx *context.Context) { switch ctx.Params(":action") { case "react": - reaction, err := issues_model.CreateIssueReaction(ctx.Doer.ID, issue.ID, form.Content) + reaction, err := issues_model.CreateIssueReaction(ctx, ctx.Doer.ID, issue.ID, form.Content) if err != nil { if issues_model.IsErrForbiddenIssueReaction(err) { ctx.ServerError("ChangeIssueReaction", err) @@ -3221,7 +3229,7 @@ func ChangeIssueReaction(ctx *context.Context) { log.Trace("Reaction for issue created: %d/%d/%d", ctx.Repo.Repository.ID, issue.ID, reaction.ID) case "unreact": - if err := issues_model.DeleteIssueReaction(ctx.Doer.ID, issue.ID, form.Content); err != nil { + if err := issues_model.DeleteIssueReaction(ctx, ctx.Doer.ID, issue.ID, form.Content); err != nil { ctx.ServerError("DeleteIssueReaction", err) return } @@ -3305,7 +3313,7 @@ func ChangeCommentReaction(ctx *context.Context) { switch ctx.Params(":action") { case "react": - reaction, err := issues_model.CreateCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Content) + reaction, err := issues_model.CreateCommentReaction(ctx, ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Content) if err != nil { if issues_model.IsErrForbiddenIssueReaction(err) { ctx.ServerError("ChangeIssueReaction", err) @@ -3316,21 +3324,21 @@ func ChangeCommentReaction(ctx *context.Context) { } // Reload new reactions comment.Reactions = nil - if err = comment.LoadReactions(ctx.Repo.Repository); err != nil { + if err = comment.LoadReactions(ctx, ctx.Repo.Repository); err != nil { log.Info("comment.LoadReactions: %s", err) break } log.Trace("Reaction for comment created: %d/%d/%d/%d", ctx.Repo.Repository.ID, comment.Issue.ID, comment.ID, reaction.ID) case "unreact": - if err := issues_model.DeleteCommentReaction(ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Content); err != nil { + if err := issues_model.DeleteCommentReaction(ctx, ctx.Doer.ID, comment.Issue.ID, comment.ID, form.Content); err != nil { ctx.ServerError("DeleteCommentReaction", err) return } // Reload new reactions comment.Reactions = nil - if err = comment.LoadReactions(ctx.Repo.Repository); err != nil { + if err = comment.LoadReactions(ctx, ctx.Repo.Repository); err != nil { log.Info("comment.LoadReactions: %s", err) break } @@ -3448,7 +3456,7 @@ func updateAttachments(ctx *context.Context, item any, files []string) error { if util.SliceContainsString(files, attachments[i].UUID) { continue } - if err := repo_model.DeleteAttachment(attachments[i], true); err != nil { + if err := repo_model.DeleteAttachment(ctx, attachments[i], true); err != nil { return err } } @@ -3456,9 +3464,9 @@ func updateAttachments(ctx *context.Context, item any, files []string) error { if len(files) > 0 { switch content := item.(type) { case *issues_model.Issue: - err = issues_model.UpdateIssueAttachments(content.ID, files) + err = issues_model.UpdateIssueAttachments(ctx, content.ID, files) case *issues_model.Comment: - err = content.UpdateAttachments(files) + err = content.UpdateAttachments(ctx, files) default: return fmt.Errorf("unknown Type: %T", content) } @@ -3571,7 +3579,7 @@ func handleTeamMentions(ctx *context.Context) { if ctx.Doer.IsAdmin { isAdmin = true } else { - isAdmin, err = org.IsOwnedBy(ctx.Doer.ID) + isAdmin, err = org.IsOwnedBy(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("IsOwnedBy", err) return @@ -3579,13 +3587,13 @@ func handleTeamMentions(ctx *context.Context) { } if isAdmin { - teams, err = org.LoadTeams() + teams, err = org.LoadTeams(ctx) if err != nil { ctx.ServerError("LoadTeams", err) return } } else { - teams, err = org.GetUserTeams(ctx.Doer.ID) + teams, err = org.GetUserTeams(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetUserTeams", err) return diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index 3dd7725c215..5c378fe9d79 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -11,7 +11,6 @@ import ( "code.gitea.io/gitea/models/avatars" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -91,11 +90,16 @@ func GetContentHistoryList(ctx *context.Context) { // Admins or owners can always delete history revisions. Normal users can only delete own history revisions. func canSoftDeleteContentHistory(ctx *context.Context, issue *issues_model.Issue, comment *issues_model.Comment, history *issues_model.ContentHistory, -) bool { - canSoftDelete := false - if ctx.Repo.IsOwner() { +) (canSoftDelete bool) { + // CanWrite means the doer can manage the issue/PR list + if ctx.Repo.IsOwner() || ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) { canSoftDelete = true - } else if ctx.Repo.CanWrite(unit.TypeIssues) { + } else { + // for read-only users, they could still post issues or comments, + // they should be able to delete the history related to their own issue/comment, a case is: + // 1. the user posts some sensitive data + // 2. then the repo owner edits the post but didn't remove the sensitive data + // 3. the poster wants to delete the edited history revision if comment == nil { // the issue poster or the history poster can soft-delete canSoftDelete = ctx.Doer.ID == issue.PosterID || ctx.Doer.ID == history.PosterID diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go index 257610d3af5..dd3e2803b4e 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -85,7 +85,7 @@ func RetrieveLabels(ctx *context.Context) { return } if ctx.Doer != nil { - ctx.Org.IsOwner, err = org.IsOwnedBy(ctx.Doer.ID) + ctx.Org.IsOwner, err = org.IsOwnedBy(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("org.IsOwnedBy", err) return @@ -145,7 +145,7 @@ func UpdateLabel(ctx *context.Context) { l.Color = form.Color l.SetArchived(form.IsArchived) - if err := issues_model.UpdateLabel(l); err != nil { + if err := issues_model.UpdateLabel(ctx, l); err != nil { ctx.ServerError("UpdateLabel", err) return } @@ -154,7 +154,7 @@ func UpdateLabel(ctx *context.Context) { // DeleteLabel delete a label func DeleteLabel(ctx *context.Context) { - if err := issues_model.DeleteLabel(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { + if err := issues_model.DeleteLabel(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteLabel: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.issues.label_deletion_success")) @@ -173,7 +173,7 @@ func UpdateIssueLabel(ctx *context.Context) { switch action := ctx.FormString("action"); action { case "clear": for _, issue := range issues { - if err := issue_service.ClearLabels(issue, ctx.Doer); err != nil { + if err := issue_service.ClearLabels(ctx, issue, ctx.Doer); err != nil { ctx.ServerError("ClearLabels", err) return } @@ -208,14 +208,14 @@ func UpdateIssueLabel(ctx *context.Context) { if action == "attach" { for _, issue := range issues { - if err = issue_service.AddLabel(issue, ctx.Doer, label); err != nil { + if err = issue_service.AddLabel(ctx, issue, ctx.Doer, label); err != nil { ctx.ServerError("AddLabel", err) return } } } else { for _, issue := range issues { - if err = issue_service.RemoveLabel(issue, ctx.Doer, label); err != nil { + if err = issue_service.RemoveLabel(ctx, issue, ctx.Doer, label); err != nil { ctx.ServerError("RemoveLabel", err) return } diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go index 3e715437e6c..d42af573297 100644 --- a/routers/web/repo/issue_stopwatch.go +++ b/routers/web/repo/issue_stopwatch.go @@ -22,7 +22,7 @@ func IssueStopwatch(c *context.Context) { var showSuccessMessage bool - if !issues_model.StopwatchExists(c.Doer.ID, issue.ID) { + if !issues_model.StopwatchExists(c, c.Doer.ID, issue.ID) { showSuccessMessage = true } @@ -31,7 +31,7 @@ func IssueStopwatch(c *context.Context) { return } - if err := issues_model.CreateOrStopIssueStopwatch(c.Doer, issue); err != nil { + if err := issues_model.CreateOrStopIssueStopwatch(c, c.Doer, issue); err != nil { c.ServerError("CreateOrStopIssueStopwatch", err) return } @@ -55,12 +55,12 @@ func CancelStopwatch(c *context.Context) { return } - if err := issues_model.CancelStopwatch(c.Doer, issue); err != nil { + if err := issues_model.CancelStopwatch(c, c.Doer, issue); err != nil { c.ServerError("CancelStopwatch", err) return } - stopwatches, err := issues_model.GetUserStopwatches(c.Doer.ID, db.ListOptions{}) + stopwatches, err := issues_model.GetUserStopwatches(c, c.Doer.ID, db.ListOptions{}) if err != nil { c.ServerError("GetUserStopwatches", err) return diff --git a/routers/web/repo/issue_timetrack.go b/routers/web/repo/issue_timetrack.go index 04ca65dd9a1..82d8d8faea9 100644 --- a/routers/web/repo/issue_timetrack.go +++ b/routers/web/repo/issue_timetrack.go @@ -61,7 +61,7 @@ func DeleteTime(c *context.Context) { return } - t, err := issues_model.GetTrackedTimeByID(c.ParamsInt64(":timeid")) + t, err := issues_model.GetTrackedTimeByID(c, c.ParamsInt64(":timeid")) if err != nil { if db.IsErrNotExist(err) { c.NotFound("time not found", err) @@ -77,7 +77,7 @@ func DeleteTime(c *context.Context) { return } - if err = issues_model.DeleteTime(t); err != nil { + if err = issues_model.DeleteTime(c, t); err != nil { c.ServerError("DeleteTime", err) return } diff --git a/routers/web/repo/issue_watch.go b/routers/web/repo/issue_watch.go index d3d3a2af21e..1cb5cc7162d 100644 --- a/routers/web/repo/issue_watch.go +++ b/routers/web/repo/issue_watch.go @@ -47,7 +47,7 @@ func IssueWatch(ctx *context.Context) { return } - if err := issues_model.CreateOrUpdateIssueWatch(ctx.Doer.ID, issue.ID, watch); err != nil { + if err := issues_model.CreateOrUpdateIssueWatch(ctx, ctx.Doer.ID, issue.ID, watch); err != nil { ctx.ServerError("CreateOrUpdateIssueWatch", err) return } diff --git a/routers/web/repo/main_test.go b/routers/web/repo/main_test.go index e3a09a95bd3..6e469cf2ed7 100644 --- a/routers/web/repo/main_test.go +++ b/routers/web/repo/main_test.go @@ -4,14 +4,11 @@ package repo import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/repo/middlewares.go b/routers/web/repo/middlewares.go index 216550ca996..b50e96be3c4 100644 --- a/routers/web/repo/middlewares.go +++ b/routers/web/repo/middlewares.go @@ -56,7 +56,7 @@ func SetDiffViewStyle(ctx *context.Context) { } ctx.Data["IsSplitStyle"] = style == "split" - if err := user_model.UpdateUserDiffViewStyle(ctx.Doer, style); err != nil { + if err := user_model.UpdateUserDiffViewStyle(ctx, ctx.Doer, style); err != nil { ctx.ServerError("ErrUpdateDiffViewStyle", err) } } @@ -72,12 +72,12 @@ func SetWhitespaceBehavior(ctx *context.Context) { whitespaceBehavior = defaultWhitespaceBehavior } if ctx.IsSigned { - userWhitespaceBehavior, err := user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyDiffWhitespaceBehavior, defaultWhitespaceBehavior) + userWhitespaceBehavior, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyDiffWhitespaceBehavior, defaultWhitespaceBehavior) if err == nil { if whitespaceBehavior == "" { whitespaceBehavior = userWhitespaceBehavior } else if whitespaceBehavior != userWhitespaceBehavior { - _ = user_model.SetUserSetting(ctx.Doer.ID, user_model.SettingsKeyDiffWhitespaceBehavior, whitespaceBehavior) + _ = user_model.SetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyDiffWhitespaceBehavior, whitespaceBehavior) } } // else: we can ignore the error safely } @@ -98,7 +98,7 @@ func SetShowOutdatedComments(ctx *context.Context) { if showOutdatedCommentsValue != "true" && showOutdatedCommentsValue != "false" { // invalid or no value for this form string -> use default or stored user setting if ctx.IsSigned { - showOutdatedCommentsValue, _ = user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyShowOutdatedComments, "false") + showOutdatedCommentsValue, _ = user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyShowOutdatedComments, "false") } else { // not logged in user -> use the default value showOutdatedCommentsValue = "false" @@ -106,7 +106,7 @@ func SetShowOutdatedComments(ctx *context.Context) { } else { // valid value -> update user setting if user is logged in if ctx.IsSigned { - _ = user_model.SetUserSetting(ctx.Doer.ID, user_model.SettingsKeyShowOutdatedComments, showOutdatedCommentsValue) + _ = user_model.SetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyShowOutdatedComments, showOutdatedCommentsValue) } } diff --git a/routers/web/repo/migrate.go b/routers/web/repo/migrate.go index a6125a1a581..b70901d5f28 100644 --- a/routers/web/repo/migrate.go +++ b/routers/web/repo/migrate.go @@ -232,13 +232,13 @@ func MigratePost(ctx *context.Context) { opts.Releases = false } - err = repo_model.CheckCreateRepository(ctx.Doer, ctxUser, opts.RepoName, false) + err = repo_model.CheckCreateRepository(ctx, ctx.Doer, ctxUser, opts.RepoName, false) if err != nil { handleMigrateError(ctx, ctxUser, err, "MigratePost", tpl, form) return } - err = task.MigrateRepository(ctx.Doer, ctxUser, opts) + err = task.MigrateRepository(ctx, ctx.Doer, ctxUser, opts) if err == nil { ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(opts.RepoName)) return @@ -260,7 +260,7 @@ func setMigrationContextData(ctx *context.Context, serviceType structs.GitServic } func MigrateRetryPost(ctx *context.Context) { - if err := task.RetryMigrateTask(ctx.Repo.Repository.ID); err != nil { + if err := task.RetryMigrateTask(ctx, ctx.Repo.Repository.ID); err != nil { log.Error("Retry task failed: %v", err) ctx.ServerError("task.RetryMigrateTask", err) return @@ -269,7 +269,7 @@ func MigrateRetryPost(ctx *context.Context) { } func MigrateCancelPost(ctx *context.Context) { - migratingTask, err := admin_model.GetMigratingTask(ctx.Repo.Repository.ID) + migratingTask, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID) if err != nil { log.Error("GetMigratingTask: %v", err) ctx.Redirect(ctx.Repo.Repository.Link()) @@ -277,7 +277,7 @@ func MigrateCancelPost(ctx *context.Context) { } if migratingTask.Status == structs.TaskStatusRunning { taskUpdate := &admin_model.Task{ID: migratingTask.ID, Status: structs.TaskStatusFailed, Message: "canceled"} - if err = taskUpdate.UpdateCols("status", "message"); err != nil { + if err = taskUpdate.UpdateCols(ctx, "status", "message"); err != nil { ctx.ServerError("task.UpdateCols", err) return } diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index ad355ce5d7d..df52ca35289 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -65,7 +65,7 @@ func Milestones(ctx *context.Context) { return } - stats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(builder.And(builder.Eq{"id": ctx.Repo.Repository.ID}), keyword) + stats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(ctx, builder.And(builder.Eq{"id": ctx.Repo.Repository.ID}), keyword) if err != nil { ctx.ServerError("GetMilestoneStats", err) return @@ -74,7 +74,7 @@ func Milestones(ctx *context.Context) { ctx.Data["ClosedCount"] = stats.ClosedCount if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { - if err := miles.LoadTotalTrackedTimes(); err != nil { + if err := miles.LoadTotalTrackedTimes(ctx); err != nil { ctx.ServerError("LoadTotalTrackedTimes", err) return } @@ -142,7 +142,7 @@ func NewMilestonePost(ctx *context.Context) { } deadline = time.Date(deadline.Year(), deadline.Month(), deadline.Day(), 23, 59, 59, 0, deadline.Location()) - if err = issues_model.NewMilestone(&issues_model.Milestone{ + if err = issues_model.NewMilestone(ctx, &issues_model.Milestone{ RepoID: ctx.Repo.Repository.ID, Name: form.Title, Content: form.Content, @@ -214,7 +214,7 @@ func EditMilestonePost(ctx *context.Context) { m.Name = form.Title m.Content = form.Content m.DeadlineUnix = timeutil.TimeStamp(deadline.Unix()) - if err = issues_model.UpdateMilestone(m, m.IsClosed); err != nil { + if err = issues_model.UpdateMilestone(ctx, m, m.IsClosed); err != nil { ctx.ServerError("UpdateMilestone", err) return } @@ -236,7 +236,7 @@ func ChangeMilestoneStatus(ctx *context.Context) { } id := ctx.ParamsInt64(":id") - if err := issues_model.ChangeMilestoneStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil { + if err := issues_model.ChangeMilestoneStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { if issues_model.IsErrMilestoneNotExist(err) { ctx.NotFound("", err) } else { @@ -249,7 +249,7 @@ func ChangeMilestoneStatus(ctx *context.Context) { // DeleteMilestone delete a milestone func DeleteMilestone(ctx *context.Context) { - if err := issues_model.DeleteMilestoneByRepoID(ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { + if err := issues_model.DeleteMilestoneByRepoID(ctx, ctx.Repo.Repository.ID, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteMilestoneByRepoID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.milestones.deletion_success")) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index eef57f46272..33bc79d96d8 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -142,7 +142,7 @@ func NewProjectPost(ctx *context.Context) { return } - if err := project_model.NewProject(&project_model.Project{ + if err := project_model.NewProject(ctx, &project_model.Project{ RepoID: ctx.Repo.Repository.ID, Title: form.Title, Description: form.Content, @@ -172,7 +172,7 @@ func ChangeProjectStatus(ctx *context.Context) { } id := ctx.ParamsInt64(":id") - if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx.Repo.Repository.ID, id, toClose); err != nil { + if err := project_model.ChangeProjectStatusByRepoIDAndID(ctx, ctx.Repo.Repository.ID, id, toClose); err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", err) } else { @@ -279,7 +279,7 @@ func EditProjectPost(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("repo.projects.edit_success", p.Title)) if ctx.FormString("redirect") == "project" { - ctx.Redirect(p.Link()) + ctx.Redirect(p.Link(ctx)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/projects") } @@ -445,7 +445,7 @@ func DeleteProjectBoard(ctx *context.Context) { return } - if err := project_model.DeleteBoardByID(ctx.ParamsInt64(":boardID")); err != nil { + if err := project_model.DeleteBoardByID(ctx, ctx.ParamsInt64(":boardID")); err != nil { ctx.ServerError("DeleteProjectBoardByID", err) return } @@ -473,7 +473,7 @@ func AddBoardToProjectPost(ctx *context.Context) { return } - if err := project_model.NewBoard(&project_model.Board{ + if err := project_model.NewBoard(ctx, &project_model.Board{ ProjectID: project.ID, Title: form.Title, Color: form.Color, @@ -565,7 +565,7 @@ func SetDefaultProjectBoard(ctx *context.Context) { return } - if err := project_model.SetDefaultBoard(project.ID, board.ID); err != nil { + if err := project_model.SetDefaultBoard(ctx, project.ID, board.ID); err != nil { ctx.ServerError("SetDefaultBoard", err) return } @@ -580,7 +580,7 @@ func UnSetDefaultProjectBoard(ctx *context.Context) { return } - if err := project_model.SetDefaultBoard(project.ID, 0); err != nil { + if err := project_model.SetDefaultBoard(ctx, project.ID, 0); err != nil { ctx.ServerError("SetDefaultBoard", err) return } @@ -682,7 +682,7 @@ func MoveIssues(ctx *context.Context) { } } - if err = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil { + if err = project_model.MoveIssuesOnProjectBoard(ctx, board, sortedIssueIDs); err != nil { ctx.ServerError("MoveIssuesOnProjectBoard", err) return } diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 0de3ace792b..639c0c74d03 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -128,18 +128,18 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { ctx.Data["repo_name"] = forkRepo.Name ctx.Data["description"] = forkRepo.Description ctx.Data["IsPrivate"] = forkRepo.IsPrivate || forkRepo.Owner.Visibility == structs.VisibleTypePrivate - canForkToUser := forkRepo.OwnerID != ctx.Doer.ID && !repo_model.HasForkedRepo(ctx.Doer.ID, forkRepo.ID) + canForkToUser := forkRepo.OwnerID != ctx.Doer.ID && !repo_model.HasForkedRepo(ctx, ctx.Doer.ID, forkRepo.ID) ctx.Data["ForkRepo"] = forkRepo - ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID) + ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetOrgsCanCreateRepoByUserID", err) return nil } var orgs []*organization.Organization for _, org := range ownedOrgs { - if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, forkRepo.ID) { + if forkRepo.OwnerID != org.ID && !repo_model.HasForkedRepo(ctx, org.ID, forkRepo.ID) { orgs = append(orgs, org) } } @@ -180,6 +180,21 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { return nil } + branches, err := git_model.FindBranchNames(ctx, git_model.FindBranchOptions{ + RepoID: ctx.Repo.Repository.ID, + ListOptions: db.ListOptions{ + ListAll: true, + }, + IsDeletedBranch: util.OptionalBoolFalse, + // Add it as the first option + ExcludeBranchNames: []string{ctx.Repo.Repository.DefaultBranch}, + }) + if err != nil { + ctx.ServerError("FindBranchNames", err) + return nil + } + ctx.Data["Branches"] = append([]string{ctx.Repo.Repository.DefaultBranch}, branches...) + return forkRepo } @@ -233,7 +248,7 @@ func ForkPost(ctx *context.Context) { ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form) return } - repo := repo_model.GetForkedRepo(ctxUser.ID, traverseParentRepo.ID) + repo := repo_model.GetForkedRepo(ctx, ctxUser.ID, traverseParentRepo.ID) if repo != nil { ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name)) return @@ -250,7 +265,7 @@ func ForkPost(ctx *context.Context) { // Check if user is allowed to create repo's on the organization. if ctxUser.IsOrganization() { - isAllowedToFork, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx.Doer.ID) + isAllowedToFork, err := organization.OrgFromUser(ctxUser).CanCreateOrgRepo(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("CanCreateOrgRepo", err) return @@ -261,9 +276,10 @@ func ForkPost(ctx *context.Context) { } repo, err := repo_service.ForkRepository(ctx, ctx.Doer, ctxUser, repo_service.ForkRepoOptions{ - BaseRepo: forkRepo, - Name: form.RepoName, - Description: form.Description, + BaseRepo: forkRepo, + Name: form.RepoName, + Description: form.Description, + SingleBranch: form.ForkSingleBranch, }) if err != nil { ctx.Data["Err_RepoName"] = true @@ -892,7 +908,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi // as the viewed information is designed to be loaded only on latest PR // diff and if you're signed in. if !ctx.IsSigned || willShowSpecifiedCommit || willShowSpecifiedCommitRange { - diff, err = gitdiff.GetDiff(gitRepo, diffOptions, files...) + diff, err = gitdiff.GetDiff(ctx, gitRepo, diffOptions, files...) methodWithError = "GetDiff" } else { diff, err = gitdiff.SyncAndGetUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diffOptions, files...) @@ -943,7 +959,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi } if ctx.IsSigned && ctx.Doer != nil { - if ctx.Data["CanMarkConversation"], err = issues_model.CanMarkConversation(issue, ctx.Doer); err != nil { + if ctx.Data["CanMarkConversation"], err = issues_model.CanMarkConversation(ctx, issue, ctx.Doer); err != nil { ctx.ServerError("CanMarkConversation", err) return } @@ -970,7 +986,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi } numPendingCodeComments := int64(0) if currentReview != nil { - numPendingCodeComments, err = issues_model.CountComments(&issues_model.FindCommentsOptions{ + numPendingCodeComments, err = issues_model.CountComments(ctx, &issues_model.FindCommentsOptions{ Type: issues_model.CommentTypeCode, ReviewID: currentReview.ID, IssueID: issue.ID, @@ -1270,7 +1286,7 @@ func MergePullRequest(ctx *context.Context) { } log.Trace("Pull request merged: %d", pr.ID) - if err := stopTimerIfAvailable(ctx.Doer, issue); err != nil { + if err := stopTimerIfAvailable(ctx, ctx.Doer, issue); err != nil { ctx.ServerError("CreateOrStopIssueStopwatch", err) return } @@ -1326,9 +1342,9 @@ func CancelAutoMergePullRequest(ctx *context.Context) { ctx.Redirect(fmt.Sprintf("%s/pulls/%d", ctx.Repo.RepoLink, issue.Index)) } -func stopTimerIfAvailable(user *user_model.User, issue *issues_model.Issue) error { - if issues_model.StopwatchExists(user.ID, issue.ID) { - if err := issues_model.CreateOrStopIssueStopwatch(user, issue); err != nil { +func stopTimerIfAvailable(ctx *context.Context, user *user_model.User, issue *issues_model.Issue) error { + if issues_model.StopwatchExists(ctx, user.ID, issue.ID) { + if err := issues_model.CreateOrStopIssueStopwatch(ctx, user, issue); err != nil { return err } } diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index 3e433dcf4d7..1359af9d3bf 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -101,7 +101,7 @@ func CreateCodeComment(ctx *context.Context) { renderConversation(ctx, comment) return } - ctx.Redirect(comment.Link()) + ctx.Redirect(comment.Link(ctx)) } // UpdateResolveConversation add or remove an Conversation resolved mark @@ -127,7 +127,7 @@ func UpdateResolveConversation(ctx *context.Context) { } var permResult bool - if permResult, err = issues_model.CanMarkConversation(comment.Issue, ctx.Doer); err != nil { + if permResult, err = issues_model.CanMarkConversation(ctx, comment.Issue, ctx.Doer); err != nil { ctx.ServerError("CanMarkConversation", err) return } @@ -142,7 +142,7 @@ func UpdateResolveConversation(ctx *context.Context) { } if action == "Resolve" || action == "UnResolve" { - err = issues_model.MarkConversation(comment, ctx.Doer, action == "Resolve") + err = issues_model.MarkConversation(ctx, comment, ctx.Doer, action == "Resolve") if err != nil { ctx.ServerError("MarkConversation", err) return diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 138df458576..61f19731258 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -71,18 +71,6 @@ func calReleaseNumCommitsBehind(repoCtx *context.Repository, release *repo_model func Releases(ctx *context.Context) { ctx.Data["PageIsReleaseList"] = true ctx.Data["Title"] = ctx.Tr("repo.release.releases") - releasesOrTags(ctx, false) -} - -// TagsList render tags list page -func TagsList(ctx *context.Context) { - ctx.Data["PageIsTagList"] = true - ctx.Data["Title"] = ctx.Tr("repo.release.tags") - releasesOrTags(ctx, true) -} - -func releasesOrTags(ctx *context.Context, isTagList bool) { - ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch ctx.Data["IsViewBranch"] = false ctx.Data["IsViewTag"] = true // Disable the showCreateNewBranch form in the dropdown on this page. @@ -100,35 +88,13 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { listOptions.PageSize = setting.API.MaxResponseItems } - // TODO(20073) tags are used for compare feature which needs all tags - // filtering is done on the client-side atm - tagListStart, tagListEnd := 0, 0 - if isTagList { - tagListStart, tagListEnd = listOptions.GetStartEnd() - } - - tags, err := ctx.Repo.GitRepo.GetTags(tagListStart, tagListEnd) - if err != nil { - ctx.ServerError("GetTags", err) - return - } - ctx.Data["Tags"] = tags - writeAccess := ctx.Repo.CanWrite(unit.TypeReleases) ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived opts := repo_model.FindReleasesOptions{ ListOptions: listOptions, - } - if isTagList { - // for the tags list page, show all releases with real tags (having real commit-id), - // the drafts should also be included because a real tag might be used as a draft. - opts.IncludeDrafts = true - opts.IncludeTags = true - opts.HasSha1 = util.OptionalBoolTrue - } else { // only show draft releases for users who can write, read-only users shouldn't see draft releases. - opts.IncludeDrafts = writeAccess + IncludeDrafts: writeAccess, } releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts) @@ -137,12 +103,6 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { return } - count, err := repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, opts) - if err != nil { - ctx.ServerError("GetReleaseCountByRepoID", err) - return - } - for _, release := range releases { release.Repo = ctx.Repo.Repository } @@ -197,16 +157,59 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { ctx.Data["Releases"] = releases - pager := context.NewPagination(int(count), opts.PageSize, opts.Page, 5) + numReleases := ctx.Data["NumReleases"].(int64) + pager := context.NewPagination(int(numReleases), opts.PageSize, opts.Page, 5) pager.SetDefaultParams(ctx) ctx.Data["Page"] = pager - if isTagList { - ctx.Data["PageIsViewCode"] = !ctx.Repo.Repository.UnitEnabled(ctx, unit.TypeReleases) - ctx.HTML(http.StatusOK, tplTagsList) - } else { - ctx.HTML(http.StatusOK, tplReleasesList) + ctx.HTML(http.StatusOK, tplReleasesList) +} + +// TagsList render tags list page +func TagsList(ctx *context.Context) { + ctx.Data["PageIsTagList"] = true + ctx.Data["Title"] = ctx.Tr("repo.release.tags") + ctx.Data["IsViewBranch"] = false + ctx.Data["IsViewTag"] = true + // Disable the showCreateNewBranch form in the dropdown on this page. + ctx.Data["CanCreateBranch"] = false + ctx.Data["HideBranchesInDropdown"] = true + + listOptions := db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: ctx.FormInt("limit"), } + if listOptions.PageSize == 0 { + listOptions.PageSize = setting.Repository.Release.DefaultPagingNum + } + if listOptions.PageSize > setting.API.MaxResponseItems { + listOptions.PageSize = setting.API.MaxResponseItems + } + + opts := repo_model.FindReleasesOptions{ + ListOptions: listOptions, + // for the tags list page, show all releases with real tags (having real commit-id), + // the drafts should also be included because a real tag might be used as a draft. + IncludeDrafts: true, + IncludeTags: true, + HasSha1: util.OptionalBoolTrue, + } + + releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, opts) + if err != nil { + ctx.ServerError("GetReleasesByRepoID", err) + return + } + + ctx.Data["Releases"] = releases + + numTags := ctx.Data["NumTags"].(int64) + pager := context.NewPagination(int(numTags), opts.PageSize, opts.Page, 5) + pager.SetDefaultParams(ctx) + ctx.Data["Page"] = pager + + ctx.Data["PageIsViewCode"] = !ctx.Repo.Repository.UnitEnabled(ctx, unit.TypeReleases) + ctx.HTML(http.StatusOK, tplTagsList) } // ReleasesFeedRSS get feeds for releases in RSS format @@ -241,7 +244,7 @@ func SingleRelease(ctx *context.Context) { writeAccess := ctx.Repo.CanWrite(unit.TypeReleases) ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived - release, err := repo_model.GetRelease(ctx.Repo.Repository.ID, ctx.Params("*")) + release, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, ctx.Params("*")) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound("GetRelease", err) @@ -297,7 +300,7 @@ func SingleRelease(ctx *context.Context) { // LatestRelease redirects to the latest release func LatestRelease(ctx *context.Context) { - release, err := repo_model.GetLatestReleaseByRepoID(ctx.Repo.Repository.ID) + release, err := repo_model.GetLatestReleaseByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound("LatestRelease", err) @@ -321,7 +324,7 @@ func NewRelease(ctx *context.Context) { ctx.Data["PageIsReleaseList"] = true ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch if tagName := ctx.FormString("tag"); len(tagName) > 0 { - rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName) + rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) if err != nil && !repo_model.IsErrReleaseNotExist(err) { ctx.ServerError("GetRelease", err) return @@ -403,7 +406,7 @@ func NewReleasePost(ctx *context.Context) { attachmentUUIDs = form.Files } - rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, form.TagName) + rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, form.TagName) if err != nil { if !repo_model.IsErrReleaseNotExist(err) { ctx.ServerError("GetRelease", err) @@ -488,7 +491,7 @@ func NewReleasePost(ctx *context.Context) { rel.PublisherID = ctx.Doer.ID rel.IsTag = false - if err = releaseservice.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil { + if err = releaseservice.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, attachmentUUIDs, nil, nil); err != nil { ctx.Data["Err_TagName"] = true ctx.ServerError("UpdateRelease", err) return @@ -508,7 +511,7 @@ func EditRelease(ctx *context.Context) { upload.AddUploadContext(ctx, "release") tagName := ctx.Params("*") - rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName) + rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound("GetRelease", err) @@ -551,7 +554,7 @@ func EditReleasePost(ctx *context.Context) { ctx.Data["PageIsEditRelease"] = true tagName := ctx.Params("*") - rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName) + rel, err := repo_model.GetRelease(ctx, ctx.Repo.Repository.ID, tagName) if err != nil { if repo_model.IsErrReleaseNotExist(err) { ctx.NotFound("GetRelease", err) @@ -594,7 +597,7 @@ func EditReleasePost(ctx *context.Context) { rel.Note = form.Content rel.IsDraft = len(form.Draft) > 0 rel.IsPrerelease = form.Prerelease - if err = releaseservice.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, + if err = releaseservice.UpdateRelease(ctx, ctx.Doer, ctx.Repo.GitRepo, rel, addAttachmentUUIDs, delAttachmentUUIDs, editAttachments); err != nil { ctx.ServerError("UpdateRelease", err) return diff --git a/routers/web/repo/release_test.go b/routers/web/repo/release_test.go index 54118fb6b3e..a5a923d464a 100644 --- a/routers/web/repo/release_test.go +++ b/routers/web/repo/release_test.go @@ -7,6 +7,7 @@ import ( "testing" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/contexttest" "code.gitea.io/gitea/modules/web" @@ -65,7 +66,7 @@ func TestNewReleasePost(t *testing.T) { } } -func TestNewReleasesList(t *testing.T) { +func TestCalReleaseNumCommitsBehind(t *testing.T) { unittest.PrepareTestEnv(t) ctx, _ := contexttest.MockContext(t, "user2/repo-release/releases") contexttest.LoadUser(t, ctx, 2) @@ -73,8 +74,17 @@ func TestNewReleasesList(t *testing.T) { contexttest.LoadGitRepo(t, ctx) t.Cleanup(func() { ctx.Repo.GitRepo.Close() }) - Releases(ctx) - releases := ctx.Data["Releases"].([]*repo_model.Release) + releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ + IncludeDrafts: ctx.Repo.CanWrite(unit.TypeReleases), + }) + assert.NoError(t, err) + + countCache := make(map[string]int64) + for _, release := range releases { + err := calReleaseNumCommitsBehind(ctx.Repo, release, countCache) + assert.NoError(t, err) + } + type computedFields struct { NumCommitsBehind int64 TargetBehind string diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 63517c42683..d11eb781f4a 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -80,7 +80,7 @@ func CommitInfoCache(ctx *context.Context) { } func checkContextUser(ctx *context.Context, uid int64) *user_model.User { - orgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx.Doer.ID) + orgs, err := organization.GetOrgsCanCreateRepoByUserID(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetOrgsCanCreateRepoByUserID", err) return nil @@ -119,7 +119,7 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User { return nil } if !ctx.Doer.IsAdmin { - canCreate, err := organization.OrgFromUser(org).CanCreateOrgRepo(ctx.Doer.ID) + canCreate, err := organization.OrgFromUser(org).CanCreateOrgRepo(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("CanCreateOrgRepo", err) return nil @@ -309,9 +309,9 @@ func Action(ctx *context.Context) { case "unwatch": err = repo_model.WatchRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, false) case "star": - err = repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true) + err = repo_model.StarRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, true) case "unstar": - err = repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, false) + err = repo_model.StarRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, false) case "accept_transfer": err = acceptOrRejectRepoTransfer(ctx, true) case "reject_transfer": @@ -345,7 +345,7 @@ func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { return err } - if !repoTransfer.CanUserAcceptTransfer(ctx.Doer) { + if !repoTransfer.CanUserAcceptTransfer(ctx, ctx.Doer) { return errors.New("user does not have enough permissions") } @@ -360,7 +360,7 @@ func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { } ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success")) } else { - if err := models.CancelRepositoryTransfer(ctx.Repo.Repository); err != nil { + if err := models.CancelRepositoryTransfer(ctx, ctx.Repo.Repository); err != nil { return err } ctx.Flash.Success(ctx.Tr("repo.settings.transfer.rejected")) @@ -397,7 +397,7 @@ func RedirectDownload(ctx *context.Context) { } else if len(releases) == 0 && vTag == "latest" { // GitHub supports the alias "latest" for the latest release // We only fetch the latest release if the tag is "latest" and no release with the tag "latest" exists - release, err := repo_model.GetLatestReleaseByRepoID(ctx.Repo.Repository.ID) + release, err := repo_model.GetLatestReleaseByRepoID(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.Error(http.StatusNotFound) return diff --git a/routers/web/repo/setting/collaboration.go b/routers/web/repo/setting/collaboration.go index 212b0346bc7..e217697cc0a 100644 --- a/routers/web/repo/setting/collaboration.go +++ b/routers/web/repo/setting/collaboration.go @@ -127,7 +127,7 @@ func ChangeCollaborationAccessMode(ctx *context.Context) { // DeleteCollaboration delete a collaboration for a repository func DeleteCollaboration(ctx *context.Context) { - if err := repo_service.DeleteCollaboration(ctx.Repo.Repository, ctx.FormInt64("id")); err != nil { + if err := repo_service.DeleteCollaboration(ctx, ctx.Repo.Repository, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteCollaboration: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.settings.remove_collaborator_success")) @@ -173,7 +173,7 @@ func AddTeamPost(ctx *context.Context) { return } - if err = org_service.TeamAddRepository(team, ctx.Repo.Repository); err != nil { + if err = org_service.TeamAddRepository(ctx, team, ctx.Repo.Repository); err != nil { ctx.ServerError("TeamAddRepository", err) return } diff --git a/routers/web/repo/setting/default_branch.go b/routers/web/repo/setting/default_branch.go index f0aa1a89e7e..9bf54e706a3 100644 --- a/routers/web/repo/setting/default_branch.go +++ b/routers/web/repo/setting/default_branch.go @@ -46,7 +46,7 @@ func SetDefaultBranchPost(ctx *context.Context) { return } } - if err := repo_model.UpdateDefaultBranch(repo); err != nil { + if err := repo_model.UpdateDefaultBranch(ctx, repo); err != nil { ctx.ServerError("SetDefaultBranch", err) return } diff --git a/routers/web/repo/setting/deploy_key.go b/routers/web/repo/setting/deploy_key.go index 577706d4544..70e31e12566 100644 --- a/routers/web/repo/setting/deploy_key.go +++ b/routers/web/repo/setting/deploy_key.go @@ -99,7 +99,7 @@ func DeployKeysPost(ctx *context.Context) { // DeleteDeployKey response for deleting a deploy key func DeleteDeployKey(ctx *context.Context) { - if err := asymkey_service.DeleteDeployKey(ctx.Doer, ctx.FormInt64("id")); err != nil { + if err := asymkey_service.DeleteDeployKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteDeployKey: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.settings.deploy_key_deletion_success")) diff --git a/routers/web/repo/setting/main_test.go b/routers/web/repo/setting/main_test.go index 5a6fa562177..c414b853e51 100644 --- a/routers/web/repo/setting/main_test.go +++ b/routers/web/repo/setting/main_test.go @@ -4,14 +4,11 @@ package setting import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index e0f2294a14f..73adfec95a0 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -70,7 +70,7 @@ func SettingsProtectedBranch(c *context.Context) { c.Data["PageIsSettingsBranches"] = true c.Data["Title"] = c.Tr("repo.settings.protected_branch") + " - " + rule.RuleName - users, err := access_model.GetRepoReaders(c.Repo.Repository) + users, err := access_model.GetRepoReaders(c, c.Repo.Repository) if err != nil { c.ServerError("Repo.Repository.GetReaders", err) return @@ -84,7 +84,7 @@ func SettingsProtectedBranch(c *context.Context) { c.Data["recent_status_checks"] = contexts if c.Repo.Owner.IsOrganization() { - teams, err := organization.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c.Repo.Repository.ID, perm.AccessModeRead) + teams, err := organization.OrgFromUser(c.Repo.Owner).TeamsWithAccessToRepo(c, c.Repo.Repository.ID, perm.AccessModeRead) if err != nil { c.ServerError("Repo.Owner.TeamsWithAccessToRepo", err) return @@ -285,7 +285,7 @@ func DeleteProtectedBranchRulePost(ctx *context.Context) { return } - if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository.ID, ruleID); err != nil { + if err := git_model.DeleteProtectedBranch(ctx, ctx.Repo.Repository, ruleID); err != nil { ctx.Flash.Error(ctx.Tr("repo.settings.remove_protected_branch_failed", rule.RuleName)) ctx.JSONRedirect(fmt.Sprintf("%s/settings/branches", ctx.Repo.RepoLink)) return diff --git a/routers/web/repo/setting/protected_tag.go b/routers/web/repo/setting/protected_tag.go index aafbd19e80e..46addb3f0ac 100644 --- a/routers/web/repo/setting/protected_tag.go +++ b/routers/web/repo/setting/protected_tag.go @@ -147,7 +147,7 @@ func setTagsContext(ctx *context.Context) error { } ctx.Data["ProtectedTags"] = protectedTags - users, err := access_model.GetRepoReaders(ctx.Repo.Repository) + users, err := access_model.GetRepoReaders(ctx, ctx.Repo.Repository) if err != nil { ctx.ServerError("Repo.Repository.GetReaders", err) return err @@ -155,7 +155,7 @@ func setTagsContext(ctx *context.Context) error { ctx.Data["Users"] = users if ctx.Repo.Owner.IsOrganization() { - teams, err := organization.OrgFromUser(ctx.Repo.Owner).TeamsWithAccessToRepo(ctx.Repo.Repository.ID, perm.AccessModeRead) + teams, err := organization.OrgFromUser(ctx.Repo.Owner).TeamsWithAccessToRepo(ctx, ctx.Repo.Repository.ID, perm.AccessModeRead) if err != nil { ctx.ServerError("Repo.Owner.TeamsWithAccessToRepo", err) return err diff --git a/routers/web/repo/setting/runners.go b/routers/web/repo/setting/runners.go index 2c192e9790a..8d4112c157b 100644 --- a/routers/web/repo/setting/runners.go +++ b/routers/web/repo/setting/runners.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" actions_shared "code.gitea.io/gitea/routers/web/shared/actions" + shared_user "code.gitea.io/gitea/routers/web/shared/user" ) const ( @@ -53,6 +54,11 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) { } if ctx.Data["PageIsOrgSettings"] == true { + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return nil, nil + } return &runnersCtx{ RepoID: 0, OwnerID: ctx.Org.Organization.ID, diff --git a/routers/web/repo/setting/secrets.go b/routers/web/repo/setting/secrets.go index 3d7a0576027..cf427b2c44b 100644 --- a/routers/web/repo/setting/secrets.go +++ b/routers/web/repo/setting/secrets.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" shared "code.gitea.io/gitea/routers/web/shared/secrets" + shared_user "code.gitea.io/gitea/routers/web/shared/user" ) const ( @@ -42,6 +43,11 @@ func getSecretsCtx(ctx *context.Context) (*secretsCtx, error) { } if ctx.Data["PageIsOrgSettings"] == true { + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return nil, nil + } return &secretsCtx{ OwnerID: ctx.ContextUser.ID, RepoID: 0, diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 457fd0ab4ed..2f6856be941 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -260,6 +260,13 @@ func SettingsPost(ctx *context.Context) { return } + remoteAddress, err := util.SanitizeURL(form.MirrorAddress) + if err != nil { + ctx.ServerError("SanitizeURL", err) + return + } + pullMirror.RemoteAddress = remoteAddress + form.LFS = form.LFS && setting.LFS.StartServer if len(form.LFSEndpoint) > 0 { @@ -295,7 +302,7 @@ func SettingsPost(ctx *context.Context) { mirror_service.AddPullMirrorToQueue(repo.ID) - ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress")) + ctx.Flash.Info(ctx.Tr("repo.settings.pull_mirror_sync_in_progress", repo.OriginalURL)) ctx.Redirect(repo.Link() + "/settings") case "push-mirror-sync": @@ -312,7 +319,7 @@ func SettingsPost(ctx *context.Context) { mirror_service.AddPushMirrorToQueue(m.ID) - ctx.Flash.Info(ctx.Tr("repo.settings.mirror_sync_in_progress")) + ctx.Flash.Info(ctx.Tr("repo.settings.push_mirror_sync_in_progress", m.RemoteAddress)) ctx.Redirect(repo.Link() + "/settings") case "push-mirror-update": @@ -414,12 +421,19 @@ func SettingsPost(ctx *context.Context) { return } + remoteAddress, err := util.SanitizeURL(form.PushMirrorAddress) + if err != nil { + ctx.ServerError("SanitizeURL", err) + return + } + m := &repo_model.PushMirror{ - RepoID: repo.ID, - Repo: repo, - RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix), - SyncOnCommit: form.PushMirrorSyncOnCommit, - Interval: interval, + RepoID: repo.ID, + Repo: repo, + RemoteName: fmt.Sprintf("remote_mirror_%s", remoteSuffix), + SyncOnCommit: form.PushMirrorSyncOnCommit, + Interval: interval, + RemoteAddress: remoteAddress, } if err := repo_model.InsertPushMirror(ctx, m); err != nil { ctx.ServerError("InsertPushMirror", err) @@ -597,7 +611,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil { + if err := repo_model.UpdateRepositoryUnits(ctx, repo, units, deleteUnitTypes); err != nil { ctx.ServerError("UpdateRepositoryUnits", err) return } @@ -698,7 +712,7 @@ func SettingsPost(ctx *context.Context) { if _, err := repo_module.CleanUpMigrateInfo(ctx, repo); err != nil { ctx.ServerError("CleanUpMigrateInfo", err) return - } else if err = repo_model.DeleteMirrorByRepoID(ctx.Repo.Repository.ID); err != nil { + } else if err = repo_model.DeleteMirrorByRepoID(ctx, ctx.Repo.Repository.ID); err != nil { ctx.ServerError("DeleteMirrorByRepoID", err) return } @@ -764,7 +778,7 @@ func SettingsPost(ctx *context.Context) { } if newOwner.Type == user_model.UserTypeOrganization { - if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx.Doer.ID) { + if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) { // The user shouldn't know about this organization ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) return @@ -816,7 +830,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := models.CancelRepositoryTransfer(ctx.Repo.Repository); err != nil { + if err := models.CancelRepositoryTransfer(ctx, ctx.Repo.Repository); err != nil { ctx.ServerError("CancelRepositoryTransfer", err) return } @@ -880,7 +894,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := repo_model.SetArchiveRepoState(repo, true); err != nil { + if err := repo_model.SetArchiveRepoState(ctx, repo, true); err != nil { log.Error("Tried to archive a repo: %s", err) ctx.Flash.Error(ctx.Tr("repo.settings.archive.error")) ctx.Redirect(ctx.Repo.RepoLink + "/settings") @@ -898,7 +912,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := repo_model.SetArchiveRepoState(repo, false); err != nil { + if err := repo_model.SetArchiveRepoState(ctx, repo, false); err != nil { log.Error("Tried to unarchive a repo: %s", err) ctx.Flash.Error(ctx.Tr("repo.settings.unarchive.error")) ctx.Redirect(ctx.Repo.RepoLink + "/settings") diff --git a/routers/web/repo/setting/settings_test.go b/routers/web/repo/setting/settings_test.go index 55f292f1436..066d2ef2a9f 100644 --- a/routers/web/repo/setting/settings_test.go +++ b/routers/web/repo/setting/settings_test.go @@ -8,6 +8,7 @@ import ( "testing" asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -248,7 +249,7 @@ func TestAddTeamPost(t *testing.T) { AddTeamPost(ctx) - assert.True(t, repo_service.HasRepository(team, re.ID)) + assert.True(t, repo_service.HasRepository(db.DefaultContext, team, re.ID)) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.Empty(t, ctx.Flash.ErrorMsg) } @@ -288,7 +289,7 @@ func TestAddTeamPost_NotAllowed(t *testing.T) { AddTeamPost(ctx) - assert.False(t, repo_service.HasRepository(team, re.ID)) + assert.False(t, repo_service.HasRepository(db.DefaultContext, team, re.ID)) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } @@ -329,7 +330,7 @@ func TestAddTeamPost_AddTeamTwice(t *testing.T) { AddTeamPost(ctx) AddTeamPost(ctx) - assert.True(t, repo_service.HasRepository(team, re.ID)) + assert.True(t, repo_service.HasRepository(db.DefaultContext, team, re.ID)) assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) assert.NotEmpty(t, ctx.Flash.ErrorMsg) } @@ -402,5 +403,5 @@ func TestDeleteTeam(t *testing.T) { DeleteTeam(ctx) - assert.False(t, repo_service.HasRepository(team, re.ID)) + assert.False(t, repo_service.HasRepository(db.DefaultContext, team, re.ID)) } diff --git a/routers/web/repo/setting/variables.go b/routers/web/repo/setting/variables.go index 1005d1d9c61..a697a5d8d85 100644 --- a/routers/web/repo/setting/variables.go +++ b/routers/web/repo/setting/variables.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" shared "code.gitea.io/gitea/routers/web/shared/actions" + shared_user "code.gitea.io/gitea/routers/web/shared/user" ) const ( @@ -40,6 +41,11 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) { } if ctx.Data["PageIsOrgSettings"] == true { + err := shared_user.LoadHeaderCount(ctx) + if err != nil { + ctx.ServerError("LoadHeaderCount", err) + return nil, nil + } return &variablesCtx{ OwnerID: ctx.ContextUser.ID, IsOrg: true, diff --git a/routers/web/repo/topic.go b/routers/web/repo/topic.go index d22c3c6aa37..d0e706c5bd7 100644 --- a/routers/web/repo/topic.go +++ b/routers/web/repo/topic.go @@ -45,7 +45,7 @@ func TopicsPost(ctx *context.Context) { return } - err := repo_model.SaveTopics(ctx.Repo.Repository.ID, validTopics...) + err := repo_model.SaveTopics(ctx, ctx.Repo.Repository.ID, validTopics...) if err != nil { log.Error("SaveTopics failed: %v", err) ctx.JSON(http.StatusInternalServerError, map[string]any{ diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index f0fe6140dfb..65717906273 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -488,8 +488,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } else { buf, _ := io.ReadAll(rd) - // empty: 0 lines; "a": one line; "a\n": two lines; "a\nb": two lines; - // the NumLines is only used for the display on the UI: "xxx lines" + // The Open Group Base Specification: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html + // empty: 0 lines; "a": 1 line, 1 incomplete-line; "a\n": 1 line; "a\nb": 1 line, 1 incomplete-line; + // Gitea uses the definition (like most modern editors): + // empty: 0 lines; "a": 1 line; "a\n": 2 lines; "a\nb": 2 lines; + // When rendering, the last empty line is not rendered in UI, while the line-number is still counted, to tell users that the file contains a trailing EOL. + // To make the UI more consistent, it could use an icon mark to indicate that there is no trailing EOL, and show line-number as the rendered lines. + // This NumLines is only used for the display on the UI: "xxx lines" if len(buf) == 0 { ctx.Data["NumLines"] = 0 } else { @@ -628,19 +633,10 @@ func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input i return escaped, output, err } -func safeURL(address string) string { - u, err := url.Parse(address) - if err != nil { - return address - } - u.User = nil - return u.String() -} - func checkHomeCodeViewable(ctx *context.Context) { if len(ctx.Repo.Units) > 0 { if ctx.Repo.Repository.IsBeingCreated() { - task, err := admin_model.GetMigratingTask(ctx.Repo.Repository.ID) + task, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID) if err != nil { if admin_model.IsErrTaskDoesNotExist(err) { ctx.Data["Repo"] = ctx.Repo @@ -660,7 +656,7 @@ func checkHomeCodeViewable(ctx *context.Context) { ctx.Data["Repo"] = ctx.Repo ctx.Data["MigrateTask"] = task - ctx.Data["CloneAddr"] = safeURL(cfg.CloneAddr) + ctx.Data["CloneAddr"], _ = util.SanitizeURL(cfg.CloneAddr) ctx.Data["Failed"] = task.Status == structs.TaskStatusFailed ctx.HTML(http.StatusOK, tplMigrating) return @@ -701,7 +697,7 @@ func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) { } tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) if err != nil { - ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.SubTree", err) return } allEntries, err := tree.ListEntries() @@ -792,7 +788,7 @@ func LastCommit(ctx *context.Context) { func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entries { tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) if err != nil { - ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.SubTree", err) return nil } @@ -801,12 +797,12 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri // Get current entry user currently looking at. entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { - ctx.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) return nil } if !entry.IsDir() { - ctx.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) return nil } @@ -852,7 +848,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri verification := asymkey_model.ParseCommitWithSignature(ctx, latestCommit) if err := asymkey_model.CalculateTrustStatus(verification, ctx.Repo.Repository.GetTrustModel(), func(user *user_model.User) (bool, error) { - return repo_model.IsOwnerMemberCollaborator(ctx.Repo.Repository, user.ID) + return repo_model.IsOwnerMemberCollaborator(ctx, ctx.Repo.Repository, user.ID) }, nil); err != nil { ctx.ServerError("CalculateTrustStatus", err) return nil @@ -893,7 +889,7 @@ func renderLanguageStats(ctx *context.Context) { } func renderRepoTopics(ctx *context.Context) { - topics, _, err := repo_model.FindTopics(&repo_model.FindTopicOptions{ + topics, _, err := repo_model.FindTopics(ctx, &repo_model.FindTopicOptions{ RepoID: ctx.Repo.Repository.ID, }) if err != nil { @@ -972,7 +968,7 @@ func renderCode(ctx *context.Context) { // Get current entry user currently looking at. entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { - ctx.NotFoundOrServerError("Repo.Commit.GetTreeEntryByPath", git.IsErrNotExist, err) + HandleGitError(ctx, "Repo.Commit.GetTreeEntryByPath", err) return } @@ -1065,7 +1061,7 @@ func Watchers(ctx *context.Context) { ctx.Data["PageIsWatchers"] = true RenderUserCards(ctx, ctx.Repo.Repository.NumWatches, func(opts db.ListOptions) ([]*user_model.User, error) { - return repo_model.GetRepoWatchers(ctx.Repo.Repository.ID, opts) + return repo_model.GetRepoWatchers(ctx, ctx.Repo.Repository.ID, opts) }, tplWatchers) } @@ -1075,7 +1071,7 @@ func Stars(ctx *context.Context) { ctx.Data["CardsTitle"] = ctx.Tr("repo.stargazers") ctx.Data["PageIsStargazers"] = true RenderUserCards(ctx, ctx.Repo.Repository.NumStars, func(opts db.ListOptions) ([]*user_model.User, error) { - return repo_model.GetStargazers(ctx.Repo.Repository, opts) + return repo_model.GetStargazers(ctx, ctx.Repo.Repository, opts) }, tplWatchers) } @@ -1091,7 +1087,7 @@ func Forks(ctx *context.Context) { pager := context.NewPagination(ctx.Repo.Repository.NumForks, setting.ItemsPerPage, page, 5) ctx.Data["Page"] = pager - forks, err := repo_model.GetForks(ctx.Repo.Repository, db.ListOptions{ + forks, err := repo_model.GetForks(ctx, ctx.Repo.Repository, db.ListOptions{ Page: pager.Paginater.Current(), PageSize: setting.ItemsPerPage, }) diff --git a/routers/web/shared/actions/runners.go b/routers/web/shared/actions/runners.go index 7ff1f3e33f5..cd60e9cbee3 100644 --- a/routers/web/shared/actions/runners.go +++ b/routers/web/shared/actions/runners.go @@ -35,15 +35,15 @@ func RunnersList(ctx *context.Context, opts actions_model.FindRunnerOptions) { // ownid=0,repo_id=0,means this token is used for global var token *actions_model.ActionRunnerToken - token, err = actions_model.GetUnactivatedRunnerToken(ctx, opts.OwnerID, opts.RepoID) - if errors.Is(err, util.ErrNotExist) { + token, err = actions_model.GetLastestRunnerToken(ctx, opts.OwnerID, opts.RepoID) + if errors.Is(err, util.ErrNotExist) || (token != nil && !token.IsActive) { token, err = actions_model.NewRunnerToken(ctx, opts.OwnerID, opts.RepoID) if err != nil { ctx.ServerError("CreateRunnerToken", err) return } } else if err != nil { - ctx.ServerError("GetUnactivatedRunnerToken", err) + ctx.ServerError("GetLastestRunnerToken", err) return } diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 6273e11fc5b..355f2ddeffe 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -30,11 +30,12 @@ func prepareContextForCommonProfile(ctx *context.Context) { func PrepareContextForProfileBigAvatar(ctx *context.Context) { prepareContextForCommonProfile(ctx) - ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID) + ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx, ctx.Doer.ID, ctx.ContextUser.ID) ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate + ctx.Data["UserLocationMapURL"] = setting.Service.UserLocationMapURL // Show OpenID URIs - openIDs, err := user_model.GetUserOpenIDs(ctx.ContextUser.ID) + openIDs, err := user_model.GetUserOpenIDs(ctx, ctx.ContextUser.ID) if err != nil { ctx.ServerError("GetUserOpenIDs", err) return @@ -56,7 +57,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) { } showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) - orgs, err := organization.FindOrgs(organization.FindOrgOptions{ + orgs, err := organization.FindOrgs(ctx, organization.FindOrgOptions{ UserID: ctx.ContextUser.ID, IncludePrivate: showPrivate, }) @@ -65,7 +66,7 @@ func PrepareContextForProfileBigAvatar(ctx *context.Context) { return } ctx.Data["Orgs"] = orgs - ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer) + ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(ctx, orgs, ctx.Doer) badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser) if err != nil { diff --git a/routers/web/user/home.go b/routers/web/user/home.go index a88479e1293..76b9262eada 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -59,7 +59,7 @@ func getDashboardContextUser(ctx *context.Context) *user_model.User { } ctx.Data["ContextUser"] = ctxUser - orgs, err := organization.GetUserOrgsList(ctx.Doer) + orgs, err := organization.GetUserOrgsList(ctx, ctx.Doer) if err != nil { ctx.ServerError("GetUserOrgsList", err) return nil @@ -105,7 +105,7 @@ func Dashboard(ctx *context.Context) { } if setting.Service.EnableUserHeatmap { - data, err := activities_model.GetUserHeatmapDataByUserTeam(ctxUser, ctx.Org.Team, ctx.Doer) + data, err := activities_model.GetUserHeatmapDataByUserTeam(ctx, ctxUser, ctx.Org.Team, ctx.Doer) if err != nil { ctx.ServerError("GetUserHeatmapDataByUserTeam", err) return @@ -213,13 +213,13 @@ func Milestones(ctx *context.Context) { } } - counts, err := issues_model.CountMilestonesByRepoCondAndKw(userRepoCond, keyword, isShowClosed) + counts, err := issues_model.CountMilestonesByRepoCondAndKw(ctx, userRepoCond, keyword, isShowClosed) if err != nil { ctx.ServerError("CountMilestonesByRepoIDs", err) return } - milestones, err := issues_model.SearchMilestones(repoCond, page, isShowClosed, sortType, keyword) + milestones, err := issues_model.SearchMilestones(ctx, repoCond, page, isShowClosed, sortType, keyword) if err != nil { ctx.ServerError("SearchMilestones", err) return @@ -256,7 +256,7 @@ func Milestones(ctx *context.Context) { } if milestones[i].Repo.IsTimetrackerEnabled(ctx) { - err := milestones[i].LoadTotalTrackedTime() + err := milestones[i].LoadTotalTrackedTime(ctx) if err != nil { ctx.ServerError("LoadTotalTrackedTime", err) return @@ -265,7 +265,7 @@ func Milestones(ctx *context.Context) { i++ } - milestoneStats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(repoCond, keyword) + milestoneStats, err := issues_model.GetMilestonesStatsByRepoCondAndKw(ctx, repoCond, keyword) if err != nil { ctx.ServerError("GetMilestoneStats", err) return @@ -275,7 +275,7 @@ func Milestones(ctx *context.Context) { if len(repoIDs) == 0 { totalMilestoneStats = milestoneStats } else { - totalMilestoneStats, err = issues_model.GetMilestonesStatsByRepoCondAndKw(userRepoCond, keyword) + totalMilestoneStats, err = issues_model.GetMilestonesStatsByRepoCondAndKw(ctx, userRepoCond, keyword) if err != nil { ctx.ServerError("GetMilestoneStats", err) return diff --git a/routers/web/user/main_test.go b/routers/web/user/main_test.go index 925482a1d2b..8b6ae69296b 100644 --- a/routers/web/user/main_test.go +++ b/routers/web/user/main_test.go @@ -4,14 +4,11 @@ package user import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 57770b2b1ae..146b94dfdf3 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -439,7 +439,7 @@ func PackageSettingsPost(ctx *context.Context) { ctx.Redirect(ctx.Link) return case "delete": - err := packages_service.RemovePackageVersion(ctx.Doer, ctx.Package.Descriptor.Version) + err := packages_service.RemovePackageVersion(ctx, ctx.Doer, ctx.Package.Descriptor.Version) if err != nil { log.Error("Error deleting package: %v", err) ctx.Flash.Error(ctx.Tr("packages.settings.delete.error")) diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 87505b94b19..48a4b94c190 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -52,11 +52,10 @@ func userProfile(ctx *context.Context) { ctx.Data["Title"] = ctx.ContextUser.DisplayName() ctx.Data["PageIsUserProfile"] = true - ctx.Data["UserLocationMapURL"] = setting.Service.UserLocationMapURL // prepare heatmap data if setting.Service.EnableUserHeatmap { - data, err := activities_model.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer) + data, err := activities_model.GetUserHeatmapDataByUser(ctx, ctx.ContextUser, ctx.Doer) if err != nil { ctx.ServerError("GetUserHeatmapDataByUser", err) return @@ -77,8 +76,9 @@ func userProfile(ctx *context.Context) { func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGitRepo *git.Repository, profileReadme *git.Blob) { // if there is a profile readme, default to "overview" page, otherwise, default to "repositories" page + // if there is not a profile readme, the overview tab should be treated as the repositories tab tab := ctx.FormString("tab") - if tab == "" { + if tab == "" || tab == "overview" { if profileReadme != nil { tab = "overview" } else { @@ -157,10 +157,10 @@ func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGi switch tab { case "followers": ctx.Data["Cards"] = followers - total = int(count) + total = int(numFollowers) case "following": ctx.Data["Cards"] = following - total = int(count) + total = int(numFollowing) case "activity": date := ctx.FormString("date") pagingNum = setting.UI.FeedPagingNum @@ -292,9 +292,9 @@ func Action(ctx *context.Context) { var err error switch ctx.FormString("action") { case "follow": - err = user_model.FollowUser(ctx.Doer.ID, ctx.ContextUser.ID) + err = user_model.FollowUser(ctx, ctx.Doer.ID, ctx.ContextUser.ID) case "unfollow": - err = user_model.UnfollowUser(ctx.Doer.ID, ctx.ContextUser.ID) + err = user_model.UnfollowUser(ctx, ctx.Doer.ID, ctx.ContextUser.ID) } if err != nil { diff --git a/routers/web/user/search.go b/routers/web/user/search.go index fa2e52dd419..4d090a3784c 100644 --- a/routers/web/user/search.go +++ b/routers/web/user/search.go @@ -19,7 +19,7 @@ func Search(ctx *context.Context) { PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), } - users, maxResults, err := user_model.SearchUsers(&user_model.SearchUserOptions{ + users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Keyword: ctx.FormTrim("q"), UID: ctx.FormInt64("uid"), diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index ecb846e91bb..5c14f3ad4b5 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -93,7 +93,7 @@ func EmailPost(ctx *context.Context) { // Make emailaddress primary. if ctx.FormString("_method") == "PRIMARY" { - if err := user_model.MakeEmailPrimary(&user_model.EmailAddress{ID: ctx.FormInt64("id")}); err != nil { + if err := user_model.MakeEmailPrimary(ctx, &user_model.EmailAddress{ID: ctx.FormInt64("id")}); err != nil { ctx.ServerError("MakeEmailPrimary", err) return } @@ -112,7 +112,7 @@ func EmailPost(ctx *context.Context) { } id := ctx.FormInt64("id") - email, err := user_model.GetEmailAddressByID(ctx.Doer.ID, id) + email, err := user_model.GetEmailAddressByID(ctx, ctx.Doer.ID, id) if err != nil { log.Error("GetEmailAddressByID(%d,%d) error: %v", ctx.Doer.ID, id, err) ctx.Redirect(setting.AppSubURL + "/user/settings/account") @@ -161,7 +161,7 @@ func EmailPost(ctx *context.Context) { ctx.ServerError("SetEmailPreference", errors.New("option unrecognized")) return } - if err := user_model.SetEmailNotifications(ctx.Doer, preference); err != nil { + if err := user_model.SetEmailNotifications(ctx, ctx.Doer, preference); err != nil { log.Error("Set Email Notifications failed: %v", err) ctx.ServerError("SetEmailNotifications", err) return @@ -220,7 +220,7 @@ func EmailPost(ctx *context.Context) { // DeleteEmail response for delete user's email func DeleteEmail(ctx *context.Context) { - if err := user_model.DeleteEmailAddress(&user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil { + if err := user_model.DeleteEmailAddress(ctx, &user_model.EmailAddress{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil { ctx.ServerError("DeleteEmail", err) return } @@ -235,7 +235,7 @@ func DeleteAccount(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsAccount"] = true - if _, _, err := auth.UserSignIn(ctx.Doer.Name, ctx.FormString("password")); err != nil { + if _, _, err := auth.UserSignIn(ctx, ctx.Doer.Name, ctx.FormString("password")); err != nil { if user_model.IsErrUserNotExist(err) { loadAccountData(ctx) @@ -267,7 +267,7 @@ func DeleteAccount(ctx *context.Context) { } func loadAccountData(ctx *context.Context) { - emlist, err := user_model.GetEmailAddresses(ctx.Doer.ID) + emlist, err := user_model.GetEmailAddresses(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetEmailAddresses", err) return diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go index 088aba38b69..ee44d48dce5 100644 --- a/routers/web/user/setting/applications.go +++ b/routers/web/user/setting/applications.go @@ -53,7 +53,7 @@ func ApplicationsPost(ctx *context.Context) { Scope: scope, } - exist, err := auth_model.AccessTokenByNameExists(t) + exist, err := auth_model.AccessTokenByNameExists(ctx, t) if err != nil { ctx.ServerError("AccessTokenByNameExists", err) return @@ -64,7 +64,7 @@ func ApplicationsPost(ctx *context.Context) { return } - if err := auth_model.NewAccessToken(t); err != nil { + if err := auth_model.NewAccessToken(ctx, t); err != nil { ctx.ServerError("NewAccessToken", err) return } @@ -77,7 +77,7 @@ func ApplicationsPost(ctx *context.Context) { // DeleteApplication response for delete user access token func DeleteApplication(ctx *context.Context) { - if err := auth_model.DeleteAccessTokenByID(ctx.FormInt64("id"), ctx.Doer.ID); err != nil { + if err := auth_model.DeleteAccessTokenByID(ctx, ctx.FormInt64("id"), ctx.Doer.ID); err != nil { ctx.Flash.Error("DeleteAccessTokenByID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("settings.delete_token_success")) @@ -88,7 +88,7 @@ func DeleteApplication(ctx *context.Context) { func loadApplicationsData(ctx *context.Context) { ctx.Data["AccessTokenScopePublicOnly"] = auth_model.AccessTokenScopePublicOnly - tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID}) + tokens, err := auth_model.ListAccessTokens(ctx, auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID}) if err != nil { ctx.ServerError("ListAccessTokens", err) return diff --git a/routers/web/user/setting/keys.go b/routers/web/user/setting/keys.go index 2336c04bbed..160c5ee0c00 100644 --- a/routers/web/user/setting/keys.go +++ b/routers/web/user/setting/keys.go @@ -51,7 +51,7 @@ func KeysPost(ctx *context.Context) { } switch form.Type { case "principal": - content, err := asymkey_model.CheckPrincipalKeyString(ctx.Doer, form.Content) + content, err := asymkey_model.CheckPrincipalKeyString(ctx, ctx.Doer, form.Content) if err != nil { if db.IsErrSSHDisabled(err) { ctx.Flash.Info(ctx.Tr("settings.ssh_disabled")) @@ -80,9 +80,9 @@ func KeysPost(ctx *context.Context) { token := asymkey_model.VerificationToken(ctx.Doer, 1) lastToken := asymkey_model.VerificationToken(ctx.Doer, 0) - keys, err := asymkey_model.AddGPGKey(ctx.Doer.ID, form.Content, token, form.Signature) + keys, err := asymkey_model.AddGPGKey(ctx, ctx.Doer.ID, form.Content, token, form.Signature) if err != nil && asymkey_model.IsErrGPGInvalidTokenSignature(err) { - keys, err = asymkey_model.AddGPGKey(ctx.Doer.ID, form.Content, lastToken, form.Signature) + keys, err = asymkey_model.AddGPGKey(ctx, ctx.Doer.ID, form.Content, lastToken, form.Signature) } if err != nil { ctx.Data["HasGPGError"] = true @@ -224,7 +224,7 @@ func KeysPost(ctx *context.Context) { func DeleteKey(ctx *context.Context) { switch ctx.FormString("type") { case "gpg": - if err := asymkey_model.DeleteGPGKey(ctx.Doer, ctx.FormInt64("id")); err != nil { + if err := asymkey_model.DeleteGPGKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeleteGPGKey: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("settings.gpg_key_deletion_success")) @@ -241,13 +241,13 @@ func DeleteKey(ctx *context.Context) { ctx.Redirect(setting.AppSubURL + "/user/settings/keys") return } - if err := asymkey_service.DeletePublicKey(ctx.Doer, keyID); err != nil { + if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, keyID); err != nil { ctx.Flash.Error("DeletePublicKey: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("settings.ssh_key_deletion_success")) } case "principal": - if err := asymkey_service.DeletePublicKey(ctx.Doer, ctx.FormInt64("id")); err != nil { + if err := asymkey_service.DeletePublicKey(ctx, ctx.Doer, ctx.FormInt64("id")); err != nil { ctx.Flash.Error("DeletePublicKey: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("settings.ssh_principal_deletion_success")) diff --git a/routers/web/user/setting/main_test.go b/routers/web/user/setting/main_test.go index c3938b32011..e398208d0da 100644 --- a/routers/web/user/setting/main_test.go +++ b/routers/web/user/setting/main_test.go @@ -4,14 +4,11 @@ package setting import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", "..", ".."), - }) + unittest.MainTest(m) } diff --git a/routers/web/user/setting/oauth2_common.go b/routers/web/user/setting/oauth2_common.go index 5786118f50d..5ac03e4a746 100644 --- a/routers/web/user/setting/oauth2_common.go +++ b/routers/web/user/setting/oauth2_common.go @@ -27,9 +27,8 @@ func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) { app := ctx.Data["App"].(*auth.OAuth2Application) ctx.Data["FormActionPath"] = fmt.Sprintf("%s/%d", oa.BasePathEditPrefix, app.ID) - if ctx.ContextUser.IsOrganization() { - err := shared_user.LoadHeaderCount(ctx) - if err != nil { + if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() { + if err := shared_user.LoadHeaderCount(ctx); err != nil { ctx.ServerError("LoadHeaderCount", err) return } @@ -68,6 +67,7 @@ func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) { ctx.ServerError("GenerateClientSecret", err) return } + oa.renderEditPage(ctx) } diff --git a/routers/web/user/setting/packages.go b/routers/web/user/setting/packages.go index 0d2eb14c202..34d18f999e2 100644 --- a/routers/web/user/setting/packages.go +++ b/routers/web/user/setting/packages.go @@ -107,7 +107,7 @@ func RegenerateChefKeyPair(ctx *context.Context) { return } - if err := user_model.SetUserSetting(ctx.Doer.ID, chef_module.SettingPublicPem, pub); err != nil { + if err := user_model.SetUserSetting(ctx, ctx.Doer.ID, chef_module.SettingPublicPem, pub); err != nil { ctx.ServerError("SetUserSetting", err) return } diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 0321a5759b2..f40c2f30879 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -114,7 +114,7 @@ func ProfilePost(ctx *context.Context) { ctx.Doer.Description = form.Description ctx.Doer.KeepActivityPrivate = form.KeepActivityPrivate ctx.Doer.Visibility = form.Visibility - if err := user_model.UpdateUserSetting(ctx.Doer); err != nil { + if err := user_model.UpdateUserSetting(ctx, ctx.Doer); err != nil { if _, ok := err.(user_model.ErrEmailAlreadyUsed); ok { ctx.Flash.Error(ctx.Tr("form.email_been_used")) ctx.Redirect(setting.AppSubURL + "/user/settings") @@ -219,12 +219,12 @@ func Organization(ctx *context.Context) { opts.Page = 1 } - orgs, err := organization.FindOrgs(opts) + orgs, err := organization.FindOrgs(ctx, opts) if err != nil { ctx.ServerError("FindOrgs", err) return } - total, err := organization.CountOrgs(opts) + total, err := organization.CountOrgs(ctx, opts) if err != nil { ctx.ServerError("CountOrgs", err) return @@ -348,7 +348,7 @@ func Appearance(ctx *context.Context) { ctx.Data["PageIsSettingsAppearance"] = true var hiddenCommentTypes *big.Int - val, err := user_model.GetUserSetting(ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes) + val, err := user_model.GetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes) if err != nil { ctx.ServerError("GetUserSetting", err) return @@ -379,7 +379,7 @@ func UpdateUIThemePost(ctx *context.Context) { return } - if err := user_model.UpdateUserTheme(ctx.Doer, form.Theme); err != nil { + if err := user_model.UpdateUserTheme(ctx, ctx.Doer, form.Theme); err != nil { ctx.Flash.Error(ctx.Tr("settings.theme_update_error")) ctx.Redirect(setting.AppSubURL + "/user/settings/appearance") return @@ -405,7 +405,7 @@ func UpdateUserLang(ctx *context.Context) { ctx.Doer.Language = form.Language } - if err := user_model.UpdateUserSetting(ctx.Doer); err != nil { + if err := user_model.UpdateUserSetting(ctx, ctx.Doer); err != nil { ctx.ServerError("UpdateUserSetting", err) return } @@ -420,7 +420,7 @@ func UpdateUserLang(ctx *context.Context) { // UpdateUserHiddenComments update a user's shown comment types func UpdateUserHiddenComments(ctx *context.Context) { - err := user_model.SetUserSetting(ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String()) + err := user_model.SetUserSetting(ctx, ctx.Doer.ID, user_model.SettingsKeyHiddenCommentTypes, forms.UserHiddenCommentTypesFromRequest(ctx).String()) if err != nil { ctx.ServerError("SetUserSetting", err) return diff --git a/routers/web/user/setting/security/2fa.go b/routers/web/user/setting/security/2fa.go index 0cecb1aa37f..7858b634ce3 100644 --- a/routers/web/user/setting/security/2fa.go +++ b/routers/web/user/setting/security/2fa.go @@ -28,7 +28,7 @@ func RegenerateScratchTwoFactor(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsSecurity"] = true - t, err := auth.GetTwoFactorByUID(ctx.Doer.ID) + t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID) if err != nil { if auth.IsErrTwoFactorNotEnrolled(err) { ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled")) @@ -44,7 +44,7 @@ func RegenerateScratchTwoFactor(ctx *context.Context) { return } - if err = auth.UpdateTwoFactor(t); err != nil { + if err = auth.UpdateTwoFactor(ctx, t); err != nil { ctx.ServerError("SettingsTwoFactor: Failed to UpdateTwoFactor", err) return } @@ -58,7 +58,7 @@ func DisableTwoFactor(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsSecurity"] = true - t, err := auth.GetTwoFactorByUID(ctx.Doer.ID) + t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID) if err != nil { if auth.IsErrTwoFactorNotEnrolled(err) { ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled")) @@ -68,7 +68,7 @@ func DisableTwoFactor(ctx *context.Context) { return } - if err = auth.DeleteTwoFactorByID(t.ID, ctx.Doer.ID); err != nil { + if err = auth.DeleteTwoFactorByID(ctx, t.ID, ctx.Doer.ID); err != nil { if auth.IsErrTwoFactorNotEnrolled(err) { // There is a potential DB race here - we must have been disabled by another request in the intervening period ctx.Flash.Success(ctx.Tr("settings.twofa_disabled")) @@ -145,7 +145,7 @@ func EnrollTwoFactor(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsSecurity"] = true - t, err := auth.GetTwoFactorByUID(ctx.Doer.ID) + t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID) if t != nil { // already enrolled - we should redirect back! log.Warn("Trying to re-enroll %-v in twofa when already enrolled", ctx.Doer) @@ -171,7 +171,7 @@ func EnrollTwoFactorPost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsSecurity"] = true - t, err := auth.GetTwoFactorByUID(ctx.Doer.ID) + t, err := auth.GetTwoFactorByUID(ctx, ctx.Doer.ID) if t != nil { // already enrolled ctx.Flash.Error(ctx.Tr("settings.twofa_is_enrolled")) @@ -237,7 +237,7 @@ func EnrollTwoFactorPost(ctx *context.Context) { log.Error("Unable to save changes to the session: %v", err) } - if err = auth.NewTwoFactor(t); err != nil { + if err = auth.NewTwoFactor(ctx, t); err != nil { // FIXME: We need to handle a unique constraint fail here it's entirely possible that another request has beaten us. // If there is a unique constraint fail we should just tolerate the error ctx.ServerError("SettingsTwoFactor: Failed to save two factor", err) diff --git a/routers/web/user/setting/security/openid.go b/routers/web/user/setting/security/openid.go index b5509f570fd..9a207e149d1 100644 --- a/routers/web/user/setting/security/openid.go +++ b/routers/web/user/setting/security/openid.go @@ -44,7 +44,7 @@ func OpenIDPost(ctx *context.Context) { form.Openid = id log.Trace("Normalized id: " + id) - oids, err := user_model.GetUserOpenIDs(ctx.Doer.ID) + oids, err := user_model.GetUserOpenIDs(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetUserOpenIDs", err) return @@ -105,7 +105,7 @@ func settingsOpenIDVerify(ctx *context.Context) { // DeleteOpenID response for delete user's openid func DeleteOpenID(ctx *context.Context) { - if err := user_model.DeleteUserOpenID(&user_model.UserOpenID{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil { + if err := user_model.DeleteUserOpenID(ctx, &user_model.UserOpenID{ID: ctx.FormInt64("id"), UID: ctx.Doer.ID}); err != nil { ctx.ServerError("DeleteUserOpenID", err) return } @@ -117,7 +117,7 @@ func DeleteOpenID(ctx *context.Context) { // ToggleOpenIDVisibility response for toggle visibility of user's openid func ToggleOpenIDVisibility(ctx *context.Context) { - if err := user_model.ToggleUserOpenIDVisibility(ctx.FormInt64("id")); err != nil { + if err := user_model.ToggleUserOpenIDVisibility(ctx, ctx.FormInt64("id")); err != nil { ctx.ServerError("ToggleUserOpenIDVisibility", err) return } diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go index dae9bf950dc..5a17c161fe2 100644 --- a/routers/web/user/setting/security/security.go +++ b/routers/web/user/setting/security/security.go @@ -52,21 +52,21 @@ func DeleteAccountLink(ctx *context.Context) { } func loadSecurityData(ctx *context.Context) { - enrolled, err := auth_model.HasTwoFactorByUID(ctx.Doer.ID) + enrolled, err := auth_model.HasTwoFactorByUID(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("SettingsTwoFactor", err) return } ctx.Data["TOTPEnrolled"] = enrolled - credentials, err := auth_model.GetWebAuthnCredentialsByUID(ctx.Doer.ID) + credentials, err := auth_model.GetWebAuthnCredentialsByUID(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetWebAuthnCredentialsByUID", err) return } ctx.Data["WebAuthnCredentials"] = credentials - tokens, err := auth_model.ListAccessTokens(auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID}) + tokens, err := auth_model.ListAccessTokens(ctx, auth_model.ListAccessTokensOptions{UserID: ctx.Doer.ID}) if err != nil { ctx.ServerError("ListAccessTokens", err) return @@ -113,7 +113,7 @@ func loadSecurityData(ctx *context.Context) { ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names ctx.Data["OAuth2Providers"] = oauth2Providers - openid, err := user_model.GetUserOpenIDs(ctx.Doer.ID) + openid, err := user_model.GetUserOpenIDs(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetUserOpenIDs", err) return diff --git a/routers/web/user/setting/security/webauthn.go b/routers/web/user/setting/security/webauthn.go index 990e506d6fd..ce103528c57 100644 --- a/routers/web/user/setting/security/webauthn.go +++ b/routers/web/user/setting/security/webauthn.go @@ -29,7 +29,7 @@ func WebAuthnRegister(ctx *context.Context) { form.Name = strconv.FormatInt(time.Now().UnixNano(), 16) } - cred, err := auth.GetWebAuthnCredentialByName(ctx.Doer.ID, form.Name) + cred, err := auth.GetWebAuthnCredentialByName(ctx, ctx.Doer.ID, form.Name) if err != nil && !auth.IsErrWebAuthnCredentialNotExist(err) { ctx.ServerError("GetWebAuthnCredentialsByUID", err) return @@ -88,7 +88,7 @@ func WebauthnRegisterPost(ctx *context.Context) { return } - dbCred, err := auth.GetWebAuthnCredentialByName(ctx.Doer.ID, name) + dbCred, err := auth.GetWebAuthnCredentialByName(ctx, ctx.Doer.ID, name) if err != nil && !auth.IsErrWebAuthnCredentialNotExist(err) { ctx.ServerError("GetWebAuthnCredentialsByUID", err) return @@ -99,7 +99,7 @@ func WebauthnRegisterPost(ctx *context.Context) { } // Create the credential - _, err = auth.CreateCredential(ctx.Doer.ID, name, cred) + _, err = auth.CreateCredential(ctx, ctx.Doer.ID, name, cred) if err != nil { ctx.ServerError("CreateCredential", err) return @@ -112,7 +112,7 @@ func WebauthnRegisterPost(ctx *context.Context) { // WebauthnDelete deletes an security key by id func WebauthnDelete(ctx *context.Context) { form := web.GetForm(ctx).(*forms.WebauthnDeleteForm) - if _, err := auth.DeleteCredential(form.ID, ctx.Doer.ID); err != nil { + if _, err := auth.DeleteCredential(ctx, form.ID, ctx.Doer.ID); err != nil { ctx.ServerError("GetWebAuthnCredentialByID", err) return } diff --git a/routers/web/user/stop_watch.go b/routers/web/user/stop_watch.go index d262c777c30..cac446d84a2 100644 --- a/routers/web/user/stop_watch.go +++ b/routers/web/user/stop_watch.go @@ -14,7 +14,7 @@ import ( // GetStopwatches get all stopwatches func GetStopwatches(ctx *context.Context) { - sws, err := issues_model.GetUserStopwatches(ctx.Doer.ID, db.ListOptions{ + sws, err := issues_model.GetUserStopwatches(ctx, ctx.Doer.ID, db.ListOptions{ Page: ctx.FormInt("page"), PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), }) @@ -23,7 +23,7 @@ func GetStopwatches(ctx *context.Context) { return } - count, err := issues_model.CountUserStopwatches(ctx.Doer.ID) + count, err := issues_model.CountUserStopwatches(ctx, ctx.Doer.ID) if err != nil { ctx.Error(http.StatusInternalServerError, err.Error()) return diff --git a/routers/web/user/task.go b/routers/web/user/task.go index d92bf64af0f..f35f40e6a0f 100644 --- a/routers/web/user/task.go +++ b/routers/web/user/task.go @@ -14,7 +14,7 @@ import ( // TaskStatus returns task's status func TaskStatus(ctx *context.Context) { - task, opts, err := admin_model.GetMigratingTaskByID(ctx.ParamsInt64("task"), ctx.Doer.ID) + task, opts, err := admin_model.GetMigratingTaskByID(ctx, ctx.ParamsInt64("task"), ctx.Doer.ID) if err != nil { if admin_model.IsErrTaskDoesNotExist(err) { ctx.JSON(http.StatusNotFound, map[string]any{ diff --git a/routers/web/web.go b/routers/web/web.go index e7af20d6a6c..5e21dc0f4dc 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -8,6 +8,7 @@ import ( "net/http" "strings" + auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" @@ -92,7 +93,10 @@ func buildAuthGroup() *auth_service.Group { if setting.Service.EnableReverseProxyAuth { group.Add(&auth_service.ReverseProxy{}) } - specialAdd(group) + + if setting.IsWindows && auth_model.IsSSPIEnabled() { + group.Add(&auth_service.SSPI{}) // it MUST be the last, see the comment of SSPI + } return group } @@ -975,9 +979,6 @@ func registerRoutes(m *web.Route) { }, reqUnitAccess(unit.TypeCode, perm.AccessModeRead, false)) }, ignSignIn, context_service.UserAssignmentWeb(), context.OrgAssignment()) // for "/{username}/-" (packages, projects, code) - // ***** Release Attachment Download without Signin - m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload) - m.Group("/{username}/{reponame}", func() { m.Group("/settings", func() { m.Group("", func() { @@ -1237,8 +1238,9 @@ func registerRoutes(m *web.Route) { m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS) m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom) }, ctxDataSet("EnableFeed", setting.Other.EnableFeed), - repo.MustBeNotEmpty, reqRepoReleaseReader, context.RepoRefByType(context.RepoRefTag, true)) - m.Get("/releases/attachments/{uuid}", repo.MustBeNotEmpty, reqRepoReleaseReader, repo.GetAttachment) + repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag, true)) + m.Get("/releases/attachments/{uuid}", repo.MustBeNotEmpty, repo.GetAttachment) + m.Get("/releases/download/{vTag}/{fileName}", repo.MustBeNotEmpty, repo.RedirectDownload) m.Group("/releases", func() { m.Get("/new", repo.NewRelease) m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost) diff --git a/services/actions/clear_tasks.go b/services/actions/clear_tasks.go index d2893e4f23e..7c7043c42f4 100644 --- a/services/actions/clear_tasks.go +++ b/services/actions/clear_tasks.go @@ -12,20 +12,15 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/actions" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" ) -const ( - zombieTaskTimeout = 10 * time.Minute - endlessTaskTimeout = 3 * time.Hour - abandonedJobTimeout = 24 * time.Hour -) - // StopZombieTasks stops the task which have running status, but haven't been updated for a long time func StopZombieTasks(ctx context.Context) error { return stopTasks(ctx, actions_model.FindTaskOptions{ Status: actions_model.StatusRunning, - UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-zombieTaskTimeout).Unix()), + UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-setting.Actions.ZombieTaskTimeout).Unix()), }) } @@ -33,7 +28,7 @@ func StopZombieTasks(ctx context.Context) error { func StopEndlessTasks(ctx context.Context) error { return stopTasks(ctx, actions_model.FindTaskOptions{ Status: actions_model.StatusRunning, - StartedBefore: timeutil.TimeStamp(time.Now().Add(-endlessTaskTimeout).Unix()), + StartedBefore: timeutil.TimeStamp(time.Now().Add(-setting.Actions.EndlessTaskTimeout).Unix()), }) } @@ -81,7 +76,7 @@ func stopTasks(ctx context.Context, opts actions_model.FindTaskOptions) error { func CancelAbandonedJobs(ctx context.Context) error { jobs, _, err := actions_model.FindRunJobs(ctx, actions_model.FindRunJobOptions{ Statuses: []actions_model.Status{actions_model.StatusWaiting, actions_model.StatusBlocked}, - UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-abandonedJobTimeout).Unix()), + UpdatedBefore: timeutil.TimeStamp(time.Now().Add(-setting.Actions.AbandonedJobTimeout).Unix()), }) if err != nil { log.Warn("find abandoned tasks: %v", err) diff --git a/services/asymkey/deploy_key.go b/services/asymkey/deploy_key.go index f5ca54b7238..e127cbfc6e0 100644 --- a/services/asymkey/deploy_key.go +++ b/services/asymkey/deploy_key.go @@ -4,6 +4,8 @@ package asymkey import ( + "context" + "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" @@ -11,19 +13,19 @@ import ( ) // DeleteDeployKey deletes deploy key from its repository authorized_keys file if needed. -func DeleteDeployKey(doer *user_model.User, id int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error { + dbCtx, committer, err := db.TxContext(ctx) if err != nil { return err } defer committer.Close() - if err := models.DeleteDeployKey(ctx, doer, id); err != nil { + if err := models.DeleteDeployKey(dbCtx, doer, id); err != nil { return err } if err := committer.Commit(); err != nil { return err } - return asymkey_model.RewriteAllPublicKeys() + return asymkey_model.RewriteAllPublicKeys(ctx) } diff --git a/services/asymkey/main_test.go b/services/asymkey/main_test.go index e7a03861b9c..3505b26f699 100644 --- a/services/asymkey/main_test.go +++ b/services/asymkey/main_test.go @@ -4,7 +4,6 @@ package asymkey import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,7 +13,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/asymkey/sign.go b/services/asymkey/sign.go index 252277e1bcd..1598f321653 100644 --- a/services/asymkey/sign.go +++ b/services/asymkey/sign.go @@ -151,7 +151,7 @@ Loop: return false, "", nil, &ErrWontSign{pubkey} } case twofa: - twofaModel, err := auth.GetTwoFactorByUID(u.ID) + twofaModel, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { return false, "", nil, err } @@ -187,7 +187,7 @@ Loop: return false, "", nil, &ErrWontSign{pubkey} } case twofa: - twofaModel, err := auth.GetTwoFactorByUID(u.ID) + twofaModel, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { return false, "", nil, err } @@ -240,7 +240,7 @@ Loop: return false, "", nil, &ErrWontSign{pubkey} } case twofa: - twofaModel, err := auth.GetTwoFactorByUID(u.ID) + twofaModel, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { return false, "", nil, err } @@ -302,7 +302,7 @@ Loop: return false, "", nil, &ErrWontSign{pubkey} } case twofa: - twofaModel, err := auth.GetTwoFactorByUID(u.ID) + twofaModel, err := auth.GetTwoFactorByUID(ctx, u.ID) if err != nil && !auth.IsErrTwoFactorNotEnrolled(err) { return false, "", nil, err } diff --git a/services/asymkey/ssh_key.go b/services/asymkey/ssh_key.go index 0809458107b..204d9c58f39 100644 --- a/services/asymkey/ssh_key.go +++ b/services/asymkey/ssh_key.go @@ -4,13 +4,15 @@ package asymkey import ( + "context" + asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" ) // DeletePublicKey deletes SSH key information both in database and authorized_keys file. -func DeletePublicKey(doer *user_model.User, id int64) (err error) { +func DeletePublicKey(ctx context.Context, doer *user_model.User, id int64) (err error) { key, err := asymkey_model.GetPublicKeyByID(id) if err != nil { return err @@ -25,13 +27,13 @@ func DeletePublicKey(doer *user_model.User, id int64) (err error) { } } - ctx, committer, err := db.TxContext(db.DefaultContext) + dbCtx, committer, err := db.TxContext(ctx) if err != nil { return err } defer committer.Close() - if err = asymkey_model.DeletePublicKeys(ctx, id); err != nil { + if err = asymkey_model.DeletePublicKeys(dbCtx, id); err != nil { return err } @@ -41,8 +43,8 @@ func DeletePublicKey(doer *user_model.User, id int64) (err error) { committer.Close() if key.Type == asymkey_model.KeyTypePrincipal { - return asymkey_model.RewriteAllPrincipalKeys(db.DefaultContext) + return asymkey_model.RewriteAllPrincipalKeys(ctx) } - return asymkey_model.RewriteAllPublicKeys() + return asymkey_model.RewriteAllPublicKeys(ctx) } diff --git a/services/asymkey/ssh_key_test.go b/services/asymkey/ssh_key_test.go index 32c31a43323..2395b2dadf8 100644 --- a/services/asymkey/ssh_key_test.go +++ b/services/asymkey/ssh_key_test.go @@ -8,6 +8,7 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -77,7 +78,7 @@ ssh-dss AAAAB3NzaC1kc3MAAACBAOChCC7lf6Uo9n7BmZ6M8St19PZf4Tn59NriyboW2x/DZuYAz3ib assert.Contains(t, kase.keyContents, key.Content) } for _, key := range keys { - DeletePublicKey(user, key.ID) + DeletePublicKey(db.DefaultContext, user, key.ID) } } } diff --git a/services/attachment/attachment.go b/services/attachment/attachment.go index 3e7df0cee0c..967332fd982 100644 --- a/services/attachment/attachment.go +++ b/services/attachment/attachment.go @@ -19,12 +19,12 @@ import ( ) // NewAttachment creates a new attachment object, but do not verify. -func NewAttachment(attach *repo_model.Attachment, file io.Reader, size int64) (*repo_model.Attachment, error) { +func NewAttachment(ctx context.Context, attach *repo_model.Attachment, file io.Reader, size int64) (*repo_model.Attachment, error) { if attach.RepoID == 0 { return nil, fmt.Errorf("attachment %s should belong to a repository", attach.Name) } - err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { + err := db.WithTx(ctx, func(ctx context.Context) error { attach.UUID = uuid.New().String() size, err := storage.Attachments.Save(attach.RelativePath(), file, size) if err != nil { @@ -39,7 +39,7 @@ func NewAttachment(attach *repo_model.Attachment, file io.Reader, size int64) (* } // UploadAttachment upload new attachment into storage and update database -func UploadAttachment(file io.Reader, allowedTypes string, fileSize int64, opts *repo_model.Attachment) (*repo_model.Attachment, error) { +func UploadAttachment(ctx context.Context, file io.Reader, allowedTypes string, fileSize int64, opts *repo_model.Attachment) (*repo_model.Attachment, error) { buf := make([]byte, 1024) n, _ := util.ReadAtMost(file, buf) buf = buf[:n] @@ -48,5 +48,5 @@ func UploadAttachment(file io.Reader, allowedTypes string, fileSize int64, opts return nil, err } - return NewAttachment(opts, io.MultiReader(bytes.NewReader(buf), file), fileSize) + return NewAttachment(ctx, opts, io.MultiReader(bytes.NewReader(buf), file), fileSize) } diff --git a/services/attachment/attachment_test.go b/services/attachment/attachment_test.go index 35fcef7445c..142bcfe6292 100644 --- a/services/attachment/attachment_test.go +++ b/services/attachment/attachment_test.go @@ -19,9 +19,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestUploadAttachment(t *testing.T) { @@ -34,7 +32,7 @@ func TestUploadAttachment(t *testing.T) { assert.NoError(t, err) defer f.Close() - attach, err := NewAttachment(&repo_model.Attachment{ + attach, err := NewAttachment(db.DefaultContext, &repo_model.Attachment{ RepoID: 1, UploaderID: user.ID, Name: filepath.Base(fPath), diff --git a/services/auth/auth.go b/services/auth/auth.go index c7fdc56cbed..0c8acac61f0 100644 --- a/services/auth/auth.go +++ b/services/auth/auth.go @@ -10,7 +10,6 @@ import ( "regexp" "strings" - "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/auth/webauthn" gitea_context "code.gitea.io/gitea/modules/context" @@ -83,7 +82,7 @@ func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore if len(user.Language) == 0 { lc := middleware.Locale(resp, req) user.Language = lc.Language() - if err := user_model.UpdateUserCols(db.DefaultContext, user, "language"); err != nil { + if err := user_model.UpdateUserCols(req.Context(), user, "language"); err != nil { log.Error(fmt.Sprintf("Error updating user language [user: %d, locale: %s]", user.ID, user.Language)) return } diff --git a/services/auth/basic.go b/services/auth/basic.go index ea8df3d0ea9..bb9eb7a3216 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -71,7 +71,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore } // check oauth2 token - uid := CheckOAuthAccessToken(authToken) + uid := CheckOAuthAccessToken(req.Context(), authToken) if uid != 0 { log.Trace("Basic Authorization: Valid OAuthAccessToken for user[%d]", uid) @@ -86,7 +86,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore } // check personal access token - token, err := auth_model.GetAccessTokenBySHA(authToken) + token, err := auth_model.GetAccessTokenBySHA(req.Context(), authToken) if err == nil { log.Trace("Basic Authorization: Valid AccessToken for user[%d]", uid) u, err := user_model.GetUserByID(req.Context(), token.UID) @@ -96,7 +96,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore } token.UpdatedUnix = timeutil.TimeStampNow() - if err = auth_model.UpdateAccessToken(token); err != nil { + if err = auth_model.UpdateAccessToken(req.Context(), token); err != nil { log.Error("UpdateAccessToken: %v", err) } @@ -123,7 +123,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore } log.Trace("Basic Authorization: Attempting SignIn for %s", uname) - u, source, err := UserSignIn(uname, passwd) + u, source, err := UserSignIn(req.Context(), uname, passwd) if err != nil { if !user_model.IsErrUserNotExist(err) { log.Error("UserSignIn: %v", err) diff --git a/services/auth/interface.go b/services/auth/interface.go index dc91747a460..ece28af12d1 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -33,7 +33,7 @@ type Method interface { // PasswordAuthenticator represents a source of authentication type PasswordAuthenticator interface { - Authenticate(user *user_model.User, login, password string) (*user_model.User, error) + Authenticate(ctx context.Context, user *user_model.User, login, password string) (*user_model.User, error) } // LocalTwoFASkipper represents a source of authentication that can skip local 2fa diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index e621b5ffad7..38b705cc5b8 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -5,13 +5,13 @@ package auth import ( + "context" "net/http" "strings" "time" actions_model "code.gitea.io/gitea/models/actions" auth_model "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" @@ -25,7 +25,7 @@ var ( ) // CheckOAuthAccessToken returns uid of user from oauth token -func CheckOAuthAccessToken(accessToken string) int64 { +func CheckOAuthAccessToken(ctx context.Context, accessToken string) int64 { // JWT tokens require a "." if !strings.Contains(accessToken, ".") { return 0 @@ -36,7 +36,7 @@ func CheckOAuthAccessToken(accessToken string) int64 { return 0 } var grant *auth_model.OAuth2Grant - if grant, err = auth_model.GetOAuth2GrantByID(db.DefaultContext, token.GrantID); err != nil || grant == nil { + if grant, err = auth_model.GetOAuth2GrantByID(ctx, token.GrantID); err != nil || grant == nil { return 0 } if token.Type != oauth2.TypeAccessToken { @@ -83,21 +83,21 @@ func parseToken(req *http.Request) (string, bool) { // userIDFromToken returns the user id corresponding to the OAuth token. // It will set 'IsApiToken' to true if the token is an API token and // set 'ApiTokenScope' to the scope of the access token -func (o *OAuth2) userIDFromToken(tokenSHA string, store DataStore) int64 { +func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store DataStore) int64 { // Let's see if token is valid. if strings.Contains(tokenSHA, ".") { - uid := CheckOAuthAccessToken(tokenSHA) + uid := CheckOAuthAccessToken(ctx, tokenSHA) if uid != 0 { store.GetData()["IsApiToken"] = true store.GetData()["ApiTokenScope"] = auth_model.AccessTokenScopeAll // fallback to all } return uid } - t, err := auth_model.GetAccessTokenBySHA(tokenSHA) + t, err := auth_model.GetAccessTokenBySHA(ctx, tokenSHA) if err != nil { if auth_model.IsErrAccessTokenNotExist(err) { // check task token - task, err := actions_model.GetRunningTaskByToken(db.DefaultContext, tokenSHA) + task, err := actions_model.GetRunningTaskByToken(ctx, tokenSHA) if err == nil && task != nil { log.Trace("Basic Authorization: Valid AccessToken for task[%d]", task.ID) @@ -112,7 +112,7 @@ func (o *OAuth2) userIDFromToken(tokenSHA string, store DataStore) int64 { return 0 } t.UpdatedUnix = timeutil.TimeStampNow() - if err = auth_model.UpdateAccessToken(t); err != nil { + if err = auth_model.UpdateAccessToken(ctx, t); err != nil { log.Error("UpdateAccessToken: %v", err) } store.GetData()["IsApiToken"] = true @@ -125,7 +125,9 @@ func (o *OAuth2) userIDFromToken(tokenSHA string, store DataStore) int64 { // If verification is successful returns an existing user object. // Returns nil if verification fails. func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { - if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) && !isAuthenticatedTokenRequest(req) { + // These paths are not API paths, but we still want to check for tokens because they maybe in the API returned URLs + if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) && !isAuthenticatedTokenRequest(req) && + !gitRawReleasePathRe.MatchString(req.URL.Path) { return nil, nil } @@ -134,7 +136,7 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor return nil, nil } - id := o.userIDFromToken(token, store) + id := o.userIDFromToken(req.Context(), token, store) if id <= 0 && id != -2 { // -2 means actions, so we need to allow it. return nil, user_model.ErrUserNotExist{} diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 62e60ccdc14..ad525f5c95f 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -164,7 +164,7 @@ func (r *ReverseProxy) newUser(req *http.Request) *user_model.User { IsActive: util.OptionalBoolTrue, } - if err := user_model.CreateUser(user, &overwriteDefault); err != nil { + if err := user_model.CreateUser(req.Context(), user, &overwriteDefault); err != nil { // FIXME: should I create a system notice? log.Error("CreateUser: %v", err) return nil diff --git a/services/auth/signin.go b/services/auth/signin.go index 1095b27fe2d..6d515ac628a 100644 --- a/services/auth/signin.go +++ b/services/auth/signin.go @@ -4,6 +4,7 @@ package auth import ( + "context" "strings" "code.gitea.io/gitea/models/auth" @@ -20,14 +21,14 @@ import ( ) // UserSignIn validates user name and password. -func UserSignIn(username, password string) (*user_model.User, *auth.Source, error) { +func UserSignIn(ctx context.Context, username, password string) (*user_model.User, *auth.Source, error) { var user *user_model.User isEmail := false if strings.Contains(username, "@") { isEmail = true emailAddress := user_model.EmailAddress{LowerEmail: strings.ToLower(strings.TrimSpace(username))} // check same email - has, err := db.GetEngine(db.DefaultContext).Get(&emailAddress) + has, err := db.GetEngine(ctx).Get(&emailAddress) if err != nil { return nil, nil, err } @@ -49,7 +50,7 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro } if user != nil { - hasUser, err := user_model.GetUser(user) + hasUser, err := user_model.GetUser(ctx, user) if err != nil { return nil, nil, err } @@ -69,7 +70,7 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro return nil, nil, smtp.ErrUnsupportedLoginType } - user, err := authenticator.Authenticate(user, user.LoginName, password) + user, err := authenticator.Authenticate(ctx, user, user.LoginName, password) if err != nil { return nil, nil, err } @@ -100,7 +101,7 @@ func UserSignIn(username, password string) (*user_model.User, *auth.Source, erro continue } - authUser, err := authenticator.Authenticate(nil, username, password) + authUser, err := authenticator.Authenticate(ctx, nil, username, password) if err == nil { if !authUser.ProhibitLogin { diff --git a/services/auth/source/db/authenticate.go b/services/auth/source/db/authenticate.go index 34a0459149a..8160141863a 100644 --- a/services/auth/source/db/authenticate.go +++ b/services/auth/source/db/authenticate.go @@ -4,9 +4,9 @@ package db import ( + "context" "fmt" - "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" @@ -43,7 +43,7 @@ func (err ErrUserPasswordInvalid) Unwrap() error { } // Authenticate authenticates the provided user against the DB -func Authenticate(user *user_model.User, login, password string) (*user_model.User, error) { +func Authenticate(ctx context.Context, user *user_model.User, login, password string) (*user_model.User, error) { if user == nil { return nil, user_model.ErrUserNotExist{Name: login} } @@ -61,7 +61,7 @@ func Authenticate(user *user_model.User, login, password string) (*user_model.Us if err := user.SetPassword(password); err != nil { return nil, err } - if err := user_model.UpdateUserCols(db.DefaultContext, user, "passwd", "passwd_hash_algo", "salt"); err != nil { + if err := user_model.UpdateUserCols(ctx, user, "passwd", "passwd_hash_algo", "salt"); err != nil { return nil, err } } diff --git a/services/auth/source/db/source.go b/services/auth/source/db/source.go index 3f4113c7904..50eae274393 100644 --- a/services/auth/source/db/source.go +++ b/services/auth/source/db/source.go @@ -4,6 +4,8 @@ package db import ( + "context" + "code.gitea.io/gitea/models/auth" user_model "code.gitea.io/gitea/models/user" ) @@ -23,8 +25,8 @@ func (source *Source) ToDB() ([]byte, error) { // Authenticate queries if login/password is valid against the PAM, // and create a local user if success when enabled. -func (source *Source) Authenticate(user *user_model.User, login, password string) (*user_model.User, error) { - return Authenticate(user, login, password) +func (source *Source) Authenticate(ctx context.Context, user *user_model.User, login, password string) (*user_model.User, error) { + return Authenticate(ctx, user, login, password) } func init() { diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go index 3f3219adb94..9f4d7ed68f5 100644 --- a/services/auth/source/ldap/source_authenticate.go +++ b/services/auth/source/ldap/source_authenticate.go @@ -4,12 +4,12 @@ package ldap import ( + "context" "fmt" "strings" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" auth_module "code.gitea.io/gitea/modules/auth" "code.gitea.io/gitea/modules/util" @@ -19,7 +19,7 @@ import ( // Authenticate queries if login/password is valid against the LDAP directory pool, // and create a local user if success when enabled. -func (source *Source) Authenticate(user *user_model.User, userName, password string) (*user_model.User, error) { +func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) { loginName := userName if user != nil { loginName = user.LoginName @@ -29,15 +29,21 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str // User not in LDAP, do nothing return nil, user_model.ErrUserNotExist{Name: loginName} } - + // Fallback. + if len(sr.Username) == 0 { + sr.Username = userName + } + if len(sr.Mail) == 0 { + sr.Mail = fmt.Sprintf("%s@localhost.local", sr.Username) + } isAttributeSSHPublicKeySet := len(strings.TrimSpace(source.AttributeSSHPublicKey)) > 0 // Update User admin flag if exist - if isExist, err := user_model.IsUserExist(db.DefaultContext, 0, sr.Username); err != nil { + if isExist, err := user_model.IsUserExist(ctx, 0, sr.Username); err != nil { return nil, err } else if isExist { if user == nil { - user, err = user_model.GetUserByName(db.DefaultContext, sr.Username) + user, err = user_model.GetUserByName(ctx, sr.Username) if err != nil { return nil, err } @@ -55,7 +61,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str cols = append(cols, "is_restricted") } if len(cols) > 0 { - err = user_model.UpdateUserCols(db.DefaultContext, user, cols...) + err = user_model.UpdateUserCols(ctx, user, cols...) if err != nil { return nil, err } @@ -65,20 +71,11 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str if user != nil { if isAttributeSSHPublicKeySet && asymkey_model.SynchronizePublicKeys(user, source.authSource, sr.SSHPublicKey) { - if err := asymkey_model.RewriteAllPublicKeys(); err != nil { + if err := asymkey_model.RewriteAllPublicKeys(ctx); err != nil { return user, err } } } else { - // Fallback. - if len(sr.Username) == 0 { - sr.Username = userName - } - - if len(sr.Mail) == 0 { - sr.Mail = fmt.Sprintf("%s@localhost.local", sr.Username) - } - user = &user_model.User{ LowerName: strings.ToLower(sr.Username), Name: sr.Username, @@ -94,13 +91,13 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str IsActive: util.OptionalBoolTrue, } - err := user_model.CreateUser(user, overwriteDefault) + err := user_model.CreateUser(ctx, user, overwriteDefault) if err != nil { return user, err } if isAttributeSSHPublicKeySet && asymkey_model.AddPublicKeysBySource(user, source.authSource, sr.SSHPublicKey) { - if err := asymkey_model.RewriteAllPublicKeys(); err != nil { + if err := asymkey_model.RewriteAllPublicKeys(ctx); err != nil { return user, err } } @@ -116,7 +113,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str if err != nil { return user, err } - if err := source_service.SyncGroupsToTeams(db.DefaultContext, user, sr.Groups, groupTeamMapping, source.GroupTeamMapRemoval); err != nil { + if err := source_service.SyncGroupsToTeams(ctx, user, sr.Groups, groupTeamMapping, source.GroupTeamMapRemoval); err != nil { return user, err } } diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go index df5eb603938..261f2b8a956 100644 --- a/services/auth/source/ldap/source_sync.go +++ b/services/auth/source/ldap/source_sync.go @@ -28,7 +28,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { var sshKeysNeedUpdate bool // Find all users with this login type - FIXME: Should this be an iterator? - users, err := user_model.GetUsersBySource(source.authSource) + users, err := user_model.GetUsersBySource(ctx, source.authSource) if err != nil { log.Error("SyncExternalUsers: %v", err) return err @@ -77,7 +77,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { log.Warn("SyncExternalUsers: Cancelled at update of %s before completed update of users", source.authSource.Name) // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed if sshKeysNeedUpdate { - err = asymkey_model.RewriteAllPublicKeys() + err = asymkey_model.RewriteAllPublicKeys(ctx) if err != nil { log.Error("RewriteAllPublicKeys: %v", err) } @@ -128,7 +128,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { IsActive: util.OptionalBoolTrue, } - err = user_model.CreateUser(usr, overwriteDefault) + err = user_model.CreateUser(ctx, usr, overwriteDefault) if err != nil { log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err) } @@ -193,7 +193,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { // Rewrite authorized_keys file if LDAP Public SSH Key attribute is set and any key was added or removed if sshKeysNeedUpdate { - err = asymkey_model.RewriteAllPublicKeys() + err = asymkey_model.RewriteAllPublicKeys(ctx) if err != nil { log.Error("RewriteAllPublicKeys: %v", err) } diff --git a/services/auth/source/oauth2/providers.go b/services/auth/source/oauth2/providers.go index 7572aa20c0a..e3a0cb0335d 100644 --- a/services/auth/source/oauth2/providers.go +++ b/services/auth/source/oauth2/providers.go @@ -22,7 +22,7 @@ import ( type Provider interface { Name() string DisplayName() string - IconHTML() template.HTML + IconHTML(size int) template.HTML CustomURLSettings() *CustomURLSettings } @@ -54,14 +54,16 @@ func (p *AuthSourceProvider) DisplayName() string { return p.sourceName } -func (p *AuthSourceProvider) IconHTML() template.HTML { +func (p *AuthSourceProvider) IconHTML(size int) template.HTML { if p.iconURL != "" { - img := fmt.Sprintf(`%s`, + img := fmt.Sprintf(`%s`, + size, + size, html.EscapeString(p.iconURL), html.EscapeString(p.DisplayName()), ) return template.HTML(img) } - return p.GothProvider.IconHTML() + return p.GothProvider.IconHTML(size) } // Providers contains the map of registered OAuth2 providers in Gitea (based on goth) diff --git a/services/auth/source/oauth2/providers_base.go b/services/auth/source/oauth2/providers_base.go index 5ba06febaf7..5b6694487bf 100644 --- a/services/auth/source/oauth2/providers_base.go +++ b/services/auth/source/oauth2/providers_base.go @@ -27,7 +27,7 @@ func (b *BaseProvider) DisplayName() string { } // IconHTML returns icon HTML for this provider -func (b *BaseProvider) IconHTML() template.HTML { +func (b *BaseProvider) IconHTML(size int) template.HTML { svgName := "gitea-" + b.name switch b.name { case "gplus": @@ -35,10 +35,10 @@ func (b *BaseProvider) IconHTML() template.HTML { case "github": svgName = "octicon-mark-github" } - svgHTML := svg.RenderHTML(svgName, 20, "gt-mr-3") + svgHTML := svg.RenderHTML(svgName, size, "gt-mr-3") if svgHTML == "" { log.Error("No SVG icon for oauth2 provider %q", b.name) - svgHTML = svg.RenderHTML("gitea-openid", 20, "gt-mr-3") + svgHTML = svg.RenderHTML("gitea-openid", size, "gt-mr-3") } return svgHTML } diff --git a/services/auth/source/oauth2/providers_openid.go b/services/auth/source/oauth2/providers_openid.go index 54530ae8a85..a4dcfcafc7e 100644 --- a/services/auth/source/oauth2/providers_openid.go +++ b/services/auth/source/oauth2/providers_openid.go @@ -28,8 +28,8 @@ func (o *OpenIDProvider) DisplayName() string { } // IconHTML returns icon HTML for this provider -func (o *OpenIDProvider) IconHTML() template.HTML { - return svg.RenderHTML("gitea-openid", 20, "gt-mr-3") +func (o *OpenIDProvider) IconHTML(size int) template.HTML { + return svg.RenderHTML("gitea-openid", size, "gt-mr-3") } // CreateGothProvider creates a GothProvider from this Provider diff --git a/services/auth/source/oauth2/source_authenticate.go b/services/auth/source/oauth2/source_authenticate.go index e3e2a9e192f..bbda35dee00 100644 --- a/services/auth/source/oauth2/source_authenticate.go +++ b/services/auth/source/oauth2/source_authenticate.go @@ -4,13 +4,15 @@ package oauth2 import ( + "context" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/services/auth/source/db" ) // Authenticate falls back to the db authenticator -func (source *Source) Authenticate(user *user_model.User, login, password string) (*user_model.User, error) { - return db.Authenticate(user, login, password) +func (source *Source) Authenticate(ctx context.Context, user *user_model.User, login, password string) (*user_model.User, error) { + return db.Authenticate(ctx, user, login, password) } // NB: Oauth2 does not implement LocalTwoFASkipper for password authentication diff --git a/services/auth/source/pam/source_authenticate.go b/services/auth/source/pam/source_authenticate.go index e3a74e495cd..0891a86392c 100644 --- a/services/auth/source/pam/source_authenticate.go +++ b/services/auth/source/pam/source_authenticate.go @@ -4,6 +4,7 @@ package pam import ( + "context" "fmt" "strings" @@ -18,7 +19,7 @@ import ( // Authenticate queries if login/password is valid against the PAM, // and create a local user if success when enabled. -func (source *Source) Authenticate(user *user_model.User, userName, password string) (*user_model.User, error) { +func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) { pamLogin, err := pam.Auth(source.ServiceName, userName, password) if err != nil { if strings.Contains(err.Error(), "Authentication failure") { @@ -62,7 +63,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str IsActive: util.OptionalBoolTrue, } - if err := user_model.CreateUser(user, overwriteDefault); err != nil { + if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { return user, err } diff --git a/services/auth/source/smtp/source_authenticate.go b/services/auth/source/smtp/source_authenticate.go index 7d7d1aa8b6b..b244fc7d408 100644 --- a/services/auth/source/smtp/source_authenticate.go +++ b/services/auth/source/smtp/source_authenticate.go @@ -4,6 +4,7 @@ package smtp import ( + "context" "errors" "net/smtp" "net/textproto" @@ -16,7 +17,7 @@ import ( // Authenticate queries if the provided login/password is authenticates against the SMTP server // Users will be autoregistered as required -func (source *Source) Authenticate(user *user_model.User, userName, password string) (*user_model.User, error) { +func (source *Source) Authenticate(ctx context.Context, user *user_model.User, userName, password string) (*user_model.User, error) { // Verify allowed domains. if len(source.AllowedDomains) > 0 { idx := strings.Index(userName, "@") @@ -77,7 +78,7 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str IsActive: util.OptionalBoolTrue, } - if err := user_model.CreateUser(user, overwriteDefault); err != nil { + if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { return user, err } diff --git a/services/auth/source/source_group_sync.go b/services/auth/source/source_group_sync.go index e42f60bde24..3a2411ec55f 100644 --- a/services/auth/source/source_group_sync.go +++ b/services/auth/source/source_group_sync.go @@ -100,12 +100,12 @@ func syncGroupsToTeamsCached(ctx context.Context, user *user_model.User, orgTeam } if action == syncAdd && !isMember { - if err := models.AddTeamMember(team, user.ID); err != nil { + if err := models.AddTeamMember(ctx, team, user.ID); err != nil { log.Error("group sync: Could not add user to team: %v", err) return err } } else if action == syncRemove && isMember { - if err := models.RemoveTeamMember(team, user.ID); err != nil { + if err := models.RemoveTeamMember(ctx, team, user.ID); err != nil { log.Error("group sync: Could not remove user from team: %v", err) return err } diff --git a/services/auth/sspi_windows.go b/services/auth/sspi.go similarity index 86% rename from services/auth/sspi_windows.go rename to services/auth/sspi.go index a4880c73346..d4f7e3ec60c 100644 --- a/services/auth/sspi_windows.go +++ b/services/auth/sspi.go @@ -4,6 +4,7 @@ package auth import ( + "context" "errors" "net/http" "strings" @@ -21,19 +22,21 @@ import ( "code.gitea.io/gitea/services/auth/source/sspi" gouuid "github.com/google/uuid" - "github.com/quasoft/websspi" ) const ( tplSignIn base.TplName = "user/auth/signin" ) +type SSPIAuth interface { + AppendAuthenticateHeader(w http.ResponseWriter, data string) + Authenticate(r *http.Request, w http.ResponseWriter) (userInfo *SSPIUserInfo, outToken string, err error) +} + var ( - // sspiAuth is a global instance of the websspi authentication package, - // which is used to avoid acquiring the server credential handle on - // every request - sspiAuth *websspi.Authenticator - sspiAuthOnce sync.Once + sspiAuth SSPIAuth // a global instance of the websspi authenticator to avoid acquiring the server credential handle on every request + sspiAuthOnce sync.Once + sspiAuthErrInit error // Ensure the struct implements the interface. _ Method = &SSPI{} @@ -41,8 +44,9 @@ var ( // SSPI implements the SingleSignOn interface and authenticates requests // via the built-in SSPI module in Windows for SPNEGO authentication. -// On successful authentication returns a valid user object. -// Returns nil if authentication fails. +// The SSPI plugin is expected to be executed last, as it returns 401 status code if negotiation +// fails (or if negotiation should continue), which would prevent other authentication methods +// to execute at all. type SSPI struct{} // Name represents the name of auth method @@ -55,15 +59,10 @@ func (s *SSPI) Name() string { // If negotiation should continue or authentication fails, immediately returns a 401 HTTP // response code, as required by the SPNEGO protocol. func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { - var errInit error - sspiAuthOnce.Do(func() { - config := websspi.NewConfig() - sspiAuth, errInit = websspi.New(config) - }) - if errInit != nil { - return nil, errInit + sspiAuthOnce.Do(func() { sspiAuthErrInit = sspiAuthInit() }) + if sspiAuthErrInit != nil { + return nil, sspiAuthErrInit } - if !s.shouldAuthenticate(req) { return nil, nil } @@ -113,7 +112,7 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, log.Error("User '%s' not found", username) return nil, nil } - user, err = s.newUser(username, cfg) + user, err = s.newUser(req.Context(), username, cfg) if err != nil { log.Error("CreateUser: %v", err) return nil, err @@ -161,7 +160,7 @@ func (s *SSPI) shouldAuthenticate(req *http.Request) (shouldAuth bool) { // newUser creates a new user object for the purpose of automatic registration // and populates its name and email with the information present in request headers. -func (s *SSPI) newUser(username string, cfg *sspi.Source) (*user_model.User, error) { +func (s *SSPI) newUser(ctx context.Context, username string, cfg *sspi.Source) (*user_model.User, error) { email := gouuid.New().String() + "@localhost.localdomain" user := &user_model.User{ Name: username, @@ -177,7 +176,7 @@ func (s *SSPI) newUser(username string, cfg *sspi.Source) (*user_model.User, err KeepEmailPrivate: util.OptionalBoolTrue, EmailNotificationsPreference: &emailNotificationPreference, } - if err := user_model.CreateUser(user, overwriteDefault); err != nil { + if err := user_model.CreateUser(ctx, user, overwriteDefault); err != nil { return nil, err } diff --git a/services/auth/sspiauth_posix.go b/services/auth/sspiauth_posix.go new file mode 100644 index 00000000000..49b0ed4a52a --- /dev/null +++ b/services/auth/sspiauth_posix.go @@ -0,0 +1,30 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build !windows + +package auth + +import ( + "errors" + "net/http" +) + +type SSPIUserInfo struct { + Username string // Name of user, usually in the form DOMAIN\User + Groups []string // The global groups the user is a member of +} + +type sspiAuthMock struct{} + +func (s sspiAuthMock) AppendAuthenticateHeader(w http.ResponseWriter, data string) { +} + +func (s sspiAuthMock) Authenticate(r *http.Request, w http.ResponseWriter) (userInfo *SSPIUserInfo, outToken string, err error) { + return nil, "", errors.New("not implemented") +} + +func sspiAuthInit() error { + sspiAuth = &sspiAuthMock{} // TODO: we can mock the SSPI auth in tests + return nil +} diff --git a/services/auth/sspiauth_windows.go b/services/auth/sspiauth_windows.go new file mode 100644 index 00000000000..093caaed33c --- /dev/null +++ b/services/auth/sspiauth_windows.go @@ -0,0 +1,19 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +//go:build windows + +package auth + +import ( + "github.com/quasoft/websspi" +) + +type SSPIUserInfo = websspi.UserInfo + +func sspiAuthInit() error { + var err error + config := websspi.NewConfig() + sspiAuth, err = websspi.New(config) + return err +} diff --git a/services/context/user.go b/services/context/user.go index 81c2746819e..8b2faf33691 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -69,7 +69,7 @@ func userAssignment(ctx *context.Base, doer *user_model.User, errCb func(int, st contextUser, err = user_model.GetUserByName(ctx, username) if err != nil { if user_model.IsErrUserNotExist(err) { - if redirectUserID, err := user_model.LookupUserRedirect(username); err == nil { + if redirectUserID, err := user_model.LookupUserRedirect(ctx, username); err == nil { context.RedirectToUser(ctx, username, redirectUserID) } else if user_model.IsErrUserRedirectNotExist(err) { errCb(http.StatusNotFound, "GetUserByName", err) diff --git a/services/convert/convert.go b/services/convert/convert.go index a7a777e8bd6..366782390a7 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -13,7 +13,6 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" - "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" @@ -107,28 +106,28 @@ func ToBranch(ctx context.Context, repo *repo_model.Repository, branchName strin } // ToBranchProtection convert a ProtectedBranch to api.BranchProtection -func ToBranchProtection(bp *git_model.ProtectedBranch) *api.BranchProtection { - pushWhitelistUsernames, err := user_model.GetUserNamesByIDs(bp.WhitelistUserIDs) +func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch) *api.BranchProtection { + pushWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.WhitelistUserIDs) if err != nil { log.Error("GetUserNamesByIDs (WhitelistUserIDs): %v", err) } - mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(bp.MergeWhitelistUserIDs) + mergeWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.MergeWhitelistUserIDs) if err != nil { log.Error("GetUserNamesByIDs (MergeWhitelistUserIDs): %v", err) } - approvalsWhitelistUsernames, err := user_model.GetUserNamesByIDs(bp.ApprovalsWhitelistUserIDs) + approvalsWhitelistUsernames, err := user_model.GetUserNamesByIDs(ctx, bp.ApprovalsWhitelistUserIDs) if err != nil { log.Error("GetUserNamesByIDs (ApprovalsWhitelistUserIDs): %v", err) } - pushWhitelistTeams, err := organization.GetTeamNamesByID(bp.WhitelistTeamIDs) + pushWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.WhitelistTeamIDs) if err != nil { log.Error("GetTeamNamesByID (WhitelistTeamIDs): %v", err) } - mergeWhitelistTeams, err := organization.GetTeamNamesByID(bp.MergeWhitelistTeamIDs) + mergeWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.MergeWhitelistTeamIDs) if err != nil { log.Error("GetTeamNamesByID (MergeWhitelistTeamIDs): %v", err) } - approvalsWhitelistTeams, err := organization.GetTeamNamesByID(bp.ApprovalsWhitelistTeamIDs) + approvalsWhitelistTeams, err := organization.GetTeamNamesByID(ctx, bp.ApprovalsWhitelistTeamIDs) if err != nil { log.Error("GetTeamNamesByID (ApprovalsWhitelistTeamIDs): %v", err) } @@ -334,7 +333,7 @@ func ToTeams(ctx context.Context, teams []*organization.Team, loadOrgs bool) ([] if loadOrgs { apiOrg, ok := cache[teams[i].OrgID] if !ok { - org, err := organization.GetOrgByID(db.DefaultContext, teams[i].OrgID) + org, err := organization.GetOrgByID(ctx, teams[i].OrgID) if err != nil { return nil, err } diff --git a/services/convert/git_commit.go b/services/convert/git_commit.go index ac15719c1cf..ed08691c8b1 100644 --- a/services/convert/git_commit.go +++ b/services/convert/git_commit.go @@ -210,7 +210,7 @@ func ToCommit(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Rep // Get diff stats for commit if opts.Stat { - diff, err := gitdiff.GetDiff(gitRepo, &gitdiff.DiffOptions{ + diff, err := gitdiff.GetDiff(ctx, gitRepo, &gitdiff.DiffOptions{ AfterCommitID: commit.ID.String(), }) if err != nil { diff --git a/services/convert/issue.go b/services/convert/issue.go index 33fad31d48a..708eac36cff 100644 --- a/services/convert/issue.go +++ b/services/convert/issue.go @@ -62,7 +62,7 @@ func toIssue(ctx context.Context, issue *issues_model.Issue, getDownloadURL func if err := issue.Repo.LoadOwner(ctx); err != nil { return &api.Issue{} } - apiIssue.URL = issue.APIURL() + apiIssue.URL = issue.APIURL(ctx) apiIssue.HTMLURL = issue.HTMLURL() apiIssue.Labels = ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner) apiIssue.Repo = &api.RepositoryMeta{ diff --git a/services/convert/issue_comment.go b/services/convert/issue_comment.go index 1308051e7c1..b034a508971 100644 --- a/services/convert/issue_comment.go +++ b/services/convert/issue_comment.go @@ -19,9 +19,9 @@ func ToAPIComment(ctx context.Context, repo *repo_model.Repository, c *issues_mo return &api.Comment{ ID: c.ID, Poster: ToUser(ctx, c.Poster, nil), - HTMLURL: c.HTMLURL(), - IssueURL: c.IssueURL(), - PRURL: c.PRURL(), + HTMLURL: c.HTMLURL(ctx), + IssueURL: c.IssueURL(ctx), + PRURL: c.PRURL(ctx), Body: c.Content, Attachments: ToAPIAttachments(repo, c.Attachments), Created: c.CreatedUnix.AsTime(), @@ -37,31 +37,31 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu return nil } - err = c.LoadAssigneeUserAndTeam() + err = c.LoadAssigneeUserAndTeam(ctx) if err != nil { log.Error("LoadAssigneeUserAndTeam: %v", err) return nil } - err = c.LoadResolveDoer() + err = c.LoadResolveDoer(ctx) if err != nil { log.Error("LoadResolveDoer: %v", err) return nil } - err = c.LoadDepIssueDetails() + err = c.LoadDepIssueDetails(ctx) if err != nil { log.Error("LoadDepIssueDetails: %v", err) return nil } - err = c.LoadTime() + err = c.LoadTime(ctx) if err != nil { log.Error("LoadTime: %v", err) return nil } - err = c.LoadLabel() + err = c.LoadLabel(ctx) if err != nil { log.Error("LoadLabel: %v", err) return nil @@ -82,9 +82,9 @@ func ToTimelineComment(ctx context.Context, repo *repo_model.Repository, c *issu ID: c.ID, Type: c.Type.String(), Poster: ToUser(ctx, c.Poster, nil), - HTMLURL: c.HTMLURL(), - IssueURL: c.IssueURL(), - PRURL: c.PRURL(), + HTMLURL: c.HTMLURL(ctx), + IssueURL: c.IssueURL(ctx), + PRURL: c.PRURL(ctx), Body: c.Content, Created: c.CreatedUnix.AsTime(), Updated: c.UpdatedUnix.AsTime(), diff --git a/services/convert/main_test.go b/services/convert/main_test.go index c2298dcb74a..363cc4a97f5 100644 --- a/services/convert/main_test.go +++ b/services/convert/main_test.go @@ -4,7 +4,6 @@ package convert import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -13,7 +12,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/convert/mirror.go b/services/convert/mirror.go index f7a8e17fd0c..249ce2f9689 100644 --- a/services/convert/mirror.go +++ b/services/convert/mirror.go @@ -4,36 +4,23 @@ package convert import ( + "context" + repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" ) // ToPushMirror convert from repo_model.PushMirror and remoteAddress to api.TopicResponse -func ToPushMirror(pm *repo_model.PushMirror) (*api.PushMirror, error) { - repo := pm.GetRepository() - remoteAddress, err := getRemoteAddress(repo, pm.RemoteName) - if err != nil { - return nil, err - } +func ToPushMirror(ctx context.Context, pm *repo_model.PushMirror) (*api.PushMirror, error) { + repo := pm.GetRepository(ctx) return &api.PushMirror{ RepoName: repo.Name, RemoteName: pm.RemoteName, - RemoteAddress: remoteAddress, - CreatedUnix: pm.CreatedUnix.FormatLong(), - LastUpdateUnix: pm.LastUpdateUnix.FormatLong(), + RemoteAddress: pm.RemoteAddress, + CreatedUnix: pm.CreatedUnix.AsTime(), + LastUpdateUnix: pm.LastUpdateUnix.AsTimePtr(), LastError: pm.LastError, Interval: pm.Interval.String(), SyncOnCommit: pm.SyncOnCommit, }, nil } - -func getRemoteAddress(repo *repo_model.Repository, remoteName string) (string, error) { - url, err := git.GetRemoteURL(git.DefaultContext, repo.RepoPath(), remoteName) - if err != nil { - return "", err - } - // remove confidential information - url.User = nil - return url.String(), nil -} diff --git a/services/convert/notification.go b/services/convert/notification.go index 3906fa9b388..0b97530d8b5 100644 --- a/services/convert/notification.go +++ b/services/convert/notification.go @@ -4,17 +4,17 @@ package convert import ( + "context" "net/url" activities_model "code.gitea.io/gitea/models/activities" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" api "code.gitea.io/gitea/modules/structs" ) // ToNotificationThread convert a Notification to api.NotificationThread -func ToNotificationThread(n *activities_model.Notification) *api.NotificationThread { +func ToNotificationThread(ctx context.Context, n *activities_model.Notification) *api.NotificationThread { result := &api.NotificationThread{ ID: n.ID, Unread: !(n.Status == activities_model.NotificationStatusRead || n.Status == activities_model.NotificationStatusPinned), @@ -25,7 +25,7 @@ func ToNotificationThread(n *activities_model.Notification) *api.NotificationThr // since user only get notifications when he has access to use minimal access mode if n.Repository != nil { - result.Repository = ToRepo(db.DefaultContext, n.Repository, access_model.Permission{AccessMode: perm.AccessModeRead}) + result.Repository = ToRepo(ctx, n.Repository, access_model.Permission{AccessMode: perm.AccessModeRead}) // This permission is not correct and we should not be reporting it for repository := result.Repository; repository != nil; repository = repository.Parent { @@ -39,29 +39,29 @@ func ToNotificationThread(n *activities_model.Notification) *api.NotificationThr result.Subject = &api.NotificationSubject{Type: api.NotifySubjectIssue} if n.Issue != nil { result.Subject.Title = n.Issue.Title - result.Subject.URL = n.Issue.APIURL() + result.Subject.URL = n.Issue.APIURL(ctx) result.Subject.HTMLURL = n.Issue.HTMLURL() result.Subject.State = n.Issue.State() - comment, err := n.Issue.GetLastComment() + comment, err := n.Issue.GetLastComment(ctx) if err == nil && comment != nil { - result.Subject.LatestCommentURL = comment.APIURL() - result.Subject.LatestCommentHTMLURL = comment.HTMLURL() + result.Subject.LatestCommentURL = comment.APIURL(ctx) + result.Subject.LatestCommentHTMLURL = comment.HTMLURL(ctx) } } case activities_model.NotificationSourcePullRequest: result.Subject = &api.NotificationSubject{Type: api.NotifySubjectPull} if n.Issue != nil { result.Subject.Title = n.Issue.Title - result.Subject.URL = n.Issue.APIURL() + result.Subject.URL = n.Issue.APIURL(ctx) result.Subject.HTMLURL = n.Issue.HTMLURL() result.Subject.State = n.Issue.State() - comment, err := n.Issue.GetLastComment() + comment, err := n.Issue.GetLastComment(ctx) if err == nil && comment != nil { - result.Subject.LatestCommentURL = comment.APIURL() - result.Subject.LatestCommentHTMLURL = comment.HTMLURL() + result.Subject.LatestCommentURL = comment.APIURL(ctx) + result.Subject.LatestCommentHTMLURL = comment.HTMLURL(ctx) } - pr, _ := n.Issue.GetPullRequest() + pr, _ := n.Issue.GetPullRequest(ctx) if pr != nil && pr.HasMerged { result.Subject.State = "merged" } @@ -88,10 +88,10 @@ func ToNotificationThread(n *activities_model.Notification) *api.NotificationThr } // ToNotifications convert list of Notification to api.NotificationThread list -func ToNotifications(nl activities_model.NotificationList) []*api.NotificationThread { +func ToNotifications(ctx context.Context, nl activities_model.NotificationList) []*api.NotificationThread { result := make([]*api.NotificationThread, 0, len(nl)) for _, n := range nl { - result = append(result, ToNotificationThread(n)) + result = append(result, ToNotificationThread(ctx, n)) } return result } diff --git a/services/convert/pull_review.go b/services/convert/pull_review.go index 5d5d5d883c9..0332606285d 100644 --- a/services/convert/pull_review.go +++ b/services/convert/pull_review.go @@ -36,10 +36,10 @@ func ToPullReview(ctx context.Context, r *issues_model.Review, doer *user_model. Stale: r.Stale, Official: r.Official, Dismissed: r.Dismissed, - CodeCommentsCount: r.GetCodeCommentsCount(), + CodeCommentsCount: r.GetCodeCommentsCount(ctx), Submitted: r.CreatedUnix.AsTime(), Updated: r.UpdatedUnix.AsTime(), - HTMLURL: r.HTMLURL(), + HTMLURL: r.HTMLURL(ctx), HTMLPullURL: r.Issue.HTMLURL(), } @@ -102,7 +102,7 @@ func ToPullReviewCommentList(ctx context.Context, review *issues_model.Review, d CommitID: comment.CommitSHA, OrigCommitID: comment.OldRef, DiffHunk: patch2diff(comment.Patch), - HTMLURL: comment.HTMLURL(), + HTMLURL: comment.HTMLURL(ctx), HTMLPullURL: review.Issue.HTMLURL(), } diff --git a/services/convert/repository.go b/services/convert/repository.go index 6f77b4932e4..71038cd0629 100644 --- a/services/convert/repository.go +++ b/services/convert/repository.go @@ -181,6 +181,7 @@ func innerToRepo(ctx context.Context, repo *repo_model.Repository, permissionInR Parent: parent, Mirror: repo.IsMirror, HTMLURL: repo.HTMLURL(), + URL: repoAPIURL, SSHURL: cloneLink.SSH, CloneURL: cloneLink.HTTPS, OriginalURL: repo.SanitizedOriginalURL(), diff --git a/services/cron/tasks_extended.go b/services/cron/tasks_extended.go index 48ea87df7fb..b9fd1dfcfff 100644 --- a/services/cron/tasks_extended.go +++ b/services/cron/tasks_extended.go @@ -9,7 +9,6 @@ import ( activities_model "code.gitea.io/gitea/models/activities" asymkey_model "code.gitea.io/gitea/models/asymkey" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/system" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -71,8 +70,8 @@ func registerRewriteAllPublicKeys() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(_ context.Context, _ *user_model.User, _ Config) error { - return asymkey_model.RewriteAllPublicKeys() + }, func(ctx context.Context, _ *user_model.User, _ Config) error { + return asymkey_model.RewriteAllPublicKeys(ctx) }) } @@ -81,8 +80,8 @@ func registerRewriteAllPrincipalKeys() { Enabled: false, RunAtStart: false, Schedule: "@every 72h", - }, func(_ context.Context, _ *user_model.User, _ Config) error { - return asymkey_model.RewriteAllPrincipalKeys(db.DefaultContext) + }, func(ctx context.Context, _ *user_model.User, _ Config) error { + return asymkey_model.RewriteAllPrincipalKeys(ctx) }) } @@ -136,7 +135,7 @@ func registerDeleteOldActions() { OlderThan: 365 * 24 * time.Hour, }, func(ctx context.Context, _ *user_model.User, config Config) error { olderThanConfig := config.(*OlderThanConfig) - return activities_model.DeleteOldActions(olderThanConfig.OlderThan) + return activities_model.DeleteOldActions(ctx, olderThanConfig.OlderThan) }) } @@ -168,7 +167,7 @@ func registerDeleteOldSystemNotices() { OlderThan: 365 * 24 * time.Hour, }, func(ctx context.Context, _ *user_model.User, config Config) error { olderThanConfig := config.(*OlderThanConfig) - return system.DeleteOldSystemNotices(olderThanConfig.OlderThan) + return system.DeleteOldSystemNotices(ctx, olderThanConfig.OlderThan) }) } diff --git a/services/externalaccount/link.go b/services/externalaccount/link.go index a19d4c5ab3e..d6e2ea7e942 100644 --- a/services/externalaccount/link.go +++ b/services/externalaccount/link.go @@ -4,6 +4,7 @@ package externalaccount import ( + "context" "fmt" user_model "code.gitea.io/gitea/models/user" @@ -19,11 +20,11 @@ type Store interface { } // LinkAccountFromStore links the provided user with a stored external user -func LinkAccountFromStore(store Store, user *user_model.User) error { +func LinkAccountFromStore(ctx context.Context, store Store, user *user_model.User) error { gothUser := store.Get("linkAccountGothUser") if gothUser == nil { return fmt.Errorf("not in LinkAccount session") } - return LinkAccountToUser(user, gothUser.(goth.User)) + return LinkAccountToUser(ctx, user, gothUser.(goth.User)) } diff --git a/services/externalaccount/user.go b/services/externalaccount/user.go index 3da5af34863..a80ba6fee7c 100644 --- a/services/externalaccount/user.go +++ b/services/externalaccount/user.go @@ -4,6 +4,7 @@ package externalaccount import ( + "context" "strings" "code.gitea.io/gitea/models/auth" @@ -42,7 +43,7 @@ func toExternalLoginUser(user *user_model.User, gothUser goth.User) (*user_model } // LinkAccountToUser link the gothUser to the user -func LinkAccountToUser(user *user_model.User, gothUser goth.User) error { +func LinkAccountToUser(ctx context.Context, user *user_model.User, gothUser goth.User) error { externalLoginUser, err := toExternalLoginUser(user, gothUser) if err != nil { return err @@ -63,7 +64,7 @@ func LinkAccountToUser(user *user_model.User, gothUser goth.User) error { } if tp.Name() != "" { - return UpdateMigrationsByType(tp, externalID, user.ID) + return UpdateMigrationsByType(ctx, tp, externalID, user.ID) } return nil @@ -80,21 +81,21 @@ func UpdateExternalUser(user *user_model.User, gothUser goth.User) error { } // UpdateMigrationsByType updates all migrated repositories' posterid from gitServiceType to replace originalAuthorID to posterID -func UpdateMigrationsByType(tp structs.GitServiceType, externalUserID string, userID int64) error { - if err := issues_model.UpdateIssuesMigrationsByType(tp, externalUserID, userID); err != nil { +func UpdateMigrationsByType(ctx context.Context, tp structs.GitServiceType, externalUserID string, userID int64) error { + if err := issues_model.UpdateIssuesMigrationsByType(ctx, tp, externalUserID, userID); err != nil { return err } - if err := issues_model.UpdateCommentsMigrationsByType(tp, externalUserID, userID); err != nil { + if err := issues_model.UpdateCommentsMigrationsByType(ctx, tp, externalUserID, userID); err != nil { return err } - if err := repo_model.UpdateReleasesMigrationsByType(tp, externalUserID, userID); err != nil { + if err := repo_model.UpdateReleasesMigrationsByType(ctx, tp, externalUserID, userID); err != nil { return err } - if err := issues_model.UpdateReactionsMigrationsByType(tp, externalUserID, userID); err != nil { + if err := issues_model.UpdateReactionsMigrationsByType(ctx, tp, externalUserID, userID); err != nil { return err } - return issues_model.UpdateReviewsMigrationsByType(tp, externalUserID, userID) + return issues_model.UpdateReviewsMigrationsByType(ctx, tp, externalUserID, userID) } diff --git a/services/feed/action.go b/services/feed/action.go index 6bf1158cc9f..83daaa1438f 100644 --- a/services/feed/action.go +++ b/services/feed/action.go @@ -265,7 +265,7 @@ func (a *actionNotifier) PullRequestReview(ctx context.Context, pr *issues_model actions = append(actions, action) } - if err := activities_model.NotifyWatchersActions(actions); err != nil { + if err := activities_model.NotifyWatchersActions(ctx, actions); err != nil { log.Error("notify watchers '%d/%d': %v", review.Reviewer.ID, review.Issue.RepoID, err) } } diff --git a/services/feed/action_test.go b/services/feed/action_test.go index fd84bb675b1..e1b071d8f60 100644 --- a/services/feed/action_test.go +++ b/services/feed/action_test.go @@ -4,7 +4,6 @@ package feed import ( - "path/filepath" "strings" "testing" @@ -20,9 +19,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestRenameRepoAction(t *testing.T) { diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 7ec4af90eac..5259b9181c7 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -57,7 +57,9 @@ type CreateRepoForm struct { Labels bool ProtectedBranch bool TrustModel string - SizeLimit int64 + + ForkSingleBranch string + SizeLimit int64 } // Validate validates the fields diff --git a/services/gitdiff/csv_test.go b/services/gitdiff/csv_test.go index ac53e2d1efa..c006a7c2bd8 100644 --- a/services/gitdiff/csv_test.go +++ b/services/gitdiff/csv_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "code.gitea.io/gitea/models/db" csv_module "code.gitea.io/gitea/modules/csv" "code.gitea.io/gitea/modules/setting" @@ -190,7 +191,7 @@ c,d,e`, } for n, c := range cases { - diff, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.diff), "") + diff, err := ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.diff), "") if err != nil { t.Errorf("ParsePatch failed: %s", err) } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 4cc093e65de..8bf6cba844d 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -494,7 +494,7 @@ func (diff *Diff) LoadComments(ctx context.Context, issue *issues_model.Issue, c const cmdDiffHead = "diff --git " // ParsePatch builds a Diff object from a io.Reader and some parameters. -func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader, skipToFile string) (*Diff, error) { +func ParsePatch(ctx context.Context, maxLines, maxLineCharacters, maxFiles int, reader io.Reader, skipToFile string) (*Diff, error) { log.Debug("ParsePatch(%d, %d, %d, ..., %s)", maxLines, maxLineCharacters, maxFiles, skipToFile) var curFile *DiffFile @@ -709,7 +709,7 @@ parsingLoop: curFile.IsAmbiguous = false } // Otherwise do nothing with this line, but now switch to parsing hunks - lineBytes, isFragment, err := parseHunks(curFile, maxLines, maxLineCharacters, input) + lineBytes, isFragment, err := parseHunks(ctx, curFile, maxLines, maxLineCharacters, input) diff.TotalAddition += curFile.Addition diff.TotalDeletion += curFile.Deletion if err != nil { @@ -818,7 +818,7 @@ func skipToNextDiffHead(input *bufio.Reader) (line string, err error) { return line, err } -func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio.Reader) (lineBytes []byte, isFragment bool, err error) { +func parseHunks(ctx context.Context, curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio.Reader) (lineBytes []byte, isFragment bool, err error) { sb := strings.Builder{} var ( @@ -995,7 +995,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio oid := strings.TrimPrefix(line[1:], lfs.MetaFileOidPrefix) if len(oid) == 64 { m := &git_model.LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}} - count, err := db.CountByBean(db.DefaultContext, m) + count, err := db.CountByBean(ctx, m) if err == nil && count > 0 { curFile.IsBin = true @@ -1106,7 +1106,7 @@ type DiffOptions struct { // GetDiff builds a Diff between two commits of a repository. // Passing the empty string as beforeCommitID returns a diff from the parent commit. // The whitespaceBehavior is either an empty string or a git flag -func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) { +func GetDiff(ctx context.Context, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) { repoPath := gitRepo.Path commit, err := gitRepo.GetCommit(opts.AfterCommitID) @@ -1165,7 +1165,7 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff _ = writer.Close() }() - diff, err := ParsePatch(opts.MaxLines, opts.MaxLineCharacters, opts.MaxFiles, reader, parsePatchSkipToFile) + diff, err := ParsePatch(ctx, opts.MaxLines, opts.MaxLineCharacters, opts.MaxFiles, reader, parsePatchSkipToFile) if err != nil { return nil, fmt.Errorf("unable to ParsePatch: %w", err) } @@ -1280,7 +1280,7 @@ func GetPullDiffStats(gitRepo *git.Repository, opts *DiffOptions) (*PullDiffStat // SyncAndGetUserSpecificDiff is like GetDiff, except that user specific data such as which files the given user has already viewed on the given PR will also be set // Additionally, the database asynchronously is updated if files have changed since the last review func SyncAndGetUserSpecificDiff(ctx context.Context, userID int64, pull *issues_model.PullRequest, gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff, error) { - diff, err := GetDiff(gitRepo, opts, files...) + diff, err := GetDiff(ctx, gitRepo, opts, files...) if err != nil { return nil, err } @@ -1343,12 +1343,12 @@ outer: } } - return diff, err + return diff, nil } // CommentAsDiff returns c.Patch as *Diff -func CommentAsDiff(c *issues_model.Comment) (*Diff, error) { - diff, err := ParsePatch(setting.Git.MaxGitDiffLines, +func CommentAsDiff(ctx context.Context, c *issues_model.Comment) (*Diff, error) { + diff, err := ParsePatch(ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(c.Patch), "") if err != nil { log.Error("Unable to parse patch: %v", err) @@ -1365,7 +1365,7 @@ func CommentAsDiff(c *issues_model.Comment) (*Diff, error) { } // CommentMustAsDiff executes AsDiff and logs the error instead of returning -func CommentMustAsDiff(c *issues_model.Comment) *Diff { +func CommentMustAsDiff(ctx context.Context, c *issues_model.Comment) *Diff { if c == nil { return nil } @@ -1374,7 +1374,7 @@ func CommentMustAsDiff(c *issues_model.Comment) *Diff { log.Error("PANIC whilst retrieving diff for comment[%d] Error: %v\nStack: %s", c.ID, err, log.Stack(2)) } }() - diff, err := CommentAsDiff(c) + diff, err := CommentAsDiff(ctx, c) if err != nil { log.Warn("CommentMustAsDiff: %v", err) } diff --git a/services/gitdiff/gitdiff_test.go b/services/gitdiff/gitdiff_test.go index e270e46fd45..adcac355a7b 100644 --- a/services/gitdiff/gitdiff_test.go +++ b/services/gitdiff/gitdiff_test.go @@ -175,7 +175,7 @@ diff --git "\\a/README.md" "\\b/README.md" } for _, testcase := range tests { t.Run(testcase.name, func(t *testing.T) { - got, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), testcase.skipTo) + got, err := ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), testcase.skipTo) if (err != nil) != testcase.wantErr { t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr) return @@ -400,7 +400,7 @@ index 6961180..9ba1a00 100644 for _, testcase := range tests { t.Run(testcase.name, func(t *testing.T) { - got, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") + got, err := ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") if (err != nil) != testcase.wantErr { t.Errorf("ParsePatch(%q) error = %v, wantErr %v", testcase.name, err, testcase.wantErr) return @@ -449,21 +449,21 @@ index 0000000..6bb8f39 diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n") } diff = diffBuilder.String() - result, err := ParsePatch(20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err := ParsePatch(db.DefaultContext, 20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") if err != nil { t.Errorf("There should not be an error: %v", err) } if !result.Files[0].IsIncomplete { t.Errorf("Files should be incomplete! %v", result.Files[0]) } - result, err = ParsePatch(40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(db.DefaultContext, 40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") if err != nil { t.Errorf("There should not be an error: %v", err) } if result.Files[0].IsIncomplete { t.Errorf("Files should not be incomplete! %v", result.Files[0]) } - result, err = ParsePatch(40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(db.DefaultContext, 40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") if err != nil { t.Errorf("There should not be an error: %v", err) } @@ -494,14 +494,14 @@ index 0000000..6bb8f39 diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n") diff = diffBuilder.String() - result, err = ParsePatch(20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(db.DefaultContext, 20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") if err != nil { t.Errorf("There should not be an error: %v", err) } if !result.Files[0].IsIncomplete { t.Errorf("Files should be incomplete! %v", result.Files[0]) } - result, err = ParsePatch(40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + result, err = ParsePatch(db.DefaultContext, 40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") if err != nil { t.Errorf("There should not be an error: %v", err) } @@ -520,7 +520,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") + _, err = ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff), "") if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -536,7 +536,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2), "") + _, err = ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2), "") if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -552,7 +552,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2a), "") + _, err = ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff2a), "") if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -568,7 +568,7 @@ index 0000000..6bb8f39 Docker Pulls + cut off + cut off` - _, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3), "") + _, err = ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff3), "") if err != nil { t.Errorf("ParsePatch failed: %s", err) } @@ -634,7 +634,7 @@ func TestGetDiffRangeWithWhitespaceBehavior(t *testing.T) { } defer gitRepo.Close() for _, behavior := range []git.TrustedCmdArgs{{"-w"}, {"--ignore-space-at-eol"}, {"-b"}, nil} { - diffs, err := GetDiff(gitRepo, + diffs, err := GetDiff(db.DefaultContext, gitRepo, &DiffOptions{ AfterCommitID: "bd7063cc7c04689c4d082183d32a604ed27a24f9", BeforeCommitID: "559c156f8e0178b71cb44355428f24001b08fc68", @@ -665,6 +665,6 @@ func TestNoCrashes(t *testing.T) { } for _, testcase := range tests { // It shouldn't crash, so don't care about the output. - ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") + ParsePatch(db.DefaultContext, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(testcase.gitdiff), "") } } diff --git a/services/gitdiff/main_test.go b/services/gitdiff/main_test.go index 7f4243576cc..cd9dcd8cd6f 100644 --- a/services/gitdiff/main_test.go +++ b/services/gitdiff/main_test.go @@ -4,7 +4,6 @@ package gitdiff import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -15,7 +14,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/issue/assignee_test.go b/services/issue/assignee_test.go index f47ef45ba00..e16b012a174 100644 --- a/services/issue/assignee_test.go +++ b/services/issue/assignee_test.go @@ -18,7 +18,7 @@ func TestDeleteNotPassedAssignee(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // Fake issue with assignees - issue, err := issues_model.GetIssueWithAttrsByID(1) + issue, err := issues_model.GetIssueWithAttrsByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Len(t, issue.Assignees, 1) diff --git a/services/issue/comments.go b/services/issue/comments.go index 4a8574edd51..8d8c575c140 100644 --- a/services/issue/comments.go +++ b/services/issue/comments.go @@ -84,7 +84,7 @@ func UpdateComment(ctx context.Context, c *issues_model.Comment, doer *user_mode } } - if err := issues_model.UpdateComment(c, doer); err != nil { + if err := issues_model.UpdateComment(ctx, c, doer); err != nil { return err } diff --git a/services/issue/content.go b/services/issue/content.go index cda11dbb18f..6e56714ddfa 100644 --- a/services/issue/content.go +++ b/services/issue/content.go @@ -4,21 +4,22 @@ package issue import ( - "code.gitea.io/gitea/models/db" + "context" + issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" notify_service "code.gitea.io/gitea/services/notify" ) // ChangeContent changes issue content, as the given user. -func ChangeContent(issue *issues_model.Issue, doer *user_model.User, content string) (err error) { +func ChangeContent(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, content string) (err error) { oldContent := issue.Content - if err := issues_model.ChangeIssueContent(issue, doer, content); err != nil { + if err := issues_model.ChangeIssueContent(ctx, issue, doer, content); err != nil { return err } - notify_service.IssueChangeContent(db.DefaultContext, doer, issue, oldContent) + notify_service.IssueChangeContent(ctx, doer, issue, oldContent) return nil } diff --git a/services/issue/issue.go b/services/issue/issue.go index 828599be6bc..198dc0b2e18 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -22,7 +22,7 @@ import ( // NewIssue creates new issue with labels for repository. func NewIssue(ctx context.Context, repo *repo_model.Repository, issue *issues_model.Issue, labelIDs []int64, uuids []string, assigneeIDs []int64) error { - if err := issues_model.NewIssue(repo, issue, labelIDs, uuids); err != nil { + if err := issues_model.NewIssue(ctx, repo, issue, labelIDs, uuids); err != nil { return err } @@ -73,7 +73,7 @@ func ChangeIssueRef(ctx context.Context, issue *issues_model.Issue, doer *user_m oldRef := issue.Ref issue.Ref = ref - if err := issues_model.ChangeIssueRef(issue, doer, oldRef); err != nil { + if err := issues_model.ChangeIssueRef(ctx, issue, doer, oldRef); err != nil { return err } @@ -262,45 +262,27 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error { } // delete all database data still assigned to this issue - if err := issues_model.DeleteInIssue(ctx, issue.ID, - &issues_model.ContentHistory{}, - &issues_model.Comment{}, - &issues_model.IssueLabel{}, - &issues_model.IssueDependency{}, - &issues_model.IssueAssignees{}, - &issues_model.IssueUser{}, - &activities_model.Notification{}, - &issues_model.Reaction{}, - &issues_model.IssueWatch{}, - &issues_model.Stopwatch{}, - &issues_model.TrackedTime{}, - &project_model.ProjectIssue{}, - &repo_model.Attachment{}, - &issues_model.PullRequest{}, + if err := db.DeleteBeans(ctx, + &issues_model.ContentHistory{IssueID: issue.ID}, + &issues_model.Comment{IssueID: issue.ID}, + &issues_model.IssueLabel{IssueID: issue.ID}, + &issues_model.IssueDependency{IssueID: issue.ID}, + &issues_model.IssueAssignees{IssueID: issue.ID}, + &issues_model.IssueUser{IssueID: issue.ID}, + &activities_model.Notification{IssueID: issue.ID}, + &issues_model.Reaction{IssueID: issue.ID}, + &issues_model.IssueWatch{IssueID: issue.ID}, + &issues_model.Stopwatch{IssueID: issue.ID}, + &issues_model.TrackedTime{IssueID: issue.ID}, + &project_model.ProjectIssue{IssueID: issue.ID}, + &repo_model.Attachment{IssueID: issue.ID}, + &issues_model.PullRequest{IssueID: issue.ID}, + &issues_model.Comment{RefIssueID: issue.ID}, + &issues_model.IssueDependency{DependencyID: issue.ID}, + &issues_model.Comment{DependentIssueID: issue.ID}, ); err != nil { return err } - // References to this issue in other issues - if _, err := db.DeleteByBean(ctx, &issues_model.Comment{ - RefIssueID: issue.ID, - }); err != nil { - return err - } - - // Delete dependencies for issues in other repositories - if _, err := db.DeleteByBean(ctx, &issues_model.IssueDependency{ - DependencyID: issue.ID, - }); err != nil { - return err - } - - // delete from dependent issues - if _, err := db.DeleteByBean(ctx, &issues_model.Comment{ - DependentIssueID: issue.ID, - }); err != nil { - return err - } - return committer.Commit() } diff --git a/services/issue/label.go b/services/issue/label.go index f830aab0e79..91f0308d9f6 100644 --- a/services/issue/label.go +++ b/services/issue/label.go @@ -4,6 +4,8 @@ package issue import ( + "context" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" access_model "code.gitea.io/gitea/models/perm/access" @@ -12,49 +14,49 @@ import ( ) // ClearLabels clears all of an issue's labels -func ClearLabels(issue *issues_model.Issue, doer *user_model.User) error { +func ClearLabels(ctx context.Context, issue *issues_model.Issue, doer *user_model.User) error { if err := issues_model.ClearIssueLabels(issue, doer); err != nil { return err } - notify_service.IssueClearLabels(db.DefaultContext, doer, issue) + notify_service.IssueClearLabels(ctx, doer, issue) return nil } // AddLabel adds a new label to the issue. -func AddLabel(issue *issues_model.Issue, doer *user_model.User, label *issues_model.Label) error { +func AddLabel(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, label *issues_model.Label) error { if err := issues_model.NewIssueLabel(issue, label, doer); err != nil { return err } - notify_service.IssueChangeLabels(db.DefaultContext, doer, issue, []*issues_model.Label{label}, nil) + notify_service.IssueChangeLabels(ctx, doer, issue, []*issues_model.Label{label}, nil) return nil } // AddLabels adds a list of new labels to the issue. -func AddLabels(issue *issues_model.Issue, doer *user_model.User, labels []*issues_model.Label) error { +func AddLabels(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, labels []*issues_model.Label) error { if err := issues_model.NewIssueLabels(issue, labels, doer); err != nil { return err } - notify_service.IssueChangeLabels(db.DefaultContext, doer, issue, labels, nil) + notify_service.IssueChangeLabels(ctx, doer, issue, labels, nil) return nil } // RemoveLabel removes a label from issue by given ID. -func RemoveLabel(issue *issues_model.Issue, doer *user_model.User, label *issues_model.Label) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func RemoveLabel(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, label *issues_model.Label) error { + dbCtx, committer, err := db.TxContext(ctx) if err != nil { return err } defer committer.Close() - if err := issue.LoadRepo(ctx); err != nil { + if err := issue.LoadRepo(dbCtx); err != nil { return err } - perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) + perm, err := access_model.GetUserRepoPermission(dbCtx, issue.Repo, doer) if err != nil { return err } @@ -65,7 +67,7 @@ func RemoveLabel(issue *issues_model.Issue, doer *user_model.User, label *issues return issues_model.ErrRepoLabelNotExist{} } - if err := issues_model.DeleteIssueLabel(ctx, issue, label, doer); err != nil { + if err := issues_model.DeleteIssueLabel(dbCtx, issue, label, doer); err != nil { return err } @@ -73,13 +75,13 @@ func RemoveLabel(issue *issues_model.Issue, doer *user_model.User, label *issues return err } - notify_service.IssueChangeLabels(db.DefaultContext, doer, issue, nil, []*issues_model.Label{label}) + notify_service.IssueChangeLabels(ctx, doer, issue, nil, []*issues_model.Label{label}) return nil } // ReplaceLabels removes all current labels and add new labels to the issue. -func ReplaceLabels(issue *issues_model.Issue, doer *user_model.User, labels []*issues_model.Label) error { - old, err := issues_model.GetLabelsByIssueID(db.DefaultContext, issue.ID) +func ReplaceLabels(ctx context.Context, issue *issues_model.Issue, doer *user_model.User, labels []*issues_model.Label) error { + old, err := issues_model.GetLabelsByIssueID(ctx, issue.ID) if err != nil { return err } @@ -88,6 +90,6 @@ func ReplaceLabels(issue *issues_model.Issue, doer *user_model.User, labels []*i return err } - notify_service.IssueChangeLabels(db.DefaultContext, doer, issue, labels, old) + notify_service.IssueChangeLabels(ctx, doer, issue, labels, old) return nil } diff --git a/services/issue/label_test.go b/services/issue/label_test.go index af220601f14..90608c9e269 100644 --- a/services/issue/label_test.go +++ b/services/issue/label_test.go @@ -6,6 +6,7 @@ package issue import ( "testing" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -32,7 +33,7 @@ func TestIssue_AddLabels(t *testing.T) { labels[i] = unittest.AssertExistsAndLoadBean(t, &issues_model.Label{ID: labelID}) } doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: test.doerID}) - assert.NoError(t, AddLabels(issue, doer, labels)) + assert.NoError(t, AddLabels(db.DefaultContext, issue, doer, labels)) for _, labelID := range test.labelIDs { unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: test.issueID, LabelID: labelID}) } @@ -55,7 +56,7 @@ func TestIssue_AddLabel(t *testing.T) { 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)) + assert.NoError(t, AddLabel(db.DefaultContext, issue, doer, label)) unittest.AssertExistsAndLoadBean(t, &issues_model.IssueLabel{IssueID: test.issueID, LabelID: test.labelID}) } } diff --git a/services/issue/main_test.go b/services/issue/main_test.go index 6bce694ccaf..5dac54183ba 100644 --- a/services/issue/main_test.go +++ b/services/issue/main_test.go @@ -4,7 +4,6 @@ package issue import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -13,7 +12,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/issue/template.go b/services/issue/template.go index 4f1e3d93a0a..b6ae0779878 100644 --- a/services/issue/template.go +++ b/services/issue/template.go @@ -72,7 +72,7 @@ func GetTemplateConfig(gitRepo *git.Repository, path string, commit *git.Commit) return GetDefaultTemplateConfig(), err } - issueConfig := api.IssueConfig{} + issueConfig := GetDefaultTemplateConfig() if err := yaml.Unmarshal(configContent, &issueConfig); err != nil { return GetDefaultTemplateConfig(), err } diff --git a/services/mailer/incoming/incoming_handler.go b/services/mailer/incoming/incoming_handler.go index b594e35189b..9682c52456d 100644 --- a/services/mailer/incoming/incoming_handler.go +++ b/services/mailer/incoming/incoming_handler.go @@ -87,7 +87,7 @@ func (h *ReplyHandler) Handle(ctx context.Context, content *MailContent, doer *u attachmentIDs := make([]string, 0, len(content.Attachments)) if setting.Attachment.Enabled { for _, attachment := range content.Attachments { - a, err := attachment_service.UploadAttachment(bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, int64(len(attachment.Content)), &repo_model.Attachment{ + a, err := attachment_service.UploadAttachment(ctx, bytes.NewReader(attachment.Content), setting.Attachment.AllowedTypes, int64(len(attachment.Content)), &repo_model.Attachment{ Name: attachment.Name, UploaderID: doer.ID, RepoID: issue.Repo.ID, @@ -170,7 +170,7 @@ func (h *UnsubscribeHandler) Handle(ctx context.Context, _ *MailContent, doer *u return nil } - return issues_model.CreateOrUpdateIssueWatch(doer.ID, issue.ID, false) + return issues_model.CreateOrUpdateIssueWatch(ctx, doer.ID, issue.ID, false) } return fmt.Errorf("unsupported unsubscribe reference: %v", ref) diff --git a/services/mailer/main_test.go b/services/mailer/main_test.go index e906f4cb6e1..f803c736ca1 100644 --- a/services/mailer/main_test.go +++ b/services/mailer/main_test.go @@ -4,7 +4,6 @@ package mailer import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -13,7 +12,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/markup/main_test.go b/services/markup/main_test.go index ce892435a1a..89fe3e7e346 100644 --- a/services/markup/main_test.go +++ b/services/markup/main_test.go @@ -4,7 +4,6 @@ package markup import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -12,7 +11,6 @@ import ( func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - FixtureFiles: []string{"user.yml"}, + FixtureFiles: []string{"user.yml"}, }) } diff --git a/services/migrations/dump.go b/services/migrations/dump.go index 603954810cf..07812002afa 100644 --- a/services/migrations/dump.go +++ b/services/migrations/dump.go @@ -655,7 +655,7 @@ func DumpRepository(ctx context.Context, baseDir, ownerName string, opts base.Mi return err } - if err := migrateRepository(doer, downloader, uploader, opts, nil); err != nil { + if err := migrateRepository(ctx, doer, downloader, uploader, opts, nil); err != nil { if err1 := uploader.Rollback(); err1 != nil { log.Error("rollback failed: %v", err1) } @@ -727,7 +727,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string, return err } - if err = migrateRepository(doer, downloader, uploader, migrateOpts, nil); err != nil { + if err = migrateRepository(ctx, doer, downloader, uploader, migrateOpts, nil); err != nil { if err1 := uploader.Rollback(); err1 != nil { log.Error("rollback failed: %v", err1) } diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 4c21efae44f..ebf22e0e409 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -162,7 +162,7 @@ func (g *GiteaLocalUploader) CreateTopics(topics ...string) error { c++ } topics = topics[:c] - return repo_model.SaveTopics(g.repo.ID, topics...) + return repo_model.SaveTopics(g.ctx, g.repo.ID, topics...) } // CreateMilestones creates milestones @@ -205,7 +205,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err mss = append(mss, &ms) } - err := issues_model.InsertMilestones(mss...) + err := issues_model.InsertMilestones(g.ctx, mss...) if err != nil { return err } @@ -236,7 +236,7 @@ func (g *GiteaLocalUploader) CreateLabels(labels ...*base.Label) error { }) } - err := issues_model.NewLabels(lbs...) + err := issues_model.NewLabels(g.ctx, lbs...) if err != nil { return err } @@ -350,12 +350,12 @@ func (g *GiteaLocalUploader) CreateReleases(releases ...*base.Release) error { rels = append(rels, &rel) } - return repo_model.InsertReleases(rels...) + return repo_model.InsertReleases(g.ctx, rels...) } // SyncTags syncs releases with tags in the database func (g *GiteaLocalUploader) SyncTags() error { - return repo_module.SyncReleasesWithTags(g.repo, g.gitRepo) + return repo_module.SyncReleasesWithTags(g.ctx, g.repo, g.gitRepo) } // CreateIssues creates issues @@ -430,7 +430,7 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { } if len(iss) > 0 { - if err := issues_model.InsertIssues(iss...); err != nil { + if err := issues_model.InsertIssues(g.ctx, iss...); err != nil { return err } @@ -510,13 +510,12 @@ func (g *GiteaLocalUploader) CreateComments(comments ...*base.Comment) error { if len(cms) == 0 { return nil } - return issues_model.InsertIssueComments(cms) + return issues_model.InsertIssueComments(g.ctx, cms) } // CreatePullRequests creates pull requests func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error { gprs := make([]*issues_model.PullRequest, 0, len(prs)) - ctx := db.DefaultContext for _, pr := range prs { gpr, err := g.newPullRequest(pr) if err != nil { @@ -529,12 +528,12 @@ func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error gprs = append(gprs, gpr) } - if err := issues_model.InsertPullRequests(ctx, gprs...); err != nil { + if err := issues_model.InsertPullRequests(g.ctx, gprs...); err != nil { return err } for _, pr := range gprs { g.issues[pr.Issue.Index] = pr.Issue - pull.AddToTaskQueue(ctx, pr) + pull.AddToTaskQueue(g.ctx, pr) } return nil } @@ -918,7 +917,7 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { } } - return issues_model.InsertReviews(cms) + return issues_model.InsertReviews(g.ctx, cms) } // Rollback when migrating failed, this will rollback all the changes. @@ -938,7 +937,7 @@ func (g *GiteaLocalUploader) Finish() error { } // update issue_index - if err := issues_model.RecalculateIssueIndexForRepo(g.repo.ID); err != nil { + if err := issues_model.RecalculateIssueIndexForRepo(g.ctx, g.repo.ID); err != nil { return err } diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index 878b6d6b845..4c6dfddc08d 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -44,7 +44,7 @@ func TestGiteaUploadRepo(t *testing.T) { uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName) ) - err := migrateRepository(user, downloader, uploader, base.MigrateOptions{ + err := migrateRepository(db.DefaultContext, user, downloader, uploader, base.MigrateOptions{ CloneAddr: "https://github.com/go-xorm/builder", RepoName: repoName, AuthUsername: "", @@ -113,7 +113,7 @@ func TestGiteaUploadRepo(t *testing.T) { assert.NoError(t, issues[0].LoadDiscussComments(db.DefaultContext)) assert.Empty(t, issues[0].Comments) - pulls, _, err := issues_model.PullRequests(repo.ID, &issues_model.PullRequestsOptions{ + pulls, _, err := issues_model.PullRequests(db.DefaultContext, repo.ID, &issues_model.PullRequestsOptions{ SortType: "oldest", }) assert.NoError(t, err) diff --git a/services/migrations/main_test.go b/services/migrations/main_test.go index 42c433fb003..d0ec6a3f8d7 100644 --- a/services/migrations/main_test.go +++ b/services/migrations/main_test.go @@ -5,7 +5,6 @@ package migrations import ( - "path/filepath" "testing" "time" @@ -16,9 +15,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func timePtr(t time.Time) *time.Time { diff --git a/services/migrations/migrate.go b/services/migrations/migrate.go index 0ebb3411fdb..0b83f3b4a32 100644 --- a/services/migrations/migrate.go +++ b/services/migrations/migrate.go @@ -127,7 +127,7 @@ func MigrateRepository(ctx context.Context, doer *user_model.User, ownerName str uploader := NewGiteaLocalUploader(ctx, doer, ownerName, opts.RepoName) uploader.gitServiceType = opts.GitServiceType - if err := migrateRepository(doer, downloader, uploader, opts, messenger); err != nil { + if err := migrateRepository(ctx, doer, downloader, uploader, opts, messenger); err != nil { if err1 := uploader.Rollback(); err1 != nil { log.Error("rollback failed: %v", err1) } @@ -176,7 +176,7 @@ func newDownloader(ctx context.Context, ownerName string, opts base.MigrateOptio // migrateRepository will download information and then upload it to Uploader, this is a simple // process for small repository. For a big repository, save all the data to disk // before upload is better -func migrateRepository(doer *user_model.User, downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions, messenger base.Messenger) error { +func migrateRepository(ctx context.Context, doer *user_model.User, downloader base.Downloader, uploader base.Uploader, opts base.MigrateOptions, messenger base.Messenger) error { if messenger == nil { messenger = base.NilMessenger } diff --git a/services/migrations/update.go b/services/migrations/update.go index 2adca01dfe3..f14c07cc806 100644 --- a/services/migrations/update.go +++ b/services/migrations/update.go @@ -62,7 +62,7 @@ func updateMigrationPosterIDByGitService(ctx context.Context, tp structs.GitServ default: } externalUserID := user.ExternalID - if err := externalaccount.UpdateMigrationsByType(tp, externalUserID, user.UserID); err != nil { + if err := externalaccount.UpdateMigrationsByType(ctx, tp, externalUserID, user.UserID); err != nil { log.Error("UpdateMigrationsByType type %s external user id %v to local user id %v failed: %v", tp.Name(), user.ExternalID, user.UserID, err) } } diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index 0fc871b214c..72e545581a1 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -46,7 +46,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { var referenceID int64 if m, ok := bean.(*repo_model.Mirror); ok { - if m.GetRepository() == nil { + if m.GetRepository(ctx) == nil { log.Error("Disconnected mirror found: %d", m.ID) return nil } @@ -54,7 +54,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { mirrorType = PullMirrorType referenceID = m.RepoID } else if m, ok := bean.(*repo_model.PushMirror); ok { - if m.GetRepository() == nil { + if m.GetRepository(ctx) == nil { log.Error("Disconnected push-mirror found: %d", m.ID) return nil } @@ -90,7 +90,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { pullMirrorsRequested := 0 if pullLimit != 0 { - if err := repo_model.MirrorsIterate(pullLimit, func(idx int, bean any) error { + if err := repo_model.MirrorsIterate(ctx, pullLimit, func(idx int, bean any) error { if err := handler(idx, bean); err != nil { return err } diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 321bd38fc32..be426d43128 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -9,7 +9,6 @@ import ( "strings" "time" - "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/modules/cache" @@ -31,7 +30,7 @@ const gitShortEmptySha = "0000000" // UpdateAddress writes new address to Git repository and database func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error { remoteName := m.GetRemoteName() - repoPath := m.GetRepository().RepoPath() + repoPath := m.GetRepository(ctx).RepoPath() // Remove old remote _, _, err := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { @@ -313,7 +312,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo } log.Trace("SyncMirrors [repo: %-v]: syncing releases with tags...", m.Repo) - if err = repo_module.SyncReleasesWithTags(m.Repo, gitRepo); err != nil { + if err = repo_module.SyncReleasesWithTags(ctx, m.Repo, gitRepo); err != nil { log.Error("SyncMirrors [repo: %-v]: failed to synchronize tags to releases: %v", m.Repo, err) } @@ -428,7 +427,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Error("SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v", repoID, err) return false } - _ = m.GetRepository() // force load repository of mirror + _ = m.GetRepository(ctx) // force load repository of mirror ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing Mirror %s/%s", m.Repo.OwnerName, m.Repo.Name)) defer finished() @@ -461,7 +460,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { } defer gitRepo.Close() - if ok := checkAndUpdateEmptyRepository(m, gitRepo, results); !ok { + if ok := checkAndUpdateEmptyRepository(ctx, m, gitRepo, results); !ok { return false } } @@ -540,7 +539,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return false } - if err = repo_model.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil { + if err = repo_model.UpdateRepositoryUpdatedTime(ctx, m.RepoID, commitDate); err != nil { log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err) return false } @@ -550,7 +549,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { return true } -func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository, results []*mirrorSyncResult) bool { +func checkAndUpdateEmptyRepository(ctx context.Context, m *repo_model.Mirror, gitRepo *git.Repository, results []*mirrorSyncResult) bool { if !m.Repo.IsEmpty { return true } @@ -592,7 +591,7 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository if err := gitRepo.SetDefaultBranch(m.Repo.DefaultBranch); err != nil { if !git.IsErrUnsupportedVersion(err) { log.Error("Failed to update default branch of underlying git repository %-v. Error: %v", m.Repo, err) - desc := fmt.Sprintf("Failed to uupdate default branch of underlying git repository '%s': %v", m.Repo.RepoPath(), err) + desc := fmt.Sprintf("Failed to update default branch of underlying git repository '%s': %v", m.Repo.RepoPath(), err) if err = system_model.CreateRepositoryNotice(desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } @@ -601,9 +600,9 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository } m.Repo.IsEmpty = false // Update the is empty and default_branch columns - if err := repo_model.UpdateRepositoryCols(db.DefaultContext, m.Repo, "default_branch", "is_empty"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, m.Repo, "default_branch", "is_empty"); err != nil { log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err) - desc := fmt.Sprintf("Failed to uupdate default branch of repository '%s': %v", m.Repo.RepoPath(), err) + desc := fmt.Sprintf("Failed to update default branch of repository '%s': %v", m.Repo.RepoPath(), err) if err = system_model.CreateRepositoryNotice(desc); err != nil { log.Error("CreateRepositoryNotice: %v", err) } diff --git a/services/mirror/mirror_push.go b/services/mirror/mirror_push.go index 594d31df89b..6eaca71495e 100644 --- a/services/mirror/mirror_push.go +++ b/services/mirror/mirror_push.go @@ -65,7 +65,7 @@ func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr str // RemovePushMirrorRemote removes the push mirror remote. func RemovePushMirrorRemote(ctx context.Context, m *repo_model.PushMirror) error { cmd := git.NewCommand(ctx, "remote", "rm").AddDynamicArguments(m.RemoteName) - _ = m.GetRepository() + _ = m.GetRepository(ctx) if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.RepoPath()}); err != nil { return err @@ -99,7 +99,7 @@ func SyncPushMirror(ctx context.Context, mirrorID int64) bool { return false } - _ = m.GetRepository() + _ = m.GetRepository(ctx) m.LastError = "" diff --git a/services/org/org_test.go b/services/org/org_test.go index cc22595c6f1..339646795da 100644 --- a/services/org/org_test.go +++ b/services/org/org_test.go @@ -4,7 +4,6 @@ package org import ( - "path/filepath" "testing" "code.gitea.io/gitea/models" @@ -16,9 +15,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestDeleteOrganization(t *testing.T) { diff --git a/services/org/repo.go b/services/org/repo.go index 0edbf2d4648..78a829ef259 100644 --- a/services/org/repo.go +++ b/services/org/repo.go @@ -14,14 +14,14 @@ import ( ) // TeamAddRepository adds new repository to team of organization. -func TeamAddRepository(t *organization.Team, repo *repo_model.Repository) (err error) { +func TeamAddRepository(ctx context.Context, t *organization.Team, repo *repo_model.Repository) (err error) { if repo.OwnerID != t.OrgID { return errors.New("repository does not belong to organization") - } else if organization.HasTeamRepo(db.DefaultContext, t.OrgID, t.ID, repo.ID) { + } else if organization.HasTeamRepo(ctx, t.OrgID, t.ID, repo.ID) { return nil } - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { + return db.WithTx(ctx, func(ctx context.Context) error { return models.AddRepository(ctx, t, repo) }) } diff --git a/services/org/repo_test.go b/services/org/repo_test.go index 40b0d17077b..68c64a01ab4 100644 --- a/services/org/repo_test.go +++ b/services/org/repo_test.go @@ -6,6 +6,7 @@ package org import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -19,7 +20,7 @@ func TestTeam_AddRepository(t *testing.T) { testSuccess := func(teamID, repoID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) - assert.NoError(t, TeamAddRepository(team, repo)) + assert.NoError(t, TeamAddRepository(db.DefaultContext, team, repo)) unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repoID}) unittest.CheckConsistencyFor(t, &organization.Team{ID: teamID}, &repo_model.Repository{ID: repoID}) } @@ -28,6 +29,6 @@ func TestTeam_AddRepository(t *testing.T) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 1}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) - assert.Error(t, TeamAddRepository(team, repo)) + assert.Error(t, TeamAddRepository(db.DefaultContext, team, repo)) unittest.CheckConsistencyFor(t, &organization.Team{ID: 1}, &repo_model.Repository{ID: 1}) } diff --git a/services/packages/alpine/repository.go b/services/packages/alpine/repository.go index 5264bd6c4a8..eeda0cca7bc 100644 --- a/services/packages/alpine/repository.go +++ b/services/packages/alpine/repository.go @@ -34,18 +34,18 @@ const IndexFilename = "APKINDEX.tar.gz" // GetOrCreateRepositoryVersion gets or creates the internal repository package // The Alpine registry needs multiple index files which are stored in this package. -func GetOrCreateRepositoryVersion(ownerID int64) (*packages_model.PackageVersion, error) { - return packages_service.GetOrCreateInternalPackageVersion(ownerID, packages_model.TypeAlpine, alpine_module.RepositoryPackage, alpine_module.RepositoryVersion) +func GetOrCreateRepositoryVersion(ctx context.Context, ownerID int64) (*packages_model.PackageVersion, error) { + return packages_service.GetOrCreateInternalPackageVersion(ctx, ownerID, packages_model.TypeAlpine, alpine_module.RepositoryPackage, alpine_module.RepositoryVersion) } // GetOrCreateKeyPair gets or creates the RSA keys used to sign repository files -func GetOrCreateKeyPair(ownerID int64) (string, string, error) { - priv, err := user_model.GetSetting(ownerID, alpine_module.SettingKeyPrivate) +func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, error) { + priv, err := user_model.GetSetting(ctx, ownerID, alpine_module.SettingKeyPrivate) if err != nil && !errors.Is(err, util.ErrNotExist) { return "", "", err } - pub, err := user_model.GetSetting(ownerID, alpine_module.SettingKeyPublic) + pub, err := user_model.GetSetting(ctx, ownerID, alpine_module.SettingKeyPublic) if err != nil && !errors.Is(err, util.ErrNotExist) { return "", "", err } @@ -56,11 +56,11 @@ func GetOrCreateKeyPair(ownerID int64) (string, string, error) { return "", "", err } - if err := user_model.SetUserSetting(ownerID, alpine_module.SettingKeyPrivate, priv); err != nil { + if err := user_model.SetUserSetting(ctx, ownerID, alpine_module.SettingKeyPrivate, priv); err != nil { return "", "", err } - if err := user_model.SetUserSetting(ownerID, alpine_module.SettingKeyPublic, pub); err != nil { + if err := user_model.SetUserSetting(ctx, ownerID, alpine_module.SettingKeyPublic, pub); err != nil { return "", "", err } } @@ -70,7 +70,7 @@ func GetOrCreateKeyPair(ownerID int64) (string, string, error) { // BuildAllRepositoryFiles (re)builds all repository files for every available distributions, components and architectures func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error { - pv, err := GetOrCreateRepositoryVersion(ownerID) + pv, err := GetOrCreateRepositoryVersion(ctx, ownerID) if err != nil { return err } @@ -118,7 +118,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error { // BuildSpecificRepositoryFiles builds index files for the repository func BuildSpecificRepositoryFiles(ctx context.Context, ownerID int64, branch, repository, architecture string) error { - pv, err := GetOrCreateRepositoryVersion(ownerID) + pv, err := GetOrCreateRepositoryVersion(ctx, ownerID) if err != nil { return err } @@ -244,7 +244,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package return err } - priv, _, err := GetOrCreateKeyPair(ownerID) + priv, _, err := GetOrCreateKeyPair(ctx, ownerID) if err != nil { return err } @@ -290,6 +290,7 @@ func buildPackagesIndex(ctx context.Context, ownerID int64, repoVersion *package } _, err = packages_service.AddFileToPackageVersionInternal( + ctx, repoVersion, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ diff --git a/services/packages/debian/repository.go b/services/packages/debian/repository.go index be82fbed6e7..25fa8073514 100644 --- a/services/packages/debian/repository.go +++ b/services/packages/debian/repository.go @@ -32,18 +32,18 @@ import ( // GetOrCreateRepositoryVersion gets or creates the internal repository package // The Debian registry needs multiple index files which are stored in this package. -func GetOrCreateRepositoryVersion(ownerID int64) (*packages_model.PackageVersion, error) { - return packages_service.GetOrCreateInternalPackageVersion(ownerID, packages_model.TypeDebian, debian_module.RepositoryPackage, debian_module.RepositoryVersion) +func GetOrCreateRepositoryVersion(ctx context.Context, ownerID int64) (*packages_model.PackageVersion, error) { + return packages_service.GetOrCreateInternalPackageVersion(ctx, ownerID, packages_model.TypeDebian, debian_module.RepositoryPackage, debian_module.RepositoryVersion) } // GetOrCreateKeyPair gets or creates the PGP keys used to sign repository files -func GetOrCreateKeyPair(ownerID int64) (string, string, error) { - priv, err := user_model.GetSetting(ownerID, debian_module.SettingKeyPrivate) +func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, error) { + priv, err := user_model.GetSetting(ctx, ownerID, debian_module.SettingKeyPrivate) if err != nil && !errors.Is(err, util.ErrNotExist) { return "", "", err } - pub, err := user_model.GetSetting(ownerID, debian_module.SettingKeyPublic) + pub, err := user_model.GetSetting(ctx, ownerID, debian_module.SettingKeyPublic) if err != nil && !errors.Is(err, util.ErrNotExist) { return "", "", err } @@ -54,11 +54,11 @@ func GetOrCreateKeyPair(ownerID int64) (string, string, error) { return "", "", err } - if err := user_model.SetUserSetting(ownerID, debian_module.SettingKeyPrivate, priv); err != nil { + if err := user_model.SetUserSetting(ctx, ownerID, debian_module.SettingKeyPrivate, priv); err != nil { return "", "", err } - if err := user_model.SetUserSetting(ownerID, debian_module.SettingKeyPublic, pub); err != nil { + if err := user_model.SetUserSetting(ctx, ownerID, debian_module.SettingKeyPublic, pub); err != nil { return "", "", err } } @@ -98,7 +98,7 @@ func generateKeypair() (string, string, error) { // BuildAllRepositoryFiles (re)builds all repository files for every available distributions, components and architectures func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error { - pv, err := GetOrCreateRepositoryVersion(ownerID) + pv, err := GetOrCreateRepositoryVersion(ctx, ownerID) if err != nil { return err } @@ -147,7 +147,7 @@ func BuildAllRepositoryFiles(ctx context.Context, ownerID int64) error { // BuildSpecificRepositoryFiles builds index files for the repository func BuildSpecificRepositoryFiles(ctx context.Context, ownerID int64, distribution, component, architecture string) error { - pv, err := GetOrCreateRepositoryVersion(ownerID) + pv, err := GetOrCreateRepositoryVersion(ctx, ownerID) if err != nil { return err } @@ -234,6 +234,7 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa {"Packages.xz", packagesXzContent}, } { _, err = packages_service.AddFileToPackageVersionInternal( + ctx, repoVersion, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ @@ -306,7 +307,7 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages sort.Strings(architectures) - priv, _, err := GetOrCreateKeyPair(ownerID) + priv, _, err := GetOrCreateKeyPair(ctx, ownerID) if err != nil { return err } @@ -381,6 +382,7 @@ func buildReleaseFiles(ctx context.Context, ownerID int64, repoVersion *packages {"InRelease", inReleaseContent}, } { _, err = packages_service.AddFileToPackageVersionInternal( + ctx, repoVersion, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ diff --git a/services/packages/packages.go b/services/packages/packages.go index d7583464569..56d5cc04de2 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -66,28 +66,28 @@ type PackageFileCreationInfo struct { } // CreatePackageAndAddFile creates a package with a file. If the same package exists already, ErrDuplicatePackageVersion is returned -func CreatePackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { - return createPackageAndAddFile(pvci, pfci, false) +func CreatePackageAndAddFile(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { + return createPackageAndAddFile(ctx, pvci, pfci, false) } // CreatePackageOrAddFileToExisting creates a package with a file or adds the file if the package exists already -func CreatePackageOrAddFileToExisting(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { - return createPackageAndAddFile(pvci, pfci, true) +func CreatePackageOrAddFileToExisting(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { + return createPackageAndAddFile(ctx, pvci, pfci, true) } -func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func createPackageAndAddFile(ctx context.Context, pvci *PackageCreationInfo, pfci *PackageFileCreationInfo, allowDuplicate bool) (*packages_model.PackageVersion, *packages_model.PackageFile, error) { + dbCtx, committer, err := db.TxContext(ctx) if err != nil { return nil, nil, err } defer committer.Close() - pv, created, err := createPackageAndVersion(ctx, pvci, allowDuplicate) + pv, created, err := createPackageAndVersion(dbCtx, pvci, allowDuplicate) if err != nil { return nil, nil, err } - pf, pb, blobCreated, err := addFileToPackageVersion(ctx, pv, &pvci.PackageInfo, pfci) + pf, pb, blobCreated, err := addFileToPackageVersion(dbCtx, pv, &pvci.PackageInfo, pfci) removeBlob := false defer func() { if blobCreated && removeBlob { @@ -108,12 +108,12 @@ func createPackageAndAddFile(pvci *PackageCreationInfo, pfci *PackageFileCreatio } if created { - pd, err := packages_model.GetPackageDescriptor(db.DefaultContext, pv) + pd, err := packages_model.GetPackageDescriptor(ctx, pv) if err != nil { return nil, nil, err } - notify_service.PackageCreate(db.DefaultContext, pvci.Creator, pd) + notify_service.PackageCreate(ctx, pvci.Creator, pd) } return pv, pf, nil @@ -189,8 +189,8 @@ func createPackageAndVersion(ctx context.Context, pvci *PackageCreationInfo, all } // AddFileToExistingPackage adds a file to an existing package. If the package does not exist, ErrPackageNotExist is returned -func AddFileToExistingPackage(pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) { - return addFileToPackageWrapper(func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { +func AddFileToExistingPackage(ctx context.Context, pvi *PackageInfo, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) { + return addFileToPackageWrapper(ctx, func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version) if err != nil { return nil, nil, false, err @@ -202,14 +202,14 @@ func AddFileToExistingPackage(pvi *PackageInfo, pfci *PackageFileCreationInfo) ( // AddFileToPackageVersionInternal adds a file to the package // This method skips quota checks and should only be used for system-managed packages. -func AddFileToPackageVersionInternal(pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) { - return addFileToPackageWrapper(func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { +func AddFileToPackageVersionInternal(ctx context.Context, pv *packages_model.PackageVersion, pfci *PackageFileCreationInfo) (*packages_model.PackageFile, error) { + return addFileToPackageWrapper(ctx, func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error) { return addFileToPackageVersionUnchecked(ctx, pv, pfci) }) } -func addFileToPackageWrapper(fn func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error)) (*packages_model.PackageFile, error) { - ctx, committer, err := db.TxContext(db.DefaultContext) +func addFileToPackageWrapper(ctx context.Context, fn func(ctx context.Context) (*packages_model.PackageFile, *packages_model.PackageBlob, bool, error)) (*packages_model.PackageFile, error) { + ctx, committer, err := db.TxContext(ctx) if err != nil { return nil, err } @@ -418,10 +418,10 @@ func CheckSizeQuotaExceeded(ctx context.Context, doer, owner *user_model.User, p // GetOrCreateInternalPackageVersion gets or creates an internal package // Some package types need such internal packages for housekeeping. -func GetOrCreateInternalPackageVersion(ownerID int64, packageType packages_model.Type, name, version string) (*packages_model.PackageVersion, error) { +func GetOrCreateInternalPackageVersion(ctx context.Context, ownerID int64, packageType packages_model.Type, name, version string) (*packages_model.PackageVersion, error) { var pv *packages_model.PackageVersion - return pv, db.WithTx(db.DefaultContext, func(ctx context.Context) error { + return pv, db.WithTx(ctx, func(ctx context.Context) error { p := &packages_model.Package{ OwnerID: ownerID, Type: packageType, @@ -457,31 +457,31 @@ func GetOrCreateInternalPackageVersion(ownerID int64, packageType packages_model } // RemovePackageVersionByNameAndVersion deletes a package version and all associated files -func RemovePackageVersionByNameAndVersion(doer *user_model.User, pvi *PackageInfo) error { - pv, err := packages_model.GetVersionByNameAndVersion(db.DefaultContext, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version) +func RemovePackageVersionByNameAndVersion(ctx context.Context, doer *user_model.User, pvi *PackageInfo) error { + pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version) if err != nil { return err } - return RemovePackageVersion(doer, pv) + return RemovePackageVersion(ctx, doer, pv) } // RemovePackageVersion deletes the package version and all associated files -func RemovePackageVersion(doer *user_model.User, pv *packages_model.PackageVersion) error { - ctx, committer, err := db.TxContext(db.DefaultContext) +func RemovePackageVersion(ctx context.Context, doer *user_model.User, pv *packages_model.PackageVersion) error { + dbCtx, committer, err := db.TxContext(ctx) if err != nil { return err } defer committer.Close() - pd, err := packages_model.GetPackageDescriptor(ctx, pv) + pd, err := packages_model.GetPackageDescriptor(dbCtx, pv) if err != nil { return err } log.Trace("Deleting package: %v", pv.ID) - if err := DeletePackageVersionAndReferences(ctx, pv); err != nil { + if err := DeletePackageVersionAndReferences(dbCtx, pv); err != nil { return err } @@ -489,16 +489,16 @@ func RemovePackageVersion(doer *user_model.User, pv *packages_model.PackageVersi return err } - notify_service.PackageDelete(db.DefaultContext, doer, pd) + notify_service.PackageDelete(ctx, doer, pd) return nil } // RemovePackageFileAndVersionIfUnreferenced deletes the package file and the version if there are no referenced files afterwards -func RemovePackageFileAndVersionIfUnreferenced(doer *user_model.User, pf *packages_model.PackageFile) error { +func RemovePackageFileAndVersionIfUnreferenced(ctx context.Context, doer *user_model.User, pf *packages_model.PackageFile) error { var pd *packages_model.PackageDescriptor - if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { + if err := db.WithTx(ctx, func(ctx context.Context) error { if err := DeletePackageFile(ctx, pf); err != nil { return err } @@ -529,7 +529,7 @@ func RemovePackageFileAndVersionIfUnreferenced(doer *user_model.User, pf *packag } if pd != nil { - notify_service.PackageDelete(db.DefaultContext, doer, pd) + notify_service.PackageDelete(ctx, doer, pd) } return nil diff --git a/services/packages/rpm/repository.go b/services/packages/rpm/repository.go index cfd70ec23e2..93d9e41ca81 100644 --- a/services/packages/rpm/repository.go +++ b/services/packages/rpm/repository.go @@ -33,18 +33,18 @@ import ( // GetOrCreateRepositoryVersion gets or creates the internal repository package // The RPM registry needs multiple metadata files which are stored in this package. -func GetOrCreateRepositoryVersion(ownerID int64) (*packages_model.PackageVersion, error) { - return packages_service.GetOrCreateInternalPackageVersion(ownerID, packages_model.TypeRpm, rpm_module.RepositoryPackage, rpm_module.RepositoryVersion) +func GetOrCreateRepositoryVersion(ctx context.Context, ownerID int64) (*packages_model.PackageVersion, error) { + return packages_service.GetOrCreateInternalPackageVersion(ctx, ownerID, packages_model.TypeRpm, rpm_module.RepositoryPackage, rpm_module.RepositoryVersion) } // GetOrCreateKeyPair gets or creates the PGP keys used to sign repository metadata files -func GetOrCreateKeyPair(ownerID int64) (string, string, error) { - priv, err := user_model.GetSetting(ownerID, rpm_module.SettingKeyPrivate) +func GetOrCreateKeyPair(ctx context.Context, ownerID int64) (string, string, error) { + priv, err := user_model.GetSetting(ctx, ownerID, rpm_module.SettingKeyPrivate) if err != nil && !errors.Is(err, util.ErrNotExist) { return "", "", err } - pub, err := user_model.GetSetting(ownerID, rpm_module.SettingKeyPublic) + pub, err := user_model.GetSetting(ctx, ownerID, rpm_module.SettingKeyPublic) if err != nil && !errors.Is(err, util.ErrNotExist) { return "", "", err } @@ -55,11 +55,11 @@ func GetOrCreateKeyPair(ownerID int64) (string, string, error) { return "", "", err } - if err := user_model.SetUserSetting(ownerID, rpm_module.SettingKeyPrivate, priv); err != nil { + if err := user_model.SetUserSetting(ctx, ownerID, rpm_module.SettingKeyPrivate, priv); err != nil { return "", "", err } - if err := user_model.SetUserSetting(ownerID, rpm_module.SettingKeyPublic, pub); err != nil { + if err := user_model.SetUserSetting(ctx, ownerID, rpm_module.SettingKeyPublic, pub); err != nil { return "", "", err } } @@ -128,7 +128,7 @@ type packageCache = map[*packages_model.PackageFile]*packageData // BuildSpecificRepositoryFiles builds metadata files for the repository func BuildRepositoryFiles(ctx context.Context, ownerID int64) error { - pv, err := GetOrCreateRepositoryVersion(ownerID) + pv, err := GetOrCreateRepositoryVersion(ctx, ownerID) if err != nil { return err } @@ -198,20 +198,21 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error { cache[pf] = pd } - primary, err := buildPrimary(pv, pfs, cache) + primary, err := buildPrimary(ctx, pv, pfs, cache) if err != nil { return err } - filelists, err := buildFilelists(pv, pfs, cache) + filelists, err := buildFilelists(ctx, pv, pfs, cache) if err != nil { return err } - other, err := buildOther(pv, pfs, cache) + other, err := buildOther(ctx, pv, pfs, cache) if err != nil { return err } return buildRepomd( + ctx, pv, ownerID, []*repoData{ @@ -223,7 +224,7 @@ func BuildRepositoryFiles(ctx context.Context, ownerID int64) error { } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#repomd-xml -func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoData) error { +func buildRepomd(ctx context.Context, pv *packages_model.PackageVersion, ownerID int64, data []*repoData) error { type Repomd struct { XMLName xml.Name `xml:"repomd"` Xmlns string `xml:"xmlns,attr"` @@ -241,7 +242,7 @@ func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoD return err } - priv, _, err := GetOrCreateKeyPair(ownerID) + priv, _, err := GetOrCreateKeyPair(ctx, ownerID) if err != nil { return err } @@ -271,6 +272,7 @@ func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoD {"repomd.xml.asc", repomdAscContent}, } { _, err = packages_service.AddFileToPackageVersionInternal( + ctx, pv, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ @@ -291,7 +293,7 @@ func buildRepomd(pv *packages_model.PackageVersion, ownerID int64, data []*repoD } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#primary-xml -func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { +func buildPrimary(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { type Version struct { Epoch string `xml:"epoch,attr"` Version string `xml:"ver,attr"` @@ -425,7 +427,7 @@ func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.Packa }) } - return addDataAsFileToRepo(pv, "primary", &Metadata{ + return addDataAsFileToRepo(ctx, pv, "primary", &Metadata{ Xmlns: "http://linux.duke.edu/metadata/common", XmlnsRpm: "http://linux.duke.edu/metadata/rpm", PackageCount: len(pfs), @@ -434,7 +436,7 @@ func buildPrimary(pv *packages_model.PackageVersion, pfs []*packages_model.Packa } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#filelists-xml -func buildFilelists(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl +func buildFilelists(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl type Version struct { Epoch string `xml:"epoch,attr"` Version string `xml:"ver,attr"` @@ -473,7 +475,7 @@ func buildFilelists(pv *packages_model.PackageVersion, pfs []*packages_model.Pac }) } - return addDataAsFileToRepo(pv, "filelists", &Filelists{ + return addDataAsFileToRepo(ctx, pv, "filelists", &Filelists{ Xmlns: "http://linux.duke.edu/metadata/other", PackageCount: len(pfs), Packages: packages, @@ -481,7 +483,7 @@ func buildFilelists(pv *packages_model.PackageVersion, pfs []*packages_model.Pac } // https://docs.pulpproject.org/en/2.19/plugins/pulp_rpm/tech-reference/rpm.html#other-xml -func buildOther(pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl +func buildOther(ctx context.Context, pv *packages_model.PackageVersion, pfs []*packages_model.PackageFile, c packageCache) (*repoData, error) { //nolint:dupl type Version struct { Epoch string `xml:"epoch,attr"` Version string `xml:"ver,attr"` @@ -520,7 +522,7 @@ func buildOther(pv *packages_model.PackageVersion, pfs []*packages_model.Package }) } - return addDataAsFileToRepo(pv, "other", &Otherdata{ + return addDataAsFileToRepo(ctx, pv, "other", &Otherdata{ Xmlns: "http://linux.duke.edu/metadata/other", PackageCount: len(pfs), Packages: packages, @@ -544,7 +546,7 @@ func (wc *writtenCounter) Written() int64 { return wc.written } -func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) { +func addDataAsFileToRepo(ctx context.Context, pv *packages_model.PackageVersion, filetype string, obj any) (*repoData, error) { content, _ := packages_module.NewHashedBuffer() gzw := gzip.NewWriter(content) wc := &writtenCounter{} @@ -564,6 +566,7 @@ func addDataAsFileToRepo(pv *packages_model.PackageVersion, filetype string, obj filename := filetype + ".xml.gz" _, err := packages_service.AddFileToPackageVersionInternal( + ctx, pv, &packages_service.PackageFileCreationInfo{ PackageFileInfo: packages_service.PackageFileInfo{ diff --git a/services/pull/check.go b/services/pull/check.go index dcb488c309f..e4a0f6b27bb 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -303,7 +303,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool { // InitializePullRequests checks and tests untested patches of pull requests. func InitializePullRequests(ctx context.Context) { - prs, err := issues_model.GetPullRequestIDsByCheckStatus(issues_model.PullRequestStatusChecking) + prs, err := issues_model.GetPullRequestIDsByCheckStatus(ctx, issues_model.PullRequestStatusChecking) if err != nil { log.Error("Find Checking PRs: %v", err) return diff --git a/services/pull/main_test.go b/services/pull/main_test.go index f5297354d65..efbb63a36ec 100644 --- a/services/pull/main_test.go +++ b/services/pull/main_test.go @@ -5,7 +5,6 @@ package pull import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -14,7 +13,5 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/pull/pull.go b/services/pull/pull.go index 8e57aebe3d8..5e76fac8151 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -336,7 +336,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, } if changed { // Mark old reviews as stale if diff to mergebase has changed - if err := issues_model.MarkReviewsAsStale(pr.IssueID); err != nil { + if err := issues_model.MarkReviewsAsStale(ctx, pr.IssueID); err != nil { log.Error("MarkReviewsAsStale: %v", err) } @@ -351,7 +351,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, } } } - if err := issues_model.MarkReviewsAsNotStale(pr.IssueID, newCommitID); err != nil { + if err := issues_model.MarkReviewsAsNotStale(ctx, pr.IssueID, newCommitID); err != nil { log.Error("MarkReviewsAsNotStale: %v", err) } divergence, err := GetDiverging(ctx, pr) diff --git a/services/pull/review.go b/services/pull/review.go index c82d1341b6d..3f5644b0cd4 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -84,7 +84,7 @@ func CreateCodeComment(ctx context.Context, doer *user_model.User, gitRepo *git. if !pendingReview && replyReviewID != 0 { // It's not part of a review; maybe a reply to a review comment or a single comment. // Check if there are reviews for that line already; if there are, this is a reply - if existsReview, err = issues_model.ReviewExists(issue, treePath, line); err != nil { + if existsReview, err = issues_model.ReviewExists(ctx, issue, treePath, line); err != nil { return nil, err } } @@ -264,7 +264,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo // SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repository, issue *issues_model.Issue, reviewType issues_model.ReviewType, content, commitID string, attachmentUUIDs []string) (*issues_model.Review, *issues_model.Comment, error) { - pr, err := issue.GetPullRequest() + pr, err := issue.GetPullRequest(ctx) if err != nil { return nil, nil, err } @@ -288,7 +288,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos } } - review, comm, err := issues_model.SubmitReview(doer, issue, reviewType, content, commitID, stale, attachmentUUIDs) + review, comm, err := issues_model.SubmitReview(ctx, doer, issue, reviewType, content, commitID, stale, attachmentUUIDs) if err != nil { return nil, nil, err } diff --git a/services/release/release.go b/services/release/release.go index ac3acc90859..e0035d42fc2 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -25,6 +25,16 @@ import ( ) func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) { + err := rel.LoadAttributes(ctx) + if err != nil { + return false, err + } + + err = rel.Repo.MustNotBeArchived() + if err != nil { + return false, err + } + var created bool // Only actual create when publish. if !rel.IsDraft { @@ -185,7 +195,7 @@ func CreateNewTag(ctx context.Context, doer *user_model.User, repo *repo_model.R // addAttachmentUUIDs accept a slice of new created attachments' uuids which will be reassigned release_id as the created release // delAttachmentUUIDs accept a slice of attachments' uuids which will be deleted from the release // editAttachments accept a map of attachment uuid to new attachment name which will be updated with attachments. -func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_model.Release, +func UpdateRelease(ctx context.Context, doer *user_model.User, gitRepo *git.Repository, rel *repo_model.Release, addAttachmentUUIDs, delAttachmentUUIDs []string, editAttachments map[string]string, ) error { if rel.ID == 0 { @@ -197,7 +207,7 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod } rel.LowerTagName = strings.ToLower(rel.TagName) - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/services/release/release_test.go b/services/release/release_test.go index 0732dbc54d3..4b57262981b 100644 --- a/services/release/release_test.go +++ b/services/release/release_test.go @@ -4,7 +4,6 @@ package release import ( - "path/filepath" "strings" "testing" "time" @@ -22,9 +21,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestRelease_Create(t *testing.T) { @@ -110,7 +107,7 @@ func TestRelease_Create(t *testing.T) { testPlayload := "testtest" - attach, err := attachment.NewAttachment(&repo_model.Attachment{ + attach, err := attachment.NewAttachment(db.DefaultContext, &repo_model.Attachment{ RepoID: repo.ID, UploaderID: user.ID, Name: "test.txt", @@ -158,12 +155,12 @@ func TestRelease_Update(t *testing.T) { IsPrerelease: false, IsTag: false, }, nil, "")) - release, err := repo_model.GetRelease(repo.ID, "v1.1.1") + release, err := repo_model.GetRelease(db.DefaultContext, repo.ID, "v1.1.1") assert.NoError(t, err) releaseCreatedUnix := release.CreatedUnix time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Note = "Changed note" - assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, nil, nil, nil)) release, err = repo_model.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -182,12 +179,12 @@ func TestRelease_Update(t *testing.T) { IsPrerelease: false, IsTag: false, }, nil, "")) - release, err = repo_model.GetRelease(repo.ID, "v1.2.1") + release, err = repo_model.GetRelease(db.DefaultContext, repo.ID, "v1.2.1") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Title = "Changed title" - assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, nil, nil, nil)) release, err = repo_model.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Less(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -206,13 +203,13 @@ func TestRelease_Update(t *testing.T) { IsPrerelease: true, IsTag: false, }, nil, "")) - release, err = repo_model.GetRelease(repo.ID, "v1.3.1") + release, err = repo_model.GetRelease(db.DefaultContext, repo.ID, "v1.3.1") assert.NoError(t, err) releaseCreatedUnix = release.CreatedUnix time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Title = "Changed title" release.Note = "Changed note" - assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, nil, nil, nil)) release, err = repo_model.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -237,21 +234,21 @@ func TestRelease_Update(t *testing.T) { release.IsDraft = false tagName := release.TagName - assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, nil, nil, nil)) release, err = repo_model.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Equal(t, tagName, release.TagName) // Add new attachments samplePayload := "testtest" - attach, err := attachment.NewAttachment(&repo_model.Attachment{ + attach, err := attachment.NewAttachment(db.DefaultContext, &repo_model.Attachment{ RepoID: repo.ID, UploaderID: user.ID, Name: "test.txt", }, strings.NewReader(samplePayload), int64(len([]byte(samplePayload)))) assert.NoError(t, err) - assert.NoError(t, UpdateRelease(user, gitRepo, release, []string{attach.UUID}, nil, nil)) + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, []string{attach.UUID}, nil, nil)) assert.NoError(t, repo_model.GetReleaseAttachments(db.DefaultContext, release)) assert.Len(t, release.Attachments, 1) assert.EqualValues(t, attach.UUID, release.Attachments[0].UUID) @@ -259,7 +256,7 @@ func TestRelease_Update(t *testing.T) { assert.EqualValues(t, attach.Name, release.Attachments[0].Name) // update the attachment name - assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, map[string]string{ + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, nil, nil, map[string]string{ attach.UUID: "test2.txt", })) release.Attachments = nil @@ -270,7 +267,7 @@ func TestRelease_Update(t *testing.T) { assert.EqualValues(t, "test2.txt", release.Attachments[0].Name) // delete the attachment - assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, []string{attach.UUID}, nil)) + assert.NoError(t, UpdateRelease(db.DefaultContext, user, gitRepo, release, nil, []string{attach.UUID}, nil)) release.Attachments = nil assert.NoError(t, repo_model.GetReleaseAttachments(db.DefaultContext, release)) assert.Empty(t, release.Attachments) diff --git a/services/repository/adopt.go b/services/repository/adopt.go index 00dce7295ed..b7e8866beb0 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -195,7 +195,7 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r return fmt.Errorf("updateRepository: %w", err) } - if err = repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil { + if err = repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { return fmt.Errorf("SyncReleasesWithTags: %w", err) } diff --git a/services/repository/archiver/archiver.go b/services/repository/archiver/archiver.go index 2e3defee8d1..f6f03e75ae5 100644 --- a/services/repository/archiver/archiver.go +++ b/services/repository/archiver/archiver.go @@ -346,7 +346,7 @@ func DeleteOldRepositoryArchives(ctx context.Context, olderThan time.Duration) e log.Trace("Doing: ArchiveCleanup") for { - archivers, err := repo_model.FindRepoArchives(repo_model.FindRepoArchiversOption{ + archivers, err := repo_model.FindRepoArchives(ctx, repo_model.FindRepoArchiversOption{ ListOptions: db.ListOptions{ PageSize: 100, Page: 1, @@ -374,7 +374,7 @@ func DeleteOldRepositoryArchives(ctx context.Context, olderThan time.Duration) e // DeleteRepositoryArchives deletes all repositories' archives. func DeleteRepositoryArchives(ctx context.Context) error { - if err := repo_model.DeleteAllRepoArchives(); err != nil { + if err := repo_model.DeleteAllRepoArchives(ctx); err != nil { return err } return storage.Clean(storage.RepoArchives) diff --git a/services/repository/archiver/archiver_test.go b/services/repository/archiver/archiver_test.go index a1bc355d4e9..ff8bb8ca7a9 100644 --- a/services/repository/archiver/archiver_test.go +++ b/services/repository/archiver/archiver_test.go @@ -5,7 +5,6 @@ package archiver import ( "errors" - "path/filepath" "testing" "time" @@ -18,9 +17,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } func TestArchive_Basic(t *testing.T) { diff --git a/services/repository/branch.go b/services/repository/branch.go index 620e0b6c9f6..33512522001 100644 --- a/services/repository/branch.go +++ b/services/repository/branch.go @@ -29,6 +29,11 @@ import ( // CreateNewBranch creates a new repository branch func CreateNewBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldBranchName, branchName string) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + // Check if branch name can be used if err := checkBranchName(ctx, repo, branchName); err != nil { return err @@ -66,7 +71,7 @@ type Branch struct { } // LoadBranches loads branches from the repository limited by page & pageSize. -func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, isDeletedBranch util.OptionalBool, page, pageSize int) (*Branch, []*Branch, int64, error) { +func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git.Repository, isDeletedBranch util.OptionalBool, keyword string, page, pageSize int) (*Branch, []*Branch, int64, error) { defaultDBBranch, err := git_model.GetBranch(ctx, repo.ID, repo.DefaultBranch) if err != nil { return nil, nil, 0, err @@ -79,6 +84,7 @@ func LoadBranches(ctx context.Context, repo *repo_model.Repository, gitRepo *git Page: page, PageSize: pageSize, }, + Keyword: keyword, } totalNumOfBranches, err := git_model.CountBranches(ctx, branchOpts) @@ -245,6 +251,11 @@ func checkBranchName(ctx context.Context, repo *repo_model.Repository, name stri // CreateNewBranchFromCommit creates a new repository branch func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, branchName string) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + // Check if branch name can be used if err := checkBranchName(ctx, repo, branchName); err != nil { return err @@ -266,6 +277,11 @@ func CreateNewBranchFromCommit(ctx context.Context, doer *user_model.User, repo // RenameBranch rename a branch func RenameBranch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, gitRepo *git.Repository, from, to string) (string, error) { + err := repo.MustNotBeArchived() + if err != nil { + return "", err + } + if from == to { return "target_exist", nil } @@ -314,6 +330,11 @@ var ( // DeleteBranch delete branch func DeleteBranch(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, gitRepo *git.Repository, branchName string) error { + err := repo.MustNotBeArchived() + if err != nil { + return err + } + if branchName == repo.DefaultBranch { return ErrBranchIsDefault } diff --git a/services/repository/collaboration.go b/services/repository/collaboration.go index 28824d83f5f..eff33c71f3c 100644 --- a/services/repository/collaboration.go +++ b/services/repository/collaboration.go @@ -5,6 +5,8 @@ package repository import ( + "context" + "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" access_model "code.gitea.io/gitea/models/perm/access" @@ -12,13 +14,13 @@ import ( ) // DeleteCollaboration removes collaboration relation between the user and repository. -func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) { +func DeleteCollaboration(ctx context.Context, repo *repo_model.Repository, uid int64) (err error) { collaboration := &repo_model.Collaboration{ RepoID: repo.ID, UserID: uid, } - ctx, committer, err := db.TxContext(db.DefaultContext) + ctx, committer, err := db.TxContext(ctx) if err != nil { return err } diff --git a/services/repository/collaboration_test.go b/services/repository/collaboration_test.go index 08159af7bcf..c3d006bfd8c 100644 --- a/services/repository/collaboration_test.go +++ b/services/repository/collaboration_test.go @@ -18,10 +18,10 @@ func TestRepository_DeleteCollaboration(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) assert.NoError(t, repo.LoadOwner(db.DefaultContext)) - assert.NoError(t, DeleteCollaboration(repo, 4)) + assert.NoError(t, DeleteCollaboration(db.DefaultContext, repo, 4)) unittest.AssertNotExistsBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) - assert.NoError(t, DeleteCollaboration(repo, 4)) + assert.NoError(t, DeleteCollaboration(db.DefaultContext, repo, 4)) unittest.AssertNotExistsBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) diff --git a/services/repository/create_test.go b/services/repository/create_test.go index 78be93bf121..a9827c68894 100644 --- a/services/repository/create_test.go +++ b/services/repository/create_test.go @@ -28,7 +28,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name) for i, rid := range repoIds { if rid > 0 { - assert.True(t, HasRepository(team, rid), "%s: HasRepository(%d) %d", rid, i) + assert.True(t, HasRepository(db.DefaultContext, team, rid), "%s: HasRepository(%d) %d", rid, i) } } } @@ -44,7 +44,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { Type: user_model.UserTypeOrganization, Visibility: structs.VisibleTypePublic, } - assert.NoError(t, organization.CreateOrganization(org, user), "CreateOrganization") + assert.NoError(t, organization.CreateOrganization(db.DefaultContext, org, user), "CreateOrganization") // Check Owner team. ownerTeam, err := org.GetOwnerTeam(db.DefaultContext) @@ -101,7 +101,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { } for i, team := range teams { if i > 0 { // first team is Owner. - assert.NoError(t, models.NewTeam(team), "%s: NewTeam", team.Name) + assert.NoError(t, models.NewTeam(db.DefaultContext, team), "%s: NewTeam", team.Name) } testTeamRepositories(team.ID, teamRepos[i]) } @@ -111,7 +111,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { teams[4].IncludesAllRepositories = true teamRepos[4] = repoIds for i, team := range teams { - assert.NoError(t, models.UpdateTeam(team, false, true), "%s: UpdateTeam", team.Name) + assert.NoError(t, models.UpdateTeam(db.DefaultContext, team, false, true), "%s: UpdateTeam", team.Name) testTeamRepositories(team.ID, teamRepos[i]) } diff --git a/services/repository/delete.go b/services/repository/delete.go index 8e28c9b2558..f3bf91af4f3 100644 --- a/services/repository/delete.go +++ b/services/repository/delete.go @@ -276,7 +276,7 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r committer.Close() if needRewriteKeysFile { - if err := asymkey_model.RewriteAllPublicKeys(); err != nil { + if err := asymkey_model.RewriteAllPublicKeys(ctx); err != nil { log.Error("RewriteAllPublicKeys failed: %v", err) } } @@ -286,36 +286,36 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, uid, r // Remove repository files. repoPath := repo.RepoPath() - system_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository files", repoPath) + system_model.RemoveAllWithNotice(ctx, "Delete repository files", repoPath) // Remove wiki files if repo.HasWiki() { - system_model.RemoveAllWithNotice(db.DefaultContext, "Delete repository wiki", repo.WikiPath()) + system_model.RemoveAllWithNotice(ctx, "Delete repository wiki", repo.WikiPath()) } // Remove archives for _, archive := range archivePaths { - system_model.RemoveStorageWithNotice(db.DefaultContext, storage.RepoArchives, "Delete repo archive file", archive) + system_model.RemoveStorageWithNotice(ctx, storage.RepoArchives, "Delete repo archive file", archive) } // Remove lfs objects for _, lfsObj := range lfsPaths { - system_model.RemoveStorageWithNotice(db.DefaultContext, storage.LFS, "Delete orphaned LFS file", lfsObj) + system_model.RemoveStorageWithNotice(ctx, storage.LFS, "Delete orphaned LFS file", lfsObj) } // Remove issue attachment files. for _, attachment := range attachmentPaths { - system_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", attachment) + system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", attachment) } // Remove release attachment files. for _, releaseAttachment := range releaseAttachments { - system_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete release attachment", releaseAttachment) + system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete release attachment", releaseAttachment) } // Remove attachment with no issue_id and release_id. for _, newAttachment := range newAttachmentPaths { - system_model.RemoveStorageWithNotice(db.DefaultContext, storage.Attachments, "Delete issue attachment", newAttachment) + system_model.RemoveStorageWithNotice(ctx, storage.Attachments, "Delete issue attachment", newAttachment) } if len(repo.Avatar) > 0 { @@ -390,14 +390,14 @@ func removeRepositoryFromTeam(ctx context.Context, t *organization.Team, repo *r } // HasRepository returns true if given repository belong to team. -func HasRepository(t *organization.Team, repoID int64) bool { - return organization.HasTeamRepo(db.DefaultContext, t.OrgID, t.ID, repoID) +func HasRepository(ctx context.Context, t *organization.Team, repoID int64) bool { + return organization.HasTeamRepo(ctx, t.OrgID, t.ID, repoID) } // RemoveRepositoryFromTeam removes repository from team of organization. // If the team shall include all repositories the request is ignored. func RemoveRepositoryFromTeam(ctx context.Context, t *organization.Team, repoID int64) error { - if !HasRepository(t, repoID) { + if !HasRepository(ctx, t, repoID) { return nil } diff --git a/services/repository/delete_test.go b/services/repository/delete_test.go index 2905c018686..ae5fd539621 100644 --- a/services/repository/delete_test.go +++ b/services/repository/delete_test.go @@ -19,7 +19,7 @@ func TestTeam_HasRepository(t *testing.T) { test := func(teamID, repoID int64, expected bool) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.Equal(t, expected, HasRepository(team, repoID)) + assert.Equal(t, expected, HasRepository(db.DefaultContext, team, repoID)) } test(1, 1, false) test(1, 3, true) diff --git a/services/repository/files/content_test.go b/services/repository/files/content_test.go index d591c468399..3ad3e3ab98b 100644 --- a/services/repository/files/content_test.go +++ b/services/repository/files/content_test.go @@ -4,7 +4,6 @@ package files import ( - "path/filepath" "testing" repo_model "code.gitea.io/gitea/models/repo" @@ -19,9 +18,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", "..", ".."), - }) + unittest.MainTest(m) } func getExpectedReadmeContentsResponse() *api.ContentsResponse { diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index fdf0b32f1a1..5ef0619636e 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -95,6 +95,11 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode // ApplyDiffPatch applies a patch to the given repository func ApplyDiffPatch(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ApplyDiffPatchOptions) (*structs.FileResponse, error) { + err := repo.MustNotBeArchived() + if err != nil { + return nil, err + } + if err := opts.Validate(ctx, repo, doer); err != nil { return nil, err } diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go index 7f6b8137ae1..50c76970fd4 100644 --- a/services/repository/files/temp_repo.go +++ b/services/repository/files/temp_repo.go @@ -343,7 +343,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) { Stderr: stderr, PipelineFunc: func(ctx context.Context, cancel context.CancelFunc) error { _ = stdoutWriter.Close() - diff, finalErr = gitdiff.ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "") + diff, finalErr = gitdiff.ParsePatch(t.ctx, setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader, "") if finalErr != nil { log.Error("ParsePatch: %v", finalErr) cancel() diff --git a/services/repository/files/update.go b/services/repository/files/update.go index f01092d360d..2a08bcbacea 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -65,6 +65,11 @@ type RepoFileOptions struct { // ChangeRepoFiles adds, updates or removes multiple files in the given repository func ChangeRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, opts *ChangeRepoFilesOptions) (*structs.FilesResponse, error) { + err := repo.MustNotBeArchived() + if err != nil { + return nil, err + } + // If no branch name is set, assume default branch if opts.OldBranch == "" { opts.OldBranch = repo.DefaultBranch diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go index 338811f0f1c..f4e1da7bb1a 100644 --- a/services/repository/files/upload.go +++ b/services/repository/files/upload.go @@ -10,7 +10,6 @@ import ( "path" "strings" - "code.gitea.io/gitea/models/db" git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -35,13 +34,13 @@ type uploadInfo struct { lfsMetaObject *git_model.LFSMetaObject } -func cleanUpAfterFailure(infos *[]uploadInfo, t *TemporaryUploadRepository, original error) error { +func cleanUpAfterFailure(ctx context.Context, infos *[]uploadInfo, t *TemporaryUploadRepository, original error) error { for _, info := range *infos { if info.lfsMetaObject == nil { continue } if !info.lfsMetaObject.Existing { - if _, err := git_model.RemoveLFSMetaObjectByOid(db.DefaultContext, t.repo.ID, info.lfsMetaObject.Oid); err != nil { + if _, err := git_model.RemoveLFSMetaObjectByOid(ctx, t.repo.ID, info.lfsMetaObject.Oid); err != nil { original = fmt.Errorf("%w, %v", original, err) // We wrap the original error - as this is the underlying error that required the fallback } } @@ -55,7 +54,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use return nil } - uploads, err := repo_model.GetUploadsByUUIDs(opts.Files) + uploads, err := repo_model.GetUploadsByUUIDs(ctx, opts.Files) if err != nil { return fmt.Errorf("GetUploadsByUUIDs [uuids: %v]: %w", opts.Files, err) } @@ -147,7 +146,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use infos[i].lfsMetaObject, err = git_model.NewLFSMetaObject(ctx, infos[i].lfsMetaObject) if err != nil { // OK Now we need to cleanup - return cleanUpAfterFailure(&infos, t, err) + return cleanUpAfterFailure(ctx, &infos, t, err) } // Don't move the files yet - we need to ensure that // everything can be inserted first @@ -158,7 +157,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use contentStore := lfs.NewContentStore() for _, info := range infos { if err := uploadToLFSContentStore(info, contentStore); err != nil { - return cleanUpAfterFailure(&infos, t, err) + return cleanUpAfterFailure(ctx, &infos, t, err) } } @@ -167,7 +166,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use return err } - return repo_model.DeleteUploads(uploads...) + return repo_model.DeleteUploads(ctx, uploads...) } func copyUploadedLFSFileIntoRepository(info *uploadInfo, filename2attribute2info map[string]map[string]string, t *TemporaryUploadRepository, treePath string) error { diff --git a/services/repository/fork.go b/services/repository/fork.go index 4e0fbc38ac3..d5ab42badd8 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -44,9 +44,10 @@ func (err ErrForkAlreadyExist) Unwrap() error { // ForkRepoOptions contains the fork repository options type ForkRepoOptions struct { - BaseRepo *repo_model.Repository - Name string - Description string + BaseRepo *repo_model.Repository + Name string + Description string + SingleBranch string } // ForkRepository forks a repository @@ -70,6 +71,10 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork } } + defaultBranch := opts.BaseRepo.DefaultBranch + if opts.SingleBranch != "" { + defaultBranch = opts.SingleBranch + } repo := &repo_model.Repository{ OwnerID: owner.ID, Owner: owner, @@ -77,7 +82,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork Name: opts.Name, LowerName: strings.ToLower(opts.Name), Description: opts.Description, - DefaultBranch: opts.BaseRepo.DefaultBranch, + DefaultBranch: defaultBranch, IsPrivate: opts.BaseRepo.IsPrivate || opts.BaseRepo.Owner.Visibility == structs.VisibleTypePrivate, IsEmpty: opts.BaseRepo.IsEmpty, IsFork: true, @@ -134,9 +139,12 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork needsRollback = true + cloneCmd := git.NewCommand(txCtx, "clone", "--bare") + if opts.SingleBranch != "" { + cloneCmd.AddArguments("--single-branch", "--branch").AddDynamicArguments(opts.SingleBranch) + } repoPath := repo_model.RepoPath(owner.Name, repo.Name) - if stdout, _, err := git.NewCommand(txCtx, - "clone", "--bare").AddDynamicArguments(oldRepoPath, repoPath). + if stdout, _, err := cloneCmd.AddDynamicArguments(oldRepoPath, repoPath). SetDescription(fmt.Sprintf("ForkRepository(git clone): %s to %s", opts.BaseRepo.FullName(), repo.FullName())). RunStdBytes(&git.RunOpts{Timeout: 10 * time.Minute}); err != nil { log.Error("Fork Repository (git clone) Failed for %v (from %v):\nStdout: %s\nError: %v", repo, opts.BaseRepo, stdout, err) @@ -186,7 +194,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork log.Error("Open created git repository failed: %v", err) } else { defer gitRepo.Close() - if err := repo_module.SyncReleasesWithTags(repo, gitRepo); err != nil { + if err := repo_module.SyncReleasesWithTags(ctx, repo, gitRepo); err != nil { log.Error("Sync releases from git tags failed: %v", err) } } diff --git a/services/repository/main_test.go b/services/repository/main_test.go index 007790f2a96..7ad1540aee4 100644 --- a/services/repository/main_test.go +++ b/services/repository/main_test.go @@ -4,14 +4,11 @@ package repository import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } diff --git a/services/repository/push.go b/services/repository/push.go index 9b00b57e71e..97da45f52b4 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -292,7 +292,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } // Change repository last updated time. - if err := repo_model.UpdateRepositoryUpdatedTime(repo.ID, time.Now()); err != nil { + if err := repo_model.UpdateRepositoryUpdatedTime(ctx, repo.ID, time.Now()); err != nil { return fmt.Errorf("UpdateRepositoryUpdatedTime: %w", err) } diff --git a/services/repository/repository.go b/services/repository/repository.go index 60f9568b541..fb52980bbda 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -95,12 +95,12 @@ func PushCreateRepo(ctx context.Context, authUser, owner *user_model.User, repoN } // Init start repository service -func Init() error { +func Init(ctx context.Context) error { if err := repo_module.LoadRepoConfig(); err != nil { return err } - system_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repository uploads", setting.Repository.Upload.TempPath) - system_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repositories", repo_module.LocalCopyPath()) + system_model.RemoveAllWithNotice(ctx, "Clean up temporary repository uploads", setting.Repository.Upload.TempPath) + system_model.RemoveAllWithNotice(ctx, "Clean up temporary repositories", repo_module.LocalCopyPath()) if err := initPushQueue(); err != nil { return err } diff --git a/services/repository/transfer.go b/services/repository/transfer.go index 2edb61816fb..574b6c6a563 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -37,7 +37,7 @@ func TransferOwnership(ctx context.Context, doer, newOwner *user_model.User, rep oldOwner := repo.Owner repoWorkingPool.CheckIn(fmt.Sprint(repo.ID)) - if err := models.TransferOwnership(doer, newOwner.Name, repo); err != nil { + if err := models.TransferOwnership(ctx, doer, newOwner.Name, repo); err != nil { repoWorkingPool.CheckOut(fmt.Sprint(repo.ID)) return err } @@ -70,7 +70,7 @@ func ChangeRepositoryName(ctx context.Context, doer *user_model.User, repo *repo // local copy's origin accordingly. repoWorkingPool.CheckIn(fmt.Sprint(repo.ID)) - if err := repo_model.ChangeRepositoryName(doer, repo, newRepoName); err != nil { + if err := repo_model.ChangeRepositoryName(ctx, doer, repo, newRepoName); err != nil { repoWorkingPool.CheckOut(fmt.Sprint(repo.ID)) return err } diff --git a/services/task/migrate.go b/services/task/migrate.go index ebf179045e0..b74e024ba6c 100644 --- a/services/task/migrate.go +++ b/services/task/migrate.go @@ -4,6 +4,7 @@ package task import ( + "context" "errors" "fmt" "strings" @@ -40,15 +41,15 @@ func handleCreateError(owner *user_model.User, err error) error { } } -func runMigrateTask(t *admin_model.Task) (err error) { +func runMigrateTask(ctx context.Context, t *admin_model.Task) (err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("PANIC whilst trying to do migrate task: %v", e) log.Critical("PANIC during runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d]: %v\nStacktrace: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, e, log.Stack(2)) } - + // fixme: Because ctx is canceled here, so the db.DefaultContext is needed. if err == nil { - err = admin_model.FinishMigrateTask(t) + err = admin_model.FinishMigrateTask(db.DefaultContext, t) if err == nil { notify_service.MigrateRepository(db.DefaultContext, t.Doer, t.Owner, t.Repo) return @@ -62,15 +63,15 @@ func runMigrateTask(t *admin_model.Task) (err error) { t.EndTime = timeutil.TimeStampNow() t.Status = structs.TaskStatusFailed t.Message = err.Error() - - if err := t.UpdateCols("status", "message", "end_time"); err != nil { + // fixme: Because ctx is canceled here, so the db.DefaultContext is needed. + if err := t.UpdateCols(db.DefaultContext, "status", "message", "end_time"); err != nil { log.Error("Task UpdateCols failed: %v", err) } // then, do not delete the repository, otherwise the users won't be able to see the last error }() - if err = t.LoadRepo(); err != nil { + if err = t.LoadRepo(ctx); err != nil { return err } @@ -79,10 +80,10 @@ func runMigrateTask(t *admin_model.Task) (err error) { return nil } - if err = t.LoadDoer(); err != nil { + if err = t.LoadDoer(ctx); err != nil { return err } - if err = t.LoadOwner(); err != nil { + if err = t.LoadOwner(ctx); err != nil { return err } @@ -100,7 +101,7 @@ func runMigrateTask(t *admin_model.Task) (err error) { t.StartTime = timeutil.TimeStampNow() t.Status = structs.TaskStatusRunning - if err = t.UpdateCols("start_time", "status"); err != nil { + if err = t.UpdateCols(ctx, "start_time", "status"); err != nil { return err } @@ -112,7 +113,7 @@ func runMigrateTask(t *admin_model.Task) (err error) { case <-ctx.Done(): return } - task, _ := admin_model.GetMigratingTask(t.RepoID) + task, _ := admin_model.GetMigratingTask(ctx, t.RepoID) if task != nil && task.Status != structs.TaskStatusRunning { log.Debug("MigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] is canceled due to status is not 'running'", t.ID, t.DoerID, t.RepoID, t.OwnerID) cancel() @@ -128,7 +129,7 @@ func runMigrateTask(t *admin_model.Task) (err error) { } bs, _ := json.Marshal(message) t.Message = string(bs) - _ = t.UpdateCols("message") + _ = t.UpdateCols(ctx, "message") }) if err == nil { diff --git a/services/task/task.go b/services/task/task.go index 3a40faef90a..e15cab7b3c9 100644 --- a/services/task/task.go +++ b/services/task/task.go @@ -4,6 +4,7 @@ package task import ( + "context" "fmt" admin_model "code.gitea.io/gitea/models/admin" @@ -27,10 +28,10 @@ import ( var taskQueue *queue.WorkerPoolQueue[*admin_model.Task] // Run a task -func Run(t *admin_model.Task) error { +func Run(ctx context.Context, t *admin_model.Task) error { switch t.Type { case structs.TaskTypeMigrateRepo: - return runMigrateTask(t) + return runMigrateTask(ctx, t) default: return fmt.Errorf("Unknown task type: %d", t.Type) } @@ -48,7 +49,7 @@ func Init() error { func handler(items ...*admin_model.Task) []*admin_model.Task { for _, task := range items { - if err := Run(task); err != nil { + if err := Run(db.DefaultContext, task); err != nil { log.Error("Run task failed: %v", err) } } @@ -56,8 +57,8 @@ func handler(items ...*admin_model.Task) []*admin_model.Task { } // MigrateRepository add migration repository to task -func MigrateRepository(doer, u *user_model.User, opts base.MigrateOptions) error { - task, err := CreateMigrateTask(doer, u, opts) +func MigrateRepository(ctx context.Context, doer, u *user_model.User, opts base.MigrateOptions) error { + task, err := CreateMigrateTask(ctx, doer, u, opts) if err != nil { return err } @@ -66,7 +67,7 @@ func MigrateRepository(doer, u *user_model.User, opts base.MigrateOptions) error } // CreateMigrateTask creates a migrate task -func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*admin_model.Task, error) { +func CreateMigrateTask(ctx context.Context, doer, u *user_model.User, opts base.MigrateOptions) (*admin_model.Task, error) { // encrypt credentials for persistence var err error opts.CloneAddrEncrypted, err = secret.EncryptSecret(setting.SecretKey, opts.CloneAddr) @@ -97,11 +98,11 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*adm PayloadContent: string(bs), } - if err := admin_model.CreateTask(task); err != nil { + if err := admin_model.CreateTask(ctx, task); err != nil { return nil, err } - repo, err := repo_service.CreateRepositoryDirectly(db.DefaultContext, doer, u, repo_service.CreateRepoOptions{ + repo, err := repo_service.CreateRepositoryDirectly(ctx, doer, u, repo_service.CreateRepoOptions{ Name: opts.RepoName, Description: opts.Description, OriginalURL: opts.OriginalURL, @@ -113,7 +114,7 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*adm if err != nil { task.EndTime = timeutil.TimeStampNow() task.Status = structs.TaskStatusFailed - err2 := task.UpdateCols("end_time", "status") + err2 := task.UpdateCols(ctx, "end_time", "status") if err2 != nil { log.Error("UpdateCols Failed: %v", err2.Error()) } @@ -121,7 +122,7 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*adm } task.RepoID = repo.ID - if err = task.UpdateCols("repo_id"); err != nil { + if err = task.UpdateCols(ctx, "repo_id"); err != nil { return nil, err } @@ -129,8 +130,8 @@ func CreateMigrateTask(doer, u *user_model.User, opts base.MigrateOptions) (*adm } // RetryMigrateTask retry a migrate task -func RetryMigrateTask(repoID int64) error { - migratingTask, err := admin_model.GetMigratingTask(repoID) +func RetryMigrateTask(ctx context.Context, repoID int64) error { + migratingTask, err := admin_model.GetMigratingTask(ctx, repoID) if err != nil { log.Error("GetMigratingTask: %v", err) return err @@ -144,7 +145,7 @@ func RetryMigrateTask(repoID int64) error { // Reset task status and messages migratingTask.Status = structs.TaskStatusQueued migratingTask.Message = "" - if err = migratingTask.UpdateCols("status", "message"); err != nil { + if err = migratingTask.UpdateCols(ctx, "status", "message"); err != nil { log.Error("task.UpdateCols failed: %v", err) return err } diff --git a/services/uinotification/notify.go b/services/uinotification/notify.go index 9cf4fe73d78..9230d1ee6ce 100644 --- a/services/uinotification/notify.go +++ b/services/uinotification/notify.go @@ -52,7 +52,7 @@ func NewNotifier() notify_service.Notifier { func handler(items ...issueNotificationOpts) []issueNotificationOpts { for _, opts := range items { - if err := activities_model.CreateOrUpdateIssueNotifications(opts.IssueID, opts.CommentID, opts.NotificationAuthorID, opts.ReceiverID); err != nil { + if err := activities_model.CreateOrUpdateIssueNotifications(db.DefaultContext, opts.IssueID, opts.CommentID, opts.NotificationAuthorID, opts.ReceiverID); err != nil { log.Error("Was unable to create issue notification: %v", err) } } diff --git a/services/user/user.go b/services/user/user.go index 72bea0b4688..53cc3611078 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -59,7 +59,7 @@ func RenameUser(ctx context.Context, u *user_model.User, newUserName string) err u.Name = oldUserName return err } - return repo_model.UpdateRepositoryOwnerNames(u.ID, newUserName) + return repo_model.UpdateRepositoryOwnerNames(ctx, u.ID, newUserName) } ctx, committer, err := db.TxContext(ctx) @@ -189,7 +189,7 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { // An alternative option here would be write a function which would delete all organizations but it seems // but such a function would likely get out of date for { - orgs, err := organization.FindOrgs(organization.FindOrgOptions{ + orgs, err := organization.FindOrgs(ctx, organization.FindOrgOptions{ ListOptions: db.ListOptions{ PageSize: repo_model.RepositoryListDefaultPageSize, Page: 1, @@ -265,10 +265,10 @@ func DeleteUser(ctx context.Context, u *user_model.User, purge bool) error { } committer.Close() - if err = asymkey_model.RewriteAllPublicKeys(); err != nil { + if err = asymkey_model.RewriteAllPublicKeys(ctx); err != nil { return err } - if err = asymkey_model.RewriteAllPrincipalKeys(db.DefaultContext); err != nil { + if err = asymkey_model.RewriteAllPrincipalKeys(ctx); err != nil { return err } diff --git a/services/user/user_test.go b/services/user/user_test.go index 3f1bf9a0f8c..550dafd9c56 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -5,7 +5,6 @@ package user import ( "fmt" - "path/filepath" "strings" "testing" @@ -22,9 +21,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestDeleteUser(t *testing.T) { @@ -92,7 +89,7 @@ func TestCreateUser(t *testing.T) { MustChangePassword: false, } - assert.NoError(t, user_model.CreateUser(user)) + assert.NoError(t, user_model.CreateUser(db.DefaultContext, user)) assert.NoError(t, DeleteUser(db.DefaultContext, user, false)) } @@ -150,7 +147,7 @@ func TestRenameUser(t *testing.T) { assert.NoError(t, RenameUser(db.DefaultContext, user, newUsername)) unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: user.ID, Name: newUsername, LowerName: strings.ToLower(newUsername)}) - redirectUID, err := user_model.LookupUserRedirect(oldUsername) + redirectUID, err := user_model.LookupUserRedirect(db.DefaultContext, oldUsername) assert.NoError(t, err) assert.EqualValues(t, user.ID, redirectUID) @@ -177,7 +174,7 @@ func TestCreateUser_Issue5882(t *testing.T) { for _, v := range tt { setting.Admin.DisableRegularOrgCreation = v.disableOrgCreation - assert.NoError(t, user_model.CreateUser(v.user)) + assert.NoError(t, user_model.CreateUser(db.DefaultContext, v.user)) u, err := user_model.GetUserByEmail(db.DefaultContext, v.user.Email) assert.NoError(t, err) diff --git a/services/webhook/dingtalk.go b/services/webhook/dingtalk.go index 69fae03299a..c6fbe2f0765 100644 --- a/services/webhook/dingtalk.go +++ b/services/webhook/dingtalk.go @@ -170,7 +170,7 @@ func (d *DingtalkPayload) Repository(p *api.RepositoryPayload) (api.Payloader, e func (d *DingtalkPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, _ := getReleasePayloadInfo(p, noneLinkFormatter, true) - return createDingtalkPayload(text, text, "view release", p.Release.URL), nil + return createDingtalkPayload(text, text, "view release", p.Release.HTMLURL), nil } func createDingtalkPayload(title, text, singleTitle, singleURL string) *DingtalkPayload { diff --git a/services/webhook/dingtalk_test.go b/services/webhook/dingtalk_test.go index e3122d2f36f..7289c751f38 100644 --- a/services/webhook/dingtalk_test.go +++ b/services/webhook/dingtalk_test.go @@ -238,7 +238,7 @@ func TestDingTalkPayload(t *testing.T) { assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Text) assert.Equal(t, "[test/repo] Release created: v1.0 by user1", pl.(*DingtalkPayload).ActionCard.Title) assert.Equal(t, "view release", pl.(*DingtalkPayload).ActionCard.SingleTitle) - assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) + assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", parseRealSingleURL(pl.(*DingtalkPayload).ActionCard.SingleURL)) }) } diff --git a/services/webhook/discord.go b/services/webhook/discord.go index 204587eca5b..b22bb4f9121 100644 --- a/services/webhook/discord.go +++ b/services/webhook/discord.go @@ -253,7 +253,7 @@ func (d *DiscordPayload) Wiki(p *api.WikiPayload) (api.Payloader, error) { func (d *DiscordPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { text, color := getReleasePayloadInfo(p, noneLinkFormatter, false) - return d.createPayload(p.Sender, text, p.Release.Note, p.Release.URL, color), nil + return d.createPayload(p.Sender, text, p.Release.Note, p.Release.HTMLURL, color), nil } // GetDiscordPayload converts a discord webhook into a DiscordPayload diff --git a/services/webhook/discord_test.go b/services/webhook/discord_test.go index 624d53446a9..6a276e9e874 100644 --- a/services/webhook/discord_test.go +++ b/services/webhook/discord_test.go @@ -270,7 +270,7 @@ func TestDiscordPayload(t *testing.T) { assert.Len(t, pl.(*DiscordPayload).Embeds, 1) assert.Equal(t, "[test/repo] Release created: v1.0", pl.(*DiscordPayload).Embeds[0].Title) assert.Equal(t, "Note of first stable release", pl.(*DiscordPayload).Embeds[0].Description) - assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*DiscordPayload).Embeds[0].URL) + assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.(*DiscordPayload).Embeds[0].URL) assert.Equal(t, p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.Name) assert.Equal(t, setting.AppURL+p.Sender.UserName, pl.(*DiscordPayload).Embeds[0].Author.URL) assert.Equal(t, p.Sender.AvatarURL, pl.(*DiscordPayload).Embeds[0].Author.IconURL) diff --git a/services/webhook/general_test.go b/services/webhook/general_test.go index 64bd72f5a05..a9a8c6b5212 100644 --- a/services/webhook/general_test.go +++ b/services/webhook/general_test.go @@ -240,7 +240,7 @@ func pullReleaseTestPayload() *api.ReleasePayload { Target: "master", Title: "First stable release", Note: "Note of first stable release", - URL: "http://localhost:3000/api/v1/repos/test/repo/releases/2", + HTMLURL: "http://localhost:3000/test/repo/releases/tag/v1.0", }, } } diff --git a/services/webhook/main_test.go b/services/webhook/main_test.go index cd34c02b5c5..756b9db2308 100644 --- a/services/webhook/main_test.go +++ b/services/webhook/main_test.go @@ -4,7 +4,6 @@ package webhook import ( - "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" @@ -19,7 +18,6 @@ func TestMain(m *testing.M) { // for tests, allow only loopback IPs setting.Webhook.AllowedHostList = hostmatcher.MatchBuiltinLoopback unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), SetUp: func() error { setting.LoadQueueSettings() return Init() diff --git a/services/webhook/matrix.go b/services/webhook/matrix.go index df97b43b64c..a7f57f97b6a 100644 --- a/services/webhook/matrix.go +++ b/services/webhook/matrix.go @@ -177,7 +177,7 @@ func (m *MatrixPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, e func (m *MatrixPayload) Review(p *api.PullRequestPayload, event webhook_module.HookEventType) (api.Payloader, error) { senderLink := MatrixLinkFormatter(setting.AppURL+url.PathEscape(p.Sender.UserName), p.Sender.UserName) title := fmt.Sprintf("#%d %s", p.Index, p.PullRequest.Title) - titleLink := MatrixLinkFormatter(p.PullRequest.URL, title) + titleLink := MatrixLinkFormatter(p.PullRequest.HTMLURL, title) repoLink := MatrixLinkFormatter(p.Repository.HTMLURL, p.Repository.FullName) var text string diff --git a/services/webhook/msteams.go b/services/webhook/msteams.go index 6ad58a6247f..dfc1c682895 100644 --- a/services/webhook/msteams.go +++ b/services/webhook/msteams.go @@ -290,7 +290,7 @@ func (m *MSTeamsPayload) Release(p *api.ReleasePayload) (api.Payloader, error) { p.Sender, title, "", - p.Release.URL, + p.Release.HTMLURL, color, &MSTeamsFact{"Tag:", p.Release.TagName}, ), nil diff --git a/services/webhook/msteams_test.go b/services/webhook/msteams_test.go index 4f378713cc7..990a535df5c 100644 --- a/services/webhook/msteams_test.go +++ b/services/webhook/msteams_test.go @@ -429,7 +429,7 @@ func TestMSTeamsPayload(t *testing.T) { } assert.Len(t, pl.(*MSTeamsPayload).PotentialAction, 1) assert.Len(t, pl.(*MSTeamsPayload).PotentialAction[0].Targets, 1) - assert.Equal(t, "http://localhost:3000/api/v1/repos/test/repo/releases/2", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) + assert.Equal(t, "http://localhost:3000/test/repo/releases/tag/v1.0", pl.(*MSTeamsPayload).PotentialAction[0].Targets[0].URI) }) } diff --git a/services/webhook/slack.go b/services/webhook/slack.go index 0cb27bb3dd6..75079d0fdf1 100644 --- a/services/webhook/slack.go +++ b/services/webhook/slack.go @@ -223,7 +223,7 @@ func (s *SlackPayload) PullRequest(p *api.PullRequestPayload) (api.Payloader, er attachments = append(attachments, SlackAttachment{ Color: fmt.Sprintf("%x", color), Title: issueTitle, - TitleLink: p.PullRequest.URL, + TitleLink: p.PullRequest.HTMLURL, Text: attachmentText, }) } diff --git a/services/wiki/wiki.go b/services/wiki/wiki.go index c0183dd2b59..18371efd098 100644 --- a/services/wiki/wiki.go +++ b/services/wiki/wiki.go @@ -79,6 +79,11 @@ func prepareGitPath(gitRepo *git.Repository, wikiPath WebPath) (bool, string, er // updateWikiPage adds a new page or edits an existing page in repository wiki. func updateWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, oldWikiName, newWikiName WebPath, content, message string, isNew bool) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + if err = validateWebPath(newWikiName); err != nil { return err } @@ -238,6 +243,11 @@ func EditWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.R // DeleteWikiPage deletes a wiki page identified by its path. func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, wikiName WebPath) (err error) { + err = repo.MustNotBeArchived() + if err != nil { + return err + } + wikiWorkingPool.CheckIn(fmt.Sprint(repo.ID)) defer wikiWorkingPool.CheckOut(fmt.Sprint(repo.ID)) @@ -340,7 +350,7 @@ func DeleteWikiPage(ctx context.Context, doer *user_model.User, repo *repo_model // DeleteWiki removes the actual and local copy of repository wiki. func DeleteWiki(ctx context.Context, repo *repo_model.Repository) error { - if err := repo_model.UpdateRepositoryUnits(repo, nil, []unit.Type{unit.TypeWiki}); err != nil { + if err := repo_model.UpdateRepositoryUnits(ctx, repo, nil, []unit.Type{unit.TypeWiki}); err != nil { return err } diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go index 0621456f3e8..e8da176a08d 100644 --- a/services/wiki/wiki_test.go +++ b/services/wiki/wiki_test.go @@ -5,7 +5,6 @@ package wiki import ( "math/rand" - "path/filepath" "strings" "testing" @@ -20,9 +19,7 @@ import ( ) func TestMain(m *testing.M) { - unittest.MainTest(m, &unittest.TestOptions{ - GiteaRootPath: filepath.Join("..", ".."), - }) + unittest.MainTest(m) } func TestWebPathSegments(t *testing.T) { @@ -168,7 +165,9 @@ func TestRepository_AddWikiPage(t *testing.T) { assert.NoError(t, AddWikiPage(git.DefaultContext, doer, repo, webPath, wikiContent, commitMsg)) // Now need to show that the page has been added: gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath()) - assert.NoError(t, err) + if !assert.NoError(t, err) { + return + } defer gitRepo.Close() masterTree, err := gitRepo.GetTree(DefaultBranch) assert.NoError(t, err) @@ -238,7 +237,9 @@ func TestRepository_DeleteWikiPage(t *testing.T) { // Now need to show that the page has been added: gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath()) - assert.NoError(t, err) + if !assert.NoError(t, err) { + return + } defer gitRepo.Close() masterTree, err := gitRepo.GetTree(DefaultBranch) assert.NoError(t, err) @@ -251,8 +252,10 @@ func TestPrepareWikiFileName(t *testing.T) { unittest.PrepareTestEnv(t) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) gitRepo, err := git.OpenRepository(git.DefaultContext, repo.WikiPath()) + if !assert.NoError(t, err) { + return + } defer gitRepo.Close() - assert.NoError(t, err) tests := []struct { name string @@ -303,8 +306,10 @@ func TestPrepareWikiFileName_FirstPage(t *testing.T) { assert.NoError(t, err) gitRepo, err := git.OpenRepository(git.DefaultContext, tmpDir) + if !assert.NoError(t, err) { + return + } defer gitRepo.Close() - assert.NoError(t, err) existence, newWikiPath, err := prepareGitPath(gitRepo, "Home") assert.False(t, existence) diff --git a/templates/admin/applications/list.tmpl b/templates/admin/applications/list.tmpl index a292051fd0d..cbb66b16053 100644 --- a/templates/admin/applications/list.tmpl +++ b/templates/admin/applications/list.tmpl @@ -1,7 +1,7 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}

- {{.locale.Tr "settings.applications"}} + {{ctx.Locale.Tr "settings.applications"}}

{{template "user/settings/applications_oauth2_list" .}}
diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl index 6dfa86d9dd1..25abefae000 100644 --- a/templates/admin/auth/edit.tmpl +++ b/templates/admin/auth/edit.tmpl @@ -1,7 +1,7 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin edit authentication")}}

- {{.locale.Tr "admin.auths.edit"}} + {{ctx.Locale.Tr "admin.auths.edit"}}

@@ -9,12 +9,12 @@ {{.CsrfTokenHtml}}
- + {{.Source.TypeName}}
- +
@@ -22,7 +22,7 @@ {{if or .Source.IsLDAP .Source.IsDLDAP}} {{$cfg:=.Source.Cfg}}
- +
- +
- +
- +
{{if .Source.IsLDAP}}
- +
- +
{{end}}
- +
{{if .Source.IsDLDAP}}
- +
{{end}}
- +
- +
- + -

{{.locale.Tr "admin.auths.restricted_filter_helper"}}

+

{{ctx.Locale.Tr "admin.auths.restricted_filter_helper"}}

- - + +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
@@ -144,31 +144,31 @@ {{if .Source.IsLDAP}}
- +
- +
- +
{{end}}
- + -

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

- +
@@ -178,7 +178,7 @@ {{if .Source.IsSMTP}} {{$cfg:=.Source.Cfg}}
- +
- +
- +
- +
-

{{.locale.Tr "admin.auths.force_smtps_helper"}}

+

{{ctx.Locale.Tr "admin.auths.force_smtps_helper"}}

- +
- + -

{{.locale.Tr "admin.auths.helo_hostname_helper"}}

+

{{ctx.Locale.Tr "admin.auths.helo_hostname_helper"}}

- +
- + -

{{.locale.Tr "admin.auths.allowed_domains_helper"}}

+

{{ctx.Locale.Tr "admin.auths.allowed_domains_helper"}}

- + -

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

{{end}} @@ -240,18 +240,18 @@ {{if .Source.IsPAM}} {{$cfg:=.Source.Cfg}}
- +
- +
- + -

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

{{end}} @@ -260,7 +260,7 @@ {{if .Source.IsOAuth2}} {{$cfg:=.Source.Cfg}}
- +
- +
- +
- +
- +
- + -

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

- +
- +
- +
- +
- +
- +
@@ -332,37 +332,37 @@ {{end}}{{end}}
- +
- + -

{{.locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}

+

{{ctx.Locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}

- + -

{{.locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}

+

{{ctx.Locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}

- +
- +
- +
- +
- +
{{end}} @@ -372,32 +372,32 @@ {{$cfg:=.Source.Cfg}}
- + -

{{.locale.Tr "admin.auths.sspi_auto_create_users_helper"}}

+

{{ctx.Locale.Tr "admin.auths.sspi_auto_create_users_helper"}}

- + -

{{.locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}

+

{{ctx.Locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}

- + -

{{.locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}

+

{{ctx.Locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}

- + -

{{.locale.Tr "admin.auths.sspi_separator_replacement_helper"}}

+

{{ctx.Locale.Tr "admin.auths.sspi_separator_replacement_helper"}}

- +
-

{{.locale.Tr "admin.auths.sspi_default_language_helper"}}

+

{{ctx.Locale.Tr "admin.auths.sspi_default_language_helper"}}

{{end}} {{if .Source.IsLDAP}}
- +
{{end}}
- +
- - + +

- {{.locale.Tr "admin.auths.tips"}} + {{ctx.Locale.Tr "admin.auths.tips"}}

GMail Settings:

Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true

-
{{.locale.Tr "admin.auths.tips.oauth2.general"}}:
-

{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}

+
{{ctx.Locale.Tr "admin.auths.tips.oauth2.general"}}:
+

{{ctx.Locale.Tr "admin.auths.tips.oauth2.general.tip"}}

diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl index c9f7c0d5164..6483ec800c4 100644 --- a/templates/admin/auth/list.tmpl +++ b/templates/admin/auth/list.tmpl @@ -1,9 +1,9 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin authentication")}}

- {{.locale.Tr "admin.auths.auth_manage_panel"}} ({{.locale.Tr "admin.total" .Total}}) + {{ctx.Locale.Tr "admin.auths.auth_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})

@@ -11,12 +11,12 @@ ID - {{.locale.Tr "admin.auths.name"}} - {{.locale.Tr "admin.auths.type"}} - {{.locale.Tr "admin.auths.enabled"}} - {{.locale.Tr "admin.auths.updated"}} - {{.locale.Tr "admin.users.created"}} - {{.locale.Tr "admin.users.edit"}} + {{ctx.Locale.Tr "admin.auths.name"}} + {{ctx.Locale.Tr "admin.auths.type"}} + {{ctx.Locale.Tr "admin.auths.enabled"}} + {{ctx.Locale.Tr "admin.auths.updated"}} + {{ctx.Locale.Tr "admin.users.created"}} + {{ctx.Locale.Tr "admin.users.edit"}} diff --git a/templates/admin/auth/new.tmpl b/templates/admin/auth/new.tmpl index 37d1635c11d..f32f77d5dc2 100644 --- a/templates/admin/auth/new.tmpl +++ b/templates/admin/auth/new.tmpl @@ -1,7 +1,7 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin new authentication")}}

- {{.locale.Tr "admin.auths.new"}} + {{ctx.Locale.Tr "admin.auths.new"}}

@@ -9,7 +9,7 @@ {{.CsrfTokenHtml}}
- +
- +
@@ -34,16 +34,16 @@
- + - +
- + -

{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

+

{{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

@@ -55,67 +55,67 @@
- +
- +
- +
- +

- {{.locale.Tr "admin.auths.tips"}} + {{ctx.Locale.Tr "admin.auths.tips"}}

GMail Settings:

Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true

-
{{.locale.Tr "admin.auths.tips.oauth2.general"}}:
-

{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}

+
{{ctx.Locale.Tr "admin.auths.tips.oauth2.general"}}:
+

{{ctx.Locale.Tr "admin.auths.tips.oauth2.general.tip"}}

-
{{.locale.Tr "admin.auths.tip.oauth2_provider"}}
+
{{ctx.Locale.Tr "admin.auths.tip.oauth2_provider"}}
  • Bitbucket
  • - {{.locale.Tr "admin.auths.tip.bitbucket"}} + {{ctx.Locale.Tr "admin.auths.tip.bitbucket"}}
  • Dropbox
  • - {{.locale.Tr "admin.auths.tip.dropbox"}} + {{ctx.Locale.Tr "admin.auths.tip.dropbox"}}
  • Facebook
  • - {{.locale.Tr "admin.auths.tip.facebook"}} + {{ctx.Locale.Tr "admin.auths.tip.facebook"}}
  • GitHub
  • - {{.locale.Tr "admin.auths.tip.github"}} + {{ctx.Locale.Tr "admin.auths.tip.github"}}
  • GitLab
  • - {{.locale.Tr "admin.auths.tip.gitlab"}} + {{ctx.Locale.Tr "admin.auths.tip.gitlab"}}
  • Google
  • - {{.locale.Tr "admin.auths.tip.google_plus"}} + {{ctx.Locale.Tr "admin.auths.tip.google_plus"}}
  • OpenID Connect
  • - {{.locale.Tr "admin.auths.tip.openid_connect"}} + {{ctx.Locale.Tr "admin.auths.tip.openid_connect"}}
  • Twitter
  • - {{.locale.Tr "admin.auths.tip.twitter"}} + {{ctx.Locale.Tr "admin.auths.tip.twitter"}}
  • Discord
  • - {{.locale.Tr "admin.auths.tip.discord"}} + {{ctx.Locale.Tr "admin.auths.tip.discord"}}
  • Gitea
  • - {{.locale.Tr "admin.auths.tip.gitea"}} + {{ctx.Locale.Tr "admin.auths.tip.gitea"}}
  • Nextcloud
  • - {{.locale.Tr "admin.auths.tip.nextcloud"}} + {{ctx.Locale.Tr "admin.auths.tip.nextcloud"}}
  • Yandex
  • - {{.locale.Tr "admin.auths.tip.yandex"}} + {{ctx.Locale.Tr "admin.auths.tip.yandex"}}
  • Mastodon
  • - {{.locale.Tr "admin.auths.tip.mastodon"}} + {{ctx.Locale.Tr "admin.auths.tip.mastodon"}}
    diff --git a/templates/admin/auth/source/ldap.tmpl b/templates/admin/auth/source/ldap.tmpl index a2bd37be0c5..a584ac76283 100644 --- a/templates/admin/auth/source/ldap.tmpl +++ b/templates/admin/auth/source/ldap.tmpl @@ -1,6 +1,6 @@
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - + -

    {{.locale.Tr "admin.auths.restricted_filter_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.restricted_filter_helper"}}

    - - + +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    - +
    @@ -117,24 +117,24 @@
    - +
    - +
    - + -

    {{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    - +
    diff --git a/templates/admin/auth/source/oauth.tmpl b/templates/admin/auth/source/oauth.tmpl index aaa8b7fe2d6..63ad77e67b1 100644 --- a/templates/admin/auth/source/oauth.tmpl +++ b/templates/admin/auth/source/oauth.tmpl @@ -1,6 +1,6 @@
    - +
    - +
    - +
    - +
    - +
    - + -

    {{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    - +
    - +
    - +
    - +
    - +
    - +
    @@ -73,37 +73,37 @@ {{end}}{{end}}
    - +
    - + -

    {{.locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}

    - + -

    {{.locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}

    - +
    - +
    - +
    - +
    - +
    diff --git a/templates/admin/auth/source/smtp.tmpl b/templates/admin/auth/source/smtp.tmpl index e83f7afb695..c4b0b0e7e4a 100644 --- a/templates/admin/auth/source/smtp.tmpl +++ b/templates/admin/auth/source/smtp.tmpl @@ -1,6 +1,6 @@
    - +
    - +
    - +
    - + -

    {{.locale.Tr "admin.auths.force_smtps_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.force_smtps_helper"}}

    - +
    - + -

    {{.locale.Tr "admin.auths.helo_hostname_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.helo_hostname_helper"}}

    - +
    - + -

    {{.locale.Tr "admin.auths.allowed_domains_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.allowed_domains_helper"}}

    - + -

    {{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.skip_local_two_fa_helper"}}

    diff --git a/templates/admin/auth/source/sspi.tmpl b/templates/admin/auth/source/sspi.tmpl index 9608616e1b2..f835e89bdfa 100644 --- a/templates/admin/auth/source/sspi.tmpl +++ b/templates/admin/auth/source/sspi.tmpl @@ -1,32 +1,32 @@
    - + -

    {{.locale.Tr "admin.auths.sspi_auto_create_users_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.sspi_auto_create_users_helper"}}

    - + -

    {{.locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}

    - + -

    {{.locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}

    - + -

    {{.locale.Tr "admin.auths.sspi_separator_replacement_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.sspi_separator_replacement_helper"}}

    - +
    -

    {{.locale.Tr "admin.auths.sspi_default_language_helper"}}

    +

    {{ctx.Locale.Tr "admin.auths.sspi_default_language_helper"}}

    diff --git a/templates/admin/base/search.tmpl b/templates/admin/base/search.tmpl index 19977f05a9b..d4bba8c0427 100644 --- a/templates/admin/base/search.tmpl +++ b/templates/admin/base/search.tmpl @@ -1,23 +1,23 @@ diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 36d9bcb8a5e..57722f98988 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -1,82 +1,82 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}

    - {{.locale.Tr "admin.config.server_config"}} + {{ctx.Locale.Tr "admin.config.server_config"}}

    -
    {{.locale.Tr "admin.config.app_name"}}
    +
    {{ctx.Locale.Tr "admin.config.app_name"}}
    {{AppName}}
    -
    {{.locale.Tr "admin.config.app_ver"}}
    +
    {{ctx.Locale.Tr "admin.config.app_ver"}}
    {{AppVer}}{{.AppBuiltWith}}
    -
    {{.locale.Tr "admin.config.custom_conf"}}
    +
    {{ctx.Locale.Tr "admin.config.custom_conf"}}
    {{.CustomConf}}
    -
    {{.locale.Tr "admin.config.app_url"}}
    +
    {{ctx.Locale.Tr "admin.config.app_url"}}
    {{.AppUrl}}
    -
    {{.locale.Tr "admin.config.domain"}}
    +
    {{ctx.Locale.Tr "admin.config.domain"}}
    {{.Domain}}
    -
    {{.locale.Tr "admin.config.offline_mode"}}
    +
    {{ctx.Locale.Tr "admin.config.offline_mode"}}
    {{if .OfflineMode}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.disable_router_log"}}
    +
    {{ctx.Locale.Tr "admin.config.disable_router_log"}}
    {{if .DisableRouterLog}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.run_user"}}
    +
    {{ctx.Locale.Tr "admin.config.run_user"}}
    {{.RunUser}}
    -
    {{.locale.Tr "admin.config.run_mode"}}
    +
    {{ctx.Locale.Tr "admin.config.run_mode"}}
    {{.RunMode}}
    -
    {{.locale.Tr "admin.config.git_version"}}
    +
    {{ctx.Locale.Tr "admin.config.git_version"}}
    {{.GitVersion}}
    -
    {{.locale.Tr "admin.config.app_data_path"}}
    +
    {{ctx.Locale.Tr "admin.config.app_data_path"}}
    {{.AppDataPath}}
    -
    {{.locale.Tr "admin.config.repo_root_path"}}
    +
    {{ctx.Locale.Tr "admin.config.repo_root_path"}}
    {{.RepoRootPath}}
    -
    {{.locale.Tr "admin.config.custom_file_root_path"}}
    +
    {{ctx.Locale.Tr "admin.config.custom_file_root_path"}}
    {{.CustomRootPath}}
    -
    {{.locale.Tr "admin.config.log_file_root_path"}}
    +
    {{ctx.Locale.Tr "admin.config.log_file_root_path"}}
    {{.LogRootPath}}
    -
    {{.locale.Tr "admin.config.script_type"}}
    +
    {{ctx.Locale.Tr "admin.config.script_type"}}
    {{.ScriptType}}
    -
    {{.locale.Tr "admin.config.reverse_auth_user"}}
    +
    {{ctx.Locale.Tr "admin.config.reverse_auth_user"}}
    {{.ReverseProxyAuthUser}}

    - {{.locale.Tr "admin.config.ssh_config"}} + {{ctx.Locale.Tr "admin.config.ssh_config"}}

    -
    {{.locale.Tr "admin.config.ssh_enabled"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_enabled"}}
    {{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if not .SSH.Disabled}} -
    {{.locale.Tr "admin.config.ssh_start_builtin_server"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_start_builtin_server"}}
    {{if .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.ssh_domain"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_domain"}}
    {{.SSH.Domain}}
    -
    {{.locale.Tr "admin.config.ssh_port"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_port"}}
    {{.SSH.Port}}
    -
    {{.locale.Tr "admin.config.ssh_listen_port"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_listen_port"}}
    {{.SSH.ListenPort}}
    {{if not .SSH.StartBuiltinServer}} -
    {{.locale.Tr "admin.config.ssh_root_path"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_root_path"}}
    {{.SSH.RootPath}}
    -
    {{.locale.Tr "admin.config.ssh_key_test_path"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_key_test_path"}}
    {{.SSH.KeyTestPath}}
    -
    {{.locale.Tr "admin.config.ssh_keygen_path"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_keygen_path"}}
    {{.SSH.KeygenPath}}
    -
    {{.locale.Tr "admin.config.ssh_minimum_key_size_check"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_minimum_key_size_check"}}
    {{if .SSH.MinimumKeySizeCheck}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .SSH.MinimumKeySizeCheck}} -
    {{.locale.Tr "admin.config.ssh_minimum_key_sizes"}}
    +
    {{ctx.Locale.Tr "admin.config.ssh_minimum_key_sizes"}}
    {{.SSH.MinimumKeySizes}}
    {{end}} {{end}} @@ -85,160 +85,160 @@

    - {{.locale.Tr "admin.config.lfs_config"}} + {{ctx.Locale.Tr "admin.config.lfs_config"}}

    -
    {{.locale.Tr "admin.config.lfs_enabled"}}
    +
    {{ctx.Locale.Tr "admin.config.lfs_enabled"}}
    {{if .LFS.StartServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .LFS.StartServer}} -
    {{.locale.Tr "admin.config.lfs_content_path"}}
    +
    {{ctx.Locale.Tr "admin.config.lfs_content_path"}}
    {{JsonUtils.EncodeToString .LFS.Storage.ToShadowCopy}}
    -
    {{.locale.Tr "admin.config.lfs_http_auth_expiry"}}
    +
    {{ctx.Locale.Tr "admin.config.lfs_http_auth_expiry"}}
    {{.LFS.HTTPAuthExpiry}}
    {{end}}

    - {{.locale.Tr "admin.config.db_config"}} + {{ctx.Locale.Tr "admin.config.db_config"}}

    -
    {{.locale.Tr "admin.config.db_type"}}
    +
    {{ctx.Locale.Tr "admin.config.db_type"}}
    {{.DbCfg.Type}}
    {{if not (eq .DbCfg.Type "sqlite3")}} -
    {{.locale.Tr "admin.config.db_host"}}
    +
    {{ctx.Locale.Tr "admin.config.db_host"}}
    {{if .DbCfg.Host}}{{.DbCfg.Host}}{{else}}-{{end}}
    -
    {{.locale.Tr "admin.config.db_name"}}
    +
    {{ctx.Locale.Tr "admin.config.db_name"}}
    {{if .DbCfg.Name}}{{.DbCfg.Name}}{{else}}-{{end}}
    -
    {{.locale.Tr "admin.config.db_user"}}
    +
    {{ctx.Locale.Tr "admin.config.db_user"}}
    {{if .DbCfg.User}}{{.DbCfg.User}}{{else}}-{{end}}
    {{end}} {{if eq .DbCfg.Type "postgres"}} -
    {{.locale.Tr "admin.config.db_schema"}}
    +
    {{ctx.Locale.Tr "admin.config.db_schema"}}
    {{if .DbCfg.Schema}}{{.DbCfg.Schema}}{{else}}-{{end}}
    -
    {{.locale.Tr "admin.config.db_ssl_mode"}}
    +
    {{ctx.Locale.Tr "admin.config.db_ssl_mode"}}
    {{if .DbCfg.SSLMode}}{{.DbCfg.SSLMode}}{{else}}-{{end}}
    {{end}} {{if eq .DbCfg.Type "sqlite3"}} -
    {{.locale.Tr "admin.config.db_path"}}
    +
    {{ctx.Locale.Tr "admin.config.db_path"}}
    {{if .DbCfg.Path}}{{.DbCfg.Path}}{{else}}-{{end}}
    {{end}}

    - {{.locale.Tr "admin.config.service_config"}} + {{ctx.Locale.Tr "admin.config.service_config"}}

    -
    {{.locale.Tr "admin.config.register_email_confirm"}}
    +
    {{ctx.Locale.Tr "admin.config.register_email_confirm"}}
    {{if .Service.RegisterEmailConfirm}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.disable_register"}}
    +
    {{ctx.Locale.Tr "admin.config.disable_register"}}
    {{if .Service.DisableRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.allow_only_internal_registration"}}
    +
    {{ctx.Locale.Tr "admin.config.allow_only_internal_registration"}}
    {{if .Service.AllowOnlyInternalRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.allow_only_external_registration"}}
    +
    {{ctx.Locale.Tr "admin.config.allow_only_external_registration"}}
    {{if .Service.AllowOnlyExternalRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.show_registration_button"}}
    +
    {{ctx.Locale.Tr "admin.config.show_registration_button"}}
    {{if .Service.ShowRegistrationButton}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.enable_openid_signup"}}
    +
    {{ctx.Locale.Tr "admin.config.enable_openid_signup"}}
    {{if .Service.EnableOpenIDSignUp}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.enable_openid_signin"}}
    +
    {{ctx.Locale.Tr "admin.config.enable_openid_signin"}}
    {{if .Service.EnableOpenIDSignIn}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.require_sign_in_view"}}
    +
    {{ctx.Locale.Tr "admin.config.require_sign_in_view"}}
    {{if .Service.RequireSignInView}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.mail_notify"}}
    +
    {{ctx.Locale.Tr "admin.config.mail_notify"}}
    {{if .Service.EnableNotifyMail}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.disable_key_size_check"}}
    +
    {{ctx.Locale.Tr "admin.config.disable_key_size_check"}}
    {{if .SSH.MinimumKeySizeCheck}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.enable_captcha"}}
    +
    {{ctx.Locale.Tr "admin.config.enable_captcha"}}
    {{if .Service.EnableCaptcha}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.default_keep_email_private"}}
    +
    {{ctx.Locale.Tr "admin.config.default_keep_email_private"}}
    {{if .Service.DefaultKeepEmailPrivate}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.default_allow_create_organization"}}
    +
    {{ctx.Locale.Tr "admin.config.default_allow_create_organization"}}
    {{if .Service.DefaultAllowCreateOrganization}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.enable_timetracking"}}
    +
    {{ctx.Locale.Tr "admin.config.enable_timetracking"}}
    {{if .Service.EnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .Service.EnableTimetracking}} -
    {{.locale.Tr "admin.config.default_enable_timetracking"}}
    +
    {{ctx.Locale.Tr "admin.config.default_enable_timetracking"}}
    {{if .Service.DefaultEnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.default_allow_only_contributors_to_track_time"}}
    +
    {{ctx.Locale.Tr "admin.config.default_allow_only_contributors_to_track_time"}}
    {{if .Service.DefaultAllowOnlyContributorsToTrackTime}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{end}} -
    {{.locale.Tr "admin.config.default_visibility_organization"}}
    +
    {{ctx.Locale.Tr "admin.config.default_visibility_organization"}}
    {{.Service.DefaultOrgVisibility}}
    -
    {{.locale.Tr "admin.config.no_reply_address"}}
    +
    {{ctx.Locale.Tr "admin.config.no_reply_address"}}
    {{if .Service.NoReplyAddress}}{{.Service.NoReplyAddress}}{{else}}-{{end}}
    -
    {{.locale.Tr "admin.config.default_enable_dependencies"}}
    +
    {{ctx.Locale.Tr "admin.config.default_enable_dependencies"}}
    {{if .Service.DefaultEnableDependencies}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.active_code_lives"}}
    -
    {{.Service.ActiveCodeLives}} {{.locale.Tr "tool.raw_minutes"}}
    -
    {{.locale.Tr "admin.config.reset_password_code_lives"}}
    -
    {{.Service.ResetPwdCodeLives}} {{.locale.Tr "tool.raw_minutes"}}
    +
    {{ctx.Locale.Tr "admin.config.active_code_lives"}}
    +
    {{.Service.ActiveCodeLives}} {{ctx.Locale.Tr "tool.raw_minutes"}}
    +
    {{ctx.Locale.Tr "admin.config.reset_password_code_lives"}}
    +
    {{.Service.ResetPwdCodeLives}} {{ctx.Locale.Tr "tool.raw_minutes"}}

    - {{.locale.Tr "admin.config.webhook_config"}} + {{ctx.Locale.Tr "admin.config.webhook_config"}}

    -
    {{.locale.Tr "admin.config.queue_length"}}
    +
    {{ctx.Locale.Tr "admin.config.queue_length"}}
    {{.Webhook.QueueLength}}
    -
    {{.locale.Tr "admin.config.deliver_timeout"}}
    -
    {{.Webhook.DeliverTimeout}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.skip_tls_verify"}}
    +
    {{ctx.Locale.Tr "admin.config.deliver_timeout"}}
    +
    {{.Webhook.DeliverTimeout}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.skip_tls_verify"}}
    {{if .Webhook.SkipTLSVerify}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}

    - {{.locale.Tr "admin.config.mailer_config"}} + {{ctx.Locale.Tr "admin.config.mailer_config"}}

    -
    {{.locale.Tr "admin.config.mailer_enabled"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_enabled"}}
    {{if .MailerEnabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{if .MailerEnabled}} -
    {{.locale.Tr "admin.config.mailer_name"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_name"}}
    {{.Mailer.Name}}
    {{if eq .Mailer.Protocol "sendmail"}} -
    {{.locale.Tr "admin.config.mailer_use_sendmail"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_use_sendmail"}}
    {{svg "octicon-check"}}
    -
    {{.locale.Tr "admin.config.mailer_sendmail_path"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_sendmail_path"}}
    {{.Mailer.SendmailPath}}
    -
    {{.locale.Tr "admin.config.mailer_sendmail_args"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_sendmail_args"}}
    {{.Mailer.SendmailArgs}}
    -
    {{.locale.Tr "admin.config.mailer_sendmail_timeout"}}
    -
    {{.Mailer.SendmailTimeout}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_sendmail_timeout"}}
    +
    {{.Mailer.SendmailTimeout}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    {{else if eq .Mailer.Protocol "dummy"}} -
    {{.locale.Tr "admin.config.mailer_use_dummy"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_use_dummy"}}
    {{svg "octicon-check"}}
    {{else}}{{/* SMTP family */}} -
    {{.locale.Tr "admin.config.mailer_protocol"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_protocol"}}
    {{.Mailer.Protocol}}
    -
    {{.locale.Tr "admin.config.mailer_enable_helo"}}
    +
    {{ctx.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"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_smtp_addr"}}
    {{.Mailer.SMTPAddr}}
    -
    {{.locale.Tr "admin.config.mailer_smtp_port"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_smtp_port"}}
    {{.Mailer.SMTPPort}}
    {{end}} -
    {{.locale.Tr "admin.config.mailer_user"}}
    +
    {{ctx.Locale.Tr "admin.config.mailer_user"}}
    {{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}
    -
    {{.locale.Tr "admin.config.send_test_mail"}}
    +
    {{ctx.Locale.Tr "admin.config.send_test_mail"}}
    {{.CsrfTokenHtml}}
    - +
    - +
    {{end}} @@ -246,118 +246,118 @@

    - {{.locale.Tr "admin.config.cache_config"}} + {{ctx.Locale.Tr "admin.config.cache_config"}}

    -
    {{.locale.Tr "admin.config.cache_adapter"}}
    +
    {{ctx.Locale.Tr "admin.config.cache_adapter"}}
    {{.CacheAdapter}}
    {{if eq .CacheAdapter "memory"}} -
    {{.locale.Tr "admin.config.cache_interval"}}
    -
    {{.CacheInterval}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.cache_interval"}}
    +
    {{.CacheInterval}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    {{end}} {{if .CacheConn}} -
    {{.locale.Tr "admin.config.cache_conn"}}
    +
    {{ctx.Locale.Tr "admin.config.cache_conn"}}
    {{.CacheConn}}
    -
    {{.locale.Tr "admin.config.cache_item_ttl"}}
    +
    {{ctx.Locale.Tr "admin.config.cache_item_ttl"}}
    {{.CacheItemTTL}}
    {{end}}

    - {{.locale.Tr "admin.config.session_config"}} + {{ctx.Locale.Tr "admin.config.session_config"}}

    -
    {{.locale.Tr "admin.config.session_provider"}}
    +
    {{ctx.Locale.Tr "admin.config.session_provider"}}
    {{.SessionConfig.Provider}}
    -
    {{.locale.Tr "admin.config.provider_config"}}
    +
    {{ctx.Locale.Tr "admin.config.provider_config"}}
    {{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}
    -
    {{.locale.Tr "admin.config.cookie_name"}}
    +
    {{ctx.Locale.Tr "admin.config.cookie_name"}}
    {{.SessionConfig.CookieName}}
    -
    {{.locale.Tr "admin.config.gc_interval_time"}}
    -
    {{.SessionConfig.Gclifetime}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.session_life_time"}}
    -
    {{.SessionConfig.Maxlifetime}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.https_only"}}
    +
    {{ctx.Locale.Tr "admin.config.gc_interval_time"}}
    +
    {{.SessionConfig.Gclifetime}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.session_life_time"}}
    +
    {{.SessionConfig.Maxlifetime}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.https_only"}}
    {{if .SessionConfig.Secure}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}

    - {{.locale.Tr "admin.config.picture_config"}} + {{ctx.Locale.Tr "admin.config.picture_config"}}

    -
    {{.locale.Tr "admin.config.disable_gravatar"}}
    +
    {{ctx.Locale.Tr "admin.config.disable_gravatar"}}
    - +
    -
    {{.locale.Tr "admin.config.enable_federated_avatar"}}
    +
    {{ctx.Locale.Tr "admin.config.enable_federated_avatar"}}
    - +

    - {{.locale.Tr "admin.config.git_config"}} + {{ctx.Locale.Tr "admin.config.git_config"}}

    -
    {{.locale.Tr "admin.config.git_disable_diff_highlight"}}
    +
    {{ctx.Locale.Tr "admin.config.git_disable_diff_highlight"}}
    {{if .Git.DisableDiffHighlight}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    -
    {{.locale.Tr "admin.config.git_max_diff_lines"}}
    +
    {{ctx.Locale.Tr "admin.config.git_max_diff_lines"}}
    {{.Git.MaxGitDiffLines}}
    -
    {{.locale.Tr "admin.config.git_max_diff_line_characters"}}
    +
    {{ctx.Locale.Tr "admin.config.git_max_diff_line_characters"}}
    {{.Git.MaxGitDiffLineCharacters}}
    -
    {{.locale.Tr "admin.config.git_max_diff_files"}}
    +
    {{ctx.Locale.Tr "admin.config.git_max_diff_files"}}
    {{.Git.MaxGitDiffFiles}}
    -
    {{.locale.Tr "admin.config.git_gc_args"}}
    +
    {{ctx.Locale.Tr "admin.config.git_gc_args"}}
    {{.Git.GCArgs}}
    -
    {{.locale.Tr "admin.config.git_migrate_timeout"}}
    -
    {{.Git.Timeout.Migrate}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.git_mirror_timeout"}}
    -
    {{.Git.Timeout.Mirror}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.git_clone_timeout"}}
    -
    {{.Git.Timeout.Clone}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.git_pull_timeout"}}
    -
    {{.Git.Timeout.Pull}} {{.locale.Tr "tool.raw_seconds"}}
    -
    {{.locale.Tr "admin.config.git_gc_timeout"}}
    -
    {{.Git.Timeout.GC}} {{.locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.git_migrate_timeout"}}
    +
    {{.Git.Timeout.Migrate}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.git_mirror_timeout"}}
    +
    {{.Git.Timeout.Mirror}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.git_clone_timeout"}}
    +
    {{.Git.Timeout.Clone}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.git_pull_timeout"}}
    +
    {{.Git.Timeout.Pull}} {{ctx.Locale.Tr "tool.raw_seconds"}}
    +
    {{ctx.Locale.Tr "admin.config.git_gc_timeout"}}
    +
    {{.Git.Timeout.GC}} {{ctx.Locale.Tr "tool.raw_seconds"}}

    - {{.locale.Tr "admin.config.log_config"}} + {{ctx.Locale.Tr "admin.config.log_config"}}

    {{if .Loggers.xorm.IsEnabled}} -
    {{$.locale.Tr "admin.config.xorm_log_sql"}}
    +
    {{ctx.Locale.Tr "admin.config.xorm_log_sql"}}
    {{if $.LogSQL}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}
    {{end}} {{if .Loggers.access.IsEnabled}} -
    {{$.locale.Tr "admin.config.access_log_template"}}
    +
    {{ctx.Locale.Tr "admin.config.access_log_template"}}
    {{$.AccessLogTemplate}}
    {{end}} {{range $loggerName, $loggerDetail := .Loggers}} -
    {{$.locale.Tr "admin.config.logger_name_fmt" $loggerName}}
    +
    {{ctx.Locale.Tr "admin.config.logger_name_fmt" $loggerName}}
    {{if $loggerDetail.IsEnabled}}
    {{$loggerDetail.EventWriters | JsonUtils.EncodeToString | JsonUtils.PrettyIndent}}
    {{else}} -
    {{$.locale.Tr "admin.config.disabled_logger"}}
    +
    {{ctx.Locale.Tr "admin.config.disabled_logger"}}
    {{end}} {{end}}
    diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl index c1546194351..af30cc06e15 100644 --- a/templates/admin/cron.tmpl +++ b/templates/admin/cron.tmpl @@ -1,7 +1,7 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin monitor")}}

    - {{.locale.Tr "admin.monitor.cron"}} + {{ctx.Locale.Tr "admin.monitor.cron"}}

    @@ -9,24 +9,24 @@ - {{.locale.Tr "admin.monitor.name"}} - {{.locale.Tr "admin.monitor.schedule"}} - {{.locale.Tr "admin.monitor.next"}} - {{.locale.Tr "admin.monitor.previous"}} - {{.locale.Tr "admin.monitor.execute_times"}} - {{.locale.Tr "admin.monitor.last_execution_result"}} + {{ctx.Locale.Tr "admin.monitor.name"}} + {{ctx.Locale.Tr "admin.monitor.schedule"}} + {{ctx.Locale.Tr "admin.monitor.next"}} + {{ctx.Locale.Tr "admin.monitor.previous"}} + {{ctx.Locale.Tr "admin.monitor.execute_times"}} + {{ctx.Locale.Tr "admin.monitor.last_execution_result"}} {{range .Entries}} - - {{$.locale.Tr (printf "admin.dashboard.%s" .Name)}} + + {{ctx.Locale.Tr (printf "admin.dashboard.%s" .Name)}} {{.Spec}} {{DateTime "full" .Next}} {{if gt .Prev.Year 1}}{{DateTime "full" .Prev}}{{else}}-{{end}} {{.ExecTimes}} - {{if eq .Status ""}}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}} + {{if eq .Status ""}}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}} {{end}} diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index 8312fba039a..6cb6c38e15a 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -2,11 +2,11 @@
    {{if .NeedUpdate}}
    -

    {{(.locale.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}

    +

    {{(ctx.Locale.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}

    {{end}}

    - {{.locale.Tr "admin.dashboard.operations"}} + {{ctx.Locale.Tr "admin.dashboard.operations"}}

    @@ -14,56 +14,56 @@ - - + + - - + + - - + + - - + + {{if and (not .SSH.Disabled) (not .SSH.StartBuiltinServer)}} - - + + - - + + {{end}} - - + + - - + + - - + + - - + + - - + + - - + +
    {{.locale.Tr "admin.dashboard.delete_inactive_accounts"}}{{ctx.Locale.Tr "admin.dashboard.delete_inactive_accounts"}}
    {{.locale.Tr "admin.dashboard.delete_repo_archives"}}{{ctx.Locale.Tr "admin.dashboard.delete_repo_archives"}}
    {{.locale.Tr "admin.dashboard.delete_missing_repos"}}{{ctx.Locale.Tr "admin.dashboard.delete_missing_repos"}}
    {{.locale.Tr "admin.dashboard.git_gc_repos"}}{{ctx.Locale.Tr "admin.dashboard.git_gc_repos"}}
    {{.locale.Tr "admin.dashboard.resync_all_sshkeys"}}
    - {{.locale.Tr "admin.dashboard.resync_all_sshkeys.desc"}}
    {{ctx.Locale.Tr "admin.dashboard.resync_all_sshkeys"}}
    + {{ctx.Locale.Tr "admin.dashboard.resync_all_sshkeys.desc"}}
    {{.locale.Tr "admin.dashboard.resync_all_sshprincipals"}}
    - {{.locale.Tr "admin.dashboard.resync_all_sshprincipals.desc"}}
    {{ctx.Locale.Tr "admin.dashboard.resync_all_sshprincipals"}}
    + {{ctx.Locale.Tr "admin.dashboard.resync_all_sshprincipals.desc"}}
    {{.locale.Tr "admin.dashboard.resync_all_hooks"}}{{ctx.Locale.Tr "admin.dashboard.resync_all_hooks"}}
    {{.locale.Tr "admin.dashboard.reinit_missing_repos"}}{{ctx.Locale.Tr "admin.dashboard.reinit_missing_repos"}}
    {{.locale.Tr "admin.dashboard.sync_external_users"}}{{ctx.Locale.Tr "admin.dashboard.sync_external_users"}}
    {{.locale.Tr "admin.dashboard.repo_health_check"}}{{ctx.Locale.Tr "admin.dashboard.repo_health_check"}}
    {{.locale.Tr "admin.dashboard.delete_generated_repository_avatars"}}{{ctx.Locale.Tr "admin.dashboard.delete_generated_repository_avatars"}}
    {{.locale.Tr "admin.dashboard.sync_repo_branches"}}{{ctx.Locale.Tr "admin.dashboard.sync_repo_branches"}}
    @@ -71,69 +71,69 @@

    - {{.locale.Tr "admin.dashboard.system_status"}} + {{ctx.Locale.Tr "admin.dashboard.system_status"}}

    -
    {{.locale.Tr "admin.dashboard.server_uptime"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.server_uptime"}}
    {{.SysStatus.StartTime}}
    -
    {{.locale.Tr "admin.dashboard.current_goroutine"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.current_goroutine"}}
    {{.SysStatus.NumGoroutine}}
    -
    {{.locale.Tr "admin.dashboard.current_memory_usage"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.current_memory_usage"}}
    {{.SysStatus.MemAllocated}}
    -
    {{.locale.Tr "admin.dashboard.total_memory_allocated"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.total_memory_allocated"}}
    {{.SysStatus.MemTotal}}
    -
    {{.locale.Tr "admin.dashboard.memory_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.memory_obtained"}}
    {{.SysStatus.MemSys}}
    -
    {{.locale.Tr "admin.dashboard.pointer_lookup_times"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.pointer_lookup_times"}}
    {{.SysStatus.Lookups}}
    -
    {{.locale.Tr "admin.dashboard.memory_allocate_times"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.memory_allocate_times"}}
    {{.SysStatus.MemMallocs}}
    -
    {{.locale.Tr "admin.dashboard.memory_free_times"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.memory_free_times"}}
    {{.SysStatus.MemFrees}}
    -
    {{.locale.Tr "admin.dashboard.current_heap_usage"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.current_heap_usage"}}
    {{.SysStatus.HeapAlloc}}
    -
    {{.locale.Tr "admin.dashboard.heap_memory_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.heap_memory_obtained"}}
    {{.SysStatus.HeapSys}}
    -
    {{.locale.Tr "admin.dashboard.heap_memory_idle"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.heap_memory_idle"}}
    {{.SysStatus.HeapIdle}}
    -
    {{.locale.Tr "admin.dashboard.heap_memory_in_use"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.heap_memory_in_use"}}
    {{.SysStatus.HeapInuse}}
    -
    {{.locale.Tr "admin.dashboard.heap_memory_released"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.heap_memory_released"}}
    {{.SysStatus.HeapReleased}}
    -
    {{.locale.Tr "admin.dashboard.heap_objects"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.heap_objects"}}
    {{.SysStatus.HeapObjects}}
    -
    {{.locale.Tr "admin.dashboard.bootstrap_stack_usage"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.bootstrap_stack_usage"}}
    {{.SysStatus.StackInuse}}
    -
    {{.locale.Tr "admin.dashboard.stack_memory_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.stack_memory_obtained"}}
    {{.SysStatus.StackSys}}
    -
    {{.locale.Tr "admin.dashboard.mspan_structures_usage"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.mspan_structures_usage"}}
    {{.SysStatus.MSpanInuse}}
    -
    {{.locale.Tr "admin.dashboard.mspan_structures_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.mspan_structures_obtained"}}
    {{.SysStatus.MSpanSys}}
    -
    {{.locale.Tr "admin.dashboard.mcache_structures_usage"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.mcache_structures_usage"}}
    {{.SysStatus.MCacheInuse}}
    -
    {{.locale.Tr "admin.dashboard.mcache_structures_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.mcache_structures_obtained"}}
    {{.SysStatus.MCacheSys}}
    -
    {{.locale.Tr "admin.dashboard.profiling_bucket_hash_table_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.profiling_bucket_hash_table_obtained"}}
    {{.SysStatus.BuckHashSys}}
    -
    {{.locale.Tr "admin.dashboard.gc_metadata_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.gc_metadata_obtained"}}
    {{.SysStatus.GCSys}}
    -
    {{.locale.Tr "admin.dashboard.other_system_allocation_obtained"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.other_system_allocation_obtained"}}
    {{.SysStatus.OtherSys}}
    -
    {{.locale.Tr "admin.dashboard.next_gc_recycle"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.next_gc_recycle"}}
    {{.SysStatus.NextGC}}
    -
    {{.locale.Tr "admin.dashboard.last_gc_time"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.last_gc_time"}}
    {{.SysStatus.LastGC}}
    -
    {{.locale.Tr "admin.dashboard.total_gc_pause"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.total_gc_pause"}}
    {{.SysStatus.PauseTotalNs}}
    -
    {{.locale.Tr "admin.dashboard.last_gc_pause"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.last_gc_pause"}}
    {{.SysStatus.PauseNs}}
    -
    {{.locale.Tr "admin.dashboard.gc_times"}}
    +
    {{ctx.Locale.Tr "admin.dashboard.gc_times"}}
    {{.SysStatus.NumGC}}
    diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index 153877174bf..84afc0585f6 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -1,27 +1,27 @@ {{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin user")}}

    - {{.locale.Tr "admin.emails.email_manage_panel"}} ({{.locale.Tr "admin.total" .Total}}) + {{ctx.Locale.Tr "admin.emails.email_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})

    @@ -31,16 +31,16 @@ - {{.locale.Tr "admin.users.name"}} + {{ctx.Locale.Tr "admin.users.name"}} {{SortArrow "username" "reverseusername" $.SortType false}} - {{.locale.Tr "admin.users.full_name"}} + {{ctx.Locale.Tr "admin.users.full_name"}} - {{.locale.Tr "email"}} + {{ctx.Locale.Tr "email"}} {{SortArrow "email" "reverseemail" $.SortType true}} - {{.locale.Tr "admin.emails.primary"}} - {{.locale.Tr "admin.emails.activated"}} + {{ctx.Locale.Tr "admin.emails.primary"}} + {{ctx.Locale.Tr "admin.emails.activated"}} @@ -72,10 +72,10 @@