diff --git a/.air.toml b/.air.toml index 061008830317..069a88924388 100644 --- a/.air.toml +++ b/.air.toml @@ -5,6 +5,6 @@ tmp_dir = ".air" cmd = "make backend" bin = "gitea" include_ext = ["go", "tmpl"] -exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata"] -include_dir = ["cmd", "models", "modules", "options", "routers", "services", "templates"] +exclude_dir = ["modules/git/tests", "services/gitdiff/testdata", "modules/avatar/testdata", "models/fixtures", "models/migrations/fixtures", "modules/migration/file_format_testdata", "modules/avatar/identicon/testdata"] +include_dir = ["cmd", "models", "modules", "options", "routers", "services"] exclude_regex = ["_test.go$", "_gen.go$"] diff --git a/.drone.yml b/.drone.yml index d349a5f2fc1d..2b5d21ddf967 100644 --- a/.drone.yml +++ b/.drone.yml @@ -551,7 +551,7 @@ steps: # TODO: We should probably build all dependencies into a test image - name: test-e2e - image: mcr.microsoft.com/playwright:v1.28.0-focal + image: mcr.microsoft.com/playwright:v1.29.0-focal commands: - curl -sLO https://go.dev/dl/go1.19.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.19.linux-amd64.tar.gz - groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea @@ -600,7 +600,7 @@ steps: from_secret: crowdin_key - name: update - image: alpine:3.13 + image: alpine:3.17 pull: always commands: - ./build/update-locales.sh @@ -928,10 +928,8 @@ trigger: steps: - name: build-docs - image: plugins/hugo:latest - pull: always + image: golang:1.19 commands: - - apk add --no-cache make bash curl - cd docs - make trans-copy clean build diff --git a/.eslintrc.yaml b/.eslintrc.yaml index 5e5cda7dc84d..32e7ea70c858 100644 --- a/.eslintrc.yaml +++ b/.eslintrc.yaml @@ -255,7 +255,7 @@ rules: no-irregular-whitespace: [2] no-iterator: [2] no-label-var: [2] - no-labels: [0] + no-labels: [0] # handled by no-restricted-syntax no-lone-blocks: [2] no-lonely-if: [0] no-loop-func: [0] @@ -335,7 +335,7 @@ rules: no-void: [2] no-warning-comments: [0] no-whitespace-before-property: [2] - no-with: [0] + no-with: [0] # handled by no-restricted-syntax nonblock-statement-body-position: [2] object-curly-newline: [0] object-curly-spacing: [2, never] @@ -495,7 +495,7 @@ rules: unicorn/prefer-native-coercion-functions: [2] unicorn/prefer-negative-index: [2] unicorn/prefer-node-append: [0] - unicorn/prefer-node-protocol: [0] + unicorn/prefer-node-protocol: [2] unicorn/prefer-node-remove: [0] unicorn/prefer-number-properties: [0] unicorn/prefer-object-from-entries: [2] diff --git a/.golangci.yml b/.golangci.yml index 99133badd9b8..130ad286b507 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,28 +1,28 @@ linters: enable: - - gosimple - - deadcode - - typecheck - - govet - - errcheck - - staticcheck - - unused - - structcheck - - varcheck + - bidichk + # - deadcode # deprecated - https://github.com/golangci/golangci-lint/issues/1841 + - depguard - dupl - #- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. - - gofmt + - errcheck - gocritic - - bidichk - - ineffassign - - revive + # - gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time. + - gofmt - gofumpt - - depguard + - gosimple + - govet + - ineffassign - nakedret - - unconvert - - wastedassign - nolintlint + - revive + - staticcheck + # - structcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841 - stylecheck + - typecheck + - unconvert + - unused + # - varcheck # deprecated - https://github.com/golangci/golangci-lint/issues/1841 + # - wastedassign # disabled - https://github.com/golangci/golangci-lint/issues/2649 enable-all: false disable-all: true fast: false diff --git a/CHANGELOG.md b/CHANGELOG.md index 1150d70081eb..e9ba23b4c493 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,60 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has been added to each release, please refer to the [blog](https://blog.gitea.io). +## [1.17.4](https://github.com/go-gitea/gitea/releases/tag/1.17.4) - 2022-12-21 + +* SECURITY + * Do not allow Ghost access to limited visible user/org (#21849) (#21875) + * Fix package access for admins and inactive users (#21580) (#21592) +* ENHANCEMENTS + * Fix button in branch list, avoid unexpected page jump before restore branch actually done (#21562) (#21927) + * Fix vertical align of committer avatar rendered by email address (#21884) (#21919) + * Fix setting HTTP headers after write (#21833) (#21874) + * Ignore line anchor links with leading zeroes (#21728) (#21777) + * Enable Monaco automaticLayout (#21516) +* BUGFIXES + * Do not list active repositories as unadopted (#22034) (#22167) + * Correctly handle moved files in apply patch (#22118) (#22136) + * Fix condition for is_internal (#22095) (#22131) + * Fix permission check on issue/pull lock (#22114) + * Fix sorting admin user list by last login (#22081) (#22106) + * Workaround for container registry push/pull errors (#21862) (#22069) + * Fix issue/PR numbers (#22037) (#22045) + * Handle empty author names (#21902) (#22028) + * Fix ListBranches to handle empty case (#21921) (#22025) + * Fix enabling partial clones on 1.17 (#21809) + * Prevent panic in doctor command when running default checks (#21791) (#21808) + * Upgrade golang.org/x/crypto (#21792) (#21794) + * Init git module before database migration (#21764) (#21766) + * Set last login when activating account (#21731) (#21754) + * Add HEAD fix to gitea doctor (#21352) (#21751) + * Fix UI language switching bug (#21597) (#21748) + * Remove semver compatible flag and change pypi to an array of test cases (#21708) (#21729) + * Allow local package identifiers for PyPI packages (#21690) (#21726) + * Fix repository adoption on Windows (#21646) (#21651) + * Sync git hooks when config file path changed (#21619) (#21625) + * Added check for disabled Packages (#21540) (#21614) + * Fix `Timestamp.IsZero` (#21593) (#21604) + * Fix issues count bug (#21600) + * Support binary deploy in npm packages (#21589) + * Update milestone counters when issue is deleted (#21459) (#21586) + * SessionUser protection against nil pointer dereference (#21581) + * Case-insensitive NuGet symbol file GUID (#21409) (#21575) + * Suppress `ExternalLoginUserNotExist` error (#21504) (#21572) + * Prevent Authorization header for presigned LFS urls (#21531) (#21569) + * Update binding to fix bugs (#21560) + * Fix generating compare link (#21519) (#21530) + * Ignore error when retrieving changed PR review files (#21487) (#21524) + * Fix incorrect notification commit url (#21479) (#21483) + * Display total commit count in hook message (#21400) (#21481) + * Enforce grouped NuGet search results (#21442) (#21480) + * Return 404 when user is not found on avatar (#21476) (#21477) + * Normalize NuGet package version on upload (#22186) (#22201) +* MISC + * Check for zero time instant in TimeStamp.IsZero() (#22171) (#22173) + * Fix warn in database structs sync (#22111) + * Allow for resolution of NPM registry paths that match upstream (#21568) (#21723) + ## [1.17.3](https://github.com/go-gitea/gitea/releases/tag/v1.17.3) - 2022-10-15 * SECURITY diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 69363c415efc..fbf2a331dd48 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -190,6 +190,8 @@ To maintain understandable code and avoid circular dependencies it is important - **templates:** Golang templates for generating the html output. - **tests/e2e:** End to end tests - **tests/integration:** Integration tests +- **tests/gitea-repositories-meta:** Sample repos used in integration tests. Adding a new repo requires editing `models/fixtures/repositories.yml` and `models/fixtures/repo_unit.yml` to match. +- **tests/gitea-lfs-meta:** Sample LFS objects used in integration tests. Adding a new object requires editing `models/fixtures/lfs_meta_object.yml` to match. - **vendor:** External code that Gitea depends on. ## Documentation @@ -439,7 +441,7 @@ be reviewed by two maintainers and must pass the automatic tests. Code that you contribute should use the standard copyright header: ``` -// Copyright 2022 The Gitea Authors. All rights reserved. +// Copyright The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT ``` diff --git a/Dockerfile b/Dockerfile index f5ba8c6dea98..cb138b994d11 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ #Build stage -FROM golang:1.19-alpine3.16 AS build-env +FROM golang:1.19-alpine3.17 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -26,7 +26,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \ # Begin env-to-ini build RUN go build contrib/environment-to-ini/environment-to-ini.go -FROM alpine:3.16 +FROM alpine:3.17 LABEL maintainer="maintainers@gitea.io" EXPOSE 22 3000 diff --git a/Dockerfile.gitea.dev b/Dockerfile.gitea.dev index 6819247c5398..14bddecf2e6a 100644 --- a/Dockerfile.gitea.dev +++ b/Dockerfile.gitea.dev @@ -1,4 +1,4 @@ -FROM golang:1.19-alpine3.16 +FROM golang:1.19-alpine3.17 ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} diff --git a/Dockerfile.rootless b/Dockerfile.rootless index 8c2b8e98c95a..a43a63fa10c7 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ #Build stage -FROM golang:1.19-alpine3.16 AS build-env +FROM golang:1.19-alpine3.17 AS build-env ARG GOPROXY ENV GOPROXY ${GOPROXY:-direct} @@ -23,7 +23,7 @@ RUN if [ -n "${GITEA_VERSION}" ]; then git checkout "${GITEA_VERSION}"; fi \ # Begin env-to-ini build RUN go build contrib/environment-to-ini/environment-to-ini.go -FROM alpine:3.16 +FROM alpine:3.17 LABEL maintainer="maintainers@gitea.io" EXPOSE 2222 3000 @@ -31,6 +31,7 @@ EXPOSE 2222 3000 RUN apk --no-cache add \ bash \ ca-certificates \ + dumb-init \ gettext \ git \ curl \ @@ -68,6 +69,6 @@ ENV HOME "/var/lib/gitea/git" VOLUME ["/var/lib/gitea", "/etc/gitea"] WORKDIR /var/lib/gitea -ENTRYPOINT ["/usr/local/bin/docker-entrypoint.sh"] +ENTRYPOINT ["/usr/bin/dumb-init", "--", "/usr/local/bin/docker-entrypoint.sh"] CMD [] diff --git a/MAINTAINERS b/MAINTAINERS index d383b8b16414..74196d4bd860 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -44,8 +44,7 @@ Janis Estelmann (@KN4CK3R) Steven Kriegler (@justusbunsi) Jimmy Praet (@jpraet) Leon Hofmeister (@delvh) -silentcode (@silentcodeg) Wim (@42wim) -xinyu (@penlinux) +Xinyu Zhou (@xin-u) Jason Song (@wolfogre) Yarden Shoham (@yardenshoham) diff --git a/Makefile b/Makefile index 4d78944de152..06a0d1c18e22 100644 --- a/Makefile +++ b/Makefile @@ -26,15 +26,15 @@ COMMA := , XGO_VERSION := go-1.19.x AIR_PACKAGE ?= github.com/cosmtrek/air@v1.40.4 -EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.5.0 -ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.1 -GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.47.0 +EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.6.0 +ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.2 +GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.4.0 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.50.1 GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10 MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4 -SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.0 +SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.30.3 XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest -GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.3.0 +GO_LICENSES_PACKAGE ?= github.com/google/go-licenses@v1.5.0 GOVULNCHECK_PACKAGE ?= golang.org/x/vuln/cmd/govulncheck@latest DOCKER_IMAGE ?= gitea/gitea @@ -359,7 +359,7 @@ watch-frontend: node-check node_modules .PHONY: watch-backend watch-backend: go-check - $(GO) run $(AIR_PACKAGE) -c .air.toml + GITEA_RUN_MODE=dev $(GO) run $(AIR_PACKAGE) -c .air.toml .PHONY: test test: test-frontend test-backend diff --git a/build/generate-images.js b/build/generate-images.js index 62ce5244f002..e5744526db61 100755 --- a/build/generate-images.js +++ b/build/generate-images.js @@ -2,7 +2,7 @@ import imageminZopfli from 'imagemin-zopfli'; import {optimize} from 'svgo'; import {fabric} from 'fabric'; -import {readFile, writeFile} from 'fs/promises'; +import {readFile, writeFile} from 'node:fs/promises'; function exit(err) { if (err) console.error(err); diff --git a/build/generate-svg.js b/build/generate-svg.js index c4f3d5a7f9f8..31e65b8a7579 100755 --- a/build/generate-svg.js +++ b/build/generate-svg.js @@ -1,9 +1,9 @@ #!/usr/bin/env node import fastGlob from 'fast-glob'; import {optimize} from 'svgo'; -import {parse} from 'path'; -import {readFile, writeFile, mkdir} from 'fs/promises'; -import {fileURLToPath} from 'url'; +import {parse} from 'node:path'; +import {readFile, writeFile, mkdir} from 'node:fs/promises'; +import {fileURLToPath} from 'node:url'; const glob = (pattern) => fastGlob.sync(pattern, { cwd: fileURLToPath(new URL('..', import.meta.url)), diff --git a/cmd/admin.go b/cmd/admin.go index a47d9ca1095f..7463b21d81ab 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -665,7 +665,7 @@ func runDeleteUser(c *cli.Context) error { } else if c.IsSet("username") { user, err = user_model.GetUserByName(ctx, c.String("username")) } else { - user, err = user_model.GetUserByID(c.Int64("id")) + user, err = user_model.GetUserByID(ctx, c.Int64("id")) } if err != nil { return err @@ -778,6 +778,7 @@ func runRepoSyncReleases(_ *cli.Context) error { func getReleaseCount(id int64) (int64, error) { return repo_model.GetReleaseCountByRepoID( + db.DefaultContext, id, repo_model.FindReleasesOptions{ IncludeTags: true, diff --git a/cmd/dump_repo.go b/cmd/dump_repo.go index 2e78877afed2..b7b9b3ccc734 100644 --- a/cmd/dump_repo.go +++ b/cmd/dump_repo.go @@ -10,13 +10,13 @@ import ( "os" "strings" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/migrations" "github.com/urfave/cli" diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5822dc1e4a85..cec5e8cf0382 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -403,6 +403,9 @@ LOG_SQL = false ; if unset defaults to true ;; ;; Database maximum number of open connections, default is 0 meaning no maximum ;MAX_OPEN_CONNS = 0 +;; +;; Whether execute database models migrations automatically +;AUTO_MIGRATION = true ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -954,6 +957,9 @@ ROUTER = console ;; Don't allow download source archive files from UI ;DISABLE_DOWNLOAD_SOURCE_ARCHIVES = false +;; Allow fork repositories without maximum number limit +;ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT = true + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository.editor] @@ -1033,6 +1039,9 @@ ROUTER = console ;; ;; Add co-authored-by and co-committed-by trailers if committer does not match author ;ADD_CO_COMMITTER_TRAILERS = true +;; +;; In addition to testing patches using the three-way merge method, re-test conflicting patches with git apply +;TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY = false ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -2144,7 +2153,7 @@ ROUTER = console ;[cron.update_checker] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;ENABLED = false +;ENABLED = true ;RUN_AT_START = false ;ENABLE_SUCCESS_NOTICE = false ;SCHEDULE = @every 168h @@ -2378,33 +2387,33 @@ ROUTER = console ;; Path for chunked uploads. Defaults to APP_DATA_PATH + `tmp/package-upload` ;CHUNKED_UPLOAD_PATH = tmp/package-upload ;; -;; Maxmimum count of package versions a single owner can have (`-1` means no limits) +;; Maximum count of package versions a single owner can have (`-1` means no limits) ;LIMIT_TOTAL_OWNER_COUNT = -1 -;; Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_TOTAL_OWNER_SIZE = -1 -;; Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_COMPOSER = -1 -;; Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_CONAN = -1 -;; Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_CONTAINER = -1 -;; Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_GENERIC = -1 -;; Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_HELM = -1 -;; Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_MAVEN = -1 -;; Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_NPM = -1 -;; Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_NUGET = -1 -;; Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_PUB = -1 -;; Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_PYPI = -1 -;; Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_RUBYGEMS = -1 -;; Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +;; Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ;LIMIT_SIZE_VAGRANT = -1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/Makefile b/docs/Makefile index 68afe03e75fe..f47ad4de3ca6 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,6 +2,8 @@ THEME := themes/gitea PUBLIC := public ARCHIVE := https://dl.gitea.io/theme/master.tar.gz +HUGO_PACKAGE := github.com/gohugoio/hugo@v0.82.0 + .PHONY: all all: build @@ -11,19 +13,19 @@ clean: .PHONY: trans-copy trans-copy: - @bash scripts/trans-copy + bash scripts/trans-copy.sh .PHONY: server server: $(THEME) - hugo server + go run $(HUGO_PACKAGE) server .PHONY: build build: $(THEME) - hugo --cleanDestinationDir + go run $(HUGO_PACKAGE) --cleanDestinationDir .PHONY: build-offline build-offline: $(THEME) - hugo --baseURL="/" --cleanDestinationDir + go run $(HUGO_PACKAGE) --baseURL="/" --cleanDestinationDir .PHONY: update update: $(THEME) diff --git a/docs/config.yaml b/docs/config.yaml index 66bd379c0ca4..b80602cb61c3 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,11 +18,13 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.17.3 + version: 1.17.4 minGoVersion: 1.18 goVersion: 1.19 minNodeVersion: 14 search: nav + repo: "https://github.com/go-gitea/gitea" + docContentPath: "docs/content" outputs: home: diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 853f0c67f254..3ccef3130cac 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -112,6 +112,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build - `ALLOW_ADOPTION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to adopt unadopted repositories - `ALLOW_DELETION_OF_UNADOPTED_REPOSITORIES`: **false**: Allow non-admin users to delete unadopted repositories - `DISABLE_DOWNLOAD_SOURCE_ARCHIVES`: **false**: Don't allow download source archive files from UI +- `ALLOW_FORK_WITHOUT_MAXIMUM_LIMIT`: **true**: Allow fork repositories without maximum number limit ### Repository - Editor (`repository.editor`) @@ -134,6 +135,7 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build - `DEFAULT_MERGE_MESSAGE_OFFICIAL_APPROVERS_ONLY`: **true**: In default merge messages only include approvers who are officially allowed to review. - `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES`: **false**: In default squash-merge messages include the commit message of all commits comprising the pull request. - `ADD_CO_COMMITTER_TRAILERS`: **true**: Add co-authored-by and co-committed-by trailers to merge commit messages if committer does not match author. +- `TEST_CONFLICTING_PATCHES_WITH_GIT_APPLY`: **false**: PR patches are tested using a three-way merge method to discover if there are conflicts. If this setting is set to **true**, conflicting patches will be retested using `git apply` - This was the previous behaviour in 1.18 (and earlier) but is somewhat inefficient. Please report if you find that this setting is required. ### Repository - Issue (`repository.issue`) @@ -238,6 +240,10 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `NOTICE_PAGING_NUM`: **25**: Number of notices that are shown in one page. - `ORG_PAGING_NUM`: **50**: Number of organizations that are shown in one page. +### UI - User (`ui.user`) + +- `REPO_PAGING_NUM`: **15**: Number of repos that are shown in one page. + ### UI - Metadata (`ui.meta`) - `AUTHOR`: **Gitea - Git with a cup of tea**: Author meta tag of the homepage. @@ -444,6 +450,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `MAX_OPEN_CONNS` **0**: Database maximum open connections - default is 0, meaning there is no limit. - `MAX_IDLE_CONNS` **2**: Max idle database connections on connection pool, default is 2 - this will be capped to `MAX_OPEN_CONNS`. - `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071). +- `AUTO_MIGRATION` **true**: Whether execute database models migrations automatically. Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their relation to port exhaustion. @@ -1004,7 +1011,7 @@ Default templates for project boards: #### Cron - Check for new Gitea versions ('cron.update_checker') -- `ENABLED`: **false**: Enable service. +- `ENABLED`: **true**: Enable service. - `RUN_AT_START`: **false**: Run tasks at start up time (if ENABLED). - `ENABLE_SUCCESS_NOTICE`: **true**: Set to false to switch off success notices. - `SCHEDULE`: **@every 168h**: Cron syntax for scheduling a work, e.g. `@every 168h`. @@ -1143,7 +1150,7 @@ in this mapping or the filetype using heuristics. ## Time (`time`) - `FORMAT`: Time format to display on UI. i.e. RFC1123 or 2006-01-02 15:04:05 -- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Shanghai/Asia +- `DEFAULT_UI_LOCATION`: Default location of time on the UI, so that we can display correct user's time on UI. i.e. Asia/Shanghai ## Task (`task`) @@ -1179,20 +1186,20 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ENABLED`: **true**: Enable/Disable package registry capabilities - `CHUNKED_UPLOAD_PATH`: **tmp/package-upload**: Path for chunked uploads. Defaults to `APP_DATA_PATH` + `tmp/package-upload` -- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maxmimum count of package versions a single owner can have (`-1` means no limits) -- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maxmimum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_COMPOSER`: **-1**: Maxmimum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_CONAN`: **-1**: Maxmimum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_CONTAINER`: **-1**: Maxmimum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_GENERIC`: **-1**: Maxmimum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_HELM`: **-1**: Maxmimum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_MAVEN`: **-1**: Maxmimum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_NPM`: **-1**: Maxmimum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_NUGET`: **-1**: Maxmimum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_PUB`: **-1**: Maxmimum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_PYPI`: **-1**: Maxmimum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_RUBYGEMS`: **-1**: Maxmimum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) -- `LIMIT_SIZE_VAGRANT`: **-1**: Maxmimum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_TOTAL_OWNER_COUNT`: **-1**: Maximum count of package versions a single owner can have (`-1` means no limits) +- `LIMIT_TOTAL_OWNER_SIZE`: **-1**: Maximum size of packages a single owner can use (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_COMPOSER`: **-1**: Maximum size of a Composer upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONAN`: **-1**: Maximum size of a Conan upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_CONTAINER`: **-1**: Maximum size of a Container upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_GENERIC`: **-1**: Maximum size of a Generic upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_HELM`: **-1**: Maximum size of a Helm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_MAVEN`: **-1**: Maximum size of a Maven upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NPM`: **-1**: Maximum size of a npm upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_NUGET`: **-1**: Maximum size of a NuGet upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PUB`: **-1**: Maximum size of a Pub upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_PYPI`: **-1**: Maximum size of a PyPI upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_RUBYGEMS`: **-1**: Maximum size of a RubyGems upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) +- `LIMIT_SIZE_VAGRANT`: **-1**: Maximum size of a Vagrant upload (`-1` means no limits, format `1000`, `1 MB`, `1 GiB`) ## Mirror (`mirror`) diff --git a/docs/content/doc/installation/from-source.en-us.md b/docs/content/doc/installation/from-source.en-us.md index 01a5e1eaee8d..4394d19203ab 100644 --- a/docs/content/doc/installation/from-source.en-us.md +++ b/docs/content/doc/installation/from-source.en-us.md @@ -145,7 +145,7 @@ launched manually from command line, it can be killed by pressing `Ctrl + C`. Gitea will search for a number of things from the _`CustomPath`_. By default this is the `custom/` directory in the current working directory when running Gitea. It will also -look for its configuration file _`CustomConf`_ in _`CustomPath`_/conf/app.ini`, and will use the +look for its configuration file _`CustomConf`_ in `$(CustomPath)/conf/app.ini`, and will use the current working directory as the relative base path _`AppWorkPath`_ for a number configurable values. Finally the static files will be served from _`StaticRootPath`_ which defaults to the _`AppWorkPath`_. diff --git a/docs/content/doc/installation/with-docker-rootless.en-us.md b/docs/content/doc/installation/with-docker-rootless.en-us.md index 8af3e5b8b66c..028d81ab913e 100644 --- a/docs/content/doc/installation/with-docker-rootless.en-us.md +++ b/docs/content/doc/installation/with-docker-rootless.en-us.md @@ -82,7 +82,7 @@ services: restart: always volumes: - ./data:/var/lib/gitea - - ./config:/etc/gitea + - ./config:/etc/gitea - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: @@ -112,7 +112,7 @@ services: restart: always volumes: - ./data:/var/lib/gitea - - ./config:/etc/gitea + - ./config:/etc/gitea - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: @@ -153,7 +153,7 @@ services: restart: always volumes: - ./data:/var/lib/gitea - - ./config:/etc/gitea + - ./config:/etc/gitea - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: @@ -293,13 +293,13 @@ These environment variables can be passed to the docker container in `docker-com services: server: environment: - - GITEA__mailer__ENABLED=true - - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} - - GITEA__mailer__MAILER_TYPE=smtp - - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} - - GITEA__mailer__IS_TLS_ENABLED=true - - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} - - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" + - GITEA__mailer__ENABLED=true + - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} + - GITEA__mailer__MAILER_TYPE=smtp + - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} + - GITEA__mailer__IS_TLS_ENABLED=true + - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} + - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" ``` To set required TOKEN and SECRET values, consider using Gitea's built-in [generate utility functions](https://docs.gitea.io/en-us/command-line/#generate). diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md index 895f04804e2b..90c6e7b5f3ea 100644 --- a/docs/content/doc/installation/with-docker.en-us.md +++ b/docs/content/doc/installation/with-docker.en-us.md @@ -117,11 +117,11 @@ services: environment: - USER_UID=1000 - USER_GID=1000 -+ - GITEA__database__DB_TYPE=mysql -+ - GITEA__database__HOST=db:3306 -+ - GITEA__database__NAME=gitea -+ - GITEA__database__USER=gitea -+ - GITEA__database__PASSWD=gitea ++ - GITEA__database__DB_TYPE=mysql ++ - GITEA__database__HOST=db:3306 ++ - GITEA__database__NAME=gitea ++ - GITEA__database__USER=gitea ++ - GITEA__database__PASSWD=gitea restart: always networks: - gitea @@ -168,11 +168,11 @@ services: environment: - USER_UID=1000 - USER_GID=1000 -+ - GITEA__database__DB_TYPE=postgres -+ - GITEA__database__HOST=db:5432 -+ - GITEA__database__NAME=gitea -+ - GITEA__database__USER=gitea -+ - GITEA__database__PASSWD=gitea ++ - GITEA__database__DB_TYPE=postgres ++ - GITEA__database__HOST=db:5432 ++ - GITEA__database__NAME=gitea ++ - GITEA__database__USER=gitea ++ - GITEA__database__PASSWD=gitea restart: always networks: - gitea @@ -225,8 +225,8 @@ services: networks: - gitea volumes: -- - ./gitea:/data -+ - gitea:/data +- - ./gitea:/data ++ - gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: @@ -294,13 +294,13 @@ These environment variables can be passed to the docker container in `docker-com services: server: environment: - - GITEA__mailer__ENABLED=true - - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} - - GITEA__mailer__MAILER_TYPE=smtp - - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} - - GITEA__mailer__IS_TLS_ENABLED=true - - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} - - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" + - GITEA__mailer__ENABLED=true + - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} + - GITEA__mailer__MAILER_TYPE=smtp + - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} + - GITEA__mailer__IS_TLS_ENABLED=true + - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} + - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" ``` Gitea will generate new secrets/tokens for every new installation automatically and write them into the app.ini. If you want to set the secrets/tokens manually, you can use the following docker commands to use of Gitea's built-in [generate utility functions](https://docs.gitea.io/en-us/command-line/#generate). Do not lose/change your SECRET_KEY after the installation, otherwise the encrypted data can not be decrypted anymore. diff --git a/docs/content/doc/installation/with-docker.zh-cn.md b/docs/content/doc/installation/with-docker.zh-cn.md index 2c63c9d4e1e4..cae28c70b866 100644 --- a/docs/content/doc/installation/with-docker.zh-cn.md +++ b/docs/content/doc/installation/with-docker.zh-cn.md @@ -103,11 +103,11 @@ services: environment: - USER_UID=1000 - USER_GID=1000 -+ - GITEA__database__DB_TYPE=mysql -+ - GITEA__database__HOST=db:3306 -+ - GITEA__database__NAME=gitea -+ - GITEA__database__USER=gitea -+ - GITEA__database__PASSWD=gitea ++ - GITEA__database__DB_TYPE=mysql ++ - GITEA__database__HOST=db:3306 ++ - GITEA__database__NAME=gitea ++ - GITEA__database__USER=gitea ++ - GITEA__database__PASSWD=gitea restart: always networks: - gitea @@ -153,11 +153,11 @@ services: environment: - USER_UID=1000 - USER_GID=1000 -+ - GITEA__database__DB_TYPE=postgres -+ - GITEA__database__HOST=db:5432 -+ - GITEA__database__NAME=gitea -+ - GITEA__database__USER=gitea -+ - GITEA__database__PASSWD=gitea ++ - GITEA__database__DB_TYPE=postgres ++ - GITEA__database__HOST=db:5432 ++ - GITEA__database__NAME=gitea ++ - GITEA__database__USER=gitea ++ - GITEA__database__PASSWD=gitea restart: always networks: - gitea @@ -207,8 +207,8 @@ services: networks: - gitea volumes: -- - ./gitea:/data -+ - gitea:/data +- - ./gitea:/data ++ - gitea:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: @@ -285,13 +285,13 @@ docker-compose up -d services: server: environment: - - GITEA__mailer__ENABLED=true - - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} - - GITEA__mailer__MAILER_TYPE=smtp - - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} - - GITEA__mailer__IS_TLS_ENABLED=true - - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} - - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" + - GITEA__mailer__ENABLED=true + - GITEA__mailer__FROM=${GITEA__mailer__FROM:?GITEA__mailer__FROM not set} + - GITEA__mailer__MAILER_TYPE=smtp + - GITEA__mailer__HOST=${GITEA__mailer__HOST:?GITEA__mailer__HOST not set} + - GITEA__mailer__IS_TLS_ENABLED=true + - GITEA__mailer__USER=${GITEA__mailer__USER:-apikey} + - GITEA__mailer__PASSWD="""${GITEA__mailer__PASSWD:?GITEA__mailer__PASSWD not set}""" ``` Gitea 将为每次新安装自动生成新的 `SECRET_KEY` 并将它们写入 `app.ini`。 如果您想手动设置 `SECRET_KEY`,您可以使用以下 docker 命令来使用 Gitea 内置的[方法](https://docs.gitea.io/en-us/command-line/#generate)生成 `SECRET_KEY`。 安装后请妥善保管您的 `SECRET_KEY`,如若丢失则无法解密已加密的数据。 diff --git a/docs/content/doc/packages/overview.en-us.md b/docs/content/doc/packages/overview.en-us.md index 0abb054b0f1b..239ba6834e88 100644 --- a/docs/content/doc/packages/overview.en-us.md +++ b/docs/content/doc/packages/overview.en-us.md @@ -32,7 +32,7 @@ The following package managers are currently supported: | [Generic]({{< relref "doc/packages/generic.en-us.md" >}}) | - | any HTTP client | | [Helm]({{< relref "doc/packages/helm.en-us.md" >}}) | - | any HTTP client, `cm-push` | | [Maven]({{< relref "doc/packages/maven.en-us.md" >}}) | Java | `mvn`, `gradle` | -| [npm]({{< relref "doc/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn` | +| [npm]({{< relref "doc/packages/npm.en-us.md" >}}) | JavaScript | `npm`, `yarn`, `pnpm` | | [NuGet]({{< relref "doc/packages/nuget.en-us.md" >}}) | .NET | `nuget` | | [Pub]({{< relref "doc/packages/pub.en-us.md" >}}) | Dart | `dart`, `flutter` | | [PyPI]({{< relref "doc/packages/pypi.en-us.md" >}}) | Python | `pip`, `twine` | diff --git a/docs/content/doc/secrets/overview.en-us.md b/docs/content/doc/secrets/overview.en-us.md new file mode 100644 index 000000000000..1a88d6cfbcc6 --- /dev/null +++ b/docs/content/doc/secrets/overview.en-us.md @@ -0,0 +1,36 @@ +--- +date: "2022-12-19T21:26:00+08:00" +title: "Encrypted secrets" +slug: "secrets/overview" +draft: false +toc: false +menu: + sidebar: + parent: "secrets" + name: "Overview" + weight: 1 + identifier: "overview" +--- + +# Encrypted secrets + +Encrypted secrets allow you to store sensitive information in your organization or repository. +Secrets are available on Gitea 1.19+. + +# Naming your secrets + +The following rules apply to secret names: + +Secret names can only contain alphanumeric characters (`[a-z]`, `[A-Z]`, `[0-9]`) or underscores (`_`). Spaces are not allowed. + +Secret names must not start with the `GITHUB_` and `GITEA_` prefix. + +Secret names must not start with a number. + +Secret names are not case-sensitive. + +Secret names must be unique at the level they are created at. + +For example, a secret created at the repository level must have a unique name in that repository, and a secret created at the organization level must have a unique name at that level. + +If a secret with the same name exists at multiple levels, the secret at the lowest level takes precedence. For example, if an organization-level secret has the same name as a repository-level secret, then the repository-level secret takes precedence. diff --git a/docs/scripts/trans-copy b/docs/scripts/trans-copy.sh similarity index 93% rename from docs/scripts/trans-copy rename to docs/scripts/trans-copy.sh index 773219288553..7374ab9e7311 100755 --- a/docs/scripts/trans-copy +++ b/docs/scripts/trans-copy.sh @@ -26,7 +26,6 @@ for SOURCE in $(find ${ROOT}/content -type f -iname *.en-us.md); do DEST="${SOURCE%.en-us.md}.${LOCALE}.md" if [[ ! -f ${DEST} ]]; then - echo "Creating fallback for ${DEST#${ROOT}/content/}" cp ${SOURCE} ${DEST} sed -i.bak "s/en\-us/${LOCALE}/g" ${DEST} rm ${DEST}.bak diff --git a/go.mod b/go.mod index ca8c79c68900..2c53867e1e98 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module code.gitea.io/gitea go 1.18 require ( - code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b + code.gitea.io/gitea-vet v0.2.2 code.gitea.io/sdk/gitea v0.15.1 codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570 gitea.com/go-chi/binding v0.0.0-20221013104517-b29891619681 @@ -15,8 +15,8 @@ require ( github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 github.com/NYTimes/gziphandler v1.1.1 github.com/PuerkitoBio/goquery v1.8.0 - github.com/alecthomas/chroma/v2 v2.3.0 - github.com/blevesearch/bleve/v2 v2.3.4 + github.com/alecthomas/chroma/v2 v2.4.0 + github.com/blevesearch/bleve/v2 v2.3.5 github.com/buildkite/terminal-to-html/v3 v3.7.0 github.com/caddyserver/certmagic v0.17.2 github.com/chi-middleware/proxy v1.1.1 @@ -88,6 +88,7 @@ require ( github.com/unrolled/render v1.5.0 github.com/urfave/cli v1.22.10 github.com/xanzy/go-gitlab v0.73.1 + github.com/xeipuuv/gojsonschema v1.2.0 github.com/yohcop/openid-go v1.0.0 github.com/yuin/goldmark v1.5.2 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87 @@ -105,8 +106,8 @@ require ( gopkg.in/yaml.v3 v3.0.1 mvdan.cc/xurls/v2 v2.4.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 - xorm.io/builder v0.3.11 - xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f + xorm.io/builder v0.3.12 + xorm.io/xorm v1.3.3-0.20221209153726-f1bfc5ce9830 ) require ( @@ -128,21 +129,21 @@ require ( github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect github.com/bits-and-blooms/bitset v1.3.3 // indirect - github.com/blevesearch/bleve_index_api v1.0.3 // indirect - github.com/blevesearch/geo v0.1.14 // indirect + github.com/blevesearch/bleve_index_api v1.0.4 // indirect + github.com/blevesearch/geo v0.1.15 // 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.2 // indirect + github.com/blevesearch/scorch_segment_api/v2 v2.1.3 // indirect github.com/blevesearch/segment v0.9.0 // indirect github.com/blevesearch/snowballstem v0.9.0 // indirect github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect - github.com/blevesearch/vellum v1.0.8 // indirect - github.com/blevesearch/zapx/v11 v11.3.5 // indirect - github.com/blevesearch/zapx/v12 v12.3.5 // indirect - github.com/blevesearch/zapx/v13 v13.3.5 // indirect - github.com/blevesearch/zapx/v14 v14.3.5 // indirect - github.com/blevesearch/zapx/v15 v15.3.5 // indirect + github.com/blevesearch/vellum v1.0.9 // indirect + github.com/blevesearch/zapx/v11 v11.3.6 // indirect + github.com/blevesearch/zapx/v12 v12.3.6 // indirect + github.com/blevesearch/zapx/v13 v13.3.6 // indirect + github.com/blevesearch/zapx/v14 v14.3.6 // indirect + github.com/blevesearch/zapx/v15 v15.3.6 // indirect github.com/boombuler/barcode v1.0.1 // indirect github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect @@ -182,7 +183,7 @@ require ( github.com/go-openapi/strfmt v0.21.3 // indirect github.com/go-openapi/swag v0.22.3 // indirect github.com/go-openapi/validate v0.22.0 // indirect - github.com/goccy/go-json v0.9.11 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect github.com/golang-sql/sqlexp v0.1.0 // indirect @@ -266,6 +267,8 @@ require ( github.com/valyala/fastjson v1.6.3 // indirect github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.2 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect go.etcd.io/bbolt v1.3.6 // indirect @@ -302,6 +305,8 @@ replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142 replace github.com/satori/go.uuid v1.2.0 => github.com/gofrs/uuid v4.2.0+incompatible +replace github.com/blevesearch/zapx/v15 v15.3.6 => github.com/zeripath/zapx/v15 v15.3.6-alignment-fix + exclude github.com/gofrs/uuid v3.2.0+incompatible exclude github.com/gofrs/uuid v4.0.0+incompatible diff --git a/go.sum b/go.sum index d6748eae34de..6388c2b18322 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= -code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b h1:uv9a8eGSdQ8Dr4HyUcuHFfDsk/QuwO+wf+Y99RYdxY0= -code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= +code.gitea.io/gitea-vet v0.2.2 h1:TEOV/Glf38iGmKzKP0EB++Z5OSL4zGg3RrAvlwaMuvk= +code.gitea.io/gitea-vet v0.2.2/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.11.3/go.mod h1:z3uwDV/b9Ls47NGukYM9XhnHtqPh/J+t40lsUrR6JDY= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= @@ -149,7 +149,6 @@ github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo= github.com/RoaringBitmap/roaring v0.7.1/go.mod h1:jdT9ykXwHFNdJbEtxePexlFYH9LXucApeS0/+/g+p1I= -github.com/RoaringBitmap/roaring v0.9.4/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA= github.com/RoaringBitmap/roaring v1.2.1 h1:58/LJlg/81wfEHd5L9qsHduznOIhyv4qb1yWcSvVq9A= github.com/RoaringBitmap/roaring v1.2.1/go.mod h1:icnadbWcNyfEHlYdr+tDlOTih1Bf/h+rzPpv4sbomAA= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= @@ -160,9 +159,10 @@ github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/assert/v2 v2.2.0 h1:f6L/b7KE2bfA+9O4FL3CM/xJccDEwPVYd5fALBiuwvw= github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= -github.com/alecthomas/chroma/v2 v2.3.0 h1:83xfxrnjv8eK+Cf8qZDzNo3PPF9IbTWHs7z28GY6D0U= -github.com/alecthomas/chroma/v2 v2.3.0/go.mod h1:mZxeWZlxP2Dy+/8cBob2PYd8O2DwNAzave5AY7A2eQw= +github.com/alecthomas/chroma/v2 v2.4.0 h1:Loe2ZjT5x3q1bcWwemqyqEi8p11/IV/ncFCeLYDpWC4= +github.com/alecthomas/chroma/v2 v2.4.0/go.mod h1:6kHzqF5O6FUSJzBXW7fXELjb+e+7OXW4UpoPqMO7IBQ= github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE= @@ -225,52 +225,47 @@ github.com/bits-and-blooms/bitset v1.3.3/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edY github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blevesearch/bleve/v2 v2.0.5/go.mod h1:ZjWibgnbRX33c+vBRgla9QhPb4QOjD6fdVJ+R1Bk8LM= -github.com/blevesearch/bleve/v2 v2.3.4 h1:SSb7/cwGzo85LWX1jchIsXM8ZiNNMX3shT5lROM63ew= -github.com/blevesearch/bleve/v2 v2.3.4/go.mod h1:Ot0zYum8XQRfPcwhae8bZmNyYubynsoMjVvl1jPqL30= +github.com/blevesearch/bleve/v2 v2.3.5 h1:1wuR7eB8Fk9UaCaBUfnQt5V7zIpi4VDok9ExN7Rl+/8= +github.com/blevesearch/bleve/v2 v2.3.5/go.mod h1:FneKGHMRrCLrp4X9+iy3wlBqgM2ALucg7bp8jUuAi/s= github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= -github.com/blevesearch/bleve_index_api v1.0.3 h1:DDSWaPXOZZJ2BB73ZTWjKxydAugjwywcqU+91AAqcAg= github.com/blevesearch/bleve_index_api v1.0.3/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= -github.com/blevesearch/geo v0.1.13/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc= -github.com/blevesearch/geo v0.1.14 h1:TTDpJN6l9ck/cUYbXSn4aCElNls0Whe44rcQKsB7EfU= -github.com/blevesearch/geo v0.1.14/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc= -github.com/blevesearch/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:9eJDeqxJ3E7WnLebQUlPD7ZjSce7AnDb9vjGmMCbD0A= +github.com/blevesearch/bleve_index_api v1.0.4 h1:mtlzsyJjMIlDngqqB1mq8kPryUMIuEVVbRbJHOWEexU= +github.com/blevesearch/bleve_index_api v1.0.4/go.mod h1:YXMDwaXFFXwncRS8UobWs7nvo0DmusriM1nztTlj1ms= +github.com/blevesearch/geo v0.1.15 h1:0NybEduqE5fduFRYiUKF0uqybAIFKXYjkBdXKYn7oA4= +github.com/blevesearch/geo v0.1.15/go.mod h1:cRIvqCdk3cgMhGeHNNe6yPzb+w56otxbfo1FBJfR2Pc= github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= -github.com/blevesearch/goleveldb v1.0.1/go.mod h1:WrU8ltZbIp0wAoig/MHbrPCXSOLpe79nz5lv5nqfYrQ= github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA= github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCDPWmc= github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs= github.com/blevesearch/scorch_segment_api/v2 v2.0.1/go.mod h1:lq7yK2jQy1yQjtjTfU931aVqz7pYxEudHaDwOt1tXfU= -github.com/blevesearch/scorch_segment_api/v2 v2.1.2 h1:TAte9VZLWda5WAVlZTTZ+GCzEHqGJb4iB2aiZSA6Iv8= -github.com/blevesearch/scorch_segment_api/v2 v2.1.2/go.mod h1:rvoQXZGq8drq7vXbNeyiRzdEOwZkjkiYGf1822i6CRA= +github.com/blevesearch/scorch_segment_api/v2 v2.1.3 h1:2UzpR2dR5DvSZk8tVJkcQ7D5xhoK/UBelYw8ttBHrRQ= +github.com/blevesearch/scorch_segment_api/v2 v2.1.3/go.mod h1:eZrfp1y+lUh+DzFjUcTBUSnKGuunyFIpBIvqYVzJfvc= github.com/blevesearch/segment v0.9.0 h1:5lG7yBCx98or7gK2cHMKPukPZ/31Kag7nONpoBt22Ac= github.com/blevesearch/segment v0.9.0/go.mod h1:9PfHYUdQCgHktBgvtUOF4x+pc4/l8rdH0u5spnW85UQ= -github.com/blevesearch/snowball v0.6.1/go.mod h1:ZF0IBg5vgpeoUhnMza2v0A/z8m1cWPlwhke08LpNusg= github.com/blevesearch/snowballstem v0.9.0 h1:lMQ189YspGP6sXvZQ4WZ+MLawfV8wOmPoD/iWeNXm8s= github.com/blevesearch/snowballstem v0.9.0/go.mod h1:PivSj3JMc8WuaFkTSRDW2SlrulNWPl4ABg1tC/hlgLs= github.com/blevesearch/upsidedown_store_api v1.0.1 h1:1SYRwyoFLwG3sj0ed89RLtM15amfX2pXlYbFOnF8zNU= github.com/blevesearch/upsidedown_store_api v1.0.1/go.mod h1:MQDVGpHZrpe3Uy26zJBf/a8h0FZY6xJbthIMm8myH2Q= github.com/blevesearch/vellum v1.0.3/go.mod h1:2u5ax02KeDuNWu4/C+hVQMD6uLN4txH1JbtpaDNLJRo= github.com/blevesearch/vellum v1.0.4/go.mod h1:cMhywHI0de50f7Nj42YgvyD6bFJ2WkNRvNBlNMrEVgY= -github.com/blevesearch/vellum v1.0.8 h1:iMGh4lfxza4BnWO/UJTMPlI3HsK9YawjPv+TteVa9ck= -github.com/blevesearch/vellum v1.0.8/go.mod h1:+cpRi/tqq49xUYSQN2P7A5zNSNrS+MscLeeaZ3J46UA= +github.com/blevesearch/vellum v1.0.9 h1:PL+NWVk3dDGPCV0hoDu9XLLJgqU4E5s/dOeEJByQ2uQ= +github.com/blevesearch/vellum v1.0.9/go.mod h1:ul1oT0FhSMDIExNjIxHqJoGpVrBpKCdgDQNxfqgJt7k= github.com/blevesearch/zapx/v11 v11.2.0/go.mod h1:gN/a0alGw1FZt/YGTo1G6Z6XpDkeOfujX5exY9sCQQM= -github.com/blevesearch/zapx/v11 v11.3.5 h1:eBQWQ7huA+mzm0sAGnZDwgGGli7S45EO+N+ObFWssbI= -github.com/blevesearch/zapx/v11 v11.3.5/go.mod h1:5UdIa/HRMdeRCiLQOyFESsnqBGiip7vQmYReA9toevU= +github.com/blevesearch/zapx/v11 v11.3.6 h1:50jET4HUJ6eCqGxdhUt+mjybMvEX2MWyqLGtCx3yUgc= +github.com/blevesearch/zapx/v11 v11.3.6/go.mod h1:B0CzJRj/pS7hJIroflRtFsa9mRHpMSucSgre0FVINns= github.com/blevesearch/zapx/v12 v12.2.0/go.mod h1:fdjwvCwWWwJW/EYTYGtAp3gBA0geCYGLcVTtJEZnY6A= -github.com/blevesearch/zapx/v12 v12.3.5 h1:5pX2hU+R1aZihT7ac1dNWh1n4wqkIM9pZzWp0ANED9s= -github.com/blevesearch/zapx/v12 v12.3.5/go.mod h1:ANcthYRZQycpbRut/6ArF5gP5HxQyJqiFcuJCBju/ss= +github.com/blevesearch/zapx/v12 v12.3.6 h1:G304NHBLgQeZ+IHK/XRCM0nhHqAts8MEvHI6LhoDNM4= +github.com/blevesearch/zapx/v12 v12.3.6/go.mod h1:iYi7tIKpauwU5os5wTxJITixr5Km21Hl365otMwdaP0= github.com/blevesearch/zapx/v13 v13.2.0/go.mod h1:o5rAy/lRS5JpAbITdrOHBS/TugWYbkcYZTz6VfEinAQ= -github.com/blevesearch/zapx/v13 v13.3.5 h1:eJ3gbD+Nu8p36/O6lhfdvWQ4pxsGYSuTOBrLLPVWJ74= -github.com/blevesearch/zapx/v13 v13.3.5/go.mod h1:FV+dRnScFgKnRDIp08RQL4JhVXt1x2HE3AOzqYa6fjo= +github.com/blevesearch/zapx/v13 v13.3.6 h1:vavltQHNdjQezhLZs5nIakf+w/uOa1oqZxB58Jy/3Ig= +github.com/blevesearch/zapx/v13 v13.3.6/go.mod h1:X+FsTwCU8qOHtK0d/ArvbOH7qiIgViSQ1GQvcR6LSkI= github.com/blevesearch/zapx/v14 v14.2.0/go.mod h1:GNgZusc1p4ot040cBQMRGEZobvwjCquiEKYh1xLFK9g= -github.com/blevesearch/zapx/v14 v14.3.5 h1:hEvVjZaagFCvOUJrlFQ6/Z6Jjy0opM3g7TMEo58TwP4= -github.com/blevesearch/zapx/v14 v14.3.5/go.mod h1:954A/eKFb+pg/ncIYWLWCKY+mIjReM9FGTGIO2Wu1cU= +github.com/blevesearch/zapx/v14 v14.3.6 h1:b9lub7TvcwUyJxK/cQtnN79abngKxsI7zMZnICU0WhE= +github.com/blevesearch/zapx/v14 v14.3.6/go.mod h1:9X8W3XoikagU0rwcTqwZho7p9cC7m7zhPZO94S4wUvM= github.com/blevesearch/zapx/v15 v15.2.0/go.mod h1:MmQceLpWfME4n1WrBFIwplhWmaQbQqLQARpaKUEOs/A= -github.com/blevesearch/zapx/v15 v15.3.5 h1:NVD0qq8vRk66ImJn1KloXT5ckqPDUZT7VbVJs9jKlac= -github.com/blevesearch/zapx/v15 v15.3.5/go.mod h1:QMUh2hXCaYIWFKPYGavq/Iga2zbHWZ9DZAa9uFbWyvg= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/boombuler/barcode v1.0.1 h1:NDBbPmhS+EqABEs5Kg3n/5ZNjy73Pz7SIV+KCeqyXcs= github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= @@ -361,7 +356,6 @@ github.com/couchbase/goutils v0.0.0-20201030094643-5e82bb967e67/go.mod h1:BQwMFl github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 h1:4KDlx3vjalrHD/EfsjCpV91HNX3JPaIqRtt83zZ7x+Y= github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/moss v0.1.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= -github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs= github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -598,8 +592,8 @@ github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJA github.com/goccy/go-json v0.8.1/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.5/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.9.11 h1:/pAaQDLHEoCq/5FFmSKBswWmK6H0e8g4159Kc/X/nqk= -github.com/goccy/go-json v0.9.11/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= @@ -830,6 +824,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/huandu/xstrings v1.0.0/go.mod h1:4qWG/gcEcfX4z/mBDHJ++3ReCw9ibxbsNJbcucJdbSo= github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= @@ -1466,6 +1461,12 @@ github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+ github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= @@ -1487,6 +1488,8 @@ github.com/yuin/goldmark-highlighting/v2 v2.0.0-20220924101305-151362477c87/go.m github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0= github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= +github.com/zeripath/zapx/v15 v15.3.6-alignment-fix h1:fKZ9OxEDoJKgM0KBXRbSb5IgKUEXis6C3zEIiMtzzQ0= +github.com/zeripath/zapx/v15 v15.3.6-alignment-fix/go.mod h1:5DbhhDTGtuQSns1tS2aJxJLPc91boXCvjOMeCLD1saM= github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -2377,7 +2380,7 @@ sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs= strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY= xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/builder v0.3.11 h1:naLkJitGyYW7ZZdncsh/JW+HF4HshmvTHTyUyPwJS00= -xorm.io/builder v0.3.11/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f h1:3NvNsM4lnttTsHpk8ODHqrwN1MCEjsO3bD/rpd8A47k= -xorm.io/xorm v1.3.2-0.20220714055524-c3bce556200f/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw= +xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM= +xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= +xorm.io/xorm v1.3.3-0.20221209153726-f1bfc5ce9830 h1:ohaHCvT7ocSDkTEa2/2z0BXfINYlHm/Z7IzN7MeXQlM= +xorm.io/xorm v1.3.3-0.20221209153726-f1bfc5ce9830/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw= diff --git a/models/activities/action.go b/models/activities/action.go index 80c117dc9572..4baedbfe124b 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -114,12 +114,12 @@ func (a *Action) GetOpType() ActionType { } // LoadActUser loads a.ActUser -func (a *Action) LoadActUser() { +func (a *Action) LoadActUser(ctx context.Context) { if a.ActUser != nil { return } var err error - a.ActUser, err = user_model.GetUserByID(a.ActUserID) + a.ActUser, err = user_model.GetUserByID(ctx, a.ActUserID) if err == nil { return } else if user_model.IsErrUserNotExist(err) { @@ -129,12 +129,12 @@ func (a *Action) LoadActUser() { } } -func (a *Action) loadRepo() { +func (a *Action) loadRepo(ctx context.Context) { if a.Repo != nil { return } var err error - a.Repo, err = repo_model.GetRepositoryByID(a.RepoID) + a.Repo, err = repo_model.GetRepositoryByID(ctx, a.RepoID) if err != nil { log.Error("repo_model.GetRepositoryByID(%d): %v", a.RepoID, err) } @@ -142,13 +142,13 @@ func (a *Action) loadRepo() { // GetActFullName gets the action's user full name. func (a *Action) GetActFullName() string { - a.LoadActUser() + a.LoadActUser(db.DefaultContext) return a.ActUser.FullName } // GetActUserName gets the action's user name. func (a *Action) GetActUserName() string { - a.LoadActUser() + a.LoadActUser(db.DefaultContext) return a.ActUser.Name } @@ -179,7 +179,7 @@ func (a *Action) GetDisplayNameTitle() string { // GetRepoUserName returns the name of the action repository owner. func (a *Action) GetRepoUserName() string { - a.loadRepo() + a.loadRepo(db.DefaultContext) return a.Repo.OwnerName } @@ -191,7 +191,7 @@ func (a *Action) ShortRepoUserName() string { // GetRepoName returns the name of the action repository. func (a *Action) GetRepoName() string { - a.loadRepo() + a.loadRepo(db.DefaultContext) return a.Repo.Name } @@ -272,7 +272,7 @@ func (a *Action) GetRefLink() string { return a.GetRepoLink() + "/src/branch/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.BranchPrefix)) case strings.HasPrefix(a.RefName, git.TagPrefix): return a.GetRepoLink() + "/src/tag/" + util.PathEscapeSegments(strings.TrimPrefix(a.RefName, git.TagPrefix)) - case len(a.RefName) == 40 && git.IsValidSHAPattern(a.RefName): + case len(a.RefName) == git.SHAFullLength && git.IsValidSHAPattern(a.RefName): return a.GetRepoLink() + "/src/commit/" + a.RefName default: // FIXME: we will just assume it's a branch - this was the old way - at some point we may want to enforce that there is always a ref here. @@ -379,7 +379,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { cond := builder.NewCond() if opts.RequestedTeam != nil && opts.RequestedUser == nil { - org, err := user_model.GetUserByID(opts.RequestedTeam.OrgID) + org, err := user_model.GetUserByID(db.DefaultContext, opts.RequestedTeam.OrgID) if err != nil { return nil, err } @@ -489,7 +489,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error { } if repoChanged { - act.loadRepo() + act.loadRepo(ctx) repo = act.Repo // check repo owner exist. @@ -514,7 +514,7 @@ func NotifyWatchers(ctx context.Context, actions ...*Action) error { permIssue = make([]bool, len(watchers)) permPR = make([]bool, len(watchers)) for i, watcher := range watchers { - user, err := user_model.GetUserByIDCtx(ctx, watcher.UserID) + user, err := user_model.GetUserByID(ctx, watcher.UserID) if err != nil { permCode[i] = false permIssue[i] = false diff --git a/models/activities/action_list.go b/models/activities/action_list.go index 0979434f7646..3d74397c6929 100644 --- a/models/activities/action_list.go +++ b/models/activities/action_list.go @@ -81,7 +81,7 @@ func (actions ActionList) loadRepoOwner(ctx context.Context, userMap map[int64]* } repoOwner, ok := userMap[action.Repo.OwnerID] if !ok { - repoOwner, err = user_model.GetUserByIDCtx(ctx, action.Repo.OwnerID) + repoOwner, err = user_model.GetUserByID(ctx, action.Repo.OwnerID) if err != nil { if user_model.IsErrUserNotExist(err) { continue diff --git a/models/activities/notification.go b/models/activities/notification.go index 9aa4b87628b1..d20a53a41d86 100644 --- a/models/activities/notification.go +++ b/models/activities/notification.go @@ -245,7 +245,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n // notify for userID := range toNotify { issue.Repo.Units = nil - user, err := user_model.GetUserByIDCtx(ctx, userID) + user, err := user_model.GetUserByID(ctx, userID) if err != nil { if user_model.IsErrUserNotExist(err) { continue @@ -388,7 +388,7 @@ func (n *Notification) LoadAttributes(ctx context.Context) (err error) { func (n *Notification) loadRepo(ctx context.Context) (err error) { if n.Repository == nil { - n.Repository, err = repo_model.GetRepositoryByIDCtx(ctx, n.RepoID) + n.Repository, err = repo_model.GetRepositoryByID(ctx, n.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %w", n.RepoID, err) } @@ -425,7 +425,7 @@ func (n *Notification) loadComment(ctx context.Context) (err error) { func (n *Notification) loadUser(ctx context.Context) (err error) { if n.User == nil { - n.User, err = user_model.GetUserByIDCtx(ctx, n.UserID) + n.User, err = user_model.GetUserByID(ctx, n.UserID) if err != nil { return fmt.Errorf("getUserByID [%d]: %w", n.UserID, err) } diff --git a/models/asymkey/gpg_key_commit_verification.go b/models/asymkey/gpg_key_commit_verification.go index 1cdd748e35af..1b88fb8b1387 100644 --- a/models/asymkey/gpg_key_commit_verification.go +++ b/models/asymkey/gpg_key_commit_verification.go @@ -426,7 +426,7 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *use Email: email, } if key.OwnerID != 0 { - owner, err := user_model.GetUserByID(key.OwnerID) + owner, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID) if err == nil { signer = owner } else if !user_model.IsErrUserNotExist(err) { diff --git a/models/auth/token.go b/models/auth/token.go index 25702532557c..feb32c616c14 100644 --- a/models/auth/token.go +++ b/models/auth/token.go @@ -6,18 +6,17 @@ package auth import ( "crypto/subtle" + "encoding/hex" "fmt" "time" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" chi_session "gitea.com/go-chi/session" "xorm.io/xorm" - gouuid "github.com/google/uuid" lru "github.com/hashicorp/golang-lru" ) @@ -102,8 +101,12 @@ func NewAccessToken(t *AccessToken) error { if err != nil { return err } + token, err := util.CryptoRandomBytes(20) + if err != nil { + return err + } t.TokenSalt = salt - t.Token = base.EncodeSha1(gouuid.New().String()) + 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) diff --git a/models/auth/twofactor.go b/models/auth/twofactor.go index 179d315364b1..5b3a9d011a09 100644 --- a/models/auth/twofactor.go +++ b/models/auth/twofactor.go @@ -9,6 +9,7 @@ import ( "crypto/subtle" "encoding/base32" "encoding/base64" + "encoding/hex" "fmt" "code.gitea.io/gitea/models/db" @@ -78,7 +79,7 @@ func (t *TwoFactor) GenerateScratchToken() (string, error) { // HashToken return the hashable salt func HashToken(token, salt string) string { tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New) - return fmt.Sprintf("%x", tempHash) + return hex.EncodeToString(tempHash) } // VerifyScratchToken verifies if the specified scratch token is valid. diff --git a/models/db/context.go b/models/db/context.go index fb95e94c931d..c8ad0c1aa273 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -21,8 +21,10 @@ type contextKey struct { } // enginedContextKey is a context key. It is used with context.Value() to get the current Engined for the context -var enginedContextKey = &contextKey{"engined"} -var _ Engined = &Context{} +var ( + enginedContextKey = &contextKey{"engined"} + _ Engined = &Context{} +) // Context represents a db context type Context struct { diff --git a/models/db/engine.go b/models/db/engine.go index 07ee6ca580ae..3d05fa8b6385 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -46,7 +46,7 @@ type Engine interface { Incr(column string, arg ...interface{}) *xorm.Session Insert(...interface{}) (int64, error) Iterate(interface{}, xorm.IterFunc) error - Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session + Join(joinOperator string, tablename, condition interface{}, args ...interface{}) *xorm.Session SQL(interface{}, ...interface{}) *xorm.Session Where(interface{}, ...interface{}) *xorm.Session Asc(colNames ...string) *xorm.Session diff --git a/models/db/engine_test.go b/models/db/engine_test.go index fa1ac08a1738..551436677782 100644 --- a/models/db/engine_test.go +++ b/models/db/engine_test.go @@ -12,6 +12,8 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" + _ "code.gitea.io/gitea/cmd" // for TestPrimaryKeys + "github.com/stretchr/testify/assert" ) @@ -51,3 +53,34 @@ func TestDeleteOrphanedObjects(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, countBefore, countAfter) } + +func TestPrimaryKeys(t *testing.T) { + // Some dbs require that all tables have primary keys, see + // https://github.com/go-gitea/gitea/issues/21086 + // https://github.com/go-gitea/gitea/issues/16802 + // To avoid creating tables without primary key again, this test will check them. + // Import "code.gitea.io/gitea/cmd" to make sure each db.RegisterModel in init functions has been called. + + beans, err := db.NamesToBean() + if err != nil { + t.Fatal(err) + } + + whitelist := map[string]string{ + "the_table_name_to_skip_checking": "Write a note here to explain why", + } + + for _, bean := range beans { + table, err := db.TableInfo(bean) + if err != nil { + t.Fatal(err) + } + if why, ok := whitelist[table.Name]; ok { + t.Logf("ignore %q because %q", table.Name, why) + continue + } + if len(table.PrimaryKeys) == 0 { + t.Errorf("table %q has no primary key", table.Name) + } + } +} diff --git a/models/db/index.go b/models/db/index.go index 46be74e91e7f..f840a62c8913 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -7,6 +7,9 @@ import ( "context" "errors" "fmt" + "strconv" + + "code.gitea.io/gitea/modules/setting" ) // ResourceIndex represents a resource index which could be used as issue/release and others @@ -23,11 +26,6 @@ var ( ErrGetResourceIndexFailed = errors.New("get resource index failed") ) -const ( - // MaxDupIndexAttempts max retry times to create index - MaxDupIndexAttempts = 3 -) - // SyncMaxResourceIndex sync the max index with the resource func SyncMaxResourceIndex(ctx context.Context, tableName string, groupID, maxIndex int64) (err error) { e := GetEngine(ctx) @@ -60,8 +58,25 @@ func SyncMaxResourceIndex(ctx context.Context, tableName string, groupID, maxInd return nil } +func postgresGetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { + res, err := GetEngine(ctx).Query(fmt.Sprintf("INSERT INTO %s (group_id, max_index) "+ + "VALUES (?,1) ON CONFLICT (group_id) DO UPDATE SET max_index = %s.max_index+1 RETURNING max_index", + tableName, tableName), groupID) + if err != nil { + return 0, err + } + if len(res) == 0 { + return 0, ErrGetResourceIndexFailed + } + return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) +} + // GetNextResourceIndex generates a resource index, it must run in the same transaction where the resource is created func GetNextResourceIndex(ctx context.Context, tableName string, groupID int64) (int64, error) { + if setting.Database.UsePostgreSQL { + return postgresGetNextResourceIndex(ctx, tableName, groupID) + } + e := GetEngine(ctx) // try to update the max_index to next value, and acquire the write-lock for the record diff --git a/models/db/iterate_test.go b/models/db/iterate_test.go index b0ea8b53ef1e..63487afa49b1 100644 --- a/models/db/iterate_test.go +++ b/models/db/iterate_test.go @@ -25,7 +25,7 @@ func TestIterate(t *testing.T) { return nil }) assert.NoError(t, err) - assert.EqualValues(t, 79, repoCnt) + assert.EqualValues(t, 81, repoCnt) err = db.Iterate(db.DefaultContext, nil, func(ctx context.Context, repoUnit *repo_model.RepoUnit) error { reopUnit2 := repo_model.RepoUnit{ID: repoUnit.ID} diff --git a/models/fixtures/foreign_reference.yml b/models/fixtures/foreign_reference.yml deleted file mode 100644 index ca780a73aa0c..000000000000 --- a/models/fixtures/foreign_reference.yml +++ /dev/null @@ -1 +0,0 @@ -[] # empty diff --git a/models/fixtures/lfs_meta_object.yml b/models/fixtures/lfs_meta_object.yml new file mode 100644 index 000000000000..1c29e02d44da --- /dev/null +++ b/models/fixtures/lfs_meta_object.yml @@ -0,0 +1,32 @@ +# These are the LFS objects in user2/lfs.git +- + + id: 1 + oid: 0b8d8b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351 + size: 107 + repository_id: 54 + created_unix: 1671607299 + +- + + id: 2 + oid: 2eccdb43825d2a49d99d542daa20075cff1d97d9d2349a8977efe9c03661737c + size: 107 + repository_id: 54 + created_unix: 1671607299 + +- + + id: 3 + oid: 7b6b2c88dba9f760a1a58469b67fee2b698ef7e9399c4ca4f34a14ccbe39f623 + size: 27 + repository_id: 54 + created_unix: 1671607299 + +- + + id: 4 + oid: 9d172e5c64b4f0024b9901ec6afe9ea052f3c9b6ff9f4b07956d8c48c86fca82 + size: 25 + repository_id: 54 + created_unix: 1671607299 diff --git a/models/fixtures/repo_unit.yml b/models/fixtures/repo_unit.yml index 59ab61834070..8706717ad46e 100644 --- a/models/fixtures/repo_unit.yml +++ b/models/fixtures/repo_unit.yml @@ -544,3 +544,15 @@ repo_id: 51 type: 2 created_unix: 946684810 + +- + id: 80 + repo_id: 53 + type: 1 + created_unix: 946684810 + +- + id: 81 + repo_id: 54 + type: 1 + created_unix: 946684810 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index f09953be7e5a..19b243fb4e4e 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -1558,3 +1558,41 @@ size: 0 is_fsck_enabled: true close_issues_via_commit_in_any_branch: false + +- + id: 53 + owner_id: 30 + owner_name: user30 + lower_name: renderer + name: renderer + is_archived: false + is_empty: false + is_private: false + num_issues: 0 + num_closed_issues: 0 + num_pulls: 0 + num_closed_pulls: 0 + num_milestones: 0 + num_closed_milestones: 0 + num_watches: 0 + num_projects: 0 + num_closed_projects: 0 + status: 0 + is_fork: false + fork_id: 0 + is_template: false + template_id: 0 + size: 0 + is_fsck_enabled: true + close_issues_via_commit_in_any_branch: false + +- + id: 54 + owner_id: 2 + owner_name: user2 + lower_name: lfs + name: lfs + is_empty: false + is_archived: false + is_private: true + status: 0 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index 0e3348e146a8..3afed37df965 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -66,7 +66,7 @@ num_followers: 2 num_following: 1 num_stars: 2 - num_repos: 9 + num_repos: 10 num_teams: 0 num_members: 0 visibility: 0 @@ -1102,7 +1102,7 @@ num_followers: 0 num_following: 0 num_stars: 0 - num_repos: 3 + num_repos: 4 num_teams: 0 num_members: 0 visibility: 0 diff --git a/models/foreignreference/error.go b/models/foreignreference/error.go deleted file mode 100644 index 07ed1052a63b..000000000000 --- a/models/foreignreference/error.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2022 Gitea. All rights reserved. -// SPDX-License-Identifier: MIT - -package foreignreference - -import ( - "fmt" - - "code.gitea.io/gitea/modules/util" -) - -// ErrLocalIndexNotExist represents a "LocalIndexNotExist" kind of error. -type ErrLocalIndexNotExist struct { - RepoID int64 - ForeignIndex int64 - Type string -} - -// ErrLocalIndexNotExist checks if an error is a ErrLocalIndexNotExist. -func IsErrLocalIndexNotExist(err error) bool { - _, ok := err.(ErrLocalIndexNotExist) - return ok -} - -func (err ErrLocalIndexNotExist) Error() string { - return fmt.Sprintf("repository %d has no LocalIndex for ForeignIndex %d of type %s", err.RepoID, err.ForeignIndex, err.Type) -} - -func (err ErrLocalIndexNotExist) Unwrap() error { - return util.ErrNotExist -} - -// ErrForeignIndexNotExist represents a "ForeignIndexNotExist" kind of error. -type ErrForeignIndexNotExist struct { - RepoID int64 - LocalIndex int64 - Type string -} - -// ErrForeignIndexNotExist checks if an error is a ErrForeignIndexNotExist. -func IsErrForeignIndexNotExist(err error) bool { - _, ok := err.(ErrForeignIndexNotExist) - return ok -} - -func (err ErrForeignIndexNotExist) Error() string { - return fmt.Sprintf("repository %d has no ForeignIndex for LocalIndex %d of type %s", err.RepoID, err.LocalIndex, err.Type) -} - -func (err ErrForeignIndexNotExist) Unwrap() error { - return util.ErrNotExist -} diff --git a/models/foreignreference/foreignreference.go b/models/foreignreference/foreignreference.go deleted file mode 100644 index 2d2ad04c5a14..000000000000 --- a/models/foreignreference/foreignreference.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2022 Gitea. All rights reserved. -// SPDX-License-Identifier: MIT - -package foreignreference - -import ( - "code.gitea.io/gitea/models/db" -) - -// Type* are valid values for the Type field of ForeignReference -const ( - TypeIssue = "issue" - TypePullRequest = "pull_request" - TypeComment = "comment" - TypeReview = "review" - TypeReviewComment = "review_comment" - TypeRelease = "release" -) - -// ForeignReference represents external references -type ForeignReference struct { - // RepoID is the first column in all indices. now we only need 2 indices: (repo, local) and (repo, foreign, type) - RepoID int64 `xorm:"UNIQUE(repo_foreign_type) INDEX(repo_local)" ` - LocalIndex int64 `xorm:"INDEX(repo_local)"` // the resource key inside Gitea, it can be IssueIndex, or some model ID. - ForeignIndex string `xorm:"INDEX UNIQUE(repo_foreign_type)"` - Type string `xorm:"VARCHAR(16) INDEX UNIQUE(repo_foreign_type)"` -} - -func init() { - db.RegisterModel(new(ForeignReference)) -} diff --git a/models/git/branches.go b/models/git/branches.go index 87246ed149b0..c02ab0a88864 100644 --- a/models/git/branches.go +++ b/models/git/branches.go @@ -73,10 +73,10 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool { } if !protectBranch.EnableWhitelist { - if user, err := user_model.GetUserByID(userID); err != nil { + if user, err := user_model.GetUserByID(db.DefaultContext, userID); err != nil { log.Error("GetUserByID: %v", err) return false - } else if repo, err := repo_model.GetRepositoryByID(protectBranch.RepoID); err != nil { + } else if repo, err := repo_model.GetRepositoryByID(db.DefaultContext, protectBranch.RepoID); err != nil { log.Error("repo_model.GetRepositoryByID: %v", err) return false } else if writeAccess, err := access_model.HasAccessUnit(db.DefaultContext, user, repo, unit.TypeCode, perm.AccessModeWrite); err != nil { @@ -127,13 +127,8 @@ func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, } // IsUserOfficialReviewer check if user is official reviewer for the branch (counts towards required approvals) -func IsUserOfficialReviewer(protectBranch *ProtectedBranch, user *user_model.User) (bool, error) { - return IsUserOfficialReviewerCtx(db.DefaultContext, protectBranch, user) -} - -// IsUserOfficialReviewerCtx check if user is official reviewer for the branch (counts towards required approvals) -func IsUserOfficialReviewerCtx(ctx context.Context, protectBranch *ProtectedBranch, user *user_model.User) (bool, error) { - repo, err := repo_model.GetRepositoryByIDCtx(ctx, protectBranch.RepoID) +func IsUserOfficialReviewer(ctx context.Context, protectBranch *ProtectedBranch, user *user_model.User) (bool, error) { + repo, err := repo_model.GetRepositoryByID(ctx, protectBranch.RepoID) if err != nil { return false, err } @@ -375,7 +370,7 @@ func updateUserWhitelist(ctx context.Context, repo *repo_model.Repository, curre whitelist = make([]int64, 0, len(newWhitelist)) for _, userID := range newWhitelist { - user, err := user_model.GetUserByIDCtx(ctx, userID) + user, err := user_model.GetUserByID(ctx, userID) if err != nil { return nil, fmt.Errorf("GetUserByID [user_id: %d, repo_id: %d]: %w", userID, repo.ID, err) } @@ -494,8 +489,8 @@ func RemoveDeletedBranchByID(repoID, id int64) (err error) { // LoadUser loads the user that deleted the branch // When there's no user found it returns a user_model.NewGhostUser -func (deletedBranch *DeletedBranch) LoadUser() { - user, err := user_model.GetUserByID(deletedBranch.DeletedByID) +func (deletedBranch *DeletedBranch) LoadUser(ctx context.Context) { + user, err := user_model.GetUserByID(ctx, deletedBranch.DeletedByID) if err != nil { user = user_model.NewGhostUser() } diff --git a/models/git/branches_test.go b/models/git/branches_test.go index 038a4f6686a6..56f416622e14 100644 --- a/models/git/branches_test.go +++ b/models/git/branches_test.go @@ -48,13 +48,13 @@ func TestDeletedBranchLoadUser(t *testing.T) { branch := getDeletedBranch(t, firstBranch) assert.Nil(t, branch.DeletedBy) - branch.LoadUser() + branch.LoadUser(db.DefaultContext) assert.NotNil(t, branch.DeletedBy) assert.Equal(t, "user1", branch.DeletedBy.Name) branch = getDeletedBranch(t, secondBranch) assert.Nil(t, branch.DeletedBy) - branch.LoadUser() + branch.LoadUser(db.DefaultContext) assert.NotNil(t, branch.DeletedBy) assert.Equal(t, "Ghost", branch.DeletedBy.Name) } diff --git a/models/git/commit_status.go b/models/git/commit_status.go index 411fbbe53604..07e0b9fb73b4 100644 --- a/models/git/commit_status.go +++ b/models/git/commit_status.go @@ -6,8 +6,10 @@ package git import ( "context" "crypto/sha1" + "errors" "fmt" "net/url" + "strconv" "strings" "time" @@ -48,90 +50,77 @@ func init() { db.RegisterModel(new(CommitStatusIndex)) } -// upsertCommitStatusIndex the function will not return until it acquires the lock or receives an error. -func upsertCommitStatusIndex(ctx context.Context, repoID int64, sha string) (err error) { - // An atomic UPSERT operation (INSERT/UPDATE) is the only operation - // that ensures that the key is actually locked. - switch { - case setting.Database.UseSQLite3 || setting.Database.UsePostgreSQL: - _, err = db.Exec(ctx, "INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ - "VALUES (?,?,1) ON CONFLICT (repo_id,sha) DO UPDATE SET max_index = `commit_status_index`.max_index+1", - repoID, sha) - case setting.Database.UseMySQL: - _, err = db.Exec(ctx, "INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ - "VALUES (?,?,1) ON DUPLICATE KEY UPDATE max_index = max_index+1", - repoID, sha) - case setting.Database.UseMSSQL: - // https://weblogs.sqlteam.com/dang/2009/01/31/upsert-race-condition-with-merge/ - _, err = db.Exec(ctx, "MERGE `commit_status_index` WITH (HOLDLOCK) as target "+ - "USING (SELECT ? AS repo_id, ? AS sha) AS src "+ - "ON src.repo_id = target.repo_id AND src.sha = target.sha "+ - "WHEN MATCHED THEN UPDATE SET target.max_index = target.max_index+1 "+ - "WHEN NOT MATCHED THEN INSERT (repo_id, sha, max_index) "+ - "VALUES (src.repo_id, src.sha, 1);", - repoID, sha) - default: - return fmt.Errorf("database type not supported") +func postgresGetCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + res, err := db.GetEngine(ctx).Query("INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ + "VALUES (?,?,1) ON CONFLICT (repo_id, sha) DO UPDATE SET max_index = `commit_status_index`.max_index+1 RETURNING max_index", + repoID, sha) + if err != nil { + return 0, err + } + if len(res) == 0 { + return 0, db.ErrGetResourceIndexFailed } - return err + return strconv.ParseInt(string(res[0]["max_index"]), 10, 64) } // GetNextCommitStatusIndex retried 3 times to generate a resource index -func GetNextCommitStatusIndex(repoID int64, sha string) (int64, error) { - for i := 0; i < db.MaxDupIndexAttempts; i++ { - idx, err := getNextCommitStatusIndex(repoID, sha) - if err == db.ErrResouceOutdated { - continue - } - if err != nil { - return 0, err - } - return idx, nil +func GetNextCommitStatusIndex(ctx context.Context, repoID int64, sha string) (int64, error) { + if setting.Database.UsePostgreSQL { + return postgresGetCommitStatusIndex(ctx, repoID, sha) } - return 0, db.ErrGetResourceIndexFailed -} -// getNextCommitStatusIndex return the next index -func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) { - ctx, commiter, err := db.TxContext(db.DefaultContext) + e := db.GetEngine(ctx) + + // try to update the max_index to next value, and acquire the write-lock for the record + res, err := e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha) if err != nil { return 0, err } - defer commiter.Close() - - var preIdx int64 - _, err = db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", repoID, sha).Get(&preIdx) + affected, err := res.RowsAffected() if err != nil { return 0, err } - - if err := upsertCommitStatusIndex(ctx, repoID, sha); err != nil { - return 0, err + if affected == 0 { + // this slow path is only for the first time of creating a resource index + _, errIns := e.Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) VALUES (?, ?, 0)", repoID, sha) + res, err = e.Exec("UPDATE `commit_status_index` SET max_index=max_index+1 WHERE repo_id=? AND sha=?", repoID, sha) + if err != nil { + return 0, err + } + affected, err = res.RowsAffected() + if err != nil { + return 0, err + } + // if the update still can not update any records, the record must not exist and there must be some errors (insert error) + if affected == 0 { + if errIns == nil { + return 0, errors.New("impossible error when GetNextCommitStatusIndex, insert and update both succeeded but no record is updated") + } + return 0, errIns + } } - var curIdx int64 - has, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ? AND max_index=?", repoID, sha, preIdx+1).Get(&curIdx) + // now, the new index is in database (protected by the transaction and write-lock) + var newIdx int64 + has, err := e.SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id=? AND sha=?", repoID, sha).Get(&newIdx) if err != nil { return 0, err } if !has { - return 0, db.ErrResouceOutdated - } - if err := commiter.Commit(); err != nil { - return 0, err + return 0, errors.New("impossible error when GetNextCommitStatusIndex, upsert succeeded but no record can be selected") } - return curIdx, nil + return newIdx, nil } func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { if status.Repo == nil { - status.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, status.RepoID) + status.Repo, err = repo_model.GetRepositoryByID(ctx, status.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %w", status.RepoID, err) } } if status.Creator == nil && status.CreatorID > 0 { - status.Creator, err = user_model.GetUserByIDCtx(ctx, status.CreatorID) + status.Creator, err = user_model.GetUserByID(ctx, status.CreatorID) if err != nil { return fmt.Errorf("getUserByID [%d]: %w", status.CreatorID, err) } @@ -290,10 +279,8 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { return fmt.Errorf("NewCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA) } - // Get the next Status Index - idx, err := GetNextCommitStatusIndex(opts.Repo.ID, opts.SHA) - if err != nil { - return fmt.Errorf("generate commit status index failed: %w", err) + if _, err := git.NewIDFromString(opts.SHA); err != nil { + return fmt.Errorf("NewCommitStatus[%s, %s]: invalid sha: %w", repoPath, opts.SHA, err) } ctx, committer, err := db.TxContext(db.DefaultContext) @@ -302,6 +289,12 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { } defer committer.Close() + // Get the next Status Index + idx, err := GetNextCommitStatusIndex(ctx, opts.Repo.ID, opts.SHA) + if err != nil { + return fmt.Errorf("generate commit status index failed: %w", err) + } + opts.CommitStatus.Description = strings.TrimSpace(opts.CommitStatus.Description) opts.CommitStatus.Context = strings.TrimSpace(opts.CommitStatus.Context) opts.CommitStatus.TargetURL = strings.TrimSpace(opts.CommitStatus.TargetURL) @@ -315,7 +308,7 @@ func NewCommitStatus(opts NewCommitStatusOptions) error { // Insert new CommitStatus if _, err = db.GetEngine(ctx).Insert(opts.CommitStatus); err != nil { - return fmt.Errorf("Insert CommitStatus[%s, %s]: %w", repoPath, opts.SHA, err) + return fmt.Errorf("insert CommitStatus[%s, %s]: %w", repoPath, opts.SHA, err) } return committer.Commit() diff --git a/models/git/lfs.go b/models/git/lfs.go index a86e84c050c2..8d418b928d14 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -6,6 +6,7 @@ package git import ( "context" "fmt" + "time" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" @@ -14,6 +15,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/util" @@ -180,6 +182,12 @@ func GetLFSMetaObjectByOid(repoID int64, oid string) (*LFSMetaObject, error) { // RemoveLFSMetaObjectByOid removes a LFSMetaObject entry from database by its OID. // It may return ErrLFSObjectNotExist or a database error. func RemoveLFSMetaObjectByOid(repoID int64, oid string) (int64, error) { + return RemoveLFSMetaObjectByOidFn(repoID, oid, nil) +} + +// RemoveLFSMetaObjectByOidFn removes a LFSMetaObject entry from database by its OID. +// It may return ErrLFSObjectNotExist or a database error. It will run Fn with the current count within the transaction +func RemoveLFSMetaObjectByOidFn(repoID int64, oid string, fn func(count int64) error) (int64, error) { if len(oid) == 0 { return 0, ErrLFSObjectNotExist } @@ -200,6 +208,12 @@ func RemoveLFSMetaObjectByOid(repoID int64, oid string) (int64, error) { return count, err } + if fn != nil { + if err := fn(count); err != nil { + return count, err + } + } + return count, committer.Commit() } @@ -319,3 +333,43 @@ func GetRepoLFSSize(ctx context.Context, repoID int64) (int64, error) { } return lfsSize, nil } + +type IterateLFSMetaObjectsForRepoOptions struct { + OlderThan time.Time +} + +// IterateLFSMetaObjectsForRepo provides a iterator for LFSMetaObjects per Repo +func IterateLFSMetaObjectsForRepo(ctx context.Context, repoID int64, f func(context.Context, *LFSMetaObject, int64) error, opts *IterateLFSMetaObjectsForRepoOptions) error { + var start int + batchSize := setting.Database.IterateBufferSize + engine := db.GetEngine(ctx) + type CountLFSMetaObject struct { + Count int64 + LFSMetaObject + } + + for { + beans := make([]*CountLFSMetaObject, 0, batchSize) + // SELECT `lfs_meta_object`.*, COUNT(`l1`.id) as `count` FROM lfs_meta_object INNER JOIN lfs_meta_object AS l1 ON l1.oid = lfs_meta_object.oid WHERE lfs_meta_object.repository_id = ? GROUP BY lfs_meta_object.id + sess := engine.Select("`lfs_meta_object`.*, COUNT(`l1`.oid) AS `count`"). + Join("INNER", "`lfs_meta_object` AS l1", "`lfs_meta_object`.oid = `l1`.oid"). + Where("`lfs_meta_object`.repository_id = ?", repoID) + if !opts.OlderThan.IsZero() { + sess.And("`lfs_meta_object`.created_unix < ?", opts.OlderThan) + } + sess.GroupBy("`lfs_meta_object`.id") + if err := sess.Limit(batchSize, start).Find(&beans); err != nil { + return err + } + if len(beans) == 0 { + return nil + } + start += len(beans) + + for _, bean := range beans { + if err := f(ctx, &bean.LFSMetaObject, bean.Count); err != nil { + return err + } + } + } +} diff --git a/models/git/lfs_lock.go b/models/git/lfs_lock.go index 3d765ea22bb7..dc5b0a2cedde 100644 --- a/models/git/lfs_lock.go +++ b/models/git/lfs_lock.go @@ -167,7 +167,7 @@ func CheckLFSAccessForRepo(ctx context.Context, ownerID int64, repo *repo_model. if ownerID == 0 { return ErrLFSUnauthorizedAction{repo.ID, "undefined", mode} } - u, err := user_model.GetUserByIDCtx(ctx, ownerID) + u, err := user_model.GetUserByID(ctx, ownerID) if err != nil { return err } diff --git a/models/issues/assignees.go b/models/issues/assignees.go index 25ecd4b05caf..159086bd0105 100644 --- a/models/issues/assignees.go +++ b/models/issues/assignees.go @@ -102,7 +102,7 @@ func toggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.Use AssigneeID: assigneeID, } // Comment - comment, err = CreateCommentCtx(ctx, opts) + comment, err = CreateComment(ctx, opts) if err != nil { return false, nil, fmt.Errorf("createComment: %w", err) } @@ -118,7 +118,7 @@ func toggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.Use // toggles user assignee state in database func toggleUserAssignee(ctx context.Context, issue *Issue, assigneeID int64) (removed bool, err error) { // Check if the user exists - assignee, err := user_model.GetUserByIDCtx(ctx, assigneeID) + assignee, err := user_model.GetUserByID(ctx, assigneeID) if err != nil { return false, err } diff --git a/models/issues/assignees_test.go b/models/issues/assignees_test.go index 7f18569d4911..8a2cef8acd8e 100644 --- a/models/issues/assignees_test.go +++ b/models/issues/assignees_test.go @@ -22,17 +22,17 @@ func TestUpdateAssignee(t *testing.T) { assert.NoError(t, err) // Assign multiple users - user2, err := user_model.GetUserByID(2) + user2, err := user_model.GetUserByID(db.DefaultContext, 2) assert.NoError(t, err) _, _, err = issues_model.ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user2.ID) assert.NoError(t, err) - user3, err := user_model.GetUserByID(3) + user3, err := user_model.GetUserByID(db.DefaultContext, 3) assert.NoError(t, err) _, _, err = issues_model.ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user3.ID) assert.NoError(t, err) - user1, err := user_model.GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him + user1, err := user_model.GetUserByID(db.DefaultContext, 1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him assert.NoError(t, err) _, _, err = issues_model.ToggleIssueAssignee(issue, &user_model.User{ID: 1}, user1.ID) assert.NoError(t, err) diff --git a/models/issues/comment.go b/models/issues/comment.go index 0aaa870b4659..612f17aa5af6 100644 --- a/models/issues/comment.go +++ b/models/issues/comment.go @@ -350,7 +350,7 @@ func (c *Comment) LoadPoster(ctx context.Context) (err error) { return nil } - c.Poster, err = user_model.GetUserByIDCtx(ctx, c.PosterID) + c.Poster, err = user_model.GetUserByID(ctx, c.PosterID) if err != nil { if user_model.IsErrUserNotExist(err) { c.PosterID = -1 @@ -580,7 +580,7 @@ func (c *Comment) LoadAssigneeUserAndTeam() error { var err error if c.AssigneeID > 0 && c.Assignee == nil { - c.Assignee, err = user_model.GetUserByIDCtx(db.DefaultContext, c.AssigneeID) + c.Assignee, err = user_model.GetUserByID(db.DefaultContext, c.AssigneeID) if err != nil { if !user_model.IsErrUserNotExist(err) { return err @@ -615,7 +615,7 @@ func (c *Comment) LoadResolveDoer() (err error) { if c.ResolveDoerID == 0 || c.Type != CommentTypeCode { return nil } - c.ResolveDoer, err = user_model.GetUserByIDCtx(db.DefaultContext, c.ResolveDoerID) + c.ResolveDoer, err = user_model.GetUserByID(db.DefaultContext, c.ResolveDoerID) if err != nil { if user_model.IsErrUserNotExist(err) { c.ResolveDoer = user_model.NewGhostUser() @@ -779,8 +779,8 @@ func (c *Comment) LoadPushCommits(ctx context.Context) (err error) { return err } -// CreateCommentCtx creates comment with context -func CreateCommentCtx(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) { +// CreateComment creates comment with context +func CreateComment(ctx context.Context, opts *CreateCommentOptions) (_ *Comment, err error) { e := db.GetEngine(ctx) var LabelID int64 if opts.Label != nil { @@ -875,6 +875,8 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment return fmt.Errorf("update attachment [%d]: %w", attachments[i].ID, err) } } + + comment.Attachments = attachments case CommentTypeReopen, CommentTypeClose: if err = repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.Issue.IsPull, true); err != nil { return err @@ -913,7 +915,7 @@ func createDeadlineComment(ctx context.Context, doer *user_model.User, issue *Is Issue: issue, Content: content, } - comment, err := CreateCommentCtx(ctx, opts) + comment, err := CreateComment(ctx, opts) if err != nil { return nil, err } @@ -938,7 +940,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is Issue: issue, DependentIssueID: dependentIssue.ID, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return } @@ -949,7 +951,7 @@ func createIssueDependencyComment(ctx context.Context, doer *user_model.User, is Issue: dependentIssue, DependentIssueID: issue.ID, } - _, err = CreateCommentCtx(ctx, opts) + _, err = CreateComment(ctx, opts) return err } @@ -991,55 +993,6 @@ type CreateCommentOptions struct { Invalidated bool } -// CreateComment creates comment of issue or commit. -func CreateComment(opts *CreateCommentOptions) (comment *Comment, err error) { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return nil, err - } - defer committer.Close() - - comment, err = CreateCommentCtx(ctx, opts) - if err != nil { - return nil, err - } - - if err = committer.Commit(); err != nil { - return nil, err - } - - return comment, nil -} - -// CreateRefComment creates a commit reference comment to issue. -func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *Issue, content, commitSHA string) error { - if len(commitSHA) == 0 { - return fmt.Errorf("cannot create reference with empty commit SHA") - } - - // Check if same reference from same commit has already existed. - has, err := db.GetEngine(db.DefaultContext).Get(&Comment{ - Type: CommentTypeCommitRef, - IssueID: issue.ID, - CommitSHA: commitSHA, - }) - if err != nil { - return fmt.Errorf("check reference comment: %w", err) - } else if has { - return nil - } - - _, err = CreateComment(&CreateCommentOptions{ - Type: CommentTypeCommitRef, - Doer: doer, - Repo: repo, - Issue: issue, - CommitSHA: commitSHA, - Content: content, - }) - return err -} - // GetCommentByID returns the comment by given ID. func GetCommentByID(ctx context.Context, id int64) (*Comment, error) { c := new(Comment) @@ -1315,39 +1268,6 @@ func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID return err } -// CreatePushPullComment create push code to pull base comment -func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *PullRequest, oldCommitID, newCommitID string) (comment *Comment, err error) { - if pr.HasMerged || oldCommitID == "" || newCommitID == "" { - return nil, nil - } - - ops := &CreateCommentOptions{ - Type: CommentTypePullRequestPush, - Doer: pusher, - Repo: pr.BaseRepo, - } - - var data PushActionContent - - data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch) - if err != nil { - return nil, err - } - - ops.Issue = pr.Issue - - dataJSON, err := json.Marshal(data) - if err != nil { - return nil, err - } - - ops.Content = string(dataJSON) - - comment, err = CreateComment(ops) - - return comment, err -} - // CreateAutoMergeComment is a internal function, only use it for CommentTypePRScheduledToAutoMerge and CommentTypePRUnScheduledToAutoMerge CommentTypes func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullRequest, doer *user_model.User) (comment *Comment, err error) { if typ != CommentTypePRScheduledToAutoMerge && typ != CommentTypePRUnScheduledToAutoMerge { @@ -1361,7 +1281,7 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques return } - comment, err = CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err = CreateComment(ctx, &CreateCommentOptions{ Type: typ, Doer: doer, Repo: pr.BaseRepo, @@ -1370,120 +1290,6 @@ func CreateAutoMergeComment(ctx context.Context, typ CommentType, pr *PullReques return comment, err } -// getCommitsFromRepo get commit IDs from repo in between oldCommitID and newCommitID -// isForcePush will be true if oldCommit isn't on the branch -// Commit on baseBranch will skip -func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { - repoPath := repo.RepoPath() - gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath) - if err != nil { - return nil, false, err - } - defer closer.Close() - - oldCommit, err := gitRepo.GetCommit(oldCommitID) - if err != nil { - return nil, false, err - } - - if err = oldCommit.LoadBranchName(); err != nil { - return nil, false, err - } - - if len(oldCommit.Branch) == 0 { - commitIDs = make([]string, 2) - commitIDs[0] = oldCommitID - commitIDs[1] = newCommitID - - return commitIDs, true, err - } - - newCommit, err := gitRepo.GetCommit(newCommitID) - if err != nil { - return nil, false, err - } - - commits, err := newCommit.CommitsBeforeUntil(oldCommitID) - if err != nil { - return nil, false, err - } - - commitIDs = make([]string, 0, len(commits)) - commitChecks := make(map[string]*commitBranchCheckItem) - - for _, commit := range commits { - commitChecks[commit.ID.String()] = &commitBranchCheckItem{ - Commit: commit, - Checked: false, - } - } - - if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil { - return - } - - for i := len(commits) - 1; i >= 0; i-- { - commitID := commits[i].ID.String() - if item, ok := commitChecks[commitID]; ok && item.Checked { - commitIDs = append(commitIDs, commitID) - } - } - - return commitIDs, isForcePush, err -} - -type commitBranchCheckItem struct { - Commit *git.Commit - Checked bool -} - -func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error { - if startCommit.ID.String() == endCommitID { - return nil - } - - checkStack := make([]string, 0, 10) - checkStack = append(checkStack, startCommit.ID.String()) - - for len(checkStack) > 0 { - commitID := checkStack[0] - checkStack = checkStack[1:] - - item, ok := commitList[commitID] - if !ok { - continue - } - - if item.Commit.ID.String() == endCommitID { - continue - } - - if err := item.Commit.LoadBranchName(); err != nil { - return err - } - - if item.Commit.Branch == baseBranch { - continue - } - - if item.Checked { - continue - } - - item.Checked = true - - parentNum := item.Commit.ParentCount() - for i := 0; i < parentNum; i++ { - parentCommit, err := item.Commit.Parent(i) - if err != nil { - return err - } - checkStack = append(checkStack, parentCommit.ID.String()) - } - } - return nil -} - // RemapExternalUser ExternalUserRemappable interface func (c *Comment) RemapExternalUser(externalName string, externalID, userID int64) error { c.OriginalAuthor = externalName diff --git a/models/issues/comment_test.go b/models/issues/comment_test.go index 6a647474dca5..0d0570ae34d6 100644 --- a/models/issues/comment_test.go +++ b/models/issues/comment_test.go @@ -24,7 +24,7 @@ func TestCreateComment(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) now := time.Now().Unix() - comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{ + comment, err := issues_model.CreateComment(db.DefaultContext, &issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeComment, Doer: doer, Repo: repo, diff --git a/models/issues/dependency_test.go b/models/issues/dependency_test.go index 7af30b201937..cdc8e3182d36 100644 --- a/models/issues/dependency_test.go +++ b/models/issues/dependency_test.go @@ -18,7 +18,7 @@ func TestCreateIssueDependency(t *testing.T) { // Prepare assert.NoError(t, unittest.PrepareTestDatabase()) - user1, err := user_model.GetUserByID(1) + user1, err := user_model.GetUserByID(db.DefaultContext, 1) assert.NoError(t, err) issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1) diff --git a/models/issues/issue.go b/models/issues/issue.go index 488a17609e51..f45e635c0ece 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -9,11 +9,9 @@ import ( "fmt" "regexp" "sort" - "strconv" "strings" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/foreignreference" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" access_model "code.gitea.io/gitea/models/perm/access" @@ -136,12 +134,11 @@ type Issue struct { UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` ClosedUnix timeutil.TimeStamp `xorm:"INDEX"` - Attachments []*repo_model.Attachment `xorm:"-"` - Comments []*Comment `xorm:"-"` - Reactions ReactionList `xorm:"-"` - TotalTrackedTime int64 `xorm:"-"` - Assignees []*user_model.User `xorm:"-"` - ForeignReference *foreignreference.ForeignReference `xorm:"-"` + Attachments []*repo_model.Attachment `xorm:"-"` + Comments []*Comment `xorm:"-"` + Reactions ReactionList `xorm:"-"` + TotalTrackedTime int64 `xorm:"-"` + Assignees []*user_model.User `xorm:"-"` // IsLocked limits commenting abilities to users on an issue // with write access @@ -193,7 +190,7 @@ func (issue *Issue) IsOverdue() bool { // LoadRepo loads issue's repository func (issue *Issue) LoadRepo(ctx context.Context) (err error) { if issue.Repo == nil { - issue.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, issue.RepoID) + issue.Repo, err = repo_model.GetRepositoryByID(ctx, issue.RepoID) if err != nil { return fmt.Errorf("getRepositoryByID [%d]: %w", issue.RepoID, err) } @@ -202,16 +199,12 @@ func (issue *Issue) LoadRepo(ctx context.Context) (err error) { } // IsTimetrackerEnabled returns true if the repo enables timetracking -func (issue *Issue) IsTimetrackerEnabled() bool { - return issue.isTimetrackerEnabled(db.DefaultContext) -} - -func (issue *Issue) isTimetrackerEnabled(ctx context.Context) bool { +func (issue *Issue) IsTimetrackerEnabled(ctx context.Context) bool { if err := issue.LoadRepo(ctx); err != nil { log.Error(fmt.Sprintf("loadRepo: %v", err)) return false } - return issue.Repo.IsTimetrackerEnabledCtx(ctx) + return issue.Repo.IsTimetrackerEnabled(ctx) } // GetPullRequest returns the issue pull request @@ -242,7 +235,7 @@ func (issue *Issue) LoadLabels(ctx context.Context) (err error) { // LoadPoster loads poster func (issue *Issue) LoadPoster(ctx context.Context) (err error) { if issue.Poster == nil { - issue.Poster, err = user_model.GetUserByIDCtx(ctx, issue.PosterID) + issue.Poster, err = user_model.GetUserByID(ctx, issue.PosterID) if err != nil { issue.PosterID = -1 issue.Poster = user_model.NewGhostUser() @@ -325,29 +318,6 @@ func (issue *Issue) loadReactions(ctx context.Context) (err error) { return nil } -func (issue *Issue) loadForeignReference(ctx context.Context) (err error) { - if issue.ForeignReference != nil { - return nil - } - reference := &foreignreference.ForeignReference{ - RepoID: issue.RepoID, - LocalIndex: issue.Index, - Type: foreignreference.TypeIssue, - } - has, err := db.GetEngine(ctx).Get(reference) - if err != nil { - return err - } else if !has { - return foreignreference.ErrForeignIndexNotExist{ - RepoID: issue.RepoID, - LocalIndex: issue.Index, - Type: foreignreference.TypeIssue, - } - } - issue.ForeignReference = reference - return nil -} - // LoadMilestone load milestone of this issue. func (issue *Issue) LoadMilestone(ctx context.Context) (err error) { if (issue.Milestone == nil || issue.Milestone.ID != issue.MilestoneID) && issue.MilestoneID > 0 { @@ -404,16 +374,12 @@ func (issue *Issue) LoadAttributes(ctx context.Context) (err error) { if err = CommentList(issue.Comments).loadAttributes(ctx); err != nil { return err } - if issue.isTimetrackerEnabled(ctx) { + if issue.IsTimetrackerEnabled(ctx) { if err = issue.LoadTotalTimes(ctx); err != nil { return err } } - if err = issue.loadForeignReference(ctx); err != nil && !foreignreference.IsErrForeignIndexNotExist(err) { - return err - } - return issue.loadReactions(ctx) } @@ -673,7 +639,7 @@ func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isMergePull bool) (*Comment, error) { // Check for open dependencies - if issue.IsClosed && issue.Repo.IsDependenciesEnabledCtx(ctx) { + if issue.IsClosed && issue.Repo.IsDependenciesEnabled(ctx) { // only check if dependencies are enabled and we're about to close an issue, otherwise reopening an issue would fail when there are unsatisfied dependencies noDeps, err := IssueNoDependenciesLeft(ctx, issue) if err != nil { @@ -725,7 +691,7 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use cmtType = CommentTypeMergePull } - return CreateCommentCtx(ctx, &CreateCommentOptions{ + return CreateComment(ctx, &CreateCommentOptions{ Type: cmtType, Doer: doer, Repo: issue.Repo, @@ -769,7 +735,7 @@ func ChangeIssueTitle(issue *Issue, doer *user_model.User, oldTitle string) (err OldTitle: oldTitle, NewTitle: issue.Title, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return fmt.Errorf("createComment: %w", err) } if err = issue.AddCrossReferences(ctx, doer, true); err != nil { @@ -805,7 +771,7 @@ func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err err OldRef: oldRefFriendly, NewRef: newRefFriendly, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return fmt.Errorf("createComment: %w", err) } @@ -825,7 +791,7 @@ func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo * Issue: issue, OldRef: branchName, } - _, err = CreateCommentCtx(ctx, opts) + _, err = CreateComment(ctx, opts) return err } @@ -992,17 +958,12 @@ func NewIssueWithIndex(ctx context.Context, doer *user_model.User, opts NewIssue OldMilestoneID: 0, MilestoneID: opts.Issue.MilestoneID, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return err } } - if opts.IsPull { - _, err = e.Exec("UPDATE `repository` SET num_pulls = num_pulls + 1 WHERE id = ?", opts.Issue.RepoID) - } else { - _, err = e.Exec("UPDATE `repository` SET num_issues = num_issues + 1 WHERE id = ?", opts.Issue.RepoID) - } - if err != nil { + if err := repo_model.UpdateRepoIssueNumbers(ctx, opts.Issue.RepoID, opts.IsPull, false); err != nil { return err } @@ -1106,26 +1067,6 @@ func GetIssueByIndex(repoID, index int64) (*Issue, error) { return issue, nil } -// GetIssueByForeignIndex returns raw issue by foreign ID -func GetIssueByForeignIndex(ctx context.Context, repoID, foreignIndex int64) (*Issue, error) { - reference := &foreignreference.ForeignReference{ - RepoID: repoID, - ForeignIndex: strconv.FormatInt(foreignIndex, 10), - Type: foreignreference.TypeIssue, - } - has, err := db.GetEngine(ctx).Get(reference) - if err != nil { - return nil, err - } else if !has { - return nil, foreignreference.ErrLocalIndexNotExist{ - RepoID: repoID, - ForeignIndex: foreignIndex, - Type: foreignreference.TypeIssue, - } - } - return GetIssueByIndex(repoID, reference.LocalIndex) -} - // GetIssueWithAttrsByIndex returns issue by index in a repository. func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) { issue, err := GetIssueByIndex(repoID, index) @@ -2005,7 +1946,7 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment OldTitle: currentIssue.Title, NewTitle: issue.Title, } - _, err := CreateCommentCtx(ctx, opts) + _, err := CreateComment(ctx, opts) if err != nil { return nil, false, fmt.Errorf("createComment: %w", err) } diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 35a0c1f0e3a7..e22e48c0bb4b 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -461,7 +461,7 @@ func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) { ids := make([]int64, 0, len(issues)) for _, issue := range issues { - if issue.Repo.IsTimetrackerEnabled() { + if issue.Repo.IsTimetrackerEnabled(ctx) { ids = append(ids, issue.ID) } } diff --git a/models/issues/issue_lock.go b/models/issues/issue_lock.go index 1376ffcadad3..19cd6d316757 100644 --- a/models/issues/issue_lock.go +++ b/models/issues/issue_lock.go @@ -56,7 +56,7 @@ func updateIssueLock(opts *IssueLockOptions, lock bool) error { Type: commentType, Content: opts.Reason, } - if _, err := CreateCommentCtx(ctx, opt); err != nil { + if _, err := CreateComment(ctx, opt); err != nil { return err } diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index a366a92fad04..8e559f13c92c 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -145,7 +145,7 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U } if oldProjectID > 0 || newProjectID > 0 { - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeProject, Doer: doer, Repo: issue.Repo, diff --git a/models/issues/issue_test.go b/models/issues/issue_test.go index 6764a9e6260e..de1da19ab9fa 100644 --- a/models/issues/issue_test.go +++ b/models/issues/issue_test.go @@ -7,13 +7,11 @@ import ( "context" "fmt" "sort" - "strconv" "sync" "testing" "time" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/foreignreference" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -501,38 +499,6 @@ func TestCorrectIssueStats(t *testing.T) { assert.EqualValues(t, issueStats.OpenCount, issueAmount) } -func TestIssueForeignReference(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: 4}) - assert.NotEqualValues(t, issue.Index, issue.ID) // make sure they are different to avoid false positive - - // it is fine for an issue to not have a foreign reference - err := issue.LoadAttributes(db.DefaultContext) - assert.NoError(t, err) - assert.Nil(t, issue.ForeignReference) - - var foreignIndex int64 = 12345 - _, err = issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex) - assert.True(t, foreignreference.IsErrLocalIndexNotExist(err)) - - err = db.Insert(db.DefaultContext, &foreignreference.ForeignReference{ - LocalIndex: issue.Index, - ForeignIndex: strconv.FormatInt(foreignIndex, 10), - RepoID: issue.RepoID, - Type: foreignreference.TypeIssue, - }) - assert.NoError(t, err) - - err = issue.LoadAttributes(db.DefaultContext) - assert.NoError(t, err) - - assert.EqualValues(t, issue.ForeignReference.ForeignIndex, strconv.FormatInt(foreignIndex, 10)) - - found, err := issues_model.GetIssueByForeignIndex(context.Background(), issue.RepoID, foreignIndex) - assert.NoError(t, err) - assert.EqualValues(t, found.Index, issue.Index) -} - func TestMilestoneList_LoadTotalTrackedTimes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) miles := issues_model.MilestoneList{ diff --git a/models/issues/issue_xref.go b/models/issues/issue_xref.go index a965cf7340d5..21ee24210f83 100644 --- a/models/issues/issue_xref.go +++ b/models/issues/issue_xref.go @@ -121,7 +121,7 @@ func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossRefe RefAction: xref.Action, RefIsPull: ctx.OrigIssue.IsPull, } - _, err := CreateCommentCtx(stdCtx, opts) + _, err := CreateComment(stdCtx, opts) if err != nil { return err } @@ -148,7 +148,7 @@ func (issue *Issue) getCrossReferences(stdCtx context.Context, ctx *crossReferen refRepo = ctx.OrigIssue.Repo } else { // Issues in other repositories - refRepo, err = repo_model.GetRepositoryByOwnerAndNameCtx(stdCtx, ref.Owner, ref.Name) + refRepo, err = repo_model.GetRepositoryByOwnerAndName(stdCtx, ref.Owner, ref.Name) if err != nil { if repo_model.IsErrRepoNotExist(err) { continue diff --git a/models/issues/label.go b/models/issues/label.go index e5583ff00f61..dbb7a139effd 100644 --- a/models/issues/label.go +++ b/models/issues/label.go @@ -613,7 +613,7 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m Label: label, Content: "1", } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return err } @@ -714,7 +714,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use Issue: issue, Label: label, } - if _, err = CreateCommentCtx(ctx, opts); err != nil { + if _, err = CreateComment(ctx, opts); err != nil { return err } diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 7c2ce407e688..8255db38f913 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -284,7 +284,7 @@ func DeleteMilestoneByRepoID(repoID, id int64) error { return err } - repo, err := repo_model.GetRepositoryByID(m.RepoID) + repo, err := repo_model.GetRepositoryByID(db.DefaultContext, m.RepoID) if err != nil { return err } diff --git a/models/issues/pull.go b/models/issues/pull.go index 9105dd4d3a6e..7af9400d17c8 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -223,7 +223,7 @@ func (pr *PullRequest) MustHeadUserName(ctx context.Context) string { // Note: don't try to get Issue because will end up recursive querying. func (pr *PullRequest) LoadAttributes(ctx context.Context) (err error) { if pr.HasMerged && pr.Merger == nil { - pr.Merger, err = user_model.GetUserByIDCtx(ctx, pr.MergerID) + pr.Merger, err = user_model.GetUserByID(ctx, pr.MergerID) if user_model.IsErrUserNotExist(err) { pr.MergerID = -1 pr.Merger = user_model.NewGhostUser() @@ -248,9 +248,9 @@ func (pr *PullRequest) LoadHeadRepo(ctx context.Context) (err error) { } } - pr.HeadRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.HeadRepoID) + pr.HeadRepo, err = repo_model.GetRepositoryByID(ctx, pr.HeadRepoID) if err != nil && !repo_model.IsErrRepoNotExist(err) { // Head repo maybe deleted, but it should still work - return fmt.Errorf("getRepositoryByID(head): %w", err) + return fmt.Errorf("GetRepositoryByID(head): %w", err) } pr.isHeadRepoLoaded = true } @@ -273,7 +273,7 @@ func (pr *PullRequest) LoadBaseRepo(ctx context.Context) (err error) { return nil } - pr.BaseRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.BaseRepoID) + pr.BaseRepo, err = repo_model.GetRepositoryByID(ctx, pr.BaseRepoID) if err != nil { return fmt.Errorf("repo_model.GetRepositoryByID(base): %w", err) } @@ -294,18 +294,13 @@ func (pr *PullRequest) LoadIssue(ctx context.Context) (err error) { } // LoadProtectedBranch loads the protected branch of the base branch -func (pr *PullRequest) LoadProtectedBranch() (err error) { - return pr.LoadProtectedBranchCtx(db.DefaultContext) -} - -// LoadProtectedBranchCtx loads the protected branch of the base branch -func (pr *PullRequest) LoadProtectedBranchCtx(ctx context.Context) (err error) { +func (pr *PullRequest) LoadProtectedBranch(ctx context.Context) (err error) { if pr.ProtectedBranch == nil { if pr.BaseRepo == nil { if pr.BaseRepoID == 0 { return nil } - pr.BaseRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.BaseRepoID) + pr.BaseRepo, err = repo_model.GetRepositoryByID(ctx, pr.BaseRepoID) if err != nil { return } diff --git a/models/issues/reaction.go b/models/issues/reaction.go index 381881ff6193..293dfa3fd11a 100644 --- a/models/issues/reaction.go +++ b/models/issues/reaction.go @@ -75,7 +75,7 @@ func (r *Reaction) LoadUser() (*user_model.User, error) { if r.User != nil { return r.User, nil } - user, err := user_model.GetUserByIDCtx(db.DefaultContext, r.UserID) + user, err := user_model.GetUserByID(db.DefaultContext, r.UserID) if err != nil { return nil, err } diff --git a/models/issues/review.go b/models/issues/review.go index 0b50763fdc3e..7dee28fe976d 100644 --- a/models/issues/review.go +++ b/models/issues/review.go @@ -158,7 +158,7 @@ func (r *Review) LoadReviewer(ctx context.Context) (err error) { if r.ReviewerID == 0 || r.Reviewer != nil { return } - r.Reviewer, err = user_model.GetUserByIDCtx(ctx, r.ReviewerID) + r.Reviewer, err = user_model.GetUserByID(ctx, r.ReviewerID) return err } @@ -263,7 +263,7 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo if err != nil { return false, err } - if err = pr.LoadProtectedBranchCtx(ctx); err != nil { + if err = pr.LoadProtectedBranch(ctx); err != nil { return false, err } if pr.ProtectedBranch == nil { @@ -271,7 +271,7 @@ func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo } for _, reviewer := range reviewers { - official, err := git_model.IsUserOfficialReviewerCtx(ctx, pr.ProtectedBranch, reviewer) + official, err := git_model.IsUserOfficialReviewer(ctx, pr.ProtectedBranch, reviewer) if official || err != nil { return official, err } @@ -286,7 +286,7 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio if err != nil { return false, err } - if err = pr.LoadProtectedBranchCtx(ctx); err != nil { + if err = pr.LoadProtectedBranch(ctx); err != nil { return false, err } if pr.ProtectedBranch == nil { @@ -294,7 +294,7 @@ func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio } if !pr.ProtectedBranch.EnableApprovalsWhitelist { - return team.UnitAccessModeCtx(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil + return team.UnitAccessMode(ctx, unit.TypeCode) >= perm.AccessModeWrite, nil } return base.Int64sContains(pr.ProtectedBranch.ApprovalsWhitelistTeamIDs, team.ID), nil @@ -436,7 +436,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co } } - comm, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comm, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReview, Doer: doer, Content: review.Content, @@ -692,7 +692,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, return nil, err } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -746,7 +746,7 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen } } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -804,7 +804,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ } } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -814,7 +814,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ ReviewID: review.ID, }) if err != nil { - return nil, fmt.Errorf("CreateCommentCtx(): %w", err) + return nil, fmt.Errorf("CreateComment(): %w", err) } return comment, committer.Commit() @@ -864,7 +864,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us return nil, committer.Commit() } - comment, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + comment, err := CreateComment(ctx, &CreateCommentOptions{ Type: CommentTypeReviewRequest, Doer: doer, Repo: issue.Repo, @@ -873,7 +873,7 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us AssigneeTeamID: reviewer.ID, // Use AssigneeTeamID as reviewer team ID }) if err != nil { - return nil, fmt.Errorf("CreateCommentCtx(): %w", err) + return nil, fmt.Errorf("CreateComment(): %w", err) } return comment, committer.Commit() diff --git a/models/issues/stopwatch.go b/models/issues/stopwatch.go index 8a8fdca339cf..6bf936c5d41b 100644 --- a/models/issues/stopwatch.go +++ b/models/issues/stopwatch.go @@ -196,7 +196,7 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Doer: user, Issue: issue, Repo: issue.Repo, @@ -246,7 +246,7 @@ func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Doer: user, Issue: issue, Repo: issue.Repo, @@ -287,7 +287,7 @@ func cancelStopwatch(ctx context.Context, user *user_model.User, issue *Issue) e return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Doer: user, Issue: issue, Repo: issue.Repo, diff --git a/models/issues/stopwatch_test.go b/models/issues/stopwatch_test.go index 7745bc513c8b..ec2778aa81f5 100644 --- a/models/issues/stopwatch_test.go +++ b/models/issues/stopwatch_test.go @@ -18,7 +18,7 @@ import ( func TestCancelStopwatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user1, err := user_model.GetUserByID(1) + user1, err := user_model.GetUserByID(db.DefaultContext, 1) assert.NoError(t, err) issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1) @@ -58,9 +58,9 @@ func TestHasUserStopwatch(t *testing.T) { func TestCreateOrStopIssueStopwatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user2, err := user_model.GetUserByID(2) + user2, err := user_model.GetUserByID(db.DefaultContext, 2) assert.NoError(t, err) - user3, err := user_model.GetUserByID(3) + user3, err := user_model.GetUserByID(db.DefaultContext, 3) assert.NoError(t, err) issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1) diff --git a/models/issues/tracked_time.go b/models/issues/tracked_time.go index 6d2597545914..ac65d654f20a 100644 --- a/models/issues/tracked_time.go +++ b/models/issues/tracked_time.go @@ -5,6 +5,7 @@ package issues import ( "context" + "errors" "time" "code.gitea.io/gitea/models/db" @@ -46,33 +47,41 @@ func (t *TrackedTime) LoadAttributes() (err error) { } func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) { + // Load the issue if t.Issue == nil { t.Issue, err = GetIssueByID(ctx, t.IssueID) - if err != nil { - return + if err != nil && !errors.Is(err, util.ErrNotExist) { + return err } + } + // Now load the repo for the issue (which we may have just loaded) + if t.Issue != nil { err = t.Issue.LoadRepo(ctx) - if err != nil { - return + if err != nil && !errors.Is(err, util.ErrNotExist) { + return err } } + // Load the user if t.User == nil { - t.User, err = user_model.GetUserByIDCtx(ctx, t.UserID) + t.User, err = user_model.GetUserByID(ctx, t.UserID) if err != nil { - return + if !errors.Is(err, util.ErrNotExist) { + return err + } + t.User = user_model.NewGhostUser() } } - return err + return nil } // LoadAttributes load Issue, User -func (tl TrackedTimeList) LoadAttributes() (err error) { +func (tl TrackedTimeList) LoadAttributes() error { for _, t := range tl { - if err = t.LoadAttributes(); err != nil { + if err := t.LoadAttributes(); err != nil { return err } } - return err + return nil } // FindTrackedTimesOptions represent the filters for tracked times. If an ID is 0 it will be ignored. @@ -163,7 +172,7 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim return nil, err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Issue: issue, Repo: issue.Repo, Doer: user, @@ -205,7 +214,7 @@ func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]string, totalTimes := make(map[*user_model.User]string) // Fetching User and making time human readable for userID, total := range totalTimesByUser { - user, err := user_model.GetUserByID(userID) + user, err := user_model.GetUserByID(db.DefaultContext, userID) if err != nil { if user_model.IsErrUserNotExist(err) { continue @@ -241,7 +250,7 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { if err := issue.LoadRepo(ctx); err != nil { return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Issue: issue, Repo: issue.Repo, Doer: user, @@ -270,7 +279,7 @@ func DeleteTime(t *TrackedTime) error { return err } - if _, err := CreateCommentCtx(ctx, &CreateCommentOptions{ + if _, err := CreateComment(ctx, &CreateCommentOptions{ Issue: t.Issue, Repo: t.Issue.Repo, Doer: t.User, diff --git a/models/issues/tracked_time_test.go b/models/issues/tracked_time_test.go index b3174c7c82da..becfd79d41b0 100644 --- a/models/issues/tracked_time_test.go +++ b/models/issues/tracked_time_test.go @@ -18,7 +18,7 @@ import ( func TestAddTime(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - user3, err := user_model.GetUserByID(3) + user3, err := user_model.GetUserByID(db.DefaultContext, 3) assert.NoError(t, err) issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1) diff --git a/models/migrate.go b/models/migrate.go index b1b556812648..82cacd4a75b2 100644 --- a/models/migrate.go +++ b/models/migrate.go @@ -83,13 +83,6 @@ func insertIssue(ctx context.Context, issue *issues_model.Issue) error { } } - if issue.ForeignReference != nil { - issue.ForeignReference.LocalIndex = issue.Index - if _, err := sess.Insert(issue.ForeignReference); err != nil { - return err - } - } - return nil } diff --git a/models/migrate_test.go b/models/migrate_test.go index 48cd905e4c0d..42102f9a7d22 100644 --- a/models/migrate_test.go +++ b/models/migrate_test.go @@ -4,11 +4,9 @@ package models import ( - "strconv" "testing" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/foreignreference" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -48,7 +46,6 @@ func assertCreateIssues(t *testing.T, isPull bool) { UserID: owner.ID, } - foreignIndex := int64(12345) title := "issuetitle1" is := &issues_model.Issue{ RepoID: repo.ID, @@ -62,20 +59,11 @@ func assertCreateIssues(t *testing.T, isPull bool) { IsClosed: true, Labels: []*issues_model.Label{label}, Reactions: []*issues_model.Reaction{reaction}, - ForeignReference: &foreignreference.ForeignReference{ - ForeignIndex: strconv.FormatInt(foreignIndex, 10), - RepoID: repo.ID, - Type: foreignreference.TypeIssue, - }, } err := InsertIssues(is) assert.NoError(t, err) i := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{Title: title}) - assert.Nil(t, i.ForeignReference) - err = i.LoadAttributes(db.DefaultContext) - assert.NoError(t, err) - assert.EqualValues(t, strconv.FormatInt(foreignIndex, 10), i.ForeignReference.ForeignIndex) unittest.AssertExistsAndLoadBean(t, &issues_model.Reaction{Type: "heart", UserID: owner.ID, IssueID: i.ID}) } diff --git a/models/migrations/base/hash.go b/models/migrations/base/hash.go index 164f826b45d0..00fd1efd4a3b 100644 --- a/models/migrations/base/hash.go +++ b/models/migrations/base/hash.go @@ -5,12 +5,12 @@ package base import ( "crypto/sha256" - "fmt" + "encoding/hex" "golang.org/x/crypto/pbkdf2" ) func HashToken(token, salt string) string { tempHash := pbkdf2.Key([]byte(token), []byte(salt), 10000, 50, sha256.New) - return fmt.Sprintf("%x", tempHash) + return hex.EncodeToString(tempHash) } diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index e718355f8349..9d9c8f5165e4 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -442,6 +442,10 @@ var migrations = []Migration{ NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable), // v235 -> v236 NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken), + // v236 -> v237 + NewMigration("Create secrets table", v1_19.CreateSecretsTable), + // v237 -> v238 + NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_10/v96.go b/models/migrations/v1_10/v96.go index 2abd260be41a..422defe8387a 100644 --- a/models/migrations/v1_10/v96.go +++ b/models/migrations/v1_10/v96.go @@ -30,19 +30,19 @@ func DeleteOrphanedAttachments(x *xorm.Engine) error { } for { - attachements := make([]Attachment, 0, limit) + attachments := make([]Attachment, 0, limit) if err := sess.Where("`issue_id` = 0 and (`release_id` = 0 or `release_id` not in (select `id` from `release`))"). Cols("id, uuid").Limit(limit). Asc("id"). - Find(&attachements); err != nil { + Find(&attachments); err != nil { return err } - if len(attachements) == 0 { + if len(attachments) == 0 { return nil } ids := make([]int64, 0, limit) - for _, attachment := range attachements { + for _, attachment := range attachments { ids = append(ids, attachment.ID) } if len(ids) > 0 { @@ -51,13 +51,13 @@ func DeleteOrphanedAttachments(x *xorm.Engine) error { } } - for _, attachment := range attachements { + for _, attachment := range attachments { uuid := attachment.UUID if err := util.RemoveAll(filepath.Join(setting.Attachment.Path, uuid[0:1], uuid[1:2], uuid)); err != nil { return err } } - if len(attachements) < limit { + if len(attachments) < limit { return nil } } diff --git a/models/migrations/v1_14/v166.go b/models/migrations/v1_14/v166.go index 1eb726334760..f797930d6d5b 100644 --- a/models/migrations/v1_14/v166.go +++ b/models/migrations/v1_14/v166.go @@ -5,7 +5,7 @@ package v1_14 //nolint import ( "crypto/sha256" - "fmt" + "encoding/hex" "golang.org/x/crypto/argon2" "golang.org/x/crypto/bcrypt" @@ -53,7 +53,7 @@ func RecalculateUserEmptyPWD(x *xorm.Engine) (err error) { tempPasswd = pbkdf2.Key([]byte(passwd), []byte(salt), 10000, 50, sha256.New) } - return fmt.Sprintf("%x", tempPasswd) + return hex.EncodeToString(tempPasswd) } // ValidatePassword checks if given password matches the one belongs to the user. diff --git a/models/migrations/v1_17/main_test.go b/models/migrations/v1_17/main_test.go index e6871cacf2e0..79cb3fa07886 100644 --- a/models/migrations/v1_17/main_test.go +++ b/models/migrations/v1_17/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "testing" diff --git a/models/migrations/v1_17/v211.go b/models/migrations/v1_17/v211.go index 227de4984fc5..16ec51849366 100644 --- a/models/migrations/v1_17/v211.go +++ b/models/migrations/v1_17/v211.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "fmt" diff --git a/models/migrations/v1_17/v212.go b/models/migrations/v1_17/v212.go index a00d29cd2fd0..536ba0a2c42d 100644 --- a/models/migrations/v1_17/v212.go +++ b/models/migrations/v1_17/v212.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/modules/timeutil" diff --git a/models/migrations/v1_17/v213.go b/models/migrations/v1_17/v213.go index 2ed56104cf7e..8607fdba47f2 100644 --- a/models/migrations/v1_17/v213.go +++ b/models/migrations/v1_17/v213.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v214.go b/models/migrations/v1_17/v214.go index e619b805a619..3b2351d16040 100644 --- a/models/migrations/v1_17/v214.go +++ b/models/migrations/v1_17/v214.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_17/v215.go b/models/migrations/v1_17/v215.go index 43e5b636c9bf..0244be216c44 100644 --- a/models/migrations/v1_17/v215.go +++ b/models/migrations/v1_17/v215.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/models/pull" diff --git a/models/migrations/v1_17/v216.go b/models/migrations/v1_17/v216.go index 388cb971e705..59b21d9b2c46 100644 --- a/models/migrations/v1_17/v216.go +++ b/models/migrations/v1_17/v216.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint // This migration added non-ideal indices to the action table which on larger datasets slowed things down // it has been superceded by v218.go diff --git a/models/migrations/v1_17/v217.go b/models/migrations/v1_17/v217.go index bbb40251fbe8..3ca9215f0937 100644 --- a/models/migrations/v1_17/v217.go +++ b/models/migrations/v1_17/v217.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_17/v218.go b/models/migrations/v1_17/v218.go index 4d5e77070bbc..675fd1df94fb 100644 --- a/models/migrations/v1_17/v218.go +++ b/models/migrations/v1_17/v218.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_17/v219.go b/models/migrations/v1_17/v219.go index c8aa2378c30a..a2165212cc9b 100644 --- a/models/migrations/v1_17/v219.go +++ b/models/migrations/v1_17/v219.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "time" diff --git a/models/migrations/v1_17/v220.go b/models/migrations/v1_17/v220.go index 31158509b87d..904ddc519293 100644 --- a/models/migrations/v1_17/v220.go +++ b/models/migrations/v1_17/v220.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( packages_model "code.gitea.io/gitea/models/packages" diff --git a/models/migrations/v1_17/v221.go b/models/migrations/v1_17/v221.go index ceb079f369d0..8a58b0f1056d 100644 --- a/models/migrations/v1_17/v221.go +++ b/models/migrations/v1_17/v221.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "encoding/base32" diff --git a/models/migrations/v1_17/v221_test.go b/models/migrations/v1_17/v221_test.go index 3215d74915f1..9ca54142e2d5 100644 --- a/models/migrations/v1_17/v221_test.go +++ b/models/migrations/v1_17/v221_test.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "encoding/base32" diff --git a/models/migrations/v1_17/v222.go b/models/migrations/v1_17/v222.go index 558c0d9adcd2..d1b77d845d16 100644 --- a/models/migrations/v1_17/v222.go +++ b/models/migrations/v1_17/v222.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "context" diff --git a/models/migrations/v1_17/v223.go b/models/migrations/v1_17/v223.go index c83deb255fe0..a23d9916b383 100644 --- a/models/migrations/v1_17/v223.go +++ b/models/migrations/v1_17/v223.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_17 // nolint +package v1_17 //nolint import ( "context" diff --git a/models/migrations/v1_18/main_test.go b/models/migrations/v1_18/main_test.go index aec48845bf7f..f71a21d1fb24 100644 --- a/models/migrations/v1_18/main_test.go +++ b/models/migrations/v1_18/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "testing" diff --git a/models/migrations/v1_18/v224.go b/models/migrations/v1_18/v224.go index f37b773effa1..afd34a5db09c 100644 --- a/models/migrations/v1_18/v224.go +++ b/models/migrations/v1_18/v224.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_18/v225.go b/models/migrations/v1_18/v225.go index 2ff5f4c7f7c6..786772c143bd 100644 --- a/models/migrations/v1_18/v225.go +++ b/models/migrations/v1_18/v225.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_18/v226.go b/models/migrations/v1_18/v226.go index 536346a97a6b..f87e24b11de9 100644 --- a/models/migrations/v1_18/v226.go +++ b/models/migrations/v1_18/v226.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_18/v227.go b/models/migrations/v1_18/v227.go index b4da88ee0aed..c938028323fd 100644 --- a/models/migrations/v1_18/v227.go +++ b/models/migrations/v1_18/v227.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "fmt" diff --git a/models/migrations/v1_18/v228.go b/models/migrations/v1_18/v228.go index 3144310507f0..58d3257528ae 100644 --- a/models/migrations/v1_18/v228.go +++ b/models/migrations/v1_18/v228.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "code.gitea.io/gitea/modules/timeutil" diff --git a/models/migrations/v1_18/v230.go b/models/migrations/v1_18/v230.go index 2d2248fcb384..cf94926be17c 100644 --- a/models/migrations/v1_18/v230.go +++ b/models/migrations/v1_18/v230.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_18 // nolint +package v1_18 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_19/main_test.go b/models/migrations/v1_19/main_test.go index 3d08ec2f5e96..59f42af11162 100644 --- a/models/migrations/v1_19/main_test.go +++ b/models/migrations/v1_19/main_test.go @@ -1,7 +1,7 @@ // Copyright 2021 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 // nolint +package v1_19 //nolint import ( "testing" diff --git a/models/migrations/v1_19/v232.go b/models/migrations/v1_19/v232.go index 9feb5343bcd8..89b595c54375 100644 --- a/models/migrations/v1_19/v232.go +++ b/models/migrations/v1_19/v232.go @@ -1,7 +1,7 @@ // Copyright 2022 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_19 // nolint +package v1_19 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_19/v234.go b/models/migrations/v1_19/v234.go index 9d609c58d3d2..4e98a2b7a9fd 100644 --- a/models/migrations/v1_19/v234.go +++ b/models/migrations/v1_19/v234.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package v1_19 //nolint diff --git a/models/migrations/v1_19/v235.go b/models/migrations/v1_19/v235.go index b43ee32a56e1..3715de3920c8 100644 --- a/models/migrations/v1_19/v235.go +++ b/models/migrations/v1_19/v235.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package v1_19 //nolint diff --git a/models/migrations/v1_19/v236.go b/models/migrations/v1_19/v236.go new file mode 100644 index 000000000000..f172a85b1fc9 --- /dev/null +++ b/models/migrations/v1_19/v236.go @@ -0,0 +1,23 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_19 //nolint + +import ( + "code.gitea.io/gitea/modules/timeutil" + + "xorm.io/xorm" +) + +func CreateSecretsTable(x *xorm.Engine) error { + type Secret struct { + ID int64 + OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"` + RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"` + Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"` + Data string `xorm:"LONGTEXT"` + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` + } + + return x.Sync(new(Secret)) +} diff --git a/models/migrations/v1_19/v237.go b/models/migrations/v1_19/v237.go new file mode 100644 index 000000000000..b23c765aa5aa --- /dev/null +++ b/models/migrations/v1_19/v237.go @@ -0,0 +1,15 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_19 //nolint + +import ( + "xorm.io/xorm" +) + +func DropForeignReferenceTable(x *xorm.Engine) error { + // Drop the table introduced in `v211`, it's considered badly designed and doesn't look like to be used. + // See: https://github.com/go-gitea/gitea/issues/21086#issuecomment-1318217453 + type ForeignReference struct{} + return x.DropTables(new(ForeignReference)) +} diff --git a/models/migrations/v1_6/v70.go b/models/migrations/v1_6/v70.go index 166772ad700a..fec88266ba6e 100644 --- a/models/migrations/v1_6/v70.go +++ b/models/migrations/v1_6/v70.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 // nolint +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_6/v71.go b/models/migrations/v1_6/v71.go index 57586c5c3265..effd2ebf9959 100644 --- a/models/migrations/v1_6/v71.go +++ b/models/migrations/v1_6/v71.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 // nolint +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_6/v72.go b/models/migrations/v1_6/v72.go index b7428150bef7..ce963eb37148 100644 --- a/models/migrations/v1_6/v72.go +++ b/models/migrations/v1_6/v72.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_6 // nolint +package v1_6 //nolint import ( "fmt" diff --git a/models/migrations/v1_7/v73.go b/models/migrations/v1_7/v73.go index 0c5775c2b2dd..1013daedbd63 100644 --- a/models/migrations/v1_7/v73.go +++ b/models/migrations/v1_7/v73.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 // nolint +package v1_7 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_7/v74.go b/models/migrations/v1_7/v74.go index aeca5448e106..bdd89d1f342a 100644 --- a/models/migrations/v1_7/v74.go +++ b/models/migrations/v1_7/v74.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 // nolint +package v1_7 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_7/v75.go b/models/migrations/v1_7/v75.go index bad8010090a8..fa7430970c91 100644 --- a/models/migrations/v1_7/v75.go +++ b/models/migrations/v1_7/v75.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_7 // nolint +package v1_7 //nolint import ( "xorm.io/builder" diff --git a/models/migrations/v1_8/v76.go b/models/migrations/v1_8/v76.go index 451268938602..f35856cc606c 100644 --- a/models/migrations/v1_8/v76.go +++ b/models/migrations/v1_8/v76.go @@ -1,7 +1,7 @@ // Copyright 2018 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "fmt" diff --git a/models/migrations/v1_8/v77.go b/models/migrations/v1_8/v77.go index f92dfed882dd..2305984c129e 100644 --- a/models/migrations/v1_8/v77.go +++ b/models/migrations/v1_8/v77.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "xorm.io/xorm" diff --git a/models/migrations/v1_8/v78.go b/models/migrations/v1_8/v78.go index 8bc0221412e7..637db451f5b8 100644 --- a/models/migrations/v1_8/v78.go +++ b/models/migrations/v1_8/v78.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "code.gitea.io/gitea/models/migrations/base" diff --git a/models/migrations/v1_8/v79.go b/models/migrations/v1_8/v79.go index 9cebca185376..e708d7229464 100644 --- a/models/migrations/v1_8/v79.go +++ b/models/migrations/v1_8/v79.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "code.gitea.io/gitea/modules/setting" diff --git a/models/migrations/v1_8/v80.go b/models/migrations/v1_8/v80.go index ec9726d88920..7f2e0ff72bf0 100644 --- a/models/migrations/v1_8/v80.go +++ b/models/migrations/v1_8/v80.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import "xorm.io/xorm" diff --git a/models/migrations/v1_8/v81.go b/models/migrations/v1_8/v81.go index ff050386b43c..a100dc1ef71f 100644 --- a/models/migrations/v1_8/v81.go +++ b/models/migrations/v1_8/v81.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_8 // nolint +package v1_8 //nolint import ( "fmt" diff --git a/models/migrations/v1_9/v82.go b/models/migrations/v1_9/v82.go index b0dffe6035f6..26806dd64505 100644 --- a/models/migrations/v1_9/v82.go +++ b/models/migrations/v1_9/v82.go @@ -1,7 +1,7 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package v1_9 // nolint +package v1_9 //nolint import ( "fmt" diff --git a/models/org.go b/models/org.go index 1c9383fe8d26..5f0e678ab45b 100644 --- a/models/org.go +++ b/models/org.go @@ -43,7 +43,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error { return err } if t.NumMembers == 1 { - if err := t.GetMembersCtx(ctx); err != nil { + if err := t.LoadMembers(ctx); err != nil { return err } if t.Members[0].ID == userID { diff --git a/models/org_team.go b/models/org_team.go index 62376192ab5c..a5a2575eec18 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -41,7 +41,7 @@ func AddRepository(ctx context.Context, t *organization.Team, repo *repo_model.R // Make all team members watch this repo if enabled in global settings if setting.Service.AutoWatchNewRepos { - if err = t.GetMembersCtx(ctx); err != nil { + if err = t.LoadMembers(ctx); err != nil { return fmt.Errorf("getMembers: %w", err) } for _, u := range t.Members { @@ -213,7 +213,7 @@ func RemoveRepository(t *organization.Team, repoID int64) error { return nil } - repo, err := repo_model.GetRepositoryByID(repoID) + repo, err := repo_model.GetRepositoryByID(db.DefaultContext, repoID) if err != nil { return err } @@ -349,8 +349,8 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err // Update access for team members if needed. if authChanged { - if err = t.GetRepositoriesCtx(ctx); err != nil { - return fmt.Errorf("getRepositories: %w", err) + if err = t.LoadRepositories(ctx); err != nil { + return fmt.Errorf("LoadRepositories: %w", err) } for _, repo := range t.Repos { @@ -381,11 +381,11 @@ func DeleteTeam(t *organization.Team) error { defer committer.Close() sess := db.GetEngine(ctx) - if err := t.GetRepositoriesCtx(ctx); err != nil { + if err := t.LoadRepositories(ctx); err != nil { return err } - if err := t.GetMembersCtx(ctx); err != nil { + if err := t.LoadMembers(ctx); err != nil { return err } @@ -516,10 +516,16 @@ func AddTeamMember(team *organization.Team, userID int64) error { } } - // watch could be failed, so run it in a goroutine + 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.GetRepositoriesCtx(db.DefaultContext); err != nil { + if err := team.LoadRepositories(db.DefaultContext); err != nil { log.Error("getRepositories failed: %v", err) } go func(repos []*repo_model.Repository) { @@ -531,7 +537,7 @@ func AddTeamMember(team *organization.Team, userID int64) error { }(team.Repos) } - return committer.Commit() + return nil } func removeTeamMember(ctx context.Context, team *organization.Team, userID int64) error { @@ -548,7 +554,7 @@ func removeTeamMember(ctx context.Context, team *organization.Team, userID int64 team.NumMembers-- - if err := team.GetRepositoriesCtx(ctx); err != nil { + if err := team.LoadRepositories(ctx); err != nil { return err } diff --git a/models/organization/org.go b/models/organization/org.go index ef7b834ad35c..9d9e9cda46a4 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" + secret_model "code.gitea.io/gitea/models/secret" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -106,7 +107,7 @@ func (org *Organization) IsOrgMember(uid int64) (bool, error) { // CanCreateOrgRepo returns true if given user can create repo in organization func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) { - return CanCreateOrgRepo(org.ID, uid) + return CanCreateOrgRepo(db.DefaultContext, org.ID, uid) } func (org *Organization) getTeam(ctx context.Context, name string) (*Team, error) { @@ -370,6 +371,7 @@ func DeleteOrganization(ctx context.Context, org *Organization) error { &TeamUser{OrgID: org.ID}, &TeamUnit{OrgID: org.ID}, &TeamInvite{OrgID: org.ID}, + &secret_model.Secret{OwnerID: org.ID}, ); err != nil { return fmt.Errorf("DeleteBeans: %w", err) } @@ -701,7 +703,7 @@ func AccessibleReposEnv(ctx context.Context, org *Organization, userID int64) (A var user *user_model.User if userID > 0 { - u, err := user_model.GetUserByIDCtx(ctx, userID) + u, err := user_model.GetUserByID(ctx, userID) if err != nil { return nil, err } diff --git a/models/organization/org_user.go b/models/organization/org_user.go index d514e401ba6a..e5cbfe6c0f3e 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -73,8 +73,8 @@ func IsPublicMembership(orgID, uid int64) (bool, error) { } // CanCreateOrgRepo returns true if user can create repo in organization -func CanCreateOrgRepo(orgID, uid int64) (bool, error) { - return db.GetEngine(db.DefaultContext). +func CanCreateOrgRepo(ctx context.Context, orgID, uid int64) (bool, error) { + return db.GetEngine(ctx). Where(builder.Eq{"team.can_create_org_repo": true}). Join("INNER", "team_user", "team_user.team_id = team.id"). And("team_user.uid = ?", uid). diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go index 1da17631e365..edd0aa3ea0cb 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -37,7 +37,7 @@ func TestUserIsPublicMember(t *testing.T) { } func testUserIsPublicMember(t *testing.T, uid, orgID int64, expected bool) { - user, err := user_model.GetUserByID(uid) + user, err := user_model.GetUserByID(db.DefaultContext, uid) assert.NoError(t, err) is, err := organization.IsPublicMembership(orgID, user.ID) assert.NoError(t, err) @@ -65,7 +65,7 @@ func TestIsUserOrgOwner(t *testing.T) { } func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) { - user, err := user_model.GetUserByID(uid) + user, err := user_model.GetUserByID(db.DefaultContext, uid) assert.NoError(t, err) is, err := organization.IsOrganizationOwner(db.DefaultContext, orgID, user.ID) assert.NoError(t, err) diff --git a/models/organization/team.go b/models/organization/team.go index f6d71845df23..55d3f1727665 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -222,8 +222,8 @@ func (t *Team) IsMember(userID int64) bool { return isMember } -// GetRepositoriesCtx returns paginated repositories in team of organization. -func (t *Team) GetRepositoriesCtx(ctx context.Context) (err error) { +// LoadRepositories returns paginated repositories in team of organization. +func (t *Team) LoadRepositories(ctx context.Context) (err error) { if t.Repos != nil { return nil } @@ -233,8 +233,8 @@ func (t *Team) GetRepositoriesCtx(ctx context.Context) (err error) { return err } -// GetMembersCtx returns paginated members in team of organization. -func (t *Team) GetMembersCtx(ctx context.Context) (err error) { +// LoadMembers returns paginated members in team of organization. +func (t *Team) LoadMembers(ctx context.Context) (err error) { t.Members, err = GetTeamMembers(ctx, &SearchMembersOptions{ TeamID: t.ID, }) @@ -242,18 +242,12 @@ func (t *Team) GetMembersCtx(ctx context.Context) (err error) { } // UnitEnabled returns if the team has the given unit type enabled -func (t *Team) UnitEnabled(tp unit.Type) bool { - return t.UnitAccessMode(tp) > perm.AccessModeNone +func (t *Team) UnitEnabled(ctx context.Context, tp unit.Type) bool { + return t.UnitAccessMode(ctx, tp) > perm.AccessModeNone } // UnitAccessMode returns if the team has the given unit type enabled -// it is called in templates, should not be replaced by `UnitAccessModeCtx(ctx ...)` -func (t *Team) UnitAccessMode(tp unit.Type) perm.AccessMode { - return t.UnitAccessModeCtx(db.DefaultContext, tp) -} - -// UnitAccessModeCtx returns if the team has the given unit type enabled -func (t *Team) UnitAccessModeCtx(ctx context.Context, tp unit.Type) perm.AccessMode { +func (t *Team) UnitAccessMode(ctx context.Context, tp unit.Type) perm.AccessMode { if err := t.getUnits(ctx); err != nil { log.Warn("Error loading team (ID: %d) units: %s", t.ID, err.Error()) } diff --git a/models/organization/team_test.go b/models/organization/team_test.go index d324c6d0da18..c63b83aab777 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -42,7 +42,7 @@ func TestTeam_GetRepositories(t *testing.T) { test := func(teamID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, team.GetRepositoriesCtx(db.DefaultContext)) + assert.NoError(t, team.LoadRepositories(db.DefaultContext)) assert.Len(t, team.Repos, team.NumRepos) for _, repo := range team.Repos { unittest.AssertExistsAndLoadBean(t, &organization.TeamRepo{TeamID: teamID, RepoID: repo.ID}) @@ -57,7 +57,7 @@ func TestTeam_GetMembers(t *testing.T) { test := func(teamID int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, team.GetMembersCtx(db.DefaultContext)) + assert.NoError(t, team.LoadMembers(db.DefaultContext)) assert.Len(t, team.Members, team.NumMembers) for _, member := range team.Members { unittest.AssertExistsAndLoadBean(t, &organization.TeamUser{UID: member.ID, TeamID: teamID}) diff --git a/models/packages/descriptor.go b/models/packages/descriptor.go index 7ffed2d8aad5..34f1cad87dc4 100644 --- a/models/packages/descriptor.go +++ b/models/packages/descriptor.go @@ -85,15 +85,15 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc if err != nil { return nil, err } - o, err := user_model.GetUserByIDCtx(ctx, p.OwnerID) + o, err := user_model.GetUserByID(ctx, p.OwnerID) if err != nil { return nil, err } - repository, err := repo_model.GetRepositoryByIDCtx(ctx, p.RepoID) + repository, err := repo_model.GetRepositoryByID(ctx, p.RepoID) if err != nil && !repo_model.IsErrRepoNotExist(err) { return nil, err } - creator, err := user_model.GetUserByIDCtx(ctx, pv.CreatorID) + creator, err := user_model.GetUserByID(ctx, pv.CreatorID) if err != nil { return nil, err } diff --git a/models/packages/package_cleanup_rule.go b/models/packages/package_cleanup_rule.go index ab45226cf150..9bd512755de5 100644 --- a/models/packages/package_cleanup_rule.go +++ b/models/packages/package_cleanup_rule.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package packages diff --git a/models/packages/package_version.go b/models/packages/package_version.go index a2a8a45d8f38..928f9d47d6cd 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -302,9 +302,14 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P cond := opts.toConds(). And(builder.Expr("pv2.id IS NULL")) + joinCond := builder.Expr("package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))") + if !opts.IsInternal.IsNone() { + joinCond = joinCond.And(builder.Eq{"pv2.is_internal": opts.IsInternal.IsTrue()}) + } + sess := db.GetEngine(ctx). Table("package_version"). - Join("LEFT", "package_version pv2", "package_version.package_id = pv2.package_id AND (package_version.created_unix < pv2.created_unix OR (package_version.created_unix = pv2.created_unix AND package_version.id < pv2.id))"). + Join("LEFT", "package_version pv2", joinCond). Join("INNER", "package", "package.id = package_version.package_id"). Where(cond) diff --git a/models/perm/access/access.go b/models/perm/access/access.go index 55d3f78e01d2..48ecf78a8c89 100644 --- a/models/perm/access/access.go +++ b/models/perm/access/access.go @@ -171,7 +171,7 @@ func RecalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i continue } - if err = t.GetMembersCtx(ctx); err != nil { + if err = t.LoadMembers(ctx); err != nil { return fmt.Errorf("getMembers '%d': %w", t.ID, err) } for _, m := range t.Members { diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index 58c4299d165c..a6bf9b6744a5 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -244,7 +244,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use for _, u := range repo.Units { var found bool for _, team := range teams { - teamMode := team.UnitAccessModeCtx(ctx, u.Type) + teamMode := team.UnitAccessMode(ctx, u.Type) if teamMode > perm_model.AccessModeNone { m := perm.UnitsMode[u.Type] if m < teamMode { @@ -364,7 +364,7 @@ func HasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) ( var user *user_model.User var err error if userID > 0 { - user, err = user_model.GetUserByIDCtx(ctx, userID) + user, err = user_model.GetUserByID(ctx, userID) if err != nil { return false, err } diff --git a/models/project/project.go b/models/project/project.go index 0d655e333eb3..bcf1166408f8 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -298,47 +298,35 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error { return updateRepositoryProjectCount(ctx, p.RepoID) } -// DeleteProjectByID deletes a project from a repository. -func DeleteProjectByID(id int64) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - - if err := DeleteProjectByIDCtx(ctx, id); err != nil { - return err - } - - return committer.Commit() -} - -// DeleteProjectByIDCtx deletes a project from a repository. -func DeleteProjectByIDCtx(ctx context.Context, id int64) error { - p, err := GetProjectByID(ctx, id) - if err != nil { - if IsErrProjectNotExist(err) { - return nil +// DeleteProjectByID deletes a project from a repository. if it's not in a database +// transaction, it will start a new database transaction +func DeleteProjectByID(ctx context.Context, id int64) error { + return db.AutoTx(ctx, func(ctx context.Context) error { + p, err := GetProjectByID(ctx, id) + if err != nil { + if IsErrProjectNotExist(err) { + return nil + } + return err } - return err - } - if err := deleteProjectIssuesByProjectID(ctx, id); err != nil { - return err - } + if err := deleteProjectIssuesByProjectID(ctx, id); err != nil { + return err + } - if err := deleteBoardByProjectID(ctx, id); err != nil { - return err - } + if err := deleteBoardByProjectID(ctx, id); err != nil { + return err + } - if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil { - return err - } + if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil { + return err + } - return updateRepositoryProjectCount(ctx, p.RepoID) + return updateRepositoryProjectCount(ctx, p.RepoID) + }) } -func DeleteProjectByRepoIDCtx(ctx context.Context, repoID int64) error { +func DeleteProjectByRepoID(ctx context.Context, repoID int64) error { switch { case setting.Database.UseSQLite3: if _, err := db.GetEngine(ctx).Exec("DELETE FROM project_issue WHERE project_issue.id IN (SELECT project_issue.id FROM project_issue INNER JOIN project WHERE project.id = project_issue.project_id AND project.repo_id = ?)", repoID); err != nil { diff --git a/models/pull/automerge.go b/models/pull/automerge.go index d7e04eafa6ca..f68fb7c681e7 100644 --- a/models/pull/automerge.go +++ b/models/pull/automerge.go @@ -74,7 +74,7 @@ func GetScheduledMergeByPullID(ctx context.Context, pullID int64) (bool, *AutoMe return false, nil, err } - doer, err := user_model.GetUserByIDCtx(ctx, scheduledPRM.DoerID) + doer, err := user_model.GetUserByID(ctx, scheduledPRM.DoerID) if err != nil { return false, nil, err } diff --git a/models/repo.go b/models/repo.go index ca4f60a2f333..e95887077c95 100644 --- a/models/repo.go +++ b/models/repo.go @@ -21,6 +21,7 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" project_model "code.gitea.io/gitea/models/project" repo_model "code.gitea.io/gitea/models/repo" + secret_model "code.gitea.io/gitea/models/secret" system_model "code.gitea.io/gitea/models/system" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -52,7 +53,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { sess := db.GetEngine(ctx) // In case is a organization. - org, err := user_model.GetUserByIDCtx(ctx, uid) + org, err := user_model.GetUserByID(ctx, uid) if err != nil { return err } @@ -150,6 +151,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { &admin_model.Task{RepoID: repoID}, &repo_model.Watch{RepoID: repoID}, &webhook.Webhook{RepoID: repoID}, + &secret_model.Secret{RepoID: repoID}, ); err != nil { return fmt.Errorf("deleteBeans: %w", err) } @@ -191,7 +193,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { } } - if err := project_model.DeleteProjectByRepoIDCtx(ctx, repoID); err != nil { + if err := project_model.DeleteProjectByRepoID(ctx, repoID); err != nil { return fmt.Errorf("unable to delete projects for repo[%d]: %w", repoID, err) } @@ -443,7 +445,7 @@ func CheckRepoStats(ctx context.Context) error { }, // Repository.NumIssues { - statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, false), + statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_issues!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=?)", false), repoStatsCorrectNumIssues, "repository count 'num_issues'", }, @@ -455,7 +457,7 @@ func CheckRepoStats(ctx context.Context) error { }, // Repository.NumPulls { - statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", false, true), + statsQuery("SELECT repo.id FROM `repository` repo WHERE repo.num_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_pull=?)", true), repoStatsCorrectNumPulls, "repository count 'num_pulls'", }, @@ -523,7 +525,7 @@ func CheckRepoStats(ctx context.Context) error { } log.Trace("Updating repository count 'num_forks': %d", id) - repo, err := repo_model.GetRepositoryByID(id) + repo, err := repo_model.GetRepositoryByID(ctx, id) if err != nil { log.Error("repo_model.GetRepositoryByID[%d]: %v", id, err) continue @@ -618,7 +620,7 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error // Check if user has access to delete this key. if !doer.IsAdmin { - repo, err := repo_model.GetRepositoryByIDCtx(ctx, key.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, key.RepoID) if err != nil { return fmt.Errorf("GetRepositoryByID: %w", err) } diff --git a/models/repo/collaboration.go b/models/repo/collaboration.go index 04d92c415fec..29bcab70f36a 100644 --- a/models/repo/collaboration.go +++ b/models/repo/collaboration.go @@ -44,7 +44,7 @@ func GetCollaborators(ctx context.Context, repoID int64, listOptions db.ListOpti collaborators := make([]*Collaborator, 0, len(collaborations)) for _, c := range collaborations { - user, err := user_model.GetUserByIDCtx(ctx, c.UserID) + user, err := user_model.GetUserByID(ctx, c.UserID) if err != nil { if user_model.IsErrUserNotExist(err) { log.Warn("Inconsistent DB: User: %d is listed as collaborator of %-v but does not exist", c.UserID, repoID) @@ -99,55 +99,42 @@ func getCollaborations(ctx context.Context, repoID int64, listOptions db.ListOpt } // ChangeCollaborationAccessMode sets new access mode for the collaboration. -func ChangeCollaborationAccessModeCtx(ctx context.Context, repo *Repository, uid int64, mode perm.AccessMode) error { +func ChangeCollaborationAccessMode(ctx context.Context, repo *Repository, uid int64, mode perm.AccessMode) error { // Discard invalid input if mode <= perm.AccessModeNone || mode > perm.AccessModeOwner { return nil } - e := db.GetEngine(ctx) - - collaboration := &Collaboration{ - RepoID: repo.ID, - UserID: uid, - } - has, err := e.Get(collaboration) - if err != nil { - return fmt.Errorf("get collaboration: %w", err) - } else if !has { - return nil - } - - if collaboration.Mode == mode { - return nil - } - collaboration.Mode = mode - - if _, err = e. - ID(collaboration.ID). - Cols("mode"). - Update(collaboration); err != nil { - return fmt.Errorf("update collaboration: %w", err) - } else if _, err = e.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil { - return fmt.Errorf("update access table: %w", err) - } + return db.AutoTx(ctx, func(ctx context.Context) error { + e := db.GetEngine(ctx) - return nil -} - -// ChangeCollaborationAccessMode sets new access mode for the collaboration. -func ChangeCollaborationAccessMode(repo *Repository, uid int64, mode perm.AccessMode) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() + collaboration := &Collaboration{ + RepoID: repo.ID, + UserID: uid, + } + has, err := e.Get(collaboration) + if err != nil { + return fmt.Errorf("get collaboration: %w", err) + } else if !has { + return nil + } - if err := ChangeCollaborationAccessModeCtx(ctx, repo, uid, mode); err != nil { - return err - } + if collaboration.Mode == mode { + return nil + } + collaboration.Mode = mode + + if _, err = e. + ID(collaboration.ID). + Cols("mode"). + Update(collaboration); err != nil { + return fmt.Errorf("update collaboration: %w", err) + } else if _, err = e.Exec("UPDATE access SET mode = ? WHERE user_id = ? AND repo_id = ?", mode, uid, repo.ID); err != nil { + return fmt.Errorf("update access table: %w", err) + } - return committer.Commit() + return nil + }) } // IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go index d240e9cbef04..0a6444de858a 100644 --- a/models/repo/collaboration_test.go +++ b/models/repo/collaboration_test.go @@ -54,7 +54,7 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}) - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin)) collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode) @@ -62,9 +62,9 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID}) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessModeAdmin)) - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, unittest.NonexistentID, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, unittest.NonexistentID, perm.AccessModeAdmin)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } diff --git a/models/repo/fork_test.go b/models/repo/fork_test.go index d02bf91dd94d..e8dca204cc45 100644 --- a/models/repo/fork_test.go +++ b/models/repo/fork_test.go @@ -17,14 +17,14 @@ func TestGetUserFork(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // User13 has repo 11 forked from repo10 - repo, err := repo_model.GetRepositoryByID(10) + repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 10) assert.NoError(t, err) assert.NotNil(t, repo) repo, err = repo_model.GetUserFork(db.DefaultContext, repo.ID, 13) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = repo_model.GetRepositoryByID(9) + repo, err = repo_model.GetRepositoryByID(db.DefaultContext, 9) assert.NoError(t, err) assert.NotNil(t, repo) repo, err = repo_model.GetUserFork(db.DefaultContext, repo.ID, 13) diff --git a/models/repo/issue.go b/models/repo/issue.go index 0d27cc041e6c..6f6b565a00cf 100644 --- a/models/repo/issue.go +++ b/models/repo/issue.go @@ -6,7 +6,6 @@ package repo import ( "context" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" @@ -26,44 +25,34 @@ func (repo *Repository) CanEnableTimetracker() bool { } // IsTimetrackerEnabled returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs. -func (repo *Repository) IsTimetrackerEnabled() bool { - return repo.IsTimetrackerEnabledCtx(db.DefaultContext) -} - -// IsTimetrackerEnabledCtx returns whether or not the timetracker is enabled. It returns the default value from config if an error occurs. -func (repo *Repository) IsTimetrackerEnabledCtx(ctx context.Context) bool { +func (repo *Repository) IsTimetrackerEnabled(ctx context.Context) bool { if !setting.Service.EnableTimetracking { return false } var u *RepoUnit var err error - if u, err = repo.GetUnitCtx(ctx, unit.TypeIssues); err != nil { + if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { return setting.Service.DefaultEnableTimetracking } return u.IssuesConfig().EnableTimetracker } // AllowOnlyContributorsToTrackTime returns value of IssuesConfig or the default value -func (repo *Repository) AllowOnlyContributorsToTrackTime() bool { +func (repo *Repository) AllowOnlyContributorsToTrackTime(ctx context.Context) bool { var u *RepoUnit var err error - if u, err = repo.GetUnit(unit.TypeIssues); err != nil { + if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { return setting.Service.DefaultAllowOnlyContributorsToTrackTime } return u.IssuesConfig().AllowOnlyContributorsToTrackTime } // IsDependenciesEnabled returns if dependencies are enabled and returns the default setting if not set. -func (repo *Repository) IsDependenciesEnabled() bool { - return repo.IsDependenciesEnabledCtx(db.DefaultContext) -} - -// IsDependenciesEnabledCtx returns if dependencies are enabled and returns the default setting if not set. -func (repo *Repository) IsDependenciesEnabledCtx(ctx context.Context) bool { +func (repo *Repository) IsDependenciesEnabled(ctx context.Context) bool { var u *RepoUnit var err error - if u, err = repo.GetUnitCtx(ctx, unit.TypeIssues); err != nil { + if u, err = repo.GetUnit(ctx, unit.TypeIssues); err != nil { log.Trace("%s", err) return setting.Service.DefaultEnableDependencies } diff --git a/models/repo/language_stats.go b/models/repo/language_stats.go index f8f5dd041fa1..2da16814bd8f 100644 --- a/models/repo/language_stats.go +++ b/models/repo/language_stats.go @@ -6,6 +6,7 @@ package repo import ( "context" "math" + "sort" "strings" "code.gitea.io/gitea/models/db" @@ -43,7 +44,7 @@ func (stats LanguageStatList) LoadAttributes() { func (stats LanguageStatList) getLanguagePercentages() map[string]float32 { langPerc := make(map[string]float32) - var otherPerc float32 = 100 + var otherPerc float32 var total int64 for _, stat := range stats { @@ -51,21 +52,52 @@ func (stats LanguageStatList) getLanguagePercentages() map[string]float32 { } if total > 0 { for _, stat := range stats { - perc := float32(math.Round(float64(stat.Size)/float64(total)*1000) / 10) + perc := float32(float64(stat.Size) / float64(total) * 100) if perc <= 0.1 { + otherPerc += perc continue } - otherPerc -= perc langPerc[stat.Language] = perc } - otherPerc = float32(math.Round(float64(otherPerc)*10) / 10) } if otherPerc > 0 { langPerc["other"] = otherPerc } + roundByLargestRemainder(langPerc, 100) return langPerc } +// Rounds to 1 decimal point, target should be the expected sum of percs +func roundByLargestRemainder(percs map[string]float32, target float32) { + leftToDistribute := int(target * 10) + + keys := make([]string, 0, len(percs)) + + for k, v := range percs { + percs[k] = v * 10 + floored := math.Floor(float64(percs[k])) + leftToDistribute -= int(floored) + keys = append(keys, k) + } + + // Sort the keys by the largest remainder + sort.SliceStable(keys, func(i, j int) bool { + _, remainderI := math.Modf(float64(percs[keys[i]])) + _, remainderJ := math.Modf(float64(percs[keys[j]])) + return remainderI > remainderJ + }) + + // Increment the values in order of largest remainder + for _, k := range keys { + percs[k] = float32(math.Floor(float64(percs[k]))) + if leftToDistribute > 0 { + percs[k]++ + leftToDistribute-- + } + percs[k] /= 10 + } +} + // GetLanguageStats returns the language statistics for a repository func GetLanguageStats(ctx context.Context, repo *Repository) (LanguageStatList, error) { stats := make(LanguageStatList, 0, 6) diff --git a/models/repo/mirror.go b/models/repo/mirror.go index 63b26b5d0cd8..2f59b85331d0 100644 --- a/models/repo/mirror.go +++ b/models/repo/mirror.go @@ -52,7 +52,7 @@ func (m *Mirror) GetRepository() *Repository { return m.Repo } var err error - m.Repo, err = GetRepositoryByIDCtx(db.DefaultContext, m.RepoID) + m.Repo, err = GetRepositoryByID(db.DefaultContext, m.RepoID) if err != nil { log.Error("getRepositoryByID[%d]: %v", m.ID, err) } diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go index 55fde8b838eb..f79ce59ee227 100644 --- a/models/repo/pushmirror.go +++ b/models/repo/pushmirror.go @@ -61,7 +61,7 @@ func (m *PushMirror) GetRepository() *Repository { return m.Repo } var err error - m.Repo, err = GetRepositoryByIDCtx(db.DefaultContext, m.RepoID) + m.Repo, err = GetRepositoryByID(db.DefaultContext, 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 da6235988a70..25eba10e05df 100644 --- a/models/repo/release.go +++ b/models/repo/release.go @@ -93,13 +93,13 @@ func init() { func (r *Release) LoadAttributes(ctx context.Context) error { var err error if r.Repo == nil { - r.Repo, err = GetRepositoryByIDCtx(ctx, r.RepoID) + r.Repo, err = GetRepositoryByID(ctx, r.RepoID) if err != nil { return err } } if r.Publisher == nil { - r.Publisher, err = user_model.GetUserByIDCtx(ctx, r.PublisherID) + r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID) if err != nil { if user_model.IsErrUserNotExist(err) { r.Publisher = user_model.NewGhostUser() @@ -286,8 +286,8 @@ func GetReleasesByRepoIDAndNames(ctx context.Context, repoID int64, tagNames []s } // GetReleaseCountByRepoID returns the count of releases of repository -func GetReleaseCountByRepoID(repoID int64, opts FindReleasesOptions) (int64, error) { - return db.GetEngine(db.DefaultContext).Where(opts.toConds(repoID)).Count(&Release{}) +func GetReleaseCountByRepoID(ctx context.Context, repoID int64, opts FindReleasesOptions) (int64, error) { + return db.GetEngine(ctx).Where(opts.toConds(repoID)).Count(&Release{}) } type releaseMetaSearch struct { diff --git a/models/repo/repo.go b/models/repo/repo.go index f58b7de6edf0..e5e1ac43b41f 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -315,12 +315,7 @@ func (repo *Repository) LoadUnits(ctx context.Context) (err error) { } // UnitEnabled if this repository has the given unit enabled -func (repo *Repository) UnitEnabled(tp unit.Type) (result bool) { - return repo.UnitEnabledCtx(db.DefaultContext, tp) -} - -// UnitEnabled if this repository has the given unit enabled -func (repo *Repository) UnitEnabledCtx(ctx context.Context, tp unit.Type) bool { +func (repo *Repository) UnitEnabled(ctx context.Context, tp unit.Type) bool { if err := repo.LoadUnits(ctx); err != nil { log.Warn("Error loading repository (ID: %d) units: %s", repo.ID, err.Error()) } @@ -333,8 +328,8 @@ func (repo *Repository) UnitEnabledCtx(ctx context.Context, tp unit.Type) bool { } // MustGetUnit always returns a RepoUnit object -func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit { - ru, err := repo.GetUnit(tp) +func (repo *Repository) MustGetUnit(ctx context.Context, tp unit.Type) *RepoUnit { + ru, err := repo.GetUnit(ctx, tp) if err == nil { return ru } @@ -367,12 +362,7 @@ func (repo *Repository) MustGetUnit(tp unit.Type) *RepoUnit { } // GetUnit returns a RepoUnit object -func (repo *Repository) GetUnit(tp unit.Type) (*RepoUnit, error) { - return repo.GetUnitCtx(db.DefaultContext, tp) -} - -// GetUnitCtx returns a RepoUnit object -func (repo *Repository) GetUnitCtx(ctx context.Context, tp unit.Type) (*RepoUnit, error) { +func (repo *Repository) GetUnit(ctx context.Context, tp unit.Type) (*RepoUnit, error) { if err := repo.LoadUnits(ctx); err != nil { return nil, err } @@ -390,7 +380,7 @@ func (repo *Repository) GetOwner(ctx context.Context) (err error) { return nil } - repo.Owner, err = user_model.GetUserByIDCtx(ctx, repo.OwnerID) + repo.Owner, err = user_model.GetUserByID(ctx, repo.OwnerID) return err } @@ -419,7 +409,7 @@ func (repo *Repository) ComposeMetas() map[string]string { "mode": "comment", } - unit, err := repo.GetUnit(unit.TypeExternalTracker) + unit, err := repo.GetUnit(db.DefaultContext, unit.TypeExternalTracker) if err == nil { metas["format"] = unit.ExternalTrackerConfig().ExternalTrackerFormat switch unit.ExternalTrackerConfig().ExternalTrackerStyle { @@ -467,16 +457,12 @@ func (repo *Repository) ComposeDocumentMetas() map[string]string { // GetBaseRepo populates repo.BaseRepo for a fork repository and // returns an error on failure (NOTE: no error is returned for // non-fork repositories, and BaseRepo will be left untouched) -func (repo *Repository) GetBaseRepo() (err error) { - return repo.getBaseRepo(db.DefaultContext) -} - -func (repo *Repository) getBaseRepo(ctx context.Context) (err error) { +func (repo *Repository) GetBaseRepo(ctx context.Context) (err error) { if !repo.IsFork { return nil } - repo.BaseRepo, err = GetRepositoryByIDCtx(ctx, repo.ForkID) + repo.BaseRepo, err = GetRepositoryByID(ctx, repo.ForkID) return err } @@ -522,7 +508,7 @@ func (repo *Repository) CanEnablePulls() bool { // AllowsPulls returns true if repository meets the requirements of accepting pulls and has them enabled. func (repo *Repository) AllowsPulls() bool { - return repo.CanEnablePulls() && repo.UnitEnabled(unit.TypePullRequests) + return repo.CanEnablePulls() && repo.UnitEnabled(db.DefaultContext, unit.TypePullRequests) } // CanEnableEditor returns true if repository meets the requirements of web editor. @@ -611,11 +597,6 @@ func (repo *Repository) GetTrustModel() TrustModelType { return trustModel } -// GetRepositoryByOwnerAndName returns the repository by given ownername and reponame. -func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) { - return GetRepositoryByOwnerAndNameCtx(db.DefaultContext, ownerName, repoName) -} - // __________ .__ __ // \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__. // | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | | @@ -647,8 +628,8 @@ func (err ErrRepoNotExist) Unwrap() error { return util.ErrNotExist } -// GetRepositoryByOwnerAndNameCtx returns the repository by given owner name and repo name -func GetRepositoryByOwnerAndNameCtx(ctx context.Context, ownerName, repoName string) (*Repository, error) { +// GetRepositoryByOwnerAndName returns the repository by given owner name and repo name +func GetRepositoryByOwnerAndName(ctx context.Context, ownerName, repoName string) (*Repository, error) { var repo Repository has, err := db.GetEngine(ctx).Table("repository").Select("repository.*"). Join("INNER", "`user`", "`user`.id = repository.owner_id"). @@ -678,8 +659,8 @@ func GetRepositoryByName(ownerID int64, name string) (*Repository, error) { return repo, err } -// GetRepositoryByIDCtx returns the repository by given id if exists. -func GetRepositoryByIDCtx(ctx context.Context, id int64) (*Repository, error) { +// GetRepositoryByID returns the repository by given id if exists. +func GetRepositoryByID(ctx context.Context, id int64) (*Repository, error) { repo := new(Repository) has, err := db.GetEngine(ctx).ID(id).Get(repo) if err != nil { @@ -690,11 +671,6 @@ func GetRepositoryByIDCtx(ctx context.Context, id int64) (*Repository, error) { return repo, nil } -// GetRepositoryByID returns the repository by given id if exists. -func GetRepositoryByID(id int64) (*Repository, error) { - return GetRepositoryByIDCtx(db.DefaultContext, id) -} - // GetRepositoriesMapByIDs returns the repositories by given id slice. func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) { repos := make(map[int64]*Repository, len(ids)) @@ -722,7 +698,7 @@ func GetTemplateRepo(ctx context.Context, repo *Repository) (*Repository, error) return nil, nil } - return GetRepositoryByIDCtx(ctx, repo.TemplateID) + return GetRepositoryByID(ctx, repo.TemplateID) } // TemplateRepo returns the repository, which is template of this repository diff --git a/models/repo/repo_list_test.go b/models/repo/repo_list_test.go index bfbceb7e2ec3..d87d70c189a6 100644 --- a/models/repo/repo_list_test.go +++ b/models/repo/repo_list_test.go @@ -235,12 +235,12 @@ func TestSearchRepository(t *testing.T) { { name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative", opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, - count: 28, + count: 29, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, - count: 33, + count: 34, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", @@ -255,7 +255,7 @@ func TestSearchRepository(t *testing.T) { { name: "AllPublic/PublicRepositoriesOfOrganization", opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, - count: 28, + count: 29, }, { name: "AllTemplates", diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go index 081221d1dfeb..fb473151eb34 100644 --- a/models/repo/repo_test.go +++ b/models/repo/repo_test.go @@ -115,7 +115,7 @@ func TestMetas(t *testing.T) { externalTracker.ExternalTrackerConfig().ExternalTrackerStyle = markup.IssueNameStyleRegexp testSuccess(markup.IssueNameStyleRegexp) - repo, err := repo_model.GetRepositoryByID(3) + repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 3) assert.NoError(t, err) metas = repo.ComposeMetas() diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index 2c04cb442b2c..b85880eab9ca 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -53,7 +53,7 @@ func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) { } func reconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Repository, uid int64) error { - user, err := user_model.GetUserByIDCtx(ctx, uid) + user, err := user_model.GetUserByID(ctx, uid) if err != nil { return err } diff --git a/models/repo_transfer.go b/models/repo_transfer.go index 6f02ab45fe25..19e6c0662727 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -39,9 +39,9 @@ func init() { } // LoadAttributes fetches the transfer recipient from the database -func (r *RepoTransfer) LoadAttributes() error { +func (r *RepoTransfer) LoadAttributes(ctx context.Context) error { if r.Recipient == nil { - u, err := user_model.GetUserByID(r.RecipientID) + u, err := user_model.GetUserByID(ctx, r.RecipientID) if err != nil { return err } @@ -51,7 +51,7 @@ func (r *RepoTransfer) LoadAttributes() error { if r.Recipient.IsOrganization() && len(r.TeamIDs) != len(r.Teams) { for _, v := range r.TeamIDs { - team, err := organization.GetTeamByID(db.DefaultContext, v) + team, err := organization.GetTeamByID(ctx, v) if err != nil { return err } @@ -65,7 +65,7 @@ func (r *RepoTransfer) LoadAttributes() error { } if r.Doer == nil { - u, err := user_model.GetUserByID(r.DoerID) + u, err := user_model.GetUserByID(ctx, r.DoerID) if err != nil { return err } @@ -80,7 +80,7 @@ func (r *RepoTransfer) LoadAttributes() error { // 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(); err != nil { + if err := r.LoadAttributes(db.DefaultContext); 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(r.RecipientID, u.ID) + allowed, err := organization.CanCreateOrgRepo(db.DefaultContext, r.RecipientID, u.ID) if err != nil { log.Error("CanCreateOrgRepo: %v", err) return false @@ -100,10 +100,10 @@ func (r *RepoTransfer) CanUserAcceptTransfer(u *user_model.User) bool { // GetPendingRepositoryTransfer fetches the most recent and ongoing transfer // process for the repository -func GetPendingRepositoryTransfer(repo *repo_model.Repository) (*RepoTransfer, error) { +func GetPendingRepositoryTransfer(ctx context.Context, repo *repo_model.Repository) (*RepoTransfer, error) { transfer := new(RepoTransfer) - has, err := db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repo.ID).Get(transfer) + has, err := db.GetEngine(ctx).Where("repo_id = ? ", repo.ID).Get(transfer) if err != nil { return nil, err } @@ -154,56 +154,48 @@ func TestRepositoryReadyForTransfer(status repo_model.RepositoryStatus) error { // CreatePendingRepositoryTransfer transfer a repo from one owner to a new one. // it marks the repository transfer as "pending" -func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error { - ctx, committer, err := db.TxContext(db.DefaultContext) - if err != nil { - return err - } - defer committer.Close() - - repo, err := repo_model.GetRepositoryByIDCtx(ctx, repoID) - if err != nil { - return err - } - - // Make sure repo is ready to transfer - if err := TestRepositoryReadyForTransfer(repo.Status); err != nil { - return err - } +func CreatePendingRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repoID int64, teams []*organization.Team) error { + return db.AutoTx(ctx, func(ctx context.Context) error { + repo, err := repo_model.GetRepositoryByID(ctx, repoID) + if err != nil { + return err + } - repo.Status = repo_model.RepositoryPendingTransfer - if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { - return err - } + // Make sure repo is ready to transfer + if err := TestRepositoryReadyForTransfer(repo.Status); err != nil { + return err + } - // Check if new owner has repository with same name. - if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil { - return fmt.Errorf("IsRepositoryExist: %w", err) - } else if has { - return repo_model.ErrRepoAlreadyExist{ - Uname: newOwner.LowerName, - Name: repo.Name, + repo.Status = repo_model.RepositoryPendingTransfer + if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { + return err } - } - transfer := &RepoTransfer{ - RepoID: repo.ID, - RecipientID: newOwner.ID, - CreatedUnix: timeutil.TimeStampNow(), - UpdatedUnix: timeutil.TimeStampNow(), - DoerID: doer.ID, - TeamIDs: make([]int64, 0, len(teams)), - } + // Check if new owner has repository with same name. + if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil { + return fmt.Errorf("IsRepositoryExist: %w", err) + } else if has { + return repo_model.ErrRepoAlreadyExist{ + Uname: newOwner.LowerName, + Name: repo.Name, + } + } - for k := range teams { - transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID) - } + transfer := &RepoTransfer{ + RepoID: repo.ID, + RecipientID: newOwner.ID, + CreatedUnix: timeutil.TimeStampNow(), + UpdatedUnix: timeutil.TimeStampNow(), + DoerID: doer.ID, + TeamIDs: make([]int64, 0, len(teams)), + } - if err := db.Insert(ctx, transfer); err != nil { - return err - } + for k := range teams { + transfer.TeamIDs = append(transfer.TeamIDs, teams[k].ID) + } - return committer.Commit() + return db.Insert(ctx, transfer) + }) } // TransferOwnership transfers all corresponding repository items from old user to new one. diff --git a/models/repo_transfer_test.go b/models/repo_transfer_test.go index 9720071a989b..8352adc94892 100644 --- a/models/repo_transfer_test.go +++ b/models/repo_transfer_test.go @@ -6,6 +6,7 @@ package models import ( "testing" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -19,36 +20,36 @@ func TestRepositoryTransfer(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) - transfer, err := GetPendingRepositoryTransfer(repo) + transfer, err := GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.NoError(t, err) assert.NotNil(t, transfer) // Cancel transfer assert.NoError(t, CancelRepositoryTransfer(repo)) - transfer, err = GetPendingRepositoryTransfer(repo) + transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.Error(t, err) assert.Nil(t, transfer) assert.True(t, IsErrNoPendingTransfer(err)) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - assert.NoError(t, CreatePendingRepositoryTransfer(doer, user2, repo.ID, nil)) + assert.NoError(t, CreatePendingRepositoryTransfer(db.DefaultContext, doer, user2, repo.ID, nil)) - transfer, err = GetPendingRepositoryTransfer(repo) + transfer, err = GetPendingRepositoryTransfer(db.DefaultContext, repo) assert.Nil(t, err) - assert.NoError(t, transfer.LoadAttributes()) + assert.NoError(t, transfer.LoadAttributes(db.DefaultContext)) assert.Equal(t, "user2", transfer.Recipient.Name) user6 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Only transfer can be started at any given time - err = CreatePendingRepositoryTransfer(doer, user6, repo.ID, nil) + err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, user6, repo.ID, nil) assert.Error(t, err) assert.True(t, IsErrRepoTransferInProgress(err)) // Unknown user - err = CreatePendingRepositoryTransfer(doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil) + err = CreatePendingRepositoryTransfer(db.DefaultContext, doer, &user_model.User{ID: 1000, LowerName: "user1000"}, repo.ID, nil) assert.Error(t, err) // Cancel transfer diff --git a/models/secret/secret.go b/models/secret/secret.go new file mode 100644 index 000000000000..f970d5319e7e --- /dev/null +++ b/models/secret/secret.go @@ -0,0 +1,124 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package secret + +import ( + "context" + "fmt" + "regexp" + "strings" + + "code.gitea.io/gitea/models/db" + secret_module "code.gitea.io/gitea/modules/secret" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" + + "xorm.io/builder" +) + +type ErrSecretInvalidValue struct { + Name *string + Data *string +} + +func (err ErrSecretInvalidValue) Error() string { + if err.Name != nil { + return fmt.Sprintf("secret name %q is invalid", *err.Name) + } + if err.Data != nil { + return fmt.Sprintf("secret data %q is invalid", *err.Data) + } + return util.ErrInvalidArgument.Error() +} + +func (err ErrSecretInvalidValue) Unwrap() error { + return util.ErrInvalidArgument +} + +// Secret represents a secret +type Secret struct { + ID int64 + OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"` + RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"` + Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"` + Data string `xorm:"LONGTEXT"` // encrypted data + CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` +} + +// newSecret Creates a new already encrypted secret +func newSecret(ownerID, repoID int64, name, data string) *Secret { + return &Secret{ + OwnerID: ownerID, + RepoID: repoID, + Name: strings.ToUpper(name), + Data: data, + } +} + +// InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database +func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) { + encrypted, err := secret_module.EncryptSecret(setting.SecretKey, strings.TrimSpace(data)) + if err != nil { + return nil, err + } + secret := newSecret(ownerID, repoID, name, encrypted) + if err := secret.Validate(); err != nil { + return secret, err + } + return secret, db.Insert(ctx, secret) +} + +func init() { + db.RegisterModel(new(Secret)) +} + +var ( + secretNameReg = regexp.MustCompile("^[A-Z_][A-Z0-9_]*$") + forbiddenSecretPrefixReg = regexp.MustCompile("^GIT(EA|HUB)_") +) + +// Validate validates the required fields and formats. +func (s *Secret) Validate() error { + switch { + case len(s.Name) == 0 || len(s.Name) > 50: + return ErrSecretInvalidValue{Name: &s.Name} + case len(s.Data) == 0: + return ErrSecretInvalidValue{Data: &s.Data} + case !secretNameReg.MatchString(s.Name) || + forbiddenSecretPrefixReg.MatchString(s.Name): + return ErrSecretInvalidValue{Name: &s.Name} + default: + return nil + } +} + +type FindSecretsOptions struct { + db.ListOptions + OwnerID int64 + RepoID int64 +} + +func (opts *FindSecretsOptions) toConds() builder.Cond { + cond := builder.NewCond() + if opts.OwnerID > 0 { + cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) + } + if opts.RepoID > 0 { + cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) + } + + return cond +} + +func FindSecrets(ctx context.Context, opts FindSecretsOptions) ([]*Secret, error) { + var secrets []*Secret + sess := db.GetEngine(ctx) + if opts.PageSize != 0 { + sess = db.SetSessionPagination(sess, &opts.ListOptions) + } + return secrets, sess. + Where(opts.toConds()). + Find(&secrets) +} diff --git a/models/user/email_address.go b/models/user/email_address.go index 70394edb23f5..69e94f8bb6be 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -332,7 +332,7 @@ func ActivateEmail(email *EmailAddress) error { } func updateActivation(ctx context.Context, email *EmailAddress, activate bool) error { - user, err := GetUserByIDCtx(ctx, email.UID) + user, err := GetUserByID(ctx, email.UID) if err != nil { return err } diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index 7e523a165dfc..53fd18c303eb 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -162,7 +162,7 @@ func TestMakeEmailPrimary(t *testing.T) { err = user_model.MakeEmailPrimary(email) assert.NoError(t, err) - user, _ := user_model.GetUserByID(int64(10)) + user, _ := user_model.GetUserByID(db.DefaultContext, int64(10)) assert.Equal(t, "user101@example.com", user.Email) } diff --git a/models/user/user.go b/models/user/user.go index 7e3ae388fb30..825223201b67 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -275,6 +275,15 @@ func (u *User) CanEditGitHook() bool { return !setting.DisableGitHooks && (u.IsAdmin || u.AllowGitHook) } +// CanForkRepo returns if user login can fork a repository +// It checks especially that the user can create repos, and potentially more +func (u *User) CanForkRepo() bool { + if setting.Repository.AllowForkWithoutMaximumLimit { + return true + } + return u.CanCreateRepo() +} + // CanImportLocal returns true if user can migrate repository by local path. func (u *User) CanImportLocal() bool { if !setting.ImportLocalPaths || u == nil { @@ -401,7 +410,7 @@ func hashPassword(passwd, salt, algo string) (string, error) { tempPasswd = pbkdf2.Key([]byte(passwd), saltBytes, 10000, 50, sha256.New) } - return fmt.Sprintf("%x", tempPasswd), nil + return hex.EncodeToString(tempPasswd), nil } // SetPassword hashes a password using the algorithm defined in the config value of PASSWORD_HASH_ALGO @@ -993,12 +1002,7 @@ func UserPath(userName string) string { //revive:disable-line:exported } // GetUserByID returns the user object by given ID if exists. -func GetUserByID(id int64) (*User, error) { - return GetUserByIDCtx(db.DefaultContext, id) -} - -// GetUserByIDCtx returns the user object by given ID if exists. -func GetUserByIDCtx(ctx context.Context, id int64) (*User, error) { +func GetUserByID(ctx context.Context, id int64) (*User, error) { u := new(User) has, err := db.GetEngine(ctx).ID(id).Get(u) if err != nil { @@ -1176,7 +1180,7 @@ func GetUserByEmailContext(ctx context.Context, email string) (*User, error) { return nil, err } if has { - return GetUserByIDCtx(ctx, emailAddress.UID) + return GetUserByID(ctx, emailAddress.UID) } // Finally, if email address is the protected email address: @@ -1220,7 +1224,7 @@ func GetUserByOpenID(uri string) (*User, error) { return nil, err } if has { - return GetUserByID(oid.UID) + return GetUserByID(db.DefaultContext, oid.UID) } return nil, ErrUserNotExist{0, uri, 0} diff --git a/models/user/user_test.go b/models/user/user_test.go index 2ee4da0d67f7..525da531f239 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -22,7 +22,7 @@ import ( func TestOAuth2Application_LoadUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &auth.OAuth2Application{ID: 1}) - user, err := user_model.GetUserByID(app.UID) + user, err := user_model.GetUserByID(db.DefaultContext, app.UID) assert.NoError(t, err) assert.NotNil(t, user) } diff --git a/modules/activitypub/client_test.go b/modules/activitypub/client_test.go index b5f978c4ddd2..0ab512c5ba7d 100644 --- a/modules/activitypub/client_test.go +++ b/modules/activitypub/client_test.go @@ -35,7 +35,7 @@ func TestActivityPubSignedPost(t *testing.T) { body, err := io.ReadAll(r.Body) assert.NoError(t, err) assert.Equal(t, expected, string(body)) - fmt.Fprintf(w, expected) + fmt.Fprint(w, expected) })) defer srv.Close() diff --git a/modules/charset/ambiguous.go b/modules/charset/ambiguous.go index c5b0c2c54d2e..96e0561e155a 100644 --- a/modules/charset/ambiguous.go +++ b/modules/charset/ambiguous.go @@ -28,6 +28,12 @@ func AmbiguousTablesForLocale(locale translation.Locale) []*AmbiguousTable { key = key[:idx] } } + if table == nil && (locale.Language() == "zh-CN" || locale.Language() == "zh_CN") { + table = AmbiguousCharacters["zh-hans"] + } + if table == nil && strings.HasPrefix(locale.Language(), "zh") { + table = AmbiguousCharacters["zh-hant"] + } if table == nil { table = AmbiguousCharacters["_default"] } diff --git a/modules/charset/escape.go b/modules/charset/escape.go index ce2eb1446dbb..3b1c20697793 100644 --- a/modules/charset/escape.go +++ b/modules/charset/escape.go @@ -8,6 +8,7 @@ package charset import ( + "bufio" "io" "strings" @@ -31,7 +32,7 @@ func EscapeControlHTML(text string, locale translation.Locale, allowed ...rune) return streamer.escaped, sb.String() } -// EscapeControlReaders escapes the unicode control sequences in a provider reader and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte +// EscapeControlReaders escapes the unicode control sequences in a provided reader of HTML content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) { outputStream := &HTMLStreamerWriter{Writer: writer} streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) @@ -43,6 +44,35 @@ func EscapeControlReader(reader io.Reader, writer io.Writer, locale translation. return streamer.escaped, err } +// EscapeControlStringReader escapes the unicode control sequences in a provided reader of string content and writer in a locale and returns the findings as an EscapeStatus and the escaped []byte +func EscapeControlStringReader(reader io.Reader, writer io.Writer, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, err error) { + bufRd := bufio.NewReader(reader) + outputStream := &HTMLStreamerWriter{Writer: writer} + streamer := NewEscapeStreamer(locale, outputStream, allowed...).(*escapeStreamer) + + for { + line, rdErr := bufRd.ReadString('\n') + if len(line) > 0 { + if err := streamer.Text(line); err != nil { + streamer.escaped.HasError = true + log.Error("Error whilst escaping: %v", err) + return streamer.escaped, err + } + } + if rdErr != nil { + if rdErr != io.EOF { + err = rdErr + } + break + } + if err := streamer.SelfClosingTag("br"); err != nil { + streamer.escaped.HasError = true + return streamer.escaped, err + } + } + return streamer.escaped, err +} + // EscapeControlString escapes the unicode control sequences in a provided string and returns the findings as an EscapeStatus and the escaped string func EscapeControlString(text string, locale translation.Locale, allowed ...rune) (escaped *EscapeStatus, output string) { sb := &strings.Builder{} diff --git a/modules/charset/escape_stream.go b/modules/charset/escape_stream.go index d29e393ab4d7..823b635137eb 100644 --- a/modules/charset/escape_stream.go +++ b/modules/charset/escape_stream.go @@ -239,7 +239,7 @@ func (counts runeCountType) needsEscape() bool { type runeType int const ( - basicASCIIRuneType runeType = iota //nolint // <- This is technically deadcode but its self-documenting so it should stay + basicASCIIRuneType runeType = iota // <- This is technically deadcode but its self-documenting so it should stay brokenRuneType nonBasicASCIIRuneType ambiguousRuneType diff --git a/modules/context/api.go b/modules/context/api.go index f49997a7875f..3f52c54d4cfd 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -219,7 +219,13 @@ func (ctx *APIContext) CheckForOTP() { func APIAuth(authMethod auth_service.Method) func(*APIContext) { return func(ctx *APIContext) { // Get user from session if logged in. - ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + var err error + ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + if err != nil { + ctx.Error(http.StatusUnauthorized, "APIAuth", err) + return + } + if ctx.Doer != nil { if ctx.Locale.Language() != ctx.Doer.Language { ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req) @@ -387,7 +393,7 @@ func RepoRefForAPI(next http.Handler) http.Handler { return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if len(refName) == 40 { + } else if len(refName) == git.SHAFullLength { ctx.Repo.CommitID = refName ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName) if err != nil { diff --git a/modules/context/context.go b/modules/context/context.go index 0d632b67c050..6273093060a1 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -139,7 +139,7 @@ func (ctx *Context) IsUserRepoReaderAny() bool { // RedirectToUser redirect to a differently-named user func RedirectToUser(ctx *Context, userName string, redirectUserID int64) { - user, err := user_model.GetUserByID(redirectUserID) + user, err := user_model.GetUserByID(ctx, redirectUserID) if err != nil { ctx.ServerError("GetUserByID", err) return @@ -662,7 +662,13 @@ func getCsrfOpts() CsrfOptions { // Auth converts auth.Auth as a middleware func Auth(authMethod auth.Method) func(*Context) { return func(ctx *Context) { - ctx.Doer = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + var err error + ctx.Doer, err = authMethod.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + if err != nil { + log.Error("Failed to verify user %v: %v", ctx.Req.RemoteAddr, err) + ctx.Error(http.StatusUnauthorized, "Verify") + return + } if ctx.Doer != nil { if ctx.Locale.Language() != ctx.Doer.Language { ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req) diff --git a/modules/context/csrf.go b/modules/context/csrf.go index df775048cb62..6639a8b00847 100644 --- a/modules/context/csrf.go +++ b/modules/context/csrf.go @@ -13,6 +13,7 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. +// SPDX-License-Identifier: Apache-2.0 // a middleware that generates and validates CSRF tokens. diff --git a/modules/context/package.go b/modules/context/package.go index 65a9d74b7752..2a55db3a77fa 100644 --- a/modules/context/package.go +++ b/modules/context/package.go @@ -110,7 +110,7 @@ func determineAccessMode(ctx *Context) (perm.AccessMode, error) { return accessMode, err } for _, t := range teams { - perm := t.UnitAccessModeCtx(ctx, unit.TypePackages) + perm := t.UnitAccessMode(ctx, unit.TypePackages) if accessMode < perm { accessMode = perm } diff --git a/modules/context/repo.go b/modules/context/repo.go index 57cf2fae5ace..d15d28cab783 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -163,13 +163,13 @@ func (r *Repository) CanUseTimetracker(issue *issues_model.Issue, user *user_mod // 1. Is timetracker enabled // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? isAssigned, _ := issues_model.IsUserAssignedToIssue(db.DefaultContext, issue, user) - return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || + return r.Repository.IsTimetrackerEnabled(db.DefaultContext) && (!r.Repository.AllowOnlyContributorsToTrackTime(db.DefaultContext) || r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned) } // CanCreateIssueDependencies returns whether or not a user can create dependencies. func (r *Repository) CanCreateIssueDependencies(user *user_model.User, isPull bool) bool { - return r.Repository.IsDependenciesEnabled() && r.Permission.CanWriteIssuesOrPulls(isPull) + return r.Repository.IsDependenciesEnabled(db.DefaultContext) && r.Permission.CanWriteIssuesOrPulls(isPull) } // GetCommitsCount returns cached commit count for current view @@ -264,7 +264,7 @@ func (r *Repository) GetEditorconfig(optCommit ...*git.Commit) (*editorconfig.Ed // RetrieveBaseRepo retrieves base repository func RetrieveBaseRepo(ctx *Context, repo *repo_model.Repository) { // Non-fork repository will not return error in this method. - if err := repo.GetBaseRepo(); err != nil { + if err := repo.GetBaseRepo(ctx); err != nil { if repo_model.IsErrRepoNotExist(err) { repo.IsFork = false repo.ForkID = 0 @@ -335,7 +335,7 @@ func RedirectToRepo(ctx *Context, redirectRepoID int64) { ownerName := ctx.Params(":username") previousRepoName := ctx.Params(":reponame") - repo, err := repo_model.GetRepositoryByID(redirectRepoID) + repo, err := repo_model.GetRepositoryByID(ctx, redirectRepoID) if err != nil { ctx.ServerError("GetRepositoryByID", err) return @@ -410,7 +410,7 @@ func RepoIDAssignment() func(ctx *Context) { repoID := ctx.ParamsInt64(":repoid") // Get repository. - repo, err := repo_model.GetRepositoryByID(repoID) + repo, err := repo_model.GetRepositoryByID(ctx, repoID) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound("GetRepositoryByID", nil) @@ -528,12 +528,12 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["RepoLink"] = ctx.Repo.RepoLink ctx.Data["RepoRelPath"] = ctx.Repo.Owner.Name + "/" + ctx.Repo.Repository.Name - unit, err := ctx.Repo.Repository.GetUnit(unit_model.TypeExternalTracker) + unit, err := ctx.Repo.Repository.GetUnit(ctx, unit_model.TypeExternalTracker) if err == nil { ctx.Data["RepoExternalIssuesLink"] = unit.ExternalTrackerConfig().ExternalTrackerURL } - ctx.Data["NumTags"], err = repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ + ctx.Data["NumTags"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ IncludeDrafts: true, IncludeTags: true, HasSha1: util.OptionalBoolTrue, // only draft releases which are created with existing tags @@ -542,7 +542,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.ServerError("GetReleaseCountByRepoID", err) return } - ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{}) + ctx.Data["NumReleases"], err = repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{}) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) return @@ -723,13 +723,13 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequest if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer { - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { ctx.ServerError("GetPendingRepositoryTransfer", err) return } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadRecipient", err) return } @@ -817,7 +817,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string { } // For legacy and API support only full commit sha parts := strings.Split(path, "/") - if len(parts) > 0 && len(parts[0]) == 40 { + if len(parts) > 0 && len(parts[0]) == git.SHAFullLength { ctx.Repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } @@ -853,7 +853,7 @@ func getRefName(ctx *Context, pathType RepoRefType) string { return getRefNameFromPath(ctx, path, ctx.Repo.GitRepo.IsTagExist) case RepoRefCommit: parts := strings.Split(path, "/") - if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= 40 { + if len(parts) > 0 && len(parts[0]) >= 7 && len(parts[0]) <= git.SHAFullLength { ctx.Repo.TreePath = strings.Join(parts[1:], "/") return parts[0] } @@ -962,7 +962,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context return } ctx.Repo.CommitID = ctx.Repo.Commit.ID.String() - } else if len(refName) >= 7 && len(refName) <= 40 { + } else if len(refName) >= 7 && len(refName) <= git.SHAFullLength { ctx.Repo.IsViewCommit = true ctx.Repo.CommitID = refName @@ -972,7 +972,7 @@ func RepoRefByType(refType RepoRefType, ignoreNotExistErr ...bool) func(*Context return } // If short commit ID add canonical link header - if len(refName) < 40 { + if len(refName) < git.SHAFullLength { ctx.RespHeader().Set("Link", fmt.Sprintf("<%s>; rel=\"canonical\"", util.URLJoin(setting.AppURL, strings.Replace(ctx.Req.URL.RequestURI(), util.PathEscapeSegments(refName), url.PathEscape(ctx.Repo.Commit.ID.String()), 1)))) } diff --git a/modules/context/xsrf.go b/modules/context/xsrf.go index e3ecc82f6d75..15e36d185985 100644 --- a/modules/context/xsrf.go +++ b/modules/context/xsrf.go @@ -13,6 +13,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// SPDX-License-Identifier: Apache-2.0 package context diff --git a/modules/context/xsrf_test.go b/modules/context/xsrf_test.go index ef42d61d5a8d..21cda5d5d46e 100644 --- a/modules/context/xsrf_test.go +++ b/modules/context/xsrf_test.go @@ -13,6 +13,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. +// SPDX-License-Identifier: Apache-2.0 package context diff --git a/modules/doctor/dbversion.go b/modules/doctor/dbversion.go index 3ddca92fb34c..2b20cb234064 100644 --- a/modules/doctor/dbversion.go +++ b/modules/doctor/dbversion.go @@ -12,6 +12,7 @@ import ( ) func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error { + logger.Info("Expected database version: %d", migrations.ExpectedVersion()) if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil { if !autofix { logger.Critical("Error: %v during ensure up to date", err) diff --git a/modules/doctor/lfs.go b/modules/doctor/lfs.go new file mode 100644 index 000000000000..410ed5a9a5f8 --- /dev/null +++ b/modules/doctor/lfs.go @@ -0,0 +1,37 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package doctor + +import ( + "context" + "fmt" + + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/repository" +) + +func init() { + Register(&Check{ + Title: "Garbage collect LFS", + Name: "gc-lfs", + IsDefault: false, + Run: garbageCollectLFSCheck, + AbortIfFailed: false, + SkipDatabaseInitialization: false, + Priority: 1, + }) +} + +func garbageCollectLFSCheck(ctx context.Context, logger log.Logger, autofix bool) error { + if !setting.LFS.StartServer { + return fmt.Errorf("LFS support is disabled") + } + + if err := repository.GarbageCollectLFSMetaObjects(ctx, logger, autofix); err != nil { + return err + } + + return checkStorage(&checkStorageOptions{LFS: true})(ctx, logger, autofix) +} diff --git a/modules/eventsource/manager_run.go b/modules/eventsource/manager_run.go index 97d08aa8a87e..35dfc62f1ed9 100644 --- a/modules/eventsource/manager_run.go +++ b/modules/eventsource/manager_run.go @@ -9,13 +9,13 @@ import ( activities_model "code.gitea.io/gitea/models/activities" issues_model "code.gitea.io/gitea/models/issues" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/services/convert" ) // Init starts this eventsource diff --git a/modules/git/ref.go b/modules/git/ref.go index cd8d26818495..47cc04b7fbdb 100644 --- a/modules/git/ref.go +++ b/modules/git/ref.go @@ -55,40 +55,57 @@ func (ref *Reference) Commit() (*Commit, error) { // ShortName returns the short name of the reference func (ref *Reference) ShortName() string { - if ref == nil { - return "" - } - if strings.HasPrefix(ref.Name, BranchPrefix) { - return strings.TrimPrefix(ref.Name, BranchPrefix) + return RefName(ref.Name).ShortName() +} + +// RefGroup returns the group type of the reference +func (ref *Reference) RefGroup() string { + return RefName(ref.Name).RefGroup() +} + +// RefName represents a git reference name +type RefName string + +func (ref RefName) IsBranch() bool { + return strings.HasPrefix(string(ref), BranchPrefix) +} + +func (ref RefName) IsTag() bool { + return strings.HasPrefix(string(ref), TagPrefix) +} + +// ShortName returns the short name of the reference name +func (ref RefName) ShortName() string { + refName := string(ref) + if strings.HasPrefix(refName, BranchPrefix) { + return strings.TrimPrefix(refName, BranchPrefix) } - if strings.HasPrefix(ref.Name, TagPrefix) { - return strings.TrimPrefix(ref.Name, TagPrefix) + if strings.HasPrefix(refName, TagPrefix) { + return strings.TrimPrefix(refName, TagPrefix) } - if strings.HasPrefix(ref.Name, RemotePrefix) { - return strings.TrimPrefix(ref.Name, RemotePrefix) + if strings.HasPrefix(refName, RemotePrefix) { + return strings.TrimPrefix(refName, RemotePrefix) } - if strings.HasPrefix(ref.Name, PullPrefix) && strings.IndexByte(ref.Name[pullLen:], '/') > -1 { - return ref.Name[pullLen : strings.IndexByte(ref.Name[pullLen:], '/')+pullLen] + if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 { + return refName[pullLen : strings.IndexByte(refName[pullLen:], '/')+pullLen] } - return ref.Name + return refName } // RefGroup returns the group type of the reference -func (ref *Reference) RefGroup() string { - if ref == nil { - return "" - } - if strings.HasPrefix(ref.Name, BranchPrefix) { +func (ref RefName) RefGroup() string { + refName := string(ref) + if strings.HasPrefix(refName, BranchPrefix) { return "heads" } - if strings.HasPrefix(ref.Name, TagPrefix) { + if strings.HasPrefix(refName, TagPrefix) { return "tags" } - if strings.HasPrefix(ref.Name, RemotePrefix) { + if strings.HasPrefix(refName, RemotePrefix) { return "remotes" } - if strings.HasPrefix(ref.Name, PullPrefix) && strings.IndexByte(ref.Name[pullLen:], '/') > -1 { + if strings.HasPrefix(refName, PullPrefix) && strings.IndexByte(refName[pullLen:], '/') > -1 { return "pull" } return "" diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go index d3a3dc8c837c..404d9e502c04 100644 --- a/modules/git/repo_attribute.go +++ b/modules/git/repo_attribute.go @@ -9,8 +9,6 @@ import ( "fmt" "io" "os" - "strconv" - "strings" "code.gitea.io/gitea/modules/log" ) @@ -288,102 +286,6 @@ func (wr *nulSeparatedAttributeWriter) Close() error { return nil } -type lineSeparatedAttributeWriter struct { - tmp []byte - attributes chan attributeTriple - closed chan struct{} -} - -func (wr *lineSeparatedAttributeWriter) Write(p []byte) (n int, err error) { - l := len(p) - - nlIdx := bytes.IndexByte(p, '\n') - for nlIdx >= 0 { - wr.tmp = append(wr.tmp, p[:nlIdx]...) - - if len(wr.tmp) == 0 { - // This should not happen - if len(p) > nlIdx+1 { - wr.tmp = wr.tmp[:0] - p = p[nlIdx+1:] - nlIdx = bytes.IndexByte(p, '\n') - continue - } else { - return l, nil - } - } - - working := attributeTriple{} - if wr.tmp[0] == '"' { - sb := new(strings.Builder) - remaining := string(wr.tmp[1:]) - for len(remaining) > 0 { - rn, _, tail, err := strconv.UnquoteChar(remaining, '"') - if err != nil { - if len(remaining) > 2 && remaining[0] == '"' && remaining[1] == ':' && remaining[2] == ' ' { - working.Filename = sb.String() - wr.tmp = []byte(remaining[3:]) - break - } - return l, fmt.Errorf("unexpected tail %s", remaining) - } - _, _ = sb.WriteRune(rn) - remaining = tail - } - } else { - idx := bytes.IndexByte(wr.tmp, ':') - if idx < 0 { - return l, fmt.Errorf("unexpected input %s", string(wr.tmp)) - } - working.Filename = string(wr.tmp[:idx]) - if len(wr.tmp) < idx+2 { - return l, fmt.Errorf("unexpected input %s", string(wr.tmp)) - } - wr.tmp = wr.tmp[idx+2:] - } - - idx := bytes.IndexByte(wr.tmp, ':') - if idx < 0 { - return l, fmt.Errorf("unexpected input %s", string(wr.tmp)) - } - - working.Attribute = string(wr.tmp[:idx]) - if len(wr.tmp) < idx+2 { - return l, fmt.Errorf("unexpected input %s", string(wr.tmp)) - } - - working.Value = string(wr.tmp[idx+2:]) - - wr.attributes <- working - wr.tmp = wr.tmp[:0] - if len(p) > nlIdx+1 { - p = p[nlIdx+1:] - nlIdx = bytes.IndexByte(p, '\n') - continue - } else { - return l, nil - } - } - - wr.tmp = append(wr.tmp, p...) - return l, nil -} - -func (wr *lineSeparatedAttributeWriter) ReadAttribute() <-chan attributeTriple { - return wr.attributes -} - -func (wr *lineSeparatedAttributeWriter) Close() error { - select { - case <-wr.closed: - return nil - default: - } - close(wr.attributes) - close(wr.closed) - return nil -} - // Create a check attribute reader for the current repository and provided commit ID func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) { indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID) diff --git a/modules/git/repo_attribute_test.go b/modules/git/repo_attribute_test.go index 6882874d2dc7..f88ae9540786 100644 --- a/modules/git/repo_attribute_test.go +++ b/modules/git/repo_attribute_test.go @@ -95,64 +95,3 @@ func Test_nulSeparatedAttributeWriter_ReadAttribute(t *testing.T) { Value: "unspecified", }, attr) } - -func Test_lineSeparatedAttributeWriter_ReadAttribute(t *testing.T) { - wr := &lineSeparatedAttributeWriter{ - attributes: make(chan attributeTriple, 5), - } - - testStr := `".gitignore\"\n": linguist-vendored: unspecified -` - n, err := wr.Write([]byte(testStr)) - - assert.Equal(t, n, len(testStr)) - assert.NoError(t, err) - - select { - case attr := <-wr.ReadAttribute(): - assert.Equal(t, ".gitignore\"\n", attr.Filename) - assert.Equal(t, "linguist-vendored", attr.Attribute) - assert.Equal(t, "unspecified", attr.Value) - case <-time.After(100 * time.Millisecond): - assert.Fail(t, "took too long to read an attribute from the list") - } - - // Write a second attribute again - n, err = wr.Write([]byte(testStr)) - - assert.Equal(t, n, len(testStr)) - assert.NoError(t, err) - - select { - case attr := <-wr.ReadAttribute(): - assert.Equal(t, ".gitignore\"\n", attr.Filename) - assert.Equal(t, "linguist-vendored", attr.Attribute) - assert.Equal(t, "unspecified", attr.Value) - case <-time.After(100 * time.Millisecond): - assert.Fail(t, "took too long to read an attribute from the list") - } - - // Write a partial attribute - _, err = wr.Write([]byte("incomplete-file")) - assert.NoError(t, err) - _, err = wr.Write([]byte("name: ")) - assert.NoError(t, err) - select { - case <-wr.ReadAttribute(): - assert.Fail(t, "There should not be an attribute ready to read") - case <-time.After(100 * time.Millisecond): - } - _, err = wr.Write([]byte("attribute: ")) - assert.NoError(t, err) - select { - case <-wr.ReadAttribute(): - assert.Fail(t, "There should not be an attribute ready to read") - case <-time.After(100 * time.Millisecond): - } - _, err = wr.Write([]byte("value\n")) - assert.NoError(t, err) - attr := <-wr.ReadAttribute() - assert.Equal(t, "incomplete-filename", attr.Filename) - assert.Equal(t, "attribute", attr.Attribute) - assert.Equal(t, "value", attr.Value) -} diff --git a/modules/git/repo_branch_nogogit.go b/modules/git/repo_branch_nogogit.go index b1d0df6474a8..7559513c9b43 100644 --- a/modules/git/repo_branch_nogogit.go +++ b/modules/git/repo_branch_nogogit.go @@ -52,7 +52,7 @@ func (repo *Repository) IsReferenceExist(name string) bool { // IsBranchExist returns true if given branch exists in current repository. func (repo *Repository) IsBranchExist(name string) bool { - if name == "" { + if repo == nil || name == "" { return false } diff --git a/modules/git/repo_commit_gogit.go b/modules/git/repo_commit_gogit.go index b6c42a802f0d..72de158e6e11 100644 --- a/modules/git/repo_commit_gogit.go +++ b/modules/git/repo_commit_gogit.go @@ -41,7 +41,7 @@ func (repo *Repository) RemoveReference(name string) error { // ConvertToSHA1 returns a Hash object from a potential ID string func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) { - if len(commitID) == 40 { + if len(commitID) == SHAFullLength { sha1, err := NewIDFromString(commitID) if err == nil { return sha1, nil diff --git a/modules/git/repo_commit_nogogit.go b/modules/git/repo_commit_nogogit.go index 35a705fea30f..7373d01c8efb 100644 --- a/modules/git/repo_commit_nogogit.go +++ b/modules/git/repo_commit_nogogit.go @@ -137,7 +137,7 @@ func (repo *Repository) getCommitFromBatchReader(rd *bufio.Reader, id SHA1) (*Co // ConvertToSHA1 returns a Hash object from a potential ID string func (repo *Repository) ConvertToSHA1(commitID string) (SHA1, error) { - if len(commitID) == 40 && IsValidSHAPattern(commitID) { + if len(commitID) == SHAFullLength && IsValidSHAPattern(commitID) { sha1, err := NewIDFromString(commitID) if err == nil { return sha1, nil diff --git a/modules/git/repo_index.go b/modules/git/repo_index.go index 99eb2b540b1a..5ff2a2e4fc9d 100644 --- a/modules/git/repo_index.go +++ b/modules/git/repo_index.go @@ -16,7 +16,7 @@ import ( // ReadTreeToIndex reads a treeish to the index func (repo *Repository) ReadTreeToIndex(treeish string, indexFilename ...string) error { - if len(treeish) != 40 { + if len(treeish) != SHAFullLength { res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(treeish).RunStdString(&RunOpts{Dir: repo.Path}) if err != nil { return err diff --git a/modules/git/repo_tag_nogogit.go b/modules/git/repo_tag_nogogit.go index 1fb631002b77..d3331cf9b73e 100644 --- a/modules/git/repo_tag_nogogit.go +++ b/modules/git/repo_tag_nogogit.go @@ -15,7 +15,7 @@ import ( // IsTagExist returns true if given tag exists in the repository. func (repo *Repository) IsTagExist(name string) bool { - if name == "" { + if repo == nil || name == "" { return false } diff --git a/modules/git/repo_tree_gogit.go b/modules/git/repo_tree_gogit.go index e0e5e73fa335..a7b1081b15f1 100644 --- a/modules/git/repo_tree_gogit.go +++ b/modules/git/repo_tree_gogit.go @@ -19,7 +19,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) { // GetTree find the tree object in the repository. func (repo *Repository) GetTree(idStr string) (*Tree, error) { - if len(idStr) != 40 { + if len(idStr) != SHAFullLength { res, _, err := NewCommand(repo.Ctx, "rev-parse", "--verify").AddDynamicArguments(idStr).RunStdString(&RunOpts{Dir: repo.Path}) if err != nil { return nil, err diff --git a/modules/git/repo_tree_nogogit.go b/modules/git/repo_tree_nogogit.go index 16ea6bbd8a31..4fd77df2b824 100644 --- a/modules/git/repo_tree_nogogit.go +++ b/modules/git/repo_tree_nogogit.go @@ -66,7 +66,7 @@ func (repo *Repository) getTree(id SHA1) (*Tree, error) { // GetTree find the tree object in the repository. func (repo *Repository) GetTree(idStr string) (*Tree, error) { - if len(idStr) != 40 { + if len(idStr) != SHAFullLength { res, err := repo.GetRefCommitID(idStr) if err != nil { return nil, err diff --git a/modules/git/sha1.go b/modules/git/sha1.go index 3a02484bc23b..4d69653e09ac 100644 --- a/modules/git/sha1.go +++ b/modules/git/sha1.go @@ -17,6 +17,9 @@ const EmptySHA = "0000000000000000000000000000000000000000" // EmptyTreeSHA is the SHA of an empty tree const EmptyTreeSHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" +// SHAFullLength is the full length of a git SHA +const SHAFullLength = 40 + // SHAPattern can be used to determine if a string is an valid sha var shaPattern = regexp.MustCompile(`^[0-9a-f]{4,40}$`) @@ -50,7 +53,7 @@ func MustIDFromString(s string) SHA1 { func NewIDFromString(s string) (SHA1, error) { var id SHA1 s = strings.TrimSpace(s) - if len(s) != 40 { + if len(s) != SHAFullLength { return id, fmt.Errorf("Length must be 40: %s", s) } b, err := hex.DecodeString(s) diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go index d07ab10db069..027d13555c05 100644 --- a/modules/indexer/code/indexer.go +++ b/modules/indexer/code/indexer.go @@ -84,7 +84,7 @@ type IndexerData struct { var indexerQueue queue.UniqueQueue func index(ctx context.Context, indexer Indexer, repoID int64) error { - repo, err := repo_model.GetRepositoryByID(repoID) + repo, err := repo_model.GetRepositoryByID(ctx, repoID) if repo_model.IsErrRepoNotExist(err) { return indexer.Delete(repoID) } diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go index 068626c4faed..9bbdcad60d46 100644 --- a/modules/indexer/stats/db.go +++ b/modules/indexer/stats/db.go @@ -21,7 +21,7 @@ func (db *DBIndexer) Index(id int64) error { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().ShutdownContext(), fmt.Sprintf("Stats.DB Index Repo[%d]", id)) defer finished() - repo, err := repo_model.GetRepositoryByID(id) + repo, err := repo_model.GetRepositoryByID(ctx, id) if err != nil { return err } diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index f9a1bc520a2f..bc6c4cd7f857 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -36,7 +36,7 @@ func TestRepoStatsIndex(t *testing.T) { err := Init() assert.NoError(t, err) - repo, err := repo_model.GetRepositoryByID(1) + repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 1) assert.NoError(t, err) err = UpdateRepoIndexer(repo) diff --git a/modules/issue/template/unmarshal.go b/modules/issue/template/unmarshal.go index f43a83fb62b8..8cae8d4c4299 100644 --- a/modules/issue/template/unmarshal.go +++ b/modules/issue/template/unmarshal.go @@ -6,7 +6,7 @@ package template import ( "fmt" "io" - "path/filepath" + "path" "strconv" "code.gitea.io/gitea/modules/git" @@ -43,7 +43,7 @@ func Unmarshal(filename string, content []byte) (*api.IssueTemplate, error) { // UnmarshalFromEntry parses out a valid template from the blob in entry func UnmarshalFromEntry(entry *git.TreeEntry, dir string) (*api.IssueTemplate, error) { - return unmarshalFromEntry(entry, filepath.Join(dir, entry.Name())) + return unmarshalFromEntry(entry, path.Join(dir, entry.Name())) // Filepaths in Git are ALWAYS '/' separated do not use filepath here } // UnmarshalFromCommit parses out a valid template from the commit @@ -108,7 +108,7 @@ func unmarshal(filename string, content []byte) (*api.IssueTemplate, error) { // It could be a valid markdown with two horizontal lines, or an invalid markdown with wrong metadata. it.Content = string(content) - it.Name = filepath.Base(it.FileName) + it.Name = path.Base(it.FileName) // paths in Git are always '/' separated - do not use filepath! it.About, _ = util.SplitStringAtByteN(it.Content, 80) } else { it.Content = templateBody diff --git a/modules/json/json.go b/modules/json/json.go index 35691eec8615..5f8c474e0526 100644 --- a/modules/json/json.go +++ b/modules/json/json.go @@ -1,5 +1,5 @@ // Copyright 2020 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a BSD-style +// SPDX-License-Identifier: MIT package json diff --git a/modules/log/groutinelabel.go b/modules/log/groutinelabel.go index 829c217574e8..56d7af42da3f 100644 --- a/modules/log/groutinelabel.go +++ b/modules/log/groutinelabel.go @@ -6,7 +6,7 @@ package log import "unsafe" //go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel -func runtime_getProfLabel() unsafe.Pointer // nolint +func runtime_getProfLabel() unsafe.Pointer //nolint type labelMap map[string]string diff --git a/modules/markup/html.go b/modules/markup/html.go index 80b19ba35f21..6b5a8e32d4ef 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -305,18 +305,15 @@ func postProcess(ctx *RenderContext, procs []processor, input io.Reader, output return err } - res := bytes.NewBuffer(make([]byte, 0, len(rawHTML)+50)) - // prepend "" - _, _ = res.WriteString("") - - // Strip out nuls - they're always invalid - _, _ = res.Write(tagCleaner.ReplaceAll([]byte(nulCleaner.Replace(string(rawHTML))), []byte("<$1"))) - - // close the tags - _, _ = res.WriteString("") - // parse the HTML - node, err := html.Parse(res) + node, err := html.Parse(io.MultiReader( + // prepend "" + strings.NewReader(""), + // Strip out nuls - they're always invalid + bytes.NewReader(tagCleaner.ReplaceAll([]byte(nulCleaner.Replace(string(rawHTML))), []byte("<$1"))), + // close the tags + strings.NewReader(""), + )) if err != nil { return &postProcessError{"invalid HTML", err} } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 1e5c4707585e..f1ffea887246 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -289,9 +289,3 @@ func RenderRawString(ctx *markup.RenderContext, content string) (string, error) } return buf.String(), nil } - -// IsMarkdownFile reports whether name looks like a Markdown file -// based on its extension. -func IsMarkdownFile(name string) bool { - return markup.IsMarkupFile(name, MarkupName) -} diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go index bb2c47f18e99..cc683dc5b7c7 100644 --- a/modules/markup/markdown/markdown_test.go +++ b/modules/markup/markdown/markdown_test.go @@ -74,28 +74,6 @@ func TestRender_StandardLinks(t *testing.T) { `

WikiPage

`) } -func TestMisc_IsMarkdownFile(t *testing.T) { - setting.Markdown.FileExtensions = []string{".md", ".markdown", ".mdown", ".mkd"} - trueTestCases := []string{ - "test.md", - "wow.MARKDOWN", - "LOL.mDoWn", - } - falseTestCases := []string{ - "test", - "abcdefg", - "abcdefghijklmnopqrstuvwxyz", - "test.md.test", - } - - for _, testCase := range trueTestCases { - assert.True(t, IsMarkdownFile(testCase)) - } - for _, testCase := range falseTestCases { - assert.False(t, IsMarkdownFile(testCase)) - } -} - func TestRender_Images(t *testing.T) { setting.AppURL = AppURL setting.AppSubURL = AppSubURL diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index 326d987ba536..97d5e04340d9 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -14,13 +14,13 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification/base" "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" webhook_services "code.gitea.io/gitea/services/webhook" ) @@ -58,7 +58,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user Action: api.HookIssueLabelCleared, Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } else { @@ -66,7 +66,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(ctx context.Context, doer *user Action: api.HookIssueLabelCleared, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } @@ -81,8 +81,8 @@ func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_m // forked webhook if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: oldRepo}, webhook.HookEventFork, &api.ForkPayload{ - Forkee: convert.ToRepo(oldRepo, oldMode), - Repo: convert.ToRepo(repo, mode), + Forkee: convert.ToRepo(ctx, oldRepo, oldMode), + Repo: convert.ToRepo(ctx, repo, mode), Sender: convert.ToUser(doer, nil), }); err != nil { log.Error("PrepareWebhooks [repo_id: %d]: %v", oldRepo.ID, err) @@ -94,7 +94,7 @@ func (m *webhookNotifier) NotifyForkRepository(ctx context.Context, doer *user_m if u.IsOrganization() { if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), Sender: convert.ToUser(doer, nil), }); err != nil { @@ -107,7 +107,7 @@ func (m *webhookNotifier) NotifyCreateRepository(ctx context.Context, doer, u *u // Add to hook queue for created repo after session commit. if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), Sender: convert.ToUser(doer, nil), }); err != nil { @@ -118,7 +118,7 @@ func (m *webhookNotifier) NotifyCreateRepository(ctx context.Context, doer, u *u func (m *webhookNotifier) NotifyDeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_model.Repository) { if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoDeleted, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(repo.MustOwner(ctx), nil), Sender: convert.ToUser(doer, nil), }); err != nil { @@ -130,7 +130,7 @@ func (m *webhookNotifier) NotifyMigrateRepository(ctx context.Context, doer, u * // Add to hook queue for created repo after session commit. if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventRepository, &api.RepositoryPayload{ Action: api.HookRepoCreated, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Organization: convert.ToUser(u, nil), Sender: convert.ToUser(doer, nil), }); err != nil { @@ -150,7 +150,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *u apiPullRequest := &api.PullRequestPayload{ Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), } if removed { @@ -168,7 +168,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(ctx context.Context, doer *u apiIssue := &api.IssuePayload{ Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), } if removed { @@ -202,7 +202,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user }, }, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } else { @@ -215,7 +215,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(ctx context.Context, doer *user }, }, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } @@ -237,7 +237,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use apiPullRequest := &api.PullRequestPayload{ Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), } if isClosed { @@ -250,7 +250,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(ctx context.Context, doer *use apiIssue := &api.IssuePayload{ Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), } if isClosed { @@ -280,7 +280,7 @@ func (m *webhookNotifier) NotifyNewIssue(ctx context.Context, issue *issues_mode Action: api.HookIssueOpened, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(issue.Poster, nil), }); err != nil { log.Error("PrepareWebhooks: %v", err) @@ -306,7 +306,7 @@ func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues Action: api.HookIssueOpened, Index: pull.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pull, nil), - Repository: convert.ToRepo(pull.Issue.Repo, mode), + Repository: convert.ToRepo(ctx, pull.Issue.Repo, mode), Sender: convert.ToUser(pull.Issue.Poster, nil), }); err != nil { log.Error("PrepareWebhooks: %v", err) @@ -314,6 +314,11 @@ func (m *webhookNotifier) NotifyNewPullRequest(ctx context.Context, pull *issues } func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldContent string) { + if err := issue.LoadRepo(ctx); err != nil { + log.Error("LoadRepo: %v", err) + return + } + mode, _ := access_model.AccessLevel(ctx, issue.Poster, issue.Repo) var err error if issue.IsPull { @@ -327,7 +332,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *us }, }, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } else { @@ -340,7 +345,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(ctx context.Context, doer *us }, }, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } @@ -381,7 +386,7 @@ func (m *webhookNotifier) NotifyUpdateComment(ctx context.Context, doer *user_mo From: oldContent, }, }, - Repository: convert.ToRepo(c.Issue.Repo, mode), + Repository: convert.ToRepo(ctx, c.Issue.Repo, mode), Sender: convert.ToUser(doer, nil), IsPull: c.Issue.IsPull, }); err != nil { @@ -404,7 +409,7 @@ func (m *webhookNotifier) NotifyCreateIssueComment(ctx context.Context, doer *us Action: api.HookIssueCommentCreated, Issue: convert.ToAPIIssue(ctx, issue), Comment: convert.ToComment(comment), - Repository: convert.ToRepo(repo, mode), + Repository: convert.ToRepo(ctx, repo, mode), Sender: convert.ToUser(doer, nil), IsPull: issue.IsPull, }); err != nil { @@ -441,7 +446,7 @@ func (m *webhookNotifier) NotifyDeleteComment(ctx context.Context, doer *user_mo Action: api.HookIssueCommentDeleted, Issue: convert.ToAPIIssue(ctx, comment.Issue), Comment: convert.ToComment(comment), - Repository: convert.ToRepo(comment.Issue.Repo, mode), + Repository: convert.ToRepo(ctx, comment.Issue.Repo, mode), Sender: convert.ToUser(doer, nil), IsPull: comment.Issue.IsPull, }); err != nil { @@ -453,7 +458,7 @@ func (m *webhookNotifier) NotifyNewWikiPage(ctx context.Context, doer *user_mode // Add to hook queue for created wiki page. if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiCreated, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), Page: page, Comment: comment, @@ -466,7 +471,7 @@ func (m *webhookNotifier) NotifyEditWikiPage(ctx context.Context, doer *user_mod // Add to hook queue for edit wiki page. if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiEdited, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), Page: page, Comment: comment, @@ -479,7 +484,7 @@ func (m *webhookNotifier) NotifyDeleteWikiPage(ctx context.Context, doer *user_m // Add to hook queue for edit wiki page. if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventWiki, &api.WikiPayload{ Action: api.HookWikiDeleted, - Repository: convert.ToRepo(repo, perm.AccessModeOwner), + Repository: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Sender: convert.ToUser(doer, nil), Page: page, }); err != nil { @@ -516,7 +521,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *use Action: api.HookIssueLabelUpdated, Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, perm.AccessModeNone), + Repository: convert.ToRepo(ctx, issue.Repo, perm.AccessModeNone), Sender: convert.ToUser(doer, nil), }) } else { @@ -524,7 +529,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(ctx context.Context, doer *use Action: api.HookIssueLabelUpdated, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } @@ -558,7 +563,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer * Action: hookAction, Index: issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } else { @@ -566,7 +571,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(ctx context.Context, doer * Action: hookAction, Index: issue.Index, Issue: convert.ToAPIIssue(ctx, issue), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }) } @@ -591,7 +596,7 @@ func (m *webhookNotifier) NotifyPushCommits(ctx context.Context, pusher *user_mo Commits: apiCommits, TotalCommits: commits.Len, HeadCommit: apiHeadCommit, - Repo: convert.ToRepo(repo, perm.AccessModeOwner), + Repo: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Pusher: apiPusher, Sender: apiPusher, }); err != nil { @@ -631,7 +636,7 @@ func (*webhookNotifier) NotifyMergePullRequest(ctx context.Context, doer *user_m apiPullRequest := &api.PullRequestPayload{ Index: pr.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), - Repository: convert.ToRepo(pr.Issue.Repo, mode), + Repository: convert.ToRepo(ctx, pr.Issue.Repo, mode), Sender: convert.ToUser(doer, nil), Action: api.HookIssueClosed, } @@ -659,7 +664,7 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(ctx context.Contex }, }, PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), - Repository: convert.ToRepo(issue.Repo, mode), + Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(doer, nil), }); err != nil { log.Error("PrepareWebhooks [pr: %d]: %v", pr.ID, err) @@ -696,7 +701,7 @@ func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issue Action: api.HookIssueReviewed, Index: review.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), - Repository: convert.ToRepo(review.Issue.Repo, mode), + Repository: convert.ToRepo(ctx, review.Issue.Repo, mode), Sender: convert.ToUser(review.Reviewer, nil), Review: &api.ReviewPayload{ Type: string(reviewHookType), @@ -709,7 +714,7 @@ func (m *webhookNotifier) NotifyPullRequestReview(ctx context.Context, pr *issue func (m *webhookNotifier) NotifyCreateRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName, refID string) { apiPusher := convert.ToUser(pusher, nil) - apiRepo := convert.ToRepo(repo, perm.AccessModeNone) + apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) refName := git.RefEndName(refFullName) if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventCreate, &api.CreatePayload{ @@ -737,7 +742,7 @@ func (m *webhookNotifier) NotifyPullRequestSynchronized(ctx context.Context, doe Action: api.HookIssueSynchronized, Index: pr.Issue.Index, PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), - Repository: convert.ToRepo(pr.Issue.Repo, perm.AccessModeNone), + Repository: convert.ToRepo(ctx, pr.Issue.Repo, perm.AccessModeNone), Sender: convert.ToUser(doer, nil), }); err != nil { log.Error("PrepareWebhooks [pull_id: %v]: %v", pr.ID, err) @@ -746,7 +751,7 @@ func (m *webhookNotifier) NotifyPullRequestSynchronized(ctx context.Context, doe func (m *webhookNotifier) NotifyDeleteRef(ctx context.Context, pusher *user_model.User, repo *repo_model.Repository, refType, refFullName string) { apiPusher := convert.ToUser(pusher, nil) - apiRepo := convert.ToRepo(repo, perm.AccessModeNone) + apiRepo := convert.ToRepo(ctx, repo, perm.AccessModeNone) refName := git.RefEndName(refFullName) if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: repo}, webhook.HookEventDelete, &api.DeletePayload{ @@ -770,7 +775,7 @@ func sendReleaseHook(ctx context.Context, doer *user_model.User, rel *repo_model if err := webhook_services.PrepareWebhooks(ctx, webhook_services.EventSource{Repository: rel.Repo}, webhook.HookEventRelease, &api.ReleasePayload{ Action: action, Release: convert.ToRelease(rel), - Repository: convert.ToRepo(rel.Repo, mode), + Repository: convert.ToRepo(ctx, rel.Repo, mode), Sender: convert.ToUser(doer, nil), }); err != nil { log.Error("PrepareWebhooks: %v", err) @@ -805,7 +810,7 @@ func (m *webhookNotifier) NotifySyncPushCommits(ctx context.Context, pusher *use Commits: apiCommits, TotalCommits: commits.Len, HeadCommit: apiHeadCommit, - Repo: convert.ToRepo(repo, perm.AccessModeOwner), + Repo: convert.ToRepo(ctx, repo, perm.AccessModeOwner), Pusher: apiPusher, Sender: apiPusher, }); err != nil { diff --git a/modules/packages/hashed_buffer_test.go b/modules/packages/hashed_buffer_test.go index 529262226fae..e907aa060578 100644 --- a/modules/packages/hashed_buffer_test.go +++ b/modules/packages/hashed_buffer_test.go @@ -4,7 +4,7 @@ package packages import ( - "fmt" + "encoding/hex" "io" "strings" "testing" @@ -36,10 +36,10 @@ func TestHashedBuffer(t *testing.T) { assert.Equal(t, c.Data, string(data)) hashMD5, hashSHA1, hashSHA256, hashSHA512 := buf.Sums() - assert.Equal(t, c.HashMD5, fmt.Sprintf("%x", hashMD5)) - assert.Equal(t, c.HashSHA1, fmt.Sprintf("%x", hashSHA1)) - assert.Equal(t, c.HashSHA256, fmt.Sprintf("%x", hashSHA256)) - assert.Equal(t, c.HashSHA512, fmt.Sprintf("%x", hashSHA512)) + assert.Equal(t, c.HashMD5, hex.EncodeToString(hashMD5)) + assert.Equal(t, c.HashSHA1, hex.EncodeToString(hashSHA1)) + assert.Equal(t, c.HashSHA256, hex.EncodeToString(hashSHA256)) + assert.Equal(t, c.HashSHA512, hex.EncodeToString(hashSHA512)) assert.NoError(t, buf.Close()) } diff --git a/modules/packages/multi_hasher_test.go b/modules/packages/multi_hasher_test.go index 42c1ef416f4e..a37debbc95ff 100644 --- a/modules/packages/multi_hasher_test.go +++ b/modules/packages/multi_hasher_test.go @@ -4,7 +4,7 @@ package packages import ( - "fmt" + "encoding/hex" "testing" "github.com/stretchr/testify/assert" @@ -24,10 +24,10 @@ func TestMultiHasherSums(t *testing.T) { hashMD5, hashSHA1, hashSHA256, hashSHA512 := h.Sums() - assert.Equal(t, expectedMD5, fmt.Sprintf("%x", hashMD5)) - assert.Equal(t, expectedSHA1, fmt.Sprintf("%x", hashSHA1)) - assert.Equal(t, expectedSHA256, fmt.Sprintf("%x", hashSHA256)) - assert.Equal(t, expectedSHA512, fmt.Sprintf("%x", hashSHA512)) + assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5)) + assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1)) + assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256)) + assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512)) }) t.Run("State", func(t *testing.T) { @@ -45,9 +45,9 @@ func TestMultiHasherSums(t *testing.T) { hashMD5, hashSHA1, hashSHA256, hashSHA512 := h2.Sums() - assert.Equal(t, expectedMD5, fmt.Sprintf("%x", hashMD5)) - assert.Equal(t, expectedSHA1, fmt.Sprintf("%x", hashSHA1)) - assert.Equal(t, expectedSHA256, fmt.Sprintf("%x", hashSHA256)) - assert.Equal(t, expectedSHA512, fmt.Sprintf("%x", hashSHA512)) + assert.Equal(t, expectedMD5, hex.EncodeToString(hashMD5)) + assert.Equal(t, expectedSHA1, hex.EncodeToString(hashSHA1)) + assert.Equal(t, expectedSHA256, hex.EncodeToString(hashSHA256)) + assert.Equal(t, expectedSHA512, hex.EncodeToString(hashSHA512)) }) } diff --git a/modules/packages/nuget/metadata.go b/modules/packages/nuget/metadata.go index dc72d0982a13..033421af96a8 100644 --- a/modules/packages/nuget/metadata.go +++ b/modules/packages/nuget/metadata.go @@ -5,8 +5,10 @@ package nuget import ( "archive/zip" + "bytes" "encoding/xml" "errors" + "fmt" "io" "path/filepath" "regexp" @@ -182,7 +184,23 @@ func ParseNuspecMetaData(r io.Reader) (*Package, error) { return &Package{ PackageType: packageType, ID: p.Metadata.ID, - Version: v.String(), + Version: toNormalizedVersion(v), Metadata: m, }, nil } + +// https://learn.microsoft.com/en-us/nuget/concepts/package-versioning#normalized-version-numbers +// https://github.com/NuGet/NuGet.Client/blob/dccbd304b11103e08b97abf4cf4bcc1499d9235a/src/NuGet.Core/NuGet.Versioning/VersionFormatter.cs#L121 +func toNormalizedVersion(v *version.Version) string { + var buf bytes.Buffer + segments := v.Segments64() + fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2]) + if len(segments) > 3 && segments[3] > 0 { + fmt.Fprintf(&buf, ".%d", segments[3]) + } + pre := v.Prerelease() + if pre != "" { + fmt.Fprint(&buf, "-", pre) + } + return buf.String() +} diff --git a/modules/packages/nuget/metadata_test.go b/modules/packages/nuget/metadata_test.go index 74c3e7dfaa5e..bba2bff4a538 100644 --- a/modules/packages/nuget/metadata_test.go +++ b/modules/packages/nuget/metadata_test.go @@ -146,6 +146,19 @@ func TestParseNuspecMetaData(t *testing.T) { assert.Len(t, deps, 1) assert.Equal(t, dependencyID, deps[0].ID) assert.Equal(t, dependencyVersion, deps[0].Version) + + t.Run("NormalizedVersion", func(t *testing.T) { + np, err := ParseNuspecMetaData(strings.NewReader(` + + + test + 1.04.5.2.5-rc.1+metadata + +`)) + assert.NoError(t, err) + assert.NotNil(t, np) + assert.Equal(t, "1.4.5.2-rc.1", np.Version) + }) }) t.Run("Symbols Package", func(t *testing.T) { diff --git a/modules/paginator/paginator.go b/modules/paginator/paginator.go index 342ee8929c63..8258d194c263 100644 --- a/modules/paginator/paginator.go +++ b/modules/paginator/paginator.go @@ -1,5 +1,6 @@ // Copyright 2022 The Gitea Authors. // Copyright 2015 https://github.com/unknwon. Licensed under the Apache License, Version 2.0 +// SPDX-License-Identifier: Apache-2.0 package paginator diff --git a/modules/paginator/paginator_test.go b/modules/paginator/paginator_test.go index 404f76f6c4f9..41bb30533756 100644 --- a/modules/paginator/paginator_test.go +++ b/modules/paginator/paginator_test.go @@ -1,5 +1,6 @@ // Copyright 2022 The Gitea Authors. // Copyright 2015 https://github.com/unknwon. Licensed under the Apache License, Version 2.0 +// SPDX-License-Identifier: Apache-2.0 package paginator diff --git a/modules/queue/queue_channel.go b/modules/queue/queue_channel.go index 431f48390c8b..6f75b8357eab 100644 --- a/modules/queue/queue_channel.go +++ b/modules/queue/queue_channel.go @@ -109,32 +109,6 @@ func (q *ChannelQueue) Flush(timeout time.Duration) error { return q.FlushWithContext(ctx) } -// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty -func (q *ChannelQueue) FlushWithContext(ctx context.Context) error { - log.Trace("ChannelQueue: %d Flush", q.qid) - paused, _ := q.IsPausedIsResumed() - for { - select { - case <-paused: - return nil - case data, ok := <-q.dataChan: - if !ok { - return nil - } - if unhandled := q.handle(data); unhandled != nil { - log.Error("Unhandled Data whilst flushing queue %d", q.qid) - } - atomic.AddInt64(&q.numInQueue, -1) - case <-q.baseCtx.Done(): - return q.baseCtx.Err() - case <-ctx.Done(): - return ctx.Err() - default: - return nil - } - } -} - // Shutdown processing from this queue func (q *ChannelQueue) Shutdown() { q.lock.Lock() diff --git a/modules/queue/unique_queue_channel.go b/modules/queue/unique_queue_channel.go index f2d3dbdc970f..c43bd1db3f7d 100644 --- a/modules/queue/unique_queue_channel.go +++ b/modules/queue/unique_queue_channel.go @@ -8,7 +8,6 @@ import ( "fmt" "runtime/pprof" "sync" - "sync/atomic" "time" "code.gitea.io/gitea/modules/container" @@ -167,35 +166,6 @@ func (q *ChannelUniqueQueue) Flush(timeout time.Duration) error { return q.FlushWithContext(ctx) } -// FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty -func (q *ChannelUniqueQueue) FlushWithContext(ctx context.Context) error { - log.Trace("ChannelUniqueQueue: %d Flush", q.qid) - paused, _ := q.IsPausedIsResumed() - for { - select { - case <-paused: - return nil - default: - } - select { - case data, ok := <-q.dataChan: - if !ok { - return nil - } - if unhandled := q.handle(data); unhandled != nil { - log.Error("Unhandled Data whilst flushing queue %d", q.qid) - } - atomic.AddInt64(&q.numInQueue, -1) - case <-q.baseCtx.Done(): - return q.baseCtx.Err() - case <-ctx.Done(): - return ctx.Err() - default: - return nil - } - } -} - // Shutdown processing from this queue func (q *ChannelUniqueQueue) Shutdown() { log.Trace("ChannelUniqueQueue: %s Shutting down", q.name) diff --git a/modules/queue/workerpool.go b/modules/queue/workerpool.go index 244927880e92..b32128cb8214 100644 --- a/modules/queue/workerpool.go +++ b/modules/queue/workerpool.go @@ -463,13 +463,43 @@ func (p *WorkerPool) IsEmpty() bool { return atomic.LoadInt64(&p.numInQueue) == 0 } +// contextError returns either ctx.Done(), the base context's error or nil +func (p *WorkerPool) contextError(ctx context.Context) error { + select { + case <-p.baseCtx.Done(): + return p.baseCtx.Err() + case <-ctx.Done(): + return ctx.Err() + default: + return nil + } +} + // FlushWithContext is very similar to CleanUp but it will return as soon as the dataChan is empty // NB: The worker will not be registered with the manager. func (p *WorkerPool) FlushWithContext(ctx context.Context) error { log.Trace("WorkerPool: %d Flush", p.qid) + paused, _ := p.IsPausedIsResumed() for { + // Because select will return any case that is satisified at random we precheck here before looking at dataChan. + select { + case <-paused: + // Ensure that even if paused that the cancelled error is still sent + return p.contextError(ctx) + case <-p.baseCtx.Done(): + return p.baseCtx.Err() + case <-ctx.Done(): + return ctx.Err() + default: + } + select { - case data := <-p.dataChan: + case <-paused: + return p.contextError(ctx) + case data, ok := <-p.dataChan: + if !ok { + return nil + } if unhandled := p.handle(data); unhandled != nil { log.Error("Unhandled Data whilst flushing queue %d", p.qid) } @@ -495,6 +525,7 @@ func (p *WorkerPool) doWork(ctx context.Context) { paused, _ := p.IsPausedIsResumed() data := make([]Data, 0, p.batchLength) for { + // Because select will return any case that is satisified at random we precheck here before looking at dataChan. select { case <-paused: log.Trace("Worker for Queue %d Pausing", p.qid) @@ -515,8 +546,19 @@ func (p *WorkerPool) doWork(ctx context.Context) { log.Trace("Worker shutting down") return } + case <-ctx.Done(): + if len(data) > 0 { + log.Trace("Handling: %d data, %v", len(data), data) + if unhandled := p.handle(data...); unhandled != nil { + log.Error("Unhandled Data in queue %d", p.qid) + } + atomic.AddInt64(&p.numInQueue, -1*int64(len(data))) + } + log.Trace("Worker shutting down") + return default: } + select { case <-paused: // go back around diff --git a/modules/repository/collaborator.go b/modules/repository/collaborator.go index 44c03f999ee7..f2b95151879f 100644 --- a/modules/repository/collaborator.go +++ b/modules/repository/collaborator.go @@ -13,30 +13,25 @@ import ( user_model "code.gitea.io/gitea/models/user" ) -func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error { - collaboration := &repo_model.Collaboration{ - RepoID: repo.ID, - UserID: u.ID, - } - - has, err := db.GetByBean(ctx, collaboration) - if err != nil { - return err - } else if has { - return nil - } - collaboration.Mode = perm.AccessModeWrite - - if err = db.Insert(ctx, collaboration); err != nil { - return err - } - - return access_model.RecalculateUserAccess(ctx, repo, u.ID) -} - -// AddCollaborator adds new collaboration to a repository with default access mode. -func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error { - return db.WithTx(db.DefaultContext, func(ctx context.Context) error { - return addCollaborator(ctx, repo, u) +func AddCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error { + return db.AutoTx(ctx, func(ctx context.Context) error { + collaboration := &repo_model.Collaboration{ + RepoID: repo.ID, + UserID: u.ID, + } + + has, err := db.GetByBean(ctx, collaboration) + if err != nil { + return err + } else if has { + return nil + } + collaboration.Mode = perm.AccessModeWrite + + if err = db.Insert(ctx, collaboration); err != nil { + return err + } + + return access_model.RecalculateUserAccess(ctx, repo, u.ID) }) } diff --git a/modules/repository/collaborator_test.go b/modules/repository/collaborator_test.go index ad835ae4d428..6cf239d0eada 100644 --- a/modules/repository/collaborator_test.go +++ b/modules/repository/collaborator_test.go @@ -25,7 +25,7 @@ func TestRepository_AddCollaborator(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) assert.NoError(t, repo.GetOwner(db.DefaultContext)) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}, &user_model.User{ID: userID}) } testSuccess(1, 4) @@ -50,7 +50,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { } // change to collaborator - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -103,7 +103,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -111,7 +111,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -155,7 +155,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -163,7 +163,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -217,7 +217,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { } // change to collaborator to default write access - assert.NoError(t, AddCollaborator(repo, user)) + assert.NoError(t, AddCollaborator(db.DefaultContext, repo, user)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { @@ -225,7 +225,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, user.ID, perm_model.AccessModeRead)) perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { diff --git a/modules/repository/create.go b/modules/repository/create.go index 8bee890aadb2..1e157ec85eff 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -125,10 +125,10 @@ func CreateRepositoryByExample(ctx context.Context, doer, u *user_model.User, re return fmt.Errorf("IsUserRepoAdmin: %w", err) } else if !isAdmin { // Make creator repo admin if it wasn't assigned automatically - if err = addCollaborator(ctx, repo, doer); err != nil { - return fmt.Errorf("addCollaborator: %w", err) + if err = AddCollaborator(ctx, repo, doer); err != nil { + return fmt.Errorf("AddCollaborator: %w", err) } - if err = repo_model.ChangeCollaborationAccessModeCtx(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil { + if err = repo_model.ChangeCollaborationAccessMode(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil { return fmt.Errorf("ChangeCollaborationAccessModeCtx: %w", err) } } diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go index 94a9b26aa695..da4a738b6497 100644 --- a/modules/repository/create_test.go +++ b/modules/repository/create_test.go @@ -25,7 +25,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { testTeamRepositories := func(teamID int64, repoIds []int64) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: teamID}) - assert.NoError(t, team.GetRepositoriesCtx(db.DefaultContext), "%s: GetRepositories", team.Name) + assert.NoError(t, team.LoadRepositories(db.DefaultContext), "%s: GetRepositories", team.Name) assert.Len(t, team.Repos, team.NumRepos, "%s: len repo", team.Name) assert.Len(t, team.Repos, len(repoIds), "%s: repo count", team.Name) for i, rid := range repoIds { @@ -36,7 +36,7 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { } // Get an admin user. - user, err := user_model.GetUserByID(1) + user, err := user_model.GetUserByID(db.DefaultContext, 1) assert.NoError(t, err, "GetUserByID") // Create org. @@ -153,7 +153,7 @@ func TestUpdateRepositoryVisibilityChanged(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // Get sample repo and change visibility - repo, err := repo_model.GetRepositoryByID(9) + repo, err := repo_model.GetRepositoryByID(db.DefaultContext, 9) assert.NoError(t, err) repo.IsPrivate = true diff --git a/modules/repository/generate.go b/modules/repository/generate.go index 5726a8fb1b4b..d72934729cd8 100644 --- a/modules/repository/generate.go +++ b/modules/repository/generate.go @@ -243,7 +243,7 @@ func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *r } // re-fetch repo - if repo, err = repo_model.GetRepositoryByIDCtx(ctx, repo.ID); err != nil { + if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil { return fmt.Errorf("getRepositoryByID: %w", err) } diff --git a/modules/repository/init.go b/modules/repository/init.go index cd7176c238d5..59284a5bafc8 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -414,7 +414,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re // Re-fetch the repository from database before updating it (else it would // override changes that were done earlier with sql) - if repo, err = repo_model.GetRepositoryByIDCtx(ctx, repo.ID); err != nil { + if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil { return fmt.Errorf("getRepositoryByID: %w", err) } diff --git a/modules/session/redis.go b/modules/session/redis.go index 334418bd7e5d..5fb59e480457 100644 --- a/modules/session/redis.go +++ b/modules/session/redis.go @@ -13,6 +13,7 @@ // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. +// SPDX-License-Identifier: Apache-2.0 package session diff --git a/modules/setting/database.go b/modules/setting/database.go index be06c47478fd..5480f9dffd90 100644 --- a/modules/setting/database.go +++ b/modules/setting/database.go @@ -49,6 +49,7 @@ var ( MaxOpenConns int ConnMaxLifetime time.Duration IterateBufferSize int + AutoMigration bool }{ Timeout: 500, IterateBufferSize: 50, @@ -105,6 +106,7 @@ func InitDBConfig() { Database.LogSQL = sec.Key("LOG_SQL").MustBool(true) Database.DBConnectRetries = sec.Key("DB_RETRIES").MustInt(10) Database.DBConnectBackoff = sec.Key("DB_RETRY_BACKOFF").MustDuration(3 * time.Second) + Database.AutoMigration = sec.Key("AUTO_MIGRATION").MustBool(true) } // DBConnStr returns database connection string diff --git a/modules/setting/repository.go b/modules/setting/repository.go index 19594369be63..d78b63a1f3f7 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -48,6 +48,7 @@ var ( AllowAdoptionOfUnadoptedRepositories bool AllowDeleteOfUnadoptedRepositories bool DisableDownloadSourceArchives bool + AllowForkWithoutMaximumLimit bool // Repository editor settings Editor struct { @@ -82,6 +83,7 @@ var ( DefaultMergeMessageOfficialApproversOnly bool PopulateSquashCommentWithCommitMessages bool AddCoCommitterTrailers bool + TestConflictingPatchesWithGitApply bool } `ini:"repository.pull-request"` // Issue Setting @@ -159,6 +161,7 @@ var ( DisableMigrations: false, DisableStars: false, DefaultBranch: "main", + AllowForkWithoutMaximumLimit: true, // Repository editor settings Editor: struct { @@ -204,6 +207,7 @@ var ( DefaultMergeMessageOfficialApproversOnly bool PopulateSquashCommentWithCommitMessages bool AddCoCommitterTrailers bool + TestConflictingPatchesWithGitApply bool }{ WorkInProgressPrefixes: []string{"WIP:", "[WIP]"}, // Same as GitHub. See diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 68892a219825..07290fbfeb9f 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -465,6 +465,13 @@ func getAppPath() (string, error) { appPath, err = exec.LookPath(os.Args[0]) } + if err != nil { + // FIXME: Once we switch to go 1.19 use !errors.Is(err, exec.ErrDot) + if !strings.Contains(err.Error(), "cannot run executable found relative to current directory") { + return "", err + } + appPath, err = filepath.Abs(os.Args[0]) + } if err != nil { return "", err } @@ -748,19 +755,22 @@ func loadFromConf(allowEmpty bool, extraConfig string) { PerWriteTimeout = sec.Key("PER_WRITE_TIMEOUT").MustDuration(PerWriteTimeout) PerWritePerKbTimeout = sec.Key("PER_WRITE_PER_KB_TIMEOUT").MustDuration(PerWritePerKbTimeout) - defaultAppURL := string(Protocol) + "://" + Domain - if (Protocol == HTTP && HTTPPort != "80") || (Protocol == HTTPS && HTTPPort != "443") { - defaultAppURL += ":" + HTTPPort - } - AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL + "/") - // This should be TrimRight to ensure that there is only a single '/' at the end of AppURL. - AppURL = strings.TrimRight(AppURL, "/") + "/" + defaultAppURL := string(Protocol) + "://" + Domain + ":" + HTTPPort + AppURL = sec.Key("ROOT_URL").MustString(defaultAppURL) - // Check if has app suburl. + // Check validity of AppURL appURL, err := url.Parse(AppURL) if err != nil { log.Fatal("Invalid ROOT_URL '%s': %s", AppURL, err) } + // Remove default ports from AppURL. + // (scheme-based URL normalization, RFC 3986 section 6.2.3) + if (appURL.Scheme == string(HTTP) && appURL.Port() == "80") || (appURL.Scheme == string(HTTPS) && appURL.Port() == "443") { + appURL.Host = appURL.Hostname() + } + // This should be TrimRight to ensure that there is only a single '/' at the end of AppURL. + AppURL = strings.TrimRight(appURL.String(), "/") + "/" + // Suburl should start with '/' and end without '/', such as '/{subpath}'. // This value is empty if site does not have sub-url. AppSubURL = strings.TrimSuffix(appURL.Path, "/") @@ -938,7 +948,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) { if SecretKey == "" { // FIXME: https://github.com/go-gitea/gitea/issues/16832 // Until it supports rotating an existing secret key, we shouldn't move users off of the widely used default value - SecretKey = "!#@FDEWREWR&*(" // nolint:gosec + SecretKey = "!#@FDEWREWR&*(" //nolint:gosec } CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").MustString("gitea_incredible") @@ -1033,7 +1043,10 @@ func loadFromConf(allowEmpty bool, extraConfig string) { // The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches. // Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly. unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false) - RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod") + RunMode = os.Getenv("GITEA_RUN_MODE") + if RunMode == "" { + RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod") + } IsProd = strings.EqualFold(RunMode, "prod") // Does not check run user when the install lock is off. if InstallLock { diff --git a/modules/storage/helper.go b/modules/storage/helper.go index 5aaa2a9e6430..1ab99d98b31b 100644 --- a/modules/storage/helper.go +++ b/modules/storage/helper.go @@ -4,6 +4,10 @@ package storage import ( + "fmt" + "io" + "net/url" + "os" "reflect" "code.gitea.io/gitea/modules/json" @@ -61,3 +65,31 @@ func toConfig(exemplar, cfg interface{}) (interface{}, error) { } return newVal.Elem().Interface(), nil } + +var uninitializedStorage = discardStorage("uninitialized storage") + +type discardStorage string + +func (s discardStorage) Open(_ string) (Object, error) { + return nil, fmt.Errorf("%s", s) +} + +func (s discardStorage) Save(_ string, _ io.Reader, _ int64) (int64, error) { + return 0, fmt.Errorf("%s", s) +} + +func (s discardStorage) Stat(_ string) (os.FileInfo, error) { + return nil, fmt.Errorf("%s", s) +} + +func (s discardStorage) Delete(_ string) error { + return fmt.Errorf("%s", s) +} + +func (s discardStorage) URL(_, _ string) (*url.URL, error) { + return nil, fmt.Errorf("%s", s) +} + +func (s discardStorage) IterateObjects(_ func(string, Object) error) error { + return fmt.Errorf("%s", s) +} diff --git a/modules/storage/helper_test.go b/modules/storage/helper_test.go new file mode 100644 index 000000000000..7d74671c544a --- /dev/null +++ b/modules/storage/helper_test.go @@ -0,0 +1,50 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package storage + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_discardStorage(t *testing.T) { + tests := []discardStorage{ + uninitializedStorage, + discardStorage("empty"), + } + for _, tt := range tests { + t.Run(string(tt), func(t *testing.T) { + { + got, err := tt.Open("path") + assert.Nil(t, got) + assert.Error(t, err, string(tt)) + } + { + got, err := tt.Save("path", bytes.NewReader([]byte{0}), 1) + assert.Equal(t, int64(0), got) + assert.Error(t, err, string(tt)) + } + { + got, err := tt.Stat("path") + assert.Nil(t, got) + assert.Error(t, err, string(tt)) + } + { + err := tt.Delete("path") + assert.Error(t, err, string(tt)) + } + { + got, err := tt.URL("path", "name") + assert.Nil(t, got) + assert.Errorf(t, err, string(tt)) + } + { + err := tt.IterateObjects(func(_ string, _ Object) error { return nil }) + assert.Error(t, err, string(tt)) + } + }) + } +} diff --git a/modules/storage/local.go b/modules/storage/local.go index a439a2459223..ca51d26c9afb 100644 --- a/modules/storage/local.go +++ b/modules/storage/local.go @@ -102,7 +102,8 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) return 0, err } // Golang's tmp file (os.CreateTemp) always have 0o600 mode, so we need to change the file to follow the umask (as what Create/MkDir does) - if err := util.ApplyUmask(p, os.ModePerm); err != nil { + // but we don't want to make these files executable - so ensure that we mask out the executable bits + if err := util.ApplyUmask(p, os.ModePerm&0o666); err != nil { return 0, err } diff --git a/modules/storage/storage.go b/modules/storage/storage.go index a7d3b9ce1f69..671e0ce56529 100644 --- a/modules/storage/storage.go +++ b/modules/storage/storage.go @@ -110,46 +110,38 @@ func SaveFrom(objStorage ObjectStorage, p string, callback func(w io.Writer) err var ( // Attachments represents attachments storage - Attachments ObjectStorage + Attachments ObjectStorage = uninitializedStorage // LFS represents lfs storage - LFS ObjectStorage + LFS ObjectStorage = uninitializedStorage // Avatars represents user avatars storage - Avatars ObjectStorage + Avatars ObjectStorage = uninitializedStorage // RepoAvatars represents repository avatars storage - RepoAvatars ObjectStorage + RepoAvatars ObjectStorage = uninitializedStorage // RepoArchives represents repository archives storage - RepoArchives ObjectStorage + RepoArchives ObjectStorage = uninitializedStorage // Packages represents packages storage - Packages ObjectStorage + Packages ObjectStorage = uninitializedStorage ) // Init init the stoarge func Init() error { - if err := initAttachments(); err != nil { - return err - } - - if err := initAvatars(); err != nil { - return err - } - - if err := initRepoAvatars(); err != nil { - return err - } - - if err := initLFS(); err != nil { - return err - } - - if err := initRepoArchives(); err != nil { - return err + for _, f := range []func() error{ + initAttachments, + initAvatars, + initRepoAvatars, + initLFS, + initRepoArchives, + initPackages, + } { + if err := f(); err != nil { + return err + } } - - return initPackages() + return nil } // NewStorage takes a storage type and some config and returns an ObjectStorage or an error @@ -172,12 +164,20 @@ func initAvatars() (err error) { } func initAttachments() (err error) { + if !setting.Attachment.Enabled { + Attachments = discardStorage("Attachment isn't enabled") + return nil + } log.Info("Initialising Attachment storage with type: %s", setting.Attachment.Storage.Type) Attachments, err = NewStorage(setting.Attachment.Storage.Type, &setting.Attachment.Storage) return err } func initLFS() (err error) { + if !setting.LFS.StartServer { + LFS = discardStorage("LFS isn't enabled") + return nil + } log.Info("Initialising LFS storage with type: %s", setting.LFS.Storage.Type) LFS, err = NewStorage(setting.LFS.Storage.Type, &setting.LFS.Storage) return err @@ -196,6 +196,10 @@ func initRepoArchives() (err error) { } func initPackages() (err error) { + if !setting.Packages.Enabled { + Packages = discardStorage("Packages isn't enabled") + return nil + } log.Info("Initialising Packages storage with type: %s", setting.Packages.Storage.Type) Packages, err = NewStorage(setting.Packages.Storage.Type, &setting.Packages.Storage) return err diff --git a/modules/structs/issue.go b/modules/structs/issue.go index 00166b7a07e5..48e4e0e7e369 100644 --- a/modules/structs/issue.go +++ b/modules/structs/issue.go @@ -41,18 +41,19 @@ type RepositoryMeta struct { // Issue represents an issue in a repository // swagger:model type Issue struct { - ID int64 `json:"id"` - URL string `json:"url"` - HTMLURL string `json:"html_url"` - Index int64 `json:"number"` - Poster *User `json:"user"` - OriginalAuthor string `json:"original_author"` - OriginalAuthorID int64 `json:"original_author_id"` - Title string `json:"title"` - Body string `json:"body"` - Ref string `json:"ref"` - Labels []*Label `json:"labels"` - Milestone *Milestone `json:"milestone"` + ID int64 `json:"id"` + URL string `json:"url"` + HTMLURL string `json:"html_url"` + Index int64 `json:"number"` + Poster *User `json:"user"` + OriginalAuthor string `json:"original_author"` + OriginalAuthorID int64 `json:"original_author_id"` + Title string `json:"title"` + Body string `json:"body"` + Ref string `json:"ref"` + Attachments []*Attachment `json:"assets"` + Labels []*Label `json:"labels"` + Milestone *Milestone `json:"milestone"` // deprecated Assignee *User `json:"assignee"` Assignees []*User `json:"assignees"` diff --git a/modules/structs/issue_comment.go b/modules/structs/issue_comment.go index 4a1085ba5012..9e8f5c4bf332 100644 --- a/modules/structs/issue_comment.go +++ b/modules/structs/issue_comment.go @@ -9,14 +9,15 @@ import ( // Comment represents a comment on a commit or issue type Comment struct { - ID int64 `json:"id"` - HTMLURL string `json:"html_url"` - PRURL string `json:"pull_request_url"` - IssueURL string `json:"issue_url"` - Poster *User `json:"user"` - OriginalAuthor string `json:"original_author"` - OriginalAuthorID int64 `json:"original_author_id"` - Body string `json:"body"` + ID int64 `json:"id"` + HTMLURL string `json:"html_url"` + PRURL string `json:"pull_request_url"` + IssueURL string `json:"issue_url"` + Poster *User `json:"user"` + OriginalAuthor string `json:"original_author"` + OriginalAuthorID int64 `json:"original_author_id"` + Body string `json:"body"` + Attachments []*Attachment `json:"assets"` // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 5fa9e17c8a13..7b997b49d9e7 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -25,6 +25,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/avatars" + "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" @@ -631,7 +632,7 @@ func Avatar(item interface{}, others ...interface{}) template.HTML { // AvatarByAction renders user avatars from action. args: action, size (int), class (string) func AvatarByAction(action *activities_model.Action, others ...interface{}) template.HTML { - action.LoadActUser() + action.LoadActUser(db.DefaultContext) return Avatar(action.ActUser, others...) } diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 61e49adb765e..d50f8efc755f 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -57,7 +57,7 @@ func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) { ctx.Repo = &context.Repository{} ctx.Repo.Repository = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}) var err error - ctx.Repo.Owner, err = user_model.GetUserByID(ctx.Repo.Repository.OwnerID) + ctx.Repo.Owner, err = user_model.GetUserByID(ctx, ctx.Repo.Repository.OwnerID) assert.NoError(t, err) ctx.Repo.RepoLink = ctx.Repo.Repository.Link() ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, ctx.Repo.Repository, ctx.Doer) diff --git a/modules/timeutil/timestamp.go b/modules/timeutil/timestamp.go index 4618db9a769d..c8e0d4bdc114 100644 --- a/modules/timeutil/timestamp.go +++ b/modules/timeutil/timestamp.go @@ -12,8 +12,13 @@ import ( // TimeStamp defines a timestamp type TimeStamp int64 -// mock is NOT concurrency-safe!! -var mock time.Time +var ( + // mock is NOT concurrency-safe!! + mock time.Time + + // Used for IsZero, to check if timestamp is the zero time instant. + timeZeroUnix = time.Time{}.Unix() +) // Set sets the time to a mocked time.Time func Set(now time.Time) { @@ -102,5 +107,5 @@ func (ts TimeStamp) FormatDate() string { // IsZero is zero time func (ts TimeStamp) IsZero() bool { - return int64(ts) == 0 + return int64(ts) == 0 || int64(ts) == timeZeroUnix } diff --git a/modules/web/route.go b/modules/web/route.go index cd72aabae5e6..0f2fdc33b5a8 100644 --- a/modules/web/route.go +++ b/modules/web/route.go @@ -7,7 +7,6 @@ import ( goctx "context" "fmt" "net/http" - "reflect" "strings" "code.gitea.io/gitea/modules/context" @@ -18,16 +17,9 @@ import ( ) // Bind binding an obj to a handler -func Bind(obj interface{}) http.HandlerFunc { - tp := reflect.TypeOf(obj) - if tp.Kind() == reflect.Ptr { - tp = tp.Elem() - } - if tp.Kind() != reflect.Struct { - panic("Only structs are allowed to bind") - } +func Bind[T any](obj T) http.HandlerFunc { return Wrap(func(ctx *context.Context) { - theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly + theObj := new(T) // create a new form obj for every request but not use obj directly binding.Bind(ctx.Req, theObj) SetForm(ctx, theObj) middleware.AssignForm(theObj, ctx.Data) diff --git a/options/gitignore/Godot b/options/gitignore/Godot index 4f48ad79f8fb..d9aac213e776 100644 --- a/options/gitignore/Godot +++ b/options/gitignore/Godot @@ -1,3 +1,6 @@ +# Godot 4+ specific ignores +.godot/ + # Godot-specific ignores .import/ export.cfg @@ -9,3 +12,4 @@ export_presets.cfg # Mono-specific ignores .mono/ data_*/ +mono_crash.*.json diff --git a/options/license/Bitstream-Charter b/options/license/Bitstream-Charter new file mode 100644 index 000000000000..7a0cf97a0c98 --- /dev/null +++ b/options/license/Bitstream-Charter @@ -0,0 +1,9 @@ +(c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA. + +You are hereby granted permission under all Bitstream propriety rights +to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream +Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts for +any purpose and without restriction; provided, that this notice is left +intact on all copies of such fonts and that Bitstream's trademark is acknowledged +as shown below on all unmodified copies of the 4 Charter Type 1 fonts. +BITSTREAM CHARTER is a registered trademark of Bitstream Inc. diff --git a/options/license/Graphics-Gems b/options/license/Graphics-Gems new file mode 100644 index 000000000000..ec28c4656361 --- /dev/null +++ b/options/license/Graphics-Gems @@ -0,0 +1,5 @@ +LICENSE + +This code repository predates the concept of Open Source, and predates most licenses along such lines. As such, the official license truly is: + +EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes with no guarantee. diff --git a/options/license/IJG-short b/options/license/IJG-short new file mode 100644 index 000000000000..bbb0859d804d --- /dev/null +++ b/options/license/IJG-short @@ -0,0 +1,35 @@ +The authors make NO WARRANTY or representation, either express or +implied, with respect to this software, its quality, accuracy, +merchantability, or fitness for a particular purpose. This software is +provided "AS IS", and you, its user, assume the entire risk as to its +quality and accuracy. + +This software is copyright (C) 1991, 1992, Thomas G. Lane. All Rights +Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to +these conditions: + +(1) If any part of the source code for this software +is distributed, then this README file must be included, with this +copyright and no-warranty notice unaltered; and any additions, +deletions, or changes to the original files must be clearly indicated +in accompanying documentation. + +(2) If only executable code is +distributed, then the accompanying documentation must state that "this +software is based in part on the work of the Independent JPEG Group". + +(3) Permission for use of this software is granted only if the user +accepts full responsibility for any undesirable consequences; the +authors accept NO LIABILITY for damages of any kind. + +Permission is NOT granted for the use of any IJG author's name or +company name in advertising or publicity relating to this software or +products derived from it. This software may be referred to only as +"the Independent JPEG Group's software". + +We specifically permit and encourage the use of this software as the +basis of commercial products, provided that all warranty or liability +claims are assumed by the product vendor. diff --git a/options/license/LOOP b/options/license/LOOP new file mode 100644 index 000000000000..434d2c45e228 --- /dev/null +++ b/options/license/LOOP @@ -0,0 +1,44 @@ +Portions of LOOP are Copyright (c) 1986 by the Massachusetts Institute of Technology. +All Rights Reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the M.I.T. copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation. The names "M.I.T." and "Massachusetts +Institute of Technology" may not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. Notice must be given in supporting documentation that +copying distribution is by permission of M.I.T. M.I.T. makes no +representations about the suitability of this software for any purpose. +It is provided "as is" without express or implied warranty. + +Massachusetts Institute of Technology +77 Massachusetts Avenue +Cambridge, Massachusetts 02139 +United States of America ++1-617-253-1000 + +Portions of LOOP are Copyright (c) 1989, 1990, 1991, 1992 by Symbolics, Inc. +All Rights Reserved. + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the Symbolics copyright notice appear in all copies and +that both that copyright notice and this permission notice appear in +supporting documentation. The name "Symbolics" may not be used in +advertising or publicity pertaining to distribution of the software +without specific, written prior permission. Notice must be given in +supporting documentation that copying distribution is by permission of +Symbolics. Symbolics makes no representations about the suitability of +this software for any purpose. It is provided "as is" without express +or implied warranty. + +Symbolics, CLOE Runtime, and Minima are trademarks, and CLOE, Genera, +and Zetalisp are registered trademarks of Symbolics, Inc. + +Symbolics, Inc. +8 New England Executive Park, East +Burlington, Massachusetts 01803 +United States of America ++1-617-221-1000 diff --git a/options/license/MIT-Wu b/options/license/MIT-Wu new file mode 100644 index 000000000000..86eec3c517a9 --- /dev/null +++ b/options/license/MIT-Wu @@ -0,0 +1,28 @@ +Copyright (c) 2003-2005 Tom Wu +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "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 TOM WU BE LIABLE FOR ANY SPECIAL, INCIDENTAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF +THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +In addition, the following condition applies: + +All redistributions must retain an intact copy of this copyright notice +and disclaimer. diff --git a/options/license/Symlinks b/options/license/Symlinks new file mode 100644 index 000000000000..35420d2ba9bb --- /dev/null +++ b/options/license/Symlinks @@ -0,0 +1,10 @@ + My "symlinks" utility pre-dates the "open source licensing" +fad by a number of years. Just to clarify, this is 100% +freeware, written entirely by myself. The intent is to use +it to detect missing/obsolete symlink targets on an installed +distro, before creating the "gold" (or "final") release discs. + +Use and distribute and modify as you (or anyone +else) sees fit. There have no formal restrictions or +requirements whatsoever regarding distribution of either +binaries or source code, whether modified or original. diff --git a/options/license/TPDL b/options/license/TPDL new file mode 100644 index 000000000000..d950f8f19e59 --- /dev/null +++ b/options/license/TPDL @@ -0,0 +1,2 @@ +Copyright (C) 1996-2010 David Muir Sharnoff. Copyright (C) 2011 Google, Inc. +License hereby granted for anyone to use, modify or redistribute this module at their own risk. Please feed useful changes back to cpan@dave.sharnoff.org. diff --git a/options/license/TTWL b/options/license/TTWL new file mode 100644 index 000000000000..c13d3fbe04a4 --- /dev/null +++ b/options/license/TTWL @@ -0,0 +1,8 @@ +Copyright (C) 1996-2002,2005,2006 David Muir Sharnoff. +Copyright (C) 2005 Aristotle Pagaltzis +Copyright (C) 2012-2013 Google, Inc. + +This module may be modified, used, copied, and redistributed at your own risk. +Although allowed by the preceding license, please do not publicly +redistribute modified versions of this code with the name "Text::Tabs" +unless it passes the unmodified Text::Tabs test suite. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 8503cb78d712..62471abe6f19 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -505,6 +505,7 @@ team_not_exist = The team does not exist. last_org_owner = You cannot remove the last user from the 'owners' team. There must be at least one owner for an organization. cannot_add_org_to_team = An organization cannot be added as a team member. duplicate_invite_to_team = The user was already invited as a team member. +organization_leave_success = You have successfully left the organization %s. invalid_ssh_key = Can not verify your SSH key: %s invalid_gpg_key = Can not verify your GPG key: %s @@ -1017,7 +1018,7 @@ unstar = Unstar star = Star fork = Fork download_archive = Download Repository -more_actions = More Actions +more_operations = More Operations no_desc = No Description quick_guide = Quick Guide @@ -1172,7 +1173,7 @@ commits.signed_by_untrusted_user_unmatched = Signed by untrusted user who does n commits.gpg_key_id = GPG Key ID commits.ssh_key_fingerprint = SSH Key Fingerprint -commit.actions = Actions +commit.operations = Operations commit.revert = Revert commit.revert-header = Revert: %s commit.revert-content = Select branch to revert onto: @@ -2278,6 +2279,8 @@ release.downloads = Downloads release.download_count = Downloads: %s release.add_tag_msg = Use the title and content of release as tag message. release.add_tag = Create Tag Only +release.releases_for = Releases for %s +release.tags_for = Tags for %s branch.name = Branch Name branch.search = Search branches @@ -2988,7 +2991,7 @@ monitor.queue.pool.cancel_desc = Leaving a queue without any worker groups may c notices.system_notice_list = System Notices notices.view_detail_header = View Notice Details -notices.actions = Actions +notices.operations = Operations notices.select_all = Select All notices.deselect_all = Deselect All notices.inverse_selection = Inverse Selection @@ -3211,3 +3214,19 @@ owner.settings.cleanuprules.remove.days = Remove versions older than owner.settings.cleanuprules.remove.pattern = Remove versions matching owner.settings.cleanuprules.success.update = Cleanup rule has been updated. owner.settings.cleanuprules.success.delete = Cleanup rule has been deleted. + +[secrets] +secrets = Secrets +description = Secrets will be passed to certain actions and cannot be read otherwise. +none = There are no secrets yet. +value = Value +name = Name +creation = Add Secret +creation.name_placeholder = case-insensitive, alphanumeric characters or underscores only, cannot start with GITEA_ or GITHUB_ +creation.value_placeholder = Input any content. Whitespace at the start and end will be omitted. +creation.success = The secret '%s' has been added. +creation.failed = Failed to add secret. +deletion = Remove secret +deletion.description = Removing a secret will revoke its access to repositories. Continue? +deletion.success = The secret has been removed. +deletion.failed = Failed to remove secret. diff --git a/package-lock.json b/package-lock.json index b9c649c9de93..65d9695a0113 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,24 +13,24 @@ "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "17.9.0", + "@primer/octicons": "17.10.0", "@vue/compiler-sfc": "3.2.45", "add-asset-webpack-plugin": "2.0.1", - "css-loader": "6.7.2", + "css-loader": "6.7.3", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", "esbuild-loader": "2.20.0", "escape-goat": "4.0.0", "fast-glob": "3.2.12", "font-awesome": "4.7.0", - "jquery": "3.6.1", + "jquery": "3.6.2", "jquery.are-you-sure": "1.9.0", - "katex": "0.16.3", + "katex": "0.16.4", "less": "4.1.3", "less-loader": "11.1.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "9.2.2", - "mini-css-extract-plugin": "2.7.0", + "mermaid": "9.3.0", + "mini-css-extract-plugin": "2.7.2", "monaco-editor": "0.34.1", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "8.0.0", @@ -44,31 +44,31 @@ "vue-loader": "17.0.1", "vue3-calendar-heatmap": "2.0.0", "webpack": "5.75.0", - "webpack-cli": "5.0.0", + "webpack-cli": "5.0.1", "workbox-routing": "6.5.4", "workbox-strategies": "6.5.4", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { - "@playwright/test": "1.28.0", + "@playwright/test": "1.29.0", "@rollup/pluginutils": "5.0.2", "@stoplight/spectral-cli": "6.6.0", - "eslint": "8.28.0", + "eslint": "8.30.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-jquery": "1.5.1", - "eslint-plugin-sonarjs": "0.16.0", - "eslint-plugin-unicorn": "45.0.0", - "eslint-plugin-vue": "9.7.0", + "eslint-plugin-sonarjs": "0.17.0", + "eslint-plugin-unicorn": "45.0.2", + "eslint-plugin-vue": "9.8.0", "jsdom": "20.0.3", "markdownlint-cli": "0.32.2", "postcss-less": "6.0.0", - "stylelint": "14.15.0", + "stylelint": "14.16.0", "stylelint-config-standard": "29.0.0", "stylelint-declaration-strict-value": "1.9.1", "svgo": "3.0.2", - "updates": "13.2.1", - "vitest": "0.25.2" + "updates": "13.2.4", + "vitest": "0.26.1" }, "engines": { "node": ">= 14.0.0" @@ -187,9 +187,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==", "bin": { "parser": "bin/babel-parser.js" }, @@ -310,9 +310,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.14.tgz", - "integrity": "sha512-+Rb20XXxRGisNu2WmNKk+scpanb7nL5yhuI1KR9wQFiC43ddPj/V1fmNyzlFC9bKiG4mYzxW7egtoHVcynr+OA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", "cpu": [ "arm" ], @@ -324,10 +324,154 @@ "node": ">=12" } }, + "node_modules/@esbuild/android-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.10.tgz", + "integrity": "sha512-47Y+NwVKTldTlDhSgJHZ/RpvBQMUDG7eKihqaF/u6g7s0ZPz4J1vy8A3rwnnUOF2CuDn7w7Gj/QcMoWz3U3SJw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.10.tgz", + "integrity": "sha512-C4PfnrBMcuAcOurQzpF1tTtZz94IXO5JmICJJ3NFJRHbXXsQUg9RFG45KvydKqtFfBaFLCHpduUkUfXwIvGnRg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.10.tgz", + "integrity": "sha512-bH/bpFwldyOKdi9HSLCLhhKeVgRYr9KblchwXgY2NeUHBB/BzTUHtUSBgGBmpydB1/4E37m+ggXXfSrnD7/E7g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.10.tgz", + "integrity": "sha512-OXt7ijoLuy+AjDSKQWu+KdDFMBbdeaL6wtgMKtDUXKWHiAMKHan5+R1QAG6HD4+K0nnOvEJXKHeA9QhXNAjOTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.10.tgz", + "integrity": "sha512-shSQX/3GHuspE3Uxtq5kcFG/zqC+VuMnJkqV7LczO41cIe6CQaXHD3QdMLA4ziRq/m0vZo7JdterlgbmgNIAlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.10.tgz", + "integrity": "sha512-5YVc1zdeaJGASijZmTzSO4h6uKzsQGG3pkjI6fuXvolhm3hVRhZwnHJkforaZLmzvNv5Tb7a3QL2FAVmrgySIA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.10.tgz", + "integrity": "sha512-c360287ZWI2miBnvIj23bPyVctgzeMT2kQKR+x94pVqIN44h3GF8VMEs1SFPH1UgyDr3yBbx3vowDS1SVhyVhA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.10.tgz", + "integrity": "sha512-2aqeNVxIaRfPcIaMZIFoblLh588sWyCbmj1HHCCs9WmeNWm+EIN0SmvsmPvTa/TsNZFKnxTcvkX2eszTcCqIrA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.10.tgz", + "integrity": "sha512-sqMIEWeyrLGU7J5RB5fTkLRIFwsgsQ7ieWXlDLEmC2HblPYGb3AucD7inw2OrKFpRPKsec1l+lssiM3+NV5aOw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/linux-loong64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz", - "integrity": "sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", "cpu": [ "loong64" ], @@ -339,16 +483,207 @@ "node": ">=12" } }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.10.tgz", + "integrity": "sha512-FN8mZOH7531iPHM0kaFhAOqqNHoAb6r/YHW2ZIxNi0a85UBi2DO4Vuyn7t1p4UN8a4LoAnLOT1PqNgHkgBJgbA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.10.tgz", + "integrity": "sha512-Dg9RiqdvHOAWnOKIOTsIx8dFX9EDlY2IbPEY7YFzchrCiTZmMkD7jWA9UdZbNUygPjdmQBVPRCrLydReFlX9yg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.10.tgz", + "integrity": "sha512-XMqtpjwzbmlar0BJIxmzu/RZ7EWlfVfH68Vadrva0Wj5UKOdKvqskuev2jY2oPV3aoQUyXwnMbMrFmloO2GfAw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.10.tgz", + "integrity": "sha512-fu7XtnoeRNFMx8DjK3gPWpFBDM2u5ba+FYwg27SjMJwKvJr4bDyKz5c+FLXLUSSAkMAt/UL+cUbEbra+rYtUgw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.10.tgz", + "integrity": "sha512-61lcjVC/RldNNMUzQQdyCWjCxp9YLEQgIxErxU9XluX7juBdGKb0pvddS0vPNuCvotRbzijZ1pzII+26haWzbA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.10.tgz", + "integrity": "sha512-JeZXCX3viSA9j4HqSoygjssdqYdfHd6yCFWyfSekLbz4Ef+D2EjvsN02ZQPwYl5a5gg/ehdHgegHhlfOFP0HCA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.10.tgz", + "integrity": "sha512-3qpxQKuEVIIg8SebpXsp82OBrqjPV/OwNWmG+TnZDr3VGyChNnGMHccC1xkbxCHDQNnnXjxhMQNyHmdFJbmbRA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.10.tgz", + "integrity": "sha512-z+q0xZ+et/7etz7WoMyXTHZ1rB8PMSNp/FOqURLJLOPb3GWJ2aj4oCqFCjPwEbW1rsT7JPpxeH/DwGAWk/I1Bg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.10.tgz", + "integrity": "sha512-+YYu5sbQ9npkNT9Dec+tn1F/kjg6SMgr6bfi/6FpXYZvCRfu2YFPZGb+3x8K30s8eRxFpoG4sGhiSUkr1xbHEw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.10.tgz", + "integrity": "sha512-Aw7Fupk7XNehR1ftHGYwUteyJ2q+em/aE+fVU3YMTBN2V5A7Z4aVCSV+SvCp9HIIHZavPFBpbdP3VfjQpdf6Xg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz", + "integrity": "sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", + "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", + "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -385,9 +720,9 @@ "dev": true }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -575,13 +910,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", - "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.0.tgz", + "integrity": "sha512-gp5PVBenxTJsm2bATWDNc2CCnrL5OaA/MXQdJwwkGQtqTjmY+ZOqAdLqo49O9MLTDh2vYh+tHWDnmFsILnWaeA==", "dev": true, "dependencies": { "@types/node": "*", - "playwright-core": "1.28.0" + "playwright-core": "1.29.0" }, "bin": { "playwright": "cli.js" @@ -600,9 +935,9 @@ } }, "node_modules/@primer/octicons": { - "version": "17.9.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.9.0.tgz", - "integrity": "sha512-B6y3VxPrF6U+GUjZR883NsstI7v/Qcup9puDG+fOJvCm8b7UXNl46TbRrctMCZnYlyIzUF3/SgjJhr5od/Y6sw==", + "version": "17.10.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.10.0.tgz", + "integrity": "sha512-rg+NfA4M/SFutVzsqGwGWoKgXpHpTAbnoGvyGbkswT7iLV0PBFGJRkV61MhC61wEEF4SErMiaH5tOQKlvgvV9A==", "dependencies": { "object-assign": "^4.1.1" } @@ -732,9 +1067,9 @@ "dev": true }, "node_modules/@stoplight/json-ref-resolver": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.4.tgz", - "integrity": "sha512-842JVmMsi++qpDuIX+JpQvK7YY8FXEZZb+/z4xuRfStOAVEryJT/tbgGOWxniSdxEl9Eni5D/I2afMyy6BuiNw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.5.tgz", + "integrity": "sha512-uaKLITor7UF+JBtI84zs3aOWM0L79zp7w9TrBTwPtx5SLbaQQ4HadDKgX5yhFOLMApLdhwhiftF4c0GFanOxGg==", "dev": true, "dependencies": { "@stoplight/json": "^3.17.0", @@ -835,9 +1170,9 @@ } }, "node_modules/@stoplight/spectral-core": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.15.1.tgz", - "integrity": "sha512-IZV8L1Hyz9759KdqJIA90W5uvurHplMmaPPIZjQzG2Bq/39kN/sbLA/Js8uOf3xB9cHBbG599t4AB+uGsI8t0g==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.16.0.tgz", + "integrity": "sha512-W/NG+wV2UffwLExboqEa04/JbjGhiSTOl7GghLWYP4NKxZGaO6karP6fIxRBOnm34n1qyoZv9thsjSe92MWcDw==", "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", @@ -895,9 +1230,9 @@ } }, "node_modules/@stoplight/spectral-functions": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.1.tgz", - "integrity": "sha512-UWeUrxc1pu45ZNYKtK3OloMpkUNTPqwpmjbGUn4oEnbqrLEYu/B2oOg66EtGcadOBEsdOb7f5vaPlhUNNrpEpQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.2.tgz", + "integrity": "sha512-f+61/FtIkQeIo+a269CeaeqjpyRsgDyIk6DGr7iS4hyuk1PPk7Uf6MNRDs9FEIBh7CpdEJ+HSHbMLwgpymWTIw==", "dev": true, "dependencies": { "@stoplight/better-ajv-errors": "1.0.3", @@ -948,9 +1283,9 @@ } }, "node_modules/@stoplight/spectral-ruleset-bundler": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.4.0.tgz", - "integrity": "sha512-aYDI4a145IXED+6jvRjj9Ha0fnB+s54cr8KbQbPCEyhCHW1cP8UGVeOuwAfk+9C4ZIg40OuYrugN5EhA35oQtA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.5.0.tgz", + "integrity": "sha512-I1ZbhnJtRTi0lG6oXA1r8J6KLxoZKkNB3aSdrNJJTHoo/AccMSMhV4ey8zbLsYNsJ/9ywR5ttkBAbyGuo3Jtxg==", "dev": true, "dependencies": { "@rollup/plugin-commonjs": "~22.0.2", @@ -975,9 +1310,9 @@ } }, "node_modules/@stoplight/spectral-ruleset-migrator": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.9.0.tgz", - "integrity": "sha512-hPSjgXsTxMQ5UV1hfkVVPknhqRjmjSnCZD5jideM4rRU5NS1fj2Pse1CiXBsRChsuAGi/2s0Ke5uuOmFFsHrxQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.9.1.tgz", + "integrity": "sha512-TiH7UZIuHX+yb6EsWA9Z2ou455Wtki3z7SCkVRgd7WdzkD7O13R8ywqKoCUJ44UP7iuo1Ejnog18Rw4qJJE/fg==", "dev": true, "dependencies": { "@stoplight/json": "~3.20.1", @@ -1179,9 +1514,9 @@ "dev": true }, "node_modules/@types/marked": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz", - "integrity": "sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==" + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz", + "integrity": "sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==" }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -1190,9 +1525,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" + "version": "18.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", + "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1454,9 +1789,9 @@ } }, "node_modules/@webpack-cli/configtest": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.0.tgz", - "integrity": "sha512-war4OU8NGjBqU3DP3bx6ciODXIh7dSXcpQq+P4K2Tqyd8L5OjZ7COx9QXx/QdCIwL2qoX09Wr4Cwf7uS4qdEng==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", "engines": { "node": ">=14.15.0" }, @@ -1466,9 +1801,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.0.tgz", - "integrity": "sha512-NNxDgbo4VOkNhOlTgY0Elhz3vKpOJq4/PKeKg7r8cmYM+GQA9vDofLYyup8jS6EpUvhNmR30cHTCEIyvXpskwA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", "engines": { "node": ">=14.15.0" }, @@ -1478,9 +1813,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.0.tgz", - "integrity": "sha512-Rumq5mHvGXamnOh3O8yLk1sjx8dB30qF1OeR6VC00DIR6SLJ4bwwUGKC4pE7qBFoQyyh0H9sAg3fikYgAqVR0w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", "engines": { "node": ">=14.15.0" }, @@ -1993,9 +2328,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001431", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", - "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==", + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==", "funding": [ { "type": "opencollective", @@ -2058,9 +2393,9 @@ } }, "node_modules/ci-info": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", - "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", "dev": true, "engines": { "node": ">=8" @@ -2145,9 +2480,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.10", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.10.tgz", - "integrity": "sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==" + "version": "5.65.11", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.11.tgz", + "integrity": "sha512-Gp62g2eKSCHYt10axmGhKq3WoJSvVpvhXmowNq7pZdRVowwtvBR/hi2LSP5srtctKkRT33T6/n8Kv1UGp7JW4A==" }, "node_modules/codemirror-spell-checker": { "version": "1.1.2", @@ -2280,12 +2615,12 @@ } }, "node_modules/css-loader": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.2.tgz", - "integrity": "sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", "dependencies": { "icss-utils": "^5.1.0", - "postcss": "^8.4.18", + "postcss": "^8.4.19", "postcss-modules-extract-imports": "^3.0.0", "postcss-modules-local-by-default": "^4.0.0", "postcss-modules-scope": "^3.0.0", @@ -2327,17 +2662,16 @@ "dev": true }, "node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, "dependencies": { - "mdn-data": "2.0.28", + "mdn-data": "2.0.30", "source-map-js": "^1.0.1" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, "node_modules/css-values": { @@ -2393,6 +2727,26 @@ "npm": ">=7.0.0" } }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -2423,9 +2777,9 @@ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" }, "node_modules/d3": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", - "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.7.0.tgz", + "integrity": "sha512-VEwHCMgMjD2WBsxeRGUE18RmzxT9Bn7ghDpzvTEvkLSBAKgTMydJjouZTjspgQfRHpPt/PB3EHWBa6SSyFQq4g==", "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -2463,9 +2817,9 @@ } }, "node_modules/d3-array": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", - "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", "dependencies": { "internmap": "1 - 2" }, @@ -2507,11 +2861,6 @@ "node": ">=12" } }, - "node_modules/d3-collection": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" - }, "node_modules/d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", @@ -2665,9 +3014,9 @@ } }, "node_modules/d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", "engines": { "node": ">=12" } @@ -2743,9 +3092,9 @@ } }, "node_modules/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "dependencies": { "d3-array": "2 - 3" }, @@ -2762,353 +3111,56 @@ }, "engines": { "node": ">=12" - } - }, - "node_modules/d3-timer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", - "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/d3-transition": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", - "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", - "dependencies": { - "d3-color": "1 - 3", - "d3-dispatch": "1 - 3", - "d3-ease": "1 - 3", - "d3-interpolate": "1 - 3", - "d3-timer": "1 - 3" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "d3-selection": "2 - 3" - } - }, - "node_modules/d3-voronoi": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", - "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" - }, - "node_modules/d3-zoom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", - "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", - "dependencies": { - "d3-dispatch": "1 - 3", - "d3-drag": "2 - 3", - "d3-interpolate": "1 - 3", - "d3-selection": "2 - 3", - "d3-transition": "2 - 3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", - "dependencies": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "node_modules/dagre-d3": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/dagre-d3/-/dagre-d3-0.6.4.tgz", - "integrity": "sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==", - "dependencies": { - "d3": "^5.14", - "dagre": "^0.8.5", - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "node_modules/dagre-d3/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/dagre-d3/node_modules/d3": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", - "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", - "dependencies": { - "d3-array": "1", - "d3-axis": "1", - "d3-brush": "1", - "d3-chord": "1", - "d3-collection": "1", - "d3-color": "1", - "d3-contour": "1", - "d3-dispatch": "1", - "d3-drag": "1", - "d3-dsv": "1", - "d3-ease": "1", - "d3-fetch": "1", - "d3-force": "1", - "d3-format": "1", - "d3-geo": "1", - "d3-hierarchy": "1", - "d3-interpolate": "1", - "d3-path": "1", - "d3-polygon": "1", - "d3-quadtree": "1", - "d3-random": "1", - "d3-scale": "2", - "d3-scale-chromatic": "1", - "d3-selection": "1", - "d3-shape": "1", - "d3-time": "1", - "d3-time-format": "2", - "d3-timer": "1", - "d3-transition": "1", - "d3-voronoi": "1", - "d3-zoom": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - }, - "node_modules/dagre-d3/node_modules/d3-axis": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", - "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==" - }, - "node_modules/dagre-d3/node_modules/d3-brush": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz", - "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==", - "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-chord": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", - "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", - "dependencies": { - "d3-array": "1", - "d3-path": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "node_modules/dagre-d3/node_modules/d3-contour": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", - "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", - "dependencies": { - "d3-array": "^1.1.1" - } - }, - "node_modules/dagre-d3/node_modules/d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" - }, - "node_modules/dagre-d3/node_modules/d3-drag": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", - "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", - "dependencies": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-dsv": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", - "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", - "dependencies": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - }, - "bin": { - "csv2json": "bin/dsv2json", - "csv2tsv": "bin/dsv2dsv", - "dsv2dsv": "bin/dsv2dsv", - "dsv2json": "bin/dsv2json", - "json2csv": "bin/json2dsv", - "json2dsv": "bin/json2dsv", - "json2tsv": "bin/json2dsv", - "tsv2csv": "bin/dsv2dsv", - "tsv2json": "bin/dsv2json" - } - }, - "node_modules/dagre-d3/node_modules/d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" - }, - "node_modules/dagre-d3/node_modules/d3-fetch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", - "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", - "dependencies": { - "d3-dsv": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-force": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", - "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", - "dependencies": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-format": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", - "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" - }, - "node_modules/dagre-d3/node_modules/d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-hierarchy": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" - }, - "node_modules/dagre-d3/node_modules/d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "dependencies": { - "d3-color": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - }, - "node_modules/dagre-d3/node_modules/d3-polygon": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", - "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" - }, - "node_modules/dagre-d3/node_modules/d3-quadtree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", - "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==" - }, - "node_modules/dagre-d3/node_modules/d3-random": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", - "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==" - }, - "node_modules/dagre-d3/node_modules/d3-scale": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", - "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", - "dependencies": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - }, - "node_modules/dagre-d3/node_modules/d3-scale-chromatic": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", - "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", - "dependencies": { - "d3-color": "1", - "d3-interpolate": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" - }, - "node_modules/dagre-d3/node_modules/d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "dependencies": { - "d3-path": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", - "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" - }, - "node_modules/dagre-d3/node_modules/d3-time-format": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", - "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", - "dependencies": { - "d3-time": "1" - } - }, - "node_modules/dagre-d3/node_modules/d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" + } }, - "node_modules/dagre-d3/node_modules/d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "dependencies": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" } }, - "node_modules/dagre-d3/node_modules/d3-zoom": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", - "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", "dependencies": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" } }, - "node_modules/dagre-d3/node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.6.tgz", + "integrity": "sha512-CaaE/nZh205ix+Up4xsnlGmpog5GGm81Upi2+/SBHxwNwrccBb3K51LzjZ1U6hgvOlAEUsVWf1xSTzCyKpJ6+Q==", + "dependencies": { + "d3": "^7.7.0", + "lodash-es": "^4.17.21" } }, "node_modules/data-uri-to-buffer": { @@ -3186,15 +3238,15 @@ } }, "node_modules/decimal.js": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", - "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, "node_modules/deep-eql": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz", - "integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, "dependencies": { "type-detect": "^4.0.0" @@ -3468,9 +3520,9 @@ } }, "node_modules/dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", + "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==" }, "node_modules/domutils": { "version": "3.0.1", @@ -3540,9 +3592,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -3602,9 +3654,9 @@ } }, "node_modules/es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", + "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", @@ -3613,6 +3665,7 @@ "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", @@ -3628,8 +3681,8 @@ "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", "unbox-primitive": "^1.0.2" }, "engines": { @@ -3692,9 +3745,9 @@ } }, "node_modules/esbuild": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.14.tgz", - "integrity": "sha512-pJN8j42fvWLFWwSMG4luuupl2Me7mxciUOsMegKvwCmhEbJ2covUdFnihxm0FMIBV+cbwbtMoHgMCCI+pj1btQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -3703,34 +3756,34 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.15.14", - "@esbuild/linux-loong64": "0.15.14", - "esbuild-android-64": "0.15.14", - "esbuild-android-arm64": "0.15.14", - "esbuild-darwin-64": "0.15.14", - "esbuild-darwin-arm64": "0.15.14", - "esbuild-freebsd-64": "0.15.14", - "esbuild-freebsd-arm64": "0.15.14", - "esbuild-linux-32": "0.15.14", - "esbuild-linux-64": "0.15.14", - "esbuild-linux-arm": "0.15.14", - "esbuild-linux-arm64": "0.15.14", - "esbuild-linux-mips64le": "0.15.14", - "esbuild-linux-ppc64le": "0.15.14", - "esbuild-linux-riscv64": "0.15.14", - "esbuild-linux-s390x": "0.15.14", - "esbuild-netbsd-64": "0.15.14", - "esbuild-openbsd-64": "0.15.14", - "esbuild-sunos-64": "0.15.14", - "esbuild-windows-32": "0.15.14", - "esbuild-windows-64": "0.15.14", - "esbuild-windows-arm64": "0.15.14" + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "node_modules/esbuild-android-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz", - "integrity": "sha512-HuilVIb4rk9abT4U6bcFdU35UHOzcWVGLSjEmC58OVr96q5UiRqzDtWjPlCMugjhgUGKEs8Zf4ueIvYbOStbIg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "cpu": [ "x64" ], @@ -3743,9 +3796,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.14.tgz", - "integrity": "sha512-/QnxRVxsR2Vtf3XottAHj7hENAMW2wCs6S+OZcAbc/8nlhbAL/bCQRCVD78VtI5mdwqWkVi3wMqM94kScQCgqg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "cpu": [ "arm64" ], @@ -3758,9 +3811,9 @@ } }, "node_modules/esbuild-darwin-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.14.tgz", - "integrity": "sha512-ToNuf1uifu8hhwWvoZJGCdLIX/1zpo8cOGnT0XAhDQXiKOKYaotVNx7pOVB1f+wHoWwTLInrOmh3EmA7Fd+8Vg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "cpu": [ "x64" ], @@ -3773,9 +3826,9 @@ } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.14.tgz", - "integrity": "sha512-KgGP+y77GszfYJgceO0Wi/PiRtYo5y2Xo9rhBUpxTPaBgWDJ14gqYN0+NMbu+qC2fykxXaipHxN4Scaj9tUS1A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "cpu": [ "arm64" ], @@ -3788,9 +3841,9 @@ } }, "node_modules/esbuild-freebsd-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.14.tgz", - "integrity": "sha512-xr0E2n5lyWw3uFSwwUXHc0EcaBDtsal/iIfLioflHdhAe10KSctV978Te7YsfnsMKzcoGeS366+tqbCXdqDHQA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "cpu": [ "x64" ], @@ -3803,9 +3856,9 @@ } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.14.tgz", - "integrity": "sha512-8XH96sOQ4b1LhMlO10eEWOjEngmZ2oyw3pW4o8kvBcpF6pULr56eeYVP5radtgw54g3T8nKHDHYEI5AItvskZg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "cpu": [ "arm64" ], @@ -3818,9 +3871,9 @@ } }, "node_modules/esbuild-linux-32": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.14.tgz", - "integrity": "sha512-6ssnvwaTAi8AzKN8By2V0nS+WF5jTP7SfuK6sStGnDP7MCJo/4zHgM9oE1eQTS2jPmo3D673rckuCzRlig+HMA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "cpu": [ "ia32" ], @@ -3833,9 +3886,9 @@ } }, "node_modules/esbuild-linux-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.14.tgz", - "integrity": "sha512-ONySx3U0wAJOJuxGUlXBWxVKFVpWv88JEv0NZ6NlHknmDd1yCbf4AEdClSgLrqKQDXYywmw4gYDvdLsS6z0hcw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "cpu": [ "x64" ], @@ -3848,9 +3901,9 @@ } }, "node_modules/esbuild-linux-arm": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.14.tgz", - "integrity": "sha512-D2LImAIV3QzL7lHURyCHBkycVFbKwkDb1XEUWan+2fb4qfW7qAeUtul7ZIcIwFKZgPcl+6gKZmvLgPSj26RQ2Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "cpu": [ "arm" ], @@ -3863,9 +3916,9 @@ } }, "node_modules/esbuild-linux-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.14.tgz", - "integrity": "sha512-kle2Ov6a1e5AjlHlMQl1e+c4myGTeggrRzArQFmWp6O6JoqqB9hT+B28EW4tjFWgV/NxUq46pWYpgaWXsXRPAg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "cpu": [ "arm64" ], @@ -3878,9 +3931,9 @@ } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.14.tgz", - "integrity": "sha512-FVdMYIzOLXUq+OE7XYKesuEAqZhmAIV6qOoYahvUp93oXy0MOVTP370ECbPfGXXUdlvc0TNgkJa3YhEwyZ6MRA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "cpu": [ "mips64el" ], @@ -3893,9 +3946,9 @@ } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.14.tgz", - "integrity": "sha512-2NzH+iuzMDA+jjtPjuIz/OhRDf8tzbQ1tRZJI//aT25o1HKc0reMMXxKIYq/8nSHXiJSnYV4ODzTiv45s+h73w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "cpu": [ "ppc64" ], @@ -3908,9 +3961,9 @@ } }, "node_modules/esbuild-linux-riscv64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.14.tgz", - "integrity": "sha512-VqxvutZNlQxmUNS7Ac+aczttLEoHBJ9e3OYGqnULrfipRvG97qLrAv9EUY9iSrRKBqeEbSvS9bSfstZqwz0T4Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "cpu": [ "riscv64" ], @@ -3923,9 +3976,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.14.tgz", - "integrity": "sha512-+KVHEUshX5n6VP6Vp/AKv9fZIl5kr2ph8EUFmQUJnDpHwcfTSn2AQgYYm0HTBR2Mr4d0Wlr0FxF/Cs5pbFgiOw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "cpu": [ "s390x" ], @@ -3957,9 +4010,9 @@ } }, "node_modules/esbuild-netbsd-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.14.tgz", - "integrity": "sha512-6D/dr17piEgevIm1xJfZP2SjB9Z+g8ERhNnBdlZPBWZl+KSPUKLGF13AbvC+nzGh8IxOH2TyTIdRMvKMP0nEzQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "cpu": [ "x64" ], @@ -3972,9 +4025,9 @@ } }, "node_modules/esbuild-openbsd-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.14.tgz", - "integrity": "sha512-rREQBIlMibBetgr2E9Lywt2Qxv2ZdpmYahR4IUlAQ1Efv/A5gYdO0/VIN3iowDbCNTLxp0bb57Vf0LFcffD6kA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "cpu": [ "x64" ], @@ -3987,9 +4040,9 @@ } }, "node_modules/esbuild-sunos-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.14.tgz", - "integrity": "sha512-DNVjSp/BY4IfwtdUAvWGIDaIjJXY5KI4uD82+15v6k/w7px9dnaDaJJ2R6Mu+KCgr5oklmFc0KjBjh311Gxl9Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "cpu": [ "x64" ], @@ -4002,9 +4055,9 @@ } }, "node_modules/esbuild-windows-32": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.14.tgz", - "integrity": "sha512-pHBWrcA+/oLgvViuG9FO3kNPO635gkoVrRQwe6ZY1S0jdET07xe2toUvQoJQ8KT3/OkxqUasIty5hpuKFLD+eg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "cpu": [ "ia32" ], @@ -4017,9 +4070,9 @@ } }, "node_modules/esbuild-windows-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.14.tgz", - "integrity": "sha512-CszIGQVk/P8FOS5UgAH4hKc9zOaFo69fe+k1rqgBHx3CSK3Opyk5lwYriIamaWOVjBt7IwEP6NALz+tkVWdFog==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "cpu": [ "x64" ], @@ -4032,9 +4085,9 @@ } }, "node_modules/esbuild-windows-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.14.tgz", - "integrity": "sha512-KW9W4psdZceaS9A7Jsgl4WialOznSURvqX/oHZk3gOP7KbjtHLSsnmSvNdzagGJfxbAe30UVGXRe8q8nDsOSQw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "cpu": [ "arm64" ], @@ -4151,13 +4204,13 @@ } }, "node_modules/eslint": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", - "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", + "version": "8.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", + "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.0", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -4176,7 +4229,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -4315,9 +4368,9 @@ } }, "node_modules/eslint-plugin-sonarjs": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.16.0.tgz", - "integrity": "sha512-al8ojAzcQW8Eu0tWn841ldhPpPcjrJ59TzzTfAVWR45bWvdAASCmrGl8vK0MWHyKVDdC0i17IGbtQQ1KgxLlVA==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.17.0.tgz", + "integrity": "sha512-jtGtxI49UbJJeJj7CVRLI3+LLH+y+hkR3GOOwM7vBbci9DEFIRGCWvEd2BJScrzltZ6D6iubukTAfc9cyG7sdw==", "dev": true, "engines": { "node": ">=14" @@ -4327,24 +4380,24 @@ } }, "node_modules/eslint-plugin-unicorn": { - "version": "45.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.0.tgz", - "integrity": "sha512-iP8cMRxXKHonKioOhnCoCcqVhoqhAp6rB+nsoLjXFDxTHz3btWMAp8xwzjHA0B1K6YV/U/Yvqn1bUXZt8sJPuQ==", + "version": "45.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", + "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.19.1", + "@eslint-community/eslint-utils": "^4.1.2", "ci-info": "^3.6.1", "clean-regexp": "^1.0.0", - "eslint-utils": "^3.0.0", "esquery": "^1.4.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.0", - "jsesc": "3.0.2", + "jsesc": "^3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", - "regjsparser": "0.9.1", + "regjsparser": "^0.9.1", "safe-regex": "^2.1.1", "semver": "^7.3.8", "strip-indent": "^3.0.0" @@ -4360,9 +4413,9 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.7.0.tgz", - "integrity": "sha512-DrOO3WZCZEwcLsnd3ohFwqCoipGRSTKTBTnLwdhqAbYZtzWl0o7D+D8ZhlmiZvABKTEl8AFsqH1GHGdybyoQmw==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.8.0.tgz", + "integrity": "sha512-E/AXwcTzunyzM83C2QqDHxepMzvI2y6x+mmeYHbVDQlKFqmKYvRrhaVixEeeG27uI44p9oKDFiyCRw4XxgtfHA==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", @@ -4543,11 +4596,6 @@ "node": ">=0.8.x" } }, - "node_modules/fast-clone": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/fast-clone/-/fast-clone-1.5.13.tgz", - "integrity": "sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==" - }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4605,9 +4653,9 @@ } }, "node_modules/fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "dependencies": { "reusify": "^1.0.4" } @@ -4970,9 +5018,9 @@ } }, "node_modules/globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -5025,6 +5073,18 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -5036,14 +5096,6 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, - "node_modules/graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "dependencies": { - "lodash": "^4.17.15" - } - }, "node_modules/gsap": { "version": "3.11.3", "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.11.3.tgz", @@ -5245,9 +5297,9 @@ ] }, "node_modules/ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true, "engines": { "node": ">= 4" @@ -5360,12 +5412,12 @@ } }, "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, "dependencies": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" }, @@ -5716,9 +5768,9 @@ } }, "node_modules/jquery": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.2.tgz", + "integrity": "sha512-/e7ulNIEEYk1Z/l4X0vpxGt+B/dNsV8ghOPAWZaJs8pkGvsSC0tm33aMGylXcj/U7y4IcvwtMXPMyBFZn/gK9A==" }, "node_modules/jquery.are-you-sure": { "version": "1.9.0", @@ -5732,10 +5784,14 @@ } }, "node_modules/js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", - "dev": true + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } }, "node_modules/js-tokens": { "version": "4.0.0", @@ -5800,9 +5856,9 @@ } }, "node_modules/jsep": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.7.tgz", - "integrity": "sha512-NFbZTr1t13fPKw53swmZFKwBkEDWDnno7uLJk+a+Rw9tGDTkGgnGdZJ8A/o3gR1+XaAXmSsbpfIBIBgqRBZWDA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz", + "integrity": "sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==", "dev": true, "engines": { "node": ">= 10.16.0" @@ -5837,9 +5893,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", + "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==", "bin": { "json5": "lib/cli.js" }, @@ -5886,9 +5942,9 @@ "integrity": "sha512-b+z6yF1d4EOyDgylzQo5IminlUmzSeqR1hs/bzjBNjuGras4FXq/6TrzjxfN0j+TmI0ltJzTNlqXUMCniciwKQ==" }, "node_modules/katex": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.3.tgz", - "integrity": "sha512-3EykQddareoRmbtNiNEDgl3IGjryyrp2eg/25fHDEnlHymIDi33bptkMv6K4EOC2LZCybLW/ZkEo6Le+EM9pmA==", + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.4.tgz", + "integrity": "sha512-WudRKUj8yyBeVDI4aYMNxhx5Vhh2PjpzQw1GRu/LVGqL4m1AxwD1GcUp0IMbdJaf5zsjtj8ghP0DOQRYhroNkw==", "funding": [ "https://opencollective.com/katex", "https://github.com/sponsors/katex" @@ -6108,7 +6164,13 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "node_modules/lodash._reinterpolate": { "version": "3.0.0", @@ -6306,9 +6368,9 @@ "dev": true }, "node_modules/markdownlint-cli/node_modules/minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -6327,9 +6389,9 @@ } }, "node_modules/marked": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz", - "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz", + "integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==", "bin": { "marked": "bin/marked.js" }, @@ -6348,9 +6410,9 @@ } }, "node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, "node_modules/mdurl": { @@ -6456,19 +6518,16 @@ } }, "node_modules/mermaid": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.2.2.tgz", - "integrity": "sha512-6s7eKMqFJGS+0MYjmx8f6ZigqKBJVoSx5ql2gw6a4Aa+WJ49QiEJg7gPwywaBg3DZMs79UP7trESp4+jmaQccw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.3.0.tgz", + "integrity": "sha512-mGl0BM19TD/HbU/LmlaZbjBi//tojelg8P/mxD6pPZTAYaI+VawcyBdqRsoUHSc7j71PrMdJ3HBadoQNdvP5cg==", "dependencies": { "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", - "dagre": "^0.8.5", - "dagre-d3": "^0.6.4", - "dompurify": "2.4.0", - "fast-clone": "^1.5.13", - "graphlib": "^2.1.8", + "dagre-d3-es": "7.0.6", + "dompurify": "2.4.1", "khroma": "^2.0.0", - "lodash": "^4.17.21", + "lodash-es": "^4.17.21", "moment-mini": "^2.24.0", "non-layered-tidy-tree-layout": "^2.0.2", "stylis": "^4.1.2", @@ -6528,9 +6587,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", - "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", "dependencies": { "schema-utils": "^4.0.0" }, @@ -6579,6 +6638,24 @@ "node": ">= 6" } }, + "node_modules/mlly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.0.0.tgz", + "integrity": "sha512-QL108Hwt+u9bXdWgOI0dhzZfACovn5Aen4Xvc8Jasd9ouRH4NjnrXEiyP3nVvJo91zPlYjVRckta0Nt2zfoR6g==", + "dev": true, + "dependencies": { + "acorn": "^8.8.1", + "pathe": "^1.0.0", + "pkg-types": "^1.0.0", + "ufo": "^1.0.0" + } + }, + "node_modules/mlly/node_modules/pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + }, "node_modules/moment-mini": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", @@ -6737,9 +6814,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" }, "node_modules/non-layered-tidy-tree-layout": { "version": "2.0.2", @@ -7025,9 +7102,9 @@ } }, "node_modules/parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dev": true, "dependencies": { "entities": "^4.4.0" @@ -7086,6 +7163,12 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz", + "integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==", + "dev": true + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -7179,10 +7262,33 @@ "node": ">=8" } }, + "node_modules/pkg-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz", + "integrity": "sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.0.0", + "pathe": "^1.0.0" + } + }, + "node_modules/pkg-types/node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + }, "node_modules/playwright-core": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", - "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.0.tgz", + "integrity": "sha512-pboOm1m0RD6z1GtwAbEH60PYRfF87vKdzOSRw2RyO0Y0a7utrMyWN2Au1ojGvQr4umuBMODkKTv607YIRypDSQ==", "dev": true, "bin": { "playwright": "cli.js" @@ -7210,9 +7316,9 @@ } }, "node_modules/postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", "funding": [ { "type": "opencollective", @@ -8181,7 +8287,8 @@ "node_modules/sourcemap-codec": { "version": "1.4.8", "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "deprecated": "Please use @jridgewell/sourcemap-codec instead" }, "node_modules/spdx-compare": { "version": "1.0.0", @@ -8356,12 +8463,12 @@ } }, "node_modules/strip-literal": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-0.4.2.tgz", - "integrity": "sha512-pv48ybn4iE1O9RLgCAN0iU4Xv7RlBTiit6DKmMiErbs9x1wH6vXBs45tWc0H5wUIF6TLTrKweqkmYF/iraQKNw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.0.tgz", + "integrity": "sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0" + "acorn": "^8.8.1" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -8374,9 +8481,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.15.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.15.0.tgz", - "integrity": "sha512-JOgDAo5QRsqiOZPZO+B9rKJvBm64S0xasbuRPAbPs6/vQDgDCnZLIiw6XcAS6GQKk9k1sBWR6rmH3Mfj8OknKg==", + "version": "14.16.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.0.tgz", + "integrity": "sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg==", "dev": true, "dependencies": { "@csstools/selector-specificity": "^2.0.2", @@ -8392,7 +8499,7 @@ "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.2.0", - "ignore": "^5.2.0", + "ignore": "^5.2.1", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", @@ -8406,7 +8513,7 @@ "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -8610,9 +8717,9 @@ } }, "node_modules/terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", "dependencies": { "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", @@ -8890,6 +8997,12 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "node_modules/ufo": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz", + "integrity": "sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==", + "dev": true + }, "node_modules/uint8-to-base64": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/uint8-to-base64/-/uint8-to-base64-0.2.0.tgz", @@ -8954,9 +9067,9 @@ } }, "node_modules/updates": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.2.1.tgz", - "integrity": "sha512-d+nIbU2fl/PDEvUkbQch4uRdkXt9AQoPlH6b/FPTOAzF9voGbXgZNNxgO79Jeish24ZMfOqUl5lJcKSwMO2RJQ==", + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.2.4.tgz", + "integrity": "sha512-aQcPi3/kRcMLqLZj6nvy0PZAX3ZhE78IdHoj02SujNqH3/55hgn2i/bHVzPUI86+qWITkt7PyjJHBLDSxDHEyA==", "dev": true, "bin": { "updates": "bin/updates.js" @@ -9037,15 +9150,15 @@ } }, "node_modules/vite": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.4.tgz", - "integrity": "sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.2.tgz", + "integrity": "sha512-QJaY3R+tFlTagH0exVqbgkkw45B+/bXVBzF2ZD1KB5Z8RiAoiKo60vSUf6/r4c2Vh9jfGBKM4oBI9b4/1ZJYng==", "dev": true, "dependencies": { - "esbuild": "^0.15.9", - "postcss": "^8.4.18", + "esbuild": "^0.16.3", + "postcss": "^8.4.20", "resolve": "^1.22.1", - "rollup": "^2.79.1" + "rollup": "^3.7.0" }, "bin": { "vite": "bin/vite.js" @@ -9085,26 +9198,135 @@ } } }, + "node_modules/vite-node": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.26.1.tgz", + "integrity": "sha512-5FJSKZZJz48zFRKHE55WyevZe61hLMQEsqGn+ungfd60kxEztFybZ3yG9ToGFtOWNCCy7Vn5EVuXD8bdeHOSdw==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "mlly": "^1.0.0", + "pathe": "^0.2.0", + "source-map": "^0.6.1", + "source-map-support": "^0.5.21", + "vite": "^3.0.0 || ^4.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.16.0" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.10.tgz", + "integrity": "sha512-RmJjQTRrO6VwUWDrzTBLmV4OJZTarYsiepLGlF2rYTVB701hSorPywPGvP6d8HCuuRibyXa5JX4s3jN2kHEtjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.10.tgz", + "integrity": "sha512-O7Pd5hLEtTg37NC73pfhUOGTjx/+aXu5YoSq3ahCxcN7Bcr2F47mv+kG5t840thnsEzrv0oB70+LJu3gUgchvg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.10.tgz", + "integrity": "sha512-z5dIViHoVnw2l+NCJ3zj5behdXjYvXne9gL18OOivCadXDUhyDkeSvEtLcGVAJW2fNmh33TDUpsi704XYlDodw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.16.10", + "@esbuild/android-arm64": "0.16.10", + "@esbuild/android-x64": "0.16.10", + "@esbuild/darwin-arm64": "0.16.10", + "@esbuild/darwin-x64": "0.16.10", + "@esbuild/freebsd-arm64": "0.16.10", + "@esbuild/freebsd-x64": "0.16.10", + "@esbuild/linux-arm": "0.16.10", + "@esbuild/linux-arm64": "0.16.10", + "@esbuild/linux-ia32": "0.16.10", + "@esbuild/linux-loong64": "0.16.10", + "@esbuild/linux-mips64el": "0.16.10", + "@esbuild/linux-ppc64": "0.16.10", + "@esbuild/linux-riscv64": "0.16.10", + "@esbuild/linux-s390x": "0.16.10", + "@esbuild/linux-x64": "0.16.10", + "@esbuild/netbsd-x64": "0.16.10", + "@esbuild/openbsd-x64": "0.16.10", + "@esbuild/sunos-x64": "0.16.10", + "@esbuild/win32-arm64": "0.16.10", + "@esbuild/win32-ia32": "0.16.10", + "@esbuild/win32-x64": "0.16.10" + } + }, + "node_modules/vite/node_modules/rollup": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", + "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/vitest": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.25.2.tgz", - "integrity": "sha512-qqkzfzglEFbQY7IGkgSJkdOhoqHjwAao/OrphnHboeYHC5JzsVFoLCaB2lnAy8krhj7sbrFTVRApzpkTOeuDWQ==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.26.1.tgz", + "integrity": "sha512-qTLRnjYmjmJpHlLUtErxtlRqGCe8WItFhGXKklpWivu7CLP9KXN9iTezROe+vf51Kb+BB/fzxK6fUG9DvFGL5Q==", "dev": true, "dependencies": { - "@types/chai": "^4.3.3", + "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "acorn": "^8.8.0", + "acorn": "^8.8.1", "acorn-walk": "^8.2.0", - "chai": "^4.3.6", + "chai": "^4.3.7", "debug": "^4.3.4", "local-pkg": "^0.4.2", "source-map": "^0.6.1", - "strip-literal": "^0.4.2", + "strip-literal": "^1.0.0", "tinybench": "^2.3.1", "tinypool": "^0.3.0", "tinyspy": "^1.0.2", - "vite": "^3.0.0" + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.26.1" }, "bin": { "vitest": "vitest.mjs" @@ -9141,9 +9363,9 @@ } }, "node_modules/vm2": { - "version": "3.9.11", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.11.tgz", - "integrity": "sha512-PFG8iJRSjvvBdisowQ7iVF580DXb1uCIiGaXgm7tynMR1uTBlv7UJlB1zdv5KJ+Tmq1f0Upnj3fayoEOPpCBKg==", + "version": "3.9.13", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.13.tgz", + "integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==", "dev": true, "dependencies": { "acorn": "^8.7.0", @@ -9316,14 +9538,14 @@ } }, "node_modules/webpack-cli": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.0.tgz", - "integrity": "sha512-AACDTo20yG+xn6HPW5xjbn2Be4KUzQPebWXsDMHwPPyKh9OnTOJgZN2Nc+g/FZKV3ObRTYsGvibAvc+5jAUrVA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", "dependencies": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.0", - "@webpack-cli/info": "^2.0.0", - "@webpack-cli/serve": "^2.0.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", "colorette": "^2.0.14", "commander": "^9.4.1", "cross-spawn": "^7.0.3", @@ -9933,9 +10155,9 @@ } }, "@babel/parser": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.3.tgz", - "integrity": "sha512-OP/s5a94frIPXwjzEcv5S/tpQfc6XhxYUnmWpgdqMWGgYCuErA3SzozaRAMQgSZWKeTJxht9aWAkUY+0UzvOFg==" + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.5.tgz", + "integrity": "sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==" }, "@braintree/sanitize-url": { "version": "6.0.2", @@ -9982,56 +10204,205 @@ "citeproc": "^2.4.6" } }, - "@citation-js/plugin-software-formats": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@citation-js/plugin-software-formats/-/plugin-software-formats-0.6.0.tgz", - "integrity": "sha512-l0Vp2h9UNlqsGMgrJulA92csgu8l3WhhBC0F2nFl76aTMOrMzC9/DX1G2Ob5tUQvPfuy4B5ZZsYPJNTJdtPVhw==", - "requires": { - "@citation-js/date": "^0.5.0", - "@citation-js/name": "^0.4.2", - "js-yaml": "^4.0.0" - } + "@citation-js/plugin-software-formats": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-software-formats/-/plugin-software-formats-0.6.0.tgz", + "integrity": "sha512-l0Vp2h9UNlqsGMgrJulA92csgu8l3WhhBC0F2nFl76aTMOrMzC9/DX1G2Ob5tUQvPfuy4B5ZZsYPJNTJdtPVhw==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "js-yaml": "^4.0.0" + } + }, + "@claviska/jquery-minicolors": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz", + "integrity": "sha512-8Ro6D4GCrmOl41+6w4NFhEOpx8vjxwVRI69bulXsFDt49uVRKhLU5TnzEV7AmOJrylkVq+ugnYNMiGHBieeKUQ==", + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "requires": {} + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" + }, + "@esbuild/android-arm": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz", + "integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.16.10.tgz", + "integrity": "sha512-47Y+NwVKTldTlDhSgJHZ/RpvBQMUDG7eKihqaF/u6g7s0ZPz4J1vy8A3rwnnUOF2CuDn7w7Gj/QcMoWz3U3SJw==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.16.10.tgz", + "integrity": "sha512-C4PfnrBMcuAcOurQzpF1tTtZz94IXO5JmICJJ3NFJRHbXXsQUg9RFG45KvydKqtFfBaFLCHpduUkUfXwIvGnRg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.16.10.tgz", + "integrity": "sha512-bH/bpFwldyOKdi9HSLCLhhKeVgRYr9KblchwXgY2NeUHBB/BzTUHtUSBgGBmpydB1/4E37m+ggXXfSrnD7/E7g==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.16.10.tgz", + "integrity": "sha512-OXt7ijoLuy+AjDSKQWu+KdDFMBbdeaL6wtgMKtDUXKWHiAMKHan5+R1QAG6HD4+K0nnOvEJXKHeA9QhXNAjOTQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.10.tgz", + "integrity": "sha512-shSQX/3GHuspE3Uxtq5kcFG/zqC+VuMnJkqV7LczO41cIe6CQaXHD3QdMLA4ziRq/m0vZo7JdterlgbmgNIAlQ==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.16.10.tgz", + "integrity": "sha512-5YVc1zdeaJGASijZmTzSO4h6uKzsQGG3pkjI6fuXvolhm3hVRhZwnHJkforaZLmzvNv5Tb7a3QL2FAVmrgySIA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.16.10.tgz", + "integrity": "sha512-c360287ZWI2miBnvIj23bPyVctgzeMT2kQKR+x94pVqIN44h3GF8VMEs1SFPH1UgyDr3yBbx3vowDS1SVhyVhA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.16.10.tgz", + "integrity": "sha512-2aqeNVxIaRfPcIaMZIFoblLh588sWyCbmj1HHCCs9WmeNWm+EIN0SmvsmPvTa/TsNZFKnxTcvkX2eszTcCqIrA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.16.10.tgz", + "integrity": "sha512-sqMIEWeyrLGU7J5RB5fTkLRIFwsgsQ7ieWXlDLEmC2HblPYGb3AucD7inw2OrKFpRPKsec1l+lssiM3+NV5aOw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz", + "integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.16.10.tgz", + "integrity": "sha512-FN8mZOH7531iPHM0kaFhAOqqNHoAb6r/YHW2ZIxNi0a85UBi2DO4Vuyn7t1p4UN8a4LoAnLOT1PqNgHkgBJgbA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.16.10.tgz", + "integrity": "sha512-Dg9RiqdvHOAWnOKIOTsIx8dFX9EDlY2IbPEY7YFzchrCiTZmMkD7jWA9UdZbNUygPjdmQBVPRCrLydReFlX9yg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.16.10.tgz", + "integrity": "sha512-XMqtpjwzbmlar0BJIxmzu/RZ7EWlfVfH68Vadrva0Wj5UKOdKvqskuev2jY2oPV3aoQUyXwnMbMrFmloO2GfAw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.16.10.tgz", + "integrity": "sha512-fu7XtnoeRNFMx8DjK3gPWpFBDM2u5ba+FYwg27SjMJwKvJr4bDyKz5c+FLXLUSSAkMAt/UL+cUbEbra+rYtUgw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.16.10.tgz", + "integrity": "sha512-61lcjVC/RldNNMUzQQdyCWjCxp9YLEQgIxErxU9XluX7juBdGKb0pvddS0vPNuCvotRbzijZ1pzII+26haWzbA==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.16.10.tgz", + "integrity": "sha512-JeZXCX3viSA9j4HqSoygjssdqYdfHd6yCFWyfSekLbz4Ef+D2EjvsN02ZQPwYl5a5gg/ehdHgegHhlfOFP0HCA==", + "dev": true, + "optional": true }, - "@claviska/jquery-minicolors": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz", - "integrity": "sha512-8Ro6D4GCrmOl41+6w4NFhEOpx8vjxwVRI69bulXsFDt49uVRKhLU5TnzEV7AmOJrylkVq+ugnYNMiGHBieeKUQ==", - "requires": {} + "@esbuild/openbsd-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.16.10.tgz", + "integrity": "sha512-3qpxQKuEVIIg8SebpXsp82OBrqjPV/OwNWmG+TnZDr3VGyChNnGMHccC1xkbxCHDQNnnXjxhMQNyHmdFJbmbRA==", + "dev": true, + "optional": true }, - "@csstools/selector-specificity": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", - "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "@esbuild/sunos-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.16.10.tgz", + "integrity": "sha512-z+q0xZ+et/7etz7WoMyXTHZ1rB8PMSNp/FOqURLJLOPb3GWJ2aj4oCqFCjPwEbW1rsT7JPpxeH/DwGAWk/I1Bg==", "dev": true, - "requires": {} + "optional": true }, - "@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" + "@esbuild/win32-arm64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.16.10.tgz", + "integrity": "sha512-+YYu5sbQ9npkNT9Dec+tn1F/kjg6SMgr6bfi/6FpXYZvCRfu2YFPZGb+3x8K30s8eRxFpoG4sGhiSUkr1xbHEw==", + "dev": true, + "optional": true }, - "@esbuild/android-arm": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.14.tgz", - "integrity": "sha512-+Rb20XXxRGisNu2WmNKk+scpanb7nL5yhuI1KR9wQFiC43ddPj/V1fmNyzlFC9bKiG4mYzxW7egtoHVcynr+OA==", + "@esbuild/win32-ia32": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.16.10.tgz", + "integrity": "sha512-Aw7Fupk7XNehR1ftHGYwUteyJ2q+em/aE+fVU3YMTBN2V5A7Z4aVCSV+SvCp9HIIHZavPFBpbdP3VfjQpdf6Xg==", + "dev": true, "optional": true }, - "@esbuild/linux-loong64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.14.tgz", - "integrity": "sha512-eQi9rosGNVQFJyJWV0HCA5WZae/qWIQME7s8/j8DMvnylfBv62Pbu+zJ2eUDqNf2O4u3WB+OEXyfkpBoe194sg==", + "@esbuild/win32-x64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.16.10.tgz", + "integrity": "sha512-qddWullt3sC1EIpfHvCRBq3H4g3L86DZpD6n8k2XFjFVyp01D++uNbN1hT/JRsHxTbyyemZcpwL5aRlJwc/zFw==", + "dev": true, "optional": true }, + "@eslint-community/eslint-utils": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.1.2.tgz", + "integrity": "sha512-7qELuQWWjVDdVsFQ5+beUl+KPczrEDA7S3zM4QUd/bJl7oXgsmpXaEVqrRTnOBqenOV4rWf2kVZk2Ot085zPWA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, "@eslint/eslintrc": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", - "integrity": "sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.0.tgz", + "integrity": "sha512-7yfvXy6MWLgWSFsLhz5yH3iQ52St8cdUY6FoGieKkRDVxuxmrNuUetIuu6cmjNWwniUHiWXjxCr5tTXDrbYS5A==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", "espree": "^9.4.0", - "globals": "^13.15.0", + "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -10060,9 +10431,9 @@ } }, "@humanwhocodes/config-array": { - "version": "0.11.7", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", - "integrity": "sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==", + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -10176,13 +10547,13 @@ } }, "@playwright/test": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", - "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.29.0.tgz", + "integrity": "sha512-gp5PVBenxTJsm2bATWDNc2CCnrL5OaA/MXQdJwwkGQtqTjmY+ZOqAdLqo49O9MLTDh2vYh+tHWDnmFsILnWaeA==", "dev": true, "requires": { "@types/node": "*", - "playwright-core": "1.28.0" + "playwright-core": "1.29.0" } }, "@popperjs/core": { @@ -10191,9 +10562,9 @@ "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==" }, "@primer/octicons": { - "version": "17.9.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.9.0.tgz", - "integrity": "sha512-B6y3VxPrF6U+GUjZR883NsstI7v/Qcup9puDG+fOJvCm8b7UXNl46TbRrctMCZnYlyIzUF3/SgjJhr5od/Y6sw==", + "version": "17.10.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.10.0.tgz", + "integrity": "sha512-rg+NfA4M/SFutVzsqGwGWoKgXpHpTAbnoGvyGbkswT7iLV0PBFGJRkV61MhC61wEEF4SErMiaH5tOQKlvgvV9A==", "requires": { "object-assign": "^4.1.1" } @@ -10294,9 +10665,9 @@ } }, "@stoplight/json-ref-resolver": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.4.tgz", - "integrity": "sha512-842JVmMsi++qpDuIX+JpQvK7YY8FXEZZb+/z4xuRfStOAVEryJT/tbgGOWxniSdxEl9Eni5D/I2afMyy6BuiNw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@stoplight/json-ref-resolver/-/json-ref-resolver-3.1.5.tgz", + "integrity": "sha512-uaKLITor7UF+JBtI84zs3aOWM0L79zp7w9TrBTwPtx5SLbaQQ4HadDKgX5yhFOLMApLdhwhiftF4c0GFanOxGg==", "dev": true, "requires": { "@stoplight/json": "^3.17.0", @@ -10378,9 +10749,9 @@ } }, "@stoplight/spectral-core": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.15.1.tgz", - "integrity": "sha512-IZV8L1Hyz9759KdqJIA90W5uvurHplMmaPPIZjQzG2Bq/39kN/sbLA/Js8uOf3xB9cHBbG599t4AB+uGsI8t0g==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-core/-/spectral-core-1.16.0.tgz", + "integrity": "sha512-W/NG+wV2UffwLExboqEa04/JbjGhiSTOl7GghLWYP4NKxZGaO6karP6fIxRBOnm34n1qyoZv9thsjSe92MWcDw==", "dev": true, "requires": { "@stoplight/better-ajv-errors": "1.0.3", @@ -10431,9 +10802,9 @@ } }, "@stoplight/spectral-functions": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.1.tgz", - "integrity": "sha512-UWeUrxc1pu45ZNYKtK3OloMpkUNTPqwpmjbGUn4oEnbqrLEYu/B2oOg66EtGcadOBEsdOb7f5vaPlhUNNrpEpQ==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-functions/-/spectral-functions-1.7.2.tgz", + "integrity": "sha512-f+61/FtIkQeIo+a269CeaeqjpyRsgDyIk6DGr7iS4hyuk1PPk7Uf6MNRDs9FEIBh7CpdEJ+HSHbMLwgpymWTIw==", "dev": true, "requires": { "@stoplight/better-ajv-errors": "1.0.3", @@ -10475,9 +10846,9 @@ } }, "@stoplight/spectral-ruleset-bundler": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.4.0.tgz", - "integrity": "sha512-aYDI4a145IXED+6jvRjj9Ha0fnB+s54cr8KbQbPCEyhCHW1cP8UGVeOuwAfk+9C4ZIg40OuYrugN5EhA35oQtA==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-bundler/-/spectral-ruleset-bundler-1.5.0.tgz", + "integrity": "sha512-I1ZbhnJtRTi0lG6oXA1r8J6KLxoZKkNB3aSdrNJJTHoo/AccMSMhV4ey8zbLsYNsJ/9ywR5ttkBAbyGuo3Jtxg==", "dev": true, "requires": { "@rollup/plugin-commonjs": "~22.0.2", @@ -10499,9 +10870,9 @@ } }, "@stoplight/spectral-ruleset-migrator": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.9.0.tgz", - "integrity": "sha512-hPSjgXsTxMQ5UV1hfkVVPknhqRjmjSnCZD5jideM4rRU5NS1fj2Pse1CiXBsRChsuAGi/2s0Ke5uuOmFFsHrxQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@stoplight/spectral-ruleset-migrator/-/spectral-ruleset-migrator-1.9.1.tgz", + "integrity": "sha512-TiH7UZIuHX+yb6EsWA9Z2ou455Wtki3z7SCkVRgd7WdzkD7O13R8ywqKoCUJ44UP7iuo1Ejnog18Rw4qJJE/fg==", "dev": true, "requires": { "@stoplight/json": "~3.20.1", @@ -10681,9 +11052,9 @@ "dev": true }, "@types/marked": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.7.tgz", - "integrity": "sha512-eEAhnz21CwvKVW+YvRvcTuFKNU9CV1qH+opcgVK3pIMI6YZzDm6gc8o2vHjldFk6MGKt5pueSB7IOpvpx5Qekw==" + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz", + "integrity": "sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==" }, "@types/minimist": { "version": "1.2.2", @@ -10692,9 +11063,9 @@ "dev": true }, "@types/node": { - "version": "18.11.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.9.tgz", - "integrity": "sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==" + "version": "18.11.17", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz", + "integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -10953,21 +11324,21 @@ } }, "@webpack-cli/configtest": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.0.tgz", - "integrity": "sha512-war4OU8NGjBqU3DP3bx6ciODXIh7dSXcpQq+P4K2Tqyd8L5OjZ7COx9QXx/QdCIwL2qoX09Wr4Cwf7uS4qdEng==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-2.0.1.tgz", + "integrity": "sha512-njsdJXJSiS2iNbQVS0eT8A/KPnmyH4pv1APj2K0d1wrZcBLw+yppxOy4CGqa0OxDJkzfL/XELDhD8rocnIwB5A==", "requires": {} }, "@webpack-cli/info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.0.tgz", - "integrity": "sha512-NNxDgbo4VOkNhOlTgY0Elhz3vKpOJq4/PKeKg7r8cmYM+GQA9vDofLYyup8jS6EpUvhNmR30cHTCEIyvXpskwA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-2.0.1.tgz", + "integrity": "sha512-fE1UEWTwsAxRhrJNikE7v4EotYflkEhBL7EbajfkPlf6E37/2QshOy/D48Mw8G5XMFlQtS6YV42vtbG9zBpIQA==", "requires": {} }, "@webpack-cli/serve": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.0.tgz", - "integrity": "sha512-Rumq5mHvGXamnOh3O8yLk1sjx8dB30qF1OeR6VC00DIR6SLJ4bwwUGKC4pE7qBFoQyyh0H9sAg3fikYgAqVR0w==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-2.0.1.tgz", + "integrity": "sha512-0G7tNyS+yW8TdgHwZKlDWYXFA6OJQnoLCQvYKkQP0Q2X205PSQ6RNUj0M+1OB/9gRQaUZ/ccYfaxd0nhaWKfjw==", "requires": {} }, "@xtuc/ieee754": { @@ -11302,9 +11673,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001431", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001431.tgz", - "integrity": "sha512-zBUoFU0ZcxpvSt9IU66dXVT/3ctO1cy4y9cscs1szkPlcWb6pasYM144GqrUygUbT+k7cmUCW61cvskjcv0enQ==" + "version": "1.0.30001439", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001439.tgz", + "integrity": "sha512-1MgUzEkoMO6gKfXflStpYgZDlFM7M/ck/bgfVCACO5vnAf0fXoNVHdWtqGU+MYca+4bL9Z5bpOVmR33cWW9G2A==" }, "chai": { "version": "4.3.7", @@ -11342,9 +11713,9 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, "ci-info": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.6.1.tgz", - "integrity": "sha512-up5ggbaDqOqJ4UqLKZ2naVkyqSJQgJi5lwD6b6mM748ysrghDBX0bx/qJTUHzw7zu6Mq4gycviSF5hJnwceD8w==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.7.0.tgz", + "integrity": "sha512-2CpRNYmImPx+RXKLq6jko/L07phmS9I02TyqkcNU20GCF/GgaWvc58hPtjxDX8lPpkdwc9sNh72V9k00S7ezog==", "dev": true }, "citeproc": { @@ -11414,9 +11785,9 @@ } }, "codemirror": { - "version": "5.65.10", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.10.tgz", - "integrity": "sha512-IXAG5wlhbgcTJ6rZZcmi4+sjWIbJqIGfeg3tNa3yX84Jb3T4huS5qzQAo/cUisc1l3bI47WZodpyf7cYcocDKg==" + "version": "5.65.11", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.11.tgz", + "integrity": "sha512-Gp62g2eKSCHYt10axmGhKq3WoJSvVpvhXmowNq7pZdRVowwtvBR/hi2LSP5srtctKkRT33T6/n8Kv1UGp7JW4A==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -11525,12 +11896,12 @@ "dev": true }, "css-loader": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.2.tgz", - "integrity": "sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz", + "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==", "requires": { "icss-utils": "^5.1.0", - "postcss": "^8.4.18", + "postcss": "^8.4.19", "postcss-modules-extract-imports": "^3.0.0", "postcss-modules-local-by-default": "^4.0.0", "postcss-modules-scope": "^3.0.0", @@ -11559,12 +11930,12 @@ "dev": true }, "css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, "requires": { - "mdn-data": "2.0.28", + "mdn-data": "2.0.30", "source-map-js": "^1.0.1" } }, @@ -11605,6 +11976,24 @@ "dev": true, "requires": { "css-tree": "~2.2.0" + }, + "dependencies": { + "css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "requires": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + } + }, + "mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + } } }, "cssom": { @@ -11636,9 +12025,9 @@ "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" }, "d3": { - "version": "7.6.1", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.6.1.tgz", - "integrity": "sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.7.0.tgz", + "integrity": "sha512-VEwHCMgMjD2WBsxeRGUE18RmzxT9Bn7ghDpzvTEvkLSBAKgTMydJjouZTjspgQfRHpPt/PB3EHWBa6SSyFQq4g==", "requires": { "d3-array": "3", "d3-axis": "3", @@ -11673,9 +12062,9 @@ } }, "d3-array": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.0.tgz", - "integrity": "sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", "requires": { "internmap": "1 - 2" } @@ -11705,11 +12094,6 @@ "d3-path": "1 - 3" } }, - "d3-collection": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz", - "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" - }, "d3-color": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", @@ -11812,9 +12196,9 @@ } }, "d3-path": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.0.1.tgz", - "integrity": "sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" }, "d3-polygon": { "version": "3.0.1", @@ -11866,9 +12250,9 @@ } }, "d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "requires": { "d3-array": "2 - 3" } @@ -11898,11 +12282,6 @@ "d3-timer": "1 - 3" } }, - "d3-voronoi": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz", - "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==" - }, "d3-zoom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", @@ -11915,293 +12294,13 @@ "d3-transition": "2 - 3" } }, - "dagre": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/dagre/-/dagre-0.8.5.tgz", - "integrity": "sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==", - "requires": { - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - } - }, - "dagre-d3": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/dagre-d3/-/dagre-d3-0.6.4.tgz", - "integrity": "sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==", + "dagre-d3-es": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.6.tgz", + "integrity": "sha512-CaaE/nZh205ix+Up4xsnlGmpog5GGm81Upi2+/SBHxwNwrccBb3K51LzjZ1U6hgvOlAEUsVWf1xSTzCyKpJ6+Q==", "requires": { - "d3": "^5.14", - "dagre": "^0.8.5", - "graphlib": "^2.1.8", - "lodash": "^4.17.15" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "d3": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-5.16.0.tgz", - "integrity": "sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==", - "requires": { - "d3-array": "1", - "d3-axis": "1", - "d3-brush": "1", - "d3-chord": "1", - "d3-collection": "1", - "d3-color": "1", - "d3-contour": "1", - "d3-dispatch": "1", - "d3-drag": "1", - "d3-dsv": "1", - "d3-ease": "1", - "d3-fetch": "1", - "d3-force": "1", - "d3-format": "1", - "d3-geo": "1", - "d3-hierarchy": "1", - "d3-interpolate": "1", - "d3-path": "1", - "d3-polygon": "1", - "d3-quadtree": "1", - "d3-random": "1", - "d3-scale": "2", - "d3-scale-chromatic": "1", - "d3-selection": "1", - "d3-shape": "1", - "d3-time": "1", - "d3-time-format": "2", - "d3-timer": "1", - "d3-transition": "1", - "d3-voronoi": "1", - "d3-zoom": "1" - } - }, - "d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - }, - "d3-axis": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz", - "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==" - }, - "d3-brush": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.1.6.tgz", - "integrity": "sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==", - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "d3-chord": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz", - "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==", - "requires": { - "d3-array": "1", - "d3-path": "1" - } - }, - "d3-color": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.4.1.tgz", - "integrity": "sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==" - }, - "d3-contour": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz", - "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==", - "requires": { - "d3-array": "^1.1.1" - } - }, - "d3-dispatch": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.6.tgz", - "integrity": "sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==" - }, - "d3-drag": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.5.tgz", - "integrity": "sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==", - "requires": { - "d3-dispatch": "1", - "d3-selection": "1" - } - }, - "d3-dsv": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.2.0.tgz", - "integrity": "sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==", - "requires": { - "commander": "2", - "iconv-lite": "0.4", - "rw": "1" - } - }, - "d3-ease": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.7.tgz", - "integrity": "sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==" - }, - "d3-fetch": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.2.0.tgz", - "integrity": "sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==", - "requires": { - "d3-dsv": "1" - } - }, - "d3-force": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz", - "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==", - "requires": { - "d3-collection": "1", - "d3-dispatch": "1", - "d3-quadtree": "1", - "d3-timer": "1" - } - }, - "d3-format": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.4.5.tgz", - "integrity": "sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==" - }, - "d3-geo": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.12.1.tgz", - "integrity": "sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==", - "requires": { - "d3-array": "1" - } - }, - "d3-hierarchy": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.9.tgz", - "integrity": "sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==" - }, - "d3-interpolate": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.4.0.tgz", - "integrity": "sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==", - "requires": { - "d3-color": "1" - } - }, - "d3-path": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", - "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" - }, - "d3-polygon": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.6.tgz", - "integrity": "sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==" - }, - "d3-quadtree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.7.tgz", - "integrity": "sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==" - }, - "d3-random": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz", - "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==" - }, - "d3-scale": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz", - "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==", - "requires": { - "d3-array": "^1.2.0", - "d3-collection": "1", - "d3-format": "1", - "d3-interpolate": "1", - "d3-time": "1", - "d3-time-format": "2" - } - }, - "d3-scale-chromatic": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.5.0.tgz", - "integrity": "sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==", - "requires": { - "d3-color": "1", - "d3-interpolate": "1" - } - }, - "d3-selection": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.2.tgz", - "integrity": "sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==" - }, - "d3-shape": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", - "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", - "requires": { - "d3-path": "1" - } - }, - "d3-time": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.1.0.tgz", - "integrity": "sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==" - }, - "d3-time-format": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.3.0.tgz", - "integrity": "sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==", - "requires": { - "d3-time": "1" - } - }, - "d3-timer": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.10.tgz", - "integrity": "sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==" - }, - "d3-transition": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.3.2.tgz", - "integrity": "sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==", - "requires": { - "d3-color": "1", - "d3-dispatch": "1", - "d3-ease": "1", - "d3-interpolate": "1", - "d3-selection": "^1.1.0", - "d3-timer": "1" - } - }, - "d3-zoom": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.8.3.tgz", - "integrity": "sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==", - "requires": { - "d3-dispatch": "1", - "d3-drag": "1", - "d3-interpolate": "1", - "d3-selection": "1", - "d3-transition": "1" - } - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } + "d3": "^7.7.0", + "lodash-es": "^4.17.21" } }, "data-uri-to-buffer": { @@ -12255,15 +12354,15 @@ } }, "decimal.js": { - "version": "10.4.2", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.2.tgz", - "integrity": "sha512-ic1yEvwT6GuvaYwBLLY6/aFFgjZdySKTE8en/fkU3QICTmRtgtSlFn0u0BXN06InZwtfCelR7j8LRiDI/02iGA==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", "dev": true }, "deep-eql": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.2.tgz", - "integrity": "sha512-gT18+YW4CcW/DBNTwAmqTtkJh7f9qqScu2qFVlx7kCoeY9tlBu9cUcr7+I+Z/noG8INehS3xQgLpTtd/QUTn4w==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", "dev": true, "requires": { "type-detect": "^4.0.0" @@ -12460,9 +12559,9 @@ } }, "dompurify": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.0.tgz", - "integrity": "sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==" + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.1.tgz", + "integrity": "sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==" }, "domutils": { "version": "3.0.1", @@ -12523,9 +12622,9 @@ "dev": true }, "enhanced-resolve": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", - "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz", + "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==", "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -12567,9 +12666,9 @@ } }, "es-abstract": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", - "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.5.tgz", + "integrity": "sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -12578,6 +12677,7 @@ "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.3", "get-symbol-description": "^1.0.0", + "gopd": "^1.0.1", "has": "^1.0.3", "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", @@ -12593,8 +12693,8 @@ "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.4.3", "safe-regex-test": "^1.0.0", - "string.prototype.trimend": "^1.0.5", - "string.prototype.trimstart": "^1.0.5", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", "unbox-primitive": "^1.0.2" } }, @@ -12639,116 +12739,116 @@ } }, "esbuild": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.14.tgz", - "integrity": "sha512-pJN8j42fvWLFWwSMG4luuupl2Me7mxciUOsMegKvwCmhEbJ2covUdFnihxm0FMIBV+cbwbtMoHgMCCI+pj1btQ==", - "requires": { - "@esbuild/android-arm": "0.15.14", - "@esbuild/linux-loong64": "0.15.14", - "esbuild-android-64": "0.15.14", - "esbuild-android-arm64": "0.15.14", - "esbuild-darwin-64": "0.15.14", - "esbuild-darwin-arm64": "0.15.14", - "esbuild-freebsd-64": "0.15.14", - "esbuild-freebsd-arm64": "0.15.14", - "esbuild-linux-32": "0.15.14", - "esbuild-linux-64": "0.15.14", - "esbuild-linux-arm": "0.15.14", - "esbuild-linux-arm64": "0.15.14", - "esbuild-linux-mips64le": "0.15.14", - "esbuild-linux-ppc64le": "0.15.14", - "esbuild-linux-riscv64": "0.15.14", - "esbuild-linux-s390x": "0.15.14", - "esbuild-netbsd-64": "0.15.14", - "esbuild-openbsd-64": "0.15.14", - "esbuild-sunos-64": "0.15.14", - "esbuild-windows-32": "0.15.14", - "esbuild-windows-64": "0.15.14", - "esbuild-windows-arm64": "0.15.14" + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz", + "integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==", + "requires": { + "@esbuild/android-arm": "0.15.18", + "@esbuild/linux-loong64": "0.15.18", + "esbuild-android-64": "0.15.18", + "esbuild-android-arm64": "0.15.18", + "esbuild-darwin-64": "0.15.18", + "esbuild-darwin-arm64": "0.15.18", + "esbuild-freebsd-64": "0.15.18", + "esbuild-freebsd-arm64": "0.15.18", + "esbuild-linux-32": "0.15.18", + "esbuild-linux-64": "0.15.18", + "esbuild-linux-arm": "0.15.18", + "esbuild-linux-arm64": "0.15.18", + "esbuild-linux-mips64le": "0.15.18", + "esbuild-linux-ppc64le": "0.15.18", + "esbuild-linux-riscv64": "0.15.18", + "esbuild-linux-s390x": "0.15.18", + "esbuild-netbsd-64": "0.15.18", + "esbuild-openbsd-64": "0.15.18", + "esbuild-sunos-64": "0.15.18", + "esbuild-windows-32": "0.15.18", + "esbuild-windows-64": "0.15.18", + "esbuild-windows-arm64": "0.15.18" } }, "esbuild-android-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.14.tgz", - "integrity": "sha512-HuilVIb4rk9abT4U6bcFdU35UHOzcWVGLSjEmC58OVr96q5UiRqzDtWjPlCMugjhgUGKEs8Zf4ueIvYbOStbIg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz", + "integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==", "optional": true }, "esbuild-android-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.14.tgz", - "integrity": "sha512-/QnxRVxsR2Vtf3XottAHj7hENAMW2wCs6S+OZcAbc/8nlhbAL/bCQRCVD78VtI5mdwqWkVi3wMqM94kScQCgqg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz", + "integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==", "optional": true }, "esbuild-darwin-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.14.tgz", - "integrity": "sha512-ToNuf1uifu8hhwWvoZJGCdLIX/1zpo8cOGnT0XAhDQXiKOKYaotVNx7pOVB1f+wHoWwTLInrOmh3EmA7Fd+8Vg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz", + "integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==", "optional": true }, "esbuild-darwin-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.14.tgz", - "integrity": "sha512-KgGP+y77GszfYJgceO0Wi/PiRtYo5y2Xo9rhBUpxTPaBgWDJ14gqYN0+NMbu+qC2fykxXaipHxN4Scaj9tUS1A==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz", + "integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==", "optional": true }, "esbuild-freebsd-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.14.tgz", - "integrity": "sha512-xr0E2n5lyWw3uFSwwUXHc0EcaBDtsal/iIfLioflHdhAe10KSctV978Te7YsfnsMKzcoGeS366+tqbCXdqDHQA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz", + "integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==", "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.14.tgz", - "integrity": "sha512-8XH96sOQ4b1LhMlO10eEWOjEngmZ2oyw3pW4o8kvBcpF6pULr56eeYVP5radtgw54g3T8nKHDHYEI5AItvskZg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz", + "integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==", "optional": true }, "esbuild-linux-32": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.14.tgz", - "integrity": "sha512-6ssnvwaTAi8AzKN8By2V0nS+WF5jTP7SfuK6sStGnDP7MCJo/4zHgM9oE1eQTS2jPmo3D673rckuCzRlig+HMA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz", + "integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==", "optional": true }, "esbuild-linux-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.14.tgz", - "integrity": "sha512-ONySx3U0wAJOJuxGUlXBWxVKFVpWv88JEv0NZ6NlHknmDd1yCbf4AEdClSgLrqKQDXYywmw4gYDvdLsS6z0hcw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz", + "integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==", "optional": true }, "esbuild-linux-arm": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.14.tgz", - "integrity": "sha512-D2LImAIV3QzL7lHURyCHBkycVFbKwkDb1XEUWan+2fb4qfW7qAeUtul7ZIcIwFKZgPcl+6gKZmvLgPSj26RQ2Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz", + "integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==", "optional": true }, "esbuild-linux-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.14.tgz", - "integrity": "sha512-kle2Ov6a1e5AjlHlMQl1e+c4myGTeggrRzArQFmWp6O6JoqqB9hT+B28EW4tjFWgV/NxUq46pWYpgaWXsXRPAg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz", + "integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==", "optional": true }, "esbuild-linux-mips64le": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.14.tgz", - "integrity": "sha512-FVdMYIzOLXUq+OE7XYKesuEAqZhmAIV6qOoYahvUp93oXy0MOVTP370ECbPfGXXUdlvc0TNgkJa3YhEwyZ6MRA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz", + "integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==", "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.14.tgz", - "integrity": "sha512-2NzH+iuzMDA+jjtPjuIz/OhRDf8tzbQ1tRZJI//aT25o1HKc0reMMXxKIYq/8nSHXiJSnYV4ODzTiv45s+h73w==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz", + "integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==", "optional": true }, "esbuild-linux-riscv64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.14.tgz", - "integrity": "sha512-VqxvutZNlQxmUNS7Ac+aczttLEoHBJ9e3OYGqnULrfipRvG97qLrAv9EUY9iSrRKBqeEbSvS9bSfstZqwz0T4Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz", + "integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==", "optional": true }, "esbuild-linux-s390x": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.14.tgz", - "integrity": "sha512-+KVHEUshX5n6VP6Vp/AKv9fZIl5kr2ph8EUFmQUJnDpHwcfTSn2AQgYYm0HTBR2Mr4d0Wlr0FxF/Cs5pbFgiOw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz", + "integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==", "optional": true }, "esbuild-loader": { @@ -12765,39 +12865,39 @@ } }, "esbuild-netbsd-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.14.tgz", - "integrity": "sha512-6D/dr17piEgevIm1xJfZP2SjB9Z+g8ERhNnBdlZPBWZl+KSPUKLGF13AbvC+nzGh8IxOH2TyTIdRMvKMP0nEzQ==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz", + "integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==", "optional": true }, "esbuild-openbsd-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.14.tgz", - "integrity": "sha512-rREQBIlMibBetgr2E9Lywt2Qxv2ZdpmYahR4IUlAQ1Efv/A5gYdO0/VIN3iowDbCNTLxp0bb57Vf0LFcffD6kA==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz", + "integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==", "optional": true }, "esbuild-sunos-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.14.tgz", - "integrity": "sha512-DNVjSp/BY4IfwtdUAvWGIDaIjJXY5KI4uD82+15v6k/w7px9dnaDaJJ2R6Mu+KCgr5oklmFc0KjBjh311Gxl9Q==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz", + "integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==", "optional": true }, "esbuild-windows-32": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.14.tgz", - "integrity": "sha512-pHBWrcA+/oLgvViuG9FO3kNPO635gkoVrRQwe6ZY1S0jdET07xe2toUvQoJQ8KT3/OkxqUasIty5hpuKFLD+eg==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz", + "integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==", "optional": true }, "esbuild-windows-64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.14.tgz", - "integrity": "sha512-CszIGQVk/P8FOS5UgAH4hKc9zOaFo69fe+k1rqgBHx3CSK3Opyk5lwYriIamaWOVjBt7IwEP6NALz+tkVWdFog==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz", + "integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==", "optional": true }, "esbuild-windows-arm64": { - "version": "0.15.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.14.tgz", - "integrity": "sha512-KW9W4psdZceaS9A7Jsgl4WialOznSURvqX/oHZk3gOP7KbjtHLSsnmSvNdzagGJfxbAe30UVGXRe8q8nDsOSQw==", + "version": "0.15.18", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz", + "integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==", "optional": true }, "escalade": { @@ -12871,13 +12971,13 @@ } }, "eslint": { - "version": "8.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.28.0.tgz", - "integrity": "sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==", + "version": "8.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.30.0.tgz", + "integrity": "sha512-MGADB39QqYuzEGov+F/qb18r4i7DohCDOfatHaxI2iGlPuC65bwG2gxgO+7DkyL38dRFaRH7RaRAgU6JKL9rMQ==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.3", - "@humanwhocodes/config-array": "^0.11.6", + "@eslint/eslintrc": "^1.4.0", + "@humanwhocodes/config-array": "^0.11.8", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -12896,7 +12996,7 @@ "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.15.0", + "globals": "^13.19.0", "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", @@ -13033,40 +13133,40 @@ "requires": {} }, "eslint-plugin-sonarjs": { - "version": "0.16.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.16.0.tgz", - "integrity": "sha512-al8ojAzcQW8Eu0tWn841ldhPpPcjrJ59TzzTfAVWR45bWvdAASCmrGl8vK0MWHyKVDdC0i17IGbtQQ1KgxLlVA==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.17.0.tgz", + "integrity": "sha512-jtGtxI49UbJJeJj7CVRLI3+LLH+y+hkR3GOOwM7vBbci9DEFIRGCWvEd2BJScrzltZ6D6iubukTAfc9cyG7sdw==", "dev": true, "requires": {} }, "eslint-plugin-unicorn": { - "version": "45.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.0.tgz", - "integrity": "sha512-iP8cMRxXKHonKioOhnCoCcqVhoqhAp6rB+nsoLjXFDxTHz3btWMAp8xwzjHA0B1K6YV/U/Yvqn1bUXZt8sJPuQ==", + "version": "45.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-45.0.2.tgz", + "integrity": "sha512-Y0WUDXRyGDMcKLiwgL3zSMpHrXI00xmdyixEGIg90gHnj0PcHY4moNv3Ppje/kDivdAy5vUeUr7z211ImPv2gw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.19.1", + "@eslint-community/eslint-utils": "^4.1.2", "ci-info": "^3.6.1", "clean-regexp": "^1.0.0", - "eslint-utils": "^3.0.0", "esquery": "^1.4.0", "indent-string": "^4.0.0", "is-builtin-module": "^3.2.0", - "jsesc": "3.0.2", + "jsesc": "^3.0.2", "lodash": "^4.17.21", "pluralize": "^8.0.0", "read-pkg-up": "^7.0.1", "regexp-tree": "^0.1.24", - "regjsparser": "0.9.1", + "regjsparser": "^0.9.1", "safe-regex": "^2.1.1", "semver": "^7.3.8", "strip-indent": "^3.0.0" } }, "eslint-plugin-vue": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.7.0.tgz", - "integrity": "sha512-DrOO3WZCZEwcLsnd3ohFwqCoipGRSTKTBTnLwdhqAbYZtzWl0o7D+D8ZhlmiZvABKTEl8AFsqH1GHGdybyoQmw==", + "version": "9.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.8.0.tgz", + "integrity": "sha512-E/AXwcTzunyzM83C2QqDHxepMzvI2y6x+mmeYHbVDQlKFqmKYvRrhaVixEeeG27uI44p9oKDFiyCRw4XxgtfHA==", "dev": true, "requires": { "eslint-utils": "^3.0.0", @@ -13172,11 +13272,6 @@ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" }, - "fast-clone": { - "version": "1.5.13", - "resolved": "https://registry.npmjs.org/fast-clone/-/fast-clone-1.5.13.tgz", - "integrity": "sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==" - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -13227,9 +13322,9 @@ "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==" }, "fastq": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", - "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.14.0.tgz", + "integrity": "sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==", "requires": { "reusify": "^1.0.4" } @@ -13507,9 +13602,9 @@ } }, "globals": { - "version": "13.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.18.0.tgz", - "integrity": "sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==", + "version": "13.19.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", + "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -13544,6 +13639,15 @@ "integrity": "sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg==", "dev": true }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -13555,14 +13659,6 @@ "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", "dev": true }, - "graphlib": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz", - "integrity": "sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==", - "requires": { - "lodash": "^4.17.15" - } - }, "gsap": { "version": "3.11.3", "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.11.3.tgz", @@ -13697,9 +13793,9 @@ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" }, "ignore": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", - "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", "dev": true }, "image-size": { @@ -13772,12 +13868,12 @@ "dev": true }, "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.4.tgz", + "integrity": "sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==", "dev": true, "requires": { - "get-intrinsic": "^1.1.0", + "get-intrinsic": "^1.1.3", "has": "^1.0.3", "side-channel": "^1.0.4" } @@ -14019,9 +14115,9 @@ "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==" }, "jquery": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.1.tgz", - "integrity": "sha512-opJeO4nCucVnsjiXOE+/PcCgYw9Gwpvs/a6B1LL/lQhwWwpbVEVYDZ1FokFr8PRc7ghYlrFPuyHuiiDNTQxmcw==" + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.2.tgz", + "integrity": "sha512-/e7ulNIEEYk1Z/l4X0vpxGt+B/dNsV8ghOPAWZaJs8pkGvsSC0tm33aMGylXcj/U7y4IcvwtMXPMyBFZn/gK9A==" }, "jquery.are-you-sure": { "version": "1.9.0", @@ -14032,9 +14128,9 @@ } }, "js-sdsl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz", - "integrity": "sha512-08bOAKweV2NUC1wqTtf3qZlnpOX/R2DU9ikpjOHs0H+ibQv3zpncVQg6um4uYtRtrwIX8M4Nh3ytK4HGlYAq7Q==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha512-dyBIzQBDkCqCu+0upx25Y2jGdbTGxE9fshMsCdK0ViOongpV+n5tXRcZY9v7CaVQ79AGS9KA1KHtojxiM7aXSQ==", "dev": true }, "js-tokens": { @@ -14086,9 +14182,9 @@ } }, "jsep": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.7.tgz", - "integrity": "sha512-NFbZTr1t13fPKw53swmZFKwBkEDWDnno7uLJk+a+Rw9tGDTkGgnGdZJ8A/o3gR1+XaAXmSsbpfIBIBgqRBZWDA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.8.tgz", + "integrity": "sha512-qofGylTGgYj9gZFsHuyWAN4jr35eJ66qJCK4eKDnldohuUoQFbU3iZn2zjvEbd9wOAhP9Wx5DsAAduTyE1PSWQ==", "dev": true }, "jsesc": { @@ -14114,9 +14210,9 @@ "dev": true }, "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.2.tgz", + "integrity": "sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ==" }, "jsonc-parser": { "version": "2.2.1", @@ -14151,9 +14247,9 @@ "integrity": "sha512-b+z6yF1d4EOyDgylzQo5IminlUmzSeqR1hs/bzjBNjuGras4FXq/6TrzjxfN0j+TmI0ltJzTNlqXUMCniciwKQ==" }, "katex": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.3.tgz", - "integrity": "sha512-3EykQddareoRmbtNiNEDgl3IGjryyrp2eg/25fHDEnlHymIDi33bptkMv6K4EOC2LZCybLW/ZkEo6Le+EM9pmA==", + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.4.tgz", + "integrity": "sha512-WudRKUj8yyBeVDI4aYMNxhx5Vhh2PjpzQw1GRu/LVGqL4m1AxwD1GcUp0IMbdJaf5zsjtj8ghP0DOQRYhroNkw==", "requires": { "commander": "^8.0.0" } @@ -14310,7 +14406,13 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "lodash._reinterpolate": { "version": "3.0.0", @@ -14477,9 +14579,9 @@ "dev": true }, "minimatch": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", - "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -14494,9 +14596,9 @@ "dev": true }, "marked": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz", - "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==" + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.4.tgz", + "integrity": "sha512-Wcc9ikX7Q5E4BYDPvh1C6QNSxrjC9tBgz+A/vAhp59KXUgachw++uMvMKiSW8oA85nopmPZcEvBoex/YLMsiyA==" }, "mathml-tag-names": { "version": "2.1.3", @@ -14505,9 +14607,9 @@ "dev": true }, "mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true }, "mdurl": { @@ -14591,19 +14693,16 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "mermaid": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.2.2.tgz", - "integrity": "sha512-6s7eKMqFJGS+0MYjmx8f6ZigqKBJVoSx5ql2gw6a4Aa+WJ49QiEJg7gPwywaBg3DZMs79UP7trESp4+jmaQccw==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.3.0.tgz", + "integrity": "sha512-mGl0BM19TD/HbU/LmlaZbjBi//tojelg8P/mxD6pPZTAYaI+VawcyBdqRsoUHSc7j71PrMdJ3HBadoQNdvP5cg==", "requires": { "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", - "dagre": "^0.8.5", - "dagre-d3": "^0.6.4", - "dompurify": "2.4.0", - "fast-clone": "^1.5.13", - "graphlib": "^2.1.8", + "dagre-d3-es": "7.0.6", + "dompurify": "2.4.1", "khroma": "^2.0.0", - "lodash": "^4.17.21", + "lodash-es": "^4.17.21", "moment-mini": "^2.24.0", "non-layered-tidy-tree-layout": "^2.0.2", "stylis": "^4.1.2", @@ -14645,9 +14744,9 @@ "dev": true }, "mini-css-extract-plugin": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.0.tgz", - "integrity": "sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==", + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz", + "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==", "requires": { "schema-utils": "^4.0.0" } @@ -14677,6 +14776,26 @@ "kind-of": "^6.0.3" } }, + "mlly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.0.0.tgz", + "integrity": "sha512-QL108Hwt+u9bXdWgOI0dhzZfACovn5Aen4Xvc8Jasd9ouRH4NjnrXEiyP3nVvJo91zPlYjVRckta0Nt2zfoR6g==", + "dev": true, + "requires": { + "acorn": "^8.8.1", + "pathe": "^1.0.0", + "pkg-types": "^1.0.0", + "ufo": "^1.0.0" + }, + "dependencies": { + "pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + } + } + }, "moment-mini": { "version": "2.29.4", "resolved": "https://registry.npmjs.org/moment-mini/-/moment-mini-2.29.4.tgz", @@ -14803,9 +14922,9 @@ } }, "node-releases": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", - "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", + "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" }, "non-layered-tidy-tree-layout": { "version": "2.0.2", @@ -15017,9 +15136,9 @@ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" }, "parse5": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.1.tgz", - "integrity": "sha512-kwpuwzB+px5WUg9pyK0IcK/shltJN5/OVhQagxhCQNtT9Y9QRZqNY2e1cmbu/paRh5LMnz/oVTVLBpjFmMZhSg==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dev": true, "requires": { "entities": "^4.4.0" @@ -15059,6 +15178,12 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathe": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz", + "integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==", + "dev": true + }, "pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -15124,10 +15249,35 @@ } } }, + "pkg-types": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.1.tgz", + "integrity": "sha512-jHv9HB+Ho7dj6ItwppRDDl0iZRYBD0jsakHXtFgoLr+cHSF6xC+QL54sJmWxyGxOLYSHm0afhXhXcQDQqH9z8g==", + "dev": true, + "requires": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.0.0", + "pathe": "^1.0.0" + }, + "dependencies": { + "jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "pathe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.0.0.tgz", + "integrity": "sha512-nPdMG0Pd09HuSsr7QOKUXO2Jr9eqaDiZvDwdyIhNG5SHYujkQHYKDfGQkulBxvbDHz8oHLsTgKN86LSwYzSHAg==", + "dev": true + } + } + }, "playwright-core": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", - "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.29.0.tgz", + "integrity": "sha512-pboOm1m0RD6z1GtwAbEH60PYRfF87vKdzOSRw2RyO0Y0a7utrMyWN2Au1ojGvQr4umuBMODkKTv607YIRypDSQ==", "dev": true }, "pluralize": { @@ -15143,9 +15293,9 @@ "dev": true }, "postcss": { - "version": "8.4.19", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz", - "integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==", + "version": "8.4.20", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz", + "integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==", "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -15990,12 +16140,12 @@ "dev": true }, "strip-literal": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-0.4.2.tgz", - "integrity": "sha512-pv48ybn4iE1O9RLgCAN0iU4Xv7RlBTiit6DKmMiErbs9x1wH6vXBs45tWc0H5wUIF6TLTrKweqkmYF/iraQKNw==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.0.tgz", + "integrity": "sha512-5o4LsH1lzBzO9UFH63AJ2ad2/S2AVx6NtjOcaz+VTT2h1RiRvbipW72z8M/lxEhcPHDBQwpDrnTF7sXy/7OwCQ==", "dev": true, "requires": { - "acorn": "^8.8.0" + "acorn": "^8.8.1" } }, "style-search": { @@ -16005,9 +16155,9 @@ "dev": true }, "stylelint": { - "version": "14.15.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.15.0.tgz", - "integrity": "sha512-JOgDAo5QRsqiOZPZO+B9rKJvBm64S0xasbuRPAbPs6/vQDgDCnZLIiw6XcAS6GQKk9k1sBWR6rmH3Mfj8OknKg==", + "version": "14.16.0", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.0.tgz", + "integrity": "sha512-X6uTi9DcxjzLV8ZUAjit1vsRtSwcls0nl07c9rqOPzvpA8IvTX/xWEkBRowS0ffevRrqkHa/ThDEu86u73FQDg==", "dev": true, "requires": { "@csstools/selector-specificity": "^2.0.2", @@ -16023,7 +16173,7 @@ "globby": "^11.1.0", "globjoin": "^0.1.4", "html-tags": "^3.2.0", - "ignore": "^5.2.0", + "ignore": "^5.2.1", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", @@ -16037,7 +16187,7 @@ "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.10", + "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -16190,9 +16340,9 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, "terser": { - "version": "5.15.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.15.1.tgz", - "integrity": "sha512-K1faMUvpm/FBxjBXud0LWVAGxmvoPbZbfTCYbSgaaYQaIXI3/TdI7a7ZGA73Zrou6Q8Zmz3oeUTsp/dj+ag2Xw==", + "version": "5.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.1.tgz", + "integrity": "sha512-xvQfyfA1ayT0qdK47zskQgRZeWLoOQ8JQ6mIgRGVNwZKdQMU+5FkCBjmv4QjcrTzyZquRw2FVtlJSRUmMKQslw==", "requires": { "@jridgewell/source-map": "^0.3.2", "acorn": "^8.5.0", @@ -16399,6 +16549,12 @@ "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", "dev": true }, + "ufo": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.0.1.tgz", + "integrity": "sha512-boAm74ubXHY7KJQZLlXrtMz52qFvpsbOxDcZOnw/Wf+LS4Mmyu7JxmzD4tDLtUQtmZECypJ0FrCz4QIe6dvKRA==", + "dev": true + }, "uint8-to-base64": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/uint8-to-base64/-/uint8-to-base64-0.2.0.tgz", @@ -16438,9 +16594,9 @@ } }, "updates": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.2.1.tgz", - "integrity": "sha512-d+nIbU2fl/PDEvUkbQch4uRdkXt9AQoPlH6b/FPTOAzF9voGbXgZNNxgO79Jeish24ZMfOqUl5lJcKSwMO2RJQ==", + "version": "13.2.4", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.2.4.tgz", + "integrity": "sha512-aQcPi3/kRcMLqLZj6nvy0PZAX3ZhE78IdHoj02SujNqH3/55hgn2i/bHVzPUI86+qWITkt7PyjJHBLDSxDHEyA==", "dev": true }, "uri-js": { @@ -16509,44 +16665,114 @@ } }, "vite": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-3.2.4.tgz", - "integrity": "sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.2.tgz", + "integrity": "sha512-QJaY3R+tFlTagH0exVqbgkkw45B+/bXVBzF2ZD1KB5Z8RiAoiKo60vSUf6/r4c2Vh9jfGBKM4oBI9b4/1ZJYng==", "dev": true, "requires": { - "esbuild": "^0.15.9", + "esbuild": "^0.16.3", "fsevents": "~2.3.2", - "postcss": "^8.4.18", + "postcss": "^8.4.20", "resolve": "^1.22.1", - "rollup": "^2.79.1" + "rollup": "^3.7.0" + }, + "dependencies": { + "@esbuild/android-arm": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.16.10.tgz", + "integrity": "sha512-RmJjQTRrO6VwUWDrzTBLmV4OJZTarYsiepLGlF2rYTVB701hSorPywPGvP6d8HCuuRibyXa5JX4s3jN2kHEtjQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.16.10.tgz", + "integrity": "sha512-O7Pd5hLEtTg37NC73pfhUOGTjx/+aXu5YoSq3ahCxcN7Bcr2F47mv+kG5t840thnsEzrv0oB70+LJu3gUgchvg==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.16.10", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.16.10.tgz", + "integrity": "sha512-z5dIViHoVnw2l+NCJ3zj5behdXjYvXne9gL18OOivCadXDUhyDkeSvEtLcGVAJW2fNmh33TDUpsi704XYlDodw==", + "dev": true, + "requires": { + "@esbuild/android-arm": "0.16.10", + "@esbuild/android-arm64": "0.16.10", + "@esbuild/android-x64": "0.16.10", + "@esbuild/darwin-arm64": "0.16.10", + "@esbuild/darwin-x64": "0.16.10", + "@esbuild/freebsd-arm64": "0.16.10", + "@esbuild/freebsd-x64": "0.16.10", + "@esbuild/linux-arm": "0.16.10", + "@esbuild/linux-arm64": "0.16.10", + "@esbuild/linux-ia32": "0.16.10", + "@esbuild/linux-loong64": "0.16.10", + "@esbuild/linux-mips64el": "0.16.10", + "@esbuild/linux-ppc64": "0.16.10", + "@esbuild/linux-riscv64": "0.16.10", + "@esbuild/linux-s390x": "0.16.10", + "@esbuild/linux-x64": "0.16.10", + "@esbuild/netbsd-x64": "0.16.10", + "@esbuild/openbsd-x64": "0.16.10", + "@esbuild/sunos-x64": "0.16.10", + "@esbuild/win32-arm64": "0.16.10", + "@esbuild/win32-ia32": "0.16.10", + "@esbuild/win32-x64": "0.16.10" + } + }, + "rollup": { + "version": "3.7.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.7.5.tgz", + "integrity": "sha512-z0ZbqHBtS/et2EEUKMrAl2CoSdwN7ZPzL17UMiKN9RjjqHShTlv7F9J6ZJZJNREYjBh3TvBrdfjkFDIXFNeuiQ==", + "dev": true, + "requires": { + "fsevents": "~2.3.2" + } + } + } + }, + "vite-node": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.26.1.tgz", + "integrity": "sha512-5FJSKZZJz48zFRKHE55WyevZe61hLMQEsqGn+ungfd60kxEztFybZ3yG9ToGFtOWNCCy7Vn5EVuXD8bdeHOSdw==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "mlly": "^1.0.0", + "pathe": "^0.2.0", + "source-map": "^0.6.1", + "source-map-support": "^0.5.21", + "vite": "^3.0.0 || ^4.0.0" } }, "vitest": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.25.2.tgz", - "integrity": "sha512-qqkzfzglEFbQY7IGkgSJkdOhoqHjwAao/OrphnHboeYHC5JzsVFoLCaB2lnAy8krhj7sbrFTVRApzpkTOeuDWQ==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.26.1.tgz", + "integrity": "sha512-qTLRnjYmjmJpHlLUtErxtlRqGCe8WItFhGXKklpWivu7CLP9KXN9iTezROe+vf51Kb+BB/fzxK6fUG9DvFGL5Q==", "dev": true, "requires": { - "@types/chai": "^4.3.3", + "@types/chai": "^4.3.4", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "acorn": "^8.8.0", + "acorn": "^8.8.1", "acorn-walk": "^8.2.0", - "chai": "^4.3.6", + "chai": "^4.3.7", "debug": "^4.3.4", "local-pkg": "^0.4.2", "source-map": "^0.6.1", - "strip-literal": "^0.4.2", + "strip-literal": "^1.0.0", "tinybench": "^2.3.1", "tinypool": "^0.3.0", "tinyspy": "^1.0.2", - "vite": "^3.0.0" + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.26.1" } }, "vm2": { - "version": "3.9.11", - "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.11.tgz", - "integrity": "sha512-PFG8iJRSjvvBdisowQ7iVF580DXb1uCIiGaXgm7tynMR1uTBlv7UJlB1zdv5KJ+Tmq1f0Upnj3fayoEOPpCBKg==", + "version": "3.9.13", + "resolved": "https://registry.npmjs.org/vm2/-/vm2-3.9.13.tgz", + "integrity": "sha512-0rvxpB8P8Shm4wX2EKOiMp7H2zq+HUE/UwodY0pCZXs9IffIKZq6vUti5OgkVCTakKo9e/fgO4X1fkwfjWxE3Q==", "dev": true, "requires": { "acorn": "^8.7.0", @@ -16721,14 +16947,14 @@ } }, "webpack-cli": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.0.tgz", - "integrity": "sha512-AACDTo20yG+xn6HPW5xjbn2Be4KUzQPebWXsDMHwPPyKh9OnTOJgZN2Nc+g/FZKV3ObRTYsGvibAvc+5jAUrVA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-5.0.1.tgz", + "integrity": "sha512-S3KVAyfwUqr0Mo/ur3NzIp6jnerNpo7GUO6so51mxLi1spqsA17YcMXy0WOIJtBSnj748lthxC6XLbNKh/ZC+A==", "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^2.0.0", - "@webpack-cli/info": "^2.0.0", - "@webpack-cli/serve": "^2.0.0", + "@webpack-cli/configtest": "^2.0.1", + "@webpack-cli/info": "^2.0.1", + "@webpack-cli/serve": "^2.0.1", "colorette": "^2.0.14", "commander": "^9.4.1", "cross-spawn": "^7.0.3", diff --git a/package.json b/package.json index 15c2601cd7aa..229d4f1aa90a 100644 --- a/package.json +++ b/package.json @@ -13,24 +13,24 @@ "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", - "@primer/octicons": "17.9.0", + "@primer/octicons": "17.10.0", "@vue/compiler-sfc": "3.2.45", "add-asset-webpack-plugin": "2.0.1", - "css-loader": "6.7.2", + "css-loader": "6.7.3", "dropzone": "6.0.0-beta.2", "easymde": "2.18.0", "esbuild-loader": "2.20.0", "escape-goat": "4.0.0", "fast-glob": "3.2.12", "font-awesome": "4.7.0", - "jquery": "3.6.1", + "jquery": "3.6.2", "jquery.are-you-sure": "1.9.0", - "katex": "0.16.3", + "katex": "0.16.4", "less": "4.1.3", "less-loader": "11.1.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "9.2.2", - "mini-css-extract-plugin": "2.7.0", + "mermaid": "9.3.0", + "mini-css-extract-plugin": "2.7.2", "monaco-editor": "0.34.1", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "8.0.0", @@ -44,31 +44,31 @@ "vue-loader": "17.0.1", "vue3-calendar-heatmap": "2.0.0", "webpack": "5.75.0", - "webpack-cli": "5.0.0", + "webpack-cli": "5.0.1", "workbox-routing": "6.5.4", "workbox-strategies": "6.5.4", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { - "@playwright/test": "1.28.0", + "@playwright/test": "1.29.0", "@rollup/pluginutils": "5.0.2", "@stoplight/spectral-cli": "6.6.0", - "eslint": "8.28.0", + "eslint": "8.30.0", "eslint-plugin-import": "2.26.0", "eslint-plugin-jquery": "1.5.1", - "eslint-plugin-sonarjs": "0.16.0", - "eslint-plugin-unicorn": "45.0.0", - "eslint-plugin-vue": "9.7.0", + "eslint-plugin-sonarjs": "0.17.0", + "eslint-plugin-unicorn": "45.0.2", + "eslint-plugin-vue": "9.8.0", "jsdom": "20.0.3", "markdownlint-cli": "0.32.2", "postcss-less": "6.0.0", - "stylelint": "14.15.0", + "stylelint": "14.16.0", "stylelint-config-standard": "29.0.0", "stylelint-declaration-strict-value": "1.9.1", "svgo": "3.0.2", - "updates": "13.2.1", - "vitest": "0.25.2" + "updates": "13.2.4", + "vitest": "0.26.1" }, "browserslist": [ "defaults", diff --git a/public/img/svg/octicon-goal.svg b/public/img/svg/octicon-goal.svg new file mode 100644 index 000000000000..b715f4bbd935 --- /dev/null +++ b/public/img/svg/octicon-goal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-read.svg b/public/img/svg/octicon-read.svg new file mode 100644 index 000000000000..bc275f50bf53 --- /dev/null +++ b/public/img/svg/octicon-read.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-rel-file-path.svg b/public/img/svg/octicon-rel-file-path.svg new file mode 100644 index 000000000000..e8c9899799cf --- /dev/null +++ b/public/img/svg/octicon-rel-file-path.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-sponsor-tiers.svg b/public/img/svg/octicon-sponsor-tiers.svg new file mode 100644 index 000000000000..dc200285f722 --- /dev/null +++ b/public/img/svg/octicon-sponsor-tiers.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-unlink.svg b/public/img/svg/octicon-unlink.svg new file mode 100644 index 000000000000..7d72ef3a267e --- /dev/null +++ b/public/img/svg/octicon-unlink.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-unread.svg b/public/img/svg/octicon-unread.svg new file mode 100644 index 000000000000..bb3c1fc6ed72 --- /dev/null +++ b/public/img/svg/octicon-unread.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index b523725c4895..78eb5e860be2 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/packages/composer" @@ -58,7 +59,13 @@ func CommonRoutes(ctx gocontext.Context) *web.Route { authGroup := auth.NewGroup(authMethods...) r.Use(func(ctx *context.Context) { - ctx.Doer = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + var err error + ctx.Doer, err = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + if err != nil { + log.Error("Verify: %v", err) + ctx.Error(http.StatusUnauthorized, "authGroup.Verify") + return + } ctx.IsSigned = ctx.Doer != nil }) @@ -321,7 +328,13 @@ func ContainerRoutes(ctx gocontext.Context) *web.Route { authGroup := auth.NewGroup(authMethods...) r.Use(func(ctx *context.Context) { - ctx.Doer = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + var err error + ctx.Doer, err = authGroup.Verify(ctx.Req, ctx.Resp, ctx, ctx.Session) + if err != nil { + log.Error("Failed to verify user: %v", err) + ctx.Error(http.StatusUnauthorized, "Verify") + return + } ctx.IsSigned = ctx.Doer != nil }) diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index c6e0593b42f5..58571fff14d0 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -14,12 +14,12 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" packages_module "code.gitea.io/gitea/modules/packages" composer_module "code.gitea.io/gitea/modules/packages/composer" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/packages/helper" + "code.gitea.io/gitea/services/convert" packages_service "code.gitea.io/gitea/services/packages" "github.com/hashicorp/go-version" diff --git a/routers/api/packages/conan/auth.go b/routers/api/packages/conan/auth.go index fe33e2c74043..ca02d61e7615 100644 --- a/routers/api/packages/conan/auth.go +++ b/routers/api/packages/conan/auth.go @@ -19,22 +19,22 @@ func (a *Auth) Name() string { } // Verify extracts the user from the Bearer token -func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) *user_model.User { +func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) { uid, err := packages.ParseAuthorizationToken(req) if err != nil { log.Trace("ParseAuthorizationToken: %v", err) - return nil + return nil, err } if uid == 0 { - return nil + return nil, nil } - u, err := user_model.GetUserByID(uid) + u, err := user_model.GetUserByID(req.Context(), uid) if err != nil { log.Error("GetUserByID: %v", err) - return nil + return nil, err } - return u + return u, nil } diff --git a/routers/api/packages/container/auth.go b/routers/api/packages/container/auth.go index 948001dcad79..33f439ec3e58 100644 --- a/routers/api/packages/container/auth.go +++ b/routers/api/packages/container/auth.go @@ -20,25 +20,25 @@ func (a *Auth) Name() string { // Verify extracts the user from the Bearer token // If it's an anonymous session a ghost user is returned -func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) *user_model.User { +func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) { uid, err := packages.ParseAuthorizationToken(req) if err != nil { log.Trace("ParseAuthorizationToken: %v", err) - return nil + return nil, err } if uid == 0 { - return nil + return nil, nil } if uid == -1 { - return user_model.NewGhostUser() + return user_model.NewGhostUser(), nil } - u, err := user_model.GetUserByID(uid) + u, err := user_model.GetUserByID(req.Context(), uid) if err != nil { log.Error("GetUserByID: %v", err) - return nil + return nil, err } - return u + return u, nil } diff --git a/routers/api/packages/maven/maven.go b/routers/api/packages/maven/maven.go index 0ca3fa179394..d0c9983cbf1f 100644 --- a/routers/api/packages/maven/maven.go +++ b/routers/api/packages/maven/maven.go @@ -8,9 +8,9 @@ import ( "crypto/sha1" "crypto/sha256" "crypto/sha512" + "encoding/hex" "encoding/xml" "errors" - "fmt" "io" "net/http" "path/filepath" @@ -128,7 +128,7 @@ func serveMavenMetadata(ctx *context.Context, params parameters) { tmp := sha512.Sum512(xmlMetadataWithHeader) hash = tmp[:] } - ctx.PlainText(http.StatusOK, fmt.Sprintf("%x", hash)) + ctx.PlainText(http.StatusOK, hex.EncodeToString(hash)) return } diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 4306d5ba363c..1a09cb6f3663 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -405,8 +405,9 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo func PackageSearch(ctx *context.Context) { pvs, total, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{ - OwnerID: ctx.Package.Owner.ID, - Type: packages_model.TypeNpm, + OwnerID: ctx.Package.Owner.ID, + Type: packages_model.TypeNpm, + IsInternal: util.OptionalBoolFalse, Name: packages_model.SearchValue{ ExactMatch: false, Value: ctx.FormTrim("text"), diff --git a/routers/api/packages/nuget/api_v2.go b/routers/api/packages/nuget/api_v2.go index c545d0fc4e94..7d0ac64a8adc 100644 --- a/routers/api/packages/nuget/api_v2.go +++ b/routers/api/packages/nuget/api_v2.go @@ -344,7 +344,7 @@ func createEntry(l *linkBuilder, pd *packages_model.PackageDescriptor, withNames Content: content, Properties: &FeedEntryProperties{ Version: pd.Version.Version, - NormalizedVersion: normalizeVersion(pd.SemVer), + NormalizedVersion: pd.Version.Version, Authors: metadata.Authors, Dependencies: buildDependencyString(metadata), Description: metadata.Description, diff --git a/routers/api/packages/nuget/api_v3.go b/routers/api/packages/nuget/api_v3.go index b5900b6c0b77..28626f9294c3 100644 --- a/routers/api/packages/nuget/api_v3.go +++ b/routers/api/packages/nuget/api_v3.go @@ -4,15 +4,11 @@ package nuget import ( - "bytes" - "fmt" "sort" "time" packages_model "code.gitea.io/gitea/models/packages" nuget_module "code.gitea.io/gitea/modules/packages/nuget" - - "github.com/hashicorp/go-version" ) // https://docs.microsoft.com/en-us/nuget/api/service-index#resources @@ -95,8 +91,8 @@ func createRegistrationIndexResponse(l *linkBuilder, pds []*packages_model.Packa { RegistrationPageURL: l.GetRegistrationIndexURL(pds[0].Package.Name), Count: len(pds), - Lower: normalizeVersion(pds[0].SemVer), - Upper: normalizeVersion(pds[len(pds)-1].SemVer), + Lower: pds[0].Version.Version, + Upper: pds[len(pds)-1].Version.Version, Items: items, }, }, @@ -173,7 +169,7 @@ type PackageVersionsResponse struct { func createPackageVersionsResponse(pds []*packages_model.PackageDescriptor) *PackageVersionsResponse { versions := make([]string, 0, len(pds)) for _, pd := range pds { - versions = append(versions, normalizeVersion(pd.SemVer)) + versions = append(versions, pd.Version.Version) } return &PackageVersionsResponse{ @@ -248,15 +244,3 @@ func createSearchResult(l *linkBuilder, pds []*packages_model.PackageDescriptor) RegistrationIndexURL: l.GetRegistrationIndexURL(latest.Package.Name), } } - -// normalizeVersion removes the metadata -func normalizeVersion(v *version.Version) string { - var buf bytes.Buffer - segments := v.Segments64() - fmt.Fprintf(&buf, "%d.%d.%d", segments[0], segments[1], segments[2]) - pre := v.Prerelease() - if pre != "" { - fmt.Fprintf(&buf, "-%s", pre) - } - return buf.String() -} diff --git a/routers/api/packages/nuget/auth.go b/routers/api/packages/nuget/auth.go index 2be102a38baf..54b33d89c0a8 100644 --- a/routers/api/packages/nuget/auth.go +++ b/routers/api/packages/nuget/auth.go @@ -20,19 +20,20 @@ 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 { +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")) if err != nil { if !(auth_model.IsErrAccessTokenNotExist(err) || auth_model.IsErrAccessTokenEmpty(err)) { log.Error("GetAccessTokenBySHA: %v", err) + return nil, err } - return nil + return nil, nil } - u, err := user_model.GetUserByID(token.UID) + u, err := user_model.GetUserByID(req.Context(), token.UID) if err != nil { log.Error("GetUserByID: %v", err) - return nil + return nil, err } token.UpdatedUnix = timeutil.TimeStampNow() @@ -40,5 +41,5 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS log.Error("UpdateAccessToken: %v", err) } - return u + return u, nil } diff --git a/routers/api/packages/pypi/pypi.go b/routers/api/packages/pypi/pypi.go index 826f58095e70..609c63dc64f5 100644 --- a/routers/api/packages/pypi/pypi.go +++ b/routers/api/packages/pypi/pypi.go @@ -4,7 +4,7 @@ package pypi import ( - "fmt" + "encoding/hex" "io" "net/http" "regexp" @@ -21,8 +21,10 @@ import ( ) // https://peps.python.org/pep-0426/#name -var normalizer = strings.NewReplacer(".", "-", "_", "-") -var nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`) +var ( + normalizer = strings.NewReplacer(".", "-", "_", "-") + nameMatcher = regexp.MustCompile(`\A(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\.\-_]*[a-zA-Z0-9])\z`) +) // https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions var versionMatcher = regexp.MustCompile(`\Av?` + @@ -118,7 +120,7 @@ func UploadPackageFile(ctx *context.Context) { _, _, hashSHA256, _ := buf.Sums() - if !strings.EqualFold(ctx.Req.FormValue("sha256_digest"), fmt.Sprintf("%x", hashSHA256)) { + if !strings.EqualFold(ctx.Req.FormValue("sha256_digest"), hex.EncodeToString(hashSHA256)) { apiError(ctx, http.StatusBadRequest, "hash mismatch") return } diff --git a/routers/api/v1/admin/org.go b/routers/api/v1/admin/org.go index 9d0725e3e85d..ff6624418442 100644 --- a/routers/api/v1/admin/org.go +++ b/routers/api/v1/admin/org.go @@ -11,10 +11,10 @@ import ( "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // CreateOrg api for create organization diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 183ade8a0a5e..6b48ce4a9d4d 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -16,7 +16,6 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/setting" @@ -26,6 +25,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/mailer" user_service "code.gitea.io/gitea/services/user" ) diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 8614d9351a5d..8115281c697c 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -67,7 +67,6 @@ import ( gocontext "context" "fmt" "net/http" - "reflect" "strings" "code.gitea.io/gitea/models/organization" @@ -231,13 +230,10 @@ func reqExploreSignIn() func(ctx *context.APIContext) { } } -func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) { +func reqBasicAuth() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - if ctx.IsSigned && setting.Service.EnableReverseProxyAuth && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName { - return - } if !ctx.Context.IsBasicAuth { - ctx.Error(http.StatusUnauthorized, "reqBasicOrRevProxyAuth", "auth required") + ctx.Error(http.StatusUnauthorized, "reqBasicAuth", "auth required") return } ctx.CheckForOTP() @@ -567,14 +563,17 @@ func mustNotBeArchived(ctx *context.APIContext) { } } -// bind binding an obj to a func(ctx *context.APIContext) -func bind(obj interface{}) http.HandlerFunc { - tp := reflect.TypeOf(obj) - for tp.Kind() == reflect.Ptr { - tp = tp.Elem() +func mustEnableAttachments(ctx *context.APIContext) { + if !setting.Attachment.Enabled { + ctx.NotFound() + return } +} + +// bind binding an obj to a func(ctx *context.APIContext) +func bind[T any](obj T) http.HandlerFunc { return web.Wrap(func(ctx *context.APIContext) { - theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly + theObj := new(T) // create a new form obj for every request but not use obj directly errs := binding.Bind(ctx.Req, theObj) if len(errs) > 0 { ctx.Error(http.StatusUnprocessableEntity, "validationError", fmt.Sprintf("%s: %s", errs[0].FieldNames, errs[0].Error())) @@ -596,9 +595,6 @@ func buildAuthGroup() *auth.Group { &auth.HTTPSign{}, &auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API ) - if setting.Service.EnableReverseProxyAuth { - group.Add(&auth.ReverseProxy{}) - } specialAdd(group) return group @@ -688,7 +684,7 @@ func Routes(ctx gocontext.Context) *web.Route { m.Combo("").Get(user.ListAccessTokens). Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken) m.Combo("/{id}").Delete(user.DeleteAccessToken) - }, reqBasicOrRevProxyAuth()) + }, reqBasicAuth()) }, context_service.UserAssignmentAPI()) }) @@ -896,6 +892,15 @@ func Routes(ctx gocontext.Context) *web.Route { Get(repo.GetIssueCommentReactions). Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueCommentReaction). Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueCommentReaction) + m.Group("/assets", func() { + m.Combo(""). + Get(repo.ListIssueCommentAttachments). + Post(reqToken(), mustNotBeArchived, repo.CreateIssueCommentAttachment) + m.Combo("/{asset}"). + Get(repo.GetIssueCommentAttachment). + Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueCommentAttachment). + Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueCommentAttachment) + }, mustEnableAttachments) }) }) m.Group("/{index}", func() { @@ -939,6 +944,15 @@ func Routes(ctx gocontext.Context) *web.Route { Get(repo.GetIssueReactions). Post(reqToken(), bind(api.EditReactionOption{}), repo.PostIssueReaction). Delete(reqToken(), bind(api.EditReactionOption{}), repo.DeleteIssueReaction) + m.Group("/assets", func() { + m.Combo(""). + Get(repo.ListIssueAttachments). + Post(reqToken(), mustNotBeArchived, repo.CreateIssueAttachment) + m.Combo("/{asset}"). + Get(repo.GetIssueAttachment). + Patch(reqToken(), mustNotBeArchived, bind(api.EditAttachmentOptions{}), repo.EditIssueAttachment). + Delete(reqToken(), mustNotBeArchived, repo.DeleteIssueAttachment) + }, mustEnableAttachments) }) }, mustEnableIssuesOrPulls) m.Group("/labels", func() { diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index a2e72cb48de0..bd3b86a6f152 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -10,9 +10,9 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" ) func statusStringToNotificationStatus(status string) activities_model.NotificationStatus { diff --git a/routers/api/v1/notify/threads.go b/routers/api/v1/notify/threads.go index 47d0e4972143..6a1bce4de41a 100644 --- a/routers/api/v1/notify/threads.go +++ b/routers/api/v1/notify/threads.go @@ -11,7 +11,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/services/convert" ) // GetThread get notification by ID diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index 725eeff017fc..2261610c0923 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -9,8 +9,8 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" ) // ListNotifications list users's notification threads diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go index 2e9d7c656a76..ef08a08be0e4 100644 --- a/routers/api/v1/org/hook.go +++ b/routers/api/v1/org/hook.go @@ -8,10 +8,10 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListHooks list an organziation's webhooks diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go index c95a6be3d20a..5d0455cdd4f4 100644 --- a/routers/api/v1/org/label.go +++ b/routers/api/v1/org/label.go @@ -11,10 +11,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListLabels list all the labels of an organization diff --git a/routers/api/v1/org/member.go b/routers/api/v1/org/member.go index fe071439588e..33c994497803 100644 --- a/routers/api/v1/org/member.go +++ b/routers/api/v1/org/member.go @@ -10,11 +10,11 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // listMembers list an organization's members diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index cf985d44fbb0..a1b071d4887a 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -12,11 +12,11 @@ import ( "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/org" ) diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index f233494fa528..8f87e8276485 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -15,12 +15,12 @@ import ( repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" org_service "code.gitea.io/gitea/services/org" ) @@ -546,7 +546,7 @@ func GetTeamRepos(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) return } - repos[i] = convert.ToRepo(repo, access) + repos[i] = convert.ToRepo(ctx, repo, access) } ctx.SetTotalCountHeader(int64(team.NumRepos)) ctx.JSON(http.StatusOK, repos) @@ -598,7 +598,7 @@ func GetTeamRepo(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToRepo(repo, access)) + ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, access)) } // getRepositoryByParams get repository by a team's organization ID and repo name diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index 433a79939cc7..6f9083ba327b 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -8,10 +8,10 @@ import ( "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" packages_service "code.gitea.io/gitea/services/packages" ) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index f5b1eb1c42c2..46fcc2fcd366 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -14,11 +14,11 @@ import ( "code.gitea.io/gitea/models/organization" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" pull_service "code.gitea.io/gitea/services/pull" repo_service "code.gitea.io/gitea/services/repository" ) @@ -251,42 +251,50 @@ func ListBranches(ctx *context.APIContext) { // "200": // "$ref": "#/responses/BranchList" + var totalNumOfBranches int + var apiBranches []*api.Branch + listOptions := utils.GetListOptions(ctx) - skip, _ := listOptions.GetStartEnd() - branches, totalNumOfBranches, err := ctx.Repo.GitRepo.GetBranches(skip, listOptions.PageSize) - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetBranches", err) - return - } - apiBranches := make([]*api.Branch, 0, len(branches)) - for i := range branches { - c, err := branches[i].GetCommit() + if !ctx.Repo.Repository.IsEmpty && ctx.Repo.GitRepo != nil { + skip, _ := listOptions.GetStartEnd() + branches, total, err := ctx.Repo.GitRepo.GetBranches(skip, listOptions.PageSize) if err != nil { - // Skip if this branch doesn't exist anymore. - if git.IsErrNotExist(err) { - totalNumOfBranches-- - continue - } - ctx.Error(http.StatusInternalServerError, "GetCommit", err) + ctx.Error(http.StatusInternalServerError, "GetBranches", err) return } - branchProtection, err := git_model.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branches[i].Name) - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) - return - } - apiBranch, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin()) - if err != nil { - ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) - return + + apiBranches = make([]*api.Branch, 0, len(branches)) + for i := range branches { + c, err := branches[i].GetCommit() + if err != nil { + // Skip if this branch doesn't exist anymore. + if git.IsErrNotExist(err) { + total-- + continue + } + ctx.Error(http.StatusInternalServerError, "GetCommit", err) + return + } + branchProtection, err := git_model.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branches[i].Name) + if err != nil { + ctx.Error(http.StatusInternalServerError, "GetProtectedBranchBy", err) + return + } + apiBranch, err := convert.ToBranch(ctx.Repo.Repository, branches[i], c, branchProtection, ctx.Doer, ctx.Repo.IsAdmin()) + if err != nil { + ctx.Error(http.StatusInternalServerError, "convert.ToBranch", err) + return + } + apiBranches = append(apiBranches, apiBranch) } - apiBranches = append(apiBranches, apiBranch) + + totalNumOfBranches = total } ctx.SetLinkHeader(totalNumOfBranches, listOptions.PageSize) ctx.SetTotalCountHeader(int64(totalNumOfBranches)) - ctx.JSON(http.StatusOK, &apiBranches) + ctx.JSON(http.StatusOK, apiBranches) } // GetBranchProtection gets a branch protection diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 383193daa71b..293778420bc2 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -14,11 +14,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" repo_module "code.gitea.io/gitea/modules/repository" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListCollaborators list a repository's collaborators @@ -174,13 +174,13 @@ func AddCollaborator(ctx *context.APIContext) { return } - if err := repo_module.AddCollaborator(ctx.Repo.Repository, collaborator); err != nil { + if err := repo_module.AddCollaborator(ctx, ctx.Repo.Repository, collaborator); err != nil { ctx.Error(http.StatusInternalServerError, "AddCollaborator", err) return } if form.Permission != nil { - if err := repo_model.ChangeCollaborationAccessMode(ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil { + if err := repo_model.ChangeCollaborationAccessMode(ctx, ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil { ctx.Error(http.StatusInternalServerError, "ChangeCollaborationAccessMode", err) return } diff --git a/routers/api/v1/repo/commits.go b/routers/api/v1/repo/commits.go index 682044407dfe..68a92ca2a840 100644 --- a/routers/api/v1/repo/commits.go +++ b/routers/api/v1/repo/commits.go @@ -12,11 +12,11 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // GetSingleCommit get a commit via sha diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index e2cb4400f592..e4c7eb70414a 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -14,10 +14,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" repo_service "code.gitea.io/gitea/services/repository" ) @@ -63,7 +63,7 @@ func ListForks(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return } - apiForks[i] = convert.ToRepo(fork, access) + apiForks[i] = convert.ToRepo(ctx, fork, access) } ctx.SetTotalCountHeader(int64(ctx.Repo.Repository.NumForks)) @@ -141,7 +141,7 @@ func CreateFork(ctx *context.APIContext) { Description: repo.Description, }) if err != nil { - if repo_model.IsErrRepoAlreadyExist(err) { + if repo_model.IsErrReachLimitOfRepo(err) || repo_model.IsErrRepoAlreadyExist(err) { ctx.Error(http.StatusConflict, "ForkRepository", err) } else { ctx.Error(http.StatusInternalServerError, "ForkRepository", err) @@ -150,5 +150,5 @@ func CreateFork(ctx *context.APIContext) { } // TODO change back to 201 - ctx.JSON(http.StatusAccepted, convert.ToRepo(fork, perm.AccessModeOwner)) + ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, fork, perm.AccessModeOwner)) } diff --git a/routers/api/v1/repo/git_hook.go b/routers/api/v1/repo/git_hook.go index 963cbc719f42..40bd35542888 100644 --- a/routers/api/v1/repo/git_hook.go +++ b/routers/api/v1/repo/git_hook.go @@ -7,10 +7,10 @@ import ( "net/http" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" ) // ListGitHooks list all Git hooks of a repository diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 9b84fb2b301b..757ae7247bf7 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -10,12 +10,12 @@ import ( "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" webhook_service "code.gitea.io/gitea/services/webhook" ) @@ -184,7 +184,7 @@ func TestHook(ctx *context.APIContext) { Commits: []*api.PayloadCommit{commit}, TotalCommits: 1, HeadCommit: commit, - Repo: convert.ToRepo(ctx.Repo.Repository, perm.AccessModeNone), + Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone), Pusher: convert.ToUserWithAccessMode(ctx.Doer, perm.AccessModeNone), Sender: convert.ToUserWithAccessMode(ctx.Doer, perm.AccessModeNone), }); err != nil { diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index c539a362388f..fecb601dd533 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -19,7 +19,6 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" @@ -28,6 +27,7 @@ import ( "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) @@ -623,7 +623,7 @@ func CreateIssue(ctx *context.APIContext) { // Check if the passed assignees is assignable for _, aID := range assigneeIDs { - assignee, err := user_model.GetUserByID(aID) + assignee, err := user_model.GetUserByID(ctx, aID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserByID", err) return diff --git a/routers/api/v1/repo/issue_attachment.go b/routers/api/v1/repo/issue_attachment.go new file mode 100644 index 000000000000..8cbd2e11b699 --- /dev/null +++ b/routers/api/v1/repo/issue_attachment.go @@ -0,0 +1,372 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/convert" + issue_service "code.gitea.io/gitea/services/issue" +) + +// GetIssueAttachment gets a single attachment of the issue +func GetIssueAttachment(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueGetIssueAttachment + // --- + // summary: Get an issue attachment + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue + // type: integer + // format: int64 + // required: true + // - name: attachment_id + // in: path + // description: id of the attachment to get + // type: integer + // format: int64 + // required: true + // responses: + // "200": + // "$ref": "#/responses/Attachment" + // "404": + // "$ref": "#/responses/error" + + issue := getIssueFromContext(ctx) + if issue == nil { + return + } + + attach := getIssueAttachmentSafeRead(ctx, issue) + if attach == nil { + return + } + + ctx.JSON(http.StatusOK, convert.ToAttachment(attach)) +} + +// ListIssueAttachments lists all attachments of the issue +func ListIssueAttachments(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/issues/{index}/assets issue issueListIssueAttachments + // --- + // summary: List issue's attachments + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue + // type: integer + // format: int64 + // required: true + // responses: + // "200": + // "$ref": "#/responses/AttachmentList" + // "404": + // "$ref": "#/responses/error" + + issue := getIssueFromContext(ctx) + if issue == nil { + return + } + + if err := issue.LoadAttributes(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) + return + } + + ctx.JSON(http.StatusOK, convert.ToAPIIssue(ctx, issue).Attachments) +} + +// CreateIssueAttachment creates an attachment and saves the given file +func CreateIssueAttachment(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/issues/{index}/assets issue issueCreateIssueAttachment + // --- + // summary: Create an issue attachment + // produces: + // - application/json + // consumes: + // - multipart/form-data + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue + // type: integer + // format: int64 + // required: true + // - name: name + // in: query + // description: name of the attachment + // type: string + // required: false + // - name: attachment + // in: formData + // description: attachment to upload + // type: file + // required: true + // responses: + // "201": + // "$ref": "#/responses/Attachment" + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/error" + + issue := getIssueFromContext(ctx) + if issue == nil { + return + } + + if !canUserWriteIssueAttachment(ctx, issue) { + return + } + + // Get uploaded file from request + file, header, err := ctx.Req.FormFile("attachment") + if err != nil { + ctx.Error(http.StatusInternalServerError, "FormFile", err) + return + } + defer file.Close() + + filename := header.Filename + if query := ctx.FormString("name"); query != "" { + filename = query + } + + attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{ + Name: filename, + UploaderID: ctx.Doer.ID, + RepoID: ctx.Repo.Repository.ID, + IssueID: issue.ID, + }) + if err != nil { + ctx.Error(http.StatusInternalServerError, "UploadAttachment", err) + return + } + + issue.Attachments = append(issue.Attachments, attachment) + + if err := issue_service.ChangeContent(issue, ctx.Doer, issue.Content); err != nil { + ctx.Error(http.StatusInternalServerError, "ChangeContent", err) + return + } + + ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment)) +} + +// EditIssueAttachment updates the given attachment +func EditIssueAttachment(ctx *context.APIContext) { + // swagger:operation PATCH /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueEditIssueAttachment + // --- + // summary: Edit an issue attachment + // produces: + // - application/json + // consumes: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue + // type: integer + // format: int64 + // required: true + // - name: attachment_id + // in: path + // description: id of the attachment to edit + // type: integer + // format: int64 + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/EditAttachmentOptions" + // responses: + // "201": + // "$ref": "#/responses/Attachment" + // "404": + // "$ref": "#/responses/error" + + attachment := getIssueAttachmentSafeWrite(ctx) + if attachment == nil { + return + } + + // do changes to attachment. only meaningful change is name. + form := web.GetForm(ctx).(*api.EditAttachmentOptions) + if form.Name != "" { + attachment.Name = form.Name + } + + if err := repo_model.UpdateAttachment(ctx, attachment); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateAttachment", err) + } + + ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment)) +} + +// DeleteIssueAttachment delete a given attachment +func DeleteIssueAttachment(ctx *context.APIContext) { + // swagger:operation DELETE /repos/{owner}/{repo}/issues/{index}/assets/{attachment_id} issue issueDeleteIssueAttachment + // --- + // summary: Delete an issue attachment + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: index + // in: path + // description: index of the issue + // type: integer + // format: int64 + // required: true + // - name: attachment_id + // in: path + // description: id of the attachment to delete + // type: integer + // format: int64 + // required: true + // responses: + // "204": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/error" + + attachment := getIssueAttachmentSafeWrite(ctx) + if attachment == nil { + return + } + + if err := repo_model.DeleteAttachment(attachment, true); err != nil { + ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err) + return + } + + ctx.Status(http.StatusNoContent) +} + +func getIssueFromContext(ctx *context.APIContext) *issues_model.Issue { + issue, err := issues_model.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64("index")) + if err != nil { + ctx.NotFoundOrServerError("GetIssueByIndex", issues_model.IsErrIssueNotExist, err) + return nil + } + + issue.Repo = ctx.Repo.Repository + + return issue +} + +func getIssueAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment { + issue := getIssueFromContext(ctx) + if issue == nil { + return nil + } + + if !canUserWriteIssueAttachment(ctx, issue) { + return nil + } + + return getIssueAttachmentSafeRead(ctx, issue) +} + +func getIssueAttachmentSafeRead(ctx *context.APIContext, issue *issues_model.Issue) *repo_model.Attachment { + attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset")) + if err != nil { + ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err) + return nil + } + if !attachmentBelongsToRepoOrIssue(ctx, attachment, issue) { + return nil + } + return attachment +} + +func canUserWriteIssueAttachment(ctx *context.APIContext, issue *issues_model.Issue) bool { + canEditIssue := ctx.IsSigned && (ctx.Doer.ID == issue.PosterID || ctx.IsUserRepoAdmin() || ctx.IsUserSiteAdmin()) && ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) + if !canEditIssue { + ctx.Error(http.StatusForbidden, "", "user should have permission to write issue") + return false + } + + return true +} + +func attachmentBelongsToRepoOrIssue(ctx *context.APIContext, attachment *repo_model.Attachment, issue *issues_model.Issue) bool { + if attachment.RepoID != ctx.Repo.Repository.ID { + log.Debug("Requested attachment[%d] does not belong to repo[%-v].", attachment.ID, ctx.Repo.Repository) + ctx.NotFound("no such attachment in repo") + return false + } + if attachment.IssueID == 0 { + log.Debug("Requested attachment[%d] is not in an issue.", attachment.ID) + ctx.NotFound("no such attachment in issue") + return false + } else if issue != nil && attachment.IssueID != issue.ID { + log.Debug("Requested attachment[%d] does not belong to issue[%d, #%d].", attachment.ID, issue.ID, issue.Index) + ctx.NotFound("no such attachment in issue") + return false + } + return true +} diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index 7f6f24605d03..40c92998d19c 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -14,11 +14,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" - comment_service "code.gitea.io/gitea/services/comments" + "code.gitea.io/gitea/services/convert" + issue_service "code.gitea.io/gitea/services/issue" ) // ListIssueComments list all the comments of an issue @@ -95,6 +95,11 @@ func ListIssueComments(ctx *context.APIContext) { return } + if err := issues_model.CommentList(comments).LoadAttachments(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttachments", err) + return + } + apiComments := make([]*api.Comment, len(comments)) for i, comment := range comments { comment.Issue = issue @@ -199,7 +204,7 @@ func isXRefCommentAccessible(ctx stdCtx.Context, user *user_model.User, c *issue if issues_model.CommentTypeIsRef(c.Type) && c.RefRepoID != issueRepoID && c.RefRepoID != 0 { var err error // Set RefRepo for description in template - c.RefRepo, err = repo_model.GetRepositoryByIDCtx(ctx, c.RefRepoID) + c.RefRepo, err = repo_model.GetRepositoryByID(ctx, c.RefRepoID) if err != nil { return false } @@ -294,6 +299,10 @@ func ListRepoIssueComments(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "LoadPosters", err) return } + if err := issues_model.CommentList(comments).LoadAttachments(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttachments", err) + return + } if _, err := issues_model.CommentList(comments).Issues().LoadRepositories(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "LoadRepositories", err) return @@ -353,7 +362,7 @@ func CreateIssueComment(ctx *context.APIContext) { return } - comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil) + comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Body, nil) if err != nil { ctx.Error(http.StatusInternalServerError, "CreateIssueComment", err) return @@ -547,7 +556,7 @@ func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) oldContent := comment.Content comment.Content = form.Body - if err := comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { + if err := issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateComment", err) return } @@ -646,7 +655,7 @@ func deleteIssueComment(ctx *context.APIContext) { return } - if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { + if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteCommentByID", err) return } diff --git a/routers/api/v1/repo/issue_comment_attachment.go b/routers/api/v1/repo/issue_comment_attachment.go new file mode 100644 index 000000000000..4c8452380f03 --- /dev/null +++ b/routers/api/v1/repo/issue_comment_attachment.go @@ -0,0 +1,383 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "net/http" + + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/convert" + issue_service "code.gitea.io/gitea/services/issue" +) + +// GetIssueCommentAttachment gets a single attachment of the comment +func GetIssueCommentAttachment(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueGetIssueCommentAttachment + // --- + // summary: Get a comment attachment + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: id + // in: path + // description: id of the comment + // type: integer + // format: int64 + // required: true + // - name: attachment_id + // in: path + // description: id of the attachment to get + // type: integer + // format: int64 + // required: true + // responses: + // "200": + // "$ref": "#/responses/Attachment" + // "404": + // "$ref": "#/responses/error" + + comment := getIssueCommentSafe(ctx) + if comment == nil { + return + } + attachment := getIssueCommentAttachmentSafeRead(ctx, comment) + if attachment == nil { + return + } + if attachment.CommentID != comment.ID { + log.Debug("User requested attachment[%d] is not in comment[%d].", attachment.ID, comment.ID) + ctx.NotFound("attachment not in comment") + return + } + + ctx.JSON(http.StatusOK, convert.ToAttachment(attachment)) +} + +// ListIssueCommentAttachments lists all attachments of the comment +func ListIssueCommentAttachments(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/issues/comments/{id}/assets issue issueListIssueCommentAttachments + // --- + // summary: List comment's attachments + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: id + // in: path + // description: id of the comment + // type: integer + // format: int64 + // required: true + // responses: + // "200": + // "$ref": "#/responses/AttachmentList" + // "404": + // "$ref": "#/responses/error" + comment := getIssueCommentSafe(ctx) + if comment == nil { + return + } + + if err := comment.LoadAttachments(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttachments", err) + return + } + + ctx.JSON(http.StatusOK, convert.ToAttachments(comment.Attachments)) +} + +// CreateIssueCommentAttachment creates an attachment and saves the given file +func CreateIssueCommentAttachment(ctx *context.APIContext) { + // swagger:operation POST /repos/{owner}/{repo}/issues/comments/{id}/assets issue issueCreateIssueCommentAttachment + // --- + // summary: Create a comment attachment + // produces: + // - application/json + // consumes: + // - multipart/form-data + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: id + // in: path + // description: id of the comment + // type: integer + // format: int64 + // required: true + // - name: name + // in: query + // description: name of the attachment + // type: string + // required: false + // - name: attachment + // in: formData + // description: attachment to upload + // type: file + // required: true + // responses: + // "201": + // "$ref": "#/responses/Attachment" + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/error" + + // Check if comment exists and load comment + comment := getIssueCommentSafe(ctx) + if comment == nil { + return + } + + if !canUserWriteIssueCommentAttachment(ctx, comment) { + return + } + + // Get uploaded file from request + file, header, err := ctx.Req.FormFile("attachment") + if err != nil { + ctx.Error(http.StatusInternalServerError, "FormFile", err) + return + } + defer file.Close() + + filename := header.Filename + if query := ctx.FormString("name"); query != "" { + filename = query + } + + attachment, err := attachment.UploadAttachment(file, setting.Attachment.AllowedTypes, &repo_model.Attachment{ + Name: filename, + UploaderID: ctx.Doer.ID, + RepoID: ctx.Repo.Repository.ID, + IssueID: comment.IssueID, + CommentID: comment.ID, + }) + if err != nil { + ctx.Error(http.StatusInternalServerError, "UploadAttachment", err) + return + } + if err := comment.LoadAttachments(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttachments", err) + return + } + + if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, comment.Content); err != nil { + ctx.ServerError("UpdateComment", err) + return + } + + ctx.JSON(http.StatusCreated, convert.ToAttachment(attachment)) +} + +// EditIssueCommentAttachment updates the given attachment +func EditIssueCommentAttachment(ctx *context.APIContext) { + // swagger:operation PATCH /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueEditIssueCommentAttachment + // --- + // summary: Edit a comment attachment + // produces: + // - application/json + // consumes: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: id + // in: path + // description: id of the comment + // type: integer + // format: int64 + // required: true + // - name: attachment_id + // in: path + // description: id of the attachment to edit + // type: integer + // format: int64 + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/EditAttachmentOptions" + // responses: + // "201": + // "$ref": "#/responses/Attachment" + // "404": + // "$ref": "#/responses/error" + + attach := getIssueCommentAttachmentSafeWrite(ctx) + if attach == nil { + return + } + + form := web.GetForm(ctx).(*api.EditAttachmentOptions) + if form.Name != "" { + attach.Name = form.Name + } + + if err := repo_model.UpdateAttachment(ctx, attach); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach) + } + ctx.JSON(http.StatusCreated, convert.ToAttachment(attach)) +} + +// DeleteIssueCommentAttachment delete a given attachment +func DeleteIssueCommentAttachment(ctx *context.APIContext) { + // swagger:operation DELETE /repos/{owner}/{repo}/issues/comments/{id}/assets/{attachment_id} issue issueDeleteIssueCommentAttachment + // --- + // summary: Delete a comment attachment + // produces: + // - application/json + // parameters: + // - name: owner + // in: path + // description: owner of the repo + // type: string + // required: true + // - name: repo + // in: path + // description: name of the repo + // type: string + // required: true + // - name: id + // in: path + // description: id of the comment + // type: integer + // format: int64 + // required: true + // - name: attachment_id + // in: path + // description: id of the attachment to delete + // type: integer + // format: int64 + // required: true + // responses: + // "204": + // "$ref": "#/responses/empty" + // "404": + // "$ref": "#/responses/error" + + attach := getIssueCommentAttachmentSafeWrite(ctx) + if attach == nil { + return + } + + if err := repo_model.DeleteAttachment(attach, true); err != nil { + ctx.Error(http.StatusInternalServerError, "DeleteAttachment", err) + return + } + ctx.Status(http.StatusNoContent) +} + +func getIssueCommentSafe(ctx *context.APIContext) *issues_model.Comment { + comment, err := issues_model.GetCommentByID(ctx, ctx.ParamsInt64("id")) + if err != nil { + ctx.NotFoundOrServerError("GetCommentByID", issues_model.IsErrCommentNotExist, err) + return nil + } + if err := comment.LoadIssue(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err) + return nil + } + if comment.Issue == nil || comment.Issue.RepoID != ctx.Repo.Repository.ID { + ctx.Error(http.StatusNotFound, "", "no matching issue comment found") + return nil + } + + comment.Issue.Repo = ctx.Repo.Repository + + return comment +} + +func getIssueCommentAttachmentSafeWrite(ctx *context.APIContext) *repo_model.Attachment { + comment := getIssueCommentSafe(ctx) + if comment == nil { + return nil + } + if !canUserWriteIssueCommentAttachment(ctx, comment) { + return nil + } + return getIssueCommentAttachmentSafeRead(ctx, comment) +} + +func canUserWriteIssueCommentAttachment(ctx *context.APIContext, comment *issues_model.Comment) bool { + canEditComment := ctx.IsSigned && (ctx.Doer.ID == comment.PosterID || ctx.IsUserRepoAdmin() || ctx.IsUserSiteAdmin()) && ctx.Repo.CanWriteIssuesOrPulls(comment.Issue.IsPull) + if !canEditComment { + ctx.Error(http.StatusForbidden, "", "user should have permission to edit comment") + return false + } + + return true +} + +func getIssueCommentAttachmentSafeRead(ctx *context.APIContext, comment *issues_model.Comment) *repo_model.Attachment { + attachment, err := repo_model.GetAttachmentByID(ctx, ctx.ParamsInt64("asset")) + if err != nil { + ctx.NotFoundOrServerError("GetAttachmentByID", repo_model.IsErrAttachmentNotExist, err) + return nil + } + if !attachmentBelongsToRepoOrComment(ctx, attachment, comment) { + return nil + } + return attachment +} + +func attachmentBelongsToRepoOrComment(ctx *context.APIContext, attachment *repo_model.Attachment, comment *issues_model.Comment) bool { + if attachment.RepoID != ctx.Repo.Repository.ID { + log.Debug("Requested attachment[%d] does not belong to repo[%-v].", attachment.ID, ctx.Repo.Repository) + ctx.NotFound("no such attachment in repo") + return false + } + if attachment.IssueID == 0 || attachment.CommentID == 0 { + log.Debug("Requested attachment[%d] is not in a comment.", attachment.ID) + ctx.NotFound("no such attachment in comment") + return false + } + if comment != nil && attachment.CommentID != comment.ID { + log.Debug("Requested attachment[%d] does not belong to comment[%d].", attachment.ID, comment.ID) + ctx.NotFound("no such attachment in comment") + return false + } + return true +} diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index 04d70913c7a6..1f0d21141bcc 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -9,9 +9,9 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" ) diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index dcfe7967b58e..1b998a535424 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -9,10 +9,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // GetIssueCommentReactions list reactions of a comment from an issue diff --git a/routers/api/v1/repo/issue_stopwatch.go b/routers/api/v1/repo/issue_stopwatch.go index 110139cc36b6..9ab3c61deb4f 100644 --- a/routers/api/v1/repo/issue_stopwatch.go +++ b/routers/api/v1/repo/issue_stopwatch.go @@ -9,8 +9,8 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // StartIssueStopwatch creates a stopwatch for the given issue. diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index 32832d83f79a..6d22c82652ef 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -10,9 +10,9 @@ import ( issues_model "code.gitea.io/gitea/models/issues" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // AddIssueSubscription Subscribe user to issue diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 6786d23a9326..16bb8cb73d6c 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -13,10 +13,10 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListTrackedTimes list all the tracked times of an issue @@ -71,7 +71,7 @@ func ListTrackedTimes(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.NotFound("Timetracker is disabled") return } @@ -190,7 +190,7 @@ func AddTime(ctx *context.APIContext) { } if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) { - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } @@ -271,7 +271,7 @@ func ResetIssueTime(ctx *context.APIContext) { } if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) { - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"}) return } @@ -342,7 +342,7 @@ func DeleteTime(ctx *context.APIContext) { } if !ctx.Repo.CanUseTimetracker(issue, ctx.Doer) { - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.JSON(http.StatusBadRequest, struct{ Message string }{Message: "time tracking disabled"}) return } @@ -410,7 +410,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } @@ -498,7 +498,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - if !ctx.Repo.Repository.IsTimetrackerEnabled() { + if !ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } diff --git a/routers/api/v1/repo/key.go b/routers/api/v1/repo/key.go index cff68504694e..d496c4a73c11 100644 --- a/routers/api/v1/repo/key.go +++ b/routers/api/v1/repo/key.go @@ -5,6 +5,7 @@ package repo import ( + stdCtx "context" "fmt" "net/http" "net/url" @@ -14,25 +15,25 @@ import ( "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/convert" ) // appendPrivateInformation appends the owner and key type information to api.PublicKey -func appendPrivateInformation(apiKey *api.DeployKey, key *asymkey_model.DeployKey, repository *repo_model.Repository) (*api.DeployKey, error) { +func appendPrivateInformation(ctx stdCtx.Context, apiKey *api.DeployKey, key *asymkey_model.DeployKey, repository *repo_model.Repository) (*api.DeployKey, error) { apiKey.ReadOnly = key.Mode == perm.AccessModeRead if repository.ID == key.RepoID { - apiKey.Repository = convert.ToRepo(repository, key.Mode) + apiKey.Repository = convert.ToRepo(ctx, repository, key.Mode) } else { - repo, err := repo_model.GetRepositoryByID(key.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, key.RepoID) if err != nil { return apiKey, err } - apiKey.Repository = convert.ToRepo(repo, key.Mode) + apiKey.Repository = convert.ToRepo(ctx, repo, key.Mode) } return apiKey, nil } @@ -107,7 +108,7 @@ func ListDeployKeys(ctx *context.APIContext) { } apiKeys[i] = convert.ToDeployKey(apiLink, keys[i]) if ctx.Doer.IsAdmin || ((ctx.Repo.Repository.ID == keys[i].RepoID) && (ctx.Doer.ID == ctx.Repo.Owner.ID)) { - apiKeys[i], _ = appendPrivateInformation(apiKeys[i], keys[i], ctx.Repo.Repository) + apiKeys[i], _ = appendPrivateInformation(ctx, apiKeys[i], keys[i], ctx.Repo.Repository) } } @@ -161,7 +162,7 @@ func GetDeployKey(ctx *context.APIContext) { apiLink := composeDeployKeysAPILink(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) apiKey := convert.ToDeployKey(apiLink, key) if ctx.Doer.IsAdmin || ((ctx.Repo.Repository.ID == key.RepoID) && (ctx.Doer.ID == ctx.Repo.Owner.ID)) { - apiKey, _ = appendPrivateInformation(apiKey, key, ctx.Repo.Repository) + apiKey, _ = appendPrivateInformation(ctx, apiKey, key, ctx.Repo.Repository) } ctx.JSON(http.StatusOK, apiKey) } diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index 8b49becd37bb..411c0274e6c7 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -12,10 +12,10 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListLabels list all the labels of a repository diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index 25a5bcd06ff1..bd3449210d4a 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -16,7 +16,6 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" base "code.gitea.io/gitea/modules/migration" @@ -24,6 +23,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" "code.gitea.io/gitea/services/task" @@ -63,7 +63,7 @@ func Migrate(ctx *context.APIContext) { if len(form.RepoOwner) != 0 { repoOwner, err = user_model.GetUserByName(ctx, form.RepoOwner) } else if form.RepoOwnerID != 0 { - repoOwner, err = user_model.GetUserByID(form.RepoOwnerID) + repoOwner, err = user_model.GetUserByID(ctx, form.RepoOwnerID) } else { repoOwner = ctx.Doer } @@ -175,7 +175,7 @@ func Migrate(ctx *context.APIContext) { repo, err := task.MigrateRepository(ctx.Doer, repoOwner, opts) if err == nil { log.Trace("Repository migrated: %s/%s", repoOwner.Name, form.RepoName) - ctx.JSON(http.StatusCreated, convert.ToRepo(repo, perm.AccessModeAdmin)) + ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeAdmin)) return } diff --git a/routers/api/v1/repo/milestone.go b/routers/api/v1/repo/milestone.go index 2b80b4df7345..b77fe8aca8a9 100644 --- a/routers/api/v1/repo/milestone.go +++ b/routers/api/v1/repo/milestone.go @@ -11,11 +11,11 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListMilestones list milestones for a repository diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index b693c0e7db46..5fce5a4a803f 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -14,13 +14,13 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" mirror_module "code.gitea.io/gitea/modules/mirror" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/migrations" mirror_service "code.gitea.io/gitea/services/mirror" diff --git a/routers/api/v1/repo/notes.go b/routers/api/v1/repo/notes.go index 91eebb4c724d..8eaa503ff7cc 100644 --- a/routers/api/v1/repo/notes.go +++ b/routers/api/v1/repo/notes.go @@ -8,9 +8,9 @@ import ( "net/http" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" ) // GetNote Get a note corresponding to a single commit from a repository diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 53505e998c24..1b1aba17d929 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -21,7 +21,6 @@ import ( "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" @@ -32,6 +31,7 @@ import ( "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" "code.gitea.io/gitea/services/automerge" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/gitdiff" issue_service "code.gitea.io/gitea/services/issue" @@ -399,7 +399,7 @@ func CreatePullRequest(ctx *context.APIContext) { } // Check if the passed assignees is assignable for _, aID := range assigneeIDs { - assignee, err := user_model.GetUserByIDCtx(ctx, aID) + assignee, err := user_model.GetUserByID(ctx, aID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserByID", err) return @@ -490,6 +490,11 @@ func EditPullRequest(ctx *context.APIContext) { issue := pr.Issue issue.Repo = ctx.Repo.Repository + if err := issue.LoadAttributes(ctx); err != nil { + ctx.Error(http.StatusInternalServerError, "LoadAttributes", err) + return + } + if !issue.IsPoster(ctx.Doer.ID) && !ctx.Repo.CanWrite(unit.TypePullRequests) { ctx.Status(http.StatusForbidden) return @@ -810,7 +815,7 @@ func MergePullRequest(ctx *context.APIContext) { message := strings.TrimSpace(form.MergeTitleField) if len(message) == 0 { - message, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) + message, _, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetDefaultMergeMessage", err) return diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index 2f357afb79f7..96dc1fc2dee1 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -13,11 +13,11 @@ import ( access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" ) diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 4e1927ea3d92..d0b20102f7a4 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -11,10 +11,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" release_service "code.gitea.io/gitea/services/release" ) diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index 88632b463773..5aaea693c03b 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -8,13 +8,13 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/attachment" + "code.gitea.io/gitea/services/convert" ) // GetReleaseAttachment gets a single attachment of the release @@ -68,7 +68,7 @@ func GetReleaseAttachment(ctx *context.APIContext) { return } // FIXME Should prove the existence of the given repo, but results in unnecessary database requests - ctx.JSON(http.StatusOK, convert.ToReleaseAttachment(attach)) + ctx.JSON(http.StatusOK, convert.ToAttachment(attach)) } // ListReleaseAttachments lists all attachments of the release @@ -194,7 +194,12 @@ func CreateReleaseAttachment(ctx *context.APIContext) { } // Create a new attachment and save the file - attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, release.RepoID, releaseID, filename, setting.Repository.Release.AllowedTypes) + attach, err := attachment.UploadAttachment(file, setting.Repository.Release.AllowedTypes, &repo_model.Attachment{ + Name: filename, + UploaderID: ctx.Doer.ID, + RepoID: release.RepoID, + ReleaseID: releaseID, + }) if err != nil { if upload.IsErrFileTypeForbidden(err) { ctx.Error(http.StatusBadRequest, "DetectContentType", err) @@ -204,7 +209,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach)) + ctx.JSON(http.StatusCreated, convert.ToAttachment(attach)) } // EditReleaseAttachment updates the given attachment @@ -274,7 +279,7 @@ func EditReleaseAttachment(ctx *context.APIContext) { if err := repo_model.UpdateAttachment(ctx, attach); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach) } - ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach)) + ctx.JSON(http.StatusCreated, convert.ToAttachment(attach)) } // DeleteReleaseAttachment delete a given attachment diff --git a/routers/api/v1/repo/release_tags.go b/routers/api/v1/repo/release_tags.go index 5e1f1860ae77..7cc846fdc443 100644 --- a/routers/api/v1/repo/release_tags.go +++ b/routers/api/v1/repo/release_tags.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/services/convert" releaseservice "code.gitea.io/gitea/services/release" ) diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index e8603d19172e..e0cae5f82c7a 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -18,7 +18,6 @@ import ( unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" @@ -28,6 +27,7 @@ import ( "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" repo_service "code.gitea.io/gitea/services/repository" ) @@ -215,7 +215,7 @@ func Search(ctx *context.APIContext) { Error: err.Error(), }) } - results[i] = convert.ToRepo(repo, accessMode) + results[i] = convert.ToRepo(ctx, repo, accessMode) } ctx.SetLinkHeader(int(count), opts.PageSize) ctx.SetTotalCountHeader(count) @@ -257,12 +257,12 @@ func CreateUserRepo(ctx *context.APIContext, owner *user_model.User, opt api.Cre } // reload repo from db to get a real state after creation - repo, err = repo_model.GetRepositoryByID(repo.ID) + repo, err = repo_model.GetRepositoryByID(ctx, repo.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetRepositoryByID", err) } - ctx.JSON(http.StatusCreated, convert.ToRepo(repo, perm.AccessModeOwner)) + ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeOwner)) } // Create one repository of mine @@ -407,7 +407,7 @@ func Generate(ctx *context.APIContext) { } log.Trace("Repository generated [%d]: %s/%s", repo.ID, ctxUser.Name, repo.Name) - ctx.JSON(http.StatusCreated, convert.ToRepo(repo, perm.AccessModeOwner)) + ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, repo, perm.AccessModeOwner)) } // CreateOrgRepoDeprecated create one repository of the organization @@ -523,7 +523,7 @@ func Get(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToRepo(ctx.Repo.Repository, ctx.Repo.AccessMode)) + ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode)) } // GetByID returns a single Repository @@ -544,7 +544,7 @@ func GetByID(ctx *context.APIContext) { // "200": // "$ref": "#/responses/Repository" - repo, err := repo_model.GetRepositoryByID(ctx.ParamsInt64(":id")) + repo, err := repo_model.GetRepositoryByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound() @@ -562,7 +562,7 @@ func GetByID(ctx *context.APIContext) { ctx.NotFound() return } - ctx.JSON(http.StatusOK, convert.ToRepo(repo, perm.AccessMode)) + ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, perm.AccessMode)) } // Edit edit repository properties @@ -618,13 +618,13 @@ func Edit(ctx *context.APIContext) { } } - repo, err := repo_model.GetRepositoryByID(ctx.Repo.Repository.ID) + repo, err := repo_model.GetRepositoryByID(ctx, ctx.Repo.Repository.ID) if err != nil { ctx.InternalServerError(err) return } - ctx.JSON(http.StatusOK, convert.ToRepo(repo, ctx.Repo.AccessMode)) + ctx.JSON(http.StatusOK, convert.ToRepo(ctx, repo, ctx.Repo.AccessMode)) } // updateBasicProperties updates the basic properties of a repo: Name, Description, Website and Visibility @@ -669,7 +669,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err if opts.Private != nil { // Visibility of forked repository is forced sync with base repository. if repo.IsFork { - if err := repo.GetBaseRepo(); err != nil { + if err := repo.GetBaseRepo(ctx); err != nil { ctx.Error(http.StatusInternalServerError, "Unable to load base repository", err) return err } @@ -731,7 +731,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { var units []repo_model.RepoUnit var deleteUnitTypes []unit_model.Type - currHasIssues := repo.UnitEnabledCtx(ctx, unit_model.TypeIssues) + currHasIssues := repo.UnitEnabled(ctx, unit_model.TypeIssues) newHasIssues := currHasIssues if opts.HasIssues != nil { newHasIssues = *opts.HasIssues @@ -771,7 +771,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { AllowOnlyContributorsToTrackTime: opts.InternalTracker.AllowOnlyContributorsToTrackTime, EnableDependencies: opts.InternalTracker.EnableIssueDependencies, } - } else if unit, err := repo.GetUnit(unit_model.TypeIssues); err != nil { + } else if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err != nil { // Unit type doesn't exist so we make a new config file with default values config = &repo_model.IssuesConfig{ EnableTimetracker: true, @@ -798,7 +798,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { } } - currHasWiki := repo.UnitEnabledCtx(ctx, unit_model.TypeWiki) + currHasWiki := repo.UnitEnabled(ctx, unit_model.TypeWiki) newHasWiki := currHasWiki if opts.HasWiki != nil { newHasWiki = *opts.HasWiki @@ -838,7 +838,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { } } - currHasPullRequests := repo.UnitEnabledCtx(ctx, unit_model.TypePullRequests) + currHasPullRequests := repo.UnitEnabled(ctx, unit_model.TypePullRequests) newHasPullRequests := currHasPullRequests if opts.HasPullRequests != nil { newHasPullRequests = *opts.HasPullRequests @@ -848,7 +848,7 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error { // We do allow setting individual PR settings through the API, so // we get the config settings and then set them // if those settings were provided in the opts. - unit, err := repo.GetUnit(unit_model.TypePullRequests) + unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests) var config *repo_model.PullRequestsConfig if err != nil { // Unit type doesn't exist so we make a new config file with default values diff --git a/routers/api/v1/repo/star.go b/routers/api/v1/repo/star.go index a3d110587390..c7b2eb01ff65 100644 --- a/routers/api/v1/repo/star.go +++ b/routers/api/v1/repo/star.go @@ -8,9 +8,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListStargazers list a repository's stargazers diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index 84827a91adf2..19f57b1cea98 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -9,10 +9,10 @@ import ( git_model "code.gitea.io/gitea/models/git" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" files_service "code.gitea.io/gitea/services/repository/files" ) @@ -66,7 +66,7 @@ func NewCommitStatus(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToCommitStatus(status)) + ctx.JSON(http.StatusCreated, convert.ToCommitStatus(ctx, status)) } // GetCommitStatuses returns all statuses for any given commit hash @@ -183,6 +183,7 @@ func getCommitStatuses(ctx *context.APIContext, sha string) { ctx.Error(http.StatusBadRequest, "ref/sha not given", nil) return } + sha = utils.MustConvertToSHA1(ctx.Context, sha) repo := ctx.Repo.Repository listOptions := utils.GetListOptions(ctx) @@ -199,7 +200,7 @@ func getCommitStatuses(ctx *context.APIContext, sha string) { apiStatuses := make([]*api.CommitStatus, 0, len(statuses)) for _, status := range statuses { - apiStatuses = append(apiStatuses, convert.ToCommitStatus(status)) + apiStatuses = append(apiStatuses, convert.ToCommitStatus(ctx, status)) } ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) @@ -263,7 +264,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) { return } - combiStatus := convert.ToCombinedStatus(statuses, convert.ToRepo(repo, ctx.Repo.AccessMode)) + combiStatus := convert.ToCombinedStatus(ctx, statuses, convert.ToRepo(ctx, repo, ctx.Repo.AccessMode)) ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, combiStatus) diff --git a/routers/api/v1/repo/subscriber.go b/routers/api/v1/repo/subscriber.go index 5cc94abd487f..6cd369898eba 100644 --- a/routers/api/v1/repo/subscriber.go +++ b/routers/api/v1/repo/subscriber.go @@ -8,9 +8,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListSubscribers list a repo's subscribers (i.e. watchers) diff --git a/routers/api/v1/repo/tag.go b/routers/api/v1/repo/tag.go index 6b38a08c2f7b..cb65e2b651b0 100644 --- a/routers/api/v1/repo/tag.go +++ b/routers/api/v1/repo/tag.go @@ -11,10 +11,10 @@ import ( "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" releaseservice "code.gitea.io/gitea/services/release" ) diff --git a/routers/api/v1/repo/teams.go b/routers/api/v1/repo/teams.go index 1ea3ae0008a8..eafe4236ec3a 100644 --- a/routers/api/v1/repo/teams.go +++ b/routers/api/v1/repo/teams.go @@ -10,7 +10,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/services/convert" org_service "code.gitea.io/gitea/services/org" ) diff --git a/routers/api/v1/repo/topic.go b/routers/api/v1/repo/topic.go index 316b19025986..7d27fe7d25a0 100644 --- a/routers/api/v1/repo/topic.go +++ b/routers/api/v1/repo/topic.go @@ -9,11 +9,11 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListTopics returns list of current topics for repo diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index a40419e13e3c..aec398da7a41 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -13,10 +13,10 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" repo_service "code.gitea.io/gitea/services/repository" ) @@ -105,7 +105,7 @@ func Transfer(ctx *context.APIContext) { oldFullname := ctx.Repo.Repository.FullName() - if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil { + if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, ctx.Repo.Repository, teams); err != nil { if models.IsErrRepoTransferInProgress(err) { ctx.Error(http.StatusConflict, "StartRepositoryTransfer", err) return @@ -122,12 +122,12 @@ func Transfer(ctx *context.APIContext) { if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer { log.Trace("Repository transfer initiated: %s -> %s", oldFullname, ctx.Repo.Repository.FullName()) - ctx.JSON(http.StatusCreated, convert.ToRepo(ctx.Repo.Repository, perm.AccessModeAdmin)) + ctx.JSON(http.StatusCreated, convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeAdmin)) return } log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName()) - ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx.Repo.Repository, perm.AccessModeAdmin)) + ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeAdmin)) } // AcceptTransfer accept a repo transfer @@ -165,7 +165,7 @@ func AcceptTransfer(ctx *context.APIContext) { return } - ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx.Repo.Repository, ctx.Repo.AccessMode)) + ctx.JSON(http.StatusAccepted, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode)) } // RejectTransfer reject a repo transfer @@ -203,11 +203,11 @@ func RejectTransfer(ctx *context.APIContext) { return } - ctx.JSON(http.StatusOK, convert.ToRepo(ctx.Repo.Repository, ctx.Repo.AccessMode)) + ctx.JSON(http.StatusOK, convert.ToRepo(ctx, ctx.Repo.Repository, ctx.Repo.AccessMode)) } func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { if models.IsErrNoPendingTransfer(err) { ctx.NotFound() @@ -216,7 +216,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { return err } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { return err } @@ -226,7 +226,7 @@ func acceptOrRejectRepoTransfer(ctx *context.APIContext, accept bool) error { } if accept { - return repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams) + return repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams) } return models.CancelRepositoryTransfer(ctx.Repo.Repository) diff --git a/routers/api/v1/repo/wiki.go b/routers/api/v1/repo/wiki.go index 0b55a9b2818f..764530a671e6 100644 --- a/routers/api/v1/repo/wiki.go +++ b/routers/api/v1/repo/wiki.go @@ -11,13 +11,13 @@ import ( repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" wiki_service "code.gitea.io/gitea/services/wiki" ) diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index 6cb7b812b233..7b2f0d8c30d2 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -12,10 +12,10 @@ import ( auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // ListAccessTokens list all the access tokens diff --git a/routers/api/v1/user/email.go b/routers/api/v1/user/email.go index 84823aaed207..fc74c8d14846 100644 --- a/routers/api/v1/user/email.go +++ b/routers/api/v1/user/email.go @@ -9,10 +9,10 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" ) // ListEmails list all of the authenticated user's email addresses diff --git a/routers/api/v1/user/follower.go b/routers/api/v1/user/follower.go index 38ddf990c47e..e9d4ae478b3d 100644 --- a/routers/api/v1/user/follower.go +++ b/routers/api/v1/user/follower.go @@ -9,9 +9,9 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) { diff --git a/routers/api/v1/user/gpg_key.go b/routers/api/v1/user/gpg_key.go index 7c91d2ac6563..84327cc92a43 100644 --- a/routers/api/v1/user/gpg_key.go +++ b/routers/api/v1/user/gpg_key.go @@ -11,10 +11,10 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) func listGPGKeys(ctx *context.APIContext, uid int64, listOptions db.ListOptions) { diff --git a/routers/api/v1/user/key.go b/routers/api/v1/user/key.go index d00eec85e494..8aad69884fd8 100644 --- a/routers/api/v1/user/key.go +++ b/routers/api/v1/user/key.go @@ -7,16 +7,17 @@ import ( "net/http" asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/repo" "code.gitea.io/gitea/routers/api/v1/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" + "code.gitea.io/gitea/services/convert" ) // appendPrivateInformation appends the owner and key type information to api.PublicKey @@ -29,7 +30,7 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *asymkey_model.PublicKe if defaultUser.ID == key.OwnerID { apiKey.Owner = convert.ToUser(defaultUser, defaultUser) } else { - user, err := user_model.GetUserByID(key.OwnerID) + user, err := user_model.GetUserByID(db.DefaultContext, key.OwnerID) if err != nil { return apiKey, err } diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index 2af70f9ad393..d566c072fba7 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -11,9 +11,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // listUserRepos - List the repositories owned by the given user. @@ -44,7 +44,7 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { return } if ctx.IsSigned && ctx.Doer.IsAdmin || access >= perm.AccessModeRead { - apiRepos = append(apiRepos, convert.ToRepo(repos[i], access)) + apiRepos = append(apiRepos, convert.ToRepo(ctx, repos[i], access)) } } @@ -127,7 +127,7 @@ func ListMyRepos(ctx *context.APIContext) { if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) } - results[i] = convert.ToRepo(repo, accessMode) + results[i] = convert.ToRepo(ctx, repo, accessMode) } ctx.SetLinkHeader(int(count), opts.ListOptions.PageSize) diff --git a/routers/api/v1/user/settings.go b/routers/api/v1/user/settings.go index 89bfd83efc15..53794c82f838 100644 --- a/routers/api/v1/user/settings.go +++ b/routers/api/v1/user/settings.go @@ -8,9 +8,9 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" ) // GetUserSettings returns user settings diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index 2ef5806974ee..ad5a8bee33be 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -13,9 +13,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // getStarredRepos returns the repos that the user with the specified userID has @@ -32,7 +32,7 @@ func getStarredRepos(ctx std_context.Context, user *user_model.User, private boo if err != nil { return nil, err } - repos[i] = convert.ToRepo(starred, access) + repos[i] = convert.ToRepo(ctx, starred, access) } return repos, nil } diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 8a21c2c7cacd..55f3df40b9cc 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -10,8 +10,8 @@ import ( activities_model "code.gitea.io/gitea/models/activities" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // Search search users diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index 43c097444ec3..211f36459a83 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -12,9 +12,9 @@ import ( repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/services/convert" ) // getWatchedRepos returns the repos that the user with the specified userID is watching @@ -30,7 +30,7 @@ func getWatchedRepos(ctx std_context.Context, user *user_model.User, private boo if err != nil { return nil, 0, err } - repos[i] = convert.ToRepo(watched, access) + repos[i] = convert.ToRepo(ctx, watched, access) } return repos, total, nil } diff --git a/routers/api/v1/utils/git.go b/routers/api/v1/utils/git.go index 2801dee8babe..eaf0f5fd37fc 100644 --- a/routers/api/v1/utils/git.go +++ b/routers/api/v1/utils/git.go @@ -33,6 +33,8 @@ func ResolveRefOrSha(ctx *context.APIContext, ref string) string { } } + sha = MustConvertToSHA1(ctx.Context, sha) + if ctx.Repo.GitRepo != nil { err := ctx.Repo.GitRepo.AddLastCommitCache(ctx.Repo.Repository.GetCommitsCountCacheKey(ref, ref != sha), ctx.Repo.Repository.FullName(), sha) if err != nil { @@ -65,3 +67,30 @@ func searchRefCommitByType(ctx *context.APIContext, refType, filter string) (str } return "", "", nil } + +// ConvertToSHA1 returns a full-length SHA1 from a potential ID string +func ConvertToSHA1(ctx *context.Context, commitID string) (git.SHA1, error) { + if len(commitID) == git.SHAFullLength && git.IsValidSHAPattern(commitID) { + sha1, err := git.NewIDFromString(commitID) + if err == nil { + return sha1, nil + } + } + + gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, ctx.Repo.Repository.RepoPath()) + if err != nil { + return git.SHA1{}, fmt.Errorf("RepositoryFromContextOrOpen: %w", err) + } + defer closer.Close() + + return gitRepo.ConvertToSHA1(commitID) +} + +// MustConvertToSHA1 returns a full-length SHA1 string from a potential ID string, or returns origin input if it can't convert to SHA1 +func MustConvertToSHA1(ctx *context.Context, commitID string) string { + sha, err := ConvertToSHA1(ctx, commitID) + if err != nil { + return commitID + } + return sha.String() +} diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index 7faf609ae813..1a27ececfe1c 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -10,10 +10,10 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/json" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" + "code.gitea.io/gitea/services/convert" webhook_service "code.gitea.io/gitea/services/webhook" ) diff --git a/routers/api/v1/utils/page.go b/routers/api/v1/utils/page.go index ef5806fa9218..6910b8293196 100644 --- a/routers/api/v1/utils/page.go +++ b/routers/api/v1/utils/page.go @@ -6,7 +6,7 @@ package utils import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/services/convert" ) // GetListOptions returns list options using the page and limit parameters diff --git a/routers/common/db.go b/routers/common/db.go index ac082ab36f99..2e86fbd0fd42 100644 --- a/routers/common/db.go +++ b/routers/common/db.go @@ -12,6 +12,8 @@ import ( "code.gitea.io/gitea/models/migrations" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + + "xorm.io/xorm" ) // InitDBEngine In case of problems connecting to DB, retry connection. Eg, PGSQL in Docker Container on Synology @@ -24,7 +26,7 @@ func InitDBEngine(ctx context.Context) (err error) { default: } log.Info("ORM engine initialization attempt #%d/%d...", i+1, setting.Database.DBConnectRetries) - if err = db.InitEngineWithMigration(ctx, migrations.Migrate); err == nil { + if err = db.InitEngineWithMigration(ctx, migrateWithSetting); err == nil { break } else if i == setting.Database.DBConnectRetries-1 { return err @@ -36,3 +38,20 @@ func InitDBEngine(ctx context.Context) (err error) { db.HasEngine = true return nil } + +func migrateWithSetting(x *xorm.Engine) error { + if setting.Database.AutoMigration { + return migrations.Migrate(x) + } + + if current, err := migrations.GetCurrentDBVersion(x); err != nil { + return err + } else if current < 0 { + // execute migrations when the database isn't initialized even if AutoMigration is false + return migrations.Migrate(x) + } else if expected := migrations.ExpectedVersion(); current != expected { + log.Fatal(`"database.AUTO_MIGRATION" is disabled, but current database version %d is not equal to the expected version %d.`+ + `You can set "database.AUTO_MIGRATION" to true or migrate manually by running "gitea [--config /path/to/app.ini] migrate"`, current, expected) + } + return nil +} diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 9c69f9c34587..c62038899d71 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -183,7 +183,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { baseRepo = repo if repo.IsFork { - if err := repo.GetBaseRepo(); err != nil { + if err := repo.GetBaseRepo(ctx); err != nil { log.Error("Failed to get Base Repository of Forked repository: %-v Error: %v", repo, err) ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ Err: fmt.Sprintf("Failed to get Base Repository of Forked repository: %-v Error: %v", repo, err), diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index 52a82bfa4450..e49ae68a64b8 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -464,7 +464,7 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool { return true } - user, err := user_model.GetUserByID(ctx.opts.UserID) + user, err := user_model.GetUserByID(ctx, ctx.opts.UserID) if err != nil { log.Error("Unable to get User id %d Error: %v", ctx.opts.UserID, err) ctx.JSON(http.StatusInternalServerError, private.Response{ diff --git a/routers/private/internal.go b/routers/private/internal.go index d5c85480a774..306e4ffb0040 100644 --- a/routers/private/internal.go +++ b/routers/private/internal.go @@ -6,7 +6,6 @@ package private import ( "net/http" - "reflect" "strings" "code.gitea.io/gitea/modules/context" @@ -39,13 +38,9 @@ func CheckInternalToken(next http.Handler) http.Handler { } // bind binding an obj to a handler -func bind(obj interface{}) http.HandlerFunc { - tp := reflect.TypeOf(obj) - for tp.Kind() == reflect.Ptr { - tp = tp.Elem() - } +func bind[T any](obj T) http.HandlerFunc { return web.Wrap(func(ctx *context.PrivateContext) { - theObj := reflect.New(tp).Interface() // create a new form obj for every request but not use obj directly + theObj := new(T) // create a new form obj for every request but not use obj directly binding.Bind(ctx.Req, theObj) web.SetForm(ctx, theObj) }) diff --git a/routers/private/internal_repo.go b/routers/private/internal_repo.go index 2e6f87d6b08b..bd8db0a1854d 100644 --- a/routers/private/internal_repo.go +++ b/routers/private/internal_repo.go @@ -68,7 +68,7 @@ func RepoAssignment(ctx *gitea_context.PrivateContext) context.CancelFunc { } func loadRepository(ctx *gitea_context.PrivateContext, ownerName, repoName string) *repo_model.Repository { - repo, err := repo_model.GetRepositoryByOwnerAndName(ownerName, repoName) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName) if err != nil { log.Error("Failed to get repository: %s/%s Error: %v", ownerName, repoName, err) ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ diff --git a/routers/private/serv.go b/routers/private/serv.go index 676d83d9e135..17f966e3e40a 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -51,7 +51,7 @@ func ServNoCommand(ctx *context.PrivateContext) { results.Key = key if key.Type == asymkey_model.KeyTypeUser || key.Type == asymkey_model.KeyTypePrincipal { - user, err := user_model.GetUserByID(key.OwnerID) + user, err := user_model.GetUserByID(ctx, key.OwnerID) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.JSON(http.StatusUnauthorized, private.Response{ @@ -259,7 +259,7 @@ func ServCommand(ctx *context.PrivateContext) { } else { // Get the user represented by the Key var err error - user, err = user_model.GetUserByID(key.OwnerID) + user, err = user_model.GetUserByID(ctx, key.OwnerID) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.JSON(http.StatusUnauthorized, private.ErrServCommand{ @@ -382,7 +382,7 @@ func ServCommand(ctx *context.PrivateContext) { if results.IsWiki { // Ensure the wiki is enabled before we allow access to it - if _, err := repo.GetUnit(unit.TypeWiki); err != nil { + if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil { if repo_model.IsErrUnitTypeNotExist(err) { ctx.JSON(http.StatusForbidden, private.ErrServCommand{ Results: results, diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 80cec51275cf..7c6d1ed840f5 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -62,6 +62,7 @@ func Packages(ctx *context.Context) { ctx.Data["PageIsAdminPackages"] = true ctx.Data["Query"] = query ctx.Data["PackageType"] = packageType + ctx.Data["AvailableTypes"] = packages_model.TypeList ctx.Data["SortType"] = sort ctx.Data["PackageDescriptors"] = pds ctx.Data["Total"] = total diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go index b488bbbd1400..dc5432c54998 100644 --- a/routers/web/admin/repos.go +++ b/routers/web/admin/repos.go @@ -41,7 +41,7 @@ func Repos(ctx *context.Context) { // DeleteRepo delete one repository func DeleteRepo(ctx *context.Context) { - repo, err := repo_model.GetRepositoryByID(ctx.FormInt64("id")) + repo, err := repo_model.GetRepositoryByID(ctx, ctx.FormInt64("id")) if err != nil { ctx.ServerError("GetRepositoryByID", err) return diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 399633e39fe5..38969dadaadc 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -206,7 +206,7 @@ func NewUserPost(ctx *context.Context) { } func prepareUserInfo(ctx *context.Context) *user_model.User { - u, err := user_model.GetUserByID(ctx.ParamsInt64(":userid")) + u, err := user_model.GetUserByID(ctx, ctx.ParamsInt64(":userid")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Redirect(setting.AppSubURL + "/admin/users") @@ -413,7 +413,7 @@ func EditUserPost(ctx *context.Context) { // DeleteUser response for deleting a user func DeleteUser(ctx *context.Context) { - u, err := user_model.GetUserByID(ctx.ParamsInt64(":userid")) + u, err := user_model.GetUserByID(ctx, ctx.ParamsInt64(":userid")) if err != nil { ctx.ServerError("GetUserByID", err) return diff --git a/routers/web/auth/2fa.go b/routers/web/auth/2fa.go index 2aacf230371c..4791b043131d 100644 --- a/routers/web/auth/2fa.go +++ b/routers/web/auth/2fa.go @@ -68,7 +68,7 @@ func TwoFactorPost(ctx *context.Context) { if ok && twofa.LastUsedPasscode != form.Passcode { remember := ctx.Session.Get("twofaRemember").(bool) - u, err := user_model.GetUserByID(id) + u, err := user_model.GetUserByID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -146,7 +146,7 @@ func TwoFactorScratchPost(ctx *context.Context) { } remember := ctx.Session.Get("twofaRemember").(bool) - u, err := user_model.GetUserByID(id) + u, err := user_model.GetUserByID(ctx, id) if err != nil { ctx.ServerError("UserSignIn", err) return diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index b289989d6974..7a0052b08df5 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -748,7 +748,7 @@ func ActivateEmail(ctx *context.Context) { log.Trace("Email activated: %s", email.Email) ctx.Flash.Success(ctx.Tr("settings.add_email_success")) - if u, err := user_model.GetUserByID(email.UID); err != nil { + if u, err := user_model.GetUserByID(ctx, email.UID); err != nil { log.Warn("GetUserByID: %d", email.UID) } else if setting.CacheService.Enabled { // Allow user to validate more emails diff --git a/routers/web/auth/kitspace_auth.go b/routers/web/auth/kitspace_auth.go index 1feaa8478148..459db28f2144 100644 --- a/routers/web/auth/kitspace_auth.go +++ b/routers/web/auth/kitspace_auth.go @@ -7,13 +7,13 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/password" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" - "code.gitea.io/gitea/services/auth" + auth_service "code.gitea.io/gitea/services/auth" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/mailer" ) @@ -141,7 +141,7 @@ func KitspaceSignIn(ctx *context.Context) { // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*forms.SignInForm) - u, _, err := auth.UserSignIn(form.UserName, form.Password) + u, _, err := auth_service.UserSignIn(form.UserName, form.Password) response := make(map[string]interface{}) if err != nil { diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 2b872178cace..3d70ca9a5067 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -194,7 +194,7 @@ func newAccessTokenResponse(ctx stdContext.Context, grant *auth.OAuth2Grant, ser ErrorDescription: "cannot find application", } } - user, err := user_model.GetUserByID(grant.UserID) + user, err := user_model.GetUserByID(ctx, grant.UserID) if err != nil { if user_model.IsErrUserNotExist(err) { return nil, &AccessTokenError{ @@ -385,7 +385,7 @@ func AuthorizeOAuth(ctx *context.Context) { var user *user_model.User if app.UID != 0 { - user, err = user_model.GetUserByID(app.UID) + user, err = user_model.GetUserByID(ctx, app.UID) if err != nil { ctx.ServerError("GetUserByID", err) return @@ -1222,7 +1222,7 @@ func oAuth2UserLoginCallback(authSource *auth.Source, request *http.Request, res return nil, goth.User{}, err } if hasUser { - user, err = user_model.GetUserByID(externalLoginUser.UserID) + user, err = user_model.GetUserByID(request.Context(), externalLoginUser.UserID) return user, gothUser, err } diff --git a/routers/web/auth/webauthn.go b/routers/web/auth/webauthn.go index b60007bc0321..965fc10fe7d8 100644 --- a/routers/web/auth/webauthn.go +++ b/routers/web/auth/webauthn.go @@ -49,7 +49,7 @@ func WebAuthnLoginAssertion(ctx *context.Context) { return } - user, err := user_model.GetUserByID(idSess) + user, err := user_model.GetUserByID(ctx, idSess) if err != nil { ctx.ServerError("UserSignIn", err) return @@ -91,7 +91,7 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) { }() // Load the user from the db - user, err := user_model.GetUserByID(idSess) + user, err := user_model.GetUserByID(ctx, idSess) if err != nil { ctx.ServerError("UserSignIn", err) return diff --git a/routers/web/explore/topic.go b/routers/web/explore/topic.go index 50df9d1113e2..e172d9e04d01 100644 --- a/routers/web/explore/topic.go +++ b/routers/web/explore/topic.go @@ -9,8 +9,8 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" ) // TopicSearch search for creating topic diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index bb6aa3dc77c9..e00493c87b76 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -68,6 +68,10 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, orderBy = "`user`.updated_unix ASC" case "reversealphabetically": orderBy = "`user`.name DESC" + case "lastlogin": + orderBy = "`user`.last_login_unix ASC" + case "reverselastlogin": + orderBy = "`user`.last_login_unix DESC" case UserSearchDefaultSortType: // "alphabetically" default: orderBy = "`user`.name ASC" diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go index e0e481d1a561..7c375a085f03 100644 --- a/routers/web/feed/convert.go +++ b/routers/web/feed/convert.go @@ -12,6 +12,7 @@ import ( "strings" activities_model "code.gitea.io/gitea/models/activities" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" @@ -68,7 +69,7 @@ func renderMarkdown(ctx *context.Context, act *activities_model.Action, content // feedActionsToFeedItems convert gitea's Action feed to feeds Item func feedActionsToFeedItems(ctx *context.Context, actions activities_model.ActionList) (items []*feeds.Item, err error) { for _, act := range actions { - act.LoadActUser() + act.LoadActUser(ctx) var content, desc, title string @@ -268,3 +269,46 @@ func GetFeedType(name string, req *http.Request) (bool, string, string) { return false, name, "" } + +// feedActionsToFeedItems convert gitea's Repo's Releases to feeds Item +func releasesToFeedItems(ctx *context.Context, releases []*repo_model.Release, isReleasesOnly bool) (items []*feeds.Item, err error) { + for _, rel := range releases { + err := rel.LoadAttributes(ctx) + if err != nil { + return nil, err + } + + var title, content string + + if rel.IsTag { + title = rel.TagName + } else { + title = rel.Title + } + + link := &feeds.Link{Href: rel.HTMLURL()} + content, err = markdown.RenderString(&markup.RenderContext{ + Ctx: ctx, + URLPrefix: rel.Repo.Link(), + Metas: rel.Repo.ComposeMetas(), + }, rel.Note) + + if err != nil { + return nil, err + } + + items = append(items, &feeds.Item{ + Title: title, + Link: link, + Created: rel.CreatedUnix.AsTime(), + Author: &feeds.Author{ + Name: rel.Publisher.DisplayName(), + Email: rel.Publisher.GetEmail(), + }, + Id: fmt.Sprintf("%v: %v", strconv.FormatInt(rel.ID, 10), link.Href), + Content: content, + }) + } + + return items, err +} diff --git a/routers/web/feed/release.go b/routers/web/feed/release.go new file mode 100644 index 000000000000..fbfa11c63ecf --- /dev/null +++ b/routers/web/feed/release.go @@ -0,0 +1,50 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package feed + +import ( + "time" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + + "github.com/gorilla/feeds" +) + +// shows tags and/or releases on the repo as RSS / Atom feed +func ShowReleaseFeed(ctx *context.Context, repo *repo_model.Repository, isReleasesOnly bool, formatType string) { + releases, err := repo_model.GetReleasesByRepoID(ctx, ctx.Repo.Repository.ID, repo_model.FindReleasesOptions{ + IncludeTags: !isReleasesOnly, + }) + if err != nil { + ctx.ServerError("GetReleasesByRepoID", err) + return + } + + var title string + var link *feeds.Link + + if isReleasesOnly { + title = ctx.Tr("repo.release.releases_for", repo.FullName()) + link = &feeds.Link{Href: repo.HTMLURL() + "/release"} + } else { + title = ctx.Tr("repo.release.tags_for", repo.FullName()) + link = &feeds.Link{Href: repo.HTMLURL() + "/tags"} + } + + feed := &feeds.Feed{ + Title: title, + Link: link, + Description: repo.Description, + Created: time.Now(), + } + + feed.Items, err = releasesToFeedItems(ctx, releases, isReleasesOnly) + if err != nil { + ctx.ServerError("releasesToFeedItems", err) + return + } + + writeFeed(ctx, feed, formatType) +} diff --git a/routers/web/goget.go b/routers/web/goget.go index b8e264c4415b..fb8afae9991a 100644 --- a/routers/web/goget.go +++ b/routers/web/goget.go @@ -52,7 +52,7 @@ func goGet(ctx *context.Context) { } branchName := setting.Repository.DefaultBranch - repo, err := repo_model.GetRepositoryByOwnerAndName(ownerName, repoName) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, ownerName, repoName) if err == nil && len(repo.DefaultBranch) > 0 { branchName = repo.DefaultBranch } diff --git a/routers/web/org/members.go b/routers/web/org/members.go index 3be2a39c2e36..8361da663211 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -107,13 +107,20 @@ func MembersAction(ctx *context.Context) { } case "leave": err = models.RemoveOrgUser(org.ID, ctx.Doer.ID) - if organization.IsErrLastOrgOwner(err) { + if err == nil { + ctx.Flash.Success(ctx.Tr("form.organization_leave_success", org.DisplayName())) + ctx.JSON(http.StatusOK, map[string]interface{}{ + "redirect": "", // keep the user stay on current page, in case they want to do other operations. + }) + } else if organization.IsErrLastOrgOwner(err) { ctx.Flash.Error(ctx.Tr("form.last_org_owner")) ctx.JSON(http.StatusOK, map[string]interface{}{ "redirect": ctx.Org.OrgLink + "/members", }) - return + } else { + log.Error("RemoveOrgUser(%d,%d): %v", org.ID, ctx.Doer.ID, err) } + return } if err != nil { diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 899e554ba0dc..e625962f7597 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" + secret_model "code.gitea.io/gitea/models/secret" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/base" @@ -37,6 +38,8 @@ const ( tplSettingsHooks base.TplName = "org/settings/hooks" // tplSettingsLabels template path for render labels settings tplSettingsLabels base.TplName = "org/settings/labels" + // tplSettingsSecrets template path for render secrets settings + tplSettingsSecrets base.TplName = "org/settings/secrets" ) // Settings render the main settings page @@ -246,3 +249,51 @@ func Labels(ctx *context.Context) { ctx.Data["LabelTemplates"] = repo_module.LabelTemplates ctx.HTML(http.StatusOK, tplSettingsLabels) } + +// Secrets render organization secrets page +func Secrets(ctx *context.Context) { + ctx.Data["Title"] = ctx.Tr("repo.secrets") + ctx.Data["PageIsOrgSettings"] = true + ctx.Data["PageIsOrgSettingsSecrets"] = true + + secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{OwnerID: ctx.Org.Organization.ID}) + if err != nil { + ctx.ServerError("FindSecrets", err) + return + } + ctx.Data["Secrets"] = secrets + + ctx.HTML(http.StatusOK, tplSettingsSecrets) +} + +// SecretsPost add secrets +func SecretsPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.AddSecretForm) + + _, err := secret_model.InsertEncryptedSecret(ctx, ctx.Org.Organization.ID, 0, form.Title, form.Content) + if err != nil { + ctx.Flash.Error(ctx.Tr("secrets.creation.failed")) + log.Error("validate secret: %v", err) + ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets") + return + } + + log.Trace("Org %d: secret added", ctx.Org.Organization.ID) + ctx.Flash.Success(ctx.Tr("secrets.creation.success", form.Title)) + ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets") +} + +// SecretsDelete delete secrets +func SecretsDelete(ctx *context.Context) { + id := ctx.FormInt64("id") + if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil { + ctx.Flash.Error(ctx.Tr("secrets.deletion.failed")) + log.Error("delete secret %d: %v", id, err) + } else { + ctx.Flash.Success(ctx.Tr("secrets.deletion.success")) + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "redirect": ctx.Org.OrgLink + "/settings/secrets", + }) +} diff --git a/routers/web/org/setting_packages.go b/routers/web/org/setting_packages.go index c7edf4a18531..80135ca2d0a0 100644 --- a/routers/web/org/setting_packages.go +++ b/routers/web/org/setting_packages.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package org diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index d12e2fcc4530..d9754633bfd9 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -20,11 +20,11 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" org_service "code.gitea.io/gitea/services/org" ) @@ -49,7 +49,7 @@ func Teams(ctx *context.Context) { ctx.Data["PageIsOrgTeams"] = true for _, t := range ctx.Org.Teams { - if err := t.GetMembersCtx(ctx); err != nil { + if err := t.LoadMembers(ctx); err != nil { ctx.ServerError("GetMembers", err) return } @@ -346,7 +346,7 @@ func TeamMembers(ctx *context.Context) { ctx.Data["Title"] = ctx.Org.Team.Name ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeamMembers"] = true - if err := ctx.Org.Team.GetMembersCtx(ctx); err != nil { + if err := ctx.Org.Team.LoadMembers(ctx); err != nil { ctx.ServerError("GetMembers", err) return } @@ -368,7 +368,7 @@ func TeamRepositories(ctx *context.Context) { ctx.Data["Title"] = ctx.Org.Team.Name ctx.Data["PageIsOrgTeams"] = true ctx.Data["PageIsOrgTeamRepos"] = true - if err := ctx.Org.Team.GetRepositoriesCtx(ctx); err != nil { + if err := ctx.Org.Team.LoadRepositories(ctx); err != nil { ctx.ServerError("GetRepositories", err) return } @@ -570,7 +570,7 @@ func getTeamInviteFromContext(ctx *context.Context) (*org_model.TeamInvite, *org return nil, nil, nil, nil, err } - inviter, err := user_model.GetUserByIDCtx(ctx, invite.InviterID) + inviter, err := user_model.GetUserByID(ctx, invite.InviterID) if err != nil { return nil, nil, nil, nil, err } @@ -580,7 +580,7 @@ func getTeamInviteFromContext(ctx *context.Context) (*org_model.TeamInvite, *org return nil, nil, nil, nil, err } - org, err := user_model.GetUserByIDCtx(ctx, team.OrgID) + org, err := user_model.GetUserByID(ctx, team.OrgID) if err != nil { return nil, nil, nil, nil, err } diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index d12fa60dafcb..589632ad6e10 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -44,7 +44,11 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) { } defer file.Close() - attach, err := attachment.UploadAttachment(file, ctx.Doer.ID, repoID, 0, header.Filename, allowedTypes) + attach, err := attachment.UploadAttachment(file, allowedTypes, &repo_model.Attachment{ + Name: header.Filename, + UploaderID: ctx.Doer.ID, + RepoID: repoID, + }) if err != nil { if upload.IsErrFileTypeForbidden(err) { ctx.Error(http.StatusBadRequest, err.Error()) @@ -82,7 +86,7 @@ func DeleteAttachment(ctx *context.Context) { }) } -// GetAttachment serve attachements +// GetAttachment serve attachments func GetAttachment(ctx *context.Context) { attach, err := repo_model.GetAttachmentByUUID(ctx, ctx.Params(":uuid")) if err != nil { @@ -94,7 +98,7 @@ func GetAttachment(ctx *context.Context) { return } - repository, unitType, err := repo_service.LinkedRepository(attach) + repository, unitType, err := repo_service.LinkedRepository(ctx, attach) if err != nil { ctx.ServerError("LinkedRepository", err) return diff --git a/routers/web/repo/branch.go b/routers/web/repo/branch.go index 61fb24d0587f..18bb06ed1a29 100644 --- a/routers/web/repo/branch.go +++ b/routers/web/repo/branch.go @@ -337,7 +337,7 @@ func getDeletedBranches(ctx *context.Context) ([]*Branch, error) { } for i := range deletedBranches { - deletedBranches[i].LoadUser() + deletedBranches[i].LoadUser(ctx) branches = append(branches, &Branch{ Name: deletedBranches[i].Name, IsDeleted: true, diff --git a/routers/web/repo/cherry_pick.go b/routers/web/repo/cherry_pick.go index 2056ad1b379b..48bc6959e075 100644 --- a/routers/web/repo/cherry_pick.go +++ b/routers/web/repo/cherry_pick.go @@ -177,7 +177,7 @@ func CherryPickPost(ctx *context.Context) { } } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName)) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index efc216661cae..6eda3fca10b3 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -283,7 +283,7 @@ func Diff(ctx *context.Context) { } return } - if len(commitID) != 40 { + if len(commitID) != git.SHAFullLength { commitID = commit.ID.String() } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index a9d6eea1ebee..d95eeaecc977 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -269,7 +269,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { ci.HeadRepo = baseRepo } } else { - ci.HeadRepo, err = repo_model.GetRepositoryByOwnerAndName(headInfosSplit[0], headInfosSplit[1]) + ci.HeadRepo, err = repo_model.GetRepositoryByOwnerAndName(ctx, headInfosSplit[0], headInfosSplit[1]) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound("GetRepositoryByOwnerAndName", nil) @@ -339,7 +339,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // forked from var rootRepo *repo_model.Repository if baseRepo.IsFork { - err = baseRepo.GetBaseRepo() + err = baseRepo.GetBaseRepo(ctx) if err != nil { if !repo_model.IsErrRepoNotExist(err) { ctx.ServerError("Unable to find root repo", err) @@ -577,7 +577,7 @@ func PrepareCompareDiff( if (headCommitID == ci.CompareInfo.MergeBase && !ci.DirectComparison) || headCommitID == ci.CompareInfo.BaseCommitID { ctx.Data["IsNothingToCompare"] = true - if unit, err := repo.GetUnit(unit.TypePullRequests); err == nil { + if unit, err := repo.GetUnit(ctx, unit.TypePullRequests); err == nil { config := unit.PullRequestsConfig() if !config.AutodetectManualMerge { diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go index 32681273b5cf..f88310c028d3 100644 --- a/routers/web/repo/editor.go +++ b/routers/web/repo/editor.go @@ -328,7 +328,7 @@ func editFilePost(ctx *context.Context, form forms.EditRepoFileForm, isNewFile b } } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) @@ -514,7 +514,7 @@ func DeleteFilePost(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath)) - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { treePath := path.Dir(ctx.Repo.TreePath) @@ -717,7 +717,7 @@ func UploadFilePost(ctx *context.Context) { return } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index d2450066e341..b2a49e3e3a10 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -258,7 +258,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) { if isWiki { // Ensure the wiki is enabled before we allow access to it - if _, err := repo.GetUnit(unit.TypeWiki); err != nil { + if _, err := repo.GetUnit(ctx, unit.TypeWiki); err != nil { if repo_model.IsErrUnitTypeNotExist(err) { ctx.PlainText(http.StatusForbidden, "repository wiki is disabled") return diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 2a0a849b5ba5..100e343de49b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -31,7 +31,6 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" issue_indexer "code.gitea.io/gitea/modules/indexer/issues" issue_template "code.gitea.io/gitea/modules/issue/template" @@ -47,7 +46,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" asymkey_service "code.gitea.io/gitea/services/asymkey" - comment_service "code.gitea.io/gitea/services/comments" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" @@ -114,7 +113,7 @@ func MustEnableIssues(ctx *context.Context) { return } - unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker) + unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker) if err == nil { ctx.Redirect(unit.ExternalTrackerConfig().ExternalTrackerURL) return @@ -1007,7 +1006,7 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull // Check if the passed assignees actually exists and is assignable for _, aID := range assigneeIDs { - assignee, err := user_model.GetUserByID(aID) + assignee, err := user_model.GetUserByID(ctx, aID) if err != nil { ctx.ServerError("GetUserByID", err) return nil, nil, 0, 0 @@ -1174,7 +1173,7 @@ func getBranchData(ctx *context.Context, issue *issues_model.Issue) { func ViewIssue(ctx *context.Context) { if ctx.Params(":type") == "issues" { // If issue was requested we check if repo has external tracker and redirect - extIssueUnit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalTracker) + extIssueUnit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalTracker) if err == nil && extIssueUnit != nil { if extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == markup.IssueNameStyleNumeric || extIssueUnit.ExternalTrackerConfig().ExternalTrackerStyle == "" { metas := ctx.Repo.Repository.ComposeMetas() @@ -1375,7 +1374,7 @@ func ViewIssue(ctx *context.Context) { comment *issues_model.Comment participants = make([]*user_model.User, 1, 10) ) - if ctx.Repo.Repository.IsTimetrackerEnabled() { + if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { if ctx.IsSigned { // Deal with the stopwatch ctx.Data["IsStopwatchRunning"] = issues_model.StopwatchExists(ctx.Doer.ID, issue.ID) @@ -1636,7 +1635,7 @@ func ViewIssue(ctx *context.Context) { } } - prUnit, err := repo.GetUnit(unit.TypePullRequests) + prUnit, err := repo.GetUnit(ctx, unit.TypePullRequests) if err != nil { ctx.ServerError("GetUnit", err) return @@ -1665,21 +1664,23 @@ func ViewIssue(ctx *context.Context) { ctx.Data["MergeStyle"] = mergeStyle - defaultMergeMessage, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle) + defaultMergeMessage, defaultMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, mergeStyle) if err != nil { ctx.ServerError("GetDefaultMergeMessage", err) return } ctx.Data["DefaultMergeMessage"] = defaultMergeMessage + ctx.Data["DefaultMergeBody"] = defaultMergeBody - defaultSquashMergeMessage, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) + defaultSquashMergeMessage, defaultSquashMergeBody, err := pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pull, repo_model.MergeStyleSquash) if err != nil { ctx.ServerError("GetDefaultSquashMergeMessage", err) return } ctx.Data["DefaultSquashMergeMessage"] = defaultSquashMergeMessage + ctx.Data["DefaultSquashMergeBody"] = defaultSquashMergeBody - if err = pull.LoadProtectedBranch(); err != nil { + if err = pull.LoadProtectedBranch(ctx); err != nil { ctx.ServerError("LoadProtectedBranch", err) return } @@ -2062,7 +2063,7 @@ func UpdateIssueAssignee(ctx *context.Context) { return } default: - assignee, err := user_model.GetUserByID(assigneeID) + assignee, err := user_model.GetUserByID(ctx, assigneeID) if err != nil { ctx.ServerError("GetUserByID", err) return @@ -2173,7 +2174,7 @@ func UpdatePullReviewRequest(ctx *context.Context) { continue } - reviewer, err := user_model.GetUserByID(reviewID) + reviewer, err := user_model.GetUserByID(ctx, reviewID) if err != nil { if user_model.IsErrUserNotExist(err) { log.Warn( @@ -2709,7 +2710,7 @@ func NewComment(ctx *context.Context) { return } - comment, err := comment_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments) + comment, err := issue_service.CreateIssueComment(ctx, ctx.Doer, ctx.Repo.Repository, issue, form.Content, attachments) if err != nil { ctx.ServerError("CreateIssueComment", err) return @@ -2749,7 +2750,7 @@ func UpdateCommentContent(ctx *context.Context) { }) return } - if err = comment_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { + if err = issue_service.UpdateComment(ctx, comment, ctx.Doer, oldContent); err != nil { ctx.ServerError("UpdateComment", err) return } @@ -2805,7 +2806,7 @@ func DeleteComment(ctx *context.Context) { return } - if err = comment_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { + if err = issue_service.DeleteComment(ctx, ctx.Doer, comment); err != nil { ctx.ServerError("DeleteComment", err) return } @@ -3027,7 +3028,7 @@ func filterXRefComments(ctx *context.Context, issue *issues_model.Issue) error { if issues_model.CommentTypeIsRef(c.Type) && c.RefRepoID != issue.RepoID && c.RefRepoID != 0 { var err error // Set RefRepo for description in template - c.RefRepo, err = repo_model.GetRepositoryByID(c.RefRepoID) + c.RefRepo, err = repo_model.GetRepositoryByID(ctx, c.RefRepoID) if err != nil { return err } @@ -3050,7 +3051,7 @@ func GetIssueAttachments(ctx *context.Context) { issue := GetActionIssue(ctx) attachments := make([]*api.Attachment, len(issue.Attachments)) for i := 0; i < len(issue.Attachments); i++ { - attachments[i] = convert.ToReleaseAttachment(issue.Attachments[i]) + attachments[i] = convert.ToAttachment(issue.Attachments[i]) } ctx.JSON(http.StatusOK, attachments) } @@ -3069,7 +3070,7 @@ func GetCommentAttachments(ctx *context.Context) { return } for i := 0; i < len(comment.Attachments); i++ { - attachments = append(attachments, convert.ToReleaseAttachment(comment.Attachments[i])) + attachments = append(attachments, convert.ToAttachment(comment.Attachments[i])) } } ctx.JSON(http.StatusOK, attachments) diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index dee506deacff..3e6b31f8f71b 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -5,16 +5,17 @@ package repo import ( "bytes" - "fmt" "html" "net/http" "strings" + "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" + "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/timeutil" "github.com/sergi/go-diff/diffmatchpatch" @@ -63,16 +64,20 @@ func GetContentHistoryList(ctx *context.Context) { } else { actionText = ctx.Locale.Tr("repo.issues.content_history.edited") } - timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, ctx.Locale) username := item.UserName if setting.UI.DefaultShowFullName && strings.TrimSpace(item.UserFullName) != "" { username = strings.TrimSpace(item.UserFullName) } + src := html.EscapeString(item.UserAvatarLink) + class := avatars.DefaultAvatarClass + " mr-3" + name := html.EscapeString(username) + avatarHTML := string(templates.AvatarHTML(src, 28, class, username)) + timeSinceText := string(timeutil.TimeSinceUnix(item.EditedUnix, ctx.Locale)) + results = append(results, map[string]interface{}{ - "name": fmt.Sprintf("%s %s %s", - html.EscapeString(item.UserAvatarLink), html.EscapeString(username), actionText, timeSinceText), + "name": avatarHTML + "" + name + " " + actionText + " " + timeSinceText, "value": item.HistoryID, }) } diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index 04271563973f..d712df1001bc 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -73,7 +73,7 @@ func Milestones(ctx *context.Context) { ctx.ServerError("GetMilestones", err) return } - if ctx.Repo.Repository.IsTimetrackerEnabled() { + if ctx.Repo.Repository.IsTimetrackerEnabled(ctx) { if err := miles.LoadTotalTrackedTimes(); err != nil { ctx.ServerError("LoadTotalTrackedTimes", err) return diff --git a/routers/web/repo/packages.go b/routers/web/repo/packages.go index 83324711da72..6ad2f71b5c2d 100644 --- a/routers/web/repo/packages.go +++ b/routers/web/repo/packages.go @@ -61,6 +61,7 @@ func Packages(ctx *context.Context) { ctx.Data["ContextUser"] = ctx.ContextUser ctx.Data["Query"] = query ctx.Data["PackageType"] = packageType + ctx.Data["AvailableTypes"] = packages.TypeList ctx.Data["HasPackages"] = hasPackages if ctx.Repo != nil { ctx.Data["CanWritePackages"] = ctx.IsUserRepoWriter([]unit.Type{unit.TypePackages}) || ctx.IsUserSiteAdmin() diff --git a/routers/web/repo/patch.go b/routers/web/repo/patch.go index 27199ba41096..12b26f38e901 100644 --- a/routers/web/repo/patch.go +++ b/routers/web/repo/patch.go @@ -108,7 +108,7 @@ func NewDiffPatchPost(ctx *context.Context) { } } - if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(unit.TypePullRequests) { + if form.CommitChoice == frmCommitChoiceNewBranch && ctx.Repo.Repository.UnitEnabled(ctx, unit.TypePullRequests) { ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ctx.Repo.BranchName) + "..." + util.PathEscapeSegments(form.NewBranchName)) } else { ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index 73f0916346b4..75cd290b8f0c 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -196,7 +196,7 @@ func DeleteProject(ctx *context.Context) { return } - if err := project_model.DeleteProjectByID(p.ID); err != nil { + if err := project_model.DeleteProjectByID(ctx, p.ID); err != nil { ctx.Flash.Error("DeleteProjectByID: " + err.Error()) } else { ctx.Flash.Success(ctx.Tr("repo.projects.deletion_success")) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 682bc64ca29d..a18f9f6a56a5 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -78,7 +78,7 @@ var pullRequestTemplateCandidates = []string{ } func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository { - repo, err := repo_model.GetRepositoryByID(repoID) + repo, err := repo_model.GetRepositoryByID(ctx, repoID) if err != nil { if repo_model.IsErrRepoNotExist(err) { ctx.NotFound("GetRepositoryByID", nil) @@ -159,7 +159,7 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { if !traverseParentRepo.IsFork { break } - traverseParentRepo, err = repo_model.GetRepositoryByID(traverseParentRepo.ForkID) + traverseParentRepo, err = repo_model.GetRepositoryByID(ctx, traverseParentRepo.ForkID) if err != nil { ctx.ServerError("GetRepositoryByID", err) return nil @@ -182,6 +182,15 @@ func getForkRepository(ctx *context.Context) *repo_model.Repository { func Fork(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("new_fork") + if ctx.Doer.CanForkRepo() { + ctx.Data["CanForkRepo"] = true + } else { + maxCreationLimit := ctx.Doer.MaxCreationLimit() + msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit) + ctx.Data["Flash"] = ctx.Flash + ctx.Flash.Error(msg) + } + getForkRepository(ctx) if ctx.Written() { return @@ -227,7 +236,7 @@ func ForkPost(ctx *context.Context) { if !traverseParentRepo.IsFork { break } - traverseParentRepo, err = repo_model.GetRepositoryByID(traverseParentRepo.ForkID) + traverseParentRepo, err = repo_model.GetRepositoryByID(ctx, traverseParentRepo.ForkID) if err != nil { ctx.ServerError("GetRepositoryByID", err) return @@ -254,6 +263,10 @@ func ForkPost(ctx *context.Context) { if err != nil { ctx.Data["Err_RepoName"] = true switch { + case repo_model.IsErrReachLimitOfRepo(err): + maxCreationLimit := ctxUser.MaxCreationLimit() + msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit) + ctx.RenderWithErr(msg, tplFork, &form) case repo_model.IsErrRepoAlreadyExist(err): ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplFork, &form) case db.IsErrNameReserved(err): @@ -427,7 +440,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *issues_model.Issue) *git.C setMergeTarget(ctx, pull) - if err := pull.LoadProtectedBranch(); err != nil { + if err := pull.LoadProtectedBranch(ctx); err != nil { ctx.ServerError("LoadProtectedBranch", err) return nil } @@ -739,7 +752,7 @@ func ViewPullFiles(ctx *context.Context) { return } - if err = pull.LoadProtectedBranch(); err != nil { + if err = pull.LoadProtectedBranch(ctx); err != nil { ctx.ServerError("LoadProtectedBranch", err) return } @@ -973,7 +986,7 @@ func MergePullRequest(ctx *context.Context) { message := strings.TrimSpace(form.MergeTitleField) if len(message) == 0 { var err error - message, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) + message, _, err = pull_service.GetDefaultMergeMessage(ctx, ctx.Repo.GitRepo, pr, repo_model.MergeStyle(form.Do)) if err != nil { ctx.ServerError("GetDefaultMergeMessage", err) return diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 9ef44eb58237..54f503642bc9 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/routers/web/feed" "code.gitea.io/gitea/services/forms" releaseservice "code.gitea.io/gitea/services/release" ) @@ -135,7 +136,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { return } - count, err := repo_model.GetReleaseCountByRepoID(ctx.Repo.Repository.ID, opts) + count, err := repo_model.GetReleaseCountByRepoID(ctx, ctx.Repo.Repository.ID, opts) if err != nil { ctx.ServerError("GetReleaseCountByRepoID", err) return @@ -156,7 +157,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { for _, r := range releases { if r.Publisher, ok = cacheUsers[r.PublisherID]; !ok { - r.Publisher, err = user_model.GetUserByID(r.PublisherID) + r.Publisher, err = user_model.GetUserByID(ctx, r.PublisherID) if err != nil { if user_model.IsErrUserNotExist(err) { r.Publisher = user_model.NewGhostUser() @@ -199,6 +200,30 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { ctx.HTML(http.StatusOK, tplReleases) } +// ReleasesFeedRSS get feeds for releases in RSS format +func ReleasesFeedRSS(ctx *context.Context) { + releasesOrTagsFeed(ctx, true, "rss") +} + +// TagsListFeedRSS get feeds for tags in RSS format +func TagsListFeedRSS(ctx *context.Context) { + releasesOrTagsFeed(ctx, false, "rss") +} + +// ReleasesFeedAtom get feeds for releases in Atom format +func ReleasesFeedAtom(ctx *context.Context) { + releasesOrTagsFeed(ctx, true, "atom") +} + +// TagsListFeedAtom get feeds for tags in RSS format +func TagsListFeedAtom(ctx *context.Context) { + releasesOrTagsFeed(ctx, false, "atom") +} + +func releasesOrTagsFeed(ctx *context.Context, isReleasesOnly bool, formatType string) { + feed.ShowReleaseFeed(ctx, ctx.Repo.Repository, isReleasesOnly, formatType) +} + // SingleRelease renders a single release's page func SingleRelease(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.release.releases") @@ -223,7 +248,7 @@ func SingleRelease(ctx *context.Context) { return } - release.Publisher, err = user_model.GetUserByID(release.PublisherID) + release.Publisher, err = user_model.GetUserByID(ctx, release.PublisherID) if err != nil { if user_model.IsErrUserNotExist(err) { release.Publisher = user_model.NewGhostUser() diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 0a8a1eb4e8ba..f9c67f170bec 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -19,7 +19,6 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" @@ -27,6 +26,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" repo_service "code.gitea.io/gitea/services/repository" archiver_service "code.gitea.io/gitea/services/repository/archiver" @@ -83,7 +83,7 @@ func checkContextUser(ctx *context.Context, uid int64) *user_model.User { return ctx.Doer } - org, err := user_model.GetUserByID(uid) + org, err := user_model.GetUserByID(ctx, uid) if user_model.IsErrUserNotExist(err) { return ctx.Doer } @@ -149,7 +149,7 @@ func Create(ctx *context.Context) { ctx.Data["repo_template_name"] = ctx.Tr("repo.template_select") templateID := ctx.FormInt64("template_id") if templateID > 0 { - templateRepo, err := repo_model.GetRepositoryByID(templateID) + templateRepo, err := repo_model.GetRepositoryByID(ctx, templateID) if err == nil && access_model.CheckRepoUnitUser(ctx, templateRepo, ctxUser, unit.TypeCode) { ctx.Data["repo_template"] = templateID ctx.Data["repo_template_name"] = templateRepo.Name @@ -314,12 +314,12 @@ func Action(ctx *context.Context) { } func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { return err } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { return err } @@ -333,7 +333,7 @@ func acceptOrRejectRepoTransfer(ctx *context.Context, accept bool) error { ctx.Repo.GitRepo = nil } - if err := repo_service.TransferOwnership(repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil { + if err := repo_service.TransferOwnership(ctx, repoTransfer.Doer, repoTransfer.Recipient, ctx.Repo.Repository, repoTransfer.Teams); err != nil { return err } ctx.Flash.Success(ctx.Tr("repo.settings.transfer.success")) diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go index 9e47d0bb1248..913ed6c7cb8e 100644 --- a/routers/web/repo/setting.go +++ b/routers/web/repo/setting.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" + secret_model "code.gitea.io/gitea/models/secret" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" @@ -397,6 +398,15 @@ func SettingsPost(ctx *context.Context) { repoChanged = true } + if form.EnableCode && !unit_model.TypeCode.UnitGlobalDisabled() { + units = append(units, repo_model.RepoUnit{ + RepoID: repo.ID, + Type: unit_model.TypeCode, + }) + } else if !unit_model.TypeCode.UnitGlobalDisabled() { + deleteUnitTypes = append(deleteUnitTypes, unit_model.TypeCode) + } + if form.EnableWiki && form.EnableExternalWiki && !unit_model.TypeExternalWiki.UnitGlobalDisabled() { if !validation.IsValidExternalURL(form.ExternalWikiURL) { ctx.Flash.Error(ctx.Tr("repo.settings.external_wiki_url_error")) @@ -689,7 +699,7 @@ func SettingsPost(ctx *context.Context) { ctx.Repo.GitRepo = nil } - if err := repo_service.StartRepositoryTransfer(ctx.Doer, newOwner, repo, nil); err != nil { + if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil { if repo_model.IsErrRepoAlreadyExist(err) { ctx.RenderWithErr(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) } else if models.IsErrRepoTransferInProgress(err) { @@ -711,7 +721,7 @@ func SettingsPost(ctx *context.Context) { return } - repoTransfer, err := models.GetPendingRepositoryTransfer(ctx.Repo.Repository) + repoTransfer, err := models.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository) if err != nil { if models.IsErrNoPendingTransfer(err) { ctx.Flash.Error("repo.settings.transfer_abort_invalid") @@ -723,7 +733,7 @@ func SettingsPost(ctx *context.Context) { return } - if err := repoTransfer.LoadAttributes(); err != nil { + if err := repoTransfer.LoadAttributes(ctx); err != nil { ctx.ServerError("LoadRecipient", err) return } @@ -929,7 +939,7 @@ func CollaborationPost(ctx *context.Context) { } } - if err = repo_module.AddCollaborator(ctx.Repo.Repository, u); err != nil { + if err = repo_module.AddCollaborator(ctx, ctx.Repo.Repository, u); err != nil { ctx.ServerError("AddCollaborator", err) return } @@ -945,6 +955,7 @@ func CollaborationPost(ctx *context.Context) { // ChangeCollaborationAccessMode response for changing access of a collaboration func ChangeCollaborationAccessMode(ctx *context.Context) { if err := repo_model.ChangeCollaborationAccessMode( + ctx, ctx.Repo.Repository, ctx.FormInt64("uid"), perm.AccessMode(ctx.FormInt("mode"))); err != nil { @@ -1103,12 +1114,37 @@ func DeployKeys(ctx *context.Context) { } ctx.Data["Deploykeys"] = keys + secrets, err := secret_model.FindSecrets(ctx, secret_model.FindSecretsOptions{RepoID: ctx.Repo.Repository.ID}) + if err != nil { + ctx.ServerError("FindSecrets", err) + return + } + ctx.Data["Secrets"] = secrets + ctx.HTML(http.StatusOK, tplDeployKeys) } +// SecretsPost response for creating a new secret +func SecretsPost(ctx *context.Context) { + form := web.GetForm(ctx).(*forms.AddSecretForm) + + _, err := secret_model.InsertEncryptedSecret(ctx, 0, ctx.Repo.Repository.ID, form.Title, form.Content) + if err != nil { + ctx.Flash.Error(ctx.Tr("secrets.creation.failed")) + log.Error("validate secret: %v", err) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys") + return + } + + log.Trace("Secret added: %d", ctx.Repo.Repository.ID) + ctx.Flash.Success(ctx.Tr("secrets.creation.success", form.Title)) + ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys") +} + // DeployKeysPost response for adding a deploy key of a repository func DeployKeysPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.AddKeyForm) + ctx.Data["Title"] = ctx.Tr("repo.settings.deploy_keys") ctx.Data["PageIsSettingsKeys"] = true ctx.Data["DisableSSH"] = setting.SSH.Disabled @@ -1167,6 +1203,20 @@ func DeployKeysPost(ctx *context.Context) { ctx.Redirect(ctx.Repo.RepoLink + "/settings/keys") } +func DeleteSecret(ctx *context.Context) { + id := ctx.FormInt64("id") + if _, err := db.DeleteByBean(ctx, &secret_model.Secret{ID: id}); err != nil { + ctx.Flash.Error(ctx.Tr("secrets.deletion.failed")) + log.Error("delete secret %d: %v", id, err) + } else { + ctx.Flash.Success(ctx.Tr("secrets.deletion.success")) + } + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "redirect": ctx.Repo.RepoLink + "/settings/keys", + }) +} + // DeleteDeployKey response for deleting a deploy key func DeleteDeployKey(ctx *context.Context) { if err := asymkey_service.DeleteDeployKey(ctx.Doer, ctx.FormInt64("id")); err != nil { diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index c7f97410ff60..915944e4d5db 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -9,7 +9,6 @@ import ( gocontext "context" "encoding/base64" "fmt" - gotemplate "html/template" "io" "net/http" "net/url" @@ -241,18 +240,19 @@ func findReadmeFile(ctx *context.Context, entries git.Entries, treeLink string) return readmeFile, readmeTreelink } -func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelink string) { - ctx.Data["RawFileLink"] = "" - ctx.Data["ReadmeInList"] = true - ctx.Data["ReadmeExist"] = true - ctx.Data["FileIsSymlink"] = readmeFile.isSymlink +type fileInfo struct { + isTextFile bool + isLFSFile bool + fileSize int64 + lfsMeta *lfs.Pointer + st typesniffer.SniffedType +} - dataRc, err := readmeFile.blob.DataAsync() +func getFileReader(repoID int64, blob *git.Blob) ([]byte, io.ReadCloser, *fileInfo, error) { + dataRc, err := blob.DataAsync() if err != nil { - ctx.ServerError("Data", err) - return + return nil, nil, nil, err } - defer dataRc.Close() buf := make([]byte, 1024) n, _ := util.ReadAtMost(dataRc, buf) @@ -261,67 +261,75 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin st := typesniffer.DetectContentType(buf) isTextFile := st.IsText() - ctx.Data["FileIsText"] = isTextFile - ctx.Data["FileName"] = readmeFile.name - fileSize := int64(0) - isLFSFile := false - ctx.Data["IsLFSFile"] = false - // FIXME: what happens when README file is an image? - if isTextFile && setting.LFS.StartServer { - pointer, _ := lfs.ReadPointerFromBuffer(buf) - if pointer.IsValid() { - meta, err := git_model.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, pointer.Oid) - if err != nil && err != git_model.ErrLFSObjectNotExist { - ctx.ServerError("GetLFSMetaObject", err) - return - } - if meta != nil { - ctx.Data["IsLFSFile"] = true - isLFSFile = true + if !isTextFile || !setting.LFS.StartServer { + return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil + } - // OK read the lfs object - var err error - dataRc, err = lfs.ReadMetaObject(pointer) - if err != nil { - ctx.ServerError("ReadMetaObject", err) - return - } - defer dataRc.Close() + pointer, _ := lfs.ReadPointerFromBuffer(buf) + if !pointer.IsValid() { // fallback to plain file + return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil + } - buf = make([]byte, 1024) - n, err = util.ReadAtMost(dataRc, buf) - if err != nil { - ctx.ServerError("Data", err) - return - } - buf = buf[:n] + meta, err := git_model.GetLFSMetaObjectByOid(repoID, pointer.Oid) + if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file + return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil + } - st = typesniffer.DetectContentType(buf) - isTextFile = st.IsText() - ctx.Data["IsTextFile"] = isTextFile + dataRc.Close() + if err != nil { + return nil, nil, nil, err + } - fileSize = meta.Size - ctx.Data["FileSize"] = meta.Size - filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name)) - ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.HTMLURL(), url.PathEscape(meta.Oid), url.PathEscape(filenameBase64)) - } - } + dataRc, err = lfs.ReadMetaObject(pointer) + if err != nil { + return nil, nil, nil, err } - if !isTextFile { + buf = make([]byte, 1024) + n, err = util.ReadAtMost(dataRc, buf) + if err != nil { + dataRc.Close() + return nil, nil, nil, err + } + buf = buf[:n] + + st = typesniffer.DetectContentType(buf) + + return buf, dataRc, &fileInfo{st.IsText(), true, meta.Size, &meta.Pointer, st}, nil +} + +func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelink string) { + ctx.Data["RawFileLink"] = "" + ctx.Data["ReadmeInList"] = true + ctx.Data["ReadmeExist"] = true + ctx.Data["FileIsSymlink"] = readmeFile.isSymlink + + buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, readmeFile.blob) + if err != nil { + ctx.ServerError("getFileReader", err) return } + defer dataRc.Close() + + ctx.Data["FileIsText"] = fInfo.isTextFile + ctx.Data["FileName"] = readmeFile.name + ctx.Data["IsLFSFile"] = fInfo.isLFSFile + + if fInfo.isLFSFile { + filenameBase64 := base64.RawURLEncoding.EncodeToString([]byte(readmeFile.name)) + ctx.Data["RawFileLink"] = fmt.Sprintf("%s.git/info/lfs/objects/%s/%s", ctx.Repo.Repository.HTMLURL(), url.PathEscape(fInfo.lfsMeta.Oid), url.PathEscape(filenameBase64)) + } - if !isLFSFile { - fileSize = readmeFile.blob.Size() + if !fInfo.isTextFile { + return } - if fileSize >= setting.UI.MaxDisplayFileSize { + if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { // Pretend that this is a normal text file to display 'This file is too large to be shown' ctx.Data["IsFileTooLarge"] = true ctx.Data["IsTextFile"] = true - ctx.Data["FileSize"] = fileSize + ctx.Data["FileSize"] = fInfo.fileSize return } @@ -341,15 +349,13 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin if err != nil { log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.name, ctx.Repo.Repository, err) buf := &bytes.Buffer{} - ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale) - ctx.Data["FileContent"] = strings.ReplaceAll( - gotemplate.HTMLEscapeString(buf.String()), "\n", `
`, - ) + ctx.Data["EscapeStatus"], _ = charset.EscapeControlStringReader(rd, buf, ctx.Locale) + ctx.Data["FileContent"] = buf.String() } } else { - ctx.Data["IsRenderedHTML"] = true + ctx.Data["IsPlainText"] = true buf := &bytes.Buffer{} - ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, &charset.BreakWriter{Writer: buf}, ctx.Locale, charset.RuneNBSP) + ctx.Data["EscapeStatus"], err = charset.EscapeControlStringReader(rd, buf, ctx.Locale) if err != nil { log.Error("Read failed: %v", err) } @@ -362,16 +368,14 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsViewFile"] = true ctx.Data["HideRepoInfo"] = true blob := entry.Blob() - dataRc, err := blob.DataAsync() + buf, dataRc, fInfo, err := getFileReader(ctx.Repo.Repository.ID, blob) if err != nil { - ctx.ServerError("DataAsync", err) + ctx.ServerError("getFileReader", err) return } defer dataRc.Close() ctx.Data["Title"] = ctx.Tr("repo.file.title", ctx.Repo.Repository.Name+"/"+path.Base(ctx.Repo.TreePath), ctx.Repo.RefName) - - fileSize := blob.Size() ctx.Data["FileIsSymlink"] = entry.IsLink() ctx.Data["FileName"] = blob.Name() ctx.Data["RawFileLink"] = rawLink + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) @@ -381,69 +385,27 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["FileError"] = editorconfigErr } - buf := make([]byte, 1024) - n, _ := util.ReadAtMost(dataRc, buf) - buf = buf[:n] - - st := typesniffer.DetectContentType(buf) - isTextFile := st.IsText() - - isLFSFile := false isDisplayingSource := ctx.FormString("display") == "source" isDisplayingRendered := !isDisplayingSource - // Check for LFS meta file - if isTextFile && setting.LFS.StartServer { - pointer, _ := lfs.ReadPointerFromBuffer(buf) - if pointer.IsValid() { - meta, err := git_model.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, pointer.Oid) - if err != nil && err != git_model.ErrLFSObjectNotExist { - ctx.ServerError("GetLFSMetaObject", err) - return - } - if meta != nil { - isLFSFile = true - - // OK read the lfs object - var err error - dataRc, err = lfs.ReadMetaObject(pointer) - if err != nil { - ctx.ServerError("ReadMetaObject", err) - return - } - defer dataRc.Close() - - buf = make([]byte, 1024) - n, err = util.ReadAtMost(dataRc, buf) - if err != nil { - ctx.ServerError("Data", err) - return - } - buf = buf[:n] - - st = typesniffer.DetectContentType(buf) - isTextFile = st.IsText() - - fileSize = meta.Size - ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/media/" + ctx.Repo.BranchNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) - } - } + if fInfo.isLFSFile { + ctx.Data["RawFileLink"] = ctx.Repo.RepoLink + "/media/" + ctx.Repo.BranchNameSubURL() + "/" + util.PathEscapeSegments(ctx.Repo.TreePath) } - isRepresentableAsText := st.IsRepresentableAsText() + isRepresentableAsText := fInfo.st.IsRepresentableAsText() if !isRepresentableAsText { // If we can't show plain text, always try to render. isDisplayingSource = false isDisplayingRendered = true } - ctx.Data["IsLFSFile"] = isLFSFile - ctx.Data["FileSize"] = fileSize - ctx.Data["IsTextFile"] = isTextFile + ctx.Data["IsLFSFile"] = fInfo.isLFSFile + ctx.Data["FileSize"] = fInfo.fileSize + ctx.Data["IsTextFile"] = fInfo.isTextFile ctx.Data["IsRepresentableAsText"] = isRepresentableAsText ctx.Data["IsDisplayingSource"] = isDisplayingSource ctx.Data["IsDisplayingRendered"] = isDisplayingRendered - isTextSource := isTextFile || isDisplayingSource + isTextSource := fInfo.isTextFile || isDisplayingSource ctx.Data["IsTextSource"] = isTextSource if isTextSource { ctx.Data["CanCopyContent"] = true @@ -457,7 +419,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st return } if lfsLock != nil { - u, err := user_model.GetUserByID(lfsLock.OwnerID) + u, err := user_model.GetUserByID(ctx, lfsLock.OwnerID) if err != nil { ctx.ServerError("GetTreePathLock", err) return @@ -468,7 +430,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } // Assume file is not editable first. - if isLFSFile { + if fInfo.isLFSFile { ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.cannot_edit_lfs_files") } else if !isRepresentableAsText { ctx.Data["EditFileTooltip"] = ctx.Tr("repo.editor.cannot_edit_non_text_files") @@ -476,13 +438,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st switch { case isRepresentableAsText: - if st.IsSvgImage() { + if fInfo.st.IsSvgImage() { ctx.Data["IsImageFile"] = true ctx.Data["CanCopyContent"] = true ctx.Data["HasSourceRenderedToggle"] = true } - if fileSize >= setting.UI.MaxDisplayFileSize { + if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { ctx.Data["IsFileTooLarge"] = true break } @@ -527,15 +489,6 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } // to prevent iframe load third-party url ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'") - } else if readmeExist && !shouldRenderSource { - buf := &bytes.Buffer{} - ctx.Data["IsRenderedHTML"] = true - - ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale) - - ctx.Data["FileContent"] = strings.ReplaceAll( - gotemplate.HTMLEscapeString(buf.String()), "\n", `
`, - ) } else { buf, _ := io.ReadAll(rd) @@ -589,7 +542,7 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["FileContent"] = fileContent ctx.Data["LineEscapeStatus"] = statuses } - if !isLFSFile { + if !fInfo.isLFSFile { if ctx.Repo.CanEnableEditor(ctx.Doer) { if lfsLock != nil && lfsLock.OwnerID != ctx.Doer.ID { ctx.Data["CanEditFile"] = false @@ -605,17 +558,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st } } - case st.IsPDF(): + case fInfo.st.IsPDF(): ctx.Data["IsPDFFile"] = true - case st.IsVideo(): + case fInfo.st.IsVideo(): ctx.Data["IsVideoFile"] = true - case st.IsAudio(): + case fInfo.st.IsAudio(): ctx.Data["IsAudioFile"] = true - case st.IsImage() && (setting.UI.SVG.Enabled || !st.IsSvgImage()): + case fInfo.st.IsImage() && (setting.UI.SVG.Enabled || !fInfo.st.IsSvgImage()): ctx.Data["IsImageFile"] = true ctx.Data["CanCopyContent"] = true default: - if fileSize >= setting.UI.MaxDisplayFileSize { + if fInfo.fileSize >= setting.UI.MaxDisplayFileSize { ctx.Data["IsFileTooLarge"] = true break } diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index 677fbc92ed3e..2b6f107fafd1 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -17,13 +17,13 @@ import ( "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" + "code.gitea.io/gitea/services/convert" "code.gitea.io/gitea/services/forms" webhook_service "code.gitea.io/gitea/services/webhook" ) @@ -684,7 +684,7 @@ func TestWebhook(ctx *context.Context) { Commits: []*api.PayloadCommit{apiCommit}, TotalCommits: 1, HeadCommit: apiCommit, - Repo: convert.ToRepo(ctx.Repo.Repository, perm.AccessModeNone), + Repo: convert.ToRepo(ctx, ctx.Repo.Repository, perm.AccessModeNone), Pusher: apiUser, Sender: apiUser, } diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 885f84543c83..b50a4be80204 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -59,7 +59,7 @@ func MustEnableWiki(ctx *context.Context) { return } - unit, err := ctx.Repo.Repository.GetUnit(unit.TypeExternalWiki) + unit, err := ctx.Repo.Repository.GetUnit(ctx, unit.TypeExternalWiki) if err == nil { ctx.Redirect(unit.ExternalWikiConfig().ExternalWikiURL) return diff --git a/routers/web/shared/packages/packages.go b/routers/web/shared/packages/packages.go index 5e934d707ee4..b9aa40bdd22b 100644 --- a/routers/web/shared/packages/packages.go +++ b/routers/web/shared/packages/packages.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package packages diff --git a/routers/web/user/home.go b/routers/web/user/home.go index fc4c919de355..36d9d4f019f7 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -231,7 +231,7 @@ func Milestones(ctx *context.Context) { return } - if milestones[i].Repo.IsTimetrackerEnabled() { + if milestones[i].Repo.IsTimetrackerEnabled(ctx) { err := milestones[i].LoadTotalTrackedTime() if err != nil { ctx.ServerError("LoadTotalTrackedTime", err) diff --git a/routers/web/user/home_test.go b/routers/web/user/home_test.go index a75b3573a00d..534b0b26207b 100644 --- a/routers/web/user/home_test.go +++ b/routers/web/user/home_test.go @@ -26,7 +26,7 @@ func TestArchivedIssues(t *testing.T) { // Assume: User 30 has access to two Repos with Issues, one of the Repos being archived. repos, _, _ := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{Actor: ctx.Doer}) - assert.Len(t, repos, 2) + assert.Len(t, repos, 3) IsArchived := make(map[int64]bool) NumIssues := make(map[int64]int) for _, repo := range repos { diff --git a/routers/web/user/package.go b/routers/web/user/package.go index ae4c239c70cc..c0aba7583fc0 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -89,6 +89,7 @@ func ListPackages(ctx *context.Context) { ctx.Data["ContextUser"] = ctx.ContextUser ctx.Data["Query"] = query ctx.Data["PackageType"] = packageType + ctx.Data["AvailableTypes"] = packages_model.TypeList ctx.Data["HasPackages"] = hasPackages ctx.Data["PackageDescriptors"] = pds ctx.Data["Total"] = total @@ -336,7 +337,7 @@ func PackageSettingsPost(ctx *context.Context) { success := func() bool { repoID := int64(0) if form.RepoID != 0 { - repo, err := repo_model.GetRepositoryByID(form.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, form.RepoID) if err != nil { log.Error("Error getting repository: %v", err) return false diff --git a/routers/web/user/search.go b/routers/web/user/search.go index 093de406a978..f9b0e0735864 100644 --- a/routers/web/user/search.go +++ b/routers/web/user/search.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/services/convert" ) // Search search users diff --git a/routers/web/user/setting/packages.go b/routers/web/user/setting/packages.go index d44e904556d2..f6f7195adf1f 100644 --- a/routers/web/user/setting/packages.go +++ b/routers/web/user/setting/packages.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package setting diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index e46724f2e74e..ef45ad8a862d 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -323,7 +323,7 @@ func Repos(ctx *context.Context) { } for _, repo := range userRepos { if repo.IsFork { - if err := repo.GetBaseRepo(); err != nil { + if err := repo.GetBaseRepo(ctx); err != nil { ctx.ServerError("GetBaseRepo", err) return } @@ -342,7 +342,7 @@ func Repos(ctx *context.Context) { for i := range repos { if repos[i].IsFork { - if err := repos[i].GetBaseRepo(); err != nil { + if err := repos[i].GetBaseRepo(ctx); err != nil { ctx.ServerError("GetBaseRepo", err) return } diff --git a/routers/web/user/stop_watch.go b/routers/web/user/stop_watch.go index 26c7558c115e..d262c777c30f 100644 --- a/routers/web/user/stop_watch.go +++ b/routers/web/user/stop_watch.go @@ -9,7 +9,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" + "code.gitea.io/gitea/services/convert" ) // GetStopwatches get all stopwatches diff --git a/routers/web/web.go b/routers/web/web.go index 773289ecf6f8..d5cc19574e51 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -234,8 +234,6 @@ func RegisterRoutes(m *web.Route) { ignExploreSignIn := context.Toggle(&context.ToggleOptions{SignInRequired: setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView}) ignSignInAndCsrf := context.Toggle(&context.ToggleOptions{DisableCSRF: true}) reqSignOut := context.Toggle(&context.ToggleOptions{SignOutRequired: true}) - - bindIgnErr := web.Bind validation.AddBindingRules() linkAccountEnabled := func(ctx *context.Context) { @@ -357,37 +355,37 @@ func RegisterRoutes(m *web.Route) { m.Get("/user/kitspace/session", auth.GetKitspaceSession) m.Group("/user", func() { m.Group("/kitspace", func() { - m.Post("/sign_up", bindIgnErr(forms.RegisterForm{}), auth.KitspaceSignUp) - m.Post("/sign_in", bindIgnErr(forms.SignInForm{}), auth.KitspaceSignIn) + m.Post("/sign_up", web.Bind(forms.RegisterForm{}), auth.KitspaceSignUp) + m.Post("/sign_in", web.Bind(forms.SignInForm{}), auth.KitspaceSignIn) }) m.Get("/login", auth.SignIn) - m.Post("/login", bindIgnErr(forms.SignInForm{}), auth.SignInPost) + m.Post("/login", web.Bind(forms.SignInForm{}), auth.SignInPost) m.Group("", func() { m.Combo("/login/openid"). Get(auth.SignInOpenID). - Post(bindIgnErr(forms.SignInOpenIDForm{}), auth.SignInOpenIDPost) + Post(web.Bind(forms.SignInOpenIDForm{}), auth.SignInOpenIDPost) }, openIDSignInEnabled) m.Group("/openid", func() { m.Combo("/connect"). Get(auth.ConnectOpenID). - Post(bindIgnErr(forms.ConnectOpenIDForm{}), auth.ConnectOpenIDPost) + Post(web.Bind(forms.ConnectOpenIDForm{}), auth.ConnectOpenIDPost) m.Group("/register", func() { m.Combo(""). Get(auth.RegisterOpenID, openIDSignUpEnabled). - Post(bindIgnErr(forms.SignUpOpenIDForm{}), auth.RegisterOpenIDPost) + Post(web.Bind(forms.SignUpOpenIDForm{}), auth.RegisterOpenIDPost) }, openIDSignUpEnabled) }, openIDSignInEnabled) m.Get("/sign_up", auth.SignUp) - m.Post("/sign_up", bindIgnErr(forms.RegisterForm{}), auth.SignUpPost) + m.Post("/sign_up", web.Bind(forms.RegisterForm{}), auth.SignUpPost) m.Get("/link_account", linkAccountEnabled, auth.LinkAccount) - m.Post("/link_account_signin", linkAccountEnabled, bindIgnErr(forms.SignInForm{}), auth.LinkAccountPostSignIn) - m.Post("/link_account_signup", linkAccountEnabled, bindIgnErr(forms.RegisterForm{}), auth.LinkAccountPostRegister) + m.Post("/link_account_signin", linkAccountEnabled, web.Bind(forms.SignInForm{}), auth.LinkAccountPostSignIn) + m.Post("/link_account_signup", linkAccountEnabled, web.Bind(forms.RegisterForm{}), auth.LinkAccountPostRegister) m.Group("/two_factor", func() { m.Get("", auth.TwoFactor) - m.Post("", bindIgnErr(forms.TwoFactorAuthForm{}), auth.TwoFactorPost) + m.Post("", web.Bind(forms.TwoFactorAuthForm{}), auth.TwoFactorPost) m.Get("/scratch", auth.TwoFactorScratch) - m.Post("/scratch", bindIgnErr(forms.TwoFactorScratchAuthForm{}), auth.TwoFactorScratchPost) + m.Post("/scratch", web.Bind(forms.TwoFactorScratchAuthForm{}), auth.TwoFactorScratchPost) }) m.Group("/webauthn", func() { m.Get("", auth.WebAuthn) @@ -399,34 +397,34 @@ func RegisterRoutes(m *web.Route) { m.Any("/user/events", routing.MarkLongPolling, events.Events) m.Group("/login/oauth", func() { - m.Get("/authorize", bindIgnErr(forms.AuthorizationForm{}), auth.AuthorizeOAuth) - m.Post("/grant", bindIgnErr(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth) + m.Get("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) + m.Post("/grant", web.Bind(forms.GrantApplicationForm{}), auth.GrantApplicationOAuth) // TODO manage redirection - m.Post("/authorize", bindIgnErr(forms.AuthorizationForm{}), auth.AuthorizeOAuth) + m.Post("/authorize", web.Bind(forms.AuthorizationForm{}), auth.AuthorizeOAuth) }, ignSignInAndCsrf, reqSignIn) m.Get("/login/oauth/userinfo", ignSignInAndCsrf, auth.InfoOAuth) - m.Post("/login/oauth/access_token", CorsHandler(), bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth) + m.Post("/login/oauth/access_token", CorsHandler(), web.Bind(forms.AccessTokenForm{}), ignSignInAndCsrf, auth.AccessTokenOAuth) m.Get("/login/oauth/keys", ignSignInAndCsrf, auth.OIDCKeys) - m.Post("/login/oauth/introspect", CorsHandler(), bindIgnErr(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth) + m.Post("/login/oauth/introspect", CorsHandler(), web.Bind(forms.IntrospectTokenForm{}), ignSignInAndCsrf, auth.IntrospectOAuth) m.Group("/user/settings", func() { m.Get("", user_setting.Profile) - m.Post("", bindIgnErr(forms.UpdateProfileForm{}), user_setting.ProfilePost) + m.Post("", web.Bind(forms.UpdateProfileForm{}), user_setting.ProfilePost) m.Get("/change_password", auth.MustChangePassword) - m.Post("/change_password", bindIgnErr(forms.MustChangePasswordForm{}), auth.MustChangePasswordPost) - m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), user_setting.AvatarPost) + m.Post("/change_password", web.Bind(forms.MustChangePasswordForm{}), auth.MustChangePasswordPost) + m.Post("/avatar", web.Bind(forms.AvatarForm{}), user_setting.AvatarPost) m.Post("/avatar/delete", user_setting.DeleteAvatar) m.Group("/account", func() { - m.Combo("").Get(user_setting.Account).Post(bindIgnErr(forms.ChangePasswordForm{}), user_setting.AccountPost) - m.Post("/email", bindIgnErr(forms.AddEmailForm{}), user_setting.EmailPost) + m.Combo("").Get(user_setting.Account).Post(web.Bind(forms.ChangePasswordForm{}), user_setting.AccountPost) + m.Post("/email", web.Bind(forms.AddEmailForm{}), user_setting.EmailPost) m.Post("/email/delete", user_setting.DeleteEmail) m.Post("/delete", user_setting.DeleteAccount) }) m.Group("/appearance", func() { m.Get("", user_setting.Appearance) - m.Post("/language", bindIgnErr(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang) + m.Post("/language", web.Bind(forms.UpdateLanguageForm{}), user_setting.UpdateUserLang) m.Post("/hidden_comments", user_setting.UpdateUserHiddenComments) - m.Post("/theme", bindIgnErr(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost) + m.Post("/theme", web.Bind(forms.UpdateThemeForm{}), user_setting.UpdateUIThemePost) }) m.Group("/security", func() { m.Get("", security.Security) @@ -434,15 +432,15 @@ func RegisterRoutes(m *web.Route) { m.Post("/regenerate_scratch", security.RegenerateScratchTwoFactor) m.Post("/disable", security.DisableTwoFactor) m.Get("/enroll", security.EnrollTwoFactor) - m.Post("/enroll", bindIgnErr(forms.TwoFactorAuthForm{}), security.EnrollTwoFactorPost) + m.Post("/enroll", web.Bind(forms.TwoFactorAuthForm{}), security.EnrollTwoFactorPost) }) m.Group("/webauthn", func() { - m.Post("/request_register", bindIgnErr(forms.WebauthnRegistrationForm{}), security.WebAuthnRegister) + m.Post("/request_register", web.Bind(forms.WebauthnRegistrationForm{}), security.WebAuthnRegister) m.Post("/register", security.WebauthnRegisterPost) - m.Post("/delete", bindIgnErr(forms.WebauthnDeleteForm{}), security.WebauthnDelete) + m.Post("/delete", web.Bind(forms.WebauthnDeleteForm{}), security.WebauthnDelete) }) m.Group("/openid", func() { - m.Post("", bindIgnErr(forms.AddOpenIDForm{}), security.OpenIDPost) + m.Post("", web.Bind(forms.AddOpenIDForm{}), security.OpenIDPost) m.Post("/delete", security.DeleteOpenID) m.Post("/toggle_visibility", security.ToggleOpenIDVisibility) }, openIDSignInEnabled) @@ -450,28 +448,28 @@ func RegisterRoutes(m *web.Route) { }) m.Group("/applications/oauth2", func() { m.Get("/{id}", user_setting.OAuth2ApplicationShow) - m.Post("/{id}", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit) + m.Post("/{id}", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit) m.Post("/{id}/regenerate_secret", user_setting.OAuthApplicationsRegenerateSecret) - m.Post("", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost) + m.Post("", web.Bind(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost) m.Post("/{id}/delete", user_setting.DeleteOAuth2Application) m.Post("/{id}/revoke/{grantId}", user_setting.RevokeOAuth2Grant) }) m.Combo("/applications").Get(user_setting.Applications). - Post(bindIgnErr(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost) + Post(web.Bind(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost) m.Post("/applications/delete", user_setting.DeleteApplication) m.Combo("/keys").Get(user_setting.Keys). - Post(bindIgnErr(forms.AddKeyForm{}), user_setting.KeysPost) + Post(web.Bind(forms.AddKeyForm{}), user_setting.KeysPost) m.Post("/keys/delete", user_setting.DeleteKey) m.Group("/packages", func() { m.Get("", user_setting.Packages) m.Group("/rules", func() { m.Group("/add", func() { m.Get("", user_setting.PackagesRuleAdd) - m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleAddPost) + m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleAddPost) }) m.Group("/{id}", func() { m.Get("", user_setting.PackagesRuleEdit) - m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleEditPost) + m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), user_setting.PackagesRuleEditPost) m.Get("/preview", user_setting.PackagesRulePreview) }) }) @@ -513,7 +511,7 @@ func RegisterRoutes(m *web.Route) { // ***** START: Admin ***** m.Group("/admin", func() { m.Get("", adminReq, admin.Dashboard) - m.Post("", adminReq, bindIgnErr(forms.AdminDashboardForm{}), admin.DashboardPost) + m.Post("", adminReq, web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost) m.Group("/config", func() { m.Get("", admin.Config) @@ -538,10 +536,10 @@ func RegisterRoutes(m *web.Route) { m.Group("/users", func() { m.Get("", admin.Users) - m.Combo("/new").Get(admin.NewUser).Post(bindIgnErr(forms.AdminCreateUserForm{}), admin.NewUserPost) - m.Combo("/{userid}").Get(admin.EditUser).Post(bindIgnErr(forms.AdminEditUserForm{}), admin.EditUserPost) + m.Combo("/new").Get(admin.NewUser).Post(web.Bind(forms.AdminCreateUserForm{}), admin.NewUserPost) + m.Combo("/{userid}").Get(admin.EditUser).Post(web.Bind(forms.AdminEditUserForm{}), admin.EditUserPost) m.Post("/{userid}/delete", admin.DeleteUser) - m.Post("/{userid}/avatar", bindIgnErr(forms.AvatarForm{}), admin.AvatarPost) + m.Post("/{userid}/avatar", web.Bind(forms.AvatarForm{}), admin.AvatarPost) m.Post("/{userid}/avatar/delete", admin.DeleteAvatar) }) @@ -572,39 +570,39 @@ func RegisterRoutes(m *web.Route) { m.Get("", repo.WebHooksEdit) m.Post("/replay/{uuid}", repo.ReplayWebhook) }) - m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) - m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost) - m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) - m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost) - m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) - m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost) - m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost) - m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) - m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) - m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) - m.Post("/packagist/{id}", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost) + m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) + m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost) + m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) + m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost) + m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) + m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost) + m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost) + m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) + m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) + m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) + m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost) }, webhooksEnabled) m.Group("/{configType:default-hooks|system-hooks}", func() { m.Get("/{type}/new", repo.WebhooksNew) - m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) - m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost) - m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) - m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost) - m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) - m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost) - m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost) - m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) - m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) - m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) - m.Post("/packagist/new", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost) + m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) + m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost) + m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) + m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost) + m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) + m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost) + m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost) + m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) + m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) + m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) + m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost) }) m.Group("/auths", func() { m.Get("", admin.Authentications) - m.Combo("/new").Get(admin.NewAuthSource).Post(bindIgnErr(forms.AuthenticationForm{}), admin.NewAuthSourcePost) + m.Combo("/new").Get(admin.NewAuthSource).Post(web.Bind(forms.AuthenticationForm{}), admin.NewAuthSourcePost) m.Combo("/{authid}").Get(admin.EditAuthSource). - Post(bindIgnErr(forms.AuthenticationForm{}), admin.EditAuthSourcePost) + Post(web.Bind(forms.AuthenticationForm{}), admin.EditAuthSourcePost) m.Post("/{authid}/delete", admin.DeleteAuthSource) }) @@ -616,9 +614,9 @@ func RegisterRoutes(m *web.Route) { m.Group("/applications", func() { m.Get("", admin.Applications) - m.Post("/oauth2", bindIgnErr(forms.EditOAuth2ApplicationForm{}), admin.ApplicationsPost) + m.Post("/oauth2", web.Bind(forms.EditOAuth2ApplicationForm{}), admin.ApplicationsPost) m.Group("/oauth2/{id}", func() { - m.Combo("").Get(admin.EditApplication).Post(bindIgnErr(forms.EditOAuth2ApplicationForm{}), admin.EditApplicationPost) + m.Combo("").Get(admin.EditApplication).Post(web.Bind(forms.EditOAuth2ApplicationForm{}), admin.EditApplicationPost) m.Post("/regenerate_secret", admin.ApplicationsRegenerateSecret) m.Post("/delete", admin.DeleteApplication) }) @@ -663,7 +661,6 @@ func RegisterRoutes(m *web.Route) { reqRepoReleaseWriter := context.RequireRepoWriter(unit.TypeReleases) reqRepoReleaseReader := context.RequireRepoReader(unit.TypeReleases) reqRepoWikiWriter := context.RequireRepoWriter(unit.TypeWiki) - reqRepoIssueWriter := context.RequireRepoWriter(unit.TypeIssues) reqRepoIssueReader := context.RequireRepoReader(unit.TypeIssues) reqRepoPullsReader := context.RequireRepoReader(unit.TypePullRequests) reqRepoIssuesOrPullsWriter := context.RequireRepoWriterOr(unit.TypeIssues, unit.TypePullRequests) @@ -689,7 +686,7 @@ func RegisterRoutes(m *web.Route) { m.Group("/org", func() { m.Group("", func() { m.Get("/create", org.Create) - m.Post("/create", bindIgnErr(forms.CreateOrgForm{}), org.CreatePost) + m.Post("/create", web.Bind(forms.CreateOrgForm{}), org.CreatePost) }) m.Group("/invite/{token}", func() { @@ -719,22 +716,22 @@ func RegisterRoutes(m *web.Route) { m.Group("/{org}", func() { m.Get("/teams/new", org.NewTeam) - m.Post("/teams/new", bindIgnErr(forms.CreateTeamForm{}), org.NewTeamPost) + m.Post("/teams/new", web.Bind(forms.CreateTeamForm{}), org.NewTeamPost) m.Get("/teams/-/search", org.SearchTeam) m.Get("/teams/{team}/edit", org.EditTeam) - m.Post("/teams/{team}/edit", bindIgnErr(forms.CreateTeamForm{}), org.EditTeamPost) + m.Post("/teams/{team}/edit", web.Bind(forms.CreateTeamForm{}), org.EditTeamPost) m.Post("/teams/{team}/delete", org.DeleteTeam) m.Group("/settings", func() { m.Combo("").Get(org.Settings). - Post(bindIgnErr(forms.UpdateOrgSettingForm{}), org.SettingsPost) - m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), org.SettingsAvatar) + Post(web.Bind(forms.UpdateOrgSettingForm{}), org.SettingsPost) + m.Post("/avatar", web.Bind(forms.AvatarForm{}), org.SettingsAvatar) m.Post("/avatar/delete", org.SettingsDeleteAvatar) m.Group("/applications", func() { m.Get("", org.Applications) - m.Post("/oauth2", bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuthApplicationsPost) + m.Post("/oauth2", web.Bind(forms.EditOAuth2ApplicationForm{}), org.OAuthApplicationsPost) m.Group("/oauth2/{id}", func() { - m.Combo("").Get(org.OAuth2ApplicationShow).Post(bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuth2ApplicationEdit) + m.Combo("").Get(org.OAuth2ApplicationShow).Post(web.Bind(forms.EditOAuth2ApplicationForm{}), org.OAuth2ApplicationEdit) m.Post("/regenerate_secret", org.OAuthApplicationsRegenerateSecret) m.Post("/delete", org.DeleteOAuth2Application) }) @@ -749,38 +746,44 @@ func RegisterRoutes(m *web.Route) { m.Get("", org.Webhooks) m.Post("/delete", org.DeleteWebhook) m.Get("/{type}/new", repo.WebhooksNew) - m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) - m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost) - m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) - m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost) - m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) - m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost) - m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost) - m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) - m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) - m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) + m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) + m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost) + m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) + m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost) + m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) + m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost) + m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost) + m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) + m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) + m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) m.Group("/{id}", func() { m.Get("", repo.WebHooksEdit) m.Post("/replay/{uuid}", repo.ReplayWebhook) }) - m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) - m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost) - m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) - m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost) - m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) - m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost) - m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost) - m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) - m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) - m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) + m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) + m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost) + m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) + m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost) + m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) + m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost) + m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost) + m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) + m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) + m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) }, webhooksEnabled) m.Group("/labels", func() { m.Get("", org.RetrieveLabels, org.Labels) - m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), org.NewLabel) - m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), org.UpdateLabel) + m.Post("/new", web.Bind(forms.CreateLabelForm{}), org.NewLabel) + m.Post("/edit", web.Bind(forms.CreateLabelForm{}), org.UpdateLabel) m.Post("/delete", org.DeleteLabel) - m.Post("/initialize", bindIgnErr(forms.InitializeLabelsForm{}), org.InitializeLabels) + m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), org.InitializeLabels) + }) + + m.Group("/secrets", func() { + m.Get("", org.Secrets) + m.Post("", web.Bind(forms.AddSecretForm{}), org.SecretsPost) + m.Post("/delete", org.SecretsDelete) }) m.Route("/delete", "GET,POST", org.SettingsDelete) @@ -790,11 +793,11 @@ func RegisterRoutes(m *web.Route) { m.Group("/rules", func() { m.Group("/add", func() { m.Get("", org.PackagesRuleAdd) - m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), org.PackagesRuleAddPost) + m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), org.PackagesRuleAddPost) }) m.Group("/{id}", func() { m.Get("", org.PackagesRuleEdit) - m.Post("", bindIgnErr(forms.PackageCleanupRuleForm{}), org.PackagesRuleEditPost) + m.Post("", web.Bind(forms.PackageCleanupRuleForm{}), org.PackagesRuleEditPost) m.Get("/preview", org.PackagesRulePreview) }) }) @@ -810,12 +813,12 @@ func RegisterRoutes(m *web.Route) { // ***** START: Repository ***** m.Group("/repo", func() { m.Get("/create", repo.Create) - m.Post("/create", bindIgnErr(forms.CreateRepoForm{}), repo.CreatePost) + m.Post("/create", web.Bind(forms.CreateRepoForm{}), repo.CreatePost) m.Get("/migrate", repo.Migrate) - m.Post("/migrate", bindIgnErr(forms.MigrateRepoForm{}), repo.MigratePost) + m.Post("/migrate", web.Bind(forms.MigrateRepoForm{}), repo.MigratePost) m.Group("/fork", func() { m.Combo("/{repoid}").Get(repo.Fork). - Post(bindIgnErr(forms.CreateRepoForm{}), repo.ForkPost) + Post(web.Bind(forms.CreateRepoForm{}), repo.ForkPost) }, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader) m.Get("/search", repo.SearchRepo) }, reqSignIn) @@ -832,7 +835,7 @@ func RegisterRoutes(m *web.Route) { m.Get("/files/{fileid}", user.DownloadPackageFile) m.Group("/settings", func() { m.Get("", user.PackageSettings) - m.Post("", bindIgnErr(forms.PackageSettingForm{}), user.PackageSettingsPost) + m.Post("", web.Bind(forms.PackageSettingForm{}), user.PackageSettingsPost) }, reqPackageAccess(perm.AccessModeWrite)) }) }) @@ -848,9 +851,9 @@ func RegisterRoutes(m *web.Route) { m.Group("/settings", func() { m.Group("", func() { m.Combo("").Get(repo.Settings). - Post(bindIgnErr(forms.RepoSettingForm{}), repo.SettingsPost) + Post(web.Bind(forms.RepoSettingForm{}), repo.SettingsPost) }, repo.SettingsCtxData) - m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), repo.SettingsAvatar) + m.Post("/avatar", web.Bind(forms.AvatarForm{}), repo.SettingsAvatar) m.Post("/avatar/delete", repo.SettingsDeleteAvatar) m.Group("/collaboration", func() { @@ -866,16 +869,16 @@ func RegisterRoutes(m *web.Route) { m.Group("/branches", func() { m.Combo("").Get(repo.ProtectedBranch).Post(repo.ProtectedBranchPost) m.Combo("/*").Get(repo.SettingsProtectedBranch). - Post(bindIgnErr(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost) + Post(web.Bind(forms.ProtectBranchForm{}), context.RepoMustNotBeArchived(), repo.SettingsProtectedBranchPost) }, repo.MustBeNotEmpty) - m.Post("/rename_branch", bindIgnErr(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo.RenameBranchPost) + m.Post("/rename_branch", web.Bind(forms.RenameBranchForm{}), context.RepoMustNotBeArchived(), repo.RenameBranchPost) m.Group("/tags", func() { m.Get("", repo.Tags) - m.Post("", bindIgnErr(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.NewProtectedTagPost) + m.Post("", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.NewProtectedTagPost) m.Post("/delete", context.RepoMustNotBeArchived(), repo.DeleteProtectedTagPost) m.Get("/{id}", repo.EditProtectedTag) - m.Post("/{id}", bindIgnErr(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.EditProtectedTagPost) + m.Post("/{id}", web.Bind(forms.ProtectTagForm{}), context.RepoMustNotBeArchived(), repo.EditProtectedTagPost) }) m.Group("/hooks/git", func() { @@ -888,39 +891,43 @@ func RegisterRoutes(m *web.Route) { m.Get("", repo.Webhooks) m.Post("/delete", repo.DeleteWebhook) m.Get("/{type}/new", repo.WebhooksNew) - m.Post("/gitea/new", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) - m.Post("/gogs/new", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksNewPost) - m.Post("/slack/new", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) - m.Post("/discord/new", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost) - m.Post("/dingtalk/new", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) - m.Post("/telegram/new", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost) - m.Post("/matrix/new", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost) - m.Post("/msteams/new", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) - m.Post("/feishu/new", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) - m.Post("/wechatwork/new", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) - m.Post("/packagist/new", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost) + m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost) + m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost) + m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost) + m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost) + m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost) + m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost) + m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost) + m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost) + m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost) + m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost) + m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost) m.Group("/{id}", func() { m.Get("", repo.WebHooksEdit) m.Post("/test", repo.TestWebhook) m.Post("/replay/{uuid}", repo.ReplayWebhook) }) - m.Post("/gitea/{id}", bindIgnErr(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) - m.Post("/gogs/{id}", bindIgnErr(forms.NewGogshookForm{}), repo.GogsHooksEditPost) - m.Post("/slack/{id}", bindIgnErr(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) - m.Post("/discord/{id}", bindIgnErr(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost) - m.Post("/dingtalk/{id}", bindIgnErr(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) - m.Post("/telegram/{id}", bindIgnErr(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost) - m.Post("/matrix/{id}", bindIgnErr(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost) - m.Post("/msteams/{id}", bindIgnErr(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) - m.Post("/feishu/{id}", bindIgnErr(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) - m.Post("/wechatwork/{id}", bindIgnErr(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) - m.Post("/packagist/{id}", bindIgnErr(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost) + m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost) + m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost) + m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost) + m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost) + m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost) + m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost) + m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost) + m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost) + m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost) + m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost) + m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost) }, webhooksEnabled) m.Group("/keys", func() { m.Combo("").Get(repo.DeployKeys). - Post(bindIgnErr(forms.AddKeyForm{}), repo.DeployKeysPost) + Post(web.Bind(forms.AddKeyForm{}), repo.DeployKeysPost) m.Post("/delete", repo.DeleteDeployKey) + m.Group("/secrets", func() { + m.Post("", web.Bind(forms.AddSecretForm{}), repo.SecretsPost) + m.Post("/delete", repo.DeleteSecret) + }) }) m.Group("/lfs", func() { @@ -958,7 +965,7 @@ func RegisterRoutes(m *web.Route) { m.Get("/compare", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists, ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff) m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists). Get(ignSignIn, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.CompareDiff). - Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost) + Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, web.Bind(forms.CreateIssueForm{}), repo.SetWhitespaceBehavior, repo.CompareAndPullRequestPost) m.Group("/{type:issues|pulls}", func() { m.Group("/{index}", func() { m.Get("/info", repo.GetIssueInfo) @@ -971,7 +978,7 @@ func RegisterRoutes(m *web.Route) { m.Group("/issues", func() { m.Group("/new", func() { m.Combo("").Get(context.RepoRef(), repo.NewIssue). - Post(bindIgnErr(forms.CreateIssueForm{}), repo.NewIssuePost) + Post(web.Bind(forms.CreateIssueForm{}), repo.NewIssuePost) m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate) }) m.Get("/search", repo.ListIssues) @@ -982,7 +989,7 @@ func RegisterRoutes(m *web.Route) { m.Group("/{index}", func() { m.Post("/title", repo.UpdateIssueTitle) m.Post("/content", repo.UpdateIssueContent) - m.Post("/deadline", bindIgnErr(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline) + m.Post("/deadline", web.Bind(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline) m.Post("/watch", repo.IssueWatch) m.Post("/ref", repo.UpdateIssueRef) m.Post("/viewed-files", repo.UpdateViewedFiles) @@ -990,18 +997,18 @@ func RegisterRoutes(m *web.Route) { m.Post("/add", repo.AddDependency) m.Post("/delete", repo.RemoveDependency) }) - m.Combo("/comments").Post(repo.MustAllowUserComment, bindIgnErr(forms.CreateCommentForm{}), repo.NewComment) + m.Combo("/comments").Post(repo.MustAllowUserComment, web.Bind(forms.CreateCommentForm{}), repo.NewComment) m.Group("/times", func() { - m.Post("/add", bindIgnErr(forms.AddTimeManuallyForm{}), repo.AddTimeManually) + m.Post("/add", web.Bind(forms.AddTimeManuallyForm{}), repo.AddTimeManually) m.Post("/{timeid}/delete", repo.DeleteTime) m.Group("/stopwatch", func() { m.Post("/toggle", repo.IssueStopwatch) m.Post("/cancel", repo.CancelStopwatch) }) }) - m.Post("/reactions/{action}", bindIgnErr(forms.ReactionForm{}), repo.ChangeIssueReaction) - m.Post("/lock", reqRepoIssueWriter, bindIgnErr(forms.IssueLockForm{}), repo.LockIssue) - m.Post("/unlock", reqRepoIssueWriter, repo.UnlockIssue) + m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeIssueReaction) + m.Post("/lock", reqRepoIssuesOrPullsWriter, web.Bind(forms.IssueLockForm{}), repo.LockIssue) + m.Post("/unlock", reqRepoIssuesOrPullsWriter, repo.UnlockIssue) m.Post("/delete", reqRepoAdmin, repo.DeleteIssue) }, context.RepoMustNotBeArchived()) m.Group("/{index}", func() { @@ -1017,7 +1024,7 @@ func RegisterRoutes(m *web.Route) { m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject) m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee) m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest) - m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview) + m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview) m.Post("/status", reqRepoIssuesOrPullsWriter, repo.UpdateIssueStatus) m.Post("/resolve_conversation", reqRepoIssuesOrPullsReader, repo.UpdateResolveConversation) m.Post("/attachments", repo.UploadIssueAttachment) @@ -1026,23 +1033,23 @@ func RegisterRoutes(m *web.Route) { m.Group("/comments/{id}", func() { m.Post("", repo.UpdateCommentContent) m.Post("/delete", repo.DeleteComment) - m.Post("/reactions/{action}", bindIgnErr(forms.ReactionForm{}), repo.ChangeCommentReaction) + m.Post("/reactions/{action}", web.Bind(forms.ReactionForm{}), repo.ChangeCommentReaction) }, context.RepoMustNotBeArchived()) m.Group("/comments/{id}", func() { m.Get("/attachments", repo.GetCommentAttachments) }) - m.Post("/markdown", bindIgnErr(structs.MarkdownOption{}), misc.Markdown) + m.Post("/markdown", web.Bind(structs.MarkdownOption{}), misc.Markdown) m.Group("/labels", func() { - m.Post("/new", bindIgnErr(forms.CreateLabelForm{}), repo.NewLabel) - m.Post("/edit", bindIgnErr(forms.CreateLabelForm{}), repo.UpdateLabel) + m.Post("/new", web.Bind(forms.CreateLabelForm{}), repo.NewLabel) + m.Post("/edit", web.Bind(forms.CreateLabelForm{}), repo.UpdateLabel) m.Post("/delete", repo.DeleteLabel) - m.Post("/initialize", bindIgnErr(forms.InitializeLabelsForm{}), repo.InitializeLabels) + m.Post("/initialize", web.Bind(forms.InitializeLabelsForm{}), repo.InitializeLabels) }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef()) m.Group("/milestones", func() { m.Combo("/new").Get(repo.NewMilestone). - Post(bindIgnErr(forms.CreateMilestoneForm{}), repo.NewMilestonePost) + Post(web.Bind(forms.CreateMilestoneForm{}), repo.NewMilestonePost) m.Get("/{id}/edit", repo.EditMilestone) - m.Post("/{id}/edit", bindIgnErr(forms.CreateMilestoneForm{}), repo.EditMilestonePost) + m.Post("/{id}/edit", web.Bind(forms.CreateMilestoneForm{}), repo.EditMilestonePost) m.Post("/{id}/{action}", repo.ChangeMilestoneStatus) m.Post("/delete", repo.DeleteMilestone) }, context.RepoMustNotBeArchived(), reqRepoIssuesOrPullsWriter, context.RepoRef()) @@ -1053,25 +1060,24 @@ func RegisterRoutes(m *web.Route) { m.Group("", func() { m.Group("", func() { m.Combo("/_edit/*").Get(repo.EditFile). - Post(bindIgnErr(forms.EditRepoFileForm{}), repo.EditFilePost) + Post(web.Bind(forms.EditRepoFileForm{}), repo.EditFilePost) m.Combo("/_new/*").Get(repo.NewFile). - Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewFilePost) - m.Post("/_preview/*", bindIgnErr(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost) + Post(web.Bind(forms.EditRepoFileForm{}), repo.NewFilePost) + m.Post("/_preview/*", web.Bind(forms.EditPreviewDiffForm{}), repo.DiffPreviewPost) m.Combo("/_delete/*").Get(repo.DeleteFile). - Post(bindIgnErr(forms.DeleteRepoFileForm{}), repo.DeleteFilePost) + Post(web.Bind(forms.DeleteRepoFileForm{}), repo.DeleteFilePost) m.Combo("/_upload/*", repo.MustBeAbleToUpload). Get(repo.UploadFile). - Post(bindIgnErr(forms.UploadRepoFileForm{}), repo.UploadFilePost) + Post(web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePost) m.Combo("/_diffpatch/*").Get(repo.NewDiffPatch). - Post(bindIgnErr(forms.EditRepoFileForm{}), repo.NewDiffPatchPost) - m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPick). - Post(bindIgnErr(forms.CherryPickForm{}), repo.CherryPickPost) - // Same as `/_upload/*` but returns JSON - m.Post("/upload/*", repo.MustBeAbleToUpload, bindIgnErr(forms.UploadRepoFileForm{}), repo.UploadFilePostJson) + Post(web.Bind(forms.EditRepoFileForm{}), repo.NewDiffPatchPost) + m.Combo("/_cherrypick/{sha:([a-f0-9]{7,40})}/*").Get(repo.CherryPickPost). + Post(web.Bind(forms.CherryPickForm{}), repo.CherryPickPost) + m.Post("/upload/*", repo.MustBeAbleToUpload, web.Bind(forms.UploadRepoFileForm{}), repo.UploadFilePostJson) }, repo.MustBeEditable) m.Group("", func() { m.Post("/upload-file", repo.UploadFileToServer) - m.Post("/upload-remove", bindIgnErr(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer) + m.Post("/upload-remove", web.Bind(forms.RemoveUploadFileForm{}), repo.RemoveUploadFileFromServer) }, repo.MustBeEditable, repo.MustBeAbleToUpload) }, context.RepoRef(), canEnableEditor, context.RepoMustNotBeArchived(), repo.MustBeNotEmpty) @@ -1080,7 +1086,7 @@ func RegisterRoutes(m *web.Route) { m.Post("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.CreateBranch) m.Post("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.CreateBranch) m.Post("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.CreateBranch) - }, bindIgnErr(forms.NewBranchForm{})) + }, web.Bind(forms.NewBranchForm{})) m.Post("/delete", repo.DeleteBranchPost) m.Post("/restore", repo.RestoreBranchPost) }, context.RepoMustNotBeArchived(), reqRepoCodeWriter, repo.MustBeNotEmpty) @@ -1088,17 +1094,26 @@ func RegisterRoutes(m *web.Route) { // Releases m.Group("/{username}/{reponame}", func() { - m.Get("/tags", repo.TagsList, repo.MustBeNotEmpty, - reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag)) + m.Group("/tags", func() { + m.Get("", repo.TagsList) + m.Get(".rss", feedEnabled, repo.TagsListFeedRSS) + m.Get(".atom", feedEnabled, repo.TagsListFeedAtom) + }, func(ctx *context.Context) { + ctx.Data["EnableFeed"] = setting.EnableFeed + }, repo.MustBeNotEmpty, reqRepoCodeReader, context.RepoRefByType(context.RepoRefTag, true)) m.Group("/releases", func() { m.Get("/", repo.Releases) m.Get("/tag/*", repo.SingleRelease) m.Get("/latest", repo.LatestRelease) + m.Get(".rss", feedEnabled, repo.ReleasesFeedRSS) + m.Get(".atom", feedEnabled, repo.ReleasesFeedAtom) + }, func(ctx *context.Context) { + ctx.Data["EnableFeed"] = setting.EnableFeed }, repo.MustBeNotEmpty, reqRepoReleaseReader, context.RepoRefByType(context.RepoRefTag, true)) m.Get("/releases/attachments/{uuid}", repo.GetAttachment, repo.MustBeNotEmpty, reqRepoReleaseReader) m.Group("/releases", func() { m.Get("/new", repo.NewRelease) - m.Post("/new", bindIgnErr(forms.NewReleaseForm{}), repo.NewReleasePost) + m.Post("/new", web.Bind(forms.NewReleaseForm{}), repo.NewReleasePost) m.Post("/delete", repo.DeleteRelease) m.Post("/attachments", repo.UploadReleaseAttachment) m.Post("/attachments/remove", repo.DeleteAttachment) @@ -1107,7 +1122,7 @@ func RegisterRoutes(m *web.Route) { repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoCodeWriter, context.RepoRef()) m.Group("/releases", func() { m.Get("/edit/*", repo.EditRelease) - m.Post("/edit/*", bindIgnErr(forms.EditReleaseForm{}), repo.EditReleasePost) + m.Post("/edit/*", web.Bind(forms.EditReleaseForm{}), repo.EditReleasePost) }, reqSignIn, repo.MustBeNotEmpty, context.RepoMustNotBeArchived(), reqRepoReleaseWriter, func(ctx *context.Context) { var err error ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch) @@ -1156,17 +1171,17 @@ func RegisterRoutes(m *web.Route) { m.Get("/{id}", repo.ViewProject) m.Group("", func() { m.Get("/new", repo.NewProject) - m.Post("/new", bindIgnErr(forms.CreateProjectForm{}), repo.NewProjectPost) + m.Post("/new", web.Bind(forms.CreateProjectForm{}), repo.NewProjectPost) m.Group("/{id}", func() { - m.Post("", bindIgnErr(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) + m.Post("", web.Bind(forms.EditProjectBoardForm{}), repo.AddBoardToProjectPost) m.Post("/delete", repo.DeleteProject) m.Get("/edit", repo.EditProject) - m.Post("/edit", bindIgnErr(forms.CreateProjectForm{}), repo.EditProjectPost) + m.Post("/edit", web.Bind(forms.CreateProjectForm{}), repo.EditProjectPost) m.Post("/{action:open|close}", repo.ChangeProjectStatus) m.Group("/{boardID}", func() { - m.Put("", bindIgnErr(forms.EditProjectBoardForm{}), repo.EditProjectBoard) + m.Put("", web.Bind(forms.EditProjectBoardForm{}), repo.EditProjectBoard) m.Delete("", repo.DeleteProjectBoard) m.Post("/default", repo.SetDefaultProjectBoard) @@ -1182,14 +1197,14 @@ func RegisterRoutes(m *web.Route) { Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, - bindIgnErr(forms.NewWikiForm{}), + web.Bind(forms.NewWikiForm{}), repo.WikiPost) m.Combo("/*"). Get(repo.Wiki). Post(context.RepoMustNotBeArchived(), reqSignIn, reqRepoWikiWriter, - bindIgnErr(forms.NewWikiForm{}), + web.Bind(forms.NewWikiForm{}), repo.WikiPost) m.Get("/commit/{sha:[a-f0-9]{7,40}}", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.Diff) m.Get("/commit/{sha:[a-f0-9]{7,40}}.{ext:patch|diff}", repo.RawDiff) @@ -1247,17 +1262,17 @@ func RegisterRoutes(m *web.Route) { m.Get(".diff", repo.DownloadPullDiff) m.Get(".patch", repo.DownloadPullPatch) m.Get("/commits", context.RepoRef(), repo.ViewPullCommits) - m.Post("/merge", context.RepoMustNotBeArchived(), bindIgnErr(forms.MergePullRequestForm{}), repo.MergePullRequest) + m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest) m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest) m.Post("/update", repo.UpdatePullRequest) - m.Post("/set_allow_maintainer_edit", bindIgnErr(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits) + m.Post("/set_allow_maintainer_edit", web.Bind(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits) m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest) m.Group("/files", func() { m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.ViewPullFiles) m.Group("/reviews", func() { m.Get("/new_comment", repo.RenderNewCodeCommentForm) - m.Post("/comments", bindIgnErr(forms.CodeCommentForm{}), repo.CreateCodeComment) - m.Post("/submit", bindIgnErr(forms.SubmitReviewForm{}), repo.SubmitReview) + m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.CreateCodeComment) + m.Post("/submit", web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview) }, context.RepoMustNotBeArchived()) }) }, repo.MustAllowPulls) diff --git a/services/agit/agit.go b/services/agit/agit.go index e21a1ea29d9e..b61cb6f3f569 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -115,7 +115,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. description = opts.GitPushOptions["description"] } - pusher, err := user_model.GetUserByID(opts.UserID) + pusher, err := user_model.GetUserByID(ctx, opts.UserID) if err != nil { return nil, fmt.Errorf("Failed to get user. Error: %w", err) } @@ -198,7 +198,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. } pull_service.AddToTaskQueue(pr) - pusher, err := user_model.GetUserByID(opts.UserID) + pusher, err := user_model.GetUserByID(ctx, opts.UserID) if err != nil { return nil, fmt.Errorf("Failed to get user. Error: %w", err) } @@ -206,7 +206,7 @@ func ProcReceive(ctx context.Context, repo *repo_model.Repository, gitRepo *git. if err != nil { return nil, fmt.Errorf("Failed to load pull issue. Error: %w", err) } - comment, err := issues_model.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i]) + comment, err := pull_service.CreatePushPullComment(ctx, pusher, pr, oldCommitID, opts.NewCommitIDs[i]) if err == nil && comment != nil { notification.NotifyPullRequestPushCommits(ctx, pusher, pr, comment) } diff --git a/services/attachment/attachment.go b/services/attachment/attachment.go index 522acd00a32d..7fdacc6aae50 100644 --- a/services/attachment/attachment.go +++ b/services/attachment/attachment.go @@ -39,19 +39,14 @@ func NewAttachment(attach *repo_model.Attachment, file io.Reader) (*repo_model.A } // UploadAttachment upload new attachment into storage and update database -func UploadAttachment(file io.Reader, actorID, repoID, releaseID int64, fileName, allowedTypes string) (*repo_model.Attachment, error) { +func UploadAttachment(file io.Reader, allowedTypes string, opts *repo_model.Attachment) (*repo_model.Attachment, error) { buf := make([]byte, 1024) n, _ := util.ReadAtMost(file, buf) buf = buf[:n] - if err := upload.Verify(buf, fileName, allowedTypes); err != nil { + if err := upload.Verify(buf, opts.Name, allowedTypes); err != nil { return nil, err } - return NewAttachment(&repo_model.Attachment{ - RepoID: repoID, - UploaderID: actorID, - ReleaseID: releaseID, - Name: fileName, - }, io.MultiReader(bytes.NewReader(buf), file)) + return NewAttachment(opts, io.MultiReader(bytes.NewReader(buf), file)) } diff --git a/services/auth/basic.go b/services/auth/basic.go index 0a82fc5b723d..5fb80703ab5a 100644 --- a/services/auth/basic.go +++ b/services/auth/basic.go @@ -40,20 +40,20 @@ func (b *Basic) Name() string { // "Authorization" header of the request and returns the corresponding user object for that // name/token on successful validation. // Returns nil if header is empty or validation fails. -func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *user_model.User { +func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { // Basic authentication should only fire on API, Download or on Git or LFSPaths if !middleware.IsAPIPath(req) && !isContainerPath(req) && !isAttachmentDownload(req) && !isGitRawReleaseOrLFSPath(req) { - return nil + return nil, nil } baHead := req.Header.Get("Authorization") if len(baHead) == 0 { - return nil + return nil, nil } auths := strings.SplitN(baHead, " ", 2) if len(auths) != 2 || (strings.ToLower(auths[0]) != "basic") { - return nil + return nil, nil } uname, passwd, _ := base.BasicAuthDecode(auths[1]) @@ -74,23 +74,23 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore if uid != 0 { log.Trace("Basic Authorization: Valid OAuthAccessToken for user[%d]", uid) - u, err := user_model.GetUserByID(uid) + u, err := user_model.GetUserByID(req.Context(), uid) if err != nil { log.Error("GetUserByID: %v", err) - return nil + return nil, err } store.GetData()["IsApiToken"] = true - return u + return u, nil } token, err := auth_model.GetAccessTokenBySHA(authToken) if err == nil { log.Trace("Basic Authorization: Valid AccessToken for user[%d]", uid) - u, err := user_model.GetUserByID(token.UID) + u, err := user_model.GetUserByID(req.Context(), token.UID) if err != nil { log.Error("GetUserByID: %v", err) - return nil + return nil, err } token.UpdatedUnix = timeutil.TimeStampNow() @@ -99,13 +99,13 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore } store.GetData()["IsApiToken"] = true - return u + return u, nil } else if !auth_model.IsErrAccessTokenNotExist(err) && !auth_model.IsErrAccessTokenEmpty(err) { log.Error("GetAccessTokenBySha: %v", err) } if !setting.Service.EnableBasicAuth { - return nil + return nil, nil } log.Trace("Basic Authorization: Attempting SignIn for %s", uname) @@ -114,7 +114,7 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore if !user_model.IsErrUserNotExist(err) { log.Error("UserSignIn: %v", err) } - return nil + return nil, err } if skipper, ok := source.Cfg.(LocalTwoFASkipper); ok && skipper.IsSkipLocalTwoFA() { @@ -123,5 +123,5 @@ func (b *Basic) Verify(req *http.Request, w http.ResponseWriter, store DataStore log.Trace("Basic Authorization: Logged in user %-v", u) - return u + return u, nil } diff --git a/services/auth/group.go b/services/auth/group.go index a9112029c54c..0a0330b3aa95 100644 --- a/services/auth/group.go +++ b/services/auth/group.go @@ -9,7 +9,6 @@ import ( "reflect" "strings" - "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" ) @@ -80,23 +79,23 @@ func (b *Group) Free() error { } // Verify extracts and validates -func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *user_model.User { - if !db.HasEngine { - return nil - } - +func (b *Group) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { // Try to sign in with each of the enabled plugins for _, ssoMethod := range b.methods { - user := ssoMethod.Verify(req, w, store, sess) + user, err := ssoMethod.Verify(req, w, store, sess) + if err != nil { + return nil, err + } + if user != nil { if store.GetData()["AuthedMethod"] == nil { if named, ok := ssoMethod.(Named); ok { store.GetData()["AuthedMethod"] = named.Name() } } - return user + return user, nil } } - return nil + return nil, nil } diff --git a/services/auth/httpsign.go b/services/auth/httpsign.go index dcdc2de83a81..4d52315381c3 100644 --- a/services/auth/httpsign.go +++ b/services/auth/httpsign.go @@ -39,10 +39,10 @@ func (h *HTTPSign) Name() string { // Verify extracts and validates HTTPsign from the Signature header of the request and returns // the corresponding user object on successful validation. // Returns nil if header is empty or validation fails. -func (h *HTTPSign) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *user_model.User { +func (h *HTTPSign) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { sigHead := req.Header.Get("Signature") if len(sigHead) == 0 { - return nil + return nil, nil } var ( @@ -53,14 +53,14 @@ func (h *HTTPSign) Verify(req *http.Request, w http.ResponseWriter, store DataSt if len(req.Header.Get("X-Ssh-Certificate")) != 0 { // Handle Signature signed by SSH certificates if len(setting.SSH.TrustedUserCAKeys) == 0 { - return nil + return nil, nil } publicKey, err = VerifyCert(req) if err != nil { log.Debug("VerifyCert on request from %s: failed: %v", req.RemoteAddr, err) log.Warn("Failed authentication attempt from %s", req.RemoteAddr) - return nil + return nil, nil } } else { // Handle Signature signed by Public Key @@ -68,21 +68,21 @@ func (h *HTTPSign) Verify(req *http.Request, w http.ResponseWriter, store DataSt if err != nil { log.Debug("VerifyPubKey on request from %s: failed: %v", req.RemoteAddr, err) log.Warn("Failed authentication attempt from %s", req.RemoteAddr) - return nil + return nil, nil } } - u, err := user_model.GetUserByID(publicKey.OwnerID) + u, err := user_model.GetUserByID(req.Context(), publicKey.OwnerID) if err != nil { log.Error("GetUserByID: %v", err) - return nil + return nil, err } store.GetData()["IsApiToken"] = true log.Trace("HTTP Sign: Logged in user %-v", u) - return u + return u, nil } func VerifyPubKey(r *http.Request) (*asymkey_model.PublicKey, error) { diff --git a/services/auth/interface.go b/services/auth/interface.go index d238a408560b..f2f1aaf39cb0 100644 --- a/services/auth/interface.go +++ b/services/auth/interface.go @@ -24,8 +24,9 @@ type Method interface { // If verification is successful returns either an existing user object (with id > 0) // or a new user object (with id = 0) populated with the information that was found // in the authentication data (username or email). - // Returns nil if verification fails. - Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *user_model.User + // Second argument returns err if verification fails, otherwise + // First return argument returns nil if no matched verification condition + Verify(http *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) } // Initializable represents a structure that requires initialization diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index da8c526382d6..c0a8250e9547 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -108,31 +108,27 @@ func (o *OAuth2) userIDFromToken(req *http.Request, store DataStore) int64 { // or the "Authorization" header and returns the corresponding user object for that ID. // 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 { - if !db.HasEngine { - return nil - } - +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) { - return nil + return nil, nil } id := o.userIDFromToken(req, store) if id <= 0 { - return nil + return nil, nil } log.Trace("OAuth2 Authorization: Found token for user[%d]", id) - user, err := user_model.GetUserByID(id) + user, err := user_model.GetUserByID(req.Context(), id) if err != nil { if !user_model.IsErrUserNotExist(err) { log.Error("GetUserByName: %v", err) } - return nil + return nil, err } log.Trace("OAuth2 Authorization: Logged in user %-v", user) - return user + return user, nil } func isAuthenticatedTokenRequest(req *http.Request) bool { diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 2d5b6611b58c..0206ccdf667d 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -51,10 +51,10 @@ func (r *ReverseProxy) Name() string { // If a username is available in the "setting.ReverseProxyAuthUser" header an existing // user object is returned (populated with username or email found in header). // Returns nil if header is empty. -func (r *ReverseProxy) getUserFromAuthUser(req *http.Request) *user_model.User { +func (r *ReverseProxy) getUserFromAuthUser(req *http.Request) (*user_model.User, error) { username := r.getUserName(req) if len(username) == 0 { - return nil + return nil, nil } log.Trace("ReverseProxy Authorization: Found username: %s", username) @@ -62,11 +62,11 @@ func (r *ReverseProxy) getUserFromAuthUser(req *http.Request) *user_model.User { if err != nil { if !user_model.IsErrUserNotExist(err) || !r.isAutoRegisterAllowed() { log.Error("GetUserByName: %v", err) - return nil + return nil, err } user = r.newUser(req) } - return user + return user, nil } // getEmail extracts the email from the "setting.ReverseProxyAuthEmail" header @@ -106,12 +106,15 @@ func (r *ReverseProxy) getUserFromAuthEmail(req *http.Request) *user_model.User // First it will attempt to load it based on the username (see docs for getUserFromAuthUser), // and failing that it will attempt to load it based on the email (see docs for getUserFromAuthEmail). // Returns nil if the headers are empty or the user is not found. -func (r *ReverseProxy) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *user_model.User { - user := r.getUserFromAuthUser(req) +func (r *ReverseProxy) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { + user, err := r.getUserFromAuthUser(req) + if err != nil { + return nil, err + } if user == nil { user = r.getUserFromAuthEmail(req) if user == nil { - return nil + return nil, nil } } @@ -124,7 +127,7 @@ func (r *ReverseProxy) Verify(req *http.Request, w http.ResponseWriter, store Da store.GetData()["IsReverseProxy"] = true log.Trace("ReverseProxy Authorization: Logged in user %-v", user) - return user + return user, nil } // isAutoRegisterAllowed checks if EnableReverseProxyAutoRegister setting is true diff --git a/services/auth/session.go b/services/auth/session.go index f35fad1a0c25..c75113573810 100644 --- a/services/auth/session.go +++ b/services/auth/session.go @@ -6,6 +6,7 @@ package auth import ( "net/http" + "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" ) @@ -28,12 +29,12 @@ func (s *Session) Name() string { // Verify checks if there is a user uid stored in the session and returns the user // object for that uid. // Returns nil if there is no user uid stored in the session. -func (s *Session) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) *user_model.User { +func (s *Session) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { user := SessionUser(sess) if user != nil { - return user + return user, nil } - return nil + return nil, nil } // SessionUser returns the user object corresponding to the "uid" session variable. @@ -55,7 +56,7 @@ func SessionUser(sess SessionStore) *user_model.User { } // Get user object - user, err := user_model.GetUserByID(id) + user, err := user_model.GetUserByID(db.DefaultContext, id) if err != nil { if !user_model.IsErrUserNotExist(err) { log.Error("GetUserById: %v", err) diff --git a/services/auth/sspi_windows.go b/services/auth/sspi_windows.go index 988afb473034..045834b6911a 100644 --- a/services/auth/sspi_windows.go +++ b/services/auth/sspi_windows.go @@ -77,15 +77,15 @@ func (s *SSPI) Free() error { // If authentication is successful, returns the corresponding user object. // 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 { +func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, sess SessionStore) (*user_model.User, error) { if !s.shouldAuthenticate(req) { - return nil + return nil, nil } cfg, err := s.getConfig() if err != nil { log.Error("could not get SSPI config: %v", err) - return nil + return nil, err } log.Trace("SSPI Authorization: Attempting to authenticate") @@ -108,7 +108,7 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, log.Error("%v", err) } - return nil + return nil, err } if outToken != "" { sspiAuth.AppendAuthenticateHeader(w, outToken) @@ -116,7 +116,7 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, username := sanitizeUsername(userInfo.Username, cfg) if len(username) == 0 { - return nil + return nil, nil } log.Info("Authenticated as %s\n", username) @@ -124,16 +124,16 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, if err != nil { if !user_model.IsErrUserNotExist(err) { log.Error("GetUserByName: %v", err) - return nil + return nil, err } if !cfg.AutoCreateUsers { log.Error("User '%s' not found", username) - return nil + return nil, nil } user, err = s.newUser(username, cfg) if err != nil { log.Error("CreateUser: %v", err) - return nil + return nil, err } } @@ -143,7 +143,7 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, } log.Trace("SSPI Authorization: Logged in user %-v", user) - return user + return user, nil } // getConfig retrieves the SSPI configuration from login sources diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index f5bf1f4491a3..15d94e79209e 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -218,7 +218,7 @@ func handlePull(pullID int64, sha string) { } // Merge if all checks succeeded - doer, err := user_model.GetUserByIDCtx(ctx, scheduledPRM.DoerID) + doer, err := user_model.GetUserByID(ctx, scheduledPRM.DoerID) if err != nil { log.Error("GetUserByIDCtx: %v", err) return diff --git a/services/convert/attachment.go b/services/convert/attachment.go new file mode 100644 index 000000000000..ddba181a1204 --- /dev/null +++ b/services/convert/attachment.go @@ -0,0 +1,30 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package convert + +import ( + repo_model "code.gitea.io/gitea/models/repo" + api "code.gitea.io/gitea/modules/structs" +) + +// ToAttachment converts models.Attachment to api.Attachment +func ToAttachment(a *repo_model.Attachment) *api.Attachment { + return &api.Attachment{ + ID: a.ID, + Name: a.Name, + Created: a.CreatedUnix.AsTime(), + DownloadCount: a.DownloadCount, + Size: a.Size, + UUID: a.UUID, + DownloadURL: a.DownloadURL(), + } +} + +func ToAttachments(attachments []*repo_model.Attachment) []*api.Attachment { + converted := make([]*api.Attachment, 0, len(attachments)) + for _, attachment := range attachments { + converted = append(converted, ToAttachment(attachment)) + } + return converted +} diff --git a/modules/convert/convert.go b/services/convert/convert.go similarity index 99% rename from modules/convert/convert.go rename to services/convert/convert.go index 107854e01335..756a1f95d905 100644 --- a/modules/convert/convert.go +++ b/services/convert/convert.go @@ -5,6 +5,7 @@ package convert import ( + "context" "fmt" "strconv" "strings" @@ -408,8 +409,8 @@ func ToOAuth2Application(app *auth.OAuth2Application) *api.OAuth2Application { } // ToLFSLock convert a LFSLock to api.LFSLock -func ToLFSLock(l *git_model.LFSLock) *api.LFSLock { - u, err := user_model.GetUserByID(l.OwnerID) +func ToLFSLock(ctx context.Context, l *git_model.LFSLock) *api.LFSLock { + u, err := user_model.GetUserByID(ctx, l.OwnerID) if err != nil { return nil } diff --git a/modules/convert/git_commit.go b/services/convert/git_commit.go similarity index 100% rename from modules/convert/git_commit.go rename to services/convert/git_commit.go diff --git a/modules/convert/git_commit_test.go b/services/convert/git_commit_test.go similarity index 100% rename from modules/convert/git_commit_test.go rename to services/convert/git_commit_test.go diff --git a/modules/convert/issue.go b/services/convert/issue.go similarity index 88% rename from modules/convert/issue.go rename to services/convert/issue.go index ff3466cb3f6a..f3af03ed949f 100644 --- a/modules/convert/issue.go +++ b/services/convert/issue.go @@ -37,20 +37,21 @@ func ToAPIIssue(ctx context.Context, issue *issues_model.Issue) *api.Issue { } apiIssue := &api.Issue{ - ID: issue.ID, - URL: issue.APIURL(), - HTMLURL: issue.HTMLURL(), - Index: issue.Index, - Poster: ToUser(issue.Poster, nil), - Title: issue.Title, - Body: issue.Content, - Ref: issue.Ref, - Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner), - State: issue.State(), - IsLocked: issue.IsLocked, - Comments: issue.NumComments, - Created: issue.CreatedUnix.AsTime(), - Updated: issue.UpdatedUnix.AsTime(), + ID: issue.ID, + URL: issue.APIURL(), + HTMLURL: issue.HTMLURL(), + Index: issue.Index, + Poster: ToUser(issue.Poster, nil), + Title: issue.Title, + Body: issue.Content, + Attachments: ToAttachments(issue.Attachments), + Ref: issue.Ref, + Labels: ToLabelList(issue.Labels, issue.Repo, issue.Repo.Owner), + State: issue.State(), + IsLocked: issue.IsLocked, + Comments: issue.NumComments, + Created: issue.CreatedUnix.AsTime(), + Updated: issue.UpdatedUnix.AsTime(), } apiIssue.Repo = &api.RepositoryMeta{ @@ -110,12 +111,11 @@ func ToAPIIssueList(ctx context.Context, il issues_model.IssueList) []*api.Issue // ToTrackedTime converts TrackedTime to API format func ToTrackedTime(ctx context.Context, t *issues_model.TrackedTime) (apiT *api.TrackedTime) { apiT = &api.TrackedTime{ - ID: t.ID, - IssueID: t.IssueID, - UserID: t.UserID, - UserName: t.User.Name, - Time: t.Time, - Created: t.Created, + ID: t.ID, + IssueID: t.IssueID, + UserID: t.UserID, + Time: t.Time, + Created: t.Created, } if t.Issue != nil { apiT.Issue = ToAPIIssue(ctx, t.Issue) @@ -149,7 +149,7 @@ func ToStopWatches(sws []*issues_model.Stopwatch) (api.StopWatches, error) { } repo, ok = repoCache[issue.RepoID] if !ok { - repo, err = repo_model.GetRepositoryByID(issue.RepoID) + repo, err = repo_model.GetRepositoryByID(db.DefaultContext, issue.RepoID) if err != nil { return nil, err } diff --git a/modules/convert/issue_comment.go b/services/convert/issue_comment.go similarity index 86% rename from modules/convert/issue_comment.go rename to services/convert/issue_comment.go index 81cd1ac245ed..6044cbcf6134 100644 --- a/modules/convert/issue_comment.go +++ b/services/convert/issue_comment.go @@ -16,14 +16,15 @@ import ( // ToComment converts a issues_model.Comment to the api.Comment format func ToComment(c *issues_model.Comment) *api.Comment { return &api.Comment{ - ID: c.ID, - Poster: ToUser(c.Poster, nil), - HTMLURL: c.HTMLURL(), - IssueURL: c.IssueURL(), - PRURL: c.PRURL(), - Body: c.Content, - Created: c.CreatedUnix.AsTime(), - Updated: c.UpdatedUnix.AsTime(), + ID: c.ID, + Poster: ToUser(c.Poster, nil), + HTMLURL: c.HTMLURL(), + IssueURL: c.IssueURL(), + PRURL: c.PRURL(), + Body: c.Content, + Attachments: ToAttachments(c.Attachments), + Created: c.CreatedUnix.AsTime(), + Updated: c.UpdatedUnix.AsTime(), } } @@ -138,17 +139,17 @@ func ToTimelineComment(ctx context.Context, c *issues_model.Comment, doer *user_ var repo *repo_model.Repository if c.Label.BelongsToOrg() { var err error - org, err = user_model.GetUserByIDCtx(ctx, c.Label.OrgID) + org, err = user_model.GetUserByID(ctx, c.Label.OrgID) if err != nil { - log.Error("GetUserByIDCtx(%d): %v", c.Label.OrgID, err) + log.Error("GetUserByID(%d): %v", c.Label.OrgID, err) return nil } } if c.Label.BelongsToRepo() { var err error - repo, err = repo_model.GetRepositoryByIDCtx(ctx, c.Label.RepoID) + repo, err = repo_model.GetRepositoryByID(ctx, c.Label.RepoID) if err != nil { - log.Error("GetRepositoryByIDCtx(%d): %v", c.Label.RepoID, err) + log.Error("GetRepositoryByID(%d): %v", c.Label.RepoID, err) return nil } } diff --git a/modules/convert/issue_test.go b/services/convert/issue_test.go similarity index 100% rename from modules/convert/issue_test.go rename to services/convert/issue_test.go diff --git a/modules/convert/main_test.go b/services/convert/main_test.go similarity index 100% rename from modules/convert/main_test.go rename to services/convert/main_test.go diff --git a/modules/convert/mirror.go b/services/convert/mirror.go similarity index 100% rename from modules/convert/mirror.go rename to services/convert/mirror.go diff --git a/modules/convert/notification.go b/services/convert/notification.go similarity index 96% rename from modules/convert/notification.go rename to services/convert/notification.go index 49a1b148fb11..5d3b078a25d5 100644 --- a/modules/convert/notification.go +++ b/services/convert/notification.go @@ -7,6 +7,7 @@ import ( "net/url" activities_model "code.gitea.io/gitea/models/activities" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" api "code.gitea.io/gitea/modules/structs" ) @@ -23,7 +24,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(n.Repository, perm.AccessModeRead) + result.Repository = ToRepo(db.DefaultContext, n.Repository, perm.AccessModeRead) // This permission is not correct and we should not be reporting it for repository := result.Repository; repository != nil; repository = repository.Parent { diff --git a/modules/convert/package.go b/services/convert/package.go similarity index 95% rename from modules/convert/package.go rename to services/convert/package.go index 900f1dd816bd..68ae6f4e62db 100644 --- a/modules/convert/package.go +++ b/services/convert/package.go @@ -22,7 +22,7 @@ func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_m } if permission.HasAccess() { - repo = ToRepo(pd.Repository, permission.AccessMode) + repo = ToRepo(ctx, pd.Repository, permission.AccessMode) } } diff --git a/modules/convert/pull.go b/services/convert/pull.go similarity index 97% rename from modules/convert/pull.go rename to services/convert/pull.go index 4291d737a4db..db0add6cdee7 100644 --- a/modules/convert/pull.go +++ b/services/convert/pull.go @@ -79,7 +79,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u Name: pr.BaseBranch, Ref: pr.BaseBranch, RepoID: pr.BaseRepoID, - Repository: ToRepo(pr.BaseRepo, p.AccessMode), + Repository: ToRepo(ctx, pr.BaseRepo, p.AccessMode), }, Head: &api.PRBranchInfo{ Name: pr.HeadBranch, @@ -139,7 +139,7 @@ func ToAPIPullRequest(ctx context.Context, pr *issues_model.PullRequest, doer *u } apiPullRequest.Head.RepoID = pr.HeadRepo.ID - apiPullRequest.Head.Repository = ToRepo(pr.HeadRepo, p.AccessMode) + apiPullRequest.Head.Repository = ToRepo(ctx, pr.HeadRepo, p.AccessMode) headGitRepo, err := git.OpenRepository(ctx, pr.HeadRepo.RepoPath()) if err != nil { diff --git a/modules/convert/pull_review.go b/services/convert/pull_review.go similarity index 100% rename from modules/convert/pull_review.go rename to services/convert/pull_review.go diff --git a/modules/convert/pull_test.go b/services/convert/pull_test.go similarity index 95% rename from modules/convert/pull_test.go rename to services/convert/pull_test.go index 21d410cfcb5c..0915d096e66c 100644 --- a/modules/convert/pull_test.go +++ b/services/convert/pull_test.go @@ -31,7 +31,7 @@ func TestPullRequest_APIFormat(t *testing.T) { Ref: "refs/pull/2/head", Sha: "4a357436d925b5c974181ff12a994538ddc5a269", RepoID: 1, - Repository: ToRepo(headRepo, perm.AccessModeRead), + Repository: ToRepo(db.DefaultContext, headRepo, perm.AccessModeRead), }, apiPullRequest.Head) // withOut HeadRepo diff --git a/modules/convert/release.go b/services/convert/release.go similarity index 59% rename from modules/convert/release.go rename to services/convert/release.go index 95c6d03ab13d..3afa53c03f5f 100644 --- a/modules/convert/release.go +++ b/services/convert/release.go @@ -10,10 +10,6 @@ import ( // ToRelease convert a repo_model.Release to api.Release func ToRelease(r *repo_model.Release) *api.Release { - assets := make([]*api.Attachment, 0) - for _, att := range r.Attachments { - assets = append(assets, ToReleaseAttachment(att)) - } return &api.Release{ ID: r.ID, TagName: r.TagName, @@ -29,19 +25,6 @@ func ToRelease(r *repo_model.Release) *api.Release { CreatedAt: r.CreatedUnix.AsTime(), PublishedAt: r.CreatedUnix.AsTime(), Publisher: ToUser(r.Publisher, nil), - Attachments: assets, - } -} - -// ToReleaseAttachment converts models.Attachment to api.Attachment -func ToReleaseAttachment(a *repo_model.Attachment) *api.Attachment { - return &api.Attachment{ - ID: a.ID, - Name: a.Name, - Created: a.CreatedUnix.AsTime(), - DownloadCount: a.DownloadCount, - Size: a.Size, - UUID: a.UUID, - DownloadURL: a.DownloadURL(), + Attachments: ToAttachments(r.Attachments), } } diff --git a/modules/convert/repository.go b/services/convert/repository.go similarity index 83% rename from modules/convert/repository.go rename to services/convert/repository.go index 3c75f588fdf7..ce53a6669237 100644 --- a/modules/convert/repository.go +++ b/services/convert/repository.go @@ -4,10 +4,10 @@ package convert import ( + "context" "time" "code.gitea.io/gitea/models" - "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" @@ -16,11 +16,11 @@ import ( ) // ToRepo converts a Repository to api.Repository -func ToRepo(repo *repo_model.Repository, mode perm.AccessMode) *api.Repository { - return innerToRepo(repo, mode, false) +func ToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode) *api.Repository { + return innerToRepo(ctx, repo, mode, false) } -func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent bool) *api.Repository { +func innerToRepo(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode, isParent bool) *api.Repository { var parent *api.Repository cloneLink := repo.CloneLink() @@ -30,12 +30,12 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo Pull: mode >= perm.AccessModeRead, } if !isParent { - err := repo.GetBaseRepo() + err := repo.GetBaseRepo(ctx) if err != nil { return nil } if repo.BaseRepo != nil { - parent = innerToRepo(repo.BaseRepo, mode, true) + parent = innerToRepo(ctx, repo.BaseRepo, mode, true) } } @@ -43,7 +43,7 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo hasIssues := false var externalTracker *api.ExternalTracker var internalTracker *api.InternalTracker - if unit, err := repo.GetUnit(unit_model.TypeIssues); err == nil { + if unit, err := repo.GetUnit(ctx, unit_model.TypeIssues); err == nil { config := unit.IssuesConfig() hasIssues = true internalTracker = &api.InternalTracker{ @@ -51,7 +51,7 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo AllowOnlyContributorsToTrackTime: config.AllowOnlyContributorsToTrackTime, EnableIssueDependencies: config.EnableDependencies, } - } else if unit, err := repo.GetUnit(unit_model.TypeExternalTracker); err == nil { + } else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalTracker); err == nil { config := unit.ExternalTrackerConfig() hasIssues = true externalTracker = &api.ExternalTracker{ @@ -63,9 +63,9 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo } hasWiki := false var externalWiki *api.ExternalWiki - if _, err := repo.GetUnit(unit_model.TypeWiki); err == nil { + if _, err := repo.GetUnit(ctx, unit_model.TypeWiki); err == nil { hasWiki = true - } else if unit, err := repo.GetUnit(unit_model.TypeExternalWiki); err == nil { + } else if unit, err := repo.GetUnit(ctx, unit_model.TypeExternalWiki); err == nil { hasWiki = true config := unit.ExternalWikiConfig() externalWiki = &api.ExternalWiki{ @@ -81,7 +81,7 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo allowRebaseUpdate := false defaultDeleteBranchAfterMerge := false defaultMergeStyle := repo_model.MergeStyleMerge - if unit, err := repo.GetUnit(unit_model.TypePullRequests); err == nil { + if unit, err := repo.GetUnit(ctx, unit_model.TypePullRequests); err == nil { config := unit.PullRequestsConfig() hasPullRequests = true ignoreWhitespaceConflicts = config.IgnoreWhitespaceConflicts @@ -94,21 +94,21 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo defaultMergeStyle = config.GetDefaultMergeStyle() } hasProjects := false - if _, err := repo.GetUnit(unit_model.TypeProjects); err == nil { + if _, err := repo.GetUnit(ctx, unit_model.TypeProjects); err == nil { hasProjects = true } - if err := repo.GetOwner(db.DefaultContext); err != nil { + if err := repo.GetOwner(ctx); err != nil { return nil } - numReleases, _ := repo_model.GetReleaseCountByRepoID(repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false}) + numReleases, _ := repo_model.GetReleaseCountByRepoID(ctx, repo.ID, repo_model.FindReleasesOptions{IncludeDrafts: false, IncludeTags: false}) mirrorInterval := "" var mirrorUpdated time.Time if repo.IsMirror { var err error - repo.Mirror, err = repo_model.GetMirrorByRepoID(db.DefaultContext, repo.ID) + repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID) if err == nil { mirrorInterval = repo.Mirror.Interval.String() mirrorUpdated = repo.Mirror.UpdatedUnix.AsTime() @@ -117,11 +117,11 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo var transfer *api.RepoTransfer if repo.Status == repo_model.RepositoryPendingTransfer { - t, err := models.GetPendingRepositoryTransfer(repo) + t, err := models.GetPendingRepositoryTransfer(ctx, repo) if err != nil && !models.IsErrNoPendingTransfer(err) { log.Warn("GetPendingRepositoryTransfer: %v", err) } else { - if err := t.LoadAttributes(); err != nil { + if err := t.LoadAttributes(ctx); err != nil { log.Warn("LoadAttributes of RepoTransfer: %v", err) } else { transfer = ToRepoTransfer(t) diff --git a/modules/convert/status.go b/services/convert/status.go similarity index 80% rename from modules/convert/status.go rename to services/convert/status.go index 5eb38ad063dd..5fcf04074f88 100644 --- a/modules/convert/status.go +++ b/services/convert/status.go @@ -4,13 +4,15 @@ package convert import ( + "context" + git_model "code.gitea.io/gitea/models/git" user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" ) // ToCommitStatus converts git_model.CommitStatus to api.CommitStatus -func ToCommitStatus(status *git_model.CommitStatus) *api.CommitStatus { +func ToCommitStatus(ctx context.Context, status *git_model.CommitStatus) *api.CommitStatus { apiStatus := &api.CommitStatus{ Created: status.CreatedUnix.AsTime(), Updated: status.CreatedUnix.AsTime(), @@ -23,7 +25,7 @@ func ToCommitStatus(status *git_model.CommitStatus) *api.CommitStatus { } if status.CreatorID != 0 { - creator, _ := user_model.GetUserByID(status.CreatorID) + creator, _ := user_model.GetUserByID(ctx, status.CreatorID) apiStatus.Creator = ToUser(creator, nil) } @@ -31,7 +33,7 @@ func ToCommitStatus(status *git_model.CommitStatus) *api.CommitStatus { } // ToCombinedStatus converts List of CommitStatus to a CombinedStatus -func ToCombinedStatus(statuses []*git_model.CommitStatus, repo *api.Repository) *api.CombinedStatus { +func ToCombinedStatus(ctx context.Context, statuses []*git_model.CommitStatus, repo *api.Repository) *api.CombinedStatus { if len(statuses) == 0 { return nil } @@ -45,7 +47,7 @@ func ToCombinedStatus(statuses []*git_model.CommitStatus, repo *api.Repository) retStatus.Statuses = make([]*api.CommitStatus, 0, len(statuses)) for _, status := range statuses { - retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(status)) + retStatus.Statuses = append(retStatus.Statuses, ToCommitStatus(ctx, status)) if status.State.NoBetterThan(retStatus.State) { retStatus.State = status.State } diff --git a/modules/convert/user.go b/services/convert/user.go similarity index 100% rename from modules/convert/user.go rename to services/convert/user.go diff --git a/modules/convert/user_test.go b/services/convert/user_test.go similarity index 100% rename from modules/convert/user_test.go rename to services/convert/user_test.go diff --git a/modules/convert/utils.go b/services/convert/utils.go similarity index 100% rename from modules/convert/utils.go rename to services/convert/utils.go diff --git a/modules/convert/utils_test.go b/services/convert/utils_test.go similarity index 100% rename from modules/convert/utils_test.go rename to services/convert/utils_test.go diff --git a/modules/convert/wiki.go b/services/convert/wiki.go similarity index 100% rename from modules/convert/wiki.go rename to services/convert/wiki.go diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index acf3896b7142..05aef6623d4f 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -63,7 +63,7 @@ func registerRepoHealthCheck() { for _, arg := range rhcConfig.Args { args = append(args, git.CmdArg(arg)) } - return repo_service.GitFsck(ctx, rhcConfig.Timeout, args) + return repo_service.GitFsckRepos(ctx, rhcConfig.Timeout, args) }) } diff --git a/services/forms/package_form.go b/services/forms/package_form.go index 6c3ff52a9c01..734bb05dc69f 100644 --- a/services/forms/package_form.go +++ b/services/forms/package_form.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package forms diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index d4fb051d8daa..89a013d9af8d 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -134,6 +134,7 @@ type RepoSettingForm struct { EnablePrune bool // Advanced settings + EnableCode bool EnableWiki bool EnableExternalWiki bool ExternalWikiURL string diff --git a/services/forms/user_form.go b/services/forms/user_form.go index cd2c45261b90..bbea58310a40 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -363,6 +363,18 @@ func (f *AddKeyForm) Validate(req *http.Request, errs binding.Errors) binding.Er return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } +// AddSecretForm for adding secrets +type AddSecretForm struct { + Title string `binding:"Required;MaxSize(50)"` + Content string `binding:"Required"` +} + +// Validate validates the fields +func (f *AddSecretForm) Validate(req *http.Request, errs binding.Errors) binding.Errors { + ctx := context.GetContext(req) + return middleware.Validate(errs, ctx.Data, f, ctx.Locale) +} + // NewAccessTokenForm form for creating access token type NewAccessTokenForm struct { Name string `binding:"Required;MaxSize(255)"` diff --git a/services/issue/assignee.go b/services/issue/assignee.go index 2e62f7cf1ce1..e5e1456c3f12 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -50,7 +50,7 @@ func ToggleAssignee(issue *issues_model.Issue, doer *user_model.User, assigneeID return } - assignee, err1 := user_model.GetUserByIDCtx(db.DefaultContext, assigneeID) + assignee, err1 := user_model.GetUserByID(db.DefaultContext, assigneeID) if err1 != nil { err = err1 return diff --git a/services/issue/assignee_test.go b/services/issue/assignee_test.go index 946085cb91e4..114ace078edd 100644 --- a/services/issue/assignee_test.go +++ b/services/issue/assignee_test.go @@ -22,7 +22,7 @@ func TestDeleteNotPassedAssignee(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 1, len(issue.Assignees)) - user1, err := user_model.GetUserByID(1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him + user1, err := user_model.GetUserByID(db.DefaultContext, 1) // This user is already assigned (see the definition in fixtures), so running UpdateAssignee should unassign him assert.NoError(t, err) // Check if he got removed diff --git a/services/comments/comments.go b/services/issue/comments.go similarity index 63% rename from services/comments/comments.go rename to services/issue/comments.go index 21640d90b4ea..46c0daf70a33 100644 --- a/services/comments/comments.go +++ b/services/issue/comments.go @@ -1,10 +1,11 @@ // Copyright 2019 The Gitea Authors. All rights reserved. // SPDX-License-Identifier: MIT -package comments +package issue import ( "context" + "fmt" "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" @@ -14,9 +15,58 @@ import ( "code.gitea.io/gitea/modules/timeutil" ) +// CreateComment creates comment of issue or commit. +func CreateComment(opts *issues_model.CreateCommentOptions) (comment *issues_model.Comment, err error) { + ctx, committer, err := db.TxContext(db.DefaultContext) + if err != nil { + return nil, err + } + defer committer.Close() + + comment, err = issues_model.CreateComment(ctx, opts) + if err != nil { + return nil, err + } + + if err = committer.Commit(); err != nil { + return nil, err + } + + return comment, nil +} + +// CreateRefComment creates a commit reference comment to issue. +func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content, commitSHA string) error { + if len(commitSHA) == 0 { + return fmt.Errorf("cannot create reference with empty commit SHA") + } + + // Check if same reference from same commit has already existed. + has, err := db.GetEngine(db.DefaultContext).Get(&issues_model.Comment{ + Type: issues_model.CommentTypeCommitRef, + IssueID: issue.ID, + CommitSHA: commitSHA, + }) + if err != nil { + return fmt.Errorf("check reference comment: %w", err) + } else if has { + return nil + } + + _, err = CreateComment(&issues_model.CreateCommentOptions{ + Type: issues_model.CommentTypeCommitRef, + Doer: doer, + Repo: repo, + Issue: issue, + CommitSHA: commitSHA, + Content: content, + }) + return err +} + // CreateIssueComment creates a plain issue comment. func CreateIssueComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issue *issues_model.Issue, content string, attachments []string) (*issues_model.Comment, error) { - comment, err := issues_model.CreateComment(&issues_model.CreateCommentOptions{ + comment, err := CreateComment(&issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeComment, Doer: doer, Repo: repo, diff --git a/services/issue/commit.go b/services/issue/commit.go index f9d59b6bd0fd..db31fc66bb3b 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -119,7 +119,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm // issue is from another repo if len(ref.Owner) > 0 && len(ref.Name) > 0 { - refRepo, err = repo_model.GetRepositoryByOwnerAndName(ref.Owner, ref.Name) + refRepo, err = repo_model.GetRepositoryByOwnerAndName(db.DefaultContext, ref.Owner, ref.Name) if err != nil { if repo_model.IsErrRepoNotExist(err) { log.Warn("Repository referenced in commit but does not exist: %v", err) @@ -158,7 +158,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm } message := fmt.Sprintf(`%s`, html.EscapeString(repo.Link()), html.EscapeString(url.PathEscape(c.Sha1)), html.EscapeString(strings.SplitN(c.Message, "\n", 2)[0])) - if err = issues_model.CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil { + if err = CreateRefComment(doer, refRepo, refIssue, message, c.Sha1); err != nil { return err } diff --git a/services/issue/issue.go b/services/issue/issue.go index 23b48c28616e..b91ee4fc18b0 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -160,7 +160,7 @@ func DeleteIssue(doer *user_model.User, gitRepo *git.Repository, issue *issues_m // AddAssigneeIfNotAssigned adds an assignee only if he isn't already assigned to the issue. // Also checks for access of assigned user func AddAssigneeIfNotAssigned(issue *issues_model.Issue, doer *user_model.User, assigneeID int64) (err error) { - assignee, err := user_model.GetUserByIDCtx(db.DefaultContext, assigneeID) + assignee, err := user_model.GetUserByID(db.DefaultContext, assigneeID) if err != nil { return err } @@ -218,9 +218,16 @@ func deleteIssue(issue *issues_model.Issue) error { return err } - if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, issue.IsClosed); err != nil { + // update the total issue numbers + if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, false); err != nil { return err } + // if the issue is closed, update the closed issue numbers + if issue.IsClosed { + if err := repo_model.UpdateRepoIssueNumbers(ctx, issue.RepoID, issue.IsPull, true); err != nil { + return err + } + } if err := issues_model.UpdateMilestoneCounters(ctx, issue.MilestoneID); err != nil { return fmt.Errorf("error updating counters for milestone id %d: %w", diff --git a/services/issue/issue_test.go b/services/issue/issue_test.go index 44168388e63d..b67d2e2e79a2 100644 --- a/services/issue/issue_test.go +++ b/services/issue/issue_test.go @@ -66,7 +66,7 @@ func TestIssue_DeleteIssue(t *testing.T) { } // check issue dependencies - user, err := user_model.GetUserByID(1) + user, err := user_model.GetUserByID(db.DefaultContext, 1) assert.NoError(t, err) issue1, err := issues_model.GetIssueByID(db.DefaultContext, 1) assert.NoError(t, err) diff --git a/services/issue/milestone.go b/services/issue/milestone.go index 6019a28a9985..a9be8bd88787 100644 --- a/services/issue/milestone.go +++ b/services/issue/milestone.go @@ -54,7 +54,7 @@ func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *is OldMilestoneID: oldMilestoneID, MilestoneID: issue.MilestoneID, } - if _, err := issues_model.CreateCommentCtx(ctx, opts); err != nil { + if _, err := issues_model.CreateComment(ctx, opts); err != nil { return err } } diff --git a/services/lfs/locks.go b/services/lfs/locks.go index aab4f1a44ed0..d5fe3f4e314c 100644 --- a/services/lfs/locks.go +++ b/services/lfs/locks.go @@ -11,12 +11,12 @@ import ( git_model "code.gitea.io/gitea/models/git" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/json" lfs_module "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/services/convert" ) func handleLockListOut(ctx *context.Context, repo *repo_model.Repository, lock *git_model.LFSLock, err error) { @@ -39,7 +39,7 @@ func handleLockListOut(ctx *context.Context, repo *repo_model.Repository, lock * return } ctx.JSON(http.StatusOK, api.LFSLockList{ - Locks: []*api.LFSLock{convert.ToLFSLock(lock)}, + Locks: []*api.LFSLock{convert.ToLFSLock(ctx, lock)}, }) } @@ -47,7 +47,7 @@ func handleLockListOut(ctx *context.Context, repo *repo_model.Repository, lock * func GetListLockHandler(ctx *context.Context) { rv := getRequestContext(ctx) - repository, err := repo_model.GetRepositoryByOwnerAndName(rv.User, rv.Repo) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rv.User, rv.Repo) if err != nil { log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err) ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") @@ -117,7 +117,7 @@ func GetListLockHandler(ctx *context.Context) { lockListAPI := make([]*api.LFSLock, len(lockList)) next := "" for i, l := range lockList { - lockListAPI[i] = convert.ToLFSLock(l) + lockListAPI[i] = convert.ToLFSLock(ctx, l) } if limit > 0 && len(lockList) == limit { next = strconv.Itoa(cursor + 1) @@ -134,7 +134,7 @@ func PostLockHandler(ctx *context.Context) { repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git") authorization := ctx.Req.Header.Get("Authorization") - repository, err := repo_model.GetRepositoryByOwnerAndName(userName, repoName) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err) ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") @@ -174,7 +174,7 @@ func PostLockHandler(ctx *context.Context) { if err != nil { if git_model.IsErrLFSLockAlreadyExist(err) { ctx.JSON(http.StatusConflict, api.LFSLockError{ - Lock: convert.ToLFSLock(lock), + Lock: convert.ToLFSLock(ctx, lock), Message: "already created lock", }) return @@ -192,7 +192,7 @@ func PostLockHandler(ctx *context.Context) { }) return } - ctx.JSON(http.StatusCreated, api.LFSLockResponse{Lock: convert.ToLFSLock(lock)}) + ctx.JSON(http.StatusCreated, api.LFSLockResponse{Lock: convert.ToLFSLock(ctx, lock)}) } // VerifyLockHandler list locks for verification @@ -201,7 +201,7 @@ func VerifyLockHandler(ctx *context.Context) { repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git") authorization := ctx.Req.Header.Get("Authorization") - repository, err := repo_model.GetRepositoryByOwnerAndName(userName, repoName) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err) ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") @@ -249,9 +249,9 @@ func VerifyLockHandler(ctx *context.Context) { lockTheirsListAPI := make([]*api.LFSLock, 0, len(lockList)) for _, l := range lockList { if l.OwnerID == ctx.Doer.ID { - lockOursListAPI = append(lockOursListAPI, convert.ToLFSLock(l)) + lockOursListAPI = append(lockOursListAPI, convert.ToLFSLock(ctx, l)) } else { - lockTheirsListAPI = append(lockTheirsListAPI, convert.ToLFSLock(l)) + lockTheirsListAPI = append(lockTheirsListAPI, convert.ToLFSLock(ctx, l)) } } ctx.JSON(http.StatusOK, api.LFSLockListVerify{ @@ -267,7 +267,7 @@ func UnLockHandler(ctx *context.Context) { repoName := strings.TrimSuffix(ctx.Params("reponame"), ".git") authorization := ctx.Req.Header.Get("Authorization") - repository, err := repo_model.GetRepositoryByOwnerAndName(userName, repoName) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, userName, repoName) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", userName, repoName, err) ctx.Resp.Header().Set("WWW-Authenticate", "Basic realm=gitea-lfs") @@ -315,5 +315,5 @@ func UnLockHandler(ctx *context.Context) { }) return } - ctx.JSON(http.StatusOK, api.LFSLockResponse{Lock: convert.ToLFSLock(lock)}) + ctx.JSON(http.StatusOK, api.LFSLockResponse{Lock: convert.ToLFSLock(ctx, lock)}) } diff --git a/services/lfs/server.go b/services/lfs/server.go index 32bd843ebfa1..8fd2759132f9 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -4,6 +4,7 @@ package lfs import ( + stdCtx "context" "crypto/sha256" "encoding/base64" "encoding/hex" @@ -408,7 +409,7 @@ func getAuthenticatedMeta(ctx *context.Context, rc *requestContext, p lfs_module } func getAuthenticatedRepository(ctx *context.Context, rc *requestContext, requireWrite bool) *repo_model.Repository { - repository, err := repo_model.GetRepositoryByOwnerAndName(rc.User, rc.Repo) + repository, err := repo_model.GetRepositoryByOwnerAndName(ctx, rc.User, rc.Repo) if err != nil { log.Error("Unable to get repository: %s/%s Error: %v", rc.User, rc.Repo, err) writeStatus(ctx, http.StatusNotFound) @@ -506,7 +507,7 @@ func authenticate(ctx *context.Context, repository *repo_model.Repository, autho return true } - user, err := parseToken(authorization, repository, accessMode) + user, err := parseToken(ctx, authorization, repository, accessMode) if err != nil { // Most of these are Warn level - the true internal server errors are logged in parseToken already log.Warn("Authentication failure for provided token with Error: %v", err) @@ -516,7 +517,7 @@ func authenticate(ctx *context.Context, repository *repo_model.Repository, autho return true } -func handleLFSToken(tokenSHA string, target *repo_model.Repository, mode perm.AccessMode) (*user_model.User, error) { +func handleLFSToken(ctx stdCtx.Context, tokenSHA string, target *repo_model.Repository, mode perm.AccessMode) (*user_model.User, error) { if !strings.Contains(tokenSHA, ".") { return nil, nil } @@ -543,7 +544,7 @@ func handleLFSToken(tokenSHA string, target *repo_model.Repository, mode perm.Ac return nil, fmt.Errorf("invalid token claim") } - u, err := user_model.GetUserByID(claims.UserID) + u, err := user_model.GetUserByID(ctx, claims.UserID) if err != nil { log.Error("Unable to GetUserById[%d]: Error: %v", claims.UserID, err) return nil, err @@ -551,7 +552,7 @@ func handleLFSToken(tokenSHA string, target *repo_model.Repository, mode perm.Ac return u, nil } -func parseToken(authorization string, target *repo_model.Repository, mode perm.AccessMode) (*user_model.User, error) { +func parseToken(ctx stdCtx.Context, authorization string, target *repo_model.Repository, mode perm.AccessMode) (*user_model.User, error) { if authorization == "" { return nil, fmt.Errorf("no token") } @@ -565,7 +566,7 @@ func parseToken(authorization string, target *repo_model.Repository, mode perm.A case "bearer": fallthrough case "token": - return handleLFSToken(tokenSHA, target, mode) + return handleLFSToken(ctx, tokenSHA, target, mode) } return nil, fmt.Errorf("token not found") } diff --git a/services/mailer/mail_team_invite.go b/services/mailer/mail_team_invite.go index f01d6f47dd13..54e82b02343e 100644 --- a/services/mailer/mail_team_invite.go +++ b/services/mailer/mail_team_invite.go @@ -26,7 +26,7 @@ func MailTeamInvite(ctx context.Context, inviter *user_model.User, team *org_mod return nil } - org, err := user_model.GetUserByIDCtx(ctx, team.OrgID) + org, err := user_model.GetUserByID(ctx, team.OrgID) if err != nil { return err } diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index ea9b1a714243..23aa4ac2ca9d 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -17,7 +17,6 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/foreignreference" issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -109,7 +108,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate Status: repo_model.RepositoryBeingMigrated, }) } else { - r, err = repo_model.GetRepositoryByID(opts.MigrateToRepoID) + r, err = repo_model.GetRepositoryByID(g.ctx, opts.MigrateToRepoID) } if err != nil { return err @@ -403,16 +402,6 @@ func (g *GiteaLocalUploader) CreateIssues(issues ...*base.Issue) error { Labels: labels, CreatedUnix: timeutil.TimeStamp(issue.Created.Unix()), UpdatedUnix: timeutil.TimeStamp(issue.Updated.Unix()), - ForeignReference: &foreignreference.ForeignReference{ - LocalIndex: issue.GetLocalIndex(), - ForeignIndex: strconv.FormatInt(issue.GetForeignIndex(), 10), - RepoID: g.repo.ID, - Type: foreignreference.TypeIssue, - }, - } - - if is.ForeignReference.ForeignIndex == "0" { - is.ForeignReference.ForeignIndex = strconv.FormatInt(is.Index, 10) } if err := g.remapUser(issue, &is); err != nil { diff --git a/services/packages/auth.go b/services/packages/auth.go index 9b84ac79a6c3..a7acdaf1c3a9 100644 --- a/services/packages/auth.go +++ b/services/packages/auth.go @@ -10,6 +10,7 @@ import ( "time" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "github.com/golang-jwt/jwt/v4" @@ -41,9 +42,15 @@ func CreateAuthorizationToken(u *user_model.User) (string, error) { } func ParseAuthorizationToken(req *http.Request) (int64, error) { - parts := strings.SplitN(req.Header.Get("Authorization"), " ", 2) + h := req.Header.Get("Authorization") + if h == "" { + return 0, nil + } + + parts := strings.SplitN(h, " ", 2) if len(parts) != 2 { - return 0, fmt.Errorf("no token") + log.Error("split token failed: %s", h) + return 0, fmt.Errorf("split token failed") } token, err := jwt.ParseWithClaims(parts[1], &packageClaims{}, func(t *jwt.Token) (interface{}, error) { diff --git a/services/packages/container/common.go b/services/packages/container/common.go index 40d8914a0163..5a14ed5b7a03 100644 --- a/services/packages/container/common.go +++ b/services/packages/container/common.go @@ -1,6 +1,5 @@ // Copyright 2022 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. +// SPDX-License-Identifier: MIT package container diff --git a/services/packages/packages.go b/services/packages/packages.go index f819949c9695..49f5a2fac4e2 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -5,6 +5,7 @@ package packages import ( "context" + "encoding/hex" "errors" "fmt" "io" @@ -229,10 +230,10 @@ func NewPackageBlob(hsr packages_module.HashedSizeReader) *packages_model.Packag return &packages_model.PackageBlob{ Size: hsr.Size(), - HashMD5: fmt.Sprintf("%x", hashMD5), - HashSHA1: fmt.Sprintf("%x", hashSHA1), - HashSHA256: fmt.Sprintf("%x", hashSHA256), - HashSHA512: fmt.Sprintf("%x", hashSHA512), + HashMD5: hex.EncodeToString(hashMD5), + HashSHA1: hex.EncodeToString(hashSHA1), + HashSHA256: hex.EncodeToString(hashSHA256), + HashSHA512: hex.EncodeToString(hashSHA512), } } diff --git a/services/pull/check.go b/services/pull/check.go index af8f2df0b6a5..86460cd49cad 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -126,7 +126,7 @@ func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *acce // isSignedIfRequired check if merge will be signed if required func isSignedIfRequired(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.User) (bool, error) { - if err := pr.LoadProtectedBranchCtx(ctx); err != nil { + if err := pr.LoadProtectedBranch(ctx); err != nil { return false, err } @@ -165,7 +165,7 @@ func checkAndUpdateStatus(ctx context.Context, pr *issues_model.PullRequest) { func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Commit, error) { if pr.BaseRepo == nil { var err error - pr.BaseRepo, err = repo_model.GetRepositoryByID(pr.BaseRepoID) + pr.BaseRepo, err = repo_model.GetRepositoryByID(ctx, pr.BaseRepoID) if err != nil { return nil, fmt.Errorf("GetRepositoryByID: %w", err) } @@ -199,19 +199,19 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com return nil, fmt.Errorf("ReadFile(%s): %w", headFile, err) } commitID := string(commitIDBytes) - if len(commitID) < 40 { + if len(commitID) < git.SHAFullLength { return nil, fmt.Errorf(`ReadFile(%s): invalid commit-ID "%s"`, headFile, commitID) } - cmd := commitID[:40] + ".." + pr.BaseBranch + cmd := commitID[:git.SHAFullLength] + ".." + pr.BaseBranch // Get the commit from BaseBranch where the pull request got merged mergeCommit, _, err := git.NewCommand(ctx, "rev-list", "--ancestry-path", "--merges", "--reverse").AddDynamicArguments(cmd). RunStdString(&git.RunOpts{Dir: "", Env: []string{"GIT_INDEX_FILE=" + indexTmpPath, "GIT_DIR=" + pr.BaseRepo.RepoPath()}}) if err != nil { return nil, fmt.Errorf("git rev-list --ancestry-path --merges --reverse: %w", err) - } else if len(mergeCommit) < 40 { + } else if len(mergeCommit) < git.SHAFullLength { // PR was maybe fast-forwarded, so just use last commit of PR - mergeCommit = commitID[:40] + mergeCommit = commitID[:git.SHAFullLength] } gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo.RepoPath()) @@ -220,9 +220,9 @@ func getMergeCommit(ctx context.Context, pr *issues_model.PullRequest) (*git.Com } defer gitRepo.Close() - commit, err := gitRepo.GetCommit(mergeCommit[:40]) + commit, err := gitRepo.GetCommit(mergeCommit[:git.SHAFullLength]) if err != nil { - return nil, fmt.Errorf("GetMergeCommit[%v]: %w", mergeCommit[:40], err) + return nil, fmt.Errorf("GetMergeCommit[%v]: %w", mergeCommit[:git.SHAFullLength], err) } return commit, nil @@ -236,7 +236,7 @@ func manuallyMerged(ctx context.Context, pr *issues_model.PullRequest) bool { return false } - if unit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests); err == nil { + if unit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests); err == nil { config := unit.PullRequestsConfig() if !config.AutodetectManualMerge { return false diff --git a/services/pull/comment.go b/services/pull/comment.go new file mode 100644 index 000000000000..068aca6cd128 --- /dev/null +++ b/services/pull/comment.go @@ -0,0 +1,162 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package pull + +import ( + "context" + + issues_model "code.gitea.io/gitea/models/issues" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/json" + issue_service "code.gitea.io/gitea/services/issue" +) + +type commitBranchCheckItem struct { + Commit *git.Commit + Checked bool +} + +func commitBranchCheck(gitRepo *git.Repository, startCommit *git.Commit, endCommitID, baseBranch string, commitList map[string]*commitBranchCheckItem) error { + if startCommit.ID.String() == endCommitID { + return nil + } + + checkStack := make([]string, 0, 10) + checkStack = append(checkStack, startCommit.ID.String()) + + for len(checkStack) > 0 { + commitID := checkStack[0] + checkStack = checkStack[1:] + + item, ok := commitList[commitID] + if !ok { + continue + } + + if item.Commit.ID.String() == endCommitID { + continue + } + + if err := item.Commit.LoadBranchName(); err != nil { + return err + } + + if item.Commit.Branch == baseBranch { + continue + } + + if item.Checked { + continue + } + + item.Checked = true + + parentNum := item.Commit.ParentCount() + for i := 0; i < parentNum; i++ { + parentCommit, err := item.Commit.Parent(i) + if err != nil { + return err + } + checkStack = append(checkStack, parentCommit.ID.String()) + } + } + return nil +} + +// getCommitIDsFromRepo get commit IDs from repo in between oldCommitID and newCommitID +// isForcePush will be true if oldCommit isn't on the branch +// Commit on baseBranch will skip +func getCommitIDsFromRepo(ctx context.Context, repo *repo_model.Repository, oldCommitID, newCommitID, baseBranch string) (commitIDs []string, isForcePush bool, err error) { + repoPath := repo.RepoPath() + gitRepo, closer, err := git.RepositoryFromContextOrOpen(ctx, repoPath) + if err != nil { + return nil, false, err + } + defer closer.Close() + + oldCommit, err := gitRepo.GetCommit(oldCommitID) + if err != nil { + return nil, false, err + } + + if err = oldCommit.LoadBranchName(); err != nil { + return nil, false, err + } + + if len(oldCommit.Branch) == 0 { + commitIDs = make([]string, 2) + commitIDs[0] = oldCommitID + commitIDs[1] = newCommitID + + return commitIDs, true, err + } + + newCommit, err := gitRepo.GetCommit(newCommitID) + if err != nil { + return nil, false, err + } + + commits, err := newCommit.CommitsBeforeUntil(oldCommitID) + if err != nil { + return nil, false, err + } + + commitIDs = make([]string, 0, len(commits)) + commitChecks := make(map[string]*commitBranchCheckItem) + + for _, commit := range commits { + commitChecks[commit.ID.String()] = &commitBranchCheckItem{ + Commit: commit, + Checked: false, + } + } + + if err = commitBranchCheck(gitRepo, newCommit, oldCommitID, baseBranch, commitChecks); err != nil { + return + } + + for i := len(commits) - 1; i >= 0; i-- { + commitID := commits[i].ID.String() + if item, ok := commitChecks[commitID]; ok && item.Checked { + commitIDs = append(commitIDs, commitID) + } + } + + return commitIDs, isForcePush, err +} + +// CreatePushPullComment create push code to pull base comment +func CreatePushPullComment(ctx context.Context, pusher *user_model.User, pr *issues_model.PullRequest, oldCommitID, newCommitID string) (comment *issues_model.Comment, err error) { + if pr.HasMerged || oldCommitID == "" || newCommitID == "" { + return nil, nil + } + + ops := &issues_model.CreateCommentOptions{ + Type: issues_model.CommentTypePullRequestPush, + Doer: pusher, + Repo: pr.BaseRepo, + } + + var data issues_model.PushActionContent + + data.CommitIDs, data.IsForcePush, err = getCommitIDsFromRepo(ctx, pr.BaseRepo, oldCommitID, newCommitID, pr.BaseBranch) + if err != nil { + return nil, err + } + + ops.Issue = pr.Issue + + dataJSON, err := json.Marshal(data) + if err != nil { + return nil, err + } + + ops.Content = string(dataJSON) + + comment, err = issue_service.CreateComment(ops) + + return comment, err +} diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index 7e4db311d9a7..e075248a3667 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -83,7 +83,7 @@ func IsCommitStatusContextSuccess(commitStatuses []*git_model.CommitStatus, requ // IsPullCommitStatusPass returns if all required status checks PASS func IsPullCommitStatusPass(ctx context.Context, pr *issues_model.PullRequest) (bool, error) { - if err := pr.LoadProtectedBranchCtx(ctx); err != nil { + if err := pr.LoadProtectedBranch(ctx); err != nil { return false, errors.Wrap(err, "GetLatestCommitStatus") } if pr.ProtectedBranch == nil || !pr.ProtectedBranch.EnableStatusCheck { @@ -137,7 +137,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *issues_model.PullR return "", errors.Wrap(err, "GetLatestCommitStatus") } - if err := pr.LoadProtectedBranchCtx(ctx); err != nil { + if err := pr.LoadProtectedBranch(ctx); err != nil { return "", errors.Wrap(err, "LoadProtectedBranch") } var requiredContexts []string diff --git a/services/pull/merge.go b/services/pull/merge.go index afed98989b5b..7a936163f1fe 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -39,22 +39,22 @@ import ( ) // GetDefaultMergeMessage returns default message used when merging pull request -func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle) (string, error) { +func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr *issues_model.PullRequest, mergeStyle repo_model.MergeStyle) (message, body string, err error) { if err := pr.LoadHeadRepo(ctx); err != nil { - return "", err + return "", "", err } if err := pr.LoadBaseRepo(ctx); err != nil { - return "", err + return "", "", err } if pr.BaseRepo == nil { - return "", repo_model.ErrRepoNotExist{ID: pr.BaseRepoID} + return "", "", repo_model.ErrRepoNotExist{ID: pr.BaseRepoID} } if err := pr.LoadIssue(ctx); err != nil { - return "", err + return "", "", err } - isExternalTracker := pr.BaseRepo.UnitEnabled(unit.TypeExternalTracker) + isExternalTracker := pr.BaseRepo.UnitEnabled(ctx, unit.TypeExternalTracker) issueReference := "#" if isExternalTracker { issueReference = "!" @@ -64,12 +64,12 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr templateFilepath := fmt.Sprintf(".gitea/default_merge_message/%s_TEMPLATE.md", strings.ToUpper(string(mergeStyle))) commit, err := baseGitRepo.GetBranchCommit(pr.BaseRepo.DefaultBranch) if err != nil { - return "", err + return "", "", err } templateContent, err := commit.GetFileContent(templateFilepath, setting.Repository.PullRequest.DefaultMergeMessageSize) if err != nil { if !git.IsErrNotExist(err) { - return "", err + return "", "", err } } else { vars := map[string]string{ @@ -107,27 +107,35 @@ func GetDefaultMergeMessage(ctx context.Context, baseGitRepo *git.Repository, pr vars["ClosingIssues"] = "" } } - - return os.Expand(templateContent, func(s string) string { - return vars[s] - }), nil + message, body = expandDefaultMergeMessage(templateContent, vars) + return message, body, nil } } // Squash merge has a different from other styles. if mergeStyle == repo_model.MergeStyleSquash { - return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), nil + return fmt.Sprintf("%s (%s%d)", pr.Issue.Title, issueReference, pr.Issue.Index), "", nil } if pr.BaseRepoID == pr.HeadRepoID { - return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil + return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), "", nil } if pr.HeadRepo == nil { - return fmt.Sprintf("Merge pull request '%s' (%s%d) from :%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), nil + return fmt.Sprintf("Merge pull request '%s' (%s%d) from :%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadBranch, pr.BaseBranch), "", nil } - return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), nil + return fmt.Sprintf("Merge pull request '%s' (%s%d) from %s:%s into %s", pr.Issue.Title, issueReference, pr.Issue.Index, pr.HeadRepo.FullName(), pr.HeadBranch, pr.BaseBranch), "", nil +} + +func expandDefaultMergeMessage(template string, vars map[string]string) (message, body string) { + message = strings.TrimSpace(template) + if splits := strings.SplitN(message, "\n", 2); len(splits) == 2 { + message = splits[0] + body = strings.TrimSpace(splits[1]) + } + mapping := func(s string) string { return vars[s] } + return os.Expand(message, mapping), os.Expand(body, mapping) } // Merge merges pull request to base repository. @@ -145,11 +153,11 @@ func Merge(ctx context.Context, pr *issues_model.PullRequest, doer *user_model.U defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID)) // Removing an auto merge pull and ignore if not exist - if err := pull_model.DeleteScheduledAutoMerge(db.DefaultContext, pr.ID); err != nil && !db.IsErrNotExist(err) { + if err := pull_model.DeleteScheduledAutoMerge(ctx, pr.ID); err != nil && !db.IsErrNotExist(err) { return err } - prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err) return err @@ -752,7 +760,7 @@ func IsUserAllowedToMerge(ctx context.Context, pr *issues_model.PullRequest, p a return false, nil } - err := pr.LoadProtectedBranchCtx(ctx) + err := pr.LoadProtectedBranch(ctx) if err != nil { return false, err } @@ -770,7 +778,7 @@ func CheckPullBranchProtections(ctx context.Context, pr *issues_model.PullReques return fmt.Errorf("LoadBaseRepo: %w", err) } - if err = pr.LoadProtectedBranchCtx(ctx); err != nil { + if err = pr.LoadProtectedBranch(ctx); err != nil { return fmt.Errorf("LoadProtectedBranch: %w", err) } if pr.ProtectedBranch == nil { @@ -828,7 +836,7 @@ func MergedManually(pr *issues_model.PullRequest, doer *user_model.User, baseGit defer pullWorkingPool.CheckOut(fmt.Sprint(pr.ID)) if err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { - prUnit, err := pr.BaseRepo.GetUnitCtx(ctx, unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { return err } @@ -839,7 +847,7 @@ func MergedManually(pr *issues_model.PullRequest, doer *user_model.User, baseGit return models.ErrInvalidMergeStyle{ID: pr.BaseRepo.ID, Style: repo_model.MergeStyleManuallyMerged} } - if len(commitID) < 40 { + if len(commitID) < git.SHAFullLength { return fmt.Errorf("Wrong commit ID") } diff --git a/services/pull/merge_test.go b/services/pull/merge_test.go new file mode 100644 index 000000000000..6df6f55d4611 --- /dev/null +++ b/services/pull/merge_test.go @@ -0,0 +1,67 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package pull + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func Test_expandDefaultMergeMessage(t *testing.T) { + type args struct { + template string + vars map[string]string + } + tests := []struct { + name string + args args + want string + wantBody string + }{ + { + name: "single line", + args: args{ + template: "Merge ${PullRequestTitle}", + vars: map[string]string{ + "PullRequestTitle": "PullRequestTitle", + "PullRequestDescription": "Pull\nRequest\nDescription\n", + }, + }, + want: "Merge PullRequestTitle", + wantBody: "", + }, + { + name: "multiple lines", + args: args{ + template: "Merge ${PullRequestTitle}\nDescription:\n\n${PullRequestDescription}\n", + vars: map[string]string{ + "PullRequestTitle": "PullRequestTitle", + "PullRequestDescription": "Pull\nRequest\nDescription\n", + }, + }, + want: "Merge PullRequestTitle", + wantBody: "Description:\n\nPull\nRequest\nDescription\n", + }, + { + name: "leading newlines", + args: args{ + template: "\n\n\nMerge ${PullRequestTitle}\n\n\nDescription:\n\n${PullRequestDescription}\n", + vars: map[string]string{ + "PullRequestTitle": "PullRequestTitle", + "PullRequestDescription": "Pull\nRequest\nDescription\n", + }, + }, + want: "Merge PullRequestTitle", + wantBody: "Description:\n\nPull\nRequest\nDescription\n", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1 := expandDefaultMergeMessage(tt.args.template, tt.args.vars) + assert.Equalf(t, tt.want, got, "expandDefaultMergeMessage(%v, %v)", tt.args.template, tt.args.vars) + assert.Equalf(t, tt.wantBody, got1, "expandDefaultMergeMessage(%v, %v)", tt.args.template, tt.args.vars) + }) + } +} diff --git a/services/pull/patch.go b/services/pull/patch.go index 925f310a2c05..9ef8b86043d6 100644 --- a/services/pull/patch.go +++ b/services/pull/patch.go @@ -14,6 +14,7 @@ import ( "strings" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/container" @@ -22,6 +23,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/process" repo_module "code.gitea.io/gitea/modules/repository" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "github.com/gobwas/glob" @@ -52,6 +54,8 @@ var patchErrorSuffices = []string{ ": patch does not apply", ": already exists in working directory", "unrecognized input", + ": No such file or directory", + ": does not exist in index", } // TestPatch will test whether a simple patch will apply @@ -286,13 +290,15 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * // 2. AttemptThreeWayMerge first - this is much quicker than plain patch to base description := fmt.Sprintf("PR[%d] %s/%s#%d", pr.ID, pr.BaseRepo.OwnerName, pr.BaseRepo.Name, pr.Index) - conflict, _, err := AttemptThreeWayMerge(ctx, + conflict, conflictFiles, err := AttemptThreeWayMerge(ctx, tmpBasePath, gitRepo, pr.MergeBase, "base", "tracking", description) if err != nil { return false, err } if !conflict { + // No conflicts detected so we need to check if the patch is empty... + // a. Write the newly merged tree and check the new tree-hash var treeHash string treeHash, _, err = git.NewCommand(ctx, "write-tree").RunStdString(&git.RunOpts{Dir: tmpBasePath}) if err != nil { @@ -304,6 +310,8 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * if err != nil { return false, err } + + // b. compare the new tree-hash with the base tree hash if treeHash == baseTree.ID.String() { log.Debug("PullRequest[%d]: Patch is empty - ignoring", pr.ID) pr.Status = issues_model.PullRequestStatusEmpty @@ -312,9 +320,17 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * return false, nil } - // 3. OK read-tree has failed so we need to try a different thing - this might actually succeed where the above fails due to whitespace handling. + // 3. OK the three-way merge method has detected conflicts + // 3a. Are still testing with GitApply? If not set the conflict status and move on + if !setting.Repository.PullRequest.TestConflictingPatchesWithGitApply { + pr.Status = issues_model.PullRequestStatusConflict + pr.ConflictedFiles = conflictFiles + + log.Trace("Found %d files conflicted: %v", len(pr.ConflictedFiles), pr.ConflictedFiles) + return true, nil + } - // 3a. Create a plain patch from head to base + // 3b. Create a plain patch from head to base tmpPatchFile, err := os.CreateTemp("", "patch") if err != nil { log.Error("Unable to create temporary patch file! Error: %v", err) @@ -337,7 +353,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * patchPath := tmpPatchFile.Name() tmpPatchFile.Close() - // 3b. if the size of that patch is 0 - there can be no conflicts! + // 3c. if the size of that patch is 0 - there can be no conflicts! if stat.Size() == 0 { log.Debug("PullRequest[%d]: Patch is empty - ignoring", pr.ID) pr.Status = issues_model.PullRequestStatusEmpty @@ -353,7 +369,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * } // 5. Now get the pull request configuration to check if we need to ignore whitespace - prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { return false, err } @@ -415,6 +431,7 @@ func checkConflicts(ctx context.Context, pr *issues_model.PullRequest, gitRepo * scanner := bufio.NewScanner(stderrReader) for scanner.Scan() { line := scanner.Text() + log.Trace("PullRequest[%d].testPatch: stderr: %s", pr.ID, line) if strings.HasPrefix(line, prefix) { conflict = true filepath := strings.TrimSpace(strings.Split(line[len(prefix):], ":")[0]) @@ -533,7 +550,7 @@ func checkPullFilesProtection(pr *issues_model.PullRequest, gitRepo *git.Reposit return nil } - if err := pr.LoadProtectedBranch(); err != nil { + if err := pr.LoadProtectedBranch(db.DefaultContext); err != nil { return err } diff --git a/services/pull/pull.go b/services/pull/pull.go index ddb407b05384..afb0fa244244 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -123,7 +123,7 @@ func NewPullRequest(ctx context.Context, repo *repo_model.Repository, pull *issu Content: string(dataJSON), } - _, _ = issues_model.CreateComment(ops) + _, _ = issue_service.CreateComment(ops) } return nil @@ -222,7 +222,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer OldRef: oldBranch, NewRef: targetBranch, } - if _, err = issues_model.CreateComment(options); err != nil { + if _, err = issue_service.CreateComment(options); err != nil { return fmt.Errorf("CreateChangeTargetBranchComment: %w", err) } @@ -230,7 +230,7 @@ func ChangeTargetBranch(ctx context.Context, pr *issues_model.PullRequest, doer } func checkForInvalidation(ctx context.Context, requests issues_model.PullRequestList, repoID int64, doer *user_model.User, branch string) error { - repo, err := repo_model.GetRepositoryByIDCtx(ctx, repoID) + repo, err := repo_model.GetRepositoryByID(ctx, repoID) if err != nil { return fmt.Errorf("GetRepositoryByIDCtx: %w", err) } @@ -317,7 +317,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, } AddToTaskQueue(pr) - comment, err := issues_model.CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID) + comment, err := CreatePushPullComment(ctx, doer, pr, oldCommitID, newCommitID) if err == nil && comment != nil { notification.NotifyPullRequestPushCommits(ctx, doer, pr, comment) } @@ -594,7 +594,7 @@ func GetSquashMergeCommitMessages(ctx context.Context, pr *issues_model.PullRequ if pr.HeadRepo == nil { var err error - pr.HeadRepo, err = repo_model.GetRepositoryByIDCtx(ctx, pr.HeadRepoID) + pr.HeadRepo, err = repo_model.GetRepositoryByID(ctx, pr.HeadRepoID) if err != nil { log.Error("GetRepositoryByIdCtx[%d]: %v", pr.HeadRepoID, err) return "" diff --git a/services/pull/pull_test.go b/services/pull/pull_test.go index cbbdccce9c07..d63227a7d5e9 100644 --- a/services/pull/pull_test.go +++ b/services/pull/pull_test.go @@ -45,13 +45,13 @@ func TestPullRequest_GetDefaultMergeMessage_InternalTracker(t *testing.T) { assert.NoError(t, err) defer gitRepo.Close() - mergeMessage, err := GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") + mergeMessage, _, err := GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (#3) from branch2 into master", mergeMessage) pr.BaseRepoID = 1 pr.HeadRepoID = 2 - mergeMessage, err = GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") + mergeMessage, _, err = GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo1:branch2 into master", mergeMessage) } @@ -75,7 +75,7 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { assert.NoError(t, err) defer gitRepo.Close() - mergeMessage, err := GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") + mergeMessage, _, err := GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (!3) from branch2 into master", mergeMessage) @@ -84,7 +84,7 @@ func TestPullRequest_GetDefaultMergeMessage_ExternalTracker(t *testing.T) { pr.HeadRepoID = 2 pr.BaseRepo = nil pr.HeadRepo = nil - mergeMessage, err = GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") + mergeMessage, _, err = GetDefaultMergeMessage(db.DefaultContext, gitRepo, pr, "") assert.NoError(t, err) assert.Equal(t, "Merge pull request 'issue3' (#3) from user2/repo2:branch2 into master", mergeMessage) diff --git a/services/pull/review.go b/services/pull/review.go index 1f2bc77e2cd1..67a10d7aad61 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/notification" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" + issue_service "code.gitea.io/gitea/services/issue" ) // CreateCodeComment creates a comment on the code line @@ -202,7 +203,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo return nil, err } } - return issues_model.CreateComment(&issues_model.CreateCommentOptions{ + return issue_service.CreateComment(&issues_model.CreateCommentOptions{ Type: issues_model.CommentTypeCode, Doer: doer, Repo: repo, @@ -322,7 +323,7 @@ func DismissReview(ctx context.Context, reviewID, repoID int64, message string, return } - comment, err = issues_model.CreateComment(&issues_model.CreateCommentOptions{ + comment, err = issue_service.CreateComment(&issues_model.CreateCommentOptions{ Doer: doer, Content: message, Type: issues_model.CommentTypeDismissReview, diff --git a/services/pull/temp_repo.go b/services/pull/temp_repo.go index 842719467f36..d49a15cea00a 100644 --- a/services/pull/temp_repo.go +++ b/services/pull/temp_repo.go @@ -166,7 +166,7 @@ func createTemporaryRepo(ctx context.Context, pr *issues_model.PullRequest) (str var headBranch string if pr.Flow == issues_model.PullRequestFlowGithub { headBranch = git.BranchPrefix + pr.HeadBranch - } else if len(pr.HeadCommitID) == 40 { // for not created pull request + } else if len(pr.HeadCommitID) == git.SHAFullLength { // for not created pull request headBranch = pr.HeadCommitID } else { headBranch = pr.GetGitRefName() diff --git a/services/pull/update.go b/services/pull/update.go index 6ff554e612c9..e09dbf624457 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -99,14 +99,14 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *issues_model.PullRequest, BaseBranch: pull.HeadBranch, } - err = pr.LoadProtectedBranch() + err = pr.LoadProtectedBranch(ctx) if err != nil { return false, false, err } // can't do rebase on protected branch because need force push if pr.ProtectedBranch == nil { - prUnit, err := pr.BaseRepo.GetUnit(unit.TypePullRequests) + prUnit, err := pr.BaseRepo.GetUnit(ctx, unit.TypePullRequests) if err != nil { log.Error("pr.BaseRepo.GetUnit(unit.TypePullRequests): %v", err) return false, false, err diff --git a/services/release/release.go b/services/release/release.go index 07e329cf43cd..13042cd3ac2e 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -21,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" ) func createTag(ctx context.Context, gitRepo *git.Repository, rel *repo_model.Release, msg string) (bool, error) { @@ -218,7 +219,10 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod } for _, attach := range attachments { if attach.ReleaseID != rel.ID { - return errors.New("delete attachement of release permission denied") + return util.SilentWrap{ + Message: "delete attachment of release permission denied", + Err: util.ErrPermissionDenied, + } } deletedUUIDs.Add(attach.UUID) } @@ -240,7 +244,10 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *repo_mod } for _, attach := range attachments { if attach.ReleaseID != rel.ID { - return errors.New("update attachement of release permission denied") + return util.SilentWrap{ + Message: "update attachment of release permission denied", + Err: util.ErrPermissionDenied, + } } } @@ -289,7 +296,7 @@ func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, del return fmt.Errorf("GetReleaseByID: %w", err) } - repo, err := repo_model.GetRepositoryByIDCtx(ctx, rel.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID) if err != nil { return fmt.Errorf("GetRepositoryByID: %w", err) } diff --git a/services/repository/adopt.go b/services/repository/adopt.go index fb7adcfd2948..93eeb56456f4 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -116,7 +116,7 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r // Re-fetch the repository from database before updating it (else it would // override changes that were done earlier with sql) - if repo, err = repo_model.GetRepositoryByIDCtx(ctx, repo.ID); err != nil { + if repo, err = repo_model.GetRepositoryByID(ctx, repo.ID); err != nil { return fmt.Errorf("getRepositoryByID: %w", err) } @@ -337,7 +337,7 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in } repoNamesToCheck = append(repoNamesToCheck, name) - if len(repoNamesToCheck) > setting.Database.IterateBufferSize { + if len(repoNamesToCheck) >= setting.Database.IterateBufferSize { if err = checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil { return err } diff --git a/services/repository/archiver/archiver.go b/services/repository/archiver/archiver.go index 94fff6ffa26f..1da4425cfc6e 100644 --- a/services/repository/archiver/archiver.go +++ b/services/repository/archiver/archiver.go @@ -226,7 +226,7 @@ func doArchive(r *ArchiveRequest) (*repo_model.RepoArchiver, error) { rd.Close() }() done := make(chan error, 1) // Ensure that there is some capacity which will ensure that the goroutine below can always finish - repo, err := repo_model.GetRepositoryByID(archiver.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, archiver.RepoID) if err != nil { return nil, fmt.Errorf("archiver.LoadRepo failed: %w", err) } diff --git a/services/repository/check.go b/services/repository/check.go index 6e29dc93d1e2..293cb04d3882 100644 --- a/services/repository/check.go +++ b/services/repository/check.go @@ -22,8 +22,8 @@ import ( "xorm.io/builder" ) -// GitFsck calls 'git fsck' to check repository health. -func GitFsck(ctx context.Context, timeout time.Duration, args []git.CmdArg) error { +// GitFsckRepos calls 'git fsck' to check repository health. +func GitFsckRepos(ctx context.Context, timeout time.Duration, args []git.CmdArg) error { log.Trace("Doing: GitFsck") if err := db.Iterate( @@ -35,15 +35,7 @@ func GitFsck(ctx context.Context, timeout time.Duration, args []git.CmdArg) erro return db.ErrCancelledf("before fsck of %s", repo.FullName()) default: } - log.Trace("Running health check on repository %v", repo) - repoPath := repo.RepoPath() - if err := git.Fsck(ctx, repoPath, timeout, args...); err != nil { - log.Warn("Failed to health check repository (%v): %v", repo, err) - if err = system_model.CreateRepositoryNotice("Failed to health check repository (%s): %v", repo.FullName(), err); err != nil { - log.Error("CreateRepositoryNotice: %v", err) - } - } - return nil + return GitFsckRepo(ctx, repo, timeout, args) }, ); err != nil { log.Trace("Error: GitFsck: %v", err) @@ -54,6 +46,19 @@ func GitFsck(ctx context.Context, timeout time.Duration, args []git.CmdArg) erro return nil } +// GitFsckRepo calls 'git fsck' to check an individual repository's health. +func GitFsckRepo(ctx context.Context, repo *repo_model.Repository, timeout time.Duration, args []git.CmdArg) error { + log.Trace("Running health check on repository %-v", repo) + repoPath := repo.RepoPath() + if err := git.Fsck(ctx, repoPath, timeout, args...); err != nil { + log.Warn("Failed to health check repository (%-v): %v", repo, err) + if err = system_model.CreateRepositoryNotice("Failed to health check repository (%s): %v", repo.FullName(), err); err != nil { + log.Error("CreateRepositoryNotice: %v", err) + } + } + return nil +} + // GitGcRepos calls 'git gc' to remove unnecessary files and optimize the local repository func GitGcRepos(ctx context.Context, timeout time.Duration, args ...git.CmdArg) error { log.Trace("Doing: GitGcRepos") @@ -68,33 +73,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...git.CmdArg) return db.ErrCancelledf("before GC of %s", repo.FullName()) default: } - log.Trace("Running git gc on %v", repo) - command := git.NewCommand(ctx, args...). - SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName())) - var stdout string - var err error - stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()}) - - if err != nil { - log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err) - desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err) - if err = system_model.CreateRepositoryNotice(desc); err != nil { - log.Error("CreateRepositoryNotice: %v", err) - } - return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %w", repo.FullName(), err) - } - - // Now update the size of the repository - if err := repo_module.UpdateRepoSize(ctx, repo); err != nil { - log.Error("Updating size as part of garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err) - desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err) - if err = system_model.CreateRepositoryNotice(desc); err != nil { - log.Error("CreateRepositoryNotice: %v", err) - } - return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %w", repo.FullName(), err) - } - - return nil + return GitGcRepo(ctx, repo, timeout, args) }, ); err != nil { return err @@ -104,6 +83,37 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...git.CmdArg) return nil } +// GitGcRepo calls 'git gc' to remove unnecessary files and optimize the local repository +func GitGcRepo(ctx context.Context, repo *repo_model.Repository, timeout time.Duration, args []git.CmdArg) error { + log.Trace("Running git gc on %-v", repo) + command := git.NewCommand(ctx, args...). + SetDescription(fmt.Sprintf("Repository Garbage Collection: %s", repo.FullName())) + var stdout string + var err error + stdout, _, err = command.RunStdString(&git.RunOpts{Timeout: timeout, Dir: repo.RepoPath()}) + + if err != nil { + log.Error("Repository garbage collection failed for %v. Stdout: %s\nError: %v", repo, stdout, err) + desc := fmt.Sprintf("Repository garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err) + if err = system_model.CreateRepositoryNotice(desc); err != nil { + log.Error("CreateRepositoryNotice: %v", err) + } + return fmt.Errorf("Repository garbage collection failed in repo: %s: Error: %w", repo.FullName(), err) + } + + // Now update the size of the repository + if err := repo_module.UpdateRepoSize(ctx, repo); err != nil { + log.Error("Updating size as part of garbage collection failed for %-v. Stdout: %s\nError: %v", repo, stdout, err) + desc := fmt.Sprintf("Updating size as part of garbage collection failed for %s. Stdout: %s\nError: %v", repo.RepoPath(), stdout, err) + if err = system_model.CreateRepositoryNotice(desc); err != nil { + log.Error("CreateRepositoryNotice: %v", err) + } + return fmt.Errorf("Updating size as part of garbage collection failed in repo: %s: Error: %w", repo.FullName(), err) + } + + return nil +} + func gatherMissingRepoRecords(ctx context.Context) ([]*repo_model.Repository, error) { repos := make([]*repo_model.Repository, 0, 10) if err := db.Iterate( diff --git a/services/repository/files/commit.go b/services/repository/files/commit.go index c49b03d60854..74f9eb868d00 100644 --- a/services/repository/files/commit.go +++ b/services/repository/files/commit.go @@ -29,9 +29,12 @@ func CreateCommitStatus(ctx context.Context, repo *repo_model.Repository, creato } defer closer.Close() - if _, err := gitRepo.GetCommit(sha); err != nil { + if commit, err := gitRepo.GetCommit(sha); err != nil { gitRepo.Close() return fmt.Errorf("GetCommit[%s]: %w", sha, err) + } else if len(sha) != git.SHAFullLength { + // use complete commit sha + sha = commit.ID.String() } gitRepo.Close() diff --git a/services/repository/files/tree.go b/services/repository/files/tree.go index 1aa6d0df36de..f4304ea6306e 100644 --- a/services/repository/files/tree.go +++ b/services/repository/files/tree.go @@ -49,7 +49,7 @@ func GetTreeBySHA(ctx context.Context, repo *repo_model.Repository, gitRepo *git copy(treeURL[apiURLLen:], "/git/trees/") // 40 is the size of the sha1 hash in hexadecimal format. - copyPos := len(treeURL) - 40 + copyPos := len(treeURL) - git.SHAFullLength if perPage <= 0 || perPage > setting.API.DefaultGitTreesPerPage { perPage = setting.API.DefaultGitTreesPerPage diff --git a/services/repository/files/upload.go b/services/repository/files/upload.go index 0ada3885b1ea..240564d40162 100644 --- a/services/repository/files/upload.go +++ b/services/repository/files/upload.go @@ -69,7 +69,7 @@ func UploadRepoFiles(ctx context.Context, repo *repo_model.Repository, doer *use return err } if lfsLock != nil && lfsLock.OwnerID != doer.ID { - u, err := user_model.GetUserByID(lfsLock.OwnerID) + u, err := user_model.GetUserByID(ctx, lfsLock.OwnerID) if err != nil { return err } diff --git a/services/repository/fork.go b/services/repository/fork.go index cf9b3992cd0c..ad534be887f1 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -51,6 +51,13 @@ type ForkRepoOptions struct { // ForkRepository forks a repository func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts ForkRepoOptions) (*repo_model.Repository, error) { + // Fork is prohibited, if user has reached maximum limit of repositories + if !owner.CanForkRepo() { + return nil, repo_model.ErrReachLimitOfRepo{ + Limit: owner.MaxRepoCreation, + } + } + forkedRepo, err := repo_model.GetUserFork(ctx, opts.BaseRepo.ID, owner.ID) if err != nil { return nil, err @@ -184,7 +191,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork // ConvertForkToNormalRepository convert the provided repo from a forked repo to normal repo func ConvertForkToNormalRepository(repo *repo_model.Repository) error { err := db.WithTx(db.DefaultContext, func(ctx context.Context) error { - repo, err := repo_model.GetRepositoryByIDCtx(ctx, repo.ID) + repo, err := repo_model.GetRepositoryByID(ctx, repo.ID) if err != nil { return err } diff --git a/services/repository/fork_test.go b/services/repository/fork_test.go index c809ed4529ce..452798b25b49 100644 --- a/services/repository/fork_test.go +++ b/services/repository/fork_test.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/setting" "github.com/stretchr/testify/assert" ) @@ -29,4 +30,19 @@ func TestForkRepository(t *testing.T) { assert.Nil(t, fork) assert.Error(t, err) assert.True(t, IsErrForkAlreadyExist(err)) + + // user not reached maximum limit of repositories + assert.False(t, repo_model.IsErrReachLimitOfRepo(err)) + + // change AllowForkWithoutMaximumLimit to false for the test + setting.Repository.AllowForkWithoutMaximumLimit = false + // user has reached maximum limit of repositories + user.MaxRepoCreation = 0 + fork2, err := ForkRepository(git.DefaultContext, user, user, ForkRepoOptions{ + BaseRepo: repo, + Name: "test", + Description: "test", + }) + assert.Nil(t, fork2) + assert.True(t, repo_model.IsErrReachLimitOfRepo(err)) } diff --git a/services/repository/lfs.go b/services/repository/lfs.go new file mode 100644 index 000000000000..0e88d359a833 --- /dev/null +++ b/services/repository/lfs.go @@ -0,0 +1,105 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repository + +import ( + "context" + "fmt" + "time" + + "code.gitea.io/gitea/models/db" + git_model "code.gitea.io/gitea/models/git" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/lfs" + "code.gitea.io/gitea/modules/log" + + "xorm.io/builder" +) + +func GarbageCollectLFSMetaObjects(ctx context.Context, logger log.Logger, autofix bool) error { + log.Trace("Doing: GarbageCollectLFSMetaObjects") + + if err := db.Iterate( + ctx, + builder.And(builder.Gt{"id": 0}), + func(ctx context.Context, repo *repo_model.Repository) error { + return GarbageCollectLFSMetaObjectsForRepo(ctx, repo, logger, autofix) + }, + ); err != nil { + return err + } + + log.Trace("Finished: GarbageCollectLFSMetaObjects") + return nil +} + +func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.Repository, logger log.Logger, autofix bool) error { + if logger != nil { + logger.Info("Checking %-v", repo) + } + total, orphaned, collected, deleted := 0, 0, 0, 0 + if logger != nil { + defer func() { + if orphaned == 0 { + logger.Info("Found %d total LFSMetaObjects in %-v", total, repo) + } else if !autofix { + logger.Info("Found %d/%d orphaned LFSMetaObjects in %-v", orphaned, total, repo) + } else { + logger.Info("Collected %d/%d orphaned/%d total LFSMetaObjects in %-v. %d removed from storage.", collected, orphaned, total, repo, deleted) + } + }() + } + + gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + if err != nil { + log.Error("Unable to open git repository %-v: %v", repo, err) + return err + } + defer gitRepo.Close() + + store := lfs.NewContentStore() + + return git_model.IterateLFSMetaObjectsForRepo(ctx, repo.ID, func(ctx context.Context, metaObject *git_model.LFSMetaObject, count int64) error { + total++ + pointerSha := git.ComputeBlobHash([]byte(metaObject.Pointer.StringContent())) + + if gitRepo.IsObjectExist(pointerSha.String()) { + return nil + } + orphaned++ + + if !autofix { + return nil + } + // Non-existent pointer file + _, err = git_model.RemoveLFSMetaObjectByOidFn(repo.ID, metaObject.Oid, func(count int64) error { + if count > 0 { + return nil + } + + if err := store.Delete(metaObject.RelativePath()); err != nil { + log.Error("Unable to remove lfs metaobject %s from store: %v", metaObject.Oid, err) + } + deleted++ + return nil + }) + if err != nil { + return fmt.Errorf("unable to remove meta-object %s in %s: %w", metaObject.Oid, repo.FullName(), err) + } + collected++ + + return nil + }, &git_model.IterateLFSMetaObjectsForRepoOptions{ + // Only attempt to garbage collect lfs meta objects older than a week as the order of git lfs upload + // and git object upload is not necessarily guaranteed. It's possible to imagine a situation whereby + // an LFS object is uploaded but the git branch is not uploaded immediately, or there are some rapid + // changes in new branches that might lead to lfs objects becoming temporarily unassociated with git + // objects. + // + // It is likely that a week is potentially excessive but it should definitely be enough that any + // unassociated LFS object is genuinely unassociated. + OlderThan: time.Now().Add(-24 * 7 * time.Hour), + }) +} diff --git a/services/repository/push.go b/services/repository/push.go index bce01cb76a50..f1eedb8e0839 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -81,7 +81,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("PushUpdates: %s/%s", optsList[0].RepoUserName, optsList[0].RepoName)) defer finished() - repo, err := repo_model.GetRepositoryByOwnerAndName(optsList[0].RepoUserName, optsList[0].RepoName) + repo, err := repo_model.GetRepositoryByOwnerAndName(ctx, optsList[0].RepoUserName, optsList[0].RepoName) if err != nil { return fmt.Errorf("GetRepositoryByOwnerAndName failed: %w", err) } @@ -109,7 +109,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { if opts.IsTag() { // If is tag reference if pusher == nil || pusher.ID != opts.PusherID { var err error - if pusher, err = user_model.GetUserByID(opts.PusherID); err != nil { + if pusher, err = user_model.GetUserByID(ctx, opts.PusherID); err != nil { return err } } @@ -149,7 +149,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } else if opts.IsBranch() { // If is branch reference if pusher == nil || pusher.ID != opts.PusherID { var err error - if pusher, err = user_model.GetUserByID(opts.PusherID); err != nil { + if pusher, err = user_model.GetUserByID(ctx, opts.PusherID); err != nil { return err } } diff --git a/services/repository/repository.go b/services/repository/repository.go index 859c32cf8fd9..3c3e7e82c3f8 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -58,7 +58,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod func PushCreateRepo(authUser, owner *user_model.User, repoName string) (*repo_model.Repository, error) { if !authUser.IsAdmin { if owner.IsOrganization() { - if ok, err := organization.CanCreateOrgRepo(owner.ID, authUser.ID); err != nil { + if ok, err := organization.CanCreateOrgRepo(db.DefaultContext, owner.ID, authUser.ID); err != nil { return nil, err } else if !ok { return nil, fmt.Errorf("cannot push-create repository for org") @@ -103,24 +103,24 @@ func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err } // LinkedRepository returns the linked repo if any -func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { +func LinkedRepository(ctx context.Context, a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { if a.IssueID != 0 { - iss, err := issues_model.GetIssueByID(db.DefaultContext, a.IssueID) + iss, err := issues_model.GetIssueByID(ctx, a.IssueID) if err != nil { return nil, unit.TypeIssues, err } - repo, err := repo_model.GetRepositoryByID(iss.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, iss.RepoID) unitType := unit.TypeIssues if iss.IsPull { unitType = unit.TypePullRequests } return repo, unitType, err } else if a.ReleaseID != 0 { - rel, err := repo_model.GetReleaseByID(db.DefaultContext, a.ReleaseID) + rel, err := repo_model.GetReleaseByID(ctx, a.ReleaseID) if err != nil { return nil, unit.TypeReleases, err } - repo, err := repo_model.GetRepositoryByID(rel.RepoID) + repo, err := repo_model.GetRepositoryByID(ctx, rel.RepoID) return repo, unit.TypeReleases, err } return nil, -1, nil diff --git a/services/repository/repository_test.go b/services/repository/repository_test.go index 5f5283bddb65..892a11a23e9b 100644 --- a/services/repository/repository_test.go +++ b/services/repository/repository_test.go @@ -31,7 +31,7 @@ func TestLinkedRepository(t *testing.T) { t.Run(tc.name, func(t *testing.T) { attach, err := repo_model.GetAttachmentByID(db.DefaultContext, tc.attachID) assert.NoError(t, err) - repo, unitType, err := LinkedRepository(attach) + repo, unitType, err := LinkedRepository(db.DefaultContext, attach) assert.NoError(t, err) if tc.expectedRepo != nil { assert.Equal(t, tc.expectedRepo.ID, repo.ID) diff --git a/services/repository/transfer.go b/services/repository/transfer.go index af28f5a4a54e..f4afb7e2dec2 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -4,6 +4,7 @@ package repository import ( + "context" "fmt" "code.gitea.io/gitea/models" @@ -24,8 +25,8 @@ import ( var repoWorkingPool = sync.NewExclusivePool() // TransferOwnership transfers all corresponding setting from old user to new one. -func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { - if err := repo.GetOwner(db.DefaultContext); err != nil { +func TransferOwnership(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { + if err := repo.GetOwner(ctx); err != nil { return err } for _, team := range teams { @@ -43,18 +44,18 @@ func TransferOwnership(doer, newOwner *user_model.User, repo *repo_model.Reposit } repoWorkingPool.CheckOut(fmt.Sprint(repo.ID)) - newRepo, err := repo_model.GetRepositoryByID(repo.ID) + newRepo, err := repo_model.GetRepositoryByID(ctx, repo.ID) if err != nil { return err } for _, team := range teams { - if err := models.AddRepository(db.DefaultContext, team, newRepo); err != nil { + if err := models.AddRepository(ctx, team, newRepo); err != nil { return err } } - notification.NotifyTransferRepository(db.DefaultContext, doer, repo, oldOwner.Name) + notification.NotifyTransferRepository(ctx, doer, repo, oldOwner.Name) return nil } @@ -84,49 +85,49 @@ func ChangeRepositoryName(doer *user_model.User, repo *repo_model.Repository, ne // StartRepositoryTransfer transfer a repo from one owner to a new one. // it make repository into pending transfer state, if doer can not create repo for new owner. -func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { +func StartRepositoryTransfer(ctx context.Context, doer, newOwner *user_model.User, repo *repo_model.Repository, teams []*organization.Team) error { if err := models.TestRepositoryReadyForTransfer(repo.Status); err != nil { return err } // Admin is always allowed to transfer || user transfer repo back to his account if doer.IsAdmin || doer.ID == newOwner.ID { - return TransferOwnership(doer, newOwner, repo, teams) + return TransferOwnership(ctx, doer, newOwner, repo, teams) } // If new owner is an org and user can create repos he can transfer directly too if newOwner.IsOrganization() { - allowed, err := organization.CanCreateOrgRepo(newOwner.ID, doer.ID) + allowed, err := organization.CanCreateOrgRepo(ctx, newOwner.ID, doer.ID) if err != nil { return err } if allowed { - return TransferOwnership(doer, newOwner, repo, teams) + return TransferOwnership(ctx, doer, newOwner, repo, teams) } } // In case the new owner would not have sufficient access to the repo, give access rights for read - hasAccess, err := access_model.HasAccess(db.DefaultContext, newOwner.ID, repo) + hasAccess, err := access_model.HasAccess(ctx, newOwner.ID, repo) if err != nil { return err } if !hasAccess { - if err := repo_module.AddCollaborator(repo, newOwner); err != nil { + if err := repo_module.AddCollaborator(ctx, repo, newOwner); err != nil { return err } - if err := repo_model.ChangeCollaborationAccessMode(repo, newOwner.ID, perm.AccessModeRead); err != nil { + if err := repo_model.ChangeCollaborationAccessMode(ctx, repo, newOwner.ID, perm.AccessModeRead); err != nil { return err } } // Make repo as pending for transfer repo.Status = repo_model.RepositoryPendingTransfer - if err := models.CreatePendingRepositoryTransfer(doer, newOwner, repo.ID, teams); err != nil { + if err := models.CreatePendingRepositoryTransfer(ctx, doer, newOwner, repo.ID, teams); err != nil { return err } // notify users who are able to accept / reject transfer - notification.NotifyRepoPendingTransfer(db.DefaultContext, doer, newOwner, repo) + notification.NotifyRepoPendingTransfer(ctx, doer, newOwner, repo) return nil } diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go index 2bbc5abbd257..1299e66be278 100644 --- a/services/repository/transfer_test.go +++ b/services/repository/transfer_test.go @@ -37,7 +37,7 @@ func TestTransferOwnership(t *testing.T) { doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}) - assert.NoError(t, TransferOwnership(doer, doer, repo, nil)) + assert.NoError(t, TransferOwnership(db.DefaultContext, doer, doer, repo, nil)) transferredRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.EqualValues(t, 2, transferredRepo.OwnerID) @@ -70,7 +70,7 @@ func TestStartRepositoryTransferSetPermission(t *testing.T) { assert.NoError(t, err) assert.False(t, hasAccess) - assert.NoError(t, StartRepositoryTransfer(doer, recipient, repo, nil)) + assert.NoError(t, StartRepositoryTransfer(db.DefaultContext, doer, recipient, repo, nil)) hasAccess, err = access_model.HasAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 437bda87aaed..25494bde2398 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -1,5 +1,5 @@ name: gitea -summary: Gitea - A painless self-hosted Git service +summary: Gitea - A painless self-hosted Git service description: | The goal of this project is to make the easiest, fastest, and most painless way of setting up a self-hosted Git service. With Go, this can be done with @@ -39,7 +39,6 @@ apps: command: usr/bin/sqlite3 parts: - gitea: plugin: make source: . diff --git a/templates/admin/base/search.tmpl b/templates/admin/base/search.tmpl index 28bc478f6a26..ae1a4d2ac562 100644 --- a/templates/admin/base/search.tmpl +++ b/templates/admin/base/search.tmpl @@ -6,12 +6,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index adf5b9bef7b6..f5f6a86dc8ae 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -15,10 +15,10 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl index 1c8b12fc2faf..cfd32b648403 100644 --- a/templates/admin/navbar.tmpl +++ b/templates/admin/navbar.tmpl @@ -1,45 +1,45 @@ diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl index 56f6eaa3ad71..67a726eb3f6d 100644 --- a/templates/admin/user/list.tmpl +++ b/templates/admin/user/list.tmpl @@ -76,9 +76,9 @@ {{.locale.Tr "admin.users.2fa"}} {{.locale.Tr "admin.users.repos"}} {{.locale.Tr "admin.users.created"}} - + {{.locale.Tr "admin.users.last_login"}} - {{SortArrow "leastupdate" "recentupdate" $.SortType false}} + {{SortArrow "lastlogin" "reverselastlogin" $.SortType false}} {{.locale.Tr "admin.users.edit"}} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 12837ebefedf..4fc61cf36909 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -175,7 +175,7 @@ {{svg "octicon-bell"}} {{.locale.Tr "notification.subscriptions"}} - + {{svg "octicon-tools"}} {{.locale.Tr "your_settings"}} @@ -186,7 +186,7 @@ {{if .IsAdmin}}
- + {{svg "octicon-server"}} {{.locale.Tr "admin_panel"}} diff --git a/templates/base/paginate.tmpl b/templates/base/paginate.tmpl index 1ed69709832d..421e96a00a88 100644 --- a/templates/base/paginate.tmpl +++ b/templates/base/paginate.tmpl @@ -15,7 +15,7 @@ {{if eq .Num -1}} ... {{else}} - {{.Num}} + {{.Num}} {{end}} {{end}} diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl index 1c59cfd03eb6..29eaa1e8c649 100644 --- a/templates/explore/navbar.tmpl +++ b/templates/explore/navbar.tmpl @@ -1,17 +1,17 @@ diff --git a/templates/explore/search.tmpl b/templates/explore/search.tmpl index 123efa56dd8a..72dee41f0f07 100644 --- a/templates/explore/search.tmpl +++ b/templates/explore/search.tmpl @@ -6,12 +6,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/org/create.tmpl b/templates/org/create.tmpl index 999f5246a388..26c432303ce0 100644 --- a/templates/org/create.tmpl +++ b/templates/org/create.tmpl @@ -48,7 +48,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl index 7df1c85903c9..765bb6aaaef2 100644 --- a/templates/org/settings/navbar.tmpl +++ b/templates/org/settings/navbar.tmpl @@ -1,28 +1,31 @@
diff --git a/templates/org/settings/secrets.tmpl b/templates/org/settings/secrets.tmpl new file mode 100644 index 000000000000..dd2a437b7525 --- /dev/null +++ b/templates/org/settings/secrets.tmpl @@ -0,0 +1,83 @@ +{{template "base/head" .}} +
+ {{template "org/header" .}} +
+
+ {{template "org/settings/navbar" .}} +
+ {{template "base/alert" .}} +

+ {{.locale.Tr "secrets.secrets"}} +
+
{{.locale.Tr "secrets.creation"}}
+
+

+
+
+
+ {{.CsrfTokenHtml}} +
+ {{.locale.Tr "secrets.description"}} +
+
+ + +
+
+ + +
+ + +
+
+ {{if .Secrets}} +
+ {{range .Secrets}} +
+
+ +
+
+ {{svg "octicon-key" 32}} +
+
+ {{.Name}} +
******
+
+ + {{$.locale.Tr "settings.add_on"}} + {{.CreatedUnix.FormatShort}} + +
+
+
+ {{end}} +
+ {{else}} + {{.locale.Tr "secrets.none"}} + {{end}} +
+
+
+
+
+ + + +{{template "base/footer" .}} diff --git a/templates/org/team/new.tmpl b/templates/org/team/new.tmpl index e5266f13c5e7..10b5abda3145 100644 --- a/templates/org/team/new.tmpl +++ b/templates/org/team/new.tmpl @@ -99,17 +99,17 @@
- +
- +
- +
@@ -121,7 +121,7 @@ {{if lt $unit.MaxPerm 2}}
- + {{$.locale.Tr $unit.DescKey}}
@@ -134,7 +134,6 @@
{{if .PageIsOrgTeamsNew}} - {{.locale.Tr "cancel"}} {{else}} {{if not (eq .Team.LowerName "owners")}} diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 5d952b501e26..ab118a7e263f 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -61,11 +61,11 @@ {{if and (lt $unit.MaxPerm 2) (not $unit.Type.UnitGlobalDisabled)}} {{$.locale.Tr $unit.NameKey}} - {{if eq ($.Team.UnitAccessMode $unit.Type) 0 -}} + {{if eq ($.Team.UnitAccessMode $.Context $unit.Type) 0 -}} {{$.locale.Tr "org.teams.none_access"}} - {{- else if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $unit.Type) 1) -}} + {{- else if or (eq $.Team.ID 0) (eq ($.Team.UnitAccessMode $.Context $unit.Type) 1) -}} {{$.locale.Tr "org.teams.read_access"}} - {{- else if eq ($.Team.UnitAccessMode $unit.Type) 2 -}} + {{- else if eq ($.Team.UnitAccessMode $.Context $unit.Type) 2 -}} {{$.locale.Tr "org.teams.write_access"}} {{- end}} diff --git a/templates/package/content/container.tmpl b/templates/package/content/container.tmpl index a79963e732ba..34d495f356d2 100644 --- a/templates/package/content/container.tmpl +++ b/templates/package/content/container.tmpl @@ -46,7 +46,7 @@ {{end}} {{if .PackageDescriptor.Metadata.ImageLayers}}

{{.locale.Tr "packages.container.layers"}}

-
+
{{range .PackageDescriptor.Metadata.ImageLayers}} diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 37c47cef335d..ec2e88c8541d 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -6,18 +6,9 @@ diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index 2dcd02ad98df..6a40d5fbee56 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -26,10 +26,10 @@ {{.locale.Tr "repo.diff.browse_source"}} {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} -
- {{$pullRequestEnabled := .Repository.UnitEnabled $.UnitTypePullRequests}} - {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} + {{$pullRequestEnabled := .Repository.UnitEnabled $.Context $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}}
{{if $pullRequestEnabled}} diff --git a/templates/repo/graph/commits.tmpl b/templates/repo/graph/commits.tmpl index 357c99b2b85f..fc4b1a1ea36a 100644 --- a/templates/repo/graph/commits.tmpl +++ b/templates/repo/graph/commits.tmpl @@ -37,7 +37,7 @@ {{if eq $refGroup "pull"}} {{if or (not $.HidePRRefs) (containGeneric $.SelectedBranches .Name)}} - + {{svg "octicon-git-pull-request" 16 "mr-2"}}#{{.ShortName}} {{end}} diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index e6bd839f5704..4da91e424df9 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -154,13 +154,13 @@ {{if not (or .Repository.IsBeingCreated .Repository.IsBroken)}}
diff --git a/templates/repo/issue/milestone_issues.tmpl b/templates/repo/issue/milestone_issues.tmpl index ba229cb5e897..f3e28208adb9 100644 --- a/templates/repo/issue/milestone_issues.tmpl +++ b/templates/repo/issue/milestone_issues.tmpl @@ -108,11 +108,11 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}}
{{end}} @@ -124,12 +124,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/milestones.tmpl b/templates/repo/issue/milestones.tmpl index 641dc6c9187e..3282e895ebc4 100644 --- a/templates/repo/issue/milestones.tmpl +++ b/templates/repo/issue/milestones.tmpl @@ -46,12 +46,12 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/issue/navbar.tmpl b/templates/repo/issue/navbar.tmpl index 9a963cd8228e..1e576796579e 100644 --- a/templates/repo/issue/navbar.tmpl +++ b/templates/repo/issue/navbar.tmpl @@ -1,4 +1,4 @@ diff --git a/templates/repo/issue/openclose.tmpl b/templates/repo/issue/openclose.tmpl index ccfb40684c3f..758fc447ce60 100644 --- a/templates/repo/issue/openclose.tmpl +++ b/templates/repo/issue/openclose.tmpl @@ -1,5 +1,5 @@ -
{{.Issue.Content}}
+
{{.Issue.Content}}
{{if .Issue.Attachments}} {{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Issue.Attachments "Content" .Issue.RenderedContent}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index e9b7172d1b32..d013c7b761ba 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -77,7 +77,7 @@ {{$.locale.Tr "repo.issues.no_content"}} {{end}} -
{{.Content}}
+
{{.Content}}
{{if .Attachments}} {{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Attachments "Content" .RenderedContent}} @@ -449,7 +449,7 @@ {{$.locale.Tr "repo.issues.no_content"}} {{end}} -
{{.Content}}
+
{{.Content}}
{{if .Attachments}} {{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Attachments "Content" .RenderedContent}} @@ -576,7 +576,7 @@ {{$.locale.Tr "repo.issues.no_content"}} {{end}} -
{{.Content}}
+
{{.Content}}
{{$reactions := .Reactions.GroupByType}} diff --git a/templates/repo/issue/view_content/context_menu.tmpl b/templates/repo/issue/view_content/context_menu.tmpl index 45dd08bf6103..7459623a54d9 100644 --- a/templates/repo/issue/view_content/context_menu.tmpl +++ b/templates/repo/issue/view_content/context_menu.tmpl @@ -11,9 +11,9 @@ {{$referenceUrl = Printf "%s/files#%s" .ctx.Issue.HTMLURL .item.HashTag}} {{end}}
{{.ctx.locale.Tr "repo.issues.context.copy_link"}}
-
{{.ctx.locale.Tr "repo.issues.context.quote_reply"}}
+
{{.ctx.locale.Tr "repo.issues.context.quote_reply"}}
{{if not .ctx.UnitIssuesGlobalDisabled}} -
{{.ctx.locale.Tr "repo.issues.context.reference_issue"}}
+
{{.ctx.locale.Tr "repo.issues.context.reference_issue"}}
{{end}} {{if or .ctx.Permission.IsAdmin .IsCommentPoster .ctx.HasIssuesOrPullsWritePermission}}
diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 9e0909064de1..665f78205386 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -330,7 +330,7 @@ {{end}} {{if .AllowMerge}} {{/* user is allowed to merge */}} - {{$prUnit := .Repository.MustGetUnit $.UnitTypePullRequests}} + {{$prUnit := .Repository.MustGetUnit $.Context $.UnitTypePullRequests}} {{$approvers := .Issue.PullRequest.GetApprovers}} {{if or $prUnit.PullRequestsConfig.AllowMerge $prUnit.PullRequestsConfig.AllowRebase $prUnit.PullRequestsConfig.AllowRebaseMerge $prUnit.PullRequestsConfig.AllowSquash}} {{$hasPendingPullRequestMergeTip := ""}} @@ -343,7 +343,8 @@ (() => { const defaultMergeTitle = {{.DefaultMergeMessage}}; const defaultSquashMergeTitle = {{.DefaultSquashMergeMessage}}; - const defaultMergeMessage = 'Reviewed-on: ' + {{$.Issue.HTMLURL}} + '\n' + {{$approvers}}; + const defaultMergeMessage = {{if .DefaultMergeBody}}{{.DefaultMergeBody}}{{else}}'Reviewed-on: ' + {{$.Issue.HTMLURL}} + '\n' + {{$approvers}}{{end}}; + const defaultSquashMergeMessage = {{if .DefaultSquashMergeBody}}{{.DefaultSquashMergeBody}}{{else}}'Reviewed-on: ' + {{$.Issue.HTMLURL}} + '\n' + {{$approvers}}{{end}}; const mergeForm = { 'baseLink': {{.Link}}, 'textCancel': {{$.locale.Tr "cancel"}}, @@ -398,7 +399,7 @@ 'allowed': {{$prUnit.PullRequestsConfig.AllowSquash}}, 'textDoMerge': {{$.locale.Tr "repo.pulls.squash_merge_pull_request"}}, 'mergeTitleFieldText': defaultSquashMergeTitle, - 'mergeMessageFieldText': {{.GetCommitMessages}} + defaultMergeMessage, + 'mergeMessageFieldText': {{.GetCommitMessages}} + defaultSquashMergeMessage, 'hideAutoMerge': generalHideAutoMerge, }, { diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index af648387db58..63b99136a8ed 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -337,7 +337,7 @@ {{end}} - {{if .Repository.IsTimetrackerEnabled}} + {{if .Repository.IsTimetrackerEnabled $.Context}} {{if and .CanUseTimetracker (not .Repository.IsArchived)}}
@@ -444,7 +444,7 @@ {{end}}
- {{if .Repository.IsDependenciesEnabled}} + {{if .Repository.IsDependenciesEnabled $.Context}}
diff --git a/templates/repo/migrate/codebase.tmpl b/templates/repo/migrate/codebase.tmpl index 20341e5768de..0f9b377f212e 100644 --- a/templates/repo/migrate/codebase.tmpl +++ b/templates/repo/migrate/codebase.tmpl @@ -107,7 +107,6 @@ - {{.locale.Tr "cancel"}}
diff --git a/templates/repo/migrate/git.tmpl b/templates/repo/migrate/git.tmpl index 612116f40257..1ef031ee1f81 100644 --- a/templates/repo/migrate/git.tmpl +++ b/templates/repo/migrate/git.tmpl @@ -81,7 +81,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gitbucket.tmpl b/templates/repo/migrate/gitbucket.tmpl index 06912b27f52e..5e6b3b452839 100644 --- a/templates/repo/migrate/gitbucket.tmpl +++ b/templates/repo/migrate/gitbucket.tmpl @@ -123,7 +123,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gitea.tmpl b/templates/repo/migrate/gitea.tmpl index 3bc615631684..f56f9df5ec7a 100644 --- a/templates/repo/migrate/gitea.tmpl +++ b/templates/repo/migrate/gitea.tmpl @@ -119,7 +119,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/github.tmpl b/templates/repo/migrate/github.tmpl index a5b1f195061f..c4249f8904b8 100644 --- a/templates/repo/migrate/github.tmpl +++ b/templates/repo/migrate/github.tmpl @@ -121,7 +121,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gitlab.tmpl b/templates/repo/migrate/gitlab.tmpl index fa68cee8914d..a959833e9668 100644 --- a/templates/repo/migrate/gitlab.tmpl +++ b/templates/repo/migrate/gitlab.tmpl @@ -118,7 +118,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/gogs.tmpl b/templates/repo/migrate/gogs.tmpl index 01936e028bbf..6d331b9e8fe6 100644 --- a/templates/repo/migrate/gogs.tmpl +++ b/templates/repo/migrate/gogs.tmpl @@ -121,7 +121,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/migrate/onedev.tmpl b/templates/repo/migrate/onedev.tmpl index e411d4776018..18256aca5dc1 100644 --- a/templates/repo/migrate/onedev.tmpl +++ b/templates/repo/migrate/onedev.tmpl @@ -107,7 +107,6 @@ - {{.locale.Tr "cancel"}} diff --git a/templates/repo/projects/list.tmpl b/templates/repo/projects/list.tmpl index 9e265f9a914e..274734f515a0 100644 --- a/templates/repo/projects/list.tmpl +++ b/templates/repo/projects/list.tmpl @@ -31,9 +31,9 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} diff --git a/templates/repo/pulls/fork.tmpl b/templates/repo/pulls/fork.tmpl index 0172e1b70829..4e20642cf612 100644 --- a/templates/repo/pulls/fork.tmpl +++ b/templates/repo/pulls/fork.tmpl @@ -58,10 +58,9 @@
- - {{.locale.Tr "cancel"}}
diff --git a/templates/repo/release/list.tmpl b/templates/repo/release/list.tmpl index 6abb240cc34b..9f4104bec5c1 100644 --- a/templates/repo/release/list.tmpl +++ b/templates/repo/release/list.tmpl @@ -5,12 +5,15 @@ {{template "base/alert" .}} + {{if .EnableFeed}} + {{svg "octicon-rss" 18}} + {{end}} {{if (and .CanCreateRelease (not .PageIsTagList))}} {{.locale.Tr "repo.release.new_release"}} @@ -36,21 +39,21 @@ @@ -69,19 +72,10 @@ {{if .IsTag}} {{if .CreatedUnix}}{{TimeSinceUnix .CreatedUnix $.locale}}{{end}} {{else}} - {{if .IsDraft}} - {{$.locale.Tr "repo.release.draft"}} - {{else if .IsPrerelease}} - {{$.locale.Tr "repo.release.prerelease"}} - {{else}} - {{$.locale.Tr "repo.release.stable"}} - {{end}} - - {{svg "octicon-tag" 16 "mr-2"}}{{.TagName}} - + {{svg "octicon-tag" 16 "mr-2"}}{{.TagName}} {{if .Sha1}} - {{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}} + {{svg "octicon-git-commit" 16 "mr-2"}}{{ShortSha .Sha1}} {{template "repo/branch_dropdown" dict "root" $ "release" .}} {{end}} @@ -89,36 +83,56 @@
{{if .IsTag}} -

- {{svg "octicon-tag" 16 "mr-2"}}{{.TagName}} -

+

{{if gt .Publisher.ID 0}} {{avatar .Publisher 20}} {{.Publisher.Name}} + + {{$.locale.Tr "repo.released_this"}} + + {{if .CreatedUnix}} + {{TimeSinceUnix .CreatedUnix $.locale}} + {{end}} + | {{end}} {{$.locale.Tr "repo.release.ahead.commits" .NumCommitsBehind | Str2html}} {{$.locale.Tr "repo.release.ahead.target" $.DefaultBranch}}

{{else}} -

- {{.Title}} - {{if $.CanCreateRelease}} - - ({{$.locale.Tr "repo.release.edit"}}) - - {{end}} -

+
+

+ {{.Title}} + {{if .IsDraft}} + {{$.locale.Tr "repo.release.draft"}} + {{else if .IsPrerelease}} + {{$.locale.Tr "repo.release.prerelease"}} + {{else if not .IsTag}} + {{$.locale.Tr "repo.release.stable"}} + {{end}} +

+
+ {{if $.CanCreateRelease}} + + {{svg "octicon-pencil"}} + + {{end}} +
+

{{if .OriginalAuthor}} diff --git a/templates/repo/settings/collaboration.tmpl b/templates/repo/settings/collaboration.tmpl index 342b260db6c0..2f932b4c3958 100644 --- a/templates/repo/settings/collaboration.tmpl +++ b/templates/repo/settings/collaboration.tmpl @@ -74,7 +74,7 @@ {{if or (eq .AccessMode 1) (eq .AccessMode 2)}} {{$first := true}}

- Sections: {{range $u, $unit := $.Units}}{{if and ($.Repo.UnitEnabled $unit.Type) ($team.UnitEnabled $unit.Type)}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{$.locale.Tr $unit.NameKey}}{{end}}{{end}} {{if $first}}None{{end}} + Sections: {{range $u, $unit := $.Units}}{{if and ($.Repo.UnitEnabled $.Context $unit.Type) ($team.UnitEnabled $.Context $unit.Type)}}{{if $first}}{{$first = false}}{{else}}, {{end}}{{$.locale.Tr $unit.NameKey}}{{end}}{{end}} {{if $first}}None{{end}}
{{end}}
diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index 44c916eefbdb..32a1258b3a9a 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -51,7 +51,7 @@ {{range .Deploykeys}}
-
@@ -75,9 +75,11 @@ {{end}}
+
+ {{template "repo/settings/secrets" .}} -