diff --git a/.drone.yml b/.drone.yml index ce922f8c60..1aac10a828 100644 --- a/.drone.yml +++ b/.drone.yml @@ -331,7 +331,7 @@ steps: image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env user: gitea commands: - - timeout -s ABRT 40m make test-mysql8-migration test-mysql8 + - timeout -s ABRT 50m make test-mysql8-migration test-mysql8 environment: GOPROXY: https://goproxy.io TAGS: bindata @@ -469,7 +469,7 @@ steps: image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env user: gitea commands: - - timeout -s ABRT 40m make test-sqlite-migration test-sqlite + - timeout -s ABRT 50m make test-sqlite-migration test-sqlite environment: GOPROXY: https://goproxy.io TAGS: bindata gogit sqlite sqlite_unlock_notify @@ -485,7 +485,7 @@ steps: image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env user: gitea commands: - - timeout -s ABRT 40m make test-pgsql-migration test-pgsql + - timeout -s ABRT 50m make test-pgsql-migration test-pgsql environment: GOPROXY: https://goproxy.io TAGS: bindata gogit diff --git a/.eslintrc b/.eslintrc index 77d9dc1228..ff62d9cc93 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,12 +13,13 @@ plugins: - eslint-plugin-import - eslint-plugin-vue - eslint-plugin-html + - eslint-plugin-jquery extends: - plugin:vue/recommended env: - es2021: true + es2022: true node: true globals: @@ -140,6 +141,55 @@ rules: import/unambiguous: [0] indent: [2, 2, {SwitchCase: 1}] init-declarations: [0] + jquery/no-ajax-events: [2] + jquery/no-ajax: [0] + jquery/no-animate: [2] + jquery/no-attr: [0] + jquery/no-bind: [2] + jquery/no-class: [0] + jquery/no-clone: [2] + jquery/no-closest: [0] + jquery/no-css: [0] + jquery/no-data: [0] + jquery/no-deferred: [2] + jquery/no-delegate: [2] + jquery/no-each: [0] + jquery/no-extend: [2] + jquery/no-fade: [0] + jquery/no-filter: [0] + jquery/no-find: [0] + jquery/no-global-eval: [2] + jquery/no-grep: [2] + jquery/no-has: [2] + jquery/no-hide: [0] + jquery/no-html: [0] + jquery/no-in-array: [2] + jquery/no-is-array: [2] + jquery/no-is-function: [2] + jquery/no-is: [0] + jquery/no-load: [2] + jquery/no-map: [0] + jquery/no-merge: [2] + jquery/no-param: [2] + jquery/no-parent: [0] + jquery/no-parents: [0] + jquery/no-parse-html: [2] + jquery/no-prop: [0] + jquery/no-proxy: [2] + jquery/no-ready: [0] + jquery/no-serialize: [2] + jquery/no-show: [0] + jquery/no-size: [2] + jquery/no-sizzle: [0] + jquery/no-slide: [0] + jquery/no-submit: [0] + jquery/no-text: [0] + jquery/no-toggle: [0] + jquery/no-trigger: [0] + jquery/no-trim: [2] + jquery/no-val: [0] + jquery/no-when: [2] + jquery/no-wrap: [2] key-spacing: [2] keyword-spacing: [2] line-comment-position: [0] @@ -174,6 +224,7 @@ rules: no-confusing-arrow: [0] no-console: [1, {allow: [info, warn, error]}] no-const-assign: [2] + no-constant-binary-expression: [2] no-constant-condition: [0] no-constructor-return: [2] no-continue: [0] @@ -384,12 +435,14 @@ rules: unicorn/no-thenable: [2] unicorn/no-this-assignment: [2] unicorn/no-unreadable-array-destructuring: [0] + unicorn/no-unreadable-iife: [2] unicorn/no-unsafe-regex: [0] unicorn/no-unused-properties: [2] unicorn/no-useless-fallback-in-spread: [2] unicorn/no-useless-length-check: [2] unicorn/no-useless-promise-resolve-reject: [2] unicorn/no-useless-spread: [2] + unicorn/no-useless-switch-case: [2] unicorn/no-useless-undefined: [0] unicorn/no-zero-fractions: [2] unicorn/number-literal-case: [0] @@ -411,7 +464,9 @@ rules: unicorn/prefer-json-parse-buffer: [0] unicorn/prefer-math-trunc: [2] unicorn/prefer-modern-dom-apis: [0] + unicorn/prefer-modern-math-apis: [2] unicorn/prefer-module: [2] + unicorn/prefer-native-coercion-functions: [2] unicorn/prefer-negative-index: [2] unicorn/prefer-node-append: [0] unicorn/prefer-node-protocol: [0] diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e79cc9d432..9bb5bb8e88 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,10 +1,10 @@ -blank_issues_enabled: true +blank_issues_enabled: false contact_links: - name: Security Concern url: https://tinyurl.com/security-gitea about: For security concerns, please send a mail to security@gitea.io instead of opening a public issue. - name: Discord Server - url: https://discord.gg/gitea + url: https://discord.gg/Gitea about: Please ask questions and discuss configuration or deployment problems here. - name: Discourse Forum url: https://discourse.gitea.io diff --git a/.golangci.yml b/.golangci.yml index 8e31d0cbc4..4ad9c9d4cb 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -162,6 +162,3 @@ issues: - path: models/user/openid.go linters: - golint - - linters: - - staticcheck - text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead." diff --git a/CHANGELOG.md b/CHANGELOG.md index 16499cb916..0ca8bef008 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,23 @@ 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.16.8](https://github.com/go-gitea/gitea/releases/tag/v1.16.8) - 2022-05-16 + +* ENHANCEMENTS + * Add doctor check/fix for bogus action rows (#19656) (#19669) + * Make .cs highlighting legible on dark themes. (#19604) (#19605) +* BUGFIXES + * Fix oauth setting list bug (#19681) + * Delete user related oauth stuff on user deletion too (#19677) (#19680) + * Fix new release from tags list UI (#19670) (#19673) + * Prevent NPE when checking repo units if the user is nil (#19625) (#19630) + * GetFeeds must always discard actions with dangling repo_id (#19598) (#19629) + * Call MultipartForm.RemoveAll when request finishes (#19606) (#19607) + * Avoid MoreThanOne error when creating a branch whose name conflicts with other ref names (#19557) (#19591) + * Fix sending empty notifications (#19589) (#19590) + * Ignore DNS error when doing migration allow/block check (#19566) (#19567) + * Fix issue overview for teams (#19652) (#19653) + ## [1.16.7](https://github.com/go-gitea/gitea/releases/tag/v1.16.7) - 2022-05-02 * SECURITY diff --git a/Dockerfile b/Dockerfile index 973d93b784..e092b5813b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ #Build stage -FROM golang:1.18-alpine3.15 AS build-env +FROM golang:1.18-alpine3.16 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.15 +FROM alpine:3.16 LABEL maintainer="maintainers@gitea.io" EXPOSE 22 3000 diff --git a/Dockerfile.rootless b/Dockerfile.rootless index 27e898c58e..e576570e5e 100644 --- a/Dockerfile.rootless +++ b/Dockerfile.rootless @@ -1,5 +1,5 @@ #Build stage -FROM golang:1.18-alpine3.15 AS build-env +FROM golang:1.18-alpine3.16 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.15 +FROM alpine:3.16 LABEL maintainer="maintainers@gitea.io" EXPOSE 2222 3000 diff --git a/MAINTAINERS b/MAINTAINERS index bbcdde333a..907cbb5c41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -46,3 +46,5 @@ Jimmy Praet (@jpraet) Leon Hofmeister (@delvh) Gusted (@singuliere) +silentcode (@silentcodeg) +Wim (@42wim) diff --git a/Makefile b/Makefile index ab112584c6..ce4dec21a2 100644 --- a/Makefile +++ b/Makefile @@ -29,8 +29,8 @@ XGO_VERSION := go-1.18.x AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0 EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0 ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0 -GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0 -GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2 +GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.1 +GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.46.0 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.29.0 @@ -195,6 +195,7 @@ help: @echo " - swagger-validate check if the swagger spec is valid" @echo " - golangci-lint run golangci-lint linter" @echo " - vet examines Go source code and reports suspicious constructs" + @echo " - tidy run go mod tidy" @echo " - test[\#TestSpecificName] run unit test" @echo " - test-sqlite[\#TestSpecificName] run integration test for sqlite" @echo " - pr# build and start gitea from a PR with integration test data loaded" @@ -369,16 +370,20 @@ unit-test-coverage: @echo "Running unit-test-coverage $(GOTESTFLAGS) -tags '$(TEST_TAGS)'..." @$(GO) test $(GOTESTFLAGS) -timeout=20m -tags='$(TEST_TAGS)' -cover -coverprofile coverage.out $(GO_PACKAGES) && echo "\n==>\033[32m Ok\033[m\n" || exit 1 +.PHONY: tidy +tidy: + $(eval MIN_GO_VERSION := $(shell grep -Eo '^go\s+[0-9]+\.[0-9.]+' go.mod | cut -d' ' -f2)) + $(GO) mod tidy -compat=$(MIN_GO_VERSION) + .PHONY: vendor -vendor: - $(GO) mod tidy && $(GO) mod vendor +vendor: tidy + $(GO) mod vendor .PHONY: gomod-check -gomod-check: - @$(GO) mod tidy +gomod-check: tidy @diff=$$(git diff go.sum); \ if [ -n "$$diff" ]; then \ - echo "Please run '$(GO) mod tidy' and commit the result:"; \ + echo "Please run 'make tidy' and commit the result:"; \ echo "$${diff}"; \ exit 1; \ fi @@ -611,27 +616,27 @@ release-windows: | $(DIST_DIRS) ifeq (,$(findstring gogit,$(TAGS))) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit . endif -ifeq ($(CI),drone) +ifeq ($(CI),true) cp /build/* $(DIST)/binaries endif .PHONY: release-linux release-linux: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) . -ifeq ($(CI),drone) +ifeq ($(CI),true) cp /build/* $(DIST)/binaries endif .PHONY: release-darwin release-darwin: | $(DIST_DIRS) CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) . -ifeq ($(CI),drone) +ifeq ($(CI),true) cp /build/* $(DIST)/binaries endif .PHONY: release-copy release-copy: | $(DIST_DIRS) - cd $(DIST); for file in `find /build -type f -name "*"`; do cp $${file} ./release/; done; + cd $(DIST); for file in `find . -type f -name "*"`; do cp $${file} ./release/; done; .PHONY: release-check release-check: | $(DIST_DIRS) @@ -698,7 +703,6 @@ fomantic: cd $(FOMANTIC_WORK_DIR) && npm install --no-save cp -f $(FOMANTIC_WORK_DIR)/theme.config.less $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/theme.config cp -rf $(FOMANTIC_WORK_DIR)/_site $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/ - cp -f web_src/js/vendor/dropdown.js $(FOMANTIC_WORK_DIR)/node_modules/fomantic-ui/src/definitions/modules cd $(FOMANTIC_WORK_DIR) && npx gulp -f node_modules/fomantic-ui/gulpfile.js build rm -f $(FOMANTIC_WORK_DIR)/build/*.min.* @@ -757,7 +761,7 @@ generate-gitignore: .PHONY: generate-images generate-images: | node_modules - npm install --no-save --no-package-lock fabric@4 imagemin-zopfli@7 + npm install --no-save --no-package-lock fabric@5 imagemin-zopfli@7 node build/generate-images.js $(TAGS) .PHONY: generate-manpage diff --git a/assets/favicon.svg b/assets/favicon.svg new file mode 100644 index 0000000000..9df6b83b56 --- /dev/null +++ b/assets/favicon.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + diff --git a/build/generate-images.js b/build/generate-images.js index b8284b1be2..62ce5244f0 100755 --- a/build/generate-images.js +++ b/build/generate-images.js @@ -1,13 +1,8 @@ +#!/usr/bin/env node import imageminZopfli from 'imagemin-zopfli'; import {optimize} from 'svgo'; import {fabric} from 'fabric'; -import fs from 'fs'; -import {resolve, dirname} from 'path'; -import {fileURLToPath} from 'url'; - -const {readFile, writeFile} = fs.promises; -const __dirname = dirname(fileURLToPath(import.meta.url)); -const logoFile = resolve(__dirname, '../assets/logo.svg'); +import {readFile, writeFile} from 'fs/promises'; function exit(err) { if (err) console.error(err); @@ -22,8 +17,10 @@ function loadSvg(svg) { }); } -async function generate(svg, outputFile, {size, bg}) { - if (outputFile.endsWith('.svg')) { +async function generate(svg, path, {size, bg}) { + const outputFile = new URL(path, import.meta.url); + + if (String(outputFile).endsWith('.svg')) { const {data} = optimize(svg, { plugins: [ 'preset-default', @@ -68,17 +65,18 @@ async function generate(svg, outputFile, {size, bg}) { async function main() { const gitea = process.argv.slice(2).includes('gitea'); - const svg = await readFile(logoFile, 'utf8'); + const logoSvg = await readFile(new URL('../assets/logo.svg', import.meta.url), 'utf8'); + const faviconSvg = await readFile(new URL('../assets/favicon.svg', import.meta.url), 'utf8'); await Promise.all([ - generate(svg, resolve(__dirname, '../public/img/logo.svg'), {size: 32}), - generate(svg, resolve(__dirname, '../public/img/logo.png'), {size: 512}), - generate(svg, resolve(__dirname, '../public/img/favicon.png'), {size: 180}), - generate(svg, resolve(__dirname, '../public/img/avatar_default.png'), {size: 200}), - generate(svg, resolve(__dirname, '../public/img/apple-touch-icon.png'), {size: 180, bg: true}), - gitea && generate(svg, resolve(__dirname, '../public/img/gitea.svg'), {size: 32}), + generate(logoSvg, '../public/img/logo.svg', {size: 32}), + generate(logoSvg, '../public/img/logo.png', {size: 512}), + generate(faviconSvg, '../public/img/favicon.svg', {size: 32}), + generate(faviconSvg, '../public/img/favicon.png', {size: 180}), + generate(logoSvg, '../public/img/avatar_default.png', {size: 200}), + generate(logoSvg, '../public/img/apple-touch-icon.png', {size: 180, bg: true}), + gitea && generate(logoSvg, '../public/img/gitea.svg', {size: 32}), ]); } main().then(exit).catch(exit); - diff --git a/build/generate-svg.js b/build/generate-svg.js index 29b7d47693..c4f3d5a7f9 100755 --- a/build/generate-svg.js +++ b/build/generate-svg.js @@ -1,13 +1,14 @@ +#!/usr/bin/env node import fastGlob from 'fast-glob'; import {optimize} from 'svgo'; -import {resolve, parse, dirname} from 'path'; -import fs from 'fs'; +import {parse} from 'path'; +import {readFile, writeFile, mkdir} from 'fs/promises'; import {fileURLToPath} from 'url'; -const {readFile, writeFile, mkdir} = fs.promises; -const __dirname = dirname(fileURLToPath(import.meta.url)); -const glob = (pattern) => fastGlob.sync(pattern, {cwd: resolve(__dirname), absolute: true}); -const outputDir = resolve(__dirname, '../public/img/svg'); +const glob = (pattern) => fastGlob.sync(pattern, { + cwd: fileURLToPath(new URL('..', import.meta.url)), + absolute: true, +}); function exit(err) { if (err) console.error(err); @@ -16,7 +17,6 @@ function exit(err) { async function processFile(file, {prefix, fullName} = {}) { let name; - if (fullName) { name = fullName; } else { @@ -35,7 +35,8 @@ async function processFile(file, {prefix, fullName} = {}) { {name: 'addAttributesToSVGElement', params: {attributes: [{'width': '16'}, {'height': '16'}, {'aria-hidden': 'true'}]}}, ], }); - await writeFile(resolve(outputDir, `${name}.svg`), data); + + await writeFile(fileURLToPath(new URL(`../public/img/svg/${name}.svg`, import.meta.url)), data); } function processFiles(pattern, opts) { @@ -44,15 +45,14 @@ function processFiles(pattern, opts) { async function main() { try { - await mkdir(outputDir); + await mkdir(fileURLToPath(new URL('../public/img/svg', import.meta.url)), {recursive: true}); } catch {} await Promise.all([ - ...processFiles('../node_modules/@primer/octicons/build/svg/*-16.svg', {prefix: 'octicon'}), - ...processFiles('../web_src/svg/*.svg'), - ...processFiles('../public/img/gitea.svg', {fullName: 'gitea-gitea'}), + ...processFiles('node_modules/@primer/octicons/build/svg/*-16.svg', {prefix: 'octicon'}), + ...processFiles('web_src/svg/*.svg'), + ...processFiles('public/img/gitea.svg', {fullName: 'gitea-gitea'}), ]); } main().then(exit).catch(exit); - diff --git a/cmd/admin.go b/cmd/admin.go index fcf331751c..32f9a95a66 100644 --- a/cmd/admin.go +++ b/cmd/admin.go @@ -17,6 +17,7 @@ import ( asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" + 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/graceful" @@ -490,7 +491,7 @@ func runChangePassword(c *cli.Context) error { return errors.New("The password you chose is on a list of stolen passwords previously exposed in public data breaches. Please try again with a different password.\nFor more details, see https://haveibeenpwned.com/Passwords") } uname := c.String("username") - user, err := user_model.GetUserByName(uname) + user, err := user_model.GetUserByName(ctx, uname) if err != nil { return err } @@ -659,7 +660,7 @@ func runDeleteUser(c *cli.Context) error { if c.IsSet("email") { user, err = user_model.GetUserByEmail(c.String("email")) } else if c.IsSet("username") { - user, err = user_model.GetUserByName(c.String("username")) + user, err = user_model.GetUserByName(ctx, c.String("username")) } else { user, err = user_model.GetUserByID(c.Int64("id")) } @@ -689,7 +690,7 @@ func runGenerateAccessToken(c *cli.Context) error { return err } - user, err := user_model.GetUserByName(c.String("username")) + user, err := user_model.GetUserByName(ctx, c.String("username")) if err != nil { return err } @@ -722,9 +723,9 @@ func runRepoSyncReleases(_ *cli.Context) error { log.Trace("Synchronizing repository releases (this may take a while)") for page := 1; ; page++ { - repos, count, err := models.SearchRepositoryByName(&models.SearchRepoOptions{ + repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ - PageSize: models.RepositoryListDefaultPageSize, + PageSize: repo_model.RepositoryListDefaultPageSize, Page: page, }, Private: true, diff --git a/cmd/doctor.go b/cmd/doctor.go index 10f62f32c1..73dfeb1dbe 100644 --- a/cmd/doctor.go +++ b/cmd/doctor.go @@ -24,8 +24,8 @@ import ( // CmdDoctor represents the available doctor sub-command. var CmdDoctor = cli.Command{ Name: "doctor", - Usage: "Diagnose problems", - Description: "A command to diagnose problems with the current Gitea instance according to the given configuration.", + Usage: "Diagnose and optionally fix problems", + Description: "A command to diagnose problems with the current Gitea instance according to the given configuration. Some problems can optionally be fixed by modifying the database or data storage.", Action: runDoctor, Flags: []cli.Flag{ cli.BoolFlag{ diff --git a/cmd/serv.go b/cmd/serv.go index 340f591dce..6ba3e9de01 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -24,6 +24,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/pprof" "code.gitea.io/gitea/modules/private" + "code.gitea.io/gitea/modules/process" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/lfs" @@ -302,10 +303,11 @@ func runServ(c *cli.Context) error { if _, err := os.Stat(setting.RepoRootPath); err != nil { if os.IsNotExist(err) { return fail("Incorrect configuration.", - "Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.") + "Directory `[repository]` `ROOT` %s was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.", setting.RepoRootPath) } } + process.SetSysProcAttribute(gitcmd) gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin diff --git a/cmd/web_acme.go b/cmd/web_acme.go index 7dbeb14a0e..57b400dae6 100644 --- a/cmd/web_acme.go +++ b/cmd/web_acme.go @@ -66,7 +66,7 @@ func runACME(listenAddr string, m http.Handler) error { log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err) } } - myACME := certmagic.NewACMEManager(magic, certmagic.ACMEManager{ + myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{ CA: setting.AcmeURL, TrustedRoots: certPool, Email: setting.AcmeEmail, diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index c53175b2e0..5814c0d69d 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -813,7 +813,8 @@ PATH = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;[repository] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Root path for storing all repository data. It must be an absolute path. By default, it is stored in a sub-directory of `APP_DATA_PATH`. +;; Root path for storing all repository data. By default, it is set to %(APP_DATA_PATH)/gitea-repositories. +;; A relative path is interpreted as %(GITEA_WORK_DIR)/%(ROOT) ;ROOT = ;; ;; The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. @@ -938,7 +939,7 @@ PATH = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; List of prefixes used in Pull Request title to mark them as Work In Progress +;; List of prefixes used in Pull Request title to mark them as Work In Progress (matched in a case-insensitive manner) ;WORK_IN_PROGRESS_PREFIXES = WIP:,[WIP] ;; ;; List of keywords used in Pull Request comments to automatically close a related issue @@ -947,6 +948,9 @@ PATH = ;; List of keywords used in Pull Request comments to automatically reopen a related issue ;REOPEN_KEYWORDS = reopen,reopens,reopened ;; +;; Set default merge style for repository creating, valid options: merge, rebase, rebase-merge, squash +;DEFAULT_MERGE_STYLE = merge +;; ;; In the default merge message for squash commits include at most this many commits ;DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT = 50 ;; @@ -1608,7 +1612,8 @@ PATH = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; -;; Either "memory", "file", or "redis", default is "memory" +;; Either "memory", "file", "redis", "db", "mysql", "couchbase", "memcache" or "postgres" +;; Default is "memory". "db" will reuse the configuration in [database] ;PROVIDER = memory ;; ;; Provider config options @@ -2086,7 +2091,7 @@ PATH = ;[mirror] ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Enables the mirror functionality. Set to **false** to disable all mirrors. +;; Enables the mirror functionality. Set to **false** to disable all mirrors. Pre-existing mirrors remain valid but won't be updated; may be converted to regular repo. ;ENABLED = true ;; Disable the creation of **new** pull mirrors. Pre-existing mirrors remain valid. Will be ignored if `mirror.ENABLED` is `false`. ;DISABLE_NEW_PULL = false diff --git a/docker/root/etc/s6/openssh/setup b/docker/root/etc/s6/openssh/setup index f7843050c1..d4b9b9cd37 100755 --- a/docker/root/etc/s6/openssh/setup +++ b/docker/root/etc/s6/openssh/setup @@ -49,6 +49,7 @@ if [ -d /etc/ssh ]; then SSH_DSA_CERT="${SSH_DSA_CERT:+"HostCertificate "}${SSH_DSA_CERT}" \ SSH_MAX_STARTUPS="${SSH_MAX_STARTUPS:+"MaxStartups "}${SSH_MAX_STARTUPS}" \ SSH_MAX_SESSIONS="${SSH_MAX_SESSIONS:+"MaxSessions "}${SSH_MAX_SESSIONS}" \ + SSH_INCLUDE_FILE="${SSH_INCLUDE_FILE:+"Include "}${SSH_INCLUDE_FILE}" \ SSH_LOG_LEVEL=${SSH_LOG_LEVEL:-"INFO"} \ envsubst < /etc/templates/sshd_config > /etc/ssh/sshd_config diff --git a/docker/root/etc/templates/sshd_config b/docker/root/etc/templates/sshd_config index 6f1a363045..17c2c397bb 100644 --- a/docker/root/etc/templates/sshd_config +++ b/docker/root/etc/templates/sshd_config @@ -41,3 +41,5 @@ Banner none Subsystem sftp /usr/lib/ssh/sftp-server AcceptEnv GIT_PROTOCOL + +${SSH_INCLUDE_FILE} diff --git a/docker/root/usr/local/bin/gitea b/docker/root/usr/local/bin/gitea index 8a8f17bc4e..24d3f91eb1 100644 --- a/docker/root/usr/local/bin/gitea +++ b/docker/root/usr/local/bin/gitea @@ -13,5 +13,3 @@ CUSTOM_PATH="/data/gitea" # Provide docker defaults GITEA_WORK_DIR="${GITEA_WORK_DIR:-$WORK_DIR}" GITEA_CUSTOM="${GITEA_CUSTOM:-$CUSTOM_PATH}" exec -a "$0" "$GITEA" $CONF_ARG "$@" - - diff --git a/docs/config.yaml b/docs/config.yaml index 41a1f7f022..075fd32ef4 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -18,7 +18,7 @@ params: description: Git with a cup of tea author: The Gitea Authors website: https://docs.gitea.io - version: 1.16.7 + version: 1.16.8 minGoVersion: 1.17 goVersion: 1.18 minNodeVersion: 14 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 461795247d..edd23012fb 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -42,8 +42,8 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. ## Repository (`repository`) -- `ROOT`: **data/gitea-repositories/**: Root path for storing all repository data. It must be - an absolute path. By default it is stored in a sub-directory of `APP_DATA_PATH`. +- `ROOT`: **%(APP_DATA_PATH)/gitea-repositories**: Root path for storing all repository data. + A relative path is interpreted as **%(GITEA_WORK_DIR)/%(ROOT)**. - `SCRIPT_TYPE`: **bash**: The script type this server supports. Usually this is `bash`, but some users report that only `sh` is available. - `DETECTED_CHARSETS_ORDER`: **UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF-32LE, ISO-8859, windows-1252, ISO-8859, windows-1250, ISO-8859, ISO-8859, ISO-8859, windows-1253, ISO-8859, windows-1255, ISO-8859, windows-1251, windows-1256, KOI8-R, ISO-8859, windows-1254, Shift_JIS, GB18030, EUC-JP, EUC-KR, Big5, ISO-2022, ISO-2022, ISO-2022, IBM424_rtl, IBM424_ltr, IBM420_rtl, IBM420_ltr**: Tie-break order of detected charsets - if the detected charsets have equal confidence, charsets earlier in the list will be chosen in preference to those later. Adding `defaults` will place the unnamed charsets at that point. @@ -87,11 +87,12 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`. ### Repository - Pull Request (`repository.pull-request`) - `WORK_IN_PROGRESS_PREFIXES`: **WIP:,\[WIP\]**: List of prefixes used in Pull Request - title to mark them as Work In Progress + title to mark them as Work In Progress. These are matched in a case-insensitive manner. - `CLOSE_KEYWORDS`: **close**, **closes**, **closed**, **fix**, **fixes**, **fixed**, **resolve**, **resolves**, **resolved**: List of keywords used in Pull Request comments to automatically close a related issue - `REOPEN_KEYWORDS`: **reopen**, **reopens**, **reopened**: List of keywords used in Pull Request comments to automatically reopen a related issue +- `DEFAULT_MERGE_STYLE`: **merge**: Set default merge style for repository creating, valid options: `merge`, `rebase`, `rebase-merge`, `squash` - `DEFAULT_MERGE_MESSAGE_COMMITS_LIMIT`: **50**: In the default merge message for squash commits include at most this many commits. Set to `-1` to include all commits - `DEFAULT_MERGE_MESSAGE_SIZE`: **5120**: In the default merge message for squash commits limit the size of the commit messages. Set to `-1` to have no limit. Only used if `POPULATE_SQUASH_COMMENT_WITH_COMMIT_MESSAGES` is `true`. - `DEFAULT_MERGE_MESSAGE_ALL_AUTHORS`: **false**: In the default merge message for squash commits walk all commits to include all authors in the Co-authored-by otherwise just use those in the limited list @@ -697,7 +698,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type ## Session (`session`) -- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. +- `PROVIDER`: **memory**: Session engine provider \[memory, file, redis, db, mysql, couchbase, memcache, postgres\]. Setting `db` will reuse the configuration in `[database]` - `PROVIDER_CONFIG`: **data/sessions**: For file, the root path; for db, empty (database config will be used); for others, the connection string. - `COOKIE_SECURE`: **false**: Enable this to force using HTTPS for all session access. - `COOKIE_NAME`: **i\_like\_gitea**: The name of the cookie used for the session ID. @@ -1094,7 +1095,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf ## Mirror (`mirror`) -- `ENABLED`: **true**: Enables the mirror functionality. Set to **false** to disable all mirrors. +- `ENABLED`: **true**: Enables the mirror functionality. Set to **false** to disable all mirrors. Pre-existing mirrors remain valid but won't be updated; may be converted to regular repo. - `DISABLE_NEW_PULL`: **false**: Disable the creation of **new** pull mirrors. Pre-existing mirrors remain valid. Will be ignored if `mirror.ENABLED` is `false`. - `DISABLE_NEW_PUSH`: **false**: Disable the creation of **new** push mirrors. Pre-existing mirrors remain valid. Will be ignored if `mirror.ENABLED` is `false`. - `DEFAULT_INTERVAL`: **8h**: Default interval between each check diff --git a/docs/content/doc/advanced/customizing-gitea.en-us.md b/docs/content/doc/advanced/customizing-gitea.en-us.md index ef798ddbf9..b97ba03482 100644 --- a/docs/content/doc/advanced/customizing-gitea.en-us.md +++ b/docs/content/doc/advanced/customizing-gitea.en-us.md @@ -60,14 +60,15 @@ the url `http://gitea.domain.tld/assets/image.png`. ## Changing the logo -To build a custom logo clone the Gitea source repository, replace `assets/logo.svg` and run -`make generate-images`. This will update below output files which you can then place in `$GITEA_CUSTOM/public/img` on your server: +To build a custom logo and/or favicon clone the Gitea source repository, replace `assets/logo.svg` and/or `assets/favicon.svg` and run +`make generate-images`. `assets/favicon.svg` is used for the favicon only. This will update below output files which you can then place in `$GITEA_CUSTOM/public/img` on your server: -- `public/img/logo.svg` - Used for favicon, site icon, app icon +- `public/img/logo.svg` - Used for site icon, app icon - `public/img/logo.png` - Used for Open Graph -- `public/img/favicon.png` - Used as fallback for browsers that don't support SVG favicons - `public/img/avatar_default.png` - Used as the default avatar image - `public/img/apple-touch-icon.png` - Used on iOS devices for bookmarks +- `public/img/favicon.svg` - Used for favicon +- `public/img/favicon.png` - Used as fallback for browsers that don't support SVG favicons In case the source image is not in vector format, you can attempt to convert a raster image using tools like [this](https://www.aconvert.com/image/png-to-svg/). diff --git a/docs/content/doc/developers/guidelines-frontend.md b/docs/content/doc/developers/guidelines-frontend.md index 874896c5dc..0fced64b14 100644 --- a/docs/content/doc/developers/guidelines-frontend.md +++ b/docs/content/doc/developers/guidelines-frontend.md @@ -27,9 +27,9 @@ The HTML pages are rendered by [Go HTML Template](https://pkg.go.dev/html/templa The source files can be found in the following directories: * **Less styles:** `web_src/less/` -* **Javascript files:** `web_src/js/` -* **Vue layouts:** `web_src/js/components/` -* **HTML templates:** `templates/` +* **JavaScript files:** `web_src/js/` +* **Vue components:** `web_src/js/components/` +* **Go HTML templates:** `templates/` ## General Guidelines @@ -40,31 +40,36 @@ We recommend [Google HTML/CSS Style Guide](https://google.github.io/styleguide/h 1. Every feature (Fomantic-UI/jQuery module) should be put in separate files/directories. 2. HTML ids and classes should use kebab-case. 3. HTML ids and classes used in JavaScript should be unique for the whole project, and should contain 2-3 feature related keywords. We recommend to use the `js-` prefix for classes that are only used in JavaScript. -4. jQuery events across different features should use their own namespaces. -5. CSS styling for classes provided by frameworks should not be overwritten. Always use new class-names to overwrite framework styles. We recommend to use the `us-` prefix for user defined styles. +4. jQuery events across different features could use their own namespaces if there are potential conflicts. +5. CSS styling for classes provided by frameworks should not be overwritten. Always use new class-names with 2-3 feature related keywords to overwrite framework styles. 6. The backend can pass complex data to the frontend by using `ctx.PageData["myModuleData"] = map[]{}` 7. Simple pages and SEO-related pages use Go HTML Template render to generate static Fomantic-UI HTML output. Complex pages can use Vue2 (or Vue3 in future). ### Framework Usage -Mixing different frameworks together is highly discouraged. A JavaScript module should follow one major framework and follow the framework's best practice. +Mixing different frameworks together is discouraged, it makes the code difficult to be maintained. +A JavaScript module should follow one major framework and follow the framework's best practice. Recommended implementations: -* Vue + Native +* Vue + Vanilla JS * Fomantic-UI (jQuery) -* Native only +* Vanilla JS Discouraged implementations: -* Vue + jQuery -* jQuery + Native +* Vue + Fomantic-UI (jQuery) +* jQuery + Vanilla JS + +To make UI consistent, Vue components can use Fomantic-UI CSS classes. +Although mixing different frameworks is discouraged, +it should also work if the mixing is necessary and the code is well-designed and maintainable. ### `async` Functions Only mark a function as `async` if and only if there are `await` calls or `Promise` returns inside the function. -It's not recommended to use `async` event listeners, which may lead to problems. +It's not recommended to use `async` event listeners, which may lead to problems. The reason is that the code after await is executed outside the event dispatch. Reference: https://github.com/github/eslint-plugin-github/blob/main/docs/rules/async-preventdefault.md @@ -73,53 +78,10 @@ it's recommended to use `const _promise = asyncFoo()` to tell readers that this is done by purpose, we want to call the async function and ignore the Promise. Some lint rules and IDEs also have warnings if the returned Promise is not handled. -#### DOM Event Listener - -```js -el.addEventListener('click', (e) => { - (async () => { - await asyncFoo(); // recommended - // then we shound't do e.preventDefault() after await, no effect - })(); - - const _promise = asyncFoo(); // recommended - - e.preventDefault(); // correct -}); - -el.addEventListener('async', async (e) => { // not recommended but acceptable - e.preventDefault(); // acceptable - await asyncFoo(); // skip out event dispatch - e.preventDefault(); // WRONG -}); -``` - -#### jQuery Event Listener - -```js -$('#el').on('click', (e) => { - (async () => { - await asyncFoo(); // recommended - // then we shound't do e.preventDefault() after await, no effect - })(); - - const _promise = asyncFoo(); // recommended - - e.preventDefault(); // correct - return false; // correct -}); - -$('#el').on('click', async (e) => { // not recommended but acceptable - e.preventDefault(); // acceptable - return false; // WRONG, jQuery expects the returned value is a boolean, not a Promise - await asyncFoo(); // skip out event dispatch - return false; // WRONG -}); -``` - ### HTML Attributes and `dataset` -We forbid `dataset` usage, its camel-casing behaviour makes it hard to grep for attributes. However there are still some special cases, so the current guideline is: +The usage of `dataset` is forbidden, its camel-casing behaviour makes it hard to grep for attributes. +However, there are still some special cases, so the current guideline is: * For legacy code: * `$.data()` should be refactored to `$.attr()`. @@ -130,6 +92,10 @@ We forbid `dataset` usage, its camel-casing behaviour makes it hard to grep for * never bind any user data to a DOM node, use a suitable design pattern to describe the relation between node and data. +### Legacy Code + +A lot of legacy code already existed before this document's written. It's recommended to refactor legacy code to follow the guidelines. + ### Vue2/Vue3 and JSX Gitea is using Vue2 now, we plan to upgrade to Vue3. We decided not to introduce JSX to keep the HTML and the JavaScript code separated. diff --git a/docs/content/doc/developers/hacking-on-gitea.en-us.md b/docs/content/doc/developers/hacking-on-gitea.en-us.md index 56ee1ca335..9d15f66dac 100644 --- a/docs/content/doc/developers/hacking-on-gitea.en-us.md +++ b/docs/content/doc/developers/hacking-on-gitea.en-us.md @@ -192,7 +192,7 @@ Start local ElasticSearch instance using docker: ```sh mkdir -p $(pwd)/data/elasticsearch sudo chown -R 1000:1000 $(pwd)/data/elasticsearch -docker run --rm -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" -v "$(pwd)/data/elasticsearch:/usr/share/elasticsearch/data" docker.elastic.co/elasticsearch/elasticsearch:7.16.3 +docker run --rm --memory="4g" -p 127.0.0.1:9200:9200 -p 127.0.0.1:9300:9300 -e "discovery.type=single-node" -v "$(pwd)/data/elasticsearch:/usr/share/elasticsearch/data" docker.elastic.co/elasticsearch/elasticsearch:7.16.3 ``` Configure `app.ini`: diff --git a/docs/content/doc/help/faq.en-us.md b/docs/content/doc/help/faq.en-us.md index e20d11ab81..a64cccfa66 100644 --- a/docs/content/doc/help/faq.en-us.md +++ b/docs/content/doc/help/faq.en-us.md @@ -52,7 +52,8 @@ https://github.com/loganinak/MigrateGitlabToGogs - WorkPath - Environment variable `GITEA_WORK_DIR` - - Else binary location + - Else `--work-path` flag + - Else the directory that contains the Gitea binary - AppDataPath (default for database, indexers, etc.) - `APP_DATA_PATH` from `app.ini` - Else `%(WorkPath)/data` @@ -63,8 +64,9 @@ https://github.com/loganinak/MigrateGitlabToGogs - Unix: Environment variable `HOME` - Windows: Environment variable `USERPROFILE`, else environment variables `HOMEDRIVE`+`HOMEPATH` - RepoRootPath - - `ROOT` in `app.ini` - - Else `%(AppDataPath)/gitea-repositories` + - `ROOT` in the \[repository] section of `app.ini` if absolute + - Else `%(AppWorkPath)/ROOT` if `ROOT` in the \[repository] section of `app.ini` if relative + - Default `%(AppDataPath)/gitea-repositories` - INI (config file) - `-c` flag - Else `%(CustomPath)/conf/app.ini` diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md index 66e596ea4d..c2e7a817c9 100644 --- a/docs/content/doc/installation/with-docker.en-us.md +++ b/docs/content/doc/installation/with-docker.en-us.md @@ -389,16 +389,6 @@ In this option, the idea is that the host simply uses the `authorized_keys` that sudo chmod +x /usr/local/bin/gitea ``` - - For Gitea v1.15.x and earlier. As an administrative user on the host run: - - ```bash - cat <<"EOF" | sudo tee /app/gitea/gitea - #!/bin/sh - ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" - EOF - sudo chmod +x /app/gitea/gitea - ``` - Here is a detailed explanation what is happening when a SSH request is made: 1. The client adds their SSH public key to Gitea using the webpage. @@ -431,7 +421,7 @@ Never add the `Gitea Host Key` as a SSH key to a user on the Gitea interface. In this option, the idea is that the host simply uses the `authorized_keys` that gitea creates but at step 8 above we change the shell that the host runs to ssh directly into the docker and then run the shell there. This means that the `gitea` that is then run is the real docker `gitea`. -- In this case we setup as per SSHing Shim except instead of creating `/usr/local/bin/gitea` or `/app/gitea/gitea` +- In this case we setup as per SSHing Shim except instead of creating `/usr/local/bin/gitea` we create a new shell for the git user. As an administrative user on the host run: ```bash diff --git a/docs/content/doc/installation/with-docker.zh-cn.md b/docs/content/doc/installation/with-docker.zh-cn.md index 77577736f2..9122ee8426 100644 --- a/docs/content/doc/installation/with-docker.zh-cn.md +++ b/docs/content/doc/installation/with-docker.zh-cn.md @@ -301,7 +301,7 @@ volumes: sudo -u git ssh-keygen -t rsa -b 4096 -C "Gitea Host Key" ``` -在下一步中,需要在主机上创建一个名为 `/app/gitea/gitea` 的文件(具有可执行权限)。该文件将发出从主机到容器的 SSH 转发。将以下内容添加到 `/app/gitea/gitea`: +在下一步中,需要在主机上创建一个名为 `/user/local/bin/gitea` 的文件(具有可执行权限)。该文件将发出从主机到容器的 SSH 转发。将以下内容添加到 `/user/local/bin/gitea`: ```bash ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 "SSH_ORIGINAL_COMMAND=\"$SSH_ORIGINAL_COMMAND\" $0 $@" @@ -324,14 +324,14 @@ ports: ssh-rsa # other keys from users -command="/app/gitea/gitea --config=/data/gitea/conf/app.ini serv key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty +command="/user/local/bin/gitea --config=/data/gitea/conf/app.ini serv key-1",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ``` 这是详细的说明,当发出 SSH 请求时会发生什么: 1. 使用 `git` 用户向主机发出 SSH 请求,例如 `git clone git@domain:user/repo.git`。 -2. 在 `/home/git/.ssh/authorized_keys` 中,该命令执行 `/app/gitea/gitea` 脚本。 -3. `/app/gitea/gitea` 将 SSH 请求转发到端口 2222,该端口已映射到容器的 SSH 端口(22)。 +2. 在 `/home/git/.ssh/authorized_keys` 中,该命令执行 `/user/local/bin/gitea` 脚本。 +3. `/user/local/bin/gitea` 将 SSH 请求转发到端口 2222,该端口已映射到容器的 SSH 端口(22)。 4. 由于 `/home/git/.ssh/authorized_keys` 中存在 `git` 用户的公钥,因此身份验证主机 → 容器成功,并且 SSH 请求转发到在 docker 容器中运行的 Gitea。 如果在 Gitea Web 界面中添加了新的 SSH 密钥,它将以与现有密钥相同的方式附加到 `.ssh/authorized_keys` 中。 diff --git a/docs/content/doc/packages/overview.en-us.md b/docs/content/doc/packages/overview.en-us.md index 10f2184bc9..81575b9ade 100644 --- a/docs/content/doc/packages/overview.en-us.md +++ b/docs/content/doc/packages/overview.en-us.md @@ -14,7 +14,7 @@ menu: # Package Registry -The Package Registry can be used as a public or private registry for common package managers. +Starting with Gitea **1.17**, the Package Registry can be used as a public or private registry for common package managers. **Table of Contents** diff --git a/docs/content/doc/usage/backup-and-restore.en-us.md b/docs/content/doc/usage/backup-and-restore.en-us.md index 7cb4a6230f..95e6d376d0 100644 --- a/docs/content/doc/usage/backup-and-restore.en-us.md +++ b/docs/content/doc/usage/backup-and-restore.en-us.md @@ -22,6 +22,12 @@ file can be unpacked and used to restore an instance. {{< toc >}} +## Backup Consistency + +To ensure the consistency of the Gitea instance, it must be shutdown during backup. + +Gitea consists of a database, files and git repositories, all of which change when it is used. For instance, when a migration is in progress, a transaction is created in the database while the git repository is being copied over. If the backup happens in the middle of the migration, the git repository may be incomplete although the database claims otherwise because it was dumped afterwards. The only way to avoid such race conditions is by stopping the Gitea instance during the backups. + ## Backup Command (`dump`) Switch to the user running Gitea: `su git`. Run `./gitea dump -c /path/to/app.ini` in the Gitea installation @@ -48,6 +54,17 @@ Inside the `gitea-dump-1482906742.zip` file, will be the following: Intermediate backup files are created in a temporary directory specified either with the `--tempdir` command-line parameter or the `TMPDIR` environment variable. +## Backup the database + +The SQL dump created by `gitea dump` uses XORM and Gitea admins may prefer to use the native the MySQL and PostgreSQL dump tools instead. There are still open issues when using XORM for dumping the database that may cause problems when attempting to restore it. + +```sh +# mysql +mysqldump -u$USER -p$PASS --database $DATABASE > gitea-db.sql +# postgres +pgdump -U $USER $DATABASE > gitea-db.sql +``` + ### Using Docker (`dump`) There are a few caveats for using the `dump` command with Docker. @@ -57,7 +74,7 @@ The command has to be executed with the `RUN_USER = ` specified in Example: ```none -docker exec -u -it -w <--tempdir> $(docker ps -qf 'name=^$') bash -c '/app/gitea/gitea dump -c ' +docker exec -u -it -w <--tempdir> $(docker ps -qf 'name=^$') bash -c '/user/local/bin/gitea dump -c ' ``` \*Note: `--tempdir` refers to the temporary directory of the docker environment used by Gitea; if you have not specified a custom `--tempdir`, then Gitea uses `/tmp` or the `TMPDIR` environment variable of the docker container. For `--tempdir` adjust your `docker exec` command options accordingly. diff --git a/docs/content/doc/usage/issue-pull-request-templates.en-us.md b/docs/content/doc/usage/issue-pull-request-templates.en-us.md index 65af260c31..185b895d10 100644 --- a/docs/content/doc/usage/issue-pull-request-templates.en-us.md +++ b/docs/content/doc/usage/issue-pull-request-templates.en-us.md @@ -52,15 +52,6 @@ Possible file names for PR default merge message templates: - `.gitea/default_merge_message/MANUALLY-MERGED_TEMPLATE.md` - `.gitea/default_merge_message/REBASE-UPDATE-ONLY_TEMPLATE.md` -Possible file names for PR default merge message templates: - -- `.gitea/default_merge_message/MERGE_TEMPLATE.md` -- `.gitea/default_merge_message/REBASE_TEMPLATE.md` -- `.gitea/default_merge_message/REBASE-MERGE_TEMPLATE.md` -- `.gitea/default_merge_message/SQUASH_TEMPLATE.md` -- `.gitea/default_merge_message/MANUALLY-MERGED_TEMPLATE.md` -- `.gitea/default_merge_message/REBASE-UPDATE-ONLY_TEMPLATE.md` - You can use the following variables enclosed in `${}` inside these templates which follow [os.Expand](https://pkg.go.dev/os#Expand) syntax: - BaseRepoOwnerName: Base repository owner name of this pull request diff --git a/docs/content/page/index.de-de.md b/docs/content/page/index.de-de.md index efe71ec38b..e901702969 100644 --- a/docs/content/page/index.de-de.md +++ b/docs/content/page/index.de-de.md @@ -26,7 +26,7 @@ Gitea ist ein [Gogs](http://gogs.io)-Fork. - 2 CPU Kerne und 1GB RAM sind für kleine Teams/Projekte ausreichend. - Gitea sollte unter einem seperaten nicht-root Account auf UNIX-Systemen ausgeführt werden. - Achtung: Gitea verwaltet die `~/.ssh/authorized_keys` Datei. Gitea unter einem normalen Benutzer auszuführen könnte dazu führen, dass dieser sich nicht mehr anmelden kann. -- [Git](https://git-scm.com/) Version 1.7.2 oder später wird benötigt. Version 1.9.0 oder später wird empfohlen. Außerdem zu beachten: +- [Git](https://git-scm.com/) Version 2.0 oder später wird benötigt. - Wenn git >= 2.1.2. und [Git large file storage](https://git-lfs.github.com/) aktiviert ist, dann wird es auch in Gitea verwendbar sein. - Wenn git >= 2.18, dann wird das Rendern von Commit-Graphen automatisch aktiviert. diff --git a/docs/content/page/index.en-us.md b/docs/content/page/index.en-us.md index b8334ab598..c3a43cd029 100644 --- a/docs/content/page/index.en-us.md +++ b/docs/content/page/index.en-us.md @@ -249,6 +249,17 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others. - Webhooks - Git Hooks - Deploy keys +- Package Registries + - Composer + - Conan + - Container + - Generic + - Helm + - Maven + - NPM + - Nuget + - PyPI + - RubyGems ## System Requirements @@ -256,7 +267,7 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others. - 2 CPU cores and 1GB RAM is typically sufficient for small teams/projects. - Gitea should be run with a dedicated non-root system account on UNIX-type systems. - Note: Gitea manages the `~/.ssh/authorized_keys` file. Running Gitea as a regular user could break that user's ability to log in. -- [Git](https://git-scm.com/) version 1.7.2 or later is required. Version 1.9.0 or later is recommended. Also please note: +- [Git](https://git-scm.com/) version 2.0.0 or later is required. - [Git Large File Storage](https://git-lfs.github.com/) will be available if enabled when Git >= 2.1.2. - Git commit-graph rendering will be enabled automatically when Git >= 2.18. @@ -267,22 +278,21 @@ Windows, on architectures like amd64, i386, ARM, PowerPC, and others. ## Components -* Web framework: [Chi](http://github.com/go-chi/chi) +* Web server framework: [Chi](http://github.com/go-chi/chi) * ORM: [XORM](https://xorm.io) -* UI components: - * [Semantic UI](http://semantic-ui.com/) - * [GitHub Octicons](https://octicons.github.com/) - * [Font Awesome](http://fontawesome.io/) - * [DropzoneJS](http://www.dropzonejs.com/) - * [Highlight](https://highlightjs.org/) - * [Clipboard](https://zenorocha.github.io/clipboard.js/) - * [CodeMirror](https://codemirror.net/) - * [jQuery MiniColors](https://github.com/claviska/jquery-minicolors) +* UI frameworks: + * [jQuery](https://jquery.com) + * [Fomantic UI](https://fomantic-ui.com) + * [Vue2](https://vuejs.org) + * and various components (see package.json) +* Editors: + * [CodeMirror](https://codemirror.net) + * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor) + * [Monaco Editor](https://microsoft.github.io/monaco-editor) * Database drivers: * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) * [github.com/lib/pq](https://github.com/lib/pq) * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - * [github.com/pingcap/tidb](https://github.com/pingcap/tidb) * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) ## Software and Service Support diff --git a/docs/content/page/index.fr-fr.md b/docs/content/page/index.fr-fr.md index 711e163deb..b3828c7141 100755 --- a/docs/content/page/index.fr-fr.md +++ b/docs/content/page/index.fr-fr.md @@ -249,27 +249,24 @@ Le but de ce projet est de fournir de la manière la plus simple, la plus rapide ## Navigateurs supportés -- Consultez [Semantic UI](https://github.com/Semantic-Org/Semantic-UI#browser-support) pour la liste des navigateurs supportés. -- La taille minimale supportée officielement est de **1024*768**, l'interface utilisateur peut toujours fonctionner à une taille plus petite, mais ce n'est pas garanti et les problèmes remontés ne seront pas corrigés. +- Chrome, Firefox, Safari, Edge ## Composants * Framework web : [Chi](http://github.com/go-chi/chi) * ORM: [XORM](https://xorm.io) * Interface graphique : - * [Semantic UI](http://semantic-ui.com/) - * [GitHub Octicons](https://octicons.github.com/) - * [Font Awesome](http://fontawesome.io/) - * [DropzoneJS](http://www.dropzonejs.com/) - * [Highlight](https://highlightjs.org/) - * [Clipboard](https://zenorocha.github.io/clipboard.js/) - * [CodeMirror](https://codemirror.net/) - * [jQuery MiniColors](https://github.com/claviska/jquery-minicolors) + * [jQuery](https://jquery.com) + * [Fomantic UI](https://fomantic-ui.com) + * [Vue2](https://vuejs.org) + * [CodeMirror](https://codemirror.net) + * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor) + * [Monaco Editor](https://microsoft.github.io/monaco-editor) + * ... (package.json) * Connecteurs de base de données : * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) * [github.com/lib/pq](https://github.com/lib/pq) * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - * [github.com/pingcap/tidb](https://github.com/pingcap/tidb) * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) ## Logiciels et services diff --git a/docs/content/page/index.zh-cn.md b/docs/content/page/index.zh-cn.md index 9aa1e6a8bc..d364edb2d7 100644 --- a/docs/content/page/index.zh-cn.md +++ b/docs/content/page/index.zh-cn.md @@ -34,6 +34,7 @@ Gitea的首要目标是创建一个极易安装,运行非常快速,安装和 - 支持后台管理面板 - 支持 MySQL、PostgreSQL、SQLite3、MSSQL 和 TiDB(MySQL) 数据库 - 支持多语言本地化(21 种语言) +- 支持软件包注册中心(Composer/Conan/Container/Generic/Helm/Maven/NPM/Nuget/PyPI/RubyGems) ## 系统要求 @@ -42,27 +43,25 @@ Gitea的首要目标是创建一个极易安装,运行非常快速,安装和 ## 浏览器支持 -- 请根据 [Semantic UI](https://github.com/Semantic-Org/Semantic-UI#browser-support) 查看具体支持的浏览器版本。 -- 官方支持的最小 UI 尺寸为 **1024*768**,UI 不一定会在更小尺寸的设备上被破坏,但我们无法保证且不会修复。 +- Chrome, Firefox, Safari, Edge ## 组件 * Web框架: [Chi](http://github.com/go-chi/chi) * ORM: [XORM](https://xorm.io) -* UI组件: - * [Semantic UI](http://semantic-ui.com/) - * [GitHub Octicons](https://octicons.github.com/) - * [Font Awesome](http://fontawesome.io/) - * [DropzoneJS](http://www.dropzonejs.com/) - * [Highlight](https://highlightjs.org/) - * [Clipboard](https://zenorocha.github.io/clipboard.js/) - * [CodeMirror](https://codemirror.net/) - * [jQuery MiniColors](https://github.com/claviska/jquery-minicolors) +* UI 框架: + * [jQuery](https://jquery.com) + * [Fomantic UI](https://fomantic-ui.com) + * [Vue2](https://vuejs.org) + * 更多组件参见 package.json +* 编辑器: + * [CodeMirror](https://codemirror.net) + * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor) + * [Monaco Editor](https://microsoft.github.io/monaco-editor) * 数据库驱动: * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) * [github.com/lib/pq](https://github.com/lib/pq) * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - * [github.com/pingcap/tidb](https://github.com/pingcap/tidb) * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) ## 软件及服务支持 diff --git a/docs/content/page/index.zh-tw.md b/docs/content/page/index.zh-tw.md index e475f6f214..0c67ef0b28 100644 --- a/docs/content/page/index.zh-tw.md +++ b/docs/content/page/index.zh-tw.md @@ -255,7 +255,7 @@ Gitea 是從 [Gogs](http://gogs.io) Fork 出來的,請閱讀部落格文章 [G - 在類 UNIX 系統上, 應該以專用的非 root 系統帳號來執行 Gitea。 - 備註:Gitea 管理著 `~/.ssh/authorized_keys` 檔案。以一般身份使用者執行 Gitea 可能會破壞該使用者的登入能力。 -- [Git](https://git-scm.com/) 的最低需求為 1.7.2 或更新版本。建議使用 1.9.0 或更新版本。並請留意: +- [Git](https://git-scm.com/) 的最低需求為 2.0 或更新版本。 - 當 git 版本 >= 2.1.2 時,可啟用 Git [large file storage](https://git-lfs.github.com/)。 - 當 git 版本 >= 2.18 時,將自動啟用 Git 提交線圖渲染。 @@ -269,20 +269,19 @@ Gitea 是從 [Gogs](http://gogs.io) Fork 出來的,請閱讀部落格文章 [G - Web 框架: [Chi](http://github.com/go-chi/chi) - ORM: [XORM](https://xorm.io) - UI 元件: - - [Semantic UI](http://semantic-ui.com/) - - [GitHub Octicons](https://octicons.github.com/) - - [Font Awesome](http://fontawesome.io/) - - [DropzoneJS](http://www.dropzonejs.com/) - - [Highlight](https://highlightjs.org/) - - [Clipboard](https://zenorocha.github.io/clipboard.js/) - - [CodeMirror](https://codemirror.net/) - - [jQuery MiniColors](https://github.com/claviska/jquery-minicolors) + * [jQuery](https://jquery.com) + * [Fomantic UI](https://fomantic-ui.com) + * [Vue2](https://vuejs.org) + * [CodeMirror](https://codemirror.net) + * [EasyMDE](https://github.com/Ionaru/easy-markdown-editor) + * [Monaco Editor](https://microsoft.github.io/monaco-editor) + * ... (package.json) - 資料庫驅動程式: - - [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - - [github.com/lib/pq](https://github.com/lib/pq) - - [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - - [github.com/pingcap/tidb](https://github.com/pingcap/tidb) - - [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) + * [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) + * [github.com/lib/pq](https://github.com/lib/pq) + * [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) + * [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) + ## 軟體和服務支援 diff --git a/go.mod b/go.mod index d2375544ce..11f7282c93 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( code.gitea.io/gitea-vet v0.2.2-0.20220122151748-48ebc902541b code.gitea.io/sdk/gitea v0.15.1 gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb - gitea.com/go-chi/cache v0.0.0-20211201020628-dcb774c4ffea + gitea.com/go-chi/cache v0.2.0 gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8 gitea.com/lunny/levelqueue v0.4.1 @@ -14,26 +14,26 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/PuerkitoBio/goquery v1.8.0 github.com/alecthomas/chroma v0.10.0 - github.com/blevesearch/bleve/v2 v2.3.1 - github.com/caddyserver/certmagic v0.15.4 + github.com/blevesearch/bleve/v2 v2.3.2 + github.com/buildkite/terminal-to-html/v3 v3.6.1 + github.com/caddyserver/certmagic v0.16.1 github.com/chi-middleware/proxy v1.1.1 github.com/denisenkom/go-mssqldb v0.12.0 github.com/djherbis/buffer v1.2.0 github.com/djherbis/nio/v3 v3.0.1 - github.com/duo-labs/webauthn v0.0.0-20220223184316-4d1cf2d34051 + github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 github.com/dustin/go-humanize v1.0.0 - github.com/editorconfig/editorconfig-core-go/v2 v2.4.3 - github.com/emirpasic/gods v1.12.0 + github.com/editorconfig/editorconfig-core-go/v2 v2.4.4 + github.com/emirpasic/gods v1.18.1 github.com/ethantkoenig/rupture v1.0.1 - github.com/gliderlabs/ssh v0.3.3 - github.com/go-ap/activitypub v0.0.0-20220420091113-4837641dc83b + github.com/gliderlabs/ssh v0.3.4 github.com/go-chi/chi/v5 v5.0.7 - github.com/go-chi/cors v1.2.0 - github.com/go-enry/go-enry/v2 v2.8.0 + github.com/go-chi/cors v1.2.1 + github.com/go-enry/go-enry/v2 v2.8.2 github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e github.com/go-git/go-billy/v5 v5.3.1 github.com/go-git/go-git/v5 v5.4.3-0.20210630082519-b4368b2a2ca4 - github.com/go-ldap/ldap/v3 v3.4.2 + github.com/go-ldap/ldap/v3 v3.4.3 github.com/go-redis/redis/v8 v8.11.5 github.com/go-sql-driver/mysql v1.6.0 github.com/go-swagger/go-swagger v0.29.0 @@ -42,9 +42,9 @@ require ( github.com/gogs/chardet v0.0.0-20211120154057-b7413eaefb8f github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14 github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 - github.com/golang-jwt/jwt/v4 v4.3.0 - github.com/google/go-github/v39 v39.2.0 - github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 + github.com/golang-jwt/jwt/v4 v4.4.1 + github.com/google/go-github/v45 v45.0.0 + github.com/google/pprof v0.0.0-20220509035851-59ca7ad80af3 github.com/google/uuid v1.3.0 github.com/gorilla/feeds v1.1.1 github.com/gorilla/sessions v1.2.1 @@ -55,21 +55,21 @@ require ( github.com/json-iterator/go v1.1.12 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4 - github.com/klauspost/compress v1.15.0 - github.com/klauspost/cpuid/v2 v2.0.11 - github.com/lib/pq v1.10.4 + github.com/klauspost/compress v1.15.3 + github.com/klauspost/cpuid/v2 v2.0.12 + github.com/lib/pq v1.10.5 github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96 - github.com/markbates/goth v1.69.0 + github.com/markbates/goth v1.72.0 github.com/mattn/go-isatty v0.0.14 github.com/mattn/go-sqlite3 v1.14.12 github.com/mholt/archiver/v3 v3.5.1 github.com/microcosm-cc/bluemonday v1.0.18 - github.com/minio/minio-go/v7 v7.0.23 + github.com/minio/minio-go/v7 v7.0.26 github.com/msteinert/pam v1.0.0 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/niklasfasching/go-org v1.6.2 github.com/oliamb/cutter v0.2.2 - github.com/olivere/elastic/v7 v7.0.31 + github.com/olivere/elastic/v7 v7.0.32 github.com/pkg/errors v0.9.1 github.com/pquerna/otp v1.3.0 github.com/prometheus/client_golang v1.12.1 @@ -77,31 +77,31 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 github.com/sergi/go-diff v1.2.0 github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546 - github.com/stretchr/testify v1.7.0 + github.com/stretchr/testify v1.7.1 github.com/syndtr/goleveldb v1.0.0 github.com/tstranex/u2f v1.0.0 github.com/unrolled/render v1.4.1 - github.com/urfave/cli v1.22.5 - github.com/xanzy/go-gitlab v0.58.0 + github.com/urfave/cli v1.22.9 + github.com/xanzy/go-gitlab v0.64.0 github.com/yohcop/openid-go v1.0.0 - github.com/yuin/goldmark v1.4.11 + github.com/yuin/goldmark v1.4.12 github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 github.com/yuin/goldmark-meta v1.1.0 go.jolheiser.com/hcaptcha v0.0.4 go.jolheiser.com/pwn v0.0.3 - golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd - golang.org/x/net v0.0.0-20220225172249-27dd8689420f - golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b - golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 + golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 + golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 + golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 + golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 golang.org/x/text v0.3.7 - golang.org/x/tools v0.1.9 + golang.org/x/tools v0.1.10 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df gopkg.in/ini.v1 v1.66.4 gopkg.in/yaml.v2 v2.4.0 mvdan.cc/xurls/v2 v2.4.0 strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 - xorm.io/builder v0.3.10 - xorm.io/xorm v1.2.5 + xorm.io/builder v0.3.11 + xorm.io/xorm v1.3.1 ) require ( @@ -109,7 +109,7 @@ require ( git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20200411073322-f0bcc40f0bf2 // indirect github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect + github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/RoaringBitmap/roaring v0.9.4 // indirect @@ -121,9 +121,10 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/speakeasy v0.1.0 // indirect - github.com/bits-and-blooms/bitset v1.2.1 // indirect + github.com/bits-and-blooms/bitset v1.2.2 // indirect github.com/blevesearch/bleve_index_api v1.0.1 // 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.3 // indirect github.com/blevesearch/scorch_segment_api/v2 v2.1.0 // indirect github.com/blevesearch/segment v0.9.0 // indirect @@ -147,7 +148,7 @@ require ( github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect github.com/couchbase/gomemcached v0.1.2 // indirect github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dlclark/regexp2 v1.4.0 // indirect @@ -156,11 +157,11 @@ require ( github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect github.com/felixge/httpsnoop v1.0.2 // indirect github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect - github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/fullstorydev/grpcurl v1.8.1 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/go-ap/jsonld v0.0.0-20200327122108-fafac2de2660 // indirect - github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect + github.com/go-asn1-ber/asn1-ber v1.5.4 // indirect github.com/go-enry/go-oniguruma v1.2.1 // indirect github.com/go-git/gcfg v1.5.0 // indirect github.com/go-openapi/analysis v0.21.2 // indirect @@ -175,7 +176,7 @@ require ( github.com/go-openapi/swag v0.19.15 // indirect github.com/go-openapi/validate v0.20.3 // indirect github.com/go-stack/stack v1.8.1 // indirect - github.com/goccy/go-json v0.9.5 // indirect + github.com/goccy/go-json v0.9.7 // 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.0.0-20170517235910-f1bb20e5a188 // indirect @@ -195,7 +196,7 @@ require ( github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - github.com/hashicorp/go-retryablehttp v0.7.0 // indirect + github.com/hashicorp/go-retryablehttp v0.7.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect @@ -215,7 +216,7 @@ require ( github.com/mattn/go-runewidth v0.0.13 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect github.com/mholt/acmez v1.0.2 // indirect - github.com/miekg/dns v1.1.46 // indirect + github.com/miekg/dns v1.1.48 // indirect github.com/minio/md5-simd v1.1.2 // indirect github.com/minio/sha256-simd v1.0.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -235,7 +236,7 @@ require ( github.com/prometheus/procfs v0.7.3 // indirect github.com/rivo/uniseg v0.2.0 // indirect github.com/rogpeppe/go-internal v1.8.1 // indirect - github.com/rs/xid v1.3.0 // indirect + github.com/rs/xid v1.4.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect github.com/sirupsen/logrus v1.8.1 // indirect @@ -247,7 +248,6 @@ require ( github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/viper v1.10.1 // indirect github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect - github.com/steveyen/gtreap v0.1.0 // indirect github.com/subosito/gotenv v1.2.0 // indirect github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect github.com/toqueteos/webbrowser v1.2.0 // indirect @@ -273,13 +273,13 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/mod v0.5.1 // indirect - golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect + golang.org/x/time v0.0.0-20220411224347-583f2d630306 // indirect + golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect google.golang.org/grpc v1.43.0 // indirect - google.golang.org/protobuf v1.27.1 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff --git a/go.sum b/go.sum index ff16c0a201..047331143f 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,8 @@ git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20200411073322-f0bcc40f0bf2/go.mod h1 gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb h1:Yy0Bxzc8R2wxiwXoG/rECGplJUSpXqCsog9PuJFgiHs= gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb/go.mod h1:77TZu701zMXWJFvB8gvTbQ92zQ3DQq/H7l5wAEjQRKc= gitea.com/go-chi/cache v0.0.0-20210110083709-82c4c9ce2d5e/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= -gitea.com/go-chi/cache v0.0.0-20211201020628-dcb774c4ffea h1:Fq/f4hjigb5v5WpA5TfBCZOSavpHPBiB4Wkj/WsITYM= -gitea.com/go-chi/cache v0.0.0-20211201020628-dcb774c4ffea/go.mod h1:k2V/gPDEtXGjjMGuBJiapffAXTv76H4snSmlJRLUhH0= +gitea.com/go-chi/cache v0.2.0 h1:E0npuTfDW6CT1yD8NMDVc1SK6IeRjfmRL2zlEsCEd7w= +gitea.com/go-chi/cache v0.2.0/go.mod h1:iQlVK2aKTZ/rE9UcHyz9pQWGvdP9i1eI2spOpzgCrtE= gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5 h1:J/1i8u40TbcLP/w2w2KCkgW2PelIqYkD5UOwu8IOvVU= gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5/go.mod h1:hQ9SYHKdOX968wJglb/NMQ+UqpOKwW4L+EYdvkWjHSo= gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8 h1:tJQRXgZigkLeeW9LPlps9G9aMoE6LAmqigLA+wxmd1Q= @@ -84,6 +84,7 @@ gitea.com/lunny/levelqueue v0.4.1 h1:RZ+AFx5gBsZuyqCvofhAkPQ9uaVDPJnsULoJZIYaJNw gitea.com/lunny/levelqueue v0.4.1/go.mod h1:HBqmLbz56JWpfEGG0prskAV97ATNRoj5LDmPicD22hU= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s= gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:EXuID2Zs0pAQhH8yz+DNjUbjppKQzKFAn28TMYPB6IU= +gitee.com/travelliu/dm v1.8.11192/go.mod h1:DHTzyhCrM843x9VdKVbZ+GKXGRbKM2sJ4LxihRxShkE= github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121 h1:r3qt8PCHnfjOv9PN3H+XXKmDA1dfFMIN1AislhlA/ps= github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121/go.mod h1:Ock8XgA7pvULhIaHGAk/cDnRfNrF9Jey81nPcc403iU= github.com/6543/go-version v1.3.1 h1:HvOp+Telns7HWJ2Xo/05YXQSB2bE0WmVgbHqwMPZT4U= @@ -98,7 +99,6 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v0.7.0/go.mod h1:yqy467j36fJxcRV2 github.com/Azure/azure-service-bus-go v0.9.1/go.mod h1:yzBx6/BUGfjfeqbRZny9AQIbIe3AcV9WZbAdpkoXOa0= github.com/Azure/azure-storage-blob-go v0.8.0/go.mod h1:lPI3aLPpuLTeUwh1sViKXFxwl2B6teiRqI0deQUvsw0= github.com/Azure/go-autorest v12.0.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/Azure/go-ntlmssp v0.0.0-20200615164410-66371956d46c/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e h1:ZU22z/2YRFLyf/P4ZwUYSdNCWsMEI0VeyrFoI2rAhJQ= github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -126,8 +126,8 @@ github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cq github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f h1:J2FzIrXN82q5uyUraeJpLIm7U6PffRwje2ORho5yIik= -github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= +github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5 h1:cSHEbLj0GZeHM1mWG84qEnGFojNEQ83W7cwaPRjcwXU= +github.com/ProtonMail/go-crypto v0.0.0-20220407094043-a94812496cf5/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U= github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI= github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -199,7 +199,6 @@ github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/aws/aws-sdk-go v1.25.11/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48= -github.com/aws/aws-sdk-go v1.42.23/go.mod h1:gyRszuZ/icHmHAVE4gc/r+cfCmhA1AD+vqfWbgI+eHs= github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g= github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -214,18 +213,22 @@ github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQ github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bits-and-blooms/bitset v1.1.10/go.mod h1:w0XsmFg8qg6cmpTtJ0z3pKgjTDBMMnI/+I2syrE6XBE= github.com/bits-and-blooms/bitset v1.2.0/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= -github.com/bits-and-blooms/bitset v1.2.1 h1:M+/hrU9xlMp7t4TyTDQW97d3tRPVuKFC6zBEK16QnXY= -github.com/bits-and-blooms/bitset v1.2.1/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= +github.com/bits-and-blooms/bitset v1.2.2 h1:J5gbX05GpMdBjCvQ9MteIg2KKDExr7DrgK+Yc15FvIk= +github.com/bits-and-blooms/bitset v1.2.2/go.mod h1:gIdJ4wp64HaoK2YrL1Q5/N7Y16edYb8uY+O0FJTyyDA= 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.1 h1:rbMTDM17tvZ7wTrTp4lJINYRnz57N5oMSw8cYuJ4l0k= -github.com/blevesearch/bleve/v2 v2.3.1/go.mod h1:kAJuWn2L1TNSUyxtPJD4AGma2/PgMSm7GBlx61F9OBs= +github.com/blevesearch/bleve/v2 v2.3.2 h1:BJUnMhi2nrkl+vboHmKfW+9l+tJSj39HeWa5c3BN3/Y= +github.com/blevesearch/bleve/v2 v2.3.2/go.mod h1:96+xE5pZUOsr3Y4vHzV1cBC837xZCpwLlX0hrrxnvIg= github.com/blevesearch/bleve_index_api v1.0.0/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= github.com/blevesearch/bleve_index_api v1.0.1 h1:nx9++0hnyiGOHJwQQYfsUGzpRdEVE5LsylmmngQvaFk= github.com/blevesearch/bleve_index_api v1.0.1/go.mod h1:fiwKS0xLEm+gBRgv5mumf0dhgFr2mDgZah1pqv1c1M4= +github.com/blevesearch/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:9eJDeqxJ3E7WnLebQUlPD7ZjSce7AnDb9vjGmMCbD0A= github.com/blevesearch/go-porterstemmer v1.0.3 h1:GtmsqID0aZdCSNiY8SkuPJ12pD4jI+DdXTAn4YRcHCo= github.com/blevesearch/go-porterstemmer v1.0.3/go.mod h1:angGc5Ht+k2xhJdZi511LtmxuEf0OVpvUUNrwmM1P7M= +github.com/blevesearch/goleveldb v1.0.1/go.mod h1:WrU8ltZbIp0wAoig/MHbrPCXSOLpe79nz5lv5nqfYrQ= +github.com/blevesearch/gtreap v0.1.1 h1:2JWigFrzDMR+42WGIN/V2p0cUvn4UP3C4Q5nmaZGW8Y= +github.com/blevesearch/gtreap v0.1.1/go.mod h1:QaQyDRAT51sotthUWAH4Sj08awFSSWzgYICSZ3w0tYk= github.com/blevesearch/mmap-go v1.0.2/go.mod h1:ol2qBqYaOUsGdm7aRMRrYGgPvnwLe6Y+7LMvAB5IbSA= github.com/blevesearch/mmap-go v1.0.3 h1:7QkALgFNooSq3a46AE+pWeKASAZc9SiNFJhDGF1NDx4= github.com/blevesearch/mmap-go v1.0.3/go.mod h1:pYvKl/grLQrBxuaRYgoTssa4rVujYYeenDp++2E+yvs= @@ -234,6 +237,7 @@ github.com/blevesearch/scorch_segment_api/v2 v2.1.0 h1:NFwteOpZEvJk5Vg0H6gD0hxup github.com/blevesearch/scorch_segment_api/v2 v2.1.0/go.mod h1:uch7xyyO/Alxkuxa+CGs79vw0QY8BENSBjg6Mw5L5DE= 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= @@ -263,9 +267,11 @@ github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pOvUGt1D1lA5KjYhPBAN/3iWdP7xeFS9F0= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/buildkite/terminal-to-html/v3 v3.6.1 h1:yHS+GXsPDXevb67YXjkVwZ4tolDCgPYa9RVOrzHlgGE= +github.com/buildkite/terminal-to-html/v3 v3.6.1/go.mod h1:g0ME1XqbkBSgXR9YmlIHcJIjzaMyWW+HbsG0rPb5puo= github.com/caarlos0/ctrlc v1.0.0/go.mod h1:CdXpj4rmq0q/1Eb44M9zi2nKB0QraNKuRGYGrrHhcQw= -github.com/caddyserver/certmagic v0.15.4 h1:kz//9+Z/xw197jtIBxxUDub8pQi9gcYvhXk5Ouw2EkM= -github.com/caddyserver/certmagic v0.15.4/go.mod h1:qhkAOthf72ufAcp3Y5jF2RaGE96oip3UbEQRIzwe3/8= +github.com/caddyserver/certmagic v0.16.1 h1:rdSnjcUVJojmL4M0efJ+yHXErrrijS4YYg3FuwRdJkI= +github.com/caddyserver/certmagic v0.16.1/go.mod h1:jKQ5n+ViHAr6DbPwEGLTSM2vDwTO6EvCKBblBRUvvuQ= github.com/campoy/unique v0.0.0-20180121183637-88950e537e7e/go.mod h1:9IOqJGCPMSc6E5ydlp5NIonxObaeu/Iub/X03EKPVYo= github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ= github.com/cavaliercoder/go-cpio v0.0.0-20180626203310-925f9528c45e/go.mod h1:oDpT4efm8tSYHXV5tHSdRvBet/b/QzxZ+XyyPehvm3A= @@ -277,7 +283,6 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d h1:S2NE3iHSwP0XV47EEXL8mWmRdEfGscSJ+7EgePNgt0s= github.com/certifi/gocertifi v0.0.0-20210507211836-431795d63e8d/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA= -github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= @@ -321,13 +326,11 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= @@ -346,12 +349,12 @@ github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 h1:4KDlx3vjalrHD 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 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk= 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= -github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= @@ -362,6 +365,8 @@ github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= @@ -384,8 +389,8 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY= github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s= github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY= -github.com/duo-labs/webauthn v0.0.0-20220223184316-4d1cf2d34051 h1:yyZ8u8em9L9B1hz0FhumWB0CUCu7mc1tymX4YOIBlxQ= -github.com/duo-labs/webauthn v0.0.0-20220223184316-4d1cf2d34051/go.mod h1:UMk1JMDgQDcdI2vQz+WJOIUTSjIq07qSepAVgc93rUc= +github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499 h1:jaQHuGKk9NVcfu9VbA7ygslr/7utxdYs47i4osBhZP8= +github.com/duo-labs/webauthn v0.0.0-20220330035159-03696f3d4499/go.mod h1:UMk1JMDgQDcdI2vQz+WJOIUTSjIq07qSepAVgc93rUc= github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= @@ -393,12 +398,13 @@ github.com/dvyukov/go-fuzz v0.0.0-20210429054444-fca39067bc72/go.mod h1:11Gm+ccJ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/editorconfig/editorconfig-core-go/v2 v2.4.3 h1:9CdJZAU1nFCIIJRzrQ13zfxM6OoI8bs/Lbwszgj6lkM= -github.com/editorconfig/editorconfig-core-go/v2 v2.4.3/go.mod h1:moOnvLV6oPQDuXHWGAPAmZgjRBq1xmMtnSwFQ1wiwSk= +github.com/editorconfig/editorconfig-core-go/v2 v2.4.4 h1:FclmQqjEE8TqTFe6OGhaZY7MmbWVp9dBvv9vZkeC4Hk= +github.com/editorconfig/editorconfig-core-go/v2 v2.4.4/go.mod h1:mz3wjBRdp75EfR6lp9qLmqyKp76AlT9I2Z13nALZeQs= github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/elazarl/go-bindata-assetfs v1.0.1/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4= -github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg= github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o= +github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= +github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= @@ -436,8 +442,9 @@ github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVB github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= +github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fullstorydev/grpcurl v1.8.0/go.mod h1:Mn2jWbdMrQGJQ8UD62uNyMumT2acsZUCkZIqFxsQf1o= github.com/fullstorydev/grpcurl v1.8.1 h1:Pp648wlTTg3OKySeqxM5pzh8XF6vLqrm8wRq66+5Xo0= github.com/fullstorydev/grpcurl v1.8.1/go.mod h1:3BWhvHZwNO7iLXaQlojdg5NA6SxUDePli4ecpK1N7gw= @@ -447,8 +454,8 @@ github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JY github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA= -github.com/gliderlabs/ssh v0.3.3/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= +github.com/gliderlabs/ssh v0.3.4 h1:+AXBtim7MTKaLVPgvE+3mhewYRawNLTd+jEEz/wExZw= +github.com/gliderlabs/ssh v0.3.4/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q= github.com/glycerine/go-unsnap-stream v0.0.0-20181221182339-f9677308dec2/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= @@ -457,17 +464,16 @@ github.com/go-ap/activitypub v0.0.0-20220420091113-4837641dc83b h1:Hh6VfXJpz8yIj github.com/go-ap/activitypub v0.0.0-20220420091113-4837641dc83b/go.mod h1:MB3P8x1tiEf6sOEfXnHEep23Zp+onx2HcD8G4eILAkM= github.com/go-ap/jsonld v0.0.0-20200327122108-fafac2de2660 h1:AUG8+r0Q/zbNUAi5CWVBK5oUhOZDX3Kkr+oWURaJIfU= github.com/go-ap/jsonld v0.0.0-20200327122108-fafac2de2660/go.mod h1:jyveZeGw5LaADntW+UEsMjl3IlIwk+DxlYNsbofQkGA= -github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= -github.com/go-asn1-ber/asn1-ber v1.5.3 h1:u7utq56RUFiynqUzgVMFDymapcOtQ/MZkh3H4QYkxag= -github.com/go-asn1-ber/asn1-ber v1.5.3/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= +github.com/go-asn1-ber/asn1-ber v1.5.4 h1:vXT6d/FNDiELJnLb6hGNa309LMsrCoYFvpwHDF0+Y1A= +github.com/go-asn1-ber/asn1-ber v1.5.4/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-chi/chi/v5 v5.0.1/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.4/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8= github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= -github.com/go-chi/cors v1.2.0 h1:tV1g1XENQ8ku4Bq3K9ub2AtgG+p16SmzeMSGTwrOKdE= -github.com/go-chi/cors v1.2.0/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-enry/go-enry/v2 v2.8.0 h1:KMW4mSG+8uUF6FaD3iPkFqyfC5tF8gRrsYImq6yhHzo= -github.com/go-enry/go-enry/v2 v2.8.0/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= +github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= +github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= +github.com/go-enry/go-enry/v2 v2.8.2 h1:uiGmC+3K8sVd/6DOe2AOJEOihJdqda83nPyJNtMR8RI= +github.com/go-enry/go-enry/v2 v2.8.2/go.mod h1:GVzIiAytiS5uT/QiuakK7TF1u4xDab87Y8V5EJRpsIQ= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= github.com/go-fed/httpsig v1.1.1-0.20201223112313-55836744818e h1:oRq/fiirun5HqlEWMLIcDmLpIELlG4iGbd0s8iqgPi8= @@ -489,8 +495,8 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o= github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-ldap/ldap/v3 v3.4.2 h1:zFZKcXKLqZpFMrMQGHeHWKXbDTdNCmhGY9AK41zPh+8= -github.com/go-ldap/ldap/v3 v3.4.2/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= +github.com/go-ldap/ldap/v3 v3.4.3 h1:JCKUtJPIcyOuG7ctGabLKMgIlKnGumD/iGjuWeEruDI= +github.com/go-ldap/ldap/v3 v3.4.3/go.mod h1:7LdHfVt6iIOESVEe3Bs4Jp2sHEKgDeduAhgM1/f9qmo= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= @@ -598,7 +604,6 @@ github.com/go-openapi/validate v0.20.1/go.mod h1:b60iJT+xNNLfaQJUqLI7946tYiFEOuE github.com/go-openapi/validate v0.20.3 h1:GZPPhhKSZrE8HjB4eEkoYAZmoWA4+tCemSgINH1/vKw= github.com/go-openapi/validate v0.20.3/go.mod h1:goDdqVGiigM3jChcrYJxD2joalke3ZXeftD16byIjA4= github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= -github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg= github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis/v8 v8.4.0/go.mod h1:A1tbYoHSa1fXwN+//ljcCYYJeLmVrwL9hbQN45Jdy0M= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= @@ -614,8 +619,6 @@ github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP github.com/go-swagger/go-swagger v0.29.0 h1:z3YoZtLvS1Y8TE/PCat1VypcZxM0IgKLt0NvZxQyNl8= github.com/go-swagger/go-swagger v0.29.0/go.mod h1:Z4GJzI+bHKKkGB2Ji1rawpi3/ldXX8CkzGIa9HAC5EE= github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= -github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013/go.mod h1:b65mBPzqzZWxOZGxSWrqs4GInLIn+u99Q9q7p+GKni0= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-testfixtures/testfixtures/v3 v3.6.1 h1:n4Fv95Exp0D05G6l6CAZv22Ck1EJK0pa0TfPqE4ncSs= github.com/go-testfixtures/testfixtures/v3 v3.6.1/go.mod h1:Bsb2MoHAfHnNsPpSwAjtOs102mqDuM+1u3nE2OCi0N0= github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= @@ -644,9 +647,11 @@ github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/V github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-json v0.7.4/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= -github.com/goccy/go-json v0.9.5 h1:ooSMW526ZjK+EaL5elrSyN2EzIfi/3V0m4+HJEDYLik= +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.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= +github.com/goccy/go-json v0.9.7/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= @@ -666,8 +671,8 @@ github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85 h1:UjoPNDAQ5JP github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85/go.mod h1:fR6z1Ie6rtF7kl/vBYMfgD5/G5B1blui7z426/sj2DU= github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= -github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA= github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= @@ -735,11 +740,12 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-github/v28 v28.1.1/go.mod h1:bsqJWQX05omyWVmc00nEUql9mhQyv38lDZ8kPZcQVoM= -github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ= -github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE= +github.com/google/go-github/v45 v45.0.0 h1:LU0WBjYidxIVyx7PZeWb+FP4JZJ3Wh3FQgdumnGqiLs= +github.com/google/go-github/v45 v45.0.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28= github.com/google/go-licenses v0.0.0-20210329231322-ce1d9163b77d/go.mod h1:+TYOmkVoJOpwnS0wfdsJCV9CoD5nJYsHoFk/0CrTK4M= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= @@ -766,11 +772,11 @@ github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20220509035851-59ca7ad80af3 h1:vFrXU7L2gqtlP/ZGijSpaDIc16ZQrZI4FAuYtpQTyQc= +github.com/google/pprof v0.0.0-20220509035851-59ca7ad80af3/go.mod h1:Pt31oes+eGImORns3McJn8zHefuQl2rG8l6xQjGYB4U= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/rpmpack v0.0.0-20191226140753-aa36bfddb3a0/go.mod h1:RaTPr0KUf2K7fnZYLNDrr8rxAamWs3iNywJLtQ2AzBg= github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= @@ -838,7 +844,6 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFb github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE= github.com/hashicorp/consul/api v1.11.0/go.mod h1:XjsvQN+RJGWI2TWy1/kqaE16HrR2J/FWgkYjdZQsX9M= -github.com/hashicorp/consul/api v1.12.0/go.mod h1:6pVBMo0ebnYdt2S3H87XhekM/HHrUoTD2XXb/VrZVy0= github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= @@ -858,9 +863,8 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.0 h1:eu1EI/mbirUgP5C8hVsTNaGZreBDlYiwC1FZWkvQPQ4= -github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= +github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= +github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= @@ -1025,19 +1029,14 @@ github.com/kisom/goutils v1.4.3/go.mod h1:Lp5qrquG7yhYnWzZCI/68Pa/GpFynw//od6EkG github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= -github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.3 h1:wmfu2iqj9q22SyMINp1uQ8C2/V4M1phJdmH9fG4nba0= +github.com/klauspost/compress v1.15.3/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= -github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.0.1/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.4/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A= -github.com/klauspost/cpuid/v2 v2.0.11/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= +github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE= github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfENGMvNRhldw= @@ -1059,7 +1058,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/go-gypsy v1.0.0/go.mod h1:chkXM0zjdpXOiqkCW1XcCHDfjfk14PH2KKkQWxfJUcU= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/lestrrat-go/jwx v0.9.0/go.mod h1:iEoxlYfZjvoGpuWwxUz+eR5e6KTJGsaRcy/YNA/UnBk= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.0/go.mod h1:TNgH//0vYSs8VXDCfkZLgIrVTTXQELZffUV0tz3MtdQ= +github.com/lestrrat-go/httpcc v1.0.0/go.mod h1:tGS/u00Vh5N6FHNkExqGGNId8e0Big+++0Gf8MBnAvE= +github.com/lestrrat-go/iter v1.0.1/go.mod h1:zIdgO1mRKhn8l9vrZJZz9TUMMFbQbLeTsbqPDrJ/OJc= +github.com/lestrrat-go/jwx v1.2.21/go.mod h1:9cfxnOH7G1gN75CaJP2hKGcxFEx5sPh1abRIA/ZJVh4= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJiIbETBPTl9ATXQag= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= @@ -1068,8 +1072,8 @@ github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.1/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk= -github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= +github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ= +github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/libdns/libdns v0.2.1 h1:Wu59T7wSHRgtA0cfxC+n1c/e+O3upJGWytknkmFEDis= github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= @@ -1097,8 +1101,8 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/markbates/going v1.0.0 h1:DQw0ZP7NbNlFGcKbcE/IVSOAFzScxRtLpd0rLMzLhq0= github.com/markbates/going v1.0.0/go.mod h1:I6mnB4BPnEeqo85ynXIx1ZFLLbtiLHNXVgWeFO9OGOA= -github.com/markbates/goth v1.69.0 h1:HoXdRES8Hfx4H4ICM27Im+IuVubflaAX7mXCmYHiWIw= -github.com/markbates/goth v1.69.0/go.mod h1:uk3KIdtCKdmyNABgOSmHFNHN0AcKqkLs8j5Ak3Ioe1Q= +github.com/markbates/goth v1.72.0 h1:Vm9OE+GsB7FrrvBqKEYsRBiPg4LWJ6DT5zD0XN2Rl4U= +github.com/markbates/goth v1.72.0/go.mod h1:X6xdNgpapSENS0O35iTBBcMHoJDQDfI9bJl+APCkYMc= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A= @@ -1133,14 +1137,13 @@ github.com/mattn/go-shellwords v1.0.10/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lL github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/go-sqlite3 v1.14.8/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.9/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.12 h1:TJ1bhYJPV44phC+IMu1u2K/i5RriLTPe+yc68XDJ1Z0= github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= -github.com/mholt/acmez v1.0.1/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo= github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM= github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo= @@ -1150,17 +1153,14 @@ github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= -github.com/miekg/dns v1.1.46 h1:uzwpxRtSVxtcIZmz/4Uz6/Rn7G11DvsaslXoy5LxQio= -github.com/miekg/dns v1.1.46/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.48 h1:Ucfr7IIVyMBz4lRE8qmGUuZ4Wt3/ZGu9hmcMT3Uu4tQ= +github.com/miekg/dns v1.1.48/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/minio/md5-simd v1.1.0/go.mod h1:XpBqgZULrMYD3R+M28PcmP0CkI7PEMzB3U77ZrKZ0Gw= github.com/minio/md5-simd v1.1.2 h1:Gdi1DZK69+ZVMoNHRXJyNcxrMA4dSxoYHZSQbirFg34= github.com/minio/md5-simd v1.1.2/go.mod h1:MzdKDxYpY2BT9XQFocsiZf/NKVtR7nkE4RoEpN+20RM= -github.com/minio/minio-go/v7 v7.0.23 h1:NleyGQvAn9VQMU+YHVrgV4CX+EPtxPt/78lHOOTncy4= -github.com/minio/minio-go/v7 v7.0.23/go.mod h1:ei5JjmxwHaMrgsMrn4U/+Nmg+d8MKS1U2DAn1ou4+Do= -github.com/minio/sha256-simd v0.1.1/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= +github.com/minio/minio-go/v7 v7.0.26 h1:D0HK+8793etZfRY/vHhDmFaP+vmT41K3K4JV9vmZCBQ= +github.com/minio/minio-go/v7 v7.0.26/go.mod h1:x81+AX5gHSfCSqw7jxRKHvxUXMlE5uKX0Vb75Xk5yYg= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -1224,7 +1224,6 @@ github.com/nwaples/rardecode v1.1.3 h1:cWCaZwfM5H7nAD6PyEdcVnczzV8i/JtotnyW/dD9l github.com/nwaples/rardecode v1.1.3/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= -github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= @@ -1235,26 +1234,21 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/oliamb/cutter v0.2.2 h1:Lfwkya0HHNU1YLnGv2hTkzHfasrSMkgv4Dn+5rmlk3k= github.com/oliamb/cutter v0.2.2/go.mod h1:4BenG2/4GuRBDbVm/OPahDVqbrOemzpPiG5mi1iryBU= -github.com/olivere/elastic/v7 v7.0.31 h1:VJu9/zIsbeiulwlRCfGQf6Tzsr++uo+FeUgj5oj+xKk= -github.com/olivere/elastic/v7 v7.0.31/go.mod h1:idEQxe7Es+Wr4XAuNnJdKeMZufkA9vQprOIFck061vg= +github.com/olivere/elastic/v7 v7.0.32 h1:R7CXvbu8Eq+WlsLgxmKVKPox0oOwAE/2T9Si5BnvK6E= +github.com/olivere/elastic/v7 v7.0.32/go.mod h1:c7PVmLe3Fxq77PIfY/bZmxY/TAamBhCzZ8xDOE09a9k= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= -github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= -github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc= -github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE= -github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74= @@ -1284,7 +1278,6 @@ github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= -github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I= github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= @@ -1303,7 +1296,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= github.com/pquerna/otp v1.3.0 h1:oJV/SkzR33anKXwQU3Of42rL4wbrffP4uvUf1SvS5Xs= github.com/pquerna/otp v1.3.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= @@ -1371,18 +1363,16 @@ github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XF github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/xid v1.3.0 h1:6NjYksEUlhurdVehpc7S7dk6DAmcKv8V9gG0FsVN2U4= -github.com/rs/xid v1.3.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= +github.com/rs/xid v1.4.0 h1:qd7wPTDkN6KQx2VmMBLrpHkiyQwgFXRnkOLacUiaSNY= +github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig= -github.com/sagikazarmark/crypt v0.4.0/go.mod h1:ALv2SRj7GxYV4HO9elxH9nS6M9gW+xDNxqmyJ6RfDFM= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 h1:TToq11gyfNlrMFZiYujSekIsPd9AmsA2Bj/iv+s4JHE= github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H/cDPdvJ/SZJQLWWXWGrZ0= @@ -1415,14 +1405,12 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1 github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM= github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfItdAd1r3cck= -github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM= github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs= -github.com/smartystreets/gunit v1.4.2/go.mod h1:ZjM1ozSIMJlAz/ay4SG8PeKF00ckUp+zMHZXV9/bvak= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= @@ -1462,7 +1450,6 @@ github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jW github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo= github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM= github.com/stephens2424/writerset v1.0.2/go.mod h1:aS2JhsMn6eA7e82oNmW4rfsgAOp9COBTTl8mzkwADnc= -github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y= github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= @@ -1476,8 +1463,9 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= @@ -1516,8 +1504,10 @@ github.com/unrolled/render v1.4.1/go.mod h1:cK4RSTTVdND5j9EYEc0LAMOvdG11JeiKjyjf github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli v1.22.9 h1:cv3/KhXGBGjEXLC4bH0sLuJ9BewaAbpk5oyMOveu4pw= +github.com/urfave/cli v1.22.9/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fastjson v1.6.3 h1:tAKFnnwmeMGPbwJ7IwxcTPCNr3uIzoIj3/Fh90ra4xc= github.com/valyala/fastjson v1.6.3/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY= @@ -1529,8 +1519,8 @@ github.com/willf/bitset v1.1.10/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPy github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= -github.com/xanzy/go-gitlab v0.58.0 h1:Entnl8GrVDlc1jd1BlOWhNR0QVQgiO3WDom5DJbT+1s= -github.com/xanzy/go-gitlab v0.58.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= +github.com/xanzy/go-gitlab v0.64.0 h1:rMgQdW9S1w3qvNAH2LYpFd2xh7KNLk+JWJd7sorNuTc= +github.com/xanzy/go-gitlab v0.64.0/go.mod h1:F0QEXwmqiBUxCgJm8fE9S+1veX4XC9Z4cfaAbqwk4YM= github.com/xanzy/ssh-agent v0.2.1/go.mod h1:mLlQY/MoOhWBj+gOGMQkOeiEvkx+8pJSI+0Bx9h2kr4= github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0= github.com/xanzy/ssh-agent v0.3.1 h1:AmzO1SSWxw73zxFZPRwaMN1MohDw8UyHnmuxyceTEGo= @@ -1553,11 +1543,9 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= -github.com/yuin/goldmark v1.4.6/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= -github.com/yuin/goldmark v1.4.11 h1:i45YIzqLnUc2tGaTlJCyUxSG8TvgyGqhqOZOUKIjJ6w= -github.com/yuin/goldmark v1.4.11/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= +github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0= +github.com/yuin/goldmark v1.4.12/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594 h1:yHfZyN55+5dp1wG7wDKv8HQ044moxkyGq12KFFMFDxg= github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594/go.mod h1:U9ihbh+1ZN7fR5Se3daSPoz1CGF9IYtSvWwVQtnzGHU= github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUeiOUc= @@ -1574,7 +1562,6 @@ go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= -go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.etcd.io/etcd/api/v3 v3.5.0-alpha.0/go.mod h1:mPcW6aZJukV6Aa81LSKpBjQXTWlXB5r74ymPoSWa3Sw= go.etcd.io/etcd/api/v3 v3.5.1 h1:v28cktvBq+7vGyJXF8G+rWJmj+1XUmMtqcLnH8hDocM= @@ -1677,7 +1664,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191117063200-497ca9f6d64f/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -1692,10 +1678,10 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220112180741-5e0467b6c7ce/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= -golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122 h1:NvGWuYG8dkDHFSKksI1P9faiVJ9rayE6l0+ouWVIDs8= +golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1733,8 +1719,9 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1782,7 +1769,6 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200930145003-4acb6c075d10/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -1797,7 +1783,6 @@ golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5o golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= @@ -1806,13 +1791,10 @@ golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1834,8 +1816,8 @@ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b h1:clP8eMhB30EHdc0bd2Twtq6kgU7yl5ub2cQLSdrv1Dg= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1921,7 +1903,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1951,18 +1932,17 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210902050250-f475640dd07b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -1983,8 +1963,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= -golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= +golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -2060,7 +2040,6 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -2071,16 +2050,16 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.8/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= -golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8= -golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= +golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -2119,7 +2098,6 @@ google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdr google.golang.org/api v0.59.0/go.mod h1:sT2boj7M9YJxZzgeZqXogmhfmRWDtPzT31xkieUbuZU= google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw= -google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= @@ -2257,8 +2235,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= @@ -2279,15 +2258,11 @@ gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkp gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.44.2/go.mod h1:M3Cogqpuv0QCi3ExAY5V4uOt4qb/R3xZubo9m8lK5wg= gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.66.3/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.66.4 h1:SsAcf+mM7mRZo2nJNGt8mZCjG8ZRaNGMURJw7BsIST4= gopkg.in/ini.v1 v1.66.4/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98= gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8= @@ -2321,31 +2296,113 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.1.4/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU= lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk= -modernc.org/cc/v3 v3.33.6 h1:r63dgSzVzRxUpAJFPQWHy1QeZeY1ydNENUDaBx1GqYc= modernc.org/cc/v3 v3.33.6/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= -modernc.org/ccgo/v3 v3.9.5 h1:dEuUSf8WN51rDkprFuAqjfchKEzN0WttP/Py3enBwjk= +modernc.org/cc/v3 v3.33.9/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.33.11/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.34.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.0/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.4/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.5/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.7/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.8/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.10/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.15/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.16/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.17/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= +modernc.org/cc/v3 v3.35.18 h1:rMZhRcWrba0y3nVmdiQ7kxAgOOSq2m2f2VzjHLgEs6U= +modernc.org/cc/v3 v3.35.18/go.mod h1:iPJg1pkwXqAV16SNgFBVYmggfMg6xhs+2oiO0vclK3g= modernc.org/ccgo/v3 v3.9.5/go.mod h1:umuo2EP2oDSBnD3ckjaVUXMrmeAw8C8OSICVa0iFf60= +modernc.org/ccgo/v3 v3.10.0/go.mod h1:c0yBmkRFi7uW4J7fwx/JiijwOjeAeR2NoSaRVFPmjMw= +modernc.org/ccgo/v3 v3.11.0/go.mod h1:dGNposbDp9TOZ/1KBxghxtUp/bzErD0/0QW4hhSaBMI= +modernc.org/ccgo/v3 v3.11.1/go.mod h1:lWHxfsn13L3f7hgGsGlU28D9eUOf6y3ZYHKoPaKU0ag= +modernc.org/ccgo/v3 v3.11.3/go.mod h1:0oHunRBMBiXOKdaglfMlRPBALQqsfrCKXgw9okQ3GEw= +modernc.org/ccgo/v3 v3.12.4/go.mod h1:Bk+m6m2tsooJchP/Yk5ji56cClmN6R1cqc9o/YtbgBQ= +modernc.org/ccgo/v3 v3.12.6/go.mod h1:0Ji3ruvpFPpz+yu+1m0wk68pdr/LENABhTrDkMDWH6c= +modernc.org/ccgo/v3 v3.12.8/go.mod h1:Hq9keM4ZfjCDuDXxaHptpv9N24JhgBZmUG5q60iLgUo= +modernc.org/ccgo/v3 v3.12.11/go.mod h1:0jVcmyDwDKDGWbcrzQ+xwJjbhZruHtouiBEvDfoIsdg= +modernc.org/ccgo/v3 v3.12.14/go.mod h1:GhTu1k0YCpJSuWwtRAEHAol5W7g1/RRfS4/9hc9vF5I= +modernc.org/ccgo/v3 v3.12.18/go.mod h1:jvg/xVdWWmZACSgOiAhpWpwHWylbJaSzayCqNOJKIhs= +modernc.org/ccgo/v3 v3.12.20/go.mod h1:aKEdssiu7gVgSy/jjMastnv/q6wWGRbszbheXgWRHc8= +modernc.org/ccgo/v3 v3.12.21/go.mod h1:ydgg2tEprnyMn159ZO/N4pLBqpL7NOkJ88GT5zNU2dE= +modernc.org/ccgo/v3 v3.12.22/go.mod h1:nyDVFMmMWhMsgQw+5JH6B6o4MnZ+UQNw1pp52XYFPRk= +modernc.org/ccgo/v3 v3.12.25/go.mod h1:UaLyWI26TwyIT4+ZFNjkyTbsPsY3plAEB6E7L/vZV3w= +modernc.org/ccgo/v3 v3.12.29/go.mod h1:FXVjG7YLf9FetsS2OOYcwNhcdOLGt8S9bQ48+OP75cE= +modernc.org/ccgo/v3 v3.12.36/go.mod h1:uP3/Fiezp/Ga8onfvMLpREq+KUjUmYMxXPO8tETHtA8= +modernc.org/ccgo/v3 v3.12.38/go.mod h1:93O0G7baRST1vNj4wnZ49b1kLxt0xCW5Hsa2qRaZPqc= +modernc.org/ccgo/v3 v3.12.43/go.mod h1:k+DqGXd3o7W+inNujK15S5ZYuPoWYLpF5PYougCmthU= +modernc.org/ccgo/v3 v3.12.46/go.mod h1:UZe6EvMSqOxaJ4sznY7b23/k13R8XNlyWsO5bAmSgOE= +modernc.org/ccgo/v3 v3.12.47/go.mod h1:m8d6p0zNps187fhBwzY/ii6gxfjob1VxWb919Nk1HUk= +modernc.org/ccgo/v3 v3.12.50/go.mod h1:bu9YIwtg+HXQxBhsRDE+cJjQRuINuT9PUK4orOco/JI= +modernc.org/ccgo/v3 v3.12.51/go.mod h1:gaIIlx4YpmGO2bLye04/yeblmvWEmE4BBBls4aJXFiE= +modernc.org/ccgo/v3 v3.12.53/go.mod h1:8xWGGTFkdFEWBEsUmi+DBjwu/WLy3SSOrqEmKUjMeEg= +modernc.org/ccgo/v3 v3.12.54/go.mod h1:yANKFTm9llTFVX1FqNKHE0aMcQb1fuPJx6p8AcUx+74= +modernc.org/ccgo/v3 v3.12.55/go.mod h1:rsXiIyJi9psOwiBkplOaHye5L4MOOaCjHg1Fxkj7IeU= +modernc.org/ccgo/v3 v3.12.56/go.mod h1:ljeFks3faDseCkr60JMpeDb2GSO3TKAmrzm7q9YOcMU= +modernc.org/ccgo/v3 v3.12.57/go.mod h1:hNSF4DNVgBl8wYHpMvPqQWDQx8luqxDnNGCMM4NFNMc= +modernc.org/ccgo/v3 v3.12.60/go.mod h1:k/Nn0zdO1xHVWjPYVshDeWKqbRWIfif5dtsIOCUVMqM= +modernc.org/ccgo/v3 v3.12.65/go.mod h1:D6hQtKxPNZiY6wDBtehSGKFKmyXn53F8nGTpH+POmS4= +modernc.org/ccgo/v3 v3.12.66/go.mod h1:jUuxlCFZTUZLMV08s7B1ekHX5+LIAurKTTaugUr/EhQ= +modernc.org/ccgo/v3 v3.12.67/go.mod h1:Bll3KwKvGROizP2Xj17GEGOTrlvB1XcVaBrC90ORO84= +modernc.org/ccgo/v3 v3.12.73/go.mod h1:hngkB+nUUqzOf3iqsM48Gf1FZhY599qzVg1iX+BT3cQ= +modernc.org/ccgo/v3 v3.12.81/go.mod h1:p2A1duHoBBg1mFtYvnhAnQyI6vL0uw5PGYLSIgF6rYY= +modernc.org/ccgo/v3 v3.12.82 h1:wudcnJyjLj1aQQCXF3IM9Gz2X6UNjw+afIghzdtn0v8= +modernc.org/ccgo/v3 v3.12.82/go.mod h1:ApbflUfa5BKadjHynCficldU1ghjen84tuM5jRynB7w= +modernc.org/ccorpus v1.11.1/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= -modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.9.8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= -modernc.org/libc v1.9.11 h1:QUxZMs48Ahg2F7SN41aERvMfGLY2HU/ADnB9DC4Yts8= modernc.org/libc v1.9.11/go.mod h1:NyF3tsA5ArIjJ83XB0JlqhjTabTCHm9aX4XMPHyQn0Q= +modernc.org/libc v1.11.0/go.mod h1:2lOfPmj7cz+g1MrPNmX65QCzVxgNq2C5o0jdLY2gAYg= +modernc.org/libc v1.11.2/go.mod h1:ioIyrl3ETkugDO3SGZ+6EOKvlP3zSOycUETe4XM4n8M= +modernc.org/libc v1.11.5/go.mod h1:k3HDCP95A6U111Q5TmG3nAyUcp3kR5YFZTeDS9v8vSU= +modernc.org/libc v1.11.6/go.mod h1:ddqmzR6p5i4jIGK1d/EiSw97LBcE3dK24QEwCFvgNgE= +modernc.org/libc v1.11.11/go.mod h1:lXEp9QOOk4qAYOtL3BmMve99S5Owz7Qyowzvg6LiZso= +modernc.org/libc v1.11.13/go.mod h1:ZYawJWlXIzXy2Pzghaf7YfM8OKacP3eZQI81PDLFdY8= +modernc.org/libc v1.11.16/go.mod h1:+DJquzYi+DMRUtWI1YNxrlQO6TcA5+dRRiq8HWBWRC8= +modernc.org/libc v1.11.19/go.mod h1:e0dgEame6mkydy19KKaVPBeEnyJB4LGNb0bBH1EtQ3I= +modernc.org/libc v1.11.24/go.mod h1:FOSzE0UwookyT1TtCJrRkvsOrX2k38HoInhw+cSCUGk= +modernc.org/libc v1.11.26/go.mod h1:SFjnYi9OSd2W7f4ct622o/PAYqk7KHv6GS8NZULIjKY= +modernc.org/libc v1.11.27/go.mod h1:zmWm6kcFXt/jpzeCgfvUNswM0qke8qVwxqZrnddlDiE= +modernc.org/libc v1.11.28/go.mod h1:Ii4V0fTFcbq3qrv3CNn+OGHAvzqMBvC7dBNyC4vHZlg= +modernc.org/libc v1.11.31/go.mod h1:FpBncUkEAtopRNJj8aRo29qUiyx5AvAlAxzlx9GNaVM= +modernc.org/libc v1.11.34/go.mod h1:+Tzc4hnb1iaX/SKAutJmfzES6awxfU1BPvrrJO0pYLg= +modernc.org/libc v1.11.37/go.mod h1:dCQebOwoO1046yTrfUE5nX1f3YpGZQKNcITUYWlrAWo= +modernc.org/libc v1.11.39/go.mod h1:mV8lJMo2S5A31uD0k1cMu7vrJbSA3J3waQJxpV4iqx8= +modernc.org/libc v1.11.42/go.mod h1:yzrLDU+sSjLE+D4bIhS7q1L5UwXDOw99PLSX0BlZvSQ= +modernc.org/libc v1.11.44/go.mod h1:KFq33jsma7F5WXiYelU8quMJasCCTnHK0mkri4yPHgA= +modernc.org/libc v1.11.45/go.mod h1:Y192orvfVQQYFzCNsn+Xt0Hxt4DiO4USpLNXBlXg/tM= +modernc.org/libc v1.11.47/go.mod h1:tPkE4PzCTW27E6AIKIR5IwHAQKCAtudEIeAV1/SiyBg= +modernc.org/libc v1.11.49/go.mod h1:9JrJuK5WTtoTWIFQ7QjX2Mb/bagYdZdscI3xrvHbXjE= +modernc.org/libc v1.11.51/go.mod h1:R9I8u9TS+meaWLdbfQhq2kFknTW0O3aw3kEMqDDxMaM= +modernc.org/libc v1.11.53/go.mod h1:5ip5vWYPAoMulkQ5XlSJTy12Sz5U6blOQiYasilVPsU= +modernc.org/libc v1.11.54/go.mod h1:S/FVnskbzVUrjfBqlGFIPA5m7UwB3n9fojHhCNfSsnw= +modernc.org/libc v1.11.55/go.mod h1:j2A5YBRm6HjNkoSs/fzZrSxCuwWqcMYTDPLNx0URn3M= +modernc.org/libc v1.11.56/go.mod h1:pakHkg5JdMLt2OgRadpPOTnyRXm/uzu+Yyg/LSLdi18= +modernc.org/libc v1.11.58/go.mod h1:ns94Rxv0OWyoQrDqMFfWwka2BcaF6/61CqJRK9LP7S8= +modernc.org/libc v1.11.70/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= +modernc.org/libc v1.11.71/go.mod h1:DUOmMYe+IvKi9n6Mycyx3DbjfzSKrdr/0Vgt3j7P5gw= +modernc.org/libc v1.11.75/go.mod h1:dGRVugT6edz361wmD9gk6ax1AbDSe0x5vji0dGJiPT0= +modernc.org/libc v1.11.82/go.mod h1:NF+Ek1BOl2jeC7lw3a7Jj5PWyHPwWD4aq3wVKxqV1fI= +modernc.org/libc v1.11.86/go.mod h1:ePuYgoQLmvxdNT06RpGnaDKJmDNEkV7ZPKI2jnsvZoE= +modernc.org/libc v1.11.87 h1:PzIzOqtlzMDDcCzJ5cUP6h/Ku6Fa9iyflP2ccTY64aE= +modernc.org/libc v1.11.87/go.mod h1:Qvd5iXTeLhI5PS0XSyqMY99282y+3euapQFxM7jYnpY= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/mathutil v1.4.0 h1:GCjoRaBew8ECCKINQA2nYjzvufFW9YiEuuB+rQ9bn2E= modernc.org/mathutil v1.4.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= -modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM= +modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8= +modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= +modernc.org/memory v1.0.5 h1:XRch8trV7GgvTec2i7jc33YlUI0RKVDBvZ5eZ5m8y14= +modernc.org/memory v1.0.5/go.mod h1:B7OYswTRnfGg+4tDH1t1OeUNnsy2viGTdME4tzd+IjM= modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= -modernc.org/sqlite v1.11.2 h1:ShWQpeD3ag/bmx6TqidBlIWonWmQaSQKls3aenCbt+w= -modernc.org/sqlite v1.11.2/go.mod h1:+mhs/P1ONd+6G7hcAs6irwDi/bjTQ7nLW6LHRBsEa3A= +modernc.org/sqlite v1.14.2 h1:ohsW2+e+Qe2To1W6GNezzKGwjXwSax6R+CrhRxVaFbE= +modernc.org/sqlite v1.14.2/go.mod h1:yqfn85u8wVOE6ub5UT8VI9JjhrwBUUCNyTACN0h6Sx8= modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs= modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw= -modernc.org/tcl v1.5.5/go.mod h1:ADkaTUuwukkrlhqwERyq0SM8OvyXo7+TjFz7yAF56EI= +modernc.org/tcl v1.8.13/go.mod h1:V+q/Ef0IJaNUSECieLU4o+8IScapxnMyFV6i/7uQlAY= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= +modernc.org/z v1.2.19/go.mod h1:+ZpP0pc4zz97eukOzW3xagV/lS82IpPN9NGG5pNF9vY= mvdan.cc/xurls/v2 v2.4.0 h1:tzxjVAj+wSBmDcF6zBB7/myTy3gX9xvi8Tyr28AuQgc= mvdan.cc/xurls/v2 v2.4.0/go.mod h1:+GEjq9uNjqs8LQfM9nVnM8rff0OQ5Iash5rzX+N1CSg= pack.ag/amqp v0.11.2/go.mod h1:4/cbmt4EJXSKlG6LCfWHoqmN0uFdy5i/+YFz+fTfhV4= @@ -2358,8 +2415,8 @@ sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU= 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.9/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/builder v0.3.10 h1:Rvkncad3Lo9YIVqCbgIf6QnpR/HcW3IEr0AANNpuyMQ= -xorm.io/builder v0.3.10/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE= -xorm.io/xorm v1.2.5 h1:tqN7OhN8P9xi52qBb76I8m5maAJMz/SSbgK2RGPCPbo= -xorm.io/xorm v1.2.5/go.mod h1:fTG8tSjk6O1BYxwuohZUK+S1glnRycsCF05L1qQyEU0= +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.1 h1:z5egKrDoOLqZFhMjcGF4FBHiTmE5/feQoHclfhNidfM= +xorm.io/xorm v1.3.1/go.mod h1:9NbjqdnjX6eyjRRhh01GHm64r6N9shTb/8Ak3YRt8Nw= diff --git a/integrations/api_admin_test.go b/integrations/api_admin_test.go index b935d3eac5..62c7d7eaf7 100644 --- a/integrations/api_admin_test.go +++ b/integrations/api_admin_test.go @@ -37,7 +37,6 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) { unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{ ID: newPublicKey.ID, Name: newPublicKey.Title, - Content: newPublicKey.Key, Fingerprint: newPublicKey.Fingerprint, OwnerID: keyOwner.ID, }) diff --git a/integrations/api_httpsig_test.go b/integrations/api_httpsig_test.go new file mode 100644 index 0000000000..7197e9afb9 --- /dev/null +++ b/integrations/api_httpsig_test.go @@ -0,0 +1,137 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "encoding/base64" + "fmt" + "net/http" + "net/url" + "testing" + + api "code.gitea.io/gitea/modules/structs" + + "github.com/go-fed/httpsig" + "golang.org/x/crypto/ssh" +) + +const ( + httpsigPrivateKey = `-----BEGIN OPENSSH PRIVATE KEY----- +b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn +NhAAAAAwEAAQAAAQEAqjmQeb5Eb1xV7qbNf9ErQ0XRvKZWzUsLFhJzZz+Ab7q8WtPs91vQ +fBiypw4i8OTG6WzDcgZaV8Ndxn7iHnIstdA1k89MVG4stydymmwmk9+mrCMNsu5OmdIy9F +AZ61RDcKuf5VG2WKkmeK0VO+OMJIYfE1C6czNeJ6UAmcIOmhGxvjMI83XUO9n0ftwTwayp ++XU5prvKx/fTvlPjbraPNU4OzwPjVLqXBzpoXYhBquPaZYFRVyvfFZLObYsmy+BrsxcloM +l+9w4P0ATJ9njB7dRDL+RrN4uhhYSihqOK4w4vaiOj1+aA0eC0zXunEfLXfGIVQ/FhWcCy +5f72mMiKnQAAA9AxSmzFMUpsxQAAAAdzc2gtcnNhAAABAQCqOZB5vkRvXFXups1/0StDRd +G8plbNSwsWEnNnP4Bvurxa0+z3W9B8GLKnDiLw5MbpbMNyBlpXw13GfuIeciy10DWTz0xU +biy3J3KabCaT36asIw2y7k6Z0jL0UBnrVENwq5/lUbZYqSZ4rRU744wkhh8TULpzM14npQ +CZwg6aEbG+MwjzddQ72fR+3BPBrKn5dTmmu8rH99O+U+Nuto81Tg7PA+NUupcHOmhdiEGq +49plgVFXK98Vks5tiybL4GuzFyWgyX73Dg/QBMn2eMHt1EMv5Gs3i6GFhKKGo4rjDi9qI6 +PX5oDR4LTNe6cR8td8YhVD8WFZwLLl/vaYyIqdAAAAAwEAAQAAAQBz+nyBNi2SYir6SxPA +flcnoq5gBkUl4ndPNosCUbXEakpi5/mQHzJRGtK+F1efIYCVEdGoIsPy/90onNKbQ9dKmO +2oI5kx/U7iCzJ+HCm8nqkEp21x+AP9scWdx+Wg/OxmG8j5iU7f4X+gwOyyvTqCuA78Lgia +7Oi9wiJCoIEqXr6dRYGJzfASwKA2dj995HzATexleLSD5fQCmZTF+Vh5OQ5WmE+c53JdZS +T3Plie/P/smgSWBtf1fWr6JL2+EBsqQsIK1Jo7r/7rxsz+ILoVfnneNQY4QSa9W+t6ZAI+ +caSA0Guv7vC92ewjlMVlwKa3XaEjMJb5sFlg1r6TYMwBAAAAgQDQwXvgSXNaSHIeH53/Ab +t4BlNibtxK8vY8CZFloAKXkjrivKSlDAmQCM0twXOweX2ScPjE+XlSMV4AUsv/J6XHGHci +W3+PGIBfc/fQRBpiyhzkoXYDVrlkSKHffCnAqTUQlYkhr0s7NkZpEeqPE0doAUs4dK3Iqb +zdtz8e5BPXZwAAAIEA4U/JskIu5Oge8Is2OLOhlol0EJGw5JGodpFyhbMC+QYK9nYqy7wI +a6mZ2EfOjjwIZD/+wYyulw6cRve4zXwgzUEXLIKp8/H3sYvJK2UMeP7y68sQFqGxbm6Rnh +tyBBSaJQnOXVOFf9gqZGCyO/J0Illg3AXTuC8KS/cxwasC38EAAACBAMFo/6XQoR6E3ynj +VBaz2SilWqQBixUyvcNz8LY73IIDCecoccRMFSEKhWtvlJijxvFbF9M8g9oKAVPuub4V5r +CGmwVPEd5yt4C2iyV0PhLp1PA2/i42FpCSnHaz/EXSz6ncTZcOMMuDqUbgUUpQg4VSUDl9 +fhTNAzWwZoQ91aHdAAAAFHUwMDIyMTQ2QGljdHMtcC1ueC03AQIDBAUG +-----END OPENSSH PRIVATE KEY-----` + httpsigCertificate = `ssh-rsa-cert-v01@openssh.com AAAAHHNzaC1yc2EtY2VydC12MDFAb3BlbnNzaC5jb20AAAAgiR7SU8gmZLhopx4Y03nOXVuAb+4fyMcJYjMGcE1Z2oEAAAADAQABAAABAQCqOZB5vkRvXFXups1/0StDRdG8plbNSwsWEnNnP4Bvurxa0+z3W9B8GLKnDiLw5MbpbMNyBlpXw13GfuIeciy10DWTz0xUbiy3J3KabCaT36asIw2y7k6Z0jL0UBnrVENwq5/lUbZYqSZ4rRU744wkhh8TULpzM14npQCZwg6aEbG+MwjzddQ72fR+3BPBrKn5dTmmu8rH99O+U+Nuto81Tg7PA+NUupcHOmhdiEGq49plgVFXK98Vks5tiybL4GuzFyWgyX73Dg/QBMn2eMHt1EMv5Gs3i6GFhKKGo4rjDi9qI6PX5oDR4LTNe6cR8td8YhVD8WFZwLLl/vaYyIqdAAAAAAAAAAEAAAABAAAABXVzZXIxAAAACQAAAAV1c2VyMQAAAABimoIOAAAAAMCWkRMAAAAAAAAAggAAABVwZXJtaXQtWDExLWZvcndhcmRpbmcAAAAAAAAAF3Blcm1pdC1hZ2VudC1mb3J3YXJkaW5nAAAAAAAAABZwZXJtaXQtcG9ydC1mb3J3YXJkaW5nAAAAAAAAAApwZXJtaXQtcHR5AAAAAAAAAA5wZXJtaXQtdXNlci1yYwAAAAAAAAAAAAABlwAAAAdzc2gtcnNhAAAAAwEAAQAAAYEAm+AwtXTBZyeqV1qOxjMU3Ibc5iR2M3zerGfRQDxUeIozC3xpIvqJbzjDuRapdf8hpxn2xC0GtUusuLIUr4/+Svs1BUnJhF2H9xnK/O0aopS5MpNekUvnBzQdbvO8Ux2xE2mt58giXhkEaXeCEODSqG++OZsA2e40AR/AGRJ4OdDofMvH4vLJAQQc2mKdYpYL8xu+NC+7nsenx1etpsqtEl3gmvqCVI6t9uhVPMvlbGt9h/AN3u7ToF2T3bdk1TZbcdkvR9ljvETIuy32ksAETX8tc7vm30edK+nn/GMeWCgjM+MFm9Uh1NRkvNNJozo5SJy0DkWETTJUsEdfry5VQ3IjqhWqQ0m4/mDlTmsEdEdWqpUiqWZLd9w7jgT8fanuglZyIu2fj8fyqjPjiws5S2P0Uvi28UKQ1nH01UYj/kuakU3BNzN1IqDf3tARP9fjKV/dCBqb1ZAOtyC2GyhGuGzNwEi+woUwq+sTeV0/hqVSb3hSitXHzcfRMRyOK82BAAABlAAAAAxyc2Etc2hhMi01MTIAAAGAMBfgZFvz4BdxriGKYd6eRhMo6hf+I8S9uzNRsflJXHuA+HR9ExIm/Q9JjKmfThQzNyGGBOBILaDU205SAJuG+kk3SieSQDd75ZQd8YmNlCc+516AriOsTiyVCupnf3I2euTjMZqEZbJcBbkBljppTOWQVN7xxE8QakDfGhg0+RjJE9wYOTmkKpDBfII5Nw8V5DoOD7kNEpXYqHdy/8lVxpqUYNIP1J0dNP4f6qBcZcM1PDA12q8zwIGqSNNjf2UXY/Nr8nv9CnK4fB8NDOPKTBa4cm48BGbvM/X0l6dYKswuZ9Np8lw+y6+GxTgznGCrkzMmuEV4FzSq4xHp41H2L2MTwUkwYaeyG1VP6aWkvn6zPkSxaaJDfQX7CAFe17IhIGXR0UPLjKjh35nDLzMWb/W6/W1lK9YkZNHXSf7Z9m9MUAZN7yQgOggGsuYEW4imZxvZizMd+fdDu9mbhr0FDis89I7MSJDnyYRE9FXS7p3QpppBwGcss/9yV3JV3Bjc` +) + +func TestHTTPSigPubKey(t *testing.T) { + // Add our public key to user1 + defer prepareTestEnv(t)() + session := loginUser(t, "user1") + token := url.QueryEscape(getTokenForLoggedInUser(t, session)) + keysURL := fmt.Sprintf("/api/v1/user/keys?token=%s", token) + keyType := "ssh-rsa" + keyContent := "AAAAB3NzaC1yc2EAAAADAQABAAABAQCqOZB5vkRvXFXups1/0StDRdG8plbNSwsWEnNnP4Bvurxa0+z3W9B8GLKnDiLw5MbpbMNyBlpXw13GfuIeciy10DWTz0xUbiy3J3KabCaT36asIw2y7k6Z0jL0UBnrVENwq5/lUbZYqSZ4rRU744wkhh8TULpzM14npQCZwg6aEbG+MwjzddQ72fR+3BPBrKn5dTmmu8rH99O+U+Nuto81Tg7PA+NUupcHOmhdiEGq49plgVFXK98Vks5tiybL4GuzFyWgyX73Dg/QBMn2eMHt1EMv5Gs3i6GFhKKGo4rjDi9qI6PX5oDR4LTNe6cR8td8YhVD8WFZwLLl/vaYyIqd" + rawKeyBody := api.CreateKeyOption{ + Title: "test-key", + Key: keyType + " " + keyContent, + } + req := NewRequestWithJSON(t, "POST", keysURL, rawKeyBody) + session.MakeRequest(t, req, http.StatusCreated) + + // parse our private key and create the httpsig request + sshSigner, _ := ssh.ParsePrivateKey([]byte(httpsigPrivateKey)) + keyID := ssh.FingerprintSHA256(sshSigner.PublicKey()) + + // create the request + req = NewRequest(t, "GET", "/api/v1/admin/users") + + signer, _, err := httpsig.NewSSHSigner(sshSigner, httpsig.DigestSha512, []string{httpsig.RequestTarget, "(created)", "(expires)"}, httpsig.Signature, 10) + if err != nil { + t.Fatal(err) + } + + // sign the request + err = signer.SignRequest(keyID, req, nil) + if err != nil { + t.Fatal(err) + } + + // make the request + MakeRequest(t, req, http.StatusOK) +} + +func TestHTTPSigCert(t *testing.T) { + // Add our public key to user1 + defer prepareTestEnv(t)() + session := loginUser(t, "user1") + + csrf := GetCSRF(t, session, "/user/settings/keys") + req := NewRequestWithValues(t, "POST", "/user/settings/keys", map[string]string{ + "_csrf": csrf, + "content": "user1", + "title": "principal", + "type": "principal", + }) + + session.MakeRequest(t, req, http.StatusSeeOther) + pkcert, _, _, _, err := ssh.ParseAuthorizedKey([]byte(httpsigCertificate)) + if err != nil { + t.Fatal(err) + } + + // parse our private key and create the httpsig request + sshSigner, _ := ssh.ParsePrivateKey([]byte(httpsigPrivateKey)) + keyID := "gitea" + + // create our certificate signer using the ssh signer and our certificate + certSigner, err := ssh.NewCertSigner(pkcert.(*ssh.Certificate), sshSigner) + if err != nil { + t.Fatal(err) + } + + // create the request + req = NewRequest(t, "GET", "/api/v1/admin/users") + + // add our cert to the request + certString := base64.RawStdEncoding.EncodeToString(pkcert.(*ssh.Certificate).Marshal()) + req.Header.Add("x-ssh-certificate", certString) + + signer, _, err := httpsig.NewSSHSigner(certSigner, httpsig.DigestSha512, []string{httpsig.RequestTarget, "(created)", "(expires)", "x-ssh-certificate"}, httpsig.Signature, 10) + if err != nil { + t.Fatal(err) + } + + // sign the request + err = signer.SignRequest(keyID, req, nil) + if err != nil { + t.Fatal(err) + } + + // make the request + MakeRequest(t, req, http.StatusOK) +} diff --git a/integrations/api_issue_test.go b/integrations/api_issue_test.go index 5ed5a0ad99..cc7d8d6bd5 100644 --- a/integrations/api_issue_test.go +++ b/integrations/api_issue_test.go @@ -209,7 +209,7 @@ func TestAPISearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count")) + assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count")) assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit query.Add("limit", "20") @@ -217,14 +217,14 @@ func TestAPISearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 15) + assert.Len(t, apiIssues, 17) query = url.Values{"assigned": {"true"}, "state": {"all"}, "token": {token}} link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 1) + assert.Len(t, apiIssues, 2) query = url.Values{"milestones": {"milestone1"}, "state": {"all"}, "token": {token}} link.RawQuery = query.Encode() @@ -252,7 +252,7 @@ func TestAPISearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 3) + assert.Len(t, apiIssues, 5) query = url.Values{"owner": {"user3"}, "team": {"team1"}, "token": {token}} // organization + team link.RawQuery = query.Encode() diff --git a/integrations/api_issue_tracked_time_test.go b/integrations/api_issue_tracked_time_test.go index b6f7091013..7c69d4eb9e 100644 --- a/integrations/api_issue_tracked_time_test.go +++ b/integrations/api_issue_tracked_time_test.go @@ -33,7 +33,7 @@ func TestAPIGetTrackedTimes(t *testing.T) { resp := session.MakeRequest(t, req, http.StatusOK) var apiTimes api.TrackedTimeList DecodeJSON(t, resp, &apiTimes) - expect, err := models.GetTrackedTimes(&models.FindTrackedTimesOptions{IssueID: issue2.ID}) + expect, err := models.GetTrackedTimes(db.DefaultContext, &models.FindTrackedTimesOptions{IssueID: issue2.ID}) assert.NoError(t, err) assert.Len(t, apiTimes, 3) @@ -83,7 +83,7 @@ func TestAPIDeleteTrackedTime(t *testing.T) { session.MakeRequest(t, req, http.StatusNotFound) // Reset time of user 2 on issue 2 - trackedSeconds, err := models.GetTrackedSeconds(models.FindTrackedTimesOptions{IssueID: 2, UserID: 2}) + trackedSeconds, err := models.GetTrackedSeconds(db.DefaultContext, models.FindTrackedTimesOptions{IssueID: 2, UserID: 2}) assert.NoError(t, err) assert.Equal(t, int64(3661), trackedSeconds) @@ -91,7 +91,7 @@ func TestAPIDeleteTrackedTime(t *testing.T) { session.MakeRequest(t, req, http.StatusNoContent) session.MakeRequest(t, req, http.StatusNotFound) - trackedSeconds, err = models.GetTrackedSeconds(models.FindTrackedTimesOptions{IssueID: 2, UserID: 2}) + trackedSeconds, err = models.GetTrackedSeconds(db.DefaultContext, models.FindTrackedTimesOptions{IssueID: 2, UserID: 2}) assert.NoError(t, err) assert.Equal(t, int64(0), trackedSeconds) } diff --git a/integrations/api_keys_test.go b/integrations/api_keys_test.go index b1f455d932..198da29b8a 100644 --- a/integrations/api_keys_test.go +++ b/integrations/api_keys_test.go @@ -116,12 +116,14 @@ func TestCreateUserKey(t *testing.T) { var newPublicKey api.PublicKey DecodeJSON(t, resp, &newPublicKey) + fingerprint, err := asymkey_model.CalcFingerprint(rawKeyBody.Key) + assert.NoError(t, err) unittest.AssertExistsAndLoadBean(t, &asymkey_model.PublicKey{ - ID: newPublicKey.ID, - OwnerID: user.ID, - Name: rawKeyBody.Title, - Content: rawKeyBody.Key, - Mode: perm.AccessModeWrite, + ID: newPublicKey.ID, + OwnerID: user.ID, + Name: rawKeyBody.Title, + Fingerprint: fingerprint, + Mode: perm.AccessModeWrite, }) // Search by fingerprint diff --git a/integrations/api_nodeinfo_test.go b/integrations/api_nodeinfo_test.go index 822dbf3f0e..c2fcd2fea5 100644 --- a/integrations/api_nodeinfo_test.go +++ b/integrations/api_nodeinfo_test.go @@ -29,7 +29,7 @@ func TestNodeinfo(t *testing.T) { assert.True(t, nodeinfo.OpenRegistrations) assert.Equal(t, "gitea", nodeinfo.Software.Name) assert.Equal(t, 23, nodeinfo.Usage.Users.Total) - assert.Equal(t, 15, nodeinfo.Usage.LocalPosts) + assert.Equal(t, 17, nodeinfo.Usage.LocalPosts) assert.Equal(t, 2, nodeinfo.Usage.LocalComments) }) } diff --git a/integrations/api_packages_container_test.go b/integrations/api_packages_container_test.go index a8f49423e2..2b5be9dd4c 100644 --- a/integrations/api_packages_container_test.go +++ b/integrations/api_packages_container_test.go @@ -66,10 +66,7 @@ func TestPackageContainer(t *testing.T) { Token string `json:"token"` } - authenticate := []string{ - `Bearer realm="` + setting.AppURL + `v2/token"`, - `Basic`, - } + authenticate := []string{`Bearer realm="` + setting.AppURL + `v2/token"`} t.Run("Anonymous", func(t *testing.T) { defer PrintCurrentTest(t)() diff --git a/integrations/api_releases_test.go b/integrations/api_releases_test.go index ebb76cc163..74639e9007 100644 --- a/integrations/api_releases_test.go +++ b/integrations/api_releases_test.go @@ -84,12 +84,13 @@ func createNewReleaseUsingAPI(t *testing.T, session *TestSession, token string, var newRelease api.Release DecodeJSON(t, resp, &newRelease) - unittest.AssertExistsAndLoadBean(t, &models.Release{ + rel := &models.Release{ ID: newRelease.ID, TagName: newRelease.TagName, Title: newRelease.Title, - Note: newRelease.Note, - }) + } + unittest.AssertExistsAndLoadBean(t, rel) + assert.EqualValues(t, newRelease.Note, rel.Note) return &newRelease } @@ -137,12 +138,13 @@ func TestAPICreateAndUpdateRelease(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &newRelease) - unittest.AssertExistsAndLoadBean(t, &models.Release{ + rel := &models.Release{ ID: newRelease.ID, TagName: newRelease.TagName, Title: newRelease.Title, - Note: newRelease.Note, - }) + } + unittest.AssertExistsAndLoadBean(t, rel) + assert.EqualValues(t, rel.Note, newRelease.Note) } func TestAPICreateReleaseToDefaultBranch(t *testing.T) { diff --git a/integrations/api_repo_file_get_test.go b/integrations/api_repo_file_get_test.go new file mode 100644 index 0000000000..8d1c4c4bcf --- /dev/null +++ b/integrations/api_repo_file_get_test.go @@ -0,0 +1,56 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package integrations + +import ( + "net/http" + "net/url" + "os" + "testing" + + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + + "github.com/stretchr/testify/assert" +) + +func TestAPIGetRawFileOrLFS(t *testing.T) { + defer prepareTestEnv(t)() + + // Test with raw file + req := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/README.md") + resp := MakeRequest(t, req, http.StatusOK) + assert.Equal(t, "# repo1\n\nDescription for repo1", resp.Body.String()) + + // Test with LFS + onGiteaRun(t, func(t *testing.T, u *url.URL) { + httpContext := NewAPITestContext(t, "user2", "repo-lfs-test") + doAPICreateRepository(httpContext, false, func(t *testing.T, repository api.Repository) { + u.Path = httpContext.GitPath() + dstPath, err := os.MkdirTemp("", httpContext.Reponame) + assert.NoError(t, err) + defer util.RemoveAll(dstPath) + + u.Path = httpContext.GitPath() + u.User = url.UserPassword("user2", userPassword) + + t.Run("Clone", doGitClone(dstPath, u)) + + dstPath2, err := os.MkdirTemp("", httpContext.Reponame) + assert.NoError(t, err) + defer util.RemoveAll(dstPath2) + + t.Run("Partial Clone", doPartialGitClone(dstPath2, u)) + + lfs, _ := lfsCommitAndPushTest(t, dstPath) + + reqLFS := NewRequest(t, "GET", "/api/v1/repos/user2/repo1/media/"+lfs) + respLFS := MakeRequestNilResponseRecorder(t, reqLFS, http.StatusOK) + assert.Equal(t, littleSize, respLFS.Length) + + doAPIDeleteRepository(httpContext) + }) + }) +} diff --git a/integrations/api_repo_test.go b/integrations/api_repo_test.go index b585ad15e3..57fe65f4bf 100644 --- a/integrations/api_repo_test.go +++ b/integrations/api_repo_test.go @@ -12,6 +12,8 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -107,6 +109,11 @@ func TestAPISearchRepo(t *testing.T) { user2: {count: 7, repoName: "big_test_"}, }, }, + { + name: "RepositoriesByName", requestURL: fmt.Sprintf("/api/v1/repos/search?q=%s&private=false", "user2/big_test_"), expectedResults: expectedResults{ + user2: {count: 2, repoName: "big_test_"}, + }, + }, { name: "RepositoriesAccessibleAndRelatedToUser", requestURL: fmt.Sprintf("/api/v1/repos/search?uid=%d", user.ID), expectedResults: expectedResults{ nil: {count: 5}, @@ -205,7 +212,7 @@ func TestAPISearchRepo(t *testing.T) { assert.Len(t, repoNames, expected.count) for _, repo := range body.Data { r := getRepo(t, repo.ID) - hasAccess, err := models.HasAccess(userID, r) + hasAccess, err := access_model.HasAccess(db.DefaultContext, userID, r) assert.NoError(t, err, "Error when checking if User: %d has access to %s: %v", userID, repo.FullName, err) assert.True(t, hasAccess, "User: %d does not have access to %s", userID, repo.FullName) @@ -386,7 +393,7 @@ func testAPIRepoMigrateConflict(t *testing.T, u *url.URL) { defer util.RemoveAll(dstPath) t.Run("CreateRepo", doAPICreateRepository(httpContext, false)) - user, err := user_model.GetUserByName(httpContext.Username) + user, err := user_model.GetUserByName(db.DefaultContext, httpContext.Username) assert.NoError(t, err) userID := user.ID diff --git a/integrations/api_team_test.go b/integrations/api_team_test.go index 412fd4c73d..d571342c3d 100644 --- a/integrations/api_team_test.go +++ b/integrations/api_team_test.go @@ -69,7 +69,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusCreated) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, + checkTeamResponse(t, "CreateTeam1", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, teamToCreate.Permission, teamToCreate.Units, nil) checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, teamToCreate.Permission, teamToCreate.Units, nil) @@ -90,7 +90,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories, + checkTeamResponse(t, "EditTeam1", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories, teamToEdit.Permission, unit.AllUnitKeyNames(), nil) checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories, teamToEdit.Permission, unit.AllUnitKeyNames(), nil) @@ -102,7 +102,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, + checkTeamResponse(t, "EditTeam1_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, teamToEdit.Permission, unit.AllUnitKeyNames(), nil) checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, teamToEdit.Permission, unit.AllUnitKeyNames(), nil) @@ -114,7 +114,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories, + checkTeamResponse(t, "ReadTeam1", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories, teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap()) // Delete team. @@ -135,7 +135,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusCreated) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, + checkTeamResponse(t, "CreateTeam2", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, "read", nil, teamToCreate.UnitsMap) checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, "read", nil, teamToCreate.UnitsMap) @@ -156,7 +156,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories, + checkTeamResponse(t, "EditTeam2", &apiTeam, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories, "read", nil, teamToEdit.UnitsMap) checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEdit.Description, *teamToEdit.IncludesAllRepositories, "read", nil, teamToEdit.UnitsMap) @@ -168,7 +168,7 @@ func TestAPITeam(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusOK) apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, + checkTeamResponse(t, "EditTeam2_DescOnly", &apiTeam, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, "read", nil, teamToEdit.UnitsMap) checkTeamBean(t, apiTeam.ID, teamToEdit.Name, *teamToEditDesc.Description, *teamToEdit.IncludesAllRepositories, "read", nil, teamToEdit.UnitsMap) @@ -180,7 +180,7 @@ func TestAPITeam(t *testing.T) { apiTeam = api.Team{} DecodeJSON(t, resp, &apiTeam) assert.NoError(t, teamRead.GetUnits()) - checkTeamResponse(t, &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories, + checkTeamResponse(t, "ReadTeam2", &apiTeam, teamRead.Name, *teamToEditDesc.Description, teamRead.IncludesAllRepositories, teamRead.AccessMode.String(), teamRead.GetUnitNames(), teamRead.GetUnitsMap()) // Delete team. @@ -189,8 +189,8 @@ func TestAPITeam(t *testing.T) { unittest.AssertNotExistsBean(t, &organization.Team{ID: teamID}) } -func checkTeamResponse(t *testing.T, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) { - t.Run(name+description, func(t *testing.T) { +func checkTeamResponse(t *testing.T, testName string, apiTeam *api.Team, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) { + t.Run(testName, func(t *testing.T) { assert.Equal(t, name, apiTeam.Name, "name") assert.Equal(t, description, apiTeam.Description, "description") assert.Equal(t, includesAllRepositories, apiTeam.IncludesAllRepositories, "includesAllRepositories") @@ -209,7 +209,9 @@ func checkTeamResponse(t *testing.T, apiTeam *api.Team, name, description string func checkTeamBean(t *testing.T, id int64, name, description string, includesAllRepositories bool, permission string, units []string, unitsMap map[string]string) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: id}).(*organization.Team) assert.NoError(t, team.GetUnits(), "GetUnits") - checkTeamResponse(t, convert.ToTeam(team), name, description, includesAllRepositories, permission, units, unitsMap) + apiTeam, err := convert.ToTeam(team) + assert.NoError(t, err) + checkTeamResponse(t, fmt.Sprintf("checkTeamBean/%s_%s", name, description), apiTeam, name, description, includesAllRepositories, permission, units, unitsMap) } type TeamSearchResults struct { diff --git a/integrations/auth_ldap_test.go b/integrations/auth_ldap_test.go index 0eee5ae0cd..296b647e6d 100644 --- a/integrations/auth_ldap_test.go +++ b/integrations/auth_ldap_test.go @@ -321,7 +321,7 @@ func TestLDAPGroupTeamSyncAddMember(t *testing.T) { addAuthSourceLDAP(t, "", "on", `{"cn=ship_crew,ou=people,dc=planetexpress,dc=com":{"org26": ["team11"]},"cn=admin_staff,ou=people,dc=planetexpress,dc=com": {"non-existent": ["non-existent"]}}`) org, err := organization.GetOrgByName("org26") assert.NoError(t, err) - team, err := organization.GetTeam(org.ID, "team11") + team, err := organization.GetTeam(db.DefaultContext, org.ID, "team11") assert.NoError(t, err) auth.SyncExternalUsers(context.Background(), true) for _, gitLDAPUser := range gitLDAPUsers { @@ -366,7 +366,7 @@ func TestLDAPGroupTeamSyncRemoveMember(t *testing.T) { addAuthSourceLDAP(t, "", "on", `{"cn=dispatch,ou=people,dc=planetexpress,dc=com": {"org26": ["team11"]}}`) org, err := organization.GetOrgByName("org26") assert.NoError(t, err) - team, err := organization.GetTeam(org.ID, "team11") + team, err := organization.GetTeam(db.DefaultContext, org.ID, "team11") assert.NoError(t, err) loginUserWithPassword(t, gitLDAPUsers[0].UserName, gitLDAPUsers[0].Password) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ diff --git a/integrations/delete_user_test.go b/integrations/delete_user_test.go index 4b67c05951..cf376f6fcc 100644 --- a/integrations/delete_user_test.go +++ b/integrations/delete_user_test.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -21,7 +22,7 @@ func assertUserDeleted(t *testing.T, userID int64) { unittest.AssertNotExistsBean(t, &user_model.Follow{UserID: userID}) unittest.AssertNotExistsBean(t, &user_model.Follow{FollowID: userID}) unittest.AssertNotExistsBean(t, &repo_model.Repository{OwnerID: userID}) - unittest.AssertNotExistsBean(t, &models.Access{UserID: userID}) + unittest.AssertNotExistsBean(t, &access_model.Access{UserID: userID}) unittest.AssertNotExistsBean(t, &organization.OrgUser{UID: userID}) unittest.AssertNotExistsBean(t, &models.IssueUser{UID: userID}) unittest.AssertNotExistsBean(t, &organization.TeamUser{UID: userID}) diff --git a/integrations/git_test.go b/integrations/git_test.go index 04cdf633bd..63afc7913b 100644 --- a/integrations/git_test.go +++ b/integrations/git_test.go @@ -18,6 +18,7 @@ import ( "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" "code.gitea.io/gitea/models/unittest" @@ -438,7 +439,7 @@ func doProtectBranch(ctx APITestContext, branch, userToWhitelist, unprotectedFil }) ctx.Session.MakeRequest(t, req, http.StatusSeeOther) } else { - user, err := user_model.GetUserByName(userToWhitelist) + user, err := user_model.GetUserByName(db.DefaultContext, userToWhitelist) assert.NoError(t, err) // Change branch to protected req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings/branches/%s", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame), url.PathEscape(branch)), map[string]string{ diff --git a/integrations/integration_test.go b/integrations/integration_test.go index 4df485a6e8..687591d5fa 100644 --- a/integrations/integration_test.go +++ b/integrations/integration_test.go @@ -193,8 +193,16 @@ func initIntegrationTest() { log.Fatal("db.Exec: %v", err) } case setting.Database.UsePostgreSQL: - db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s", - setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode)) + var db *sql.DB + var err error + if setting.Database.Host[0] == '/' { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host)) + } else { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + } + defer db.Close() if err != nil { log.Fatal("sql.Open: %v", err) @@ -216,8 +224,13 @@ func initIntegrationTest() { } db.Close() - db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", - setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + if setting.Database.Host[0] == '/' { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host)) + } else { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + } // This is a different db object; requires a different Close() defer db.Close() if err != nil { diff --git a/integrations/issue_test.go b/integrations/issue_test.go index c6b801c9a6..8e04b99d5e 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -392,7 +392,7 @@ func TestSearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count")) + assert.EqualValues(t, "17", resp.Header().Get("X-Total-Count")) assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit query.Add("limit", "20") @@ -400,14 +400,14 @@ func TestSearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 15) + assert.Len(t, apiIssues, 17) query = url.Values{"assigned": {"true"}, "state": {"all"}} link.RawQuery = query.Encode() req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 1) + assert.Len(t, apiIssues, 2) query = url.Values{"milestones": {"milestone1"}, "state": {"all"}} link.RawQuery = query.Encode() @@ -435,7 +435,7 @@ func TestSearchIssues(t *testing.T) { req = NewRequest(t, "GET", link.String()) resp = session.MakeRequest(t, req, http.StatusOK) DecodeJSON(t, resp, &apiIssues) - assert.Len(t, apiIssues, 3) + assert.Len(t, apiIssues, 5) query = url.Values{"owner": {"user3"}, "team": {"team1"}} // organization + team link.RawQuery = query.Encode() diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go index 6e55807c27..6a431504a0 100644 --- a/integrations/migration-test/migration_test.go +++ b/integrations/migration-test/migration_test.go @@ -185,9 +185,17 @@ func restoreOldDB(t *testing.T, version string) bool { db.Close() case setting.Database.UsePostgreSQL: - db, err := sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s", - setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode)) - assert.NoError(t, err) + var db *sql.DB + var err error + if setting.Database.Host[0] == '/' { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/?sslmode=%s&host=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.SSLMode, setting.Database.Host)) + assert.NoError(t, err) + } else { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/?sslmode=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.SSLMode)) + assert.NoError(t, err) + } defer db.Close() _, err = db.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", setting.Database.Name)) @@ -199,8 +207,13 @@ func restoreOldDB(t *testing.T, version string) bool { // Check if we need to setup a specific schema if len(setting.Database.Schema) != 0 { - db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", - setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + if setting.Database.Host[0] == '/' { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host)) + } else { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + } if !assert.NoError(t, err) { return false } @@ -225,8 +238,13 @@ func restoreOldDB(t *testing.T, version string) bool { db.Close() } - db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", - setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + if setting.Database.Host[0] == '/' { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host)) + } else { + db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s", + setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode)) + } assert.NoError(t, err) defer db.Close() diff --git a/integrations/mirror_pull_test.go b/integrations/mirror_pull_test.go index dd66974e04..8f74d5fe16 100644 --- a/integrations/mirror_pull_test.go +++ b/integrations/mirror_pull_test.go @@ -75,7 +75,7 @@ func TestMirrorPull(t *testing.T) { IsTag: true, }, nil, "")) - _, err = repo_model.GetMirrorByRepoID(mirror.ID) + _, err = repo_model.GetMirrorByRepoID(ctx, mirror.ID) assert.NoError(t, err) ok := mirror_service.SyncPullMirror(ctx, mirror.ID) diff --git a/integrations/mssql.ini.tmpl b/integrations/mssql.ini.tmpl index b076bb863c..da15e9ef69 100644 --- a/integrations/mssql.ini.tmpl +++ b/integrations/mssql.ini.tmpl @@ -49,6 +49,7 @@ OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-mssql/data BUILTIN_SSH_SERVER_USER = git +SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [attachment] PATH = integrations/gitea-integration-mssql/data/attachments diff --git a/integrations/mysql.ini.tmpl b/integrations/mysql.ini.tmpl index 6a0fd4ab86..4df4933642 100644 --- a/integrations/mysql.ini.tmpl +++ b/integrations/mysql.ini.tmpl @@ -51,6 +51,7 @@ OFFLINE_MODE = false LFS_START_SERVER = true LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w +SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [lfs] MINIO_BASE_PATH = lfs/ diff --git a/integrations/mysql8.ini.tmpl b/integrations/mysql8.ini.tmpl index 16f8851fe5..4b63dd51a1 100644 --- a/integrations/mysql8.ini.tmpl +++ b/integrations/mysql8.ini.tmpl @@ -49,6 +49,7 @@ OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-mysql8/data BUILTIN_SSH_SERVER_USER = git +SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [attachment] PATH = integrations/gitea-integration-mysql8/data/attachments diff --git a/integrations/org_test.go b/integrations/org_test.go index 227a1b8d40..d755385726 100644 --- a/integrations/org_test.go +++ b/integrations/org_test.go @@ -157,7 +157,7 @@ func TestOrgRestrictedUser(t *testing.T) { resp := adminSession.MakeRequest(t, req, http.StatusCreated) DecodeJSON(t, resp, &apiTeam) - checkTeamResponse(t, &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, + checkTeamResponse(t, "CreateTeam_codereader", &apiTeam, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, teamToCreate.Permission, teamToCreate.Units, nil) checkTeamBean(t, apiTeam.ID, teamToCreate.Name, teamToCreate.Description, teamToCreate.IncludesAllRepositories, teamToCreate.Permission, teamToCreate.Units, nil) diff --git a/integrations/pgsql.ini.tmpl b/integrations/pgsql.ini.tmpl index 5c4fbcc829..5b54a02c9f 100644 --- a/integrations/pgsql.ini.tmpl +++ b/integrations/pgsql.ini.tmpl @@ -50,6 +50,7 @@ OFFLINE_MODE = false LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-pgsql/data BUILTIN_SSH_SERVER_USER = git +SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [attachment] PATH = integrations/gitea-integration-pgsql/data/attachments diff --git a/integrations/pull_merge_test.go b/integrations/pull_merge_test.go index c50913383c..6c5b67caa6 100644 --- a/integrations/pull_merge_test.go +++ b/integrations/pull_merge_test.go @@ -18,6 +18,7 @@ import ( "time" "code.gitea.io/gitea/models" + "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" @@ -37,10 +38,8 @@ func testPullMerge(t *testing.T, session *TestSession, user, repo, pullnum strin req := NewRequest(t, "GET", path.Join(user, repo, "pulls", pullnum)) resp := session.MakeRequest(t, req, http.StatusOK) - // Click the little green button to create a pull htmlDoc := NewHTMLParser(t, resp.Body) - link, exists := htmlDoc.doc.Find(".ui.form." + string(mergeStyle) + "-fields > form").Attr("action") - assert.True(t, exists, "The template has changed") + link := path.Join(user, repo, "pulls", pullnum, "merge") req = NewRequestWithValues(t, "POST", link, map[string]string{ "_csrf": htmlDoc.GetCSRF(), "do": string(mergeStyle), @@ -57,7 +56,7 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str // Click the little green button to create a pull htmlDoc := NewHTMLParser(t, resp.Body) link, exists := htmlDoc.doc.Find(".timeline-item .delete-button").Attr("data-url") - assert.True(t, exists, "The template has changed") + assert.True(t, exists, "The template has changed, can not find delete button url") req = NewRequestWithValues(t, "POST", link, map[string]string{ "_csrf": htmlDoc.GetCSRF(), }) @@ -409,7 +408,7 @@ func TestConflictChecking(t *testing.T) { assert.NoError(t, err) issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "PR with conflict!"}).(*models.Issue) - conflictingPR, err := models.GetPullRequestByIssueID(issue.ID) + conflictingPR, err := models.GetPullRequestByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) // Ensure conflictedFiles is populated. diff --git a/integrations/pull_update_test.go b/integrations/pull_update_test.go index 20b4eaeb4a..f11eacf144 100644 --- a/integrations/pull_update_test.go +++ b/integrations/pull_update_test.go @@ -11,6 +11,7 @@ import ( "time" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -165,7 +166,7 @@ func createOutdatedPR(t *testing.T, actor, forkOrg *user_model.User) *models.Pul assert.NoError(t, err) issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{Title: "Test Pull -to-update-"}).(*models.Issue) - pr, err := models.GetPullRequestByIssueID(issue.ID) + pr, err := models.GetPullRequestByIssueID(db.DefaultContext, issue.ID) assert.NoError(t, err) return pr diff --git a/integrations/sqlite.ini.tmpl b/integrations/sqlite.ini.tmpl index c180148891..2da7fd65d3 100644 --- a/integrations/sqlite.ini.tmpl +++ b/integrations/sqlite.ini.tmpl @@ -46,6 +46,7 @@ LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w APP_DATA_PATH = integrations/gitea-integration-sqlite/data ENABLE_GZIP = true BUILTIN_SSH_SERVER_USER = git +SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE= [attachment] PATH = integrations/gitea-integration-sqlite/data/attachments diff --git a/integrations/testlogger.go b/integrations/testlogger.go index 70efa95cce..373ad80752 100644 --- a/integrations/testlogger.go +++ b/integrations/testlogger.go @@ -126,7 +126,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() { if log.CanColorStdout { fmt.Fprintf(os.Stdout, "+++ %s is a slow test (took %v)\n", fmt.Formatter(log.NewColoredValue(t.Name(), log.Bold, log.FgYellow)), fmt.Formatter(log.NewColoredValue(took, log.Bold, log.FgYellow))) } else { - fmt.Fprintf(os.Stdout, "+++ %s is a slow tets (took %v)\n", t.Name(), took) + fmt.Fprintf(os.Stdout, "+++ %s is a slow test (took %v)\n", t.Name(), took) } } timer := time.AfterFunc(slowFlush, func() { diff --git a/jest.config.js b/jest.config.js index 690f58d177..d24333aa35 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,11 +1,11 @@ export default { rootDir: 'web_src', setupFilesAfterEnv: ['jest-extended/all'], - testEnvironment: 'jsdom', + testEnvironment: '@happy-dom/jest-environment', testMatch: ['/**/*.test.js'], testTimeout: 20000, transform: { - '\\.svg$': 'jest-raw-loader', + '\\.svg$': '/js/testUtils/jestRawLoader.js', }, verbose: false, }; diff --git a/main.go b/main.go index 19b9dd6327..ac60f85a66 100644 --- a/main.go +++ b/main.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/setting" // register supported doc types + _ "code.gitea.io/gitea/modules/markup/console" _ "code.gitea.io/gitea/modules/markup/csv" _ "code.gitea.io/gitea/modules/markup/markdown" _ "code.gitea.io/gitea/modules/markup/orgmode" diff --git a/models/action.go b/models/action.go index 7055ce81d6..882bc59d8f 100644 --- a/models/action.go +++ b/models/action.go @@ -16,6 +16,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -221,9 +222,8 @@ func (a *Action) getCommentLink(ctx context.Context) string { if a == nil { return "#" } - e := db.GetEngine(ctx) if a.Comment == nil && a.CommentID != 0 { - a.Comment, _ = getCommentByID(e, a.CommentID) + a.Comment, _ = GetCommentByID(ctx, a.CommentID) } if a.Comment != nil { return a.Comment.HTMLURL() @@ -238,7 +238,7 @@ func (a *Action) getCommentLink(ctx context.Context) string { return "#" } - issue, err := getIssueByID(e, issueID) + issue, err := getIssueByID(ctx, issueID) if err != nil { return "#" } @@ -339,8 +339,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) { return nil, err } - e := db.GetEngine(ctx) - sess := e.Where(cond). + sess := db.GetEngine(ctx).Where(cond). Select("`action`.*"). // this line will avoid select other joined table's columns Join("INNER", "repository", "`repository`.id = `action`.repo_id") @@ -353,7 +352,7 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) { return nil, fmt.Errorf("Find: %v", err) } - if err := ActionList(actions).loadAttributes(e); err != nil { + if err := ActionList(actions).loadAttributes(ctx); err != nil { return nil, fmt.Errorf("LoadAttributes: %v", err) } @@ -394,7 +393,7 @@ func activityQueryCondition(opts GetFeedsOptions) (builder.Cond, error) { // check readable repositories by doer/actor if opts.Actor == nil || !opts.Actor.IsAdmin { - cond = cond.And(builder.In("repo_id", AccessibleRepoIDsQuery(opts.Actor))) + cond = cond.And(builder.In("repo_id", repo_model.AccessibleRepoIDsQuery(opts.Actor))) } if opts.RequestedRepo != nil { @@ -493,7 +492,7 @@ func notifyWatchers(ctx context.Context, actions ...*Action) error { if act.Repo.Owner.IsOrganization() && act.ActUserID != act.Repo.Owner.ID { act.ID = 0 act.UserID = act.Repo.Owner.ID - if _, err = e.InsertOne(act); err != nil { + if err = db.Insert(ctx, act); err != nil { return fmt.Errorf("insert new actioner: %v", err) } } @@ -503,14 +502,14 @@ 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.GetUserByIDEngine(e, watcher.UserID) + user, err := user_model.GetUserByIDCtx(ctx, watcher.UserID) if err != nil { permCode[i] = false permIssue[i] = false permPR[i] = false continue } - perm, err := GetUserRepoPermission(ctx, repo, user) + perm, err := access_model.GetUserRepoPermission(ctx, repo, user) if err != nil { permCode[i] = false permIssue[i] = false @@ -546,7 +545,7 @@ func notifyWatchers(ctx context.Context, actions ...*Action) error { } } - if _, err = e.InsertOne(act); err != nil { + if err = db.Insert(ctx, act); err != nil { return fmt.Errorf("insert new action: %v", err) } } diff --git a/models/action_list.go b/models/action_list.go index 5f7b17b9de..d585ef0fc2 100644 --- a/models/action_list.go +++ b/models/action_list.go @@ -5,6 +5,7 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" @@ -26,14 +27,14 @@ func (actions ActionList) getUserIDs() []int64 { return container.KeysInt64(userIDs) } -func (actions ActionList) loadUsers(e db.Engine) (map[int64]*user_model.User, error) { +func (actions ActionList) loadUsers(ctx context.Context) (map[int64]*user_model.User, error) { if len(actions) == 0 { return nil, nil } userIDs := actions.getUserIDs() userMaps := make(map[int64]*user_model.User, len(userIDs)) - err := e. + err := db.GetEngine(ctx). In("id", userIDs). Find(&userMaps) if err != nil { @@ -56,14 +57,14 @@ func (actions ActionList) getRepoIDs() []int64 { return container.KeysInt64(repoIDs) } -func (actions ActionList) loadRepositories(e db.Engine) error { +func (actions ActionList) loadRepositories(ctx context.Context) error { if len(actions) == 0 { return nil } repoIDs := actions.getRepoIDs() repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs)) - err := e.In("id", repoIDs).Find(&repoMaps) + err := db.GetEngine(ctx).In("id", repoIDs).Find(&repoMaps) if err != nil { return fmt.Errorf("find repository: %v", err) } @@ -74,7 +75,7 @@ func (actions ActionList) loadRepositories(e db.Engine) error { return nil } -func (actions ActionList) loadRepoOwner(e db.Engine, userMap map[int64]*user_model.User) (err error) { +func (actions ActionList) loadRepoOwner(ctx context.Context, userMap map[int64]*user_model.User) (err error) { if userMap == nil { userMap = make(map[int64]*user_model.User) } @@ -85,7 +86,7 @@ func (actions ActionList) loadRepoOwner(e db.Engine, userMap map[int64]*user_mod } repoOwner, ok := userMap[action.Repo.OwnerID] if !ok { - repoOwner, err = user_model.GetUserByID(action.Repo.OwnerID) + repoOwner, err = user_model.GetUserByIDCtx(ctx, action.Repo.OwnerID) if err != nil { if user_model.IsErrUserNotExist(err) { continue @@ -101,15 +102,15 @@ func (actions ActionList) loadRepoOwner(e db.Engine, userMap map[int64]*user_mod } // loadAttributes loads all attributes -func (actions ActionList) loadAttributes(e db.Engine) error { - userMap, err := actions.loadUsers(e) +func (actions ActionList) loadAttributes(ctx context.Context) error { + userMap, err := actions.loadUsers(ctx) if err != nil { return err } - if err := actions.loadRepositories(e); err != nil { + if err := actions.loadRepositories(ctx); err != nil { return err } - return actions.loadRepoOwner(e, userMap) + return actions.loadRepoOwner(ctx, userMap) } diff --git a/models/asymkey/gpg_key.go b/models/asymkey/gpg_key.go index ced6ca37a3..2b99972379 100644 --- a/models/asymkey/gpg_key.go +++ b/models/asymkey/gpg_key.go @@ -198,16 +198,16 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity, verified bool) (*GPGKey, erro } // deleteGPGKey does the actual key deletion -func deleteGPGKey(e db.Engine, keyID string) (int64, error) { +func deleteGPGKey(ctx context.Context, keyID string) (int64, error) { if keyID == "" { return 0, fmt.Errorf("empty KeyId forbidden") // Should never happen but just to be sure } // Delete imported key - n, err := e.Where("key_id=?", keyID).Delete(new(GPGKeyImport)) + n, err := db.GetEngine(ctx).Where("key_id=?", keyID).Delete(new(GPGKeyImport)) if err != nil { return n, err } - return e.Where("key_id=?", keyID).Or("primary_key_id=?", keyID).Delete(new(GPGKey)) + return db.GetEngine(ctx).Where("key_id=?", keyID).Or("primary_key_id=?", keyID).Delete(new(GPGKey)) } // DeleteGPGKey deletes GPG key information in database. @@ -231,7 +231,7 @@ func DeleteGPGKey(doer *user_model.User, id int64) (err error) { } defer committer.Close() - if _, err = deleteGPGKey(db.GetEngine(ctx), key.KeyID); err != nil { + if _, err = deleteGPGKey(ctx, key.KeyID); err != nil { return err } diff --git a/models/asymkey/gpg_key_add.go b/models/asymkey/gpg_key_add.go index 8f84bba1df..d01f2deb03 100644 --- a/models/asymkey/gpg_key_add.go +++ b/models/asymkey/gpg_key_add.go @@ -5,6 +5,7 @@ package asymkey import ( + "context" "strings" "code.gitea.io/gitea/models/db" @@ -29,21 +30,21 @@ import ( // This file contains functions relating to adding GPG Keys // addGPGKey add key, import and subkeys to database -func addGPGKey(e db.Engine, key *GPGKey, content string) (err error) { +func addGPGKey(ctx context.Context, key *GPGKey, content string) (err error) { // Add GPGKeyImport - if _, err = e.Insert(GPGKeyImport{ + if err = db.Insert(ctx, &GPGKeyImport{ KeyID: key.KeyID, Content: content, }); err != nil { return err } // Save GPG primary key. - if _, err = e.Insert(key); err != nil { + if err = db.Insert(ctx, key); err != nil { return err } // Save GPG subs key. for _, subkey := range key.SubsKey { - if err := addGPGSubKey(e, subkey); err != nil { + if err := addGPGSubKey(ctx, subkey); err != nil { return err } } @@ -51,14 +52,14 @@ func addGPGKey(e db.Engine, key *GPGKey, content string) (err error) { } // addGPGSubKey add subkeys to database -func addGPGSubKey(e db.Engine, key *GPGKey) (err error) { +func addGPGSubKey(ctx context.Context, key *GPGKey) (err error) { // Save GPG primary key. - if _, err = e.Insert(key); err != nil { + if err = db.Insert(ctx, key); err != nil { return err } // Save GPG subs key. for _, subkey := range key.SubsKey { - if err := addGPGSubKey(e, subkey); err != nil { + if err := addGPGSubKey(ctx, subkey); err != nil { return err } } @@ -158,7 +159,7 @@ func AddGPGKey(ownerID int64, content, token, signature string) ([]*GPGKey, erro return nil, err } - if err = addGPGKey(db.GetEngine(ctx), key, content); err != nil { + if err = addGPGKey(ctx, key, content); err != nil { return nil, err } keys = append(keys, key) diff --git a/models/asymkey/ssh_key.go b/models/asymkey/ssh_key.go index 74d2411dd9..107a29e985 100644 --- a/models/asymkey/ssh_key.go +++ b/models/asymkey/ssh_key.go @@ -75,16 +75,16 @@ func (key *PublicKey) AuthorizedString() string { return AuthorizedStringForKey(key) } -func addKey(e db.Engine, key *PublicKey) (err error) { +func addKey(ctx context.Context, key *PublicKey) (err error) { if len(key.Fingerprint) == 0 { - key.Fingerprint, err = calcFingerprint(key.Content) + key.Fingerprint, err = CalcFingerprint(key.Content) if err != nil { return err } } // Save SSH key. - if _, err = e.Insert(key); err != nil { + if err = db.Insert(ctx, key); err != nil { return err } @@ -95,7 +95,7 @@ func addKey(e db.Engine, key *PublicKey) (err error) { func AddPublicKey(ownerID int64, name, content string, authSourceID int64) (*PublicKey, error) { log.Trace(content) - fingerprint, err := calcFingerprint(content) + fingerprint, err := CalcFingerprint(content) if err != nil { return nil, err } @@ -105,14 +105,13 @@ func AddPublicKey(ownerID int64, name, content string, authSourceID int64) (*Pub return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) - if err := checkKeyFingerprint(sess, fingerprint); err != nil { + if err := checkKeyFingerprint(ctx, fingerprint); err != nil { return nil, err } // Key name of same user cannot be duplicated. - has, err := sess. + has, err := db.GetEngine(ctx). Where("owner_id = ? AND name = ?", ownerID, name). Get(new(PublicKey)) if err != nil { @@ -130,7 +129,7 @@ func AddPublicKey(ownerID int64, name, content string, authSourceID int64) (*Pub Type: KeyTypeUser, LoginSourceID: authSourceID, } - if err = addKey(sess, key); err != nil { + if err = addKey(ctx, key); err != nil { return nil, fmt.Errorf("addKey: %v", err) } @@ -151,29 +150,12 @@ func GetPublicKeyByID(keyID int64) (*PublicKey, error) { return key, nil } -func searchPublicKeyByContentWithEngine(e db.Engine, content string) (*PublicKey, error) { - key := new(PublicKey) - has, err := e. - Where("content like ?", content+"%"). - Get(key) - if err != nil { - return nil, err - } else if !has { - return nil, ErrKeyNotExist{} - } - return key, nil -} - // SearchPublicKeyByContent searches content as prefix (leak e-mail part) // and returns public key found. -func SearchPublicKeyByContent(content string) (*PublicKey, error) { - return searchPublicKeyByContentWithEngine(db.GetEngine(db.DefaultContext), content) -} - -func searchPublicKeyByContentExactWithEngine(e db.Engine, content string) (*PublicKey, error) { +func SearchPublicKeyByContent(ctx context.Context, content string) (*PublicKey, error) { key := new(PublicKey) - has, err := e. - Where("content = ?", content). + has, err := db.GetEngine(ctx). + Where("content like ?", content+"%"). Get(key) if err != nil { return nil, err @@ -185,8 +167,17 @@ func searchPublicKeyByContentExactWithEngine(e db.Engine, content string) (*Publ // SearchPublicKeyByContentExact searches content // and returns public key found. -func SearchPublicKeyByContentExact(content string) (*PublicKey, error) { - return searchPublicKeyByContentExactWithEngine(db.GetEngine(db.DefaultContext), content) +func SearchPublicKeyByContentExact(ctx context.Context, content string) (*PublicKey, error) { + key := new(PublicKey) + has, err := db.GetEngine(ctx). + Where("content = ?", content). + Get(key) + if err != nil { + return nil, err + } else if !has { + return nil, ErrKeyNotExist{} + } + return key, nil } // SearchPublicKey returns a list of public keys matching the provided arguments. @@ -335,12 +326,11 @@ func deleteKeysMarkedForDeletion(keys []string) (bool, error) { return false, err } defer committer.Close() - sess := db.GetEngine(ctx) // Delete keys marked for deletion var sshKeysNeedUpdate bool for _, KeyToDelete := range keys { - key, err := searchPublicKeyByContentWithEngine(sess, KeyToDelete) + key, err := SearchPublicKeyByContent(ctx, KeyToDelete) if err != nil { log.Error("SearchPublicKeyByContent: %v", err) continue diff --git a/models/asymkey/ssh_key_authorized_keys.go b/models/asymkey/ssh_key_authorized_keys.go index dd058f5d11..ce3b0248ce 100644 --- a/models/asymkey/ssh_key_authorized_keys.go +++ b/models/asymkey/ssh_key_authorized_keys.go @@ -6,6 +6,7 @@ package asymkey import ( "bufio" + "context" "fmt" "io" "os" @@ -165,7 +166,7 @@ func RewriteAllPublicKeys() error { } } - if err := RegeneratePublicKeys(t); err != nil { + if err := RegeneratePublicKeys(db.DefaultContext, t); err != nil { return err } @@ -174,12 +175,8 @@ func RewriteAllPublicKeys() error { } // RegeneratePublicKeys regenerates the authorized_keys file -func RegeneratePublicKeys(t io.StringWriter) error { - return regeneratePublicKeys(db.GetEngine(db.DefaultContext), t) -} - -func regeneratePublicKeys(e db.Engine, t io.StringWriter) error { - if err := e.Where("type != ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) { +func RegeneratePublicKeys(ctx context.Context, t io.StringWriter) error { + if err := db.GetEngine(ctx).Where("type != ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) { _, err = t.WriteString((bean.(*PublicKey)).AuthorizedString()) return err }); err != nil { diff --git a/models/asymkey/ssh_key_authorized_principals.go b/models/asymkey/ssh_key_authorized_principals.go index a8c48c50aa..4b08d0dfe7 100644 --- a/models/asymkey/ssh_key_authorized_principals.go +++ b/models/asymkey/ssh_key_authorized_principals.go @@ -6,6 +6,7 @@ package asymkey import ( "bufio" + "context" "fmt" "io" "os" @@ -42,11 +43,7 @@ const authorizedPrincipalsFile = "authorized_principals" // RewriteAllPrincipalKeys removes any authorized principal and rewrite all keys from database again. // Note: db.GetEngine(db.DefaultContext).Iterate does not get latest data after insert/delete, so we have to call this function // outside any session scope independently. -func RewriteAllPrincipalKeys() error { - return rewriteAllPrincipalKeys(db.GetEngine(db.DefaultContext)) -} - -func rewriteAllPrincipalKeys(e db.Engine) error { +func RewriteAllPrincipalKeys(ctx context.Context) error { // Don't rewrite key if internal server if setting.SSH.StartBuiltinServer || !setting.SSH.CreateAuthorizedPrincipalsFile { return nil @@ -92,7 +89,7 @@ func rewriteAllPrincipalKeys(e db.Engine) error { } } - if err := regeneratePrincipalKeys(e, t); err != nil { + if err := regeneratePrincipalKeys(ctx, t); err != nil { return err } @@ -100,13 +97,8 @@ func rewriteAllPrincipalKeys(e db.Engine) error { return util.Rename(tmpPath, fPath) } -// RegeneratePrincipalKeys regenerates the authorized_principals file -func RegeneratePrincipalKeys(t io.StringWriter) error { - return regeneratePrincipalKeys(db.GetEngine(db.DefaultContext), t) -} - -func regeneratePrincipalKeys(e db.Engine, t io.StringWriter) error { - if err := e.Where("type = ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) { +func regeneratePrincipalKeys(ctx context.Context, t io.StringWriter) error { + if err := db.GetEngine(ctx).Where("type = ?", KeyTypePrincipal).Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) { _, err = t.WriteString((bean.(*PublicKey)).AuthorizedString()) return err }); err != nil { diff --git a/models/asymkey/ssh_key_deploy.go b/models/asymkey/ssh_key_deploy.go index fe2ade43ae..fd8388e61d 100644 --- a/models/asymkey/ssh_key_deploy.go +++ b/models/asymkey/ssh_key_deploy.go @@ -67,9 +67,9 @@ func init() { db.RegisterModel(new(DeployKey)) } -func checkDeployKey(e db.Engine, keyID, repoID int64, name string) error { +func checkDeployKey(ctx context.Context, keyID, repoID int64, name string) error { // Note: We want error detail, not just true or false here. - has, err := e. + has, err := db.GetEngine(ctx). Where("key_id = ? AND repo_id = ?", keyID, repoID). Get(new(DeployKey)) if err != nil { @@ -78,7 +78,7 @@ func checkDeployKey(e db.Engine, keyID, repoID int64, name string) error { return ErrDeployKeyAlreadyExist{keyID, repoID} } - has, err = e. + has, err = db.GetEngine(ctx). Where("repo_id = ? AND name = ?", repoID, name). Get(new(DeployKey)) if err != nil { @@ -91,8 +91,8 @@ func checkDeployKey(e db.Engine, keyID, repoID int64, name string) error { } // addDeployKey adds new key-repo relation. -func addDeployKey(e db.Engine, keyID, repoID int64, name, fingerprint string, mode perm.AccessMode) (*DeployKey, error) { - if err := checkDeployKey(e, keyID, repoID, name); err != nil { +func addDeployKey(ctx context.Context, keyID, repoID int64, name, fingerprint string, mode perm.AccessMode) (*DeployKey, error) { + if err := checkDeployKey(ctx, keyID, repoID, name); err != nil { return nil, err } @@ -103,8 +103,7 @@ func addDeployKey(e db.Engine, keyID, repoID int64, name, fingerprint string, mo Fingerprint: fingerprint, Mode: mode, } - _, err := e.Insert(key) - return key, err + return key, db.Insert(ctx, key) } // HasDeployKey returns true if public key is a deploy key of given repository. @@ -117,7 +116,7 @@ func HasDeployKey(keyID, repoID int64) bool { // AddDeployKey add new deploy key to database and authorized_keys file. func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey, error) { - fingerprint, err := calcFingerprint(content) + fingerprint, err := CalcFingerprint(content) if err != nil { return nil, err } @@ -133,12 +132,10 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey } defer committer.Close() - sess := db.GetEngine(ctx) - pkey := &PublicKey{ Fingerprint: fingerprint, } - has, err := sess.Get(pkey) + has, err := db.GetByBean(ctx, pkey) if err != nil { return nil, err } @@ -153,12 +150,12 @@ func AddDeployKey(repoID int64, name, content string, readOnly bool) (*DeployKey pkey.Type = KeyTypeDeploy pkey.Content = content pkey.Name = name - if err = addKey(sess, pkey); err != nil { + if err = addKey(ctx, pkey); err != nil { return nil, fmt.Errorf("addKey: %v", err) } } - key, err := addDeployKey(sess, pkey.ID, repoID, name, pkey.Fingerprint, accessMode) + key, err := addDeployKey(ctx, pkey.ID, repoID, name, pkey.Fingerprint, accessMode) if err != nil { return nil, err } @@ -179,16 +176,12 @@ func GetDeployKeyByID(ctx context.Context, id int64) (*DeployKey, error) { } // GetDeployKeyByRepo returns deploy key by given public key ID and repository ID. -func GetDeployKeyByRepo(keyID, repoID int64) (*DeployKey, error) { - return getDeployKeyByRepo(db.GetEngine(db.DefaultContext), keyID, repoID) -} - -func getDeployKeyByRepo(e db.Engine, keyID, repoID int64) (*DeployKey, error) { +func GetDeployKeyByRepo(ctx context.Context, keyID, repoID int64) (*DeployKey, error) { key := &DeployKey{ KeyID: keyID, RepoID: repoID, } - has, err := e.Get(key) + has, err := db.GetByBean(ctx, key) if err != nil { return nil, err } else if !has { @@ -197,6 +190,13 @@ func getDeployKeyByRepo(e db.Engine, keyID, repoID int64) (*DeployKey, error) { return key, nil } +// IsDeployKeyExistByKeyID return true if there is at least one deploykey with the key id +func IsDeployKeyExistByKeyID(ctx context.Context, keyID int64) (bool, error) { + return db.GetEngine(ctx). + Where("key_id = ?", keyID). + Get(new(DeployKey)) +} + // UpdateDeployKeyCols updates deploy key information in the specified columns. func UpdateDeployKeyCols(key *DeployKey, cols ...string) error { _, err := db.GetEngine(db.DefaultContext).ID(key.ID).Cols(cols...).Update(key) diff --git a/models/asymkey/ssh_key_fingerprint.go b/models/asymkey/ssh_key_fingerprint.go index 437f283bfa..747a7e6473 100644 --- a/models/asymkey/ssh_key_fingerprint.go +++ b/models/asymkey/ssh_key_fingerprint.go @@ -5,6 +5,7 @@ package asymkey import ( + "context" "errors" "fmt" "strings" @@ -31,8 +32,8 @@ import ( // checkKeyFingerprint only checks if key fingerprint has been used as public key, // it is OK to use same key as deploy key for multiple repositories/users. -func checkKeyFingerprint(e db.Engine, fingerprint string) error { - has, err := e.Get(&PublicKey{ +func checkKeyFingerprint(ctx context.Context, fingerprint string) error { + has, err := db.GetByBean(ctx, &PublicKey{ Fingerprint: fingerprint, }) if err != nil { @@ -75,7 +76,8 @@ func calcFingerprintNative(publicKeyContent string) (string, error) { return ssh.FingerprintSHA256(pk), nil } -func calcFingerprint(publicKeyContent string) (string, error) { +// CalcFingerprint calculate public key's fingerprint +func CalcFingerprint(publicKeyContent string) (string, error) { // Call the method based on configuration var ( fnName, fp string diff --git a/models/asymkey/ssh_key_principals.go b/models/asymkey/ssh_key_principals.go index 5f18fd04d1..7a5c234f6f 100644 --- a/models/asymkey/ssh_key_principals.go +++ b/models/asymkey/ssh_key_principals.go @@ -31,10 +31,9 @@ func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*Public return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) // Principals cannot be duplicated. - has, err := sess. + has, err := db.GetEngine(ctx). Where("content = ? AND type = ?", content, KeyTypePrincipal). Get(new(PublicKey)) if err != nil { @@ -51,7 +50,7 @@ func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*Public Type: KeyTypePrincipal, LoginSourceID: authSourceID, } - if err = addPrincipalKey(sess, key); err != nil { + if err = db.Insert(ctx, key); err != nil { return nil, fmt.Errorf("addKey: %v", err) } @@ -61,16 +60,7 @@ func AddPrincipalKey(ownerID int64, content string, authSourceID int64) (*Public committer.Close() - return key, RewriteAllPrincipalKeys() -} - -func addPrincipalKey(e db.Engine, key *PublicKey) (err error) { - // Save Key representing a principal. - if _, err = e.Insert(key); err != nil { - return err - } - - return nil + return key, RewriteAllPrincipalKeys(db.DefaultContext) } // CheckPrincipalKeyString strips spaces and returns an error if the given principal contains newlines diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go index 4d44a8842a..c5c6e91120 100644 --- a/models/auth/oauth2.go +++ b/models/auth/oauth2.go @@ -5,6 +5,7 @@ package auth import ( + "context" "crypto/sha256" "encoding/base32" "encoding/base64" @@ -18,6 +19,7 @@ import ( uuid "github.com/google/uuid" "golang.org/x/crypto/bcrypt" + "xorm.io/builder" "xorm.io/xorm" ) @@ -90,13 +92,9 @@ func (app *OAuth2Application) ValidateClientSecret(secret []byte) bool { } // GetGrantByUserID returns a OAuth2Grant by its user and application ID -func (app *OAuth2Application) GetGrantByUserID(userID int64) (*OAuth2Grant, error) { - return app.getGrantByUserID(db.GetEngine(db.DefaultContext), userID) -} - -func (app *OAuth2Application) getGrantByUserID(e db.Engine, userID int64) (grant *OAuth2Grant, err error) { +func (app *OAuth2Application) GetGrantByUserID(ctx context.Context, userID int64) (grant *OAuth2Grant, err error) { grant = new(OAuth2Grant) - if has, err := e.Where("user_id = ? AND application_id = ?", userID, app.ID).Get(grant); err != nil { + if has, err := db.GetEngine(ctx).Where("user_id = ? AND application_id = ?", userID, app.ID).Get(grant); err != nil { return nil, err } else if !has { return nil, nil @@ -105,17 +103,13 @@ func (app *OAuth2Application) getGrantByUserID(e db.Engine, userID int64) (grant } // CreateGrant generates a grant for an user -func (app *OAuth2Application) CreateGrant(userID int64, scope string) (*OAuth2Grant, error) { - return app.createGrant(db.GetEngine(db.DefaultContext), userID, scope) -} - -func (app *OAuth2Application) createGrant(e db.Engine, userID int64, scope string) (*OAuth2Grant, error) { +func (app *OAuth2Application) CreateGrant(ctx context.Context, userID int64, scope string) (*OAuth2Grant, error) { grant := &OAuth2Grant{ ApplicationID: app.ID, UserID: userID, Scope: scope, } - _, err := e.Insert(grant) + err := db.Insert(ctx, grant) if err != nil { return nil, err } @@ -123,13 +117,9 @@ func (app *OAuth2Application) createGrant(e db.Engine, userID int64, scope strin } // GetOAuth2ApplicationByClientID returns the oauth2 application with the given client_id. Returns an error if not found. -func GetOAuth2ApplicationByClientID(clientID string) (app *OAuth2Application, err error) { - return getOAuth2ApplicationByClientID(db.GetEngine(db.DefaultContext), clientID) -} - -func getOAuth2ApplicationByClientID(e db.Engine, clientID string) (app *OAuth2Application, err error) { +func GetOAuth2ApplicationByClientID(ctx context.Context, clientID string) (app *OAuth2Application, err error) { app = new(OAuth2Application) - has, err := e.Where("client_id = ?", clientID).Get(app) + has, err := db.GetEngine(ctx).Where("client_id = ?", clientID).Get(app) if !has { return nil, ErrOAuthClientIDInvalid{ClientID: clientID} } @@ -137,13 +127,9 @@ func getOAuth2ApplicationByClientID(e db.Engine, clientID string) (app *OAuth2Ap } // GetOAuth2ApplicationByID returns the oauth2 application with the given id. Returns an error if not found. -func GetOAuth2ApplicationByID(id int64) (app *OAuth2Application, err error) { - return getOAuth2ApplicationByID(db.GetEngine(db.DefaultContext), id) -} - -func getOAuth2ApplicationByID(e db.Engine, id int64) (app *OAuth2Application, err error) { +func GetOAuth2ApplicationByID(ctx context.Context, id int64) (app *OAuth2Application, err error) { app = new(OAuth2Application) - has, err := e.ID(id).Get(app) + has, err := db.GetEngine(ctx).ID(id).Get(app) if err != nil { return nil, err } @@ -154,13 +140,9 @@ func getOAuth2ApplicationByID(e db.Engine, id int64) (app *OAuth2Application, er } // GetOAuth2ApplicationsByUserID returns all oauth2 applications owned by the user -func GetOAuth2ApplicationsByUserID(userID int64) (apps []*OAuth2Application, err error) { - return getOAuth2ApplicationsByUserID(db.GetEngine(db.DefaultContext), userID) -} - -func getOAuth2ApplicationsByUserID(e db.Engine, userID int64) (apps []*OAuth2Application, err error) { +func GetOAuth2ApplicationsByUserID(ctx context.Context, userID int64) (apps []*OAuth2Application, err error) { apps = make([]*OAuth2Application, 0) - err = e.Where("uid = ?", userID).Find(&apps) + err = db.GetEngine(ctx).Where("uid = ?", userID).Find(&apps) return } @@ -172,11 +154,7 @@ type CreateOAuth2ApplicationOptions struct { } // CreateOAuth2Application inserts a new oauth2 application -func CreateOAuth2Application(opts CreateOAuth2ApplicationOptions) (*OAuth2Application, error) { - return createOAuth2Application(db.GetEngine(db.DefaultContext), opts) -} - -func createOAuth2Application(e db.Engine, opts CreateOAuth2ApplicationOptions) (*OAuth2Application, error) { +func CreateOAuth2Application(ctx context.Context, opts CreateOAuth2ApplicationOptions) (*OAuth2Application, error) { clientID := uuid.New().String() app := &OAuth2Application{ UID: opts.UserID, @@ -184,7 +162,7 @@ func createOAuth2Application(e db.Engine, opts CreateOAuth2ApplicationOptions) ( ClientID: clientID, RedirectURIs: opts.RedirectURIs, } - if _, err := e.Insert(app); err != nil { + if err := db.Insert(ctx, app); err != nil { return nil, err } return app, nil @@ -205,9 +183,8 @@ func UpdateOAuth2Application(opts UpdateOAuth2ApplicationOptions) (*OAuth2Applic return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) - app, err := getOAuth2ApplicationByID(sess, opts.ID) + app, err := GetOAuth2ApplicationByID(ctx, opts.ID) if err != nil { return nil, err } @@ -218,7 +195,7 @@ func UpdateOAuth2Application(opts UpdateOAuth2ApplicationOptions) (*OAuth2Applic app.Name = opts.Name app.RedirectURIs = opts.RedirectURIs - if err = updateOAuth2Application(sess, app); err != nil { + if err = updateOAuth2Application(ctx, app); err != nil { return nil, err } app.ClientSecret = "" @@ -226,14 +203,15 @@ func UpdateOAuth2Application(opts UpdateOAuth2ApplicationOptions) (*OAuth2Applic return app, committer.Commit() } -func updateOAuth2Application(e db.Engine, app *OAuth2Application) error { - if _, err := e.ID(app.ID).Update(app); err != nil { +func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error { + if _, err := db.GetEngine(ctx).ID(app.ID).Update(app); err != nil { return err } return nil } -func deleteOAuth2Application(sess db.Engine, id, userid int64) error { +func deleteOAuth2Application(ctx context.Context, id, userid int64) error { + sess := db.GetEngine(ctx) if deleted, err := sess.Delete(&OAuth2Application{ID: id, UID: userid}); err != nil { return err } else if deleted == 0 { @@ -267,7 +245,7 @@ func DeleteOAuth2Application(id, userid int64) error { return err } defer committer.Close() - if err := deleteOAuth2Application(db.GetEngine(ctx), id, userid); err != nil { + if err := deleteOAuth2Application(ctx, id, userid); err != nil { return err } return committer.Commit() @@ -326,21 +304,13 @@ func (code *OAuth2AuthorizationCode) GenerateRedirectURI(state string) (redirect } // Invalidate deletes the auth code from the database to invalidate this code -func (code *OAuth2AuthorizationCode) Invalidate() error { - return code.invalidate(db.GetEngine(db.DefaultContext)) -} - -func (code *OAuth2AuthorizationCode) invalidate(e db.Engine) error { - _, err := e.Delete(code) +func (code *OAuth2AuthorizationCode) Invalidate(ctx context.Context) error { + _, err := db.GetEngine(ctx).ID(code.ID).NoAutoCondition().Delete(code) return err } // ValidateCodeChallenge validates the given verifier against the saved code challenge. This is part of the PKCE implementation. func (code *OAuth2AuthorizationCode) ValidateCodeChallenge(verifier string) bool { - return code.validateCodeChallenge(verifier) -} - -func (code *OAuth2AuthorizationCode) validateCodeChallenge(verifier string) bool { switch code.CodeChallengeMethod { case "S256": // base64url(SHA256(verifier)) see https://tools.ietf.org/html/rfc7636#section-4.6 @@ -358,19 +328,15 @@ func (code *OAuth2AuthorizationCode) validateCodeChallenge(verifier string) bool } // GetOAuth2AuthorizationByCode returns an authorization by its code -func GetOAuth2AuthorizationByCode(code string) (*OAuth2AuthorizationCode, error) { - return getOAuth2AuthorizationByCode(db.GetEngine(db.DefaultContext), code) -} - -func getOAuth2AuthorizationByCode(e db.Engine, code string) (auth *OAuth2AuthorizationCode, err error) { +func GetOAuth2AuthorizationByCode(ctx context.Context, code string) (auth *OAuth2AuthorizationCode, err error) { auth = new(OAuth2AuthorizationCode) - if has, err := e.Where("code = ?", code).Get(auth); err != nil { + if has, err := db.GetEngine(ctx).Where("code = ?", code).Get(auth); err != nil { return nil, err } else if !has { return nil, nil } auth.Grant = new(OAuth2Grant) - if has, err := e.ID(auth.GrantID).Get(auth.Grant); err != nil { + if has, err := db.GetEngine(ctx).ID(auth.GrantID).Get(auth.Grant); err != nil { return nil, err } else if !has { return nil, nil @@ -399,11 +365,7 @@ func (grant *OAuth2Grant) TableName() string { } // GenerateNewAuthorizationCode generates a new authorization code for a grant and saves it to the database -func (grant *OAuth2Grant) GenerateNewAuthorizationCode(redirectURI, codeChallenge, codeChallengeMethod string) (*OAuth2AuthorizationCode, error) { - return grant.generateNewAuthorizationCode(db.GetEngine(db.DefaultContext), redirectURI, codeChallenge, codeChallengeMethod) -} - -func (grant *OAuth2Grant) generateNewAuthorizationCode(e db.Engine, redirectURI, codeChallenge, codeChallengeMethod string) (code *OAuth2AuthorizationCode, err error) { +func (grant *OAuth2Grant) GenerateNewAuthorizationCode(ctx context.Context, redirectURI, codeChallenge, codeChallengeMethod string) (code *OAuth2AuthorizationCode, err error) { rBytes, err := util.CryptoRandomBytes(32) if err != nil { return &OAuth2AuthorizationCode{}, err @@ -420,23 +382,19 @@ func (grant *OAuth2Grant) generateNewAuthorizationCode(e db.Engine, redirectURI, CodeChallenge: codeChallenge, CodeChallengeMethod: codeChallengeMethod, } - if _, err := e.Insert(code); err != nil { + if err := db.Insert(ctx, code); err != nil { return nil, err } return code, nil } // IncreaseCounter increases the counter and updates the grant -func (grant *OAuth2Grant) IncreaseCounter() error { - return grant.increaseCount(db.GetEngine(db.DefaultContext)) -} - -func (grant *OAuth2Grant) increaseCount(e db.Engine) error { - _, err := e.ID(grant.ID).Incr("counter").Update(new(OAuth2Grant)) +func (grant *OAuth2Grant) IncreaseCounter(ctx context.Context) error { + _, err := db.GetEngine(ctx).ID(grant.ID).Incr("counter").Update(new(OAuth2Grant)) if err != nil { return err } - updatedGrant, err := getOAuth2GrantByID(e, grant.ID) + updatedGrant, err := GetOAuth2GrantByID(ctx, grant.ID) if err != nil { return err } @@ -455,13 +413,9 @@ func (grant *OAuth2Grant) ScopeContains(scope string) bool { } // SetNonce updates the current nonce value of a grant -func (grant *OAuth2Grant) SetNonce(nonce string) error { - return grant.setNonce(db.GetEngine(db.DefaultContext), nonce) -} - -func (grant *OAuth2Grant) setNonce(e db.Engine, nonce string) error { +func (grant *OAuth2Grant) SetNonce(ctx context.Context, nonce string) error { grant.Nonce = nonce - _, err := e.ID(grant.ID).Cols("nonce").Update(grant) + _, err := db.GetEngine(ctx).ID(grant.ID).Cols("nonce").Update(grant) if err != nil { return err } @@ -469,13 +423,9 @@ func (grant *OAuth2Grant) setNonce(e db.Engine, nonce string) error { } // GetOAuth2GrantByID returns the grant with the given ID -func GetOAuth2GrantByID(id int64) (*OAuth2Grant, error) { - return getOAuth2GrantByID(db.GetEngine(db.DefaultContext), id) -} - -func getOAuth2GrantByID(e db.Engine, id int64) (grant *OAuth2Grant, err error) { +func GetOAuth2GrantByID(ctx context.Context, id int64) (grant *OAuth2Grant, err error) { grant = new(OAuth2Grant) - if has, err := e.ID(id).Get(grant); err != nil { + if has, err := db.GetEngine(ctx).ID(id).Get(grant); err != nil { return nil, err } else if !has { return nil, nil @@ -484,18 +434,14 @@ func getOAuth2GrantByID(e db.Engine, id int64) (grant *OAuth2Grant, err error) { } // GetOAuth2GrantsByUserID lists all grants of a certain user -func GetOAuth2GrantsByUserID(uid int64) ([]*OAuth2Grant, error) { - return getOAuth2GrantsByUserID(db.GetEngine(db.DefaultContext), uid) -} - -func getOAuth2GrantsByUserID(e db.Engine, uid int64) ([]*OAuth2Grant, error) { +func GetOAuth2GrantsByUserID(ctx context.Context, uid int64) ([]*OAuth2Grant, error) { type joinedOAuth2Grant struct { Grant *OAuth2Grant `xorm:"extends"` Application *OAuth2Application `xorm:"extends"` } var results *xorm.Rows var err error - if results, err = e. + if results, err = db.GetEngine(ctx). Table("oauth2_grant"). Where("user_id = ?", uid). Join("INNER", "oauth2_application", "application_id = oauth2_application.id"). @@ -516,12 +462,8 @@ func getOAuth2GrantsByUserID(e db.Engine, uid int64) ([]*OAuth2Grant, error) { } // RevokeOAuth2Grant deletes the grant with grantID and userID -func RevokeOAuth2Grant(grantID, userID int64) error { - return revokeOAuth2Grant(db.GetEngine(db.DefaultContext), grantID, userID) -} - -func revokeOAuth2Grant(e db.Engine, grantID, userID int64) error { - _, err := e.Delete(&OAuth2Grant{ID: grantID, UserID: userID}) +func RevokeOAuth2Grant(ctx context.Context, grantID, userID int64) error { + _, err := db.DeleteByBean(ctx, &OAuth2Grant{ID: grantID, UserID: userID}) return err } @@ -576,3 +518,21 @@ func GetActiveOAuth2SourceByName(name string) (*Source, error) { return authSource, nil } + +func DeleteOAuth2RelictsByUserID(ctx context.Context, userID int64) error { + deleteCond := builder.Select("id").From("oauth2_grant").Where(builder.Eq{"oauth2_grant.user_id": userID}) + + if _, err := db.GetEngine(ctx).In("grant_id", deleteCond). + Delete(&OAuth2AuthorizationCode{}); err != nil { + return err + } + + if err := db.DeleteBeans(ctx, + &OAuth2Application{UID: userID}, + &OAuth2Grant{UserID: userID}, + ); err != nil { + return fmt.Errorf("DeleteBeans: %v", err) + } + + return nil +} diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go index b712fc285f..cb8c4aeb6a 100644 --- a/models/auth/oauth2_test.go +++ b/models/auth/oauth2_test.go @@ -7,6 +7,7 @@ package auth import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -52,18 +53,18 @@ func TestOAuth2Application_ValidateClientSecret(t *testing.T) { func TestGetOAuth2ApplicationByClientID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app, err := GetOAuth2ApplicationByClientID("da7da3ba-9a13-4167-856f-3899de0b0138") + app, err := GetOAuth2ApplicationByClientID(db.DefaultContext, "da7da3ba-9a13-4167-856f-3899de0b0138") assert.NoError(t, err) assert.Equal(t, "da7da3ba-9a13-4167-856f-3899de0b0138", app.ClientID) - app, err = GetOAuth2ApplicationByClientID("invalid client id") + app, err = GetOAuth2ApplicationByClientID(db.DefaultContext, "invalid client id") assert.Error(t, err) assert.Nil(t, app) } func TestCreateOAuth2Application(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - app, err := CreateOAuth2Application(CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1}) + app, err := CreateOAuth2Application(db.DefaultContext, CreateOAuth2ApplicationOptions{Name: "newapp", UserID: 1}) assert.NoError(t, err) assert.Equal(t, "newapp", app.Name) assert.Len(t, app.ClientID, 36) @@ -77,11 +78,11 @@ func TestOAuth2Application_TableName(t *testing.T) { func TestOAuth2Application_GetGrantByUserID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application) - grant, err := app.GetGrantByUserID(1) + grant, err := app.GetGrantByUserID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, int64(1), grant.UserID) - grant, err = app.GetGrantByUserID(34923458) + grant, err = app.GetGrantByUserID(db.DefaultContext, 34923458) assert.NoError(t, err) assert.Nil(t, grant) } @@ -89,7 +90,7 @@ func TestOAuth2Application_GetGrantByUserID(t *testing.T) { func TestOAuth2Application_CreateGrant(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) app := unittest.AssertExistsAndLoadBean(t, &OAuth2Application{ID: 1}).(*OAuth2Application) - grant, err := app.CreateGrant(2, "") + grant, err := app.CreateGrant(db.DefaultContext, 2, "") assert.NoError(t, err) assert.NotNil(t, grant) assert.Equal(t, int64(2), grant.UserID) @@ -101,11 +102,11 @@ func TestOAuth2Application_CreateGrant(t *testing.T) { func TestGetOAuth2GrantByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - grant, err := GetOAuth2GrantByID(1) + grant, err := GetOAuth2GrantByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, int64(1), grant.ID) - grant, err = GetOAuth2GrantByID(34923458) + grant, err = GetOAuth2GrantByID(db.DefaultContext, 34923458) assert.NoError(t, err) assert.Nil(t, grant) } @@ -113,7 +114,7 @@ func TestGetOAuth2GrantByID(t *testing.T) { func TestOAuth2Grant_IncreaseCounter(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 1}).(*OAuth2Grant) - assert.NoError(t, grant.IncreaseCounter()) + assert.NoError(t, grant.IncreaseCounter(db.DefaultContext)) assert.Equal(t, int64(2), grant.Counter) unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1, Counter: 2}) } @@ -130,7 +131,7 @@ func TestOAuth2Grant_ScopeContains(t *testing.T) { func TestOAuth2Grant_GenerateNewAuthorizationCode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) grant := unittest.AssertExistsAndLoadBean(t, &OAuth2Grant{ID: 1}).(*OAuth2Grant) - code, err := grant.GenerateNewAuthorizationCode("https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256") + code, err := grant.GenerateNewAuthorizationCode(db.DefaultContext, "https://example2.com/callback", "CjvyTLSdR47G5zYenDA-eDWW4lRrO8yvjcWwbD_deOg", "S256") assert.NoError(t, err) assert.NotNil(t, code) assert.True(t, len(code.Code) > 32) // secret length > 32 @@ -142,20 +143,20 @@ func TestOAuth2Grant_TableName(t *testing.T) { func TestGetOAuth2GrantsByUserID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - result, err := GetOAuth2GrantsByUserID(1) + result, err := GetOAuth2GrantsByUserID(db.DefaultContext, 1) assert.NoError(t, err) assert.Len(t, result, 1) assert.Equal(t, int64(1), result[0].ID) assert.Equal(t, result[0].ApplicationID, result[0].Application.ID) - result, err = GetOAuth2GrantsByUserID(34134) + result, err = GetOAuth2GrantsByUserID(db.DefaultContext, 34134) assert.NoError(t, err) assert.Empty(t, result) } func TestRevokeOAuth2Grant(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.NoError(t, RevokeOAuth2Grant(1, 1)) + assert.NoError(t, RevokeOAuth2Grant(db.DefaultContext, 1, 1)) unittest.AssertNotExistsBean(t, &OAuth2Grant{ID: 1, UserID: 1}) } @@ -163,13 +164,13 @@ func TestRevokeOAuth2Grant(t *testing.T) { func TestGetOAuth2AuthorizationByCode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - code, err := GetOAuth2AuthorizationByCode("authcode") + code, err := GetOAuth2AuthorizationByCode(db.DefaultContext, "authcode") assert.NoError(t, err) assert.NotNil(t, code) assert.Equal(t, "authcode", code.Code) assert.Equal(t, int64(1), code.ID) - code, err = GetOAuth2AuthorizationByCode("does not exist") + code, err = GetOAuth2AuthorizationByCode(db.DefaultContext, "does not exist") assert.NoError(t, err) assert.Nil(t, code) } @@ -224,7 +225,7 @@ func TestOAuth2AuthorizationCode_GenerateRedirectURI(t *testing.T) { func TestOAuth2AuthorizationCode_Invalidate(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) code := unittest.AssertExistsAndLoadBean(t, &OAuth2AuthorizationCode{Code: "authcode"}).(*OAuth2AuthorizationCode) - assert.NoError(t, code.Invalidate()) + assert.NoError(t, code.Invalidate(db.DefaultContext)) unittest.AssertNotExistsBean(t, &OAuth2AuthorizationCode{Code: "authcode"}) } diff --git a/models/branches.go b/models/branches.go index 47fd3dc0a4..98d2c3a993 100644 --- a/models/branches.go +++ b/models/branches.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -79,7 +80,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool { } else if repo, err := repo_model.GetRepositoryByID(protectBranch.RepoID); err != nil { log.Error("repo_model.GetRepositoryByID: %v", err) return false - } else if writeAccess, err := HasAccessUnit(user, repo, unit.TypeCode, perm.AccessModeWrite); err != nil { + } else if writeAccess, err := access_model.HasAccessUnit(db.DefaultContext, user, repo, unit.TypeCode, perm.AccessModeWrite); err != nil { log.Error("HasAccessUnit: %v", err) return false } else { @@ -104,7 +105,7 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool { } // IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch -func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, userID int64, permissionInRepo Permission) bool { +func IsUserMergeWhitelisted(ctx context.Context, protectBranch *ProtectedBranch, userID int64, permissionInRepo access_model.Permission) bool { if !protectBranch.EnableMergeWhitelist { // Then we need to fall back on whether the user has write permission return permissionInRepo.CanWrite(unit.TypeCode) @@ -139,7 +140,7 @@ func isUserOfficialReviewer(ctx context.Context, protectBranch *ProtectedBranch, if !protectBranch.EnableApprovalsWhitelist { // Anyone with write access is considered official reviewer - writeAccess, err := hasAccessUnit(ctx, user, repo, unit.TypeCode, perm.AccessModeWrite) + writeAccess, err := access_model.HasAccessUnit(ctx, user, repo, unit.TypeCode, perm.AccessModeWrite) if err != nil { return false, err } @@ -305,13 +306,9 @@ func (protectBranch *ProtectedBranch) IsUnprotectedFile(patterns []glob.Glob, pa } // GetProtectedBranchBy getting protected branch by ID/Name -func GetProtectedBranchBy(repoID int64, branchName string) (*ProtectedBranch, error) { - return getProtectedBranchBy(db.GetEngine(db.DefaultContext), repoID, branchName) -} - -func getProtectedBranchBy(e db.Engine, repoID int64, branchName string) (*ProtectedBranch, error) { +func GetProtectedBranchBy(ctx context.Context, repoID int64, branchName string) (*ProtectedBranch, error) { rel := &ProtectedBranch{RepoID: repoID, BranchName: branchName} - has, err := e.Get(rel) + has, err := db.GetByBean(ctx, rel) if err != nil { return nil, err } @@ -424,7 +421,7 @@ func updateApprovalWhitelist(ctx context.Context, repo *repo_model.Repository, c whitelist = make([]int64, 0, len(newWhitelist)) for _, userID := range newWhitelist { - if reader, err := IsRepoReader(ctx, repo, userID); err != nil { + if reader, err := access_model.IsRepoReader(ctx, repo, userID); err != nil { return nil, err } else if !reader { continue @@ -449,7 +446,7 @@ func updateUserWhitelist(ctx context.Context, repo *repo_model.Repository, curre if err != nil { return nil, fmt.Errorf("GetUserByID [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err) } - perm, err := GetUserRepoPermission(ctx, repo, user) + perm, err := access_model.GetUserRepoPermission(ctx, repo, user) if err != nil { return nil, fmt.Errorf("GetUserRepoPermission [user_id: %d, repo_id: %d]: %v", userID, repo.ID, err) } @@ -631,7 +628,7 @@ func RenameBranch(repo *repo_model.Repository, from, to string, gitAction func(i } // 2. Update protected branch if needed - protectedBranch, err := getProtectedBranchBy(sess, repo.ID, from) + protectedBranch, err := GetProtectedBranchBy(ctx, repo.ID, from) if err != nil { return err } diff --git a/models/commit_status.go b/models/commit_status.go index cf2143d30f..ef92c5847a 100644 --- a/models/commit_status.go +++ b/models/commit_status.go @@ -49,21 +49,21 @@ func init() { } // upsertCommitStatusIndex the function will not return until it acquires the lock or receives an error. -func upsertCommitStatusIndex(e db.Engine, repoID int64, sha string) (err 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 = e.Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ + _, 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 = e.Exec("INSERT INTO `commit_status_index` (repo_id, sha, max_index) "+ + _, 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 = e.Exec("MERGE `commit_status_index` WITH (HOLDLOCK) as target "+ + _, 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 "+ @@ -100,17 +100,17 @@ func getNextCommitStatusIndex(repoID int64, sha string) (int64, error) { defer commiter.Close() var preIdx int64 - _, err = ctx.Engine().SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", repoID, sha).Get(&preIdx) + _, err = db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ?", repoID, sha).Get(&preIdx) if err != nil { return 0, err } - if err := upsertCommitStatusIndex(ctx.Engine(), repoID, sha); err != nil { + if err := upsertCommitStatusIndex(ctx, repoID, sha); err != nil { return 0, err } var curIdx int64 - has, err := ctx.Engine().SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ? AND max_index=?", repoID, sha, preIdx+1).Get(&curIdx) + has, err := db.GetEngine(ctx).SQL("SELECT max_index FROM `commit_status_index` WHERE repo_id = ? AND sha = ? AND max_index=?", repoID, sha, preIdx+1).Get(&curIdx) if err != nil { return 0, err } @@ -131,7 +131,7 @@ func (status *CommitStatus) loadAttributes(ctx context.Context) (err error) { } } if status.Creator == nil && status.CreatorID > 0 { - status.Creator, err = user_model.GetUserByIDEngine(db.GetEngine(ctx), status.CreatorID) + status.Creator, err = user_model.GetUserByIDCtx(ctx, status.CreatorID) if err != nil { return fmt.Errorf("getUserByID [%d]: %v", status.CreatorID, err) } @@ -231,12 +231,7 @@ type CommitStatusIndex struct { } // GetLatestCommitStatus returns all statuses with a unique context for a given commit. -func GetLatestCommitStatus(repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { - return GetLatestCommitStatusCtx(db.DefaultContext, repoID, sha, listOptions) -} - -// GetLatestCommitStatusCtx returns all statuses with a unique context for a given commit. -func GetLatestCommitStatusCtx(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { +func GetLatestCommitStatus(ctx context.Context, repoID int64, sha string, listOptions db.ListOptions) ([]*CommitStatus, int64, error) { ids := make([]int64, 0, 10) sess := db.GetEngine(ctx).Table(&CommitStatus{}). Where("repo_id = ?", repoID).And("sha = ?", sha). @@ -341,7 +336,7 @@ func ParseCommitsWithStatus(oldCommits []*asymkey_model.SignCommit, repo *repo_m commit := &SignCommitWithStatuses{ SignCommit: c, } - statuses, _, err := GetLatestCommitStatus(repo.ID, commit.ID.String(), db.ListOptions{}) + statuses, _, err := GetLatestCommitStatus(db.DefaultContext, repo.ID, commit.ID.String(), db.ListOptions{}) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } else { diff --git a/models/consistency.go b/models/consistency.go index 4a94fe25d4..e817b69176 100644 --- a/models/consistency.go +++ b/models/consistency.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/setting" "xorm.io/builder" ) @@ -85,7 +86,6 @@ func DeleteOrphanedIssueLabels() error { _, err := db.GetEngine(db.DefaultContext). NotIn("label_id", builder.Select("id").From("label")). Delete(IssueLabel{}) - return err } @@ -94,7 +94,8 @@ func CountOrphanedIssues() (int64, error) { return db.GetEngine(db.DefaultContext).Table("issue"). Join("LEFT", "repository", "issue.repo_id=repository.id"). Where(builder.IsNull{"repository.id"}). - Count("id") + Select("COUNT(`issue`.`id`)"). + Count() } // DeleteOrphanedIssues delete issues without a repo @@ -116,7 +117,7 @@ func DeleteOrphanedIssues() error { var attachmentPaths []string for i := range ids { - paths, err := deleteIssuesByRepoID(db.GetEngine(ctx), ids[i]) + paths, err := deleteIssuesByRepoID(ctx, ids[i]) if err != nil { return err } @@ -140,7 +141,8 @@ func CountOrphanedObjects(subject, refobject, joinCond string) (int64, error) { return db.GetEngine(db.DefaultContext).Table("`"+subject+"`"). Join("LEFT", "`"+refobject+"`", joinCond). Where(builder.IsNull{"`" + refobject + "`.id"}). - Count("id") + Select("COUNT(`" + subject + "`.`id`)"). + Count() } // DeleteOrphanedObjects delete subjects with have no existing refobject anymore @@ -246,3 +248,23 @@ func FixIssueLabelWithOutsideLabels() (int64, error) { return res.RowsAffected() } + +// CountActionCreatedUnixString count actions where created_unix is an empty string +func CountActionCreatedUnixString() (int64, error) { + if setting.Database.UseSQLite3 { + return db.GetEngine(db.DefaultContext).Where(`created_unix = ""`).Count(new(Action)) + } + return 0, nil +} + +// FixActionCreatedUnixString set created_unix to zero if it is an empty string +func FixActionCreatedUnixString() (int64, error) { + if setting.Database.UseSQLite3 { + res, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = 0 WHERE created_unix = ""`) + if err != nil { + return 0, err + } + return res.RowsAffected() + } + return 0, nil +} diff --git a/models/consistency_test.go b/models/consistency_test.go index 1593500361..fb946b2fb7 100644 --- a/models/consistency_test.go +++ b/models/consistency_test.go @@ -11,6 +11,7 @@ import ( issues_model "code.gitea.io/gitea/models/issues" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "github.com/stretchr/testify/assert" @@ -103,3 +104,46 @@ func TestUpdateMilestoneCounters(t *testing.T) { assert.NoError(t, issues_model.UpdateMilestoneCounters(db.DefaultContext, issue.MilestoneID)) unittest.CheckConsistencyFor(t, &issues_model.Milestone{}) } + +func TestConsistencyUpdateAction(t *testing.T) { + if !setting.Database.UseSQLite3 { + t.Skip("Test is only for SQLite database.") + } + assert.NoError(t, unittest.PrepareTestDatabase()) + id := 8 + unittest.AssertExistsAndLoadBean(t, &Action{ + ID: int64(id), + }) + _, err := db.GetEngine(db.DefaultContext).Exec(`UPDATE action SET created_unix = "" WHERE id = ?`, id) + assert.NoError(t, err) + actions := make([]*Action, 0, 1) + // + // XORM returns an error when created_unix is a string + // + err = db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions) + if assert.Error(t, err) { + assert.Contains(t, err.Error(), "type string to a int64: invalid syntax") + } + // + // Get rid of incorrectly set created_unix + // + count, err := CountActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 1, count) + count, err = FixActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 1, count) + + count, err = CountActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 0, count) + count, err = FixActionCreatedUnixString() + assert.NoError(t, err) + assert.EqualValues(t, 0, count) + + // + // XORM must be happy now + // + assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)) + unittest.CheckConsistencyFor(t, &Action{}) +} diff --git a/models/db/context.go b/models/db/context.go index c823952cf6..dae7be3a93 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/setting" "xorm.io/builder" + "xorm.io/xorm/schemas" ) // DefaultContext is the default context to run xorm queries in @@ -175,3 +176,24 @@ func CountByBean(ctx context.Context, bean interface{}) (int64, error) { func TableName(bean interface{}) string { return x.TableName(bean) } + +// EstimateCount returns an estimate of total number of rows in table +func EstimateCount(ctx context.Context, bean interface{}) (int64, error) { + e := GetEngine(ctx) + e.Context(ctx) + + var rows int64 + var err error + tablename := TableName(bean) + switch x.Dialect().URI().DBType { + case schemas.MYSQL: + _, err = e.Context(ctx).SQL("SELECT table_rows FROM information_schema.tables WHERE tables.table_name = ? AND tables.table_schema = ?;", tablename, x.Dialect().URI().DBName).Get(&rows) + case schemas.POSTGRES: + _, err = e.Context(ctx).SQL("SELECT reltuples AS estimate FROM pg_class WHERE relname = ?;", tablename).Get(&rows) + case schemas.MSSQL: + _, err = e.Context(ctx).SQL("sp_spaceused ?;", tablename).Get(&rows) + default: + return e.Context(ctx).Count(tablename) + } + return rows, err +} diff --git a/models/db/engine.go b/models/db/engine.go index 9f38af3c67..8a3b4b206e 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -41,12 +41,11 @@ type Engine interface { Delete(...interface{}) (int64, error) Exec(...interface{}) (sql.Result, error) Find(interface{}, ...interface{}) error - Get(interface{}) (bool, error) + Get(beans ...interface{}) (bool, error) ID(interface{}) *xorm.Session In(string, ...interface{}) *xorm.Session Incr(column string, arg ...interface{}) *xorm.Session Insert(...interface{}) (int64, error) - InsertOne(interface{}) (int64, error) Iterate(interface{}, xorm.IterFunc) error Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *xorm.Session SQL(interface{}, ...interface{}) *xorm.Session @@ -59,7 +58,7 @@ type Engine interface { Sync2(...interface{}) error Select(string) *xorm.Session NotIn(string, ...interface{}) *xorm.Session - OrderBy(string) *xorm.Session + OrderBy(interface{}, ...interface{}) *xorm.Session Exist(...interface{}) (bool, error) Distinct(...string) *xorm.Session Query(...interface{}) ([]map[string][]byte, error) @@ -272,11 +271,6 @@ func MaxBatchInsertSize(bean interface{}) int { return 999 / len(t.ColumnsSeq()) } -// Count returns records number according struct's fields as database query conditions -func Count(bean interface{}) (int64, error) { - return x.Count(bean) -} - // IsTableNotEmpty returns true if table has at least one record func IsTableNotEmpty(tableName string) (bool, error) { return x.Table(tableName).Exist() diff --git a/models/db/index.go b/models/db/index.go index 0086a8f548..8598de9498 100644 --- a/models/db/index.go +++ b/models/db/index.go @@ -5,6 +5,7 @@ package db import ( + "context" "errors" "fmt" @@ -74,8 +75,8 @@ func GetNextResourceIndex(tableName string, groupID int64) (int64, error) { } // DeleteResouceIndex delete resource index -func DeleteResouceIndex(e Engine, tableName string, groupID int64) error { - _, err := e.Exec(fmt.Sprintf("DELETE FROM %s WHERE group_id=?", tableName), groupID) +func DeleteResouceIndex(ctx context.Context, tableName string, groupID int64) error { + _, err := Exec(ctx, fmt.Sprintf("DELETE FROM %s WHERE group_id=?", tableName), groupID) return err } diff --git a/models/fixture_generation.go b/models/fixture_generation.go index 56baa1c345..f4644859eb 100644 --- a/models/fixture_generation.go +++ b/models/fixture_generation.go @@ -9,6 +9,7 @@ import ( "strings" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" ) @@ -22,14 +23,14 @@ func GetYamlFixturesAccess() (string, error) { for _, repo := range repos { repo.MustOwner() - if err := RecalculateAccesses(repo); err != nil { + if err := access_model.RecalculateAccesses(db.DefaultContext, repo); err != nil { return "", err } } var b strings.Builder - accesses := make([]*Access, 0, 200) + accesses := make([]*access_model.Access, 0, 200) if err := db.GetEngine(db.DefaultContext).OrderBy("user_id, repo_id").Find(&accesses); err != nil { return "", err } diff --git a/models/fixtures/issue.yml b/models/fixtures/issue.yml index d5738d5db4..39dacc92ff 100644 --- a/models/fixtures/issue.yml +++ b/models/fixtures/issue.yml @@ -184,3 +184,27 @@ is_pull: false created_unix: 1602935696 updated_unix: 1602935696 + +- + id: 16 + repo_id: 32 + index: 1 + poster_id: 2 + name: just a normal issue + content: content + is_closed: false + is_pull: false + created_unix: 1602935696 + updated_unix: 1602935696 + +- + id: 17 + repo_id: 32 + index: 2 + poster_id: 15 + name: a issue with a assignment + content: content + is_closed: false + is_pull: false + created_unix: 1602935696 + updated_unix: 1602935696 diff --git a/models/fixtures/issue_assignees.yml b/models/fixtures/issue_assignees.yml index 2e89b2b0b3..e5d36f921a 100644 --- a/models/fixtures/issue_assignees.yml +++ b/models/fixtures/issue_assignees.yml @@ -10,3 +10,7 @@ id: 3 assignee_id: 2 issue_id: 6 +- + id: 4 + assignee_id: 2 + issue_id: 17 diff --git a/models/fixtures/issue_index.yml b/models/fixtures/issue_index.yml index 49d95c57ab..de6e955804 100644 --- a/models/fixtures/issue_index.yml +++ b/models/fixtures/issue_index.yml @@ -10,6 +10,9 @@ - group_id: 10 max_index: 1 +- + group_id: 32 + max_index: 2 - group_id: 48 max_index: 1 @@ -21,4 +24,4 @@ max_index: 1 - group_id: 51 - max_index: 1 \ No newline at end of file + max_index: 1 diff --git a/models/fixtures/repository.yml b/models/fixtures/repository.yml index 475cda3b55..82b3ed16dc 100644 --- a/models/fixtures/repository.yml +++ b/models/fixtures/repository.yml @@ -483,7 +483,7 @@ is_private: false num_stars: 0 num_forks: 0 - num_issues: 0 + num_issues: 2 is_mirror: false status: 0 @@ -618,7 +618,8 @@ num_forks: 0 num_issues: 1 num_milestones: 1 - is_mirror: false + is_mirror: + is_archived: false - id: 43 diff --git a/models/fixtures/team_unit.yml b/models/fixtures/team_unit.yml index 66f0d22efd..2e23a63129 100644 --- a/models/fixtures/team_unit.yml +++ b/models/fixtures/team_unit.yml @@ -252,6 +252,7 @@ - id: 43 + org_id: 3 team_id: 7 type: 2 # issues access_mode: 2 diff --git a/models/issue.go b/models/issue.go index 98e64adafd..a22c115523 100644 --- a/models/issue.go +++ b/models/issue.go @@ -19,6 +19,7 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + 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" "code.gitea.io/gitea/models/unit" @@ -106,9 +107,9 @@ func init() { db.RegisterModel(new(IssueIndex)) } -func (issue *Issue) loadTotalTimes(e db.Engine) (err error) { +func (issue *Issue) loadTotalTimes(ctx context.Context) (err error) { opts := FindTrackedTimesOptions{IssueID: issue.ID} - issue.TotalTrackedTime, err = opts.toSession(e).SumInt(&TrackedTime{}, "time") + issue.TotalTrackedTime, err = opts.toSession(db.GetEngine(ctx)).SumInt(&TrackedTime{}, "time") if err != nil { return err } @@ -153,7 +154,7 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) { return nil, fmt.Errorf("Issue is not a pull request") } - pr, err = getPullRequestByIssueID(db.GetEngine(db.DefaultContext), issue.ID) + pr, err = GetPullRequestByIssueID(db.DefaultContext, issue.ID) if err != nil { return nil, err } @@ -164,7 +165,7 @@ func (issue *Issue) GetPullRequest() (pr *PullRequest, err error) { // LoadLabels loads labels func (issue *Issue) LoadLabels(ctx context.Context) (err error) { if issue.Labels == nil { - issue.Labels, err = getLabelsByIssueID(db.GetEngine(ctx), issue.ID) + issue.Labels, err = GetLabelsByIssueID(ctx, issue.ID) if err != nil { return fmt.Errorf("getLabelsByIssueID [%d]: %v", issue.ID, err) } @@ -174,12 +175,12 @@ func (issue *Issue) LoadLabels(ctx context.Context) (err error) { // LoadPoster loads poster func (issue *Issue) LoadPoster() error { - return issue.loadPoster(db.GetEngine(db.DefaultContext)) + return issue.loadPoster(db.DefaultContext) } -func (issue *Issue) loadPoster(e db.Engine) (err error) { +func (issue *Issue) loadPoster(ctx context.Context) (err error) { if issue.Poster == nil { - issue.Poster, err = user_model.GetUserByIDEngine(e, issue.PosterID) + issue.Poster, err = user_model.GetUserByIDCtx(ctx, issue.PosterID) if err != nil { issue.PosterID = -1 issue.Poster = user_model.NewGhostUser() @@ -193,9 +194,9 @@ func (issue *Issue) loadPoster(e db.Engine) (err error) { return } -func (issue *Issue) loadPullRequest(e db.Engine) (err error) { +func (issue *Issue) loadPullRequest(ctx context.Context) (err error) { if issue.IsPull && issue.PullRequest == nil { - issue.PullRequest, err = getPullRequestByIssueID(e, issue.ID) + issue.PullRequest, err = GetPullRequestByIssueID(ctx, issue.ID) if err != nil { if IsErrPullRequestNotExist(err) { return err @@ -209,23 +210,23 @@ func (issue *Issue) loadPullRequest(e db.Engine) (err error) { // LoadPullRequest loads pull request info func (issue *Issue) LoadPullRequest() error { - return issue.loadPullRequest(db.GetEngine(db.DefaultContext)) + return issue.loadPullRequest(db.DefaultContext) } -func (issue *Issue) loadComments(e db.Engine) (err error) { - return issue.loadCommentsByType(e, CommentTypeUnknown) +func (issue *Issue) loadComments(ctx context.Context) (err error) { + return issue.loadCommentsByType(ctx, CommentTypeUnknown) } // LoadDiscussComments loads discuss comments func (issue *Issue) LoadDiscussComments() error { - return issue.loadCommentsByType(db.GetEngine(db.DefaultContext), CommentTypeComment) + return issue.loadCommentsByType(db.DefaultContext, CommentTypeComment) } -func (issue *Issue) loadCommentsByType(e db.Engine, tp CommentType) (err error) { +func (issue *Issue) loadCommentsByType(ctx context.Context, tp CommentType) (err error) { if issue.Comments != nil { return nil } - issue.Comments, err = findComments(e, &FindCommentsOptions{ + issue.Comments, err = FindComments(ctx, &FindCommentsOptions{ IssueID: issue.ID, Type: tp, }) @@ -300,12 +301,11 @@ func (issue *Issue) loadMilestone(ctx context.Context) (err error) { } func (issue *Issue) loadAttributes(ctx context.Context) (err error) { - e := db.GetEngine(ctx) if err = issue.LoadRepo(ctx); err != nil { return } - if err = issue.loadPoster(e); err != nil { + if err = issue.loadPoster(ctx); err != nil { return } @@ -317,27 +317,27 @@ func (issue *Issue) loadAttributes(ctx context.Context) (err error) { return } - if err = issue.loadProject(e); err != nil { + if err = issue.loadProject(ctx); err != nil { return } - if err = issue.loadAssignees(e); err != nil { + if err = issue.LoadAssignees(ctx); err != nil { return } - if err = issue.loadPullRequest(e); err != nil && !IsErrPullRequestNotExist(err) { + if err = issue.loadPullRequest(ctx); err != nil && !IsErrPullRequestNotExist(err) { // It is possible pull request is not yet created. return err } if issue.Attachments == nil { - issue.Attachments, err = repo_model.GetAttachmentsByIssueIDCtx(ctx, issue.ID) + issue.Attachments, err = repo_model.GetAttachmentsByIssueID(ctx, issue.ID) if err != nil { return fmt.Errorf("getAttachmentsByIssueID [%d]: %v", issue.ID, err) } } - if err = issue.loadComments(e); err != nil { + if err = issue.loadComments(ctx); err != nil { return err } @@ -345,7 +345,7 @@ func (issue *Issue) loadAttributes(ctx context.Context) (err error) { return err } if issue.isTimetrackerEnabled(ctx) { - if err = issue.loadTotalTimes(e); err != nil { + if err = issue.loadTotalTimes(ctx); err != nil { return err } } @@ -448,12 +448,12 @@ func (issue *Issue) IsPoster(uid int64) bool { return issue.OriginalAuthorID == 0 && issue.PosterID == uid } -func (issue *Issue) getLabels(e db.Engine) (err error) { +func (issue *Issue) getLabels(ctx context.Context) (err error) { if len(issue.Labels) > 0 { return nil } - issue.Labels, err = getLabelsByIssueID(e, issue.ID) + issue.Labels, err = GetLabelsByIssueID(ctx, issue.ID) if err != nil { return fmt.Errorf("getLabelsByIssueID: %v", err) } @@ -461,7 +461,7 @@ func (issue *Issue) getLabels(e db.Engine) (err error) { } func clearIssueLabels(ctx context.Context, issue *Issue, doer *user_model.User) (err error) { - if err = issue.getLabels(db.GetEngine(ctx)); err != nil { + if err = issue.getLabels(ctx); err != nil { return fmt.Errorf("getLabels: %v", err) } @@ -485,11 +485,11 @@ func ClearIssueLabels(issue *Issue, doer *user_model.User) (err error) { if err := issue.LoadRepo(ctx); err != nil { return err - } else if err = issue.loadPullRequest(db.GetEngine(ctx)); err != nil { + } else if err = issue.loadPullRequest(ctx); err != nil { return err } - perm, err := GetUserRepoPermission(ctx, issue.Repo, doer) + perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } @@ -596,7 +596,7 @@ func (issue *Issue) ReadBy(ctx context.Context, userID int64) error { return err } - return setIssueNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, issue.ID) + return setIssueNotificationStatusReadIfUnread(ctx, userID, issue.ID) } // UpdateIssueCols updates cols of issue @@ -609,7 +609,7 @@ func UpdateIssueCols(ctx context.Context, issue *Issue, cols ...string) error { func changeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, isClosed, isMergePull bool) (*Comment, error) { // Reload the issue - currentIssue, err := getIssueByID(db.GetEngine(ctx), issue.ID) + currentIssue, err := getIssueByID(ctx, issue.ID) if err != nil { return nil, err } @@ -631,7 +631,6 @@ 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) { - e := db.GetEngine(ctx) // Check for open dependencies if issue.IsClosed && issue.Repo.IsDependenciesEnabledCtx(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 @@ -656,11 +655,11 @@ func doChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.Use } // Update issue count of labels - if err := issue.getLabels(e); err != nil { + if err := issue.getLabels(ctx); err != nil { return nil, err } for idx := range issue.Labels { - if err := updateLabelCols(e, issue.Labels[idx], "num_issues", "num_closed_issue"); err != nil { + if err := updateLabelCols(ctx, issue.Labels[idx], "num_issues", "num_closed_issue"); err != nil { return nil, err } } @@ -697,7 +696,7 @@ func ChangeIssueStatus(ctx context.Context, issue *Issue, doer *user_model.User, if err := issue.LoadRepo(ctx); err != nil { return nil, err } - if err := issue.loadPoster(db.GetEngine(ctx)); err != nil { + if err := issue.loadPoster(ctx); err != nil { return nil, err } @@ -773,7 +772,7 @@ func ChangeIssueRef(issue *Issue, doer *user_model.User, oldRef string) (err err // AddDeletePRBranchComment adds delete branch comment for pull request issue func AddDeletePRBranchComment(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, issueID int64, branchName string) error { - issue, err := getIssueByID(db.GetEngine(ctx), issueID) + issue, err := getIssueByID(ctx, issueID) if err != nil { return err } @@ -801,7 +800,7 @@ func UpdateIssueAttachments(issueID int64, uuids []string) (err error) { } for i := 0; i < len(attachments); i++ { attachments[i].IssueID = issueID - if err := repo_model.UpdateAttachmentCtx(ctx, attachments[i]); err != nil { + if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil { return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) } } @@ -821,7 +820,7 @@ func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (er return fmt.Errorf("HasIssueContentHistory: %v", err) } if !hasContentHistory { - if err = issues_model.SaveIssueContentHistory(db.GetEngine(ctx), issue.PosterID, issue.ID, 0, + if err = issues_model.SaveIssueContentHistory(ctx, issue.PosterID, issue.ID, 0, issue.CreatedUnix, issue.Content, true); err != nil { return fmt.Errorf("SaveIssueContentHistory: %v", err) } @@ -833,7 +832,7 @@ func ChangeIssueContent(issue *Issue, doer *user_model.User, content string) (er return fmt.Errorf("UpdateIssueCols: %v", err) } - if err = issues_model.SaveIssueContentHistory(db.GetEngine(ctx), doer.ID, issue.ID, 0, + if err = issues_model.SaveIssueContentHistory(ctx, doer.ID, issue.ID, 0, timeutil.TimeStampNow(), issue.Content, false); err != nil { return fmt.Errorf("SaveIssueContentHistory: %v", err) } @@ -972,7 +971,7 @@ func newIssue(ctx context.Context, doer *user_model.User, opts NewIssueOptions) return fmt.Errorf("find all labels [label_ids: %v]: %v", opts.LabelIDs, err) } - if err = opts.Issue.loadPoster(e); err != nil { + if err = opts.Issue.loadPoster(ctx); err != nil { return err } @@ -1118,9 +1117,9 @@ func GetIssueWithAttrsByIndex(repoID, index int64) (*Issue, error) { return issue, issue.LoadAttributes() } -func getIssueByID(e db.Engine, id int64) (*Issue, error) { +func getIssueByID(ctx context.Context, id int64) (*Issue, error) { issue := new(Issue) - has, err := e.ID(id).Get(issue) + has, err := db.GetEngine(ctx).ID(id).Get(issue) if err != nil { return nil, err } else if !has { @@ -1131,7 +1130,7 @@ func getIssueByID(e db.Engine, id int64) (*Issue, error) { // GetIssueWithAttrsByID returns an issue with attributes by given ID. func GetIssueWithAttrsByID(id int64) (*Issue, error) { - issue, err := getIssueByID(db.GetEngine(db.DefaultContext), id) + issue, err := getIssueByID(db.DefaultContext, id) if err != nil { return nil, err } @@ -1140,28 +1139,20 @@ func GetIssueWithAttrsByID(id int64) (*Issue, error) { // GetIssueByID returns an issue by given ID. func GetIssueByID(id int64) (*Issue, error) { - return getIssueByID(db.GetEngine(db.DefaultContext), id) -} - -func getIssuesByIDs(e db.Engine, issueIDs []int64) ([]*Issue, error) { - issues := make([]*Issue, 0, 10) - return issues, e.In("id", issueIDs).Find(&issues) -} - -func getIssueIDsByRepoID(e db.Engine, repoID int64) ([]int64, error) { - ids := make([]int64, 0, 10) - err := e.Table("issue").Cols("id").Where("repo_id = ?", repoID).Find(&ids) - return ids, err -} - -// GetIssueIDsByRepoID returns all issue ids by repo id -func GetIssueIDsByRepoID(repoID int64) ([]int64, error) { - return getIssueIDsByRepoID(db.GetEngine(db.DefaultContext), repoID) + return getIssueByID(db.DefaultContext, id) } // GetIssuesByIDs return issues with the given IDs. -func GetIssuesByIDs(issueIDs []int64) ([]*Issue, error) { - return getIssuesByIDs(db.GetEngine(db.DefaultContext), issueIDs) +func GetIssuesByIDs(ctx context.Context, issueIDs []int64) ([]*Issue, error) { + issues := make([]*Issue, 0, 10) + return issues, db.GetEngine(ctx).In("id", issueIDs).Find(&issues) +} + +// GetIssueIDsByRepoID returns all issue ids by repo id +func GetIssueIDsByRepoID(ctx context.Context, repoID int64) ([]int64, error) { + ids := make([]int64, 0, 10) + err := db.GetEngine(ctx).Table("issue").Cols("id").Where("repo_id = ?", repoID).Find(&ids) + return ids, err } // IssuesOptions represents options of an issue. @@ -1229,9 +1220,9 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64 Desc("issue.created_unix"). Desc("issue.id") case "priorityrepo": - sess.OrderBy("CASE " + - "WHEN issue.repo_id = " + strconv.FormatInt(priorityRepoID, 10) + " THEN 1 " + - "ELSE 2 END ASC"). + sess.OrderBy("CASE "+ + "WHEN issue.repo_id = ? THEN 1 "+ + "ELSE 2 END ASC", priorityRepoID). Desc("issue.created_unix"). Desc("issue.id") case "project-column-sorting": @@ -1348,12 +1339,52 @@ func (opts *IssuesOptions) setupSessionNoLimit(sess *xorm.Session) { } if opts.User != nil { - sess.And( - issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue()), - ) + sess.And(issuePullAccessibleRepoCond("issue.repo_id", opts.User.ID, opts.Org, opts.Team, opts.IsPull.IsTrue())) } } +// teamUnitsRepoCond returns query condition for those repo id in the special org team with special units access +func teamUnitsRepoCond(id string, userID, orgID, teamID int64, units ...unit.Type) builder.Cond { + return builder.In(id, + builder.Select("repo_id").From("team_repo").Where( + builder.Eq{ + "team_id": teamID, + }.And( + builder.Or( + // Check if the user is member of the team. + builder.In( + "team_id", builder.Select("team_id").From("team_user").Where( + builder.Eq{ + "uid": userID, + }, + ), + ), + // Check if the user is in the owner team of the organisation. + builder.Exists(builder.Select("team_id").From("team_user"). + Where(builder.Eq{ + "org_id": orgID, + "team_id": builder.Select("id").From("team").Where( + builder.Eq{ + "org_id": orgID, + "lower_name": strings.ToLower(organization.OwnerTeamName), + }), + "uid": userID, + }), + ), + )).And( + builder.In( + "team_id", builder.Select("team_id").From("team_unit").Where( + builder.Eq{ + "`team_unit`.org_id": orgID, + }.And( + builder.In("`team_unit`.type", units), + ), + ), + ), + ), + )) +} + // issuePullAccessibleRepoCond userID must not be zero, this condition require join repository table func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organization.Organization, team *organization.Team, isPull bool) builder.Cond { cond := builder.NewCond() @@ -1367,19 +1398,19 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organizati } else { cond = cond.And( builder.Or( - userOrgUnitRepoCond(repoIDstr, userID, org.ID, unitType), // team member repos - userOrgPublicUnitRepoCond(userID, org.ID), // user org public non-member repos, TODO: check repo has issues + repo_model.UserOrgUnitRepoCond(repoIDstr, userID, org.ID, unitType), // team member repos + repo_model.UserOrgPublicUnitRepoCond(userID, org.ID), // user org public non-member repos, TODO: check repo has issues ), ) } } else { cond = cond.And( builder.Or( - userOwnedRepoCond(userID), // owned repos - userCollaborationRepoCond(repoIDstr, userID), // collaboration repos - userAssignedRepoCond(repoIDstr, userID), // user has been assigned accessible public repos - userMentionedRepoCond(repoIDstr, userID), // user has been mentioned accessible public repos - userCreateIssueRepoCond(repoIDstr, userID, isPull), // user has created issue/pr accessible public repos + repo_model.UserOwnedRepoCond(userID), // owned repos + repo_model.UserCollaborationRepoCond(repoIDstr, userID), // collaboration repos + repo_model.UserAssignedRepoCond(repoIDstr, userID), // user has been assigned accessible public repos + repo_model.UserMentionedRepoCond(repoIDstr, userID), // user has been mentioned accessible public repos + repo_model.UserCreateIssueRepoCond(repoIDstr, userID, isPull), // user has created issue/pr accessible public repos ), ) } @@ -1445,7 +1476,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i opts.setupSessionNoLimit(sess) - accessCond := accessibleRepositoryCondition(user) + accessCond := repo_model.AccessibleRepositoryCondition(user) if err := sess.Where(accessCond). Distinct("issue.repo_id"). Table("issue"). @@ -1462,6 +1493,7 @@ func Issues(opts *IssuesOptions) ([]*Issue, error) { sess := e.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") opts.setupSessionWithLimit(sess) + sortIssuesSession(sess, opts.SortType, opts.PriorityRepoID) issues := make([]*Issue, 0, opts.ListOptions.PageSize) @@ -1483,6 +1515,7 @@ func CountIssues(opts *IssuesOptions) (int64, error) { sess := e.Select("COUNT(issue.id) AS count").Table("issue") sess.Join("INNER", "repository", "`issue`.repo_id = `repository`.id") opts.setupSessionNoLimit(sess) + return sess.Count() } @@ -1501,7 +1534,7 @@ func GetParticipantsIDsByIssueID(issueID int64) ([]int64, error) { // IsUserParticipantsOfIssue return true if user is participants of an issue func IsUserParticipantsOfIssue(user *user_model.User, issue *Issue) bool { - userIDs, err := issue.getParticipantIDsByIssue(db.GetEngine(db.DefaultContext)) + userIDs, err := issue.getParticipantIDsByIssue(db.DefaultContext) if err != nil { log.Error(err.Error()) return false @@ -1911,19 +1944,18 @@ func UpdateIssueByAPI(issue *Issue, doer *user_model.User) (statusChangeComment return nil, false, err } defer committer.Close() - sess := db.GetEngine(ctx) if err := issue.LoadRepo(ctx); err != nil { return nil, false, fmt.Errorf("loadRepo: %v", err) } // Reload the issue - currentIssue, err := getIssueByID(sess, issue.ID) + currentIssue, err := getIssueByID(ctx, issue.ID) if err != nil { return nil, false, err } - if _, err := sess.ID(issue.ID).Cols( + if _, err := db.GetEngine(ctx).ID(issue.ID).Cols( "name", "content", "milestone_id", "priority", "deadline_unix", "updated_unix", "is_locked"). Update(issue); err != nil { @@ -1999,7 +2031,8 @@ func DeleteIssue(issue *Issue) error { return committer.Commit() } -func deleteInIssue(e db.Engine, issueID int64, beans ...interface{}) error { +func deleteInIssue(ctx context.Context, issueID int64, beans ...interface{}) error { + e := db.GetEngine(ctx) for _, bean := range beans { if _, err := e.In("issue_id", issueID).Delete(bean); err != nil { return err @@ -2060,7 +2093,7 @@ func deleteIssue(ctx context.Context, issue *Issue) error { } // delete all database data still assigned to this issue - if err := deleteInIssue(e, issue.ID, + if err := deleteInIssue(ctx, issue.ID, &issues_model.ContentHistory{}, &Comment{}, &IssueLabel{}, @@ -2104,12 +2137,12 @@ type DependencyInfo struct { } // getParticipantIDsByIssue returns all userIDs who are participated in comments of an issue and issue author -func (issue *Issue) getParticipantIDsByIssue(e db.Engine) ([]int64, error) { +func (issue *Issue) getParticipantIDsByIssue(ctx context.Context) ([]int64, error) { if issue == nil { return nil, nil } userIDs := make([]int64, 0, 5) - if err := e.Table("comment").Cols("poster_id"). + if err := db.GetEngine(ctx).Table("comment").Cols("poster_id"). Where("`comment`.issue_id = ?", issue.ID). And("`comment`.type in (?,?,?)", CommentTypeComment, CommentTypeCode, CommentTypeReview). And("`user`.is_active = ?", true). @@ -2125,15 +2158,15 @@ func (issue *Issue) getParticipantIDsByIssue(e db.Engine) ([]int64, error) { return userIDs, nil } -// Get Blocked By Dependencies, aka all issues this issue is blocked by. -func (issue *Issue) getBlockedByDependencies(e db.Engine) (issueDeps []*DependencyInfo, err error) { - err = e. +// BlockedByDependencies finds all Dependencies an issue is blocked by +func (issue *Issue) BlockedByDependencies(ctx context.Context) (issueDeps []*DependencyInfo, err error) { + err = db.GetEngine(ctx). Table("issue"). Join("INNER", "repository", "repository.id = issue.repo_id"). Join("INNER", "issue_dependency", "issue_dependency.dependency_id = issue.id"). Where("issue_id = ?", issue.ID). // sort by repo id then created date, with the issues of the same repo at the beginning of the list - OrderBy("CASE WHEN issue.repo_id = " + strconv.FormatInt(issue.RepoID, 10) + " THEN 0 ELSE issue.repo_id END, issue.created_unix DESC"). + OrderBy("CASE WHEN issue.repo_id = ? THEN 0 ELSE issue.repo_id END, issue.created_unix DESC", issue.RepoID). Find(&issueDeps) for _, depInfo := range issueDeps { @@ -2143,15 +2176,15 @@ func (issue *Issue) getBlockedByDependencies(e db.Engine) (issueDeps []*Dependen return issueDeps, err } -// Get Blocking Dependencies, aka all issues this issue blocks. -func (issue *Issue) getBlockingDependencies(e db.Engine) (issueDeps []*DependencyInfo, err error) { - err = e. +// BlockingDependencies returns all blocking dependencies, aka all other issues a given issue blocks +func (issue *Issue) BlockingDependencies(ctx context.Context) (issueDeps []*DependencyInfo, err error) { + err = db.GetEngine(ctx). Table("issue"). Join("INNER", "repository", "repository.id = issue.repo_id"). Join("INNER", "issue_dependency", "issue_dependency.issue_id = issue.id"). Where("dependency_id = ?", issue.ID). // sort by repo id then created date, with the issues of the same repo at the beginning of the list - OrderBy("CASE WHEN issue.repo_id = " + strconv.FormatInt(issue.RepoID, 10) + " THEN 0 ELSE issue.repo_id END, issue.created_unix DESC"). + OrderBy("CASE WHEN issue.repo_id = ? THEN 0 ELSE issue.repo_id END, issue.created_unix DESC", issue.RepoID). Find(&issueDeps) for _, depInfo := range issueDeps { @@ -2161,16 +2194,6 @@ func (issue *Issue) getBlockingDependencies(e db.Engine) (issueDeps []*Dependenc return issueDeps, err } -// BlockedByDependencies finds all Dependencies an issue is blocked by -func (issue *Issue) BlockedByDependencies() ([]*DependencyInfo, error) { - return issue.getBlockedByDependencies(db.GetEngine(db.DefaultContext)) -} - -// BlockingDependencies returns all blocking dependencies, aka all other issues a given issue blocks -func (issue *Issue) BlockingDependencies() ([]*DependencyInfo, error) { - return issue.getBlockingDependencies(db.GetEngine(db.DefaultContext)) -} - func updateIssueClosedNum(ctx context.Context, issue *Issue) (err error) { if issue.IsPull { err = repoStatsCorrectNumClosed(ctx, issue.RepoID, true, "num_closed_pulls") @@ -2314,7 +2337,7 @@ func ResolveIssueMentionsByVisibility(ctx context.Context, issue *Issue, doer *u continue } // Normal users must have read access to the referencing issue - perm, err := GetUserRepoPermission(ctx, issue.Repo, user) + perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, user) if err != nil { return nil, fmt.Errorf("GetUserRepoPermission [%d]: %v", user.ID, err) } @@ -2353,9 +2376,10 @@ func UpdateReactionsMigrationsByType(gitServiceType api.GitServiceType, original return err } -func deleteIssuesByRepoID(sess db.Engine, repoID int64) (attachmentPaths []string, err error) { +func deleteIssuesByRepoID(ctx context.Context, repoID int64) (attachmentPaths []string, err error) { deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"issue.repo_id": repoID}) + sess := db.GetEngine(ctx) // Delete content histories if _, err = sess.In("issue_id", deleteCond). Delete(&issues_model.ContentHistory{}); err != nil { @@ -2430,7 +2454,7 @@ func deleteIssuesByRepoID(sess db.Engine, repoID int64) (attachmentPaths []strin return } - if _, err = sess.Delete(&Issue{RepoID: repoID}); err != nil { + if _, err = db.DeleteByBean(ctx, &Issue{RepoID: repoID}); err != nil { return } diff --git a/models/issue_assignees.go b/models/issue_assignees.go index 0f1f7b6576..c6ccb6e9d2 100644 --- a/models/issue_assignees.go +++ b/models/issue_assignees.go @@ -25,20 +25,15 @@ func init() { } // LoadAssignees load assignees of this issue. -func (issue *Issue) LoadAssignees() error { - return issue.loadAssignees(db.GetEngine(db.DefaultContext)) -} - -// This loads all assignees of an issue -func (issue *Issue) loadAssignees(e db.Engine) (err error) { +func (issue *Issue) LoadAssignees(ctx context.Context) (err error) { // Reset maybe preexisting assignees issue.Assignees = []*user_model.User{} + issue.Assignee = nil - err = e.Table("`user`"). + err = db.GetEngine(ctx).Table("`user`"). Join("INNER", "issue_assignees", "assignee_id = `user`.id"). Where("issue_assignees.issue_id = ?", issue.ID). Find(&issue.Assignees) - if err != nil { return err } @@ -47,7 +42,6 @@ func (issue *Issue) loadAssignees(e db.Engine) (err error) { if len(issue.Assignees) > 0 { issue.Assignee = issue.Assignees[0] } - return } @@ -63,33 +57,9 @@ func GetAssigneeIDsByIssue(issueID int64) ([]int64, error) { Find(&userIDs) } -// GetAssigneesByIssue returns everyone assigned to that issue -func GetAssigneesByIssue(issue *Issue) (assignees []*user_model.User, err error) { - return getAssigneesByIssue(db.GetEngine(db.DefaultContext), issue) -} - -func getAssigneesByIssue(e db.Engine, issue *Issue) (assignees []*user_model.User, err error) { - err = issue.loadAssignees(e) - if err != nil { - return assignees, err - } - - return issue.Assignees, nil -} - // IsUserAssignedToIssue returns true when the user is assigned to the issue -func IsUserAssignedToIssue(issue *Issue, user *user_model.User) (isAssigned bool, err error) { - return isUserAssignedToIssue(db.GetEngine(db.DefaultContext), issue, user) -} - -func isUserAssignedToIssue(e db.Engine, issue *Issue, user *user_model.User) (isAssigned bool, err error) { - return e.Get(&IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID}) -} - -// ClearAssigneeByUserID deletes all assignments of an user -func clearAssigneeByUserID(sess db.Engine, userID int64) (err error) { - _, err = sess.Delete(&IssueAssignees{AssigneeID: userID}) - return +func IsUserAssignedToIssue(ctx context.Context, issue *Issue, user *user_model.User) (isAssigned bool, err error) { + return db.GetByBean(ctx, &IssueAssignees{IssueID: issue.ID, AssigneeID: user.ID}) } // ToggleIssueAssignee changes a user between assigned and not assigned for this issue, and make issue comment for it. @@ -113,8 +83,7 @@ func ToggleIssueAssignee(issue *Issue, doer *user_model.User, assigneeID int64) } func toggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.User, assigneeID int64, isCreate bool) (removed bool, comment *Comment, err error) { - sess := db.GetEngine(ctx) - removed, err = toggleUserAssignee(sess, issue, assigneeID) + removed, err = toggleUserAssignee(ctx, issue, assigneeID) if err != nil { return false, nil, fmt.Errorf("UpdateIssueUserByAssignee: %v", err) } @@ -147,39 +116,38 @@ func toggleIssueAssignee(ctx context.Context, issue *Issue, doer *user_model.Use } // toggles user assignee state in database -func toggleUserAssignee(e db.Engine, issue *Issue, assigneeID int64) (removed bool, err error) { +func toggleUserAssignee(ctx context.Context, issue *Issue, assigneeID int64) (removed bool, err error) { // Check if the user exists - assignee, err := user_model.GetUserByIDEngine(e, assigneeID) + assignee, err := user_model.GetUserByIDCtx(ctx, assigneeID) if err != nil { return false, err } // Check if the submitted user is already assigned, if yes delete him otherwise add him - var i int - for i = 0; i < len(issue.Assignees); i++ { + found := false + i := 0 + for ; i < len(issue.Assignees); i++ { if issue.Assignees[i].ID == assigneeID { + found = true break } } assigneeIn := IssueAssignees{AssigneeID: assigneeID, IssueID: issue.ID} - - toBeDeleted := i < len(issue.Assignees) - if toBeDeleted { - issue.Assignees = append(issue.Assignees[:i], issue.Assignees[i:]...) - _, err = e.Delete(assigneeIn) + if found { + issue.Assignees = append(issue.Assignees[:i], issue.Assignees[i+1:]...) + _, err = db.DeleteByBean(ctx, &assigneeIn) if err != nil { - return toBeDeleted, err + return found, err } } else { issue.Assignees = append(issue.Assignees, assignee) - _, err = e.Insert(assigneeIn) - if err != nil { - return toBeDeleted, err + if err = db.Insert(ctx, &assigneeIn); err != nil { + return found, err } } - return toBeDeleted, nil + return found, nil } // MakeIDsFromAPIAssigneesToAdd returns an array with all assignee IDs diff --git a/models/issue_assignees_test.go b/models/issue_assignees_test.go index 41a3ad86e3..80317e1604 100644 --- a/models/issue_assignees_test.go +++ b/models/issue_assignees_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -37,28 +38,28 @@ func TestUpdateAssignee(t *testing.T) { assert.NoError(t, err) // Check if he got removed - isAssigned, err := IsUserAssignedToIssue(issue, user1) + isAssigned, err := IsUserAssignedToIssue(db.DefaultContext, issue, user1) assert.NoError(t, err) assert.False(t, isAssigned) // Check if they're all there - assignees, err := GetAssigneesByIssue(issue) + err = issue.LoadAssignees(db.DefaultContext) assert.NoError(t, err) var expectedAssignees []*user_model.User expectedAssignees = append(expectedAssignees, user2, user3) - for in, assignee := range assignees { + for in, assignee := range issue.Assignees { assert.Equal(t, assignee.ID, expectedAssignees[in].ID) } // Check if the user is assigned - isAssigned, err = IsUserAssignedToIssue(issue, user2) + isAssigned, err = IsUserAssignedToIssue(db.DefaultContext, issue, user2) assert.NoError(t, err) assert.True(t, isAssigned) // This user should not be assigned - isAssigned, err = IsUserAssignedToIssue(issue, &user_model.User{ID: 4}) + isAssigned, err = IsUserAssignedToIssue(db.DefaultContext, issue, &user_model.User{ID: 4}) assert.NoError(t, err) assert.False(t, isAssigned) } diff --git a/models/issue_comment.go b/models/issue_comment.go index 2cf3d5a61d..90c95afa4e 100644 --- a/models/issue_comment.go +++ b/models/issue_comment.go @@ -298,7 +298,7 @@ func (c *Comment) LoadIssueCtx(ctx context.Context) (err error) { if c.Issue != nil { return nil } - c.Issue, err = getIssueByID(db.GetEngine(ctx), c.IssueID) + c.Issue, err = getIssueByID(ctx, c.IssueID) return } @@ -329,12 +329,12 @@ func (c *Comment) AfterLoad(session *xorm.Session) { } } -func (c *Comment) loadPoster(e db.Engine) (err error) { +func (c *Comment) loadPoster(ctx context.Context) (err error) { if c.PosterID <= 0 || c.Poster != nil { return nil } - c.Poster, err = user_model.GetUserByIDEngine(e, c.PosterID) + c.Poster, err = user_model.GetUserByIDCtx(ctx, c.PosterID) if err != nil { if user_model.IsErrUserNotExist(err) { c.PosterID = -1 @@ -525,7 +525,7 @@ func (c *Comment) LoadMilestone() error { // LoadPoster loads comment poster func (c *Comment) LoadPoster() error { - return c.loadPoster(db.GetEngine(db.DefaultContext)) + return c.loadPoster(db.DefaultContext) } // LoadAttachments loads attachments (it never returns error, the error during `GetAttachmentsByCommentIDCtx` is ignored) @@ -535,7 +535,7 @@ func (c *Comment) LoadAttachments() error { } var err error - c.Attachments, err = repo_model.GetAttachmentsByCommentIDCtx(db.DefaultContext, c.ID) + c.Attachments, err = repo_model.GetAttachmentsByCommentID(db.DefaultContext, c.ID) if err != nil { log.Error("getAttachmentsByCommentID[%d]: %v", c.ID, err) } @@ -557,7 +557,7 @@ func (c *Comment) UpdateAttachments(uuids []string) error { for i := 0; i < len(attachments); i++ { attachments[i].IssueID = c.IssueID attachments[i].CommentID = c.ID - if err := repo_model.UpdateAttachmentCtx(ctx, attachments[i]); err != nil { + if err := repo_model.UpdateAttachment(ctx, attachments[i]); err != nil { return fmt.Errorf("update attachment [id: %d]: %v", attachments[i].ID, err) } } @@ -590,7 +590,7 @@ func (c *Comment) LoadAssigneeUserAndTeam() error { } if c.Issue.Repo.Owner.IsOrganization() { - c.AssigneeTeam, err = organization.GetTeamByID(c.AssigneeTeamID) + c.AssigneeTeam, err = organization.GetTeamByID(db.DefaultContext, c.AssigneeTeamID) if err != nil && !organization.IsErrTeamNotExist(err) { return err } @@ -624,7 +624,7 @@ func (c *Comment) LoadDepIssueDetails() (err error) { if c.DependentIssueID <= 0 || c.DependentIssue != nil { return nil } - c.DependentIssue, err = getIssueByID(db.GetEngine(db.DefaultContext), c.DependentIssueID) + c.DependentIssue, err = getIssueByID(db.DefaultContext, c.DependentIssueID) return err } @@ -661,9 +661,9 @@ func (c *Comment) LoadReactions(repo *repo_model.Repository) error { return c.loadReactions(db.DefaultContext, repo) } -func (c *Comment) loadReview(e db.Engine) (err error) { +func (c *Comment) loadReview(ctx context.Context) (err error) { if c.Review == nil { - if c.Review, err = getReviewByID(e, c.ReviewID); err != nil { + if c.Review, err = GetReviewByID(ctx, c.ReviewID); err != nil { return err } } @@ -673,7 +673,7 @@ func (c *Comment) loadReview(e db.Engine) (err error) { // LoadReview loads the associated review func (c *Comment) LoadReview() error { - return c.loadReview(db.GetEngine(db.DefaultContext)) + return c.loadReview(db.DefaultContext) } var notEnoughLines = regexp.MustCompile(`fatal: file .* has only \d+ lines?`) @@ -830,13 +830,12 @@ func CreateCommentCtx(ctx context.Context, opts *CreateCommentOptions) (_ *Comme } func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment *Comment) (err error) { - e := db.GetEngine(ctx) // Check comment type. switch opts.Type { case CommentTypeCode: if comment.ReviewID != 0 { if comment.Review == nil { - if err := comment.loadReview(e); err != nil { + if err := comment.loadReview(ctx); err != nil { return err } } @@ -846,7 +845,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment } fallthrough case CommentTypeComment: - if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil { + if _, err = db.Exec(ctx, "UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil { return err } fallthrough @@ -861,7 +860,7 @@ func updateCommentInfos(ctx context.Context, opts *CreateCommentOptions, comment attachments[i].IssueID = opts.Issue.ID attachments[i].CommentID = comment.ID // No assign value could be 0, so ignore AllCols(). - if _, err = e.ID(attachments[i].ID).Update(attachments[i]); err != nil { + if _, err = db.GetEngine(ctx).ID(attachments[i].ID).Update(attachments[i]); err != nil { return fmt.Errorf("update attachment [%d]: %v", attachments[i].ID, err) } } @@ -1031,13 +1030,9 @@ func CreateRefComment(doer *user_model.User, repo *repo_model.Repository, issue } // GetCommentByID returns the comment by given ID. -func GetCommentByID(id int64) (*Comment, error) { - return getCommentByID(db.GetEngine(db.DefaultContext), id) -} - -func getCommentByID(e db.Engine, id int64) (*Comment, error) { +func GetCommentByID(ctx context.Context, id int64) (*Comment, error) { c := new(Comment) - has, err := e.ID(id).Get(c) + has, err := db.GetEngine(ctx).ID(id).Get(c) if err != nil { return nil, err } else if !has { @@ -1088,9 +1083,10 @@ func (opts *FindCommentsOptions) toConds() builder.Cond { return cond } -func findComments(e db.Engine, opts *FindCommentsOptions) ([]*Comment, error) { +// FindComments returns all comments according options +func FindComments(ctx context.Context, opts *FindCommentsOptions) ([]*Comment, error) { comments := make([]*Comment, 0, 10) - sess := e.Where(opts.toConds()) + sess := db.GetEngine(ctx).Where(opts.toConds()) if opts.RepoID > 0 { sess.Join("INNER", "issue", "issue.id = comment.issue_id") } @@ -1107,11 +1103,6 @@ func findComments(e db.Engine, opts *FindCommentsOptions) ([]*Comment, error) { Find(&comments) } -// FindComments returns all comments according options -func FindComments(opts *FindCommentsOptions) ([]*Comment, error) { - return findComments(db.GetEngine(db.DefaultContext), opts) -} - // CountComments count all comments according options by ignoring pagination func CountComments(opts *FindCommentsOptions) (int64, error) { sess := db.GetEngine(db.DefaultContext).Where(opts.toConds()) @@ -1167,7 +1158,7 @@ func deleteComment(ctx context.Context, comment *Comment) error { return err } - if _, err := e.Delete(&issues_model.ContentHistory{ + if _, err := db.DeleteByBean(ctx, &issues_model.ContentHistory{ CommentID: comment.ID, }); err != nil { return err @@ -1182,7 +1173,7 @@ func deleteComment(ctx context.Context, comment *Comment) error { return err } - if err := comment.neuterCrossReferences(e); err != nil { + if err := comment.neuterCrossReferences(ctx); err != nil { return err } @@ -1192,7 +1183,8 @@ func deleteComment(ctx context.Context, comment *Comment) error { // CodeComments represents comments on code by using this structure: FILENAME -> LINE (+ == proposed; - == previous) -> COMMENTS type CodeComments map[string]map[int64][]*Comment -func fetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) { +// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line +func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) { return fetchCodeCommentsByReview(ctx, issue, currentUser, nil) } @@ -1242,7 +1234,7 @@ func findCodeComments(ctx context.Context, opts FindCommentsOptions, issue *Issu return nil, err } - if err := CommentList(comments).loadPosters(e); err != nil { + if err := CommentList(comments).loadPosters(ctx); err != nil { return nil, err } @@ -1302,11 +1294,6 @@ func FetchCodeCommentsByLine(ctx context.Context, issue *Issue, currentUser *use return findCodeComments(ctx, opts, issue, currentUser, nil) } -// FetchCodeComments will return a 2d-map: ["Path"]["Line"] = Comments at line -func FetchCodeComments(ctx context.Context, issue *Issue, currentUser *user_model.User) (CodeComments, error) { - return fetchCodeComments(ctx, issue, currentUser) -} - // UpdateCommentsMigrationsByType updates comments' migrations information via given git service type and original id and poster id func UpdateCommentsMigrationsByType(tp structs.GitServiceType, originalAuthorID string, posterID int64) error { _, err := db.GetEngine(db.DefaultContext).Table("comment"). diff --git a/models/issue_comment_list.go b/models/issue_comment_list.go index 4133fc8761..d62984c1e6 100644 --- a/models/issue_comment_list.go +++ b/models/issue_comment_list.go @@ -27,7 +27,7 @@ func (comments CommentList) getPosterIDs() []int64 { return container.KeysInt64(posterIDs) } -func (comments CommentList) loadPosters(e db.Engine) error { +func (comments CommentList) loadPosters(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -40,7 +40,7 @@ func (comments CommentList) loadPosters(e db.Engine) error { if left < limit { limit = left } - err := e. + err := db.GetEngine(ctx). In("id", posterIDs[:limit]). Find(&posterMaps) if err != nil { @@ -80,7 +80,7 @@ func (comments CommentList) getLabelIDs() []int64 { return container.KeysInt64(ids) } -func (comments CommentList) loadLabels(e db.Engine) error { +func (comments CommentList) loadLabels(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -93,7 +93,7 @@ func (comments CommentList) loadLabels(e db.Engine) error { if left < limit { limit = left } - rows, err := e. + rows, err := db.GetEngine(ctx). In("id", labelIDs[:limit]). Rows(new(Label)) if err != nil { @@ -130,7 +130,7 @@ func (comments CommentList) getMilestoneIDs() []int64 { return container.KeysInt64(ids) } -func (comments CommentList) loadMilestones(e db.Engine) error { +func (comments CommentList) loadMilestones(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -147,7 +147,7 @@ func (comments CommentList) loadMilestones(e db.Engine) error { if left < limit { limit = left } - err := e. + err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). Find(&milestoneMaps) if err != nil { @@ -173,7 +173,7 @@ func (comments CommentList) getOldMilestoneIDs() []int64 { return container.KeysInt64(ids) } -func (comments CommentList) loadOldMilestones(e db.Engine) error { +func (comments CommentList) loadOldMilestones(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -190,7 +190,7 @@ func (comments CommentList) loadOldMilestones(e db.Engine) error { if left < limit { limit = left } - err := e. + err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). Find(&milestoneMaps) if err != nil { @@ -216,7 +216,7 @@ func (comments CommentList) getAssigneeIDs() []int64 { return container.KeysInt64(ids) } -func (comments CommentList) loadAssignees(e db.Engine) error { +func (comments CommentList) loadAssignees(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -229,7 +229,7 @@ func (comments CommentList) loadAssignees(e db.Engine) error { if left < limit { limit = left } - rows, err := e. + rows, err := db.GetEngine(ctx). In("id", assigneeIDs[:limit]). Rows(new(user_model.User)) if err != nil { @@ -290,7 +290,7 @@ func (comments CommentList) Issues() IssueList { return issueList } -func (comments CommentList) loadIssues(e db.Engine) error { +func (comments CommentList) loadIssues(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -303,7 +303,7 @@ func (comments CommentList) loadIssues(e db.Engine) error { if left < limit { limit = left } - rows, err := e. + rows, err := db.GetEngine(ctx). In("id", issueIDs[:limit]). Rows(new(Issue)) if err != nil { @@ -397,7 +397,7 @@ func (comments CommentList) loadDependentIssues(ctx context.Context) error { return nil } -func (comments CommentList) loadAttachments(e db.Engine) (err error) { +func (comments CommentList) loadAttachments(ctx context.Context) (err error) { if len(comments) == 0 { return nil } @@ -410,7 +410,7 @@ func (comments CommentList) loadAttachments(e db.Engine) (err error) { if left < limit { limit = left } - rows, err := e.Table("attachment"). + rows, err := db.GetEngine(ctx).Table("attachment"). Join("INNER", "comment", "comment.id = attachment.comment_id"). In("comment.id", commentsIDs[:limit]). Rows(new(repo_model.Attachment)) @@ -449,7 +449,7 @@ func (comments CommentList) getReviewIDs() []int64 { return container.KeysInt64(ids) } -func (comments CommentList) loadReviews(e db.Engine) error { +func (comments CommentList) loadReviews(ctx context.Context) error { if len(comments) == 0 { return nil } @@ -462,7 +462,7 @@ func (comments CommentList) loadReviews(e db.Engine) error { if left < limit { limit = left } - rows, err := e. + rows, err := db.GetEngine(ctx). In("id", reviewIDs[:limit]). Rows(new(Review)) if err != nil { @@ -493,36 +493,35 @@ func (comments CommentList) loadReviews(e db.Engine) error { // loadAttributes loads all attributes func (comments CommentList) loadAttributes(ctx context.Context) (err error) { - e := db.GetEngine(ctx) - if err = comments.loadPosters(e); err != nil { + if err = comments.loadPosters(ctx); err != nil { return } - if err = comments.loadLabels(e); err != nil { + if err = comments.loadLabels(ctx); err != nil { return } - if err = comments.loadMilestones(e); err != nil { + if err = comments.loadMilestones(ctx); err != nil { return } - if err = comments.loadOldMilestones(e); err != nil { + if err = comments.loadOldMilestones(ctx); err != nil { return } - if err = comments.loadAssignees(e); err != nil { + if err = comments.loadAssignees(ctx); err != nil { return } - if err = comments.loadAttachments(e); err != nil { + if err = comments.loadAttachments(ctx); err != nil { return } - if err = comments.loadReviews(e); err != nil { + if err = comments.loadReviews(ctx); err != nil { return } - if err = comments.loadIssues(e); err != nil { + if err = comments.loadIssues(ctx); err != nil { return } @@ -541,15 +540,15 @@ func (comments CommentList) LoadAttributes() error { // LoadAttachments loads attachments func (comments CommentList) LoadAttachments() error { - return comments.loadAttachments(db.GetEngine(db.DefaultContext)) + return comments.loadAttachments(db.DefaultContext) } // LoadPosters loads posters func (comments CommentList) LoadPosters() error { - return comments.loadPosters(db.GetEngine(db.DefaultContext)) + return comments.loadPosters(db.DefaultContext) } // LoadIssues loads issues of comments func (comments CommentList) LoadIssues() error { - return comments.loadIssues(db.GetEngine(db.DefaultContext)) + return comments.loadIssues(db.DefaultContext) } diff --git a/models/issue_dependency.go b/models/issue_dependency.go index b292db57e0..af40aa45d3 100644 --- a/models/issue_dependency.go +++ b/models/issue_dependency.go @@ -42,10 +42,9 @@ func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error { return err } defer committer.Close() - sess := db.GetEngine(ctx) // Check if it aleready exists - exists, err := issueDepExists(sess, issue.ID, dep.ID) + exists, err := issueDepExists(ctx, issue.ID, dep.ID) if err != nil { return err } @@ -53,7 +52,7 @@ func CreateIssueDependency(user *user_model.User, issue, dep *Issue) error { return ErrDependencyExists{issue.ID, dep.ID} } // And if it would be circular - circular, err := issueDepExists(sess, dep.ID, issue.ID) + circular, err := issueDepExists(ctx, dep.ID, issue.ID) if err != nil { return err } @@ -114,8 +113,8 @@ func RemoveIssueDependency(user *user_model.User, issue, dep *Issue, depType Dep } // Check if the dependency already exists -func issueDepExists(e db.Engine, issueID, depID int64) (bool, error) { - return e.Where("(issue_id = ? AND dependency_id = ?)", issueID, depID).Exist(&IssueDependency{}) +func issueDepExists(ctx context.Context, issueID, depID int64) (bool, error) { + return db.GetEngine(ctx).Where("(issue_id = ? AND dependency_id = ?)", issueID, depID).Exist(&IssueDependency{}) } // IssueNoDependenciesLeft checks if issue can be closed diff --git a/models/issue_label.go b/models/issue_label.go index d069153939..48a48dbb7c 100644 --- a/models/issue_label.go +++ b/models/issue_label.go @@ -193,12 +193,12 @@ func UpdateLabel(l *Label) error { if !LabelColorPattern.MatchString(l.Color) { return fmt.Errorf("bad color code: %s", l.Color) } - return updateLabelCols(db.GetEngine(db.DefaultContext), l, "name", "description", "color") + return updateLabelCols(db.DefaultContext, l, "name", "description", "color") } // DeleteLabel delete a label func DeleteLabel(id, labelID int64) error { - label, err := GetLabelByID(labelID) + label, err := GetLabelByID(db.DefaultContext, labelID) if err != nil { if IsErrLabelNotExist(err) { return nil @@ -237,14 +237,14 @@ func DeleteLabel(id, labelID int64) error { return committer.Commit() } -// getLabelByID returns a label by label id -func getLabelByID(e db.Engine, labelID int64) (*Label, error) { +// GetLabelByID returns a label by given ID. +func GetLabelByID(ctx context.Context, labelID int64) (*Label, error) { if labelID <= 0 { return nil, ErrLabelNotExist{labelID} } l := &Label{} - has, err := e.ID(labelID).Get(l) + has, err := db.GetEngine(ctx).ID(labelID).Get(l) if err != nil { return nil, err } else if !has { @@ -253,11 +253,6 @@ func getLabelByID(e db.Engine, labelID int64) (*Label, error) { return l, nil } -// GetLabelByID returns a label by given ID. -func GetLabelByID(id int64) (*Label, error) { - return getLabelByID(db.GetEngine(db.DefaultContext), id) -} - // GetLabelsByIDs returns a list of labels by IDs func GetLabelsByIDs(labelIDs []int64) ([]*Label, error) { labels := make([]*Label, 0, len(labelIDs)) @@ -275,8 +270,8 @@ func GetLabelsByIDs(labelIDs []int64) ([]*Label, error) { // |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____| // \/ \/|__| \/ \/ -// getLabelInRepoByName returns a label by Name in given repository. -func getLabelInRepoByName(e db.Engine, repoID int64, labelName string) (*Label, error) { +// GetLabelInRepoByName returns a label by name in given repository. +func GetLabelInRepoByName(ctx context.Context, repoID int64, labelName string) (*Label, error) { if len(labelName) == 0 || repoID <= 0 { return nil, ErrRepoLabelNotExist{0, repoID} } @@ -285,7 +280,7 @@ func getLabelInRepoByName(e db.Engine, repoID int64, labelName string) (*Label, Name: labelName, RepoID: repoID, } - has, err := e.Get(l) + has, err := db.GetByBean(ctx, l) if err != nil { return nil, err } else if !has { @@ -294,8 +289,8 @@ func getLabelInRepoByName(e db.Engine, repoID int64, labelName string) (*Label, return l, nil } -// getLabelInRepoByID returns a label by ID in given repository. -func getLabelInRepoByID(e db.Engine, repoID, labelID int64) (*Label, error) { +// GetLabelInRepoByID returns a label by ID in given repository. +func GetLabelInRepoByID(ctx context.Context, repoID, labelID int64) (*Label, error) { if labelID <= 0 || repoID <= 0 { return nil, ErrRepoLabelNotExist{labelID, repoID} } @@ -304,7 +299,7 @@ func getLabelInRepoByID(e db.Engine, repoID, labelID int64) (*Label, error) { ID: labelID, RepoID: repoID, } - has, err := e.Get(l) + has, err := db.GetByBean(ctx, l) if err != nil { return nil, err } else if !has { @@ -313,11 +308,6 @@ func getLabelInRepoByID(e db.Engine, repoID, labelID int64) (*Label, error) { return l, nil } -// GetLabelInRepoByName returns a label by name in given repository. -func GetLabelInRepoByName(repoID int64, labelName string) (*Label, error) { - return getLabelInRepoByName(db.GetEngine(db.DefaultContext), repoID, labelName) -} - // GetLabelIDsInRepoByNames returns a list of labelIDs by names in a given // repository. // it silently ignores label names that do not belong to the repository. @@ -342,11 +332,6 @@ func BuildLabelNamesIssueIDsCondition(labelNames []string) *builder.Builder { GroupBy("issue_label.issue_id") } -// GetLabelInRepoByID returns a label by ID in given repository. -func GetLabelInRepoByID(repoID, labelID int64) (*Label, error) { - return getLabelInRepoByID(db.GetEngine(db.DefaultContext), repoID, labelID) -} - // GetLabelsInRepoByIDs returns a list of labels by IDs in given repository, // it silently ignores label IDs that do not belong to the repository. func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) { @@ -358,12 +343,13 @@ func GetLabelsInRepoByIDs(repoID int64, labelIDs []int64) ([]*Label, error) { Find(&labels) } -func getLabelsByRepoID(e db.Engine, repoID int64, sortType string, listOptions db.ListOptions) ([]*Label, error) { +// GetLabelsByRepoID returns all labels that belong to given repository by ID. +func GetLabelsByRepoID(ctx context.Context, repoID int64, sortType string, listOptions db.ListOptions) ([]*Label, error) { if repoID <= 0 { return nil, ErrRepoLabelNotExist{0, repoID} } labels := make([]*Label, 0, 10) - sess := e.Where("repo_id = ?", repoID) + sess := db.GetEngine(ctx).Where("repo_id = ?", repoID) switch sortType { case "reversealphabetically": @@ -383,11 +369,6 @@ func getLabelsByRepoID(e db.Engine, repoID int64, sortType string, listOptions d return labels, sess.Find(&labels) } -// GetLabelsByRepoID returns all labels that belong to given repository by ID. -func GetLabelsByRepoID(repoID int64, sortType string, listOptions db.ListOptions) ([]*Label, error) { - return getLabelsByRepoID(db.GetEngine(db.DefaultContext), repoID, sortType, listOptions) -} - // CountLabelsByRepoID count number of all labels that belong to given repository by ID. func CountLabelsByRepoID(repoID int64) (int64, error) { return db.GetEngine(db.DefaultContext).Where("repo_id = ?", repoID).Count(&Label{}) @@ -400,8 +381,8 @@ func CountLabelsByRepoID(repoID int64) (int64, error) { // \_______ /__| \___ / // \/ /_____/ -// getLabelInOrgByName returns a label by Name in given organization -func getLabelInOrgByName(e db.Engine, orgID int64, labelName string) (*Label, error) { +// GetLabelInOrgByName returns a label by name in given organization. +func GetLabelInOrgByName(ctx context.Context, orgID int64, labelName string) (*Label, error) { if len(labelName) == 0 || orgID <= 0 { return nil, ErrOrgLabelNotExist{0, orgID} } @@ -410,7 +391,7 @@ func getLabelInOrgByName(e db.Engine, orgID int64, labelName string) (*Label, er Name: labelName, OrgID: orgID, } - has, err := e.Get(l) + has, err := db.GetByBean(ctx, l) if err != nil { return nil, err } else if !has { @@ -419,8 +400,8 @@ func getLabelInOrgByName(e db.Engine, orgID int64, labelName string) (*Label, er return l, nil } -// getLabelInOrgByID returns a label by ID in given organization. -func getLabelInOrgByID(e db.Engine, orgID, labelID int64) (*Label, error) { +// GetLabelInOrgByID returns a label by ID in given organization. +func GetLabelInOrgByID(ctx context.Context, orgID, labelID int64) (*Label, error) { if labelID <= 0 || orgID <= 0 { return nil, ErrOrgLabelNotExist{labelID, orgID} } @@ -429,7 +410,7 @@ func getLabelInOrgByID(e db.Engine, orgID, labelID int64) (*Label, error) { ID: labelID, OrgID: orgID, } - has, err := e.Get(l) + has, err := db.GetByBean(ctx, l) if err != nil { return nil, err } else if !has { @@ -438,11 +419,6 @@ func getLabelInOrgByID(e db.Engine, orgID, labelID int64) (*Label, error) { return l, nil } -// GetLabelInOrgByName returns a label by name in given organization. -func GetLabelInOrgByName(orgID int64, labelName string) (*Label, error) { - return getLabelInOrgByName(db.GetEngine(db.DefaultContext), orgID, labelName) -} - // GetLabelIDsInOrgByNames returns a list of labelIDs by names in a given // organization. func GetLabelIDsInOrgByNames(orgID int64, labelNames []string) ([]int64, error) { @@ -459,11 +435,6 @@ func GetLabelIDsInOrgByNames(orgID int64, labelNames []string) ([]int64, error) Find(&labelIDs) } -// GetLabelInOrgByID returns a label by ID in given organization. -func GetLabelInOrgByID(orgID, labelID int64) (*Label, error) { - return getLabelInOrgByID(db.GetEngine(db.DefaultContext), orgID, labelID) -} - // GetLabelsInOrgByIDs returns a list of labels by IDs in given organization, // it silently ignores label IDs that do not belong to the organization. func GetLabelsInOrgByIDs(orgID int64, labelIDs []int64) ([]*Label, error) { @@ -475,12 +446,13 @@ func GetLabelsInOrgByIDs(orgID int64, labelIDs []int64) ([]*Label, error) { Find(&labels) } -func getLabelsByOrgID(e db.Engine, orgID int64, sortType string, listOptions db.ListOptions) ([]*Label, error) { +// GetLabelsByOrgID returns all labels that belong to given organization by ID. +func GetLabelsByOrgID(ctx context.Context, orgID int64, sortType string, listOptions db.ListOptions) ([]*Label, error) { if orgID <= 0 { return nil, ErrOrgLabelNotExist{0, orgID} } labels := make([]*Label, 0, 10) - sess := e.Where("org_id = ?", orgID) + sess := db.GetEngine(ctx).Where("org_id = ?", orgID) switch sortType { case "reversealphabetically": @@ -500,11 +472,6 @@ func getLabelsByOrgID(e db.Engine, orgID int64, sortType string, listOptions db. return labels, sess.Find(&labels) } -// GetLabelsByOrgID returns all labels that belong to given organization by ID. -func GetLabelsByOrgID(orgID int64, sortType string, listOptions db.ListOptions) ([]*Label, error) { - return getLabelsByOrgID(db.GetEngine(db.DefaultContext), orgID, sortType, listOptions) -} - // CountLabelsByOrgID count all labels that belong to given organization by ID. func CountLabelsByOrgID(orgID int64) (int64, error) { return db.GetEngine(db.DefaultContext).Where("org_id = ?", orgID).Count(&Label{}) @@ -517,21 +484,17 @@ func CountLabelsByOrgID(orgID int64) (int64, error) { // |___/____ >____ >____/ \___ | // \/ \/ \/ -func getLabelsByIssueID(e db.Engine, issueID int64) ([]*Label, error) { +// GetLabelsByIssueID returns all labels that belong to given issue by ID. +func GetLabelsByIssueID(ctx context.Context, issueID int64) ([]*Label, error) { var labels []*Label - return labels, e.Where("issue_label.issue_id = ?", issueID). + return labels, db.GetEngine(ctx).Where("issue_label.issue_id = ?", issueID). Join("LEFT", "issue_label", "issue_label.label_id = label.id"). Asc("label.name"). Find(&labels) } -// GetLabelsByIssueID returns all labels that belong to given issue by ID. -func GetLabelsByIssueID(issueID int64) ([]*Label, error) { - return getLabelsByIssueID(db.GetEngine(db.DefaultContext), issueID) -} - -func updateLabelCols(e db.Engine, l *Label, cols ...string) error { - _, err := e.ID(l.ID). +func updateLabelCols(ctx context.Context, l *Label, cols ...string) error { + _, err := db.GetEngine(ctx).ID(l.ID). SetExpr("num_issues", builder.Select("count(*)").From("issue_label"). Where(builder.Eq{"label_id": l.ID}), @@ -562,21 +525,16 @@ type IssueLabel struct { LabelID int64 `xorm:"UNIQUE(s)"` } -func hasIssueLabel(e db.Engine, issueID, labelID int64) bool { - has, _ := e.Where("issue_id = ? AND label_id = ?", issueID, labelID).Get(new(IssueLabel)) - return has -} - // HasIssueLabel returns true if issue has been labeled. -func HasIssueLabel(issueID, labelID int64) bool { - return hasIssueLabel(db.GetEngine(db.DefaultContext), issueID, labelID) +func HasIssueLabel(ctx context.Context, issueID, labelID int64) bool { + has, _ := db.GetEngine(ctx).Where("issue_id = ? AND label_id = ?", issueID, labelID).Get(new(IssueLabel)) + return has } // newIssueLabel this function creates a new label it does not check if the label is valid for the issue // YOU MUST CHECK THIS BEFORE THIS FUNCTION func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_model.User) (err error) { - e := db.GetEngine(ctx) - if _, err = e.Insert(&IssueLabel{ + if err = db.Insert(ctx, &IssueLabel{ IssueID: issue.ID, LabelID: label.ID, }); err != nil { @@ -599,12 +557,12 @@ func newIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_m return err } - return updateLabelCols(e, label, "num_issues", "num_closed_issue") + return updateLabelCols(ctx, label, "num_issues", "num_closed_issue") } // NewIssueLabel creates a new issue-label relation. func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error) { - if HasIssueLabel(issue.ID, label.ID) { + if HasIssueLabel(db.DefaultContext, issue.ID, label.ID) { return nil } @@ -637,13 +595,12 @@ func NewIssueLabel(issue *Issue, label *Label, doer *user_model.User) (err error // newIssueLabels add labels to an issue. It will check if the labels are valid for the issue func newIssueLabels(ctx context.Context, issue *Issue, labels []*Label, doer *user_model.User) (err error) { - e := db.GetEngine(ctx) if err = issue.LoadRepo(ctx); err != nil { return err } for _, label := range labels { // Don't add already present labels and invalid labels - if hasIssueLabel(e, issue.ID, label.ID) || + if HasIssueLabel(ctx, issue.ID, label.ID) || (label.RepoID != issue.RepoID && label.OrgID != issue.Repo.OwnerID) { continue } @@ -677,8 +634,7 @@ func NewIssueLabels(issue *Issue, labels []*Label, doer *user_model.User) (err e } func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *user_model.User) (err error) { - e := db.GetEngine(ctx) - if count, err := e.Delete(&IssueLabel{ + if count, err := db.DeleteByBean(ctx, &IssueLabel{ IssueID: issue.ID, LabelID: label.ID, }); err != nil { @@ -702,7 +658,7 @@ func deleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use return err } - return updateLabelCols(e, label, "num_issues", "num_closed_issue") + return updateLabelCols(ctx, label, "num_issues", "num_closed_issue") } // DeleteIssueLabel deletes issue-label relation. @@ -715,14 +671,14 @@ func DeleteIssueLabel(ctx context.Context, issue *Issue, label *Label, doer *use return issue.LoadLabels(ctx) } -func deleteLabelsByRepoID(sess db.Engine, repoID int64) error { +func deleteLabelsByRepoID(ctx context.Context, repoID int64) error { deleteCond := builder.Select("id").From("label").Where(builder.Eq{"label.repo_id": repoID}) - if _, err := sess.In("label_id", deleteCond). + if _, err := db.GetEngine(ctx).In("label_id", deleteCond). Delete(&IssueLabel{}); err != nil { return err } - _, err := sess.Delete(&Label{RepoID: repoID}) + _, err := db.DeleteByBean(ctx, &Label{RepoID: repoID}) return err } diff --git a/models/issue_label_test.go b/models/issue_label_test.go index 2dd0cf98e0..67a09151d8 100644 --- a/models/issue_label_test.go +++ b/models/issue_label_test.go @@ -59,25 +59,25 @@ func TestNewLabels(t *testing.T) { func TestGetLabelByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label, err := GetLabelByID(1) + label, err := GetLabelByID(db.DefaultContext, 1) assert.NoError(t, err) assert.EqualValues(t, 1, label.ID) - _, err = GetLabelByID(unittest.NonexistentID) + _, err = GetLabelByID(db.DefaultContext, unittest.NonexistentID) assert.True(t, IsErrLabelNotExist(err)) } func TestGetLabelInRepoByName(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label, err := GetLabelInRepoByName(1, "label1") + label, err := GetLabelInRepoByName(db.DefaultContext, 1, "label1") assert.NoError(t, err) assert.EqualValues(t, 1, label.ID) assert.Equal(t, "label1", label.Name) - _, err = GetLabelInRepoByName(1, "") + _, err = GetLabelInRepoByName(db.DefaultContext, 1, "") assert.True(t, IsErrRepoLabelNotExist(err)) - _, err = GetLabelInRepoByName(unittest.NonexistentID, "nonexistent") + _, err = GetLabelInRepoByName(db.DefaultContext, unittest.NonexistentID, "nonexistent") assert.True(t, IsErrRepoLabelNotExist(err)) } @@ -107,14 +107,14 @@ func TestGetLabelInRepoByNamesDiscardsNonExistentLabels(t *testing.T) { func TestGetLabelInRepoByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label, err := GetLabelInRepoByID(1, 1) + label, err := GetLabelInRepoByID(db.DefaultContext, 1, 1) assert.NoError(t, err) assert.EqualValues(t, 1, label.ID) - _, err = GetLabelInRepoByID(1, -1) + _, err = GetLabelInRepoByID(db.DefaultContext, 1, -1) assert.True(t, IsErrRepoLabelNotExist(err)) - _, err = GetLabelInRepoByID(unittest.NonexistentID, unittest.NonexistentID) + _, err = GetLabelInRepoByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID) assert.True(t, IsErrRepoLabelNotExist(err)) } @@ -131,7 +131,7 @@ func TestGetLabelsInRepoByIDs(t *testing.T) { func TestGetLabelsByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(repoID int64, sortType string, expectedIssueIDs []int64) { - labels, err := GetLabelsByRepoID(repoID, sortType, db.ListOptions{}) + labels, err := GetLabelsByRepoID(db.DefaultContext, repoID, sortType, db.ListOptions{}) assert.NoError(t, err) assert.Len(t, labels, len(expectedIssueIDs)) for i, label := range labels { @@ -148,21 +148,21 @@ func TestGetLabelsByRepoID(t *testing.T) { func TestGetLabelInOrgByName(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label, err := GetLabelInOrgByName(3, "orglabel3") + label, err := GetLabelInOrgByName(db.DefaultContext, 3, "orglabel3") assert.NoError(t, err) assert.EqualValues(t, 3, label.ID) assert.Equal(t, "orglabel3", label.Name) - _, err = GetLabelInOrgByName(3, "") + _, err = GetLabelInOrgByName(db.DefaultContext, 3, "") assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelInOrgByName(0, "orglabel3") + _, err = GetLabelInOrgByName(db.DefaultContext, 0, "orglabel3") assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelInOrgByName(-1, "orglabel3") + _, err = GetLabelInOrgByName(db.DefaultContext, -1, "orglabel3") assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelInOrgByName(unittest.NonexistentID, "nonexistent") + _, err = GetLabelInOrgByName(db.DefaultContext, unittest.NonexistentID, "nonexistent") assert.True(t, IsErrOrgLabelNotExist(err)) } @@ -192,20 +192,20 @@ func TestGetLabelInOrgByNamesDiscardsNonExistentLabels(t *testing.T) { func TestGetLabelInOrgByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - label, err := GetLabelInOrgByID(3, 3) + label, err := GetLabelInOrgByID(db.DefaultContext, 3, 3) assert.NoError(t, err) assert.EqualValues(t, 3, label.ID) - _, err = GetLabelInOrgByID(3, -1) + _, err = GetLabelInOrgByID(db.DefaultContext, 3, -1) assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelInOrgByID(0, 3) + _, err = GetLabelInOrgByID(db.DefaultContext, 0, 3) assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelInOrgByID(-1, 3) + _, err = GetLabelInOrgByID(db.DefaultContext, -1, 3) assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelInOrgByID(unittest.NonexistentID, unittest.NonexistentID) + _, err = GetLabelInOrgByID(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID) assert.True(t, IsErrOrgLabelNotExist(err)) } @@ -222,7 +222,7 @@ func TestGetLabelsInOrgByIDs(t *testing.T) { func TestGetLabelsByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(orgID int64, sortType string, expectedIssueIDs []int64) { - labels, err := GetLabelsByOrgID(orgID, sortType, db.ListOptions{}) + labels, err := GetLabelsByOrgID(db.DefaultContext, orgID, sortType, db.ListOptions{}) assert.NoError(t, err) assert.Len(t, labels, len(expectedIssueIDs)) for i, label := range labels { @@ -235,10 +235,10 @@ func TestGetLabelsByOrgID(t *testing.T) { testSuccess(3, "default", []int64{3, 4}) var err error - _, err = GetLabelsByOrgID(0, "leastissues", db.ListOptions{}) + _, err = GetLabelsByOrgID(db.DefaultContext, 0, "leastissues", db.ListOptions{}) assert.True(t, IsErrOrgLabelNotExist(err)) - _, err = GetLabelsByOrgID(-1, "leastissues", db.ListOptions{}) + _, err = GetLabelsByOrgID(db.DefaultContext, -1, "leastissues", db.ListOptions{}) assert.True(t, IsErrOrgLabelNotExist(err)) } @@ -246,13 +246,13 @@ func TestGetLabelsByOrgID(t *testing.T) { func TestGetLabelsByIssueID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - labels, err := GetLabelsByIssueID(1) + labels, err := GetLabelsByIssueID(db.DefaultContext, 1) assert.NoError(t, err) if assert.Len(t, labels, 1) { assert.EqualValues(t, 1, labels[0].ID) } - labels, err = GetLabelsByIssueID(unittest.NonexistentID) + labels, err = GetLabelsByIssueID(db.DefaultContext, unittest.NonexistentID) assert.NoError(t, err) assert.Len(t, labels, 0) } @@ -293,9 +293,9 @@ func TestDeleteLabel(t *testing.T) { func TestHasIssueLabel(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.True(t, HasIssueLabel(1, 1)) - assert.False(t, HasIssueLabel(1, 2)) - assert.False(t, HasIssueLabel(unittest.NonexistentID, unittest.NonexistentID)) + assert.True(t, HasIssueLabel(db.DefaultContext, 1, 1)) + assert.False(t, HasIssueLabel(db.DefaultContext, 1, 2)) + assert.False(t, HasIssueLabel(db.DefaultContext, unittest.NonexistentID, unittest.NonexistentID)) } func TestNewIssueLabel(t *testing.T) { diff --git a/models/issue_list.go b/models/issue_list.go index 3116b49d8a..a5fc095e12 100644 --- a/models/issue_list.go +++ b/models/issue_list.go @@ -5,6 +5,7 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" @@ -24,20 +25,21 @@ const ( defaultMaxInSize = 50 ) +// get the repo IDs to be loaded later, these IDs are for issue.Repo and issue.PullRequest.HeadRepo func (issues IssueList) getRepoIDs() []int64 { repoIDs := make(map[int64]struct{}, len(issues)) for _, issue := range issues { - if issue.Repo != nil { - continue - } - if _, ok := repoIDs[issue.RepoID]; !ok { + if issue.Repo == nil { repoIDs[issue.RepoID] = struct{}{} } + if issue.PullRequest != nil && issue.PullRequest.HeadRepo == nil { + repoIDs[issue.PullRequest.HeadRepoID] = struct{}{} + } } return container.KeysInt64(repoIDs) } -func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) { +func (issues IssueList) loadRepositories(ctx context.Context) ([]*repo_model.Repository, error) { if len(issues) == 0 { return nil, nil } @@ -50,7 +52,7 @@ func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository, if left < limit { limit = left } - err := e. + err := db.GetEngine(ctx). In("id", repoIDs[:limit]). Find(&repoMaps) if err != nil { @@ -66,16 +68,19 @@ func (issues IssueList) loadRepositories(e db.Engine) ([]*repo_model.Repository, } else { repoMaps[issue.RepoID] = issue.Repo } - if issue.PullRequest != nil && issue.PullRequest.BaseRepo == nil { + if issue.PullRequest != nil { issue.PullRequest.BaseRepo = issue.Repo + if issue.PullRequest.HeadRepo == nil { + issue.PullRequest.HeadRepo = repoMaps[issue.PullRequest.HeadRepoID] + } } } - return valuesRepository(repoMaps), nil + return repo_model.ValuesRepository(repoMaps), nil } // LoadRepositories loads issues' all repositories func (issues IssueList) LoadRepositories() ([]*repo_model.Repository, error) { - return issues.loadRepositories(db.GetEngine(db.DefaultContext)) + return issues.loadRepositories(db.DefaultContext) } func (issues IssueList) getPosterIDs() []int64 { @@ -88,7 +93,7 @@ func (issues IssueList) getPosterIDs() []int64 { return container.KeysInt64(posterIDs) } -func (issues IssueList) loadPosters(e db.Engine) error { +func (issues IssueList) loadPosters(ctx context.Context) error { if len(issues) == 0 { return nil } @@ -101,7 +106,7 @@ func (issues IssueList) loadPosters(e db.Engine) error { if left < limit { limit = left } - err := e. + err := db.GetEngine(ctx). In("id", posterIDs[:limit]). Find(&posterMaps) if err != nil { @@ -131,7 +136,7 @@ func (issues IssueList) getIssueIDs() []int64 { return ids } -func (issues IssueList) loadLabels(e db.Engine) error { +func (issues IssueList) loadLabels(ctx context.Context) error { if len(issues) == 0 { return nil } @@ -149,7 +154,7 @@ func (issues IssueList) loadLabels(e db.Engine) error { if left < limit { limit = left } - rows, err := e.Table("label"). + rows, err := db.GetEngine(ctx).Table("label"). Join("LEFT", "issue_label", "issue_label.label_id = label.id"). In("issue_label.issue_id", issueIDs[:limit]). Asc("label.name"). @@ -194,7 +199,7 @@ func (issues IssueList) getMilestoneIDs() []int64 { return container.KeysInt64(ids) } -func (issues IssueList) loadMilestones(e db.Engine) error { +func (issues IssueList) loadMilestones(ctx context.Context) error { milestoneIDs := issues.getMilestoneIDs() if len(milestoneIDs) == 0 { return nil @@ -207,7 +212,7 @@ func (issues IssueList) loadMilestones(e db.Engine) error { if left < limit { limit = left } - err := e. + err := db.GetEngine(ctx). In("id", milestoneIDs[:limit]). Find(&milestoneMaps) if err != nil { @@ -223,7 +228,7 @@ func (issues IssueList) loadMilestones(e db.Engine) error { return nil } -func (issues IssueList) loadAssignees(e db.Engine) error { +func (issues IssueList) loadAssignees(ctx context.Context) error { if len(issues) == 0 { return nil } @@ -241,7 +246,7 @@ func (issues IssueList) loadAssignees(e db.Engine) error { if left < limit { limit = left } - rows, err := e.Table("issue_assignees"). + rows, err := db.GetEngine(ctx).Table("issue_assignees"). Join("INNER", "`user`", "`user`.id = `issue_assignees`.assignee_id"). In("`issue_assignees`.issue_id", issueIDs[:limit]). Rows(new(AssigneeIssue)) @@ -284,7 +289,7 @@ func (issues IssueList) getPullIssueIDs() []int64 { return ids } -func (issues IssueList) loadPullRequests(e db.Engine) error { +func (issues IssueList) loadPullRequests(ctx context.Context) error { issuesIDs := issues.getPullIssueIDs() if len(issuesIDs) == 0 { return nil @@ -297,7 +302,7 @@ func (issues IssueList) loadPullRequests(e db.Engine) error { if left < limit { limit = left } - rows, err := e. + rows, err := db.GetEngine(ctx). In("issue_id", issuesIDs[:limit]). Rows(new(PullRequest)) if err != nil { @@ -328,7 +333,7 @@ func (issues IssueList) loadPullRequests(e db.Engine) error { return nil } -func (issues IssueList) loadAttachments(e db.Engine) (err error) { +func (issues IssueList) loadAttachments(ctx context.Context) (err error) { if len(issues) == 0 { return nil } @@ -341,7 +346,7 @@ func (issues IssueList) loadAttachments(e db.Engine) (err error) { if left < limit { limit = left } - rows, err := e.Table("attachment"). + rows, err := db.GetEngine(ctx).Table("attachment"). Join("INNER", "issue", "issue.id = attachment.issue_id"). In("issue.id", issuesIDs[:limit]). Rows(new(repo_model.Attachment)) @@ -373,7 +378,7 @@ func (issues IssueList) loadAttachments(e db.Engine) (err error) { return nil } -func (issues IssueList) loadComments(e db.Engine, cond builder.Cond) (err error) { +func (issues IssueList) loadComments(ctx context.Context, cond builder.Cond) (err error) { if len(issues) == 0 { return nil } @@ -386,7 +391,7 @@ func (issues IssueList) loadComments(e db.Engine, cond builder.Cond) (err error) if left < limit { limit = left } - rows, err := e.Table("comment"). + rows, err := db.GetEngine(ctx).Table("comment"). Join("INNER", "issue", "issue.id = comment.issue_id"). In("issue.id", issuesIDs[:limit]). Where(cond). @@ -419,7 +424,7 @@ func (issues IssueList) loadComments(e db.Engine, cond builder.Cond) (err error) return nil } -func (issues IssueList) loadTotalTrackedTimes(e db.Engine) (err error) { +func (issues IssueList) loadTotalTrackedTimes(ctx context.Context) (err error) { type totalTimesByIssue struct { IssueID int64 Time int64 @@ -444,7 +449,7 @@ func (issues IssueList) loadTotalTrackedTimes(e db.Engine) (err error) { } // select issue_id, sum(time) from tracked_time where issue_id in () group by issue_id - rows, err := e.Table("tracked_time"). + rows, err := db.GetEngine(ctx).Table("tracked_time"). Where("deleted = ?", false). Select("issue_id, sum(time) as time"). In("issue_id", ids[:limit]). @@ -479,32 +484,32 @@ func (issues IssueList) loadTotalTrackedTimes(e db.Engine) (err error) { } // loadAttributes loads all attributes, expect for attachments and comments -func (issues IssueList) loadAttributes(e db.Engine) error { - if _, err := issues.loadRepositories(e); err != nil { +func (issues IssueList) loadAttributes(ctx context.Context) error { + if _, err := issues.loadRepositories(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadRepositories: %v", err) } - if err := issues.loadPosters(e); err != nil { + if err := issues.loadPosters(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadPosters: %v", err) } - if err := issues.loadLabels(e); err != nil { + if err := issues.loadLabels(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadLabels: %v", err) } - if err := issues.loadMilestones(e); err != nil { + if err := issues.loadMilestones(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadMilestones: %v", err) } - if err := issues.loadAssignees(e); err != nil { + if err := issues.loadAssignees(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadAssignees: %v", err) } - if err := issues.loadPullRequests(e); err != nil { + if err := issues.loadPullRequests(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadPullRequests: %v", err) } - if err := issues.loadTotalTrackedTimes(e); err != nil { + if err := issues.loadTotalTrackedTimes(ctx); err != nil { return fmt.Errorf("issue.loadAttributes: loadTotalTrackedTimes: %v", err) } @@ -514,42 +519,38 @@ func (issues IssueList) loadAttributes(e db.Engine) error { // LoadAttributes loads attributes of the issues, except for attachments and // comments func (issues IssueList) LoadAttributes() error { - return issues.loadAttributes(db.GetEngine(db.DefaultContext)) + return issues.loadAttributes(db.DefaultContext) } // LoadAttachments loads attachments func (issues IssueList) LoadAttachments() error { - return issues.loadAttachments(db.GetEngine(db.DefaultContext)) + return issues.loadAttachments(db.DefaultContext) } // LoadComments loads comments func (issues IssueList) LoadComments() error { - return issues.loadComments(db.GetEngine(db.DefaultContext), builder.NewCond()) + return issues.loadComments(db.DefaultContext, builder.NewCond()) } // LoadDiscussComments loads discuss comments func (issues IssueList) LoadDiscussComments() error { - return issues.loadComments(db.GetEngine(db.DefaultContext), builder.Eq{"comment.type": CommentTypeComment}) + return issues.loadComments(db.DefaultContext, builder.Eq{"comment.type": CommentTypeComment}) } // LoadPullRequests loads pull requests func (issues IssueList) LoadPullRequests() error { - return issues.loadPullRequests(db.GetEngine(db.DefaultContext)) + return issues.loadPullRequests(db.DefaultContext) } // GetApprovalCounts returns a map of issue ID to slice of approval counts // FIXME: only returns official counts due to double counting of non-official approvals -func (issues IssueList) GetApprovalCounts() (map[int64][]*ReviewCount, error) { - return issues.getApprovalCounts(db.GetEngine(db.DefaultContext)) -} - -func (issues IssueList) getApprovalCounts(e db.Engine) (map[int64][]*ReviewCount, error) { +func (issues IssueList) GetApprovalCounts(ctx context.Context) (map[int64][]*ReviewCount, error) { rCounts := make([]*ReviewCount, 0, 2*len(issues)) ids := make([]int64, len(issues)) for i, issue := range issues { ids[i] = issue.ID } - sess := e.In("issue_id", ids) + sess := db.GetEngine(ctx).In("issue_id", ids) err := sess.Select("issue_id, type, count(id) as `count`"). Where("official = ? AND dismissed = ?", true, false). GroupBy("issue_id, type"). diff --git a/models/issue_project.go b/models/issue_project.go index 0e993b39c5..0f8c61977b 100644 --- a/models/issue_project.go +++ b/models/issue_project.go @@ -15,13 +15,13 @@ import ( // LoadProject load the project the issue was assigned to func (i *Issue) LoadProject() (err error) { - return i.loadProject(db.GetEngine(db.DefaultContext)) + return i.loadProject(db.DefaultContext) } -func (i *Issue) loadProject(e db.Engine) (err error) { +func (i *Issue) loadProject(ctx context.Context) (err error) { if i.Project == nil { var p project_model.Project - if _, err = e.Table("project"). + if _, err = db.GetEngine(ctx).Table("project"). Join("INNER", "project_issue", "project.id=project_issue.project_id"). Where("project_issue.issue_id = ?", i.ID). Get(&p); err != nil { @@ -34,12 +34,12 @@ func (i *Issue) loadProject(e db.Engine) (err error) { // ProjectID return project id if issue was assigned to one func (i *Issue) ProjectID() int64 { - return i.projectID(db.GetEngine(db.DefaultContext)) + return i.projectID(db.DefaultContext) } -func (i *Issue) projectID(e db.Engine) int64 { +func (i *Issue) projectID(ctx context.Context) int64 { var ip project_model.ProjectIssue - has, err := e.Where("issue_id=?", i.ID).Get(&ip) + has, err := db.GetEngine(ctx).Where("issue_id=?", i.ID).Get(&ip) if err != nil || !has { return 0 } @@ -48,12 +48,12 @@ func (i *Issue) projectID(e db.Engine) int64 { // ProjectBoardID return project board id if issue was assigned to one func (i *Issue) ProjectBoardID() int64 { - return i.projectBoardID(db.GetEngine(db.DefaultContext)) + return i.projectBoardID(db.DefaultContext) } -func (i *Issue) projectBoardID(e db.Engine) int64 { +func (i *Issue) projectBoardID(ctx context.Context) int64 { var ip project_model.ProjectIssue - has, err := e.Where("issue_id=?", i.ID).Get(&ip) + has, err := db.GetEngine(ctx).Where("issue_id=?", i.ID).Get(&ip) if err != nil || !has { return 0 } @@ -122,10 +122,9 @@ func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64 } func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error { - e := db.GetEngine(ctx) - oldProjectID := issue.projectID(e) + oldProjectID := issue.projectID(ctx) - if _, err := e.Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil { + if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil { return err } @@ -146,11 +145,10 @@ func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.U } } - _, err := e.Insert(&project_model.ProjectIssue{ + return db.Insert(ctx, &project_model.ProjectIssue{ IssueID: issue.ID, ProjectID: newProjectID, }) - return err } // MoveIssueAcrossProjectBoards move a card from one board to another diff --git a/models/issue_stopwatch.go b/models/issue_stopwatch.go index 81459ba446..2cb4a62bd3 100644 --- a/models/issue_stopwatch.go +++ b/models/issue_stopwatch.go @@ -75,7 +75,7 @@ type UserStopwatch struct { // GetUIDsAndNotificationCounts between the two provided times func GetUIDsAndStopwatch() ([]*UserStopwatch, error) { sws := []*Stopwatch{} - if err := db.GetEngine(db.DefaultContext).Find(&sws); err != nil { + if err := db.GetEngine(db.DefaultContext).Where("issue_id != 0").Find(&sws); err != nil { return nil, err } if len(sws) == 0 { @@ -125,13 +125,9 @@ func StopwatchExists(userID, issueID int64) bool { } // HasUserStopwatch returns true if the user has a stopwatch -func HasUserStopwatch(userID int64) (exists bool, sw *Stopwatch, err error) { - return hasUserStopwatch(db.GetEngine(db.DefaultContext), userID) -} - -func hasUserStopwatch(e db.Engine, userID int64) (exists bool, sw *Stopwatch, err error) { +func HasUserStopwatch(ctx context.Context, userID int64) (exists bool, sw *Stopwatch, err error) { sw = new(Stopwatch) - exists, err = e. + exists, err = db.GetEngine(ctx). Where("user_id = ?", userID). Get(sw) return @@ -203,24 +199,23 @@ func FinishIssueStopwatch(ctx context.Context, user *user_model.User, issue *Iss }); err != nil { return err } - _, err = db.GetEngine(ctx).Delete(sw) + _, err = db.DeleteByBean(ctx, sw) return err } // CreateIssueStopwatch creates a stopwatch if not exist, otherwise return an error func CreateIssueStopwatch(ctx context.Context, user *user_model.User, issue *Issue) error { - e := db.GetEngine(ctx) if err := issue.LoadRepo(ctx); err != nil { return err } // if another stopwatch is running: stop it - exists, sw, err := hasUserStopwatch(e, user.ID) + exists, sw, err := HasUserStopwatch(ctx, user.ID) if err != nil { return err } if exists { - issue, err := getIssueByID(e, sw.IssueID) + issue, err := getIssueByID(ctx, sw.IssueID) if err != nil { return err } diff --git a/models/issue_stopwatch_test.go b/models/issue_stopwatch_test.go index 0f578f101f..15d5f234fd 100644 --- a/models/issue_stopwatch_test.go +++ b/models/issue_stopwatch_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" @@ -44,12 +45,12 @@ func TestStopwatchExists(t *testing.T) { func TestHasUserStopwatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - exists, sw, err := HasUserStopwatch(1) + exists, sw, err := HasUserStopwatch(db.DefaultContext, 1) assert.NoError(t, err) assert.True(t, exists) assert.Equal(t, int64(1), sw.ID) - exists, _, err = HasUserStopwatch(3) + exists, _, err = HasUserStopwatch(db.DefaultContext, 3) assert.NoError(t, err) assert.False(t, exists) } diff --git a/models/issue_test.go b/models/issue_test.go index 9b82fc80fb..5b2f461a84 100644 --- a/models/issue_test.go +++ b/models/issue_test.go @@ -16,6 +16,7 @@ import ( "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" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -51,7 +52,7 @@ func TestIssue_ReplaceLabels(t *testing.T) { func Test_GetIssueIDsByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - ids, err := GetIssueIDsByRepoID(1) + ids, err := GetIssueIDsByRepoID(db.DefaultContext, 1) assert.NoError(t, err) assert.Len(t, ids, 5) } @@ -68,7 +69,7 @@ func TestIssueAPIURL(t *testing.T) { func TestGetIssuesByIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(expectedIssueIDs, nonExistentIssueIDs []int64) { - issues, err := GetIssuesByIDs(append(expectedIssueIDs, nonExistentIssueIDs...)) + issues, err := GetIssuesByIDs(db.DefaultContext, append(expectedIssueIDs, nonExistentIssueIDs...)) assert.NoError(t, err) actualIssueIDs := make([]int64, len(issues)) for i, issue := range issues { @@ -86,7 +87,7 @@ func TestGetParticipantIDsByIssue(t *testing.T) { checkParticipants := func(issueID int64, userIDs []int) { issue, err := GetIssueByID(issueID) assert.NoError(t, err) - participants, err := issue.getParticipantIDsByIssue(db.GetEngine(db.DefaultContext)) + participants, err := issue.getParticipantIDsByIssue(db.DefaultContext) if assert.NoError(t, err) { participantsIDs := make([]int, len(participants)) for i, uid := range participants { @@ -287,6 +288,20 @@ func TestGetUserIssueStats(t *testing.T) { ClosedCount: 0, }, }, + { + UserIssueStatsOptions{ + UserID: 2, + Org: unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}).(*organization.Organization), + Team: unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 7}).(*organization.Team), + FilterMode: FilterModeAll, + }, + IssueStats{ + YourRepositoriesCount: 2, + AssignCount: 1, + CreateCount: 1, + OpenCount: 2, + }, + }, } { t.Run(fmt.Sprintf("%#v", test.Opts), func(t *testing.T) { stats, err := GetUserIssueStats(test.Opts) @@ -302,7 +317,7 @@ func TestIssue_loadTotalTimes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) ms, err := GetIssueByID(2) assert.NoError(t, err) - assert.NoError(t, ms.loadTotalTimes(db.GetEngine(db.DefaultContext))) + assert.NoError(t, ms.loadTotalTimes(db.DefaultContext)) assert.Equal(t, int64(3682), ms.TotalTrackedTime) } @@ -341,7 +356,7 @@ func TestGetRepoIDsForIssuesOptions(t *testing.T) { IssuesOptions{ AssigneeID: 2, }, - []int64{3}, + []int64{3, 32}, }, { IssuesOptions{ @@ -404,7 +419,7 @@ func TestIssue_InsertIssue(t *testing.T) { func TestIssue_DeleteIssue(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - issueIDs, err := GetIssueIDsByRepoID(1) + issueIDs, err := GetIssueIDsByRepoID(db.DefaultContext, 1) assert.NoError(t, err) assert.EqualValues(t, 5, len(issueIDs)) @@ -415,12 +430,12 @@ func TestIssue_DeleteIssue(t *testing.T) { err = DeleteIssue(issue) assert.NoError(t, err) - issueIDs, err = GetIssueIDsByRepoID(1) + issueIDs, err = GetIssueIDsByRepoID(db.DefaultContext, 1) assert.NoError(t, err) assert.EqualValues(t, 4, len(issueIDs)) // check attachment removal - attachments, err := repo_model.GetAttachmentsByIssueID(4) + attachments, err := repo_model.GetAttachmentsByIssueID(db.DefaultContext, 4) assert.NoError(t, err) issue, err = GetIssueByID(4) assert.NoError(t, err) @@ -428,7 +443,7 @@ func TestIssue_DeleteIssue(t *testing.T) { assert.NoError(t, err) assert.EqualValues(t, 2, len(attachments)) for i := range attachments { - attachment, err := repo_model.GetAttachmentByUUID(attachments[i].UUID) + attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, attachments[i].UUID) assert.Error(t, err) assert.True(t, repo_model.IsErrAttachmentNotExist(err)) assert.Nil(t, attachment) @@ -595,5 +610,5 @@ func TestCountIssues(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) count, err := CountIssues(&IssuesOptions{}) assert.NoError(t, err) - assert.EqualValues(t, 15, count) + assert.EqualValues(t, 17, count) } diff --git a/models/issue_tracked_time.go b/models/issue_tracked_time.go index 76ff874c59..30b3905bbc 100644 --- a/models/issue_tracked_time.go +++ b/models/issue_tracked_time.go @@ -47,9 +47,8 @@ func (t *TrackedTime) LoadAttributes() (err error) { } func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) { - e := db.GetEngine(ctx) if t.Issue == nil { - t.Issue, err = getIssueByID(e, t.IssueID) + t.Issue, err = getIssueByID(ctx, t.IssueID) if err != nil { return } @@ -59,7 +58,7 @@ func (t *TrackedTime) loadAttributes(ctx context.Context) (err error) { } } if t.User == nil { - t.User, err = user_model.GetUserByIDEngine(e, t.UserID) + t.User, err = user_model.GetUserByIDCtx(ctx, t.UserID) if err != nil { return } @@ -128,14 +127,10 @@ func (opts *FindTrackedTimesOptions) toSession(e db.Engine) db.Engine { return sess } -func getTrackedTimes(e db.Engine, options *FindTrackedTimesOptions) (trackedTimes TrackedTimeList, err error) { - err = options.toSession(e).Find(&trackedTimes) - return -} - // GetTrackedTimes returns all tracked times that fit to the given options. -func GetTrackedTimes(opts *FindTrackedTimesOptions) (TrackedTimeList, error) { - return getTrackedTimes(db.GetEngine(db.DefaultContext), opts) +func GetTrackedTimes(ctx context.Context, options *FindTrackedTimesOptions) (trackedTimes TrackedTimeList, err error) { + err = options.toSession(db.GetEngine(ctx)).Find(&trackedTimes) + return } // CountTrackedTimes returns count of tracked times that fit to the given options. @@ -147,13 +142,9 @@ func CountTrackedTimes(opts *FindTrackedTimesOptions) (int64, error) { return sess.Count(&TrackedTime{}) } -func getTrackedSeconds(e db.Engine, opts FindTrackedTimesOptions) (trackedSeconds int64, err error) { - return opts.toSession(e).SumInt(&TrackedTime{}, "time") -} - // GetTrackedSeconds return sum of seconds -func GetTrackedSeconds(opts FindTrackedTimesOptions) (int64, error) { - return getTrackedSeconds(db.GetEngine(db.DefaultContext), opts) +func GetTrackedSeconds(ctx context.Context, opts FindTrackedTimesOptions) (trackedSeconds int64, err error) { + return opts.toSession(db.GetEngine(ctx)).SumInt(&TrackedTime{}, "time") } // AddTime will add the given time (in seconds) to the issue @@ -163,9 +154,8 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) - t, err := addTime(sess, user, issue, amount, created) + t, err := addTime(ctx, user, issue, amount, created) if err != nil { return nil, err } @@ -188,7 +178,7 @@ func AddTime(user *user_model.User, issue *Issue, amount int64, created time.Tim return t, committer.Commit() } -func addTime(e db.Engine, user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) { +func addTime(ctx context.Context, user *user_model.User, issue *Issue, amount int64, created time.Time) (*TrackedTime, error) { if created.IsZero() { created = time.Now() } @@ -198,16 +188,12 @@ func addTime(e db.Engine, user *user_model.User, issue *Issue, amount int64, cre Time: amount, Created: created, } - if _, err := e.Insert(tt); err != nil { - return nil, err - } - - return tt, nil + return tt, db.Insert(ctx, tt) } // TotalTimes returns the spent time for each user by an issue func TotalTimes(options *FindTrackedTimesOptions) (map[*user_model.User]string, error) { - trackedTimes, err := GetTrackedTimes(options) + trackedTimes, err := GetTrackedTimes(db.DefaultContext, options) if err != nil { return nil, err } @@ -239,14 +225,13 @@ func DeleteIssueUserTimes(issue *Issue, user *user_model.User) error { return err } defer committer.Close() - sess := db.GetEngine(ctx) opts := FindTrackedTimesOptions{ IssueID: issue.ID, UserID: user.ID, } - removedTime, err := deleteTimes(sess, opts) + removedTime, err := deleteTimes(ctx, opts) if err != nil { return err } @@ -282,7 +267,7 @@ func DeleteTime(t *TrackedTime) error { return err } - if err := deleteTime(db.GetEngine(ctx), t); err != nil { + if err := deleteTime(ctx, t); err != nil { return err } @@ -299,22 +284,22 @@ func DeleteTime(t *TrackedTime) error { return committer.Commit() } -func deleteTimes(e db.Engine, opts FindTrackedTimesOptions) (removedTime int64, err error) { - removedTime, err = getTrackedSeconds(e, opts) +func deleteTimes(ctx context.Context, opts FindTrackedTimesOptions) (removedTime int64, err error) { + removedTime, err = GetTrackedSeconds(ctx, opts) if err != nil || removedTime == 0 { return } - _, err = opts.toSession(e).Table("tracked_time").Cols("deleted").Update(&TrackedTime{Deleted: true}) + _, err = opts.toSession(db.GetEngine(ctx)).Table("tracked_time").Cols("deleted").Update(&TrackedTime{Deleted: true}) return } -func deleteTime(e db.Engine, t *TrackedTime) error { +func deleteTime(ctx context.Context, t *TrackedTime) error { if t.Deleted { return db.ErrNotExist{ID: t.ID} } t.Deleted = true - _, err := e.ID(t.ID).Cols("deleted").Update(t) + _, err := db.GetEngine(ctx).ID(t.ID).Cols("deleted").Update(t) return err } diff --git a/models/issue_tracked_time_test.go b/models/issue_tracked_time_test.go index 68e78c71c7..a628329712 100644 --- a/models/issue_tracked_time_test.go +++ b/models/issue_tracked_time_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -41,27 +42,27 @@ func TestGetTrackedTimes(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // by Issue - times, err := GetTrackedTimes(&FindTrackedTimesOptions{IssueID: 1}) + times, err := GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{IssueID: 1}) assert.NoError(t, err) assert.Len(t, times, 1) assert.Equal(t, int64(400), times[0].Time) - times, err = GetTrackedTimes(&FindTrackedTimesOptions{IssueID: -1}) + times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{IssueID: -1}) assert.NoError(t, err) assert.Len(t, times, 0) // by User - times, err = GetTrackedTimes(&FindTrackedTimesOptions{UserID: 1}) + times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{UserID: 1}) assert.NoError(t, err) assert.Len(t, times, 3) assert.Equal(t, int64(400), times[0].Time) - times, err = GetTrackedTimes(&FindTrackedTimesOptions{UserID: 3}) + times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{UserID: 3}) assert.NoError(t, err) assert.Len(t, times, 0) // by Repo - times, err = GetTrackedTimes(&FindTrackedTimesOptions{RepositoryID: 2}) + times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{RepositoryID: 2}) assert.NoError(t, err) assert.Len(t, times, 3) assert.Equal(t, int64(1), times[0].Time) @@ -69,11 +70,11 @@ func TestGetTrackedTimes(t *testing.T) { assert.NoError(t, err) assert.Equal(t, issue.RepoID, int64(2)) - times, err = GetTrackedTimes(&FindTrackedTimesOptions{RepositoryID: 1}) + times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{RepositoryID: 1}) assert.NoError(t, err) assert.Len(t, times, 5) - times, err = GetTrackedTimes(&FindTrackedTimesOptions{RepositoryID: 10}) + times, err = GetTrackedTimes(db.DefaultContext, &FindTrackedTimesOptions{RepositoryID: 10}) assert.NoError(t, err) assert.Len(t, times, 0) } diff --git a/models/issue_user.go b/models/issue_user.go index 0b1f8204ba..19c64094a1 100644 --- a/models/issue_user.go +++ b/models/issue_user.go @@ -26,7 +26,7 @@ func init() { } func newIssueUsers(ctx context.Context, repo *repo_model.Repository, issue *Issue) error { - assignees, err := getRepoAssignees(ctx, repo) + assignees, err := repo_model.GetRepoAssignees(ctx, repo) if err != nil { return fmt.Errorf("getAssignees: %v", err) } diff --git a/models/issue_watch.go b/models/issue_watch.go index 92dc847415..9f41d36e19 100644 --- a/models/issue_watch.go +++ b/models/issue_watch.go @@ -5,6 +5,8 @@ package models import ( + "context" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -30,7 +32,7 @@ type IssueWatchList []*IssueWatch // CreateOrUpdateIssueWatch set watching for a user and issue func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error { - iw, exists, err := getIssueWatch(db.GetEngine(db.DefaultContext), userID, issueID) + iw, exists, err := GetIssueWatch(db.DefaultContext, userID, issueID) if err != nil { return err } @@ -57,14 +59,9 @@ func CreateOrUpdateIssueWatch(userID, issueID int64, isWatching bool) error { // GetIssueWatch returns all IssueWatch objects from db by user and issue // the current Web-UI need iw object for watchers AND explicit non-watchers -func GetIssueWatch(userID, issueID int64) (iw *IssueWatch, exists bool, err error) { - return getIssueWatch(db.GetEngine(db.DefaultContext), userID, issueID) -} - -// Return watcher AND explicit non-watcher if entry in db exist -func getIssueWatch(e db.Engine, userID, issueID int64) (iw *IssueWatch, exists bool, err error) { +func GetIssueWatch(ctx context.Context, userID, issueID int64) (iw *IssueWatch, exists bool, err error) { iw = new(IssueWatch) - exists, err = e. + exists, err = db.GetEngine(ctx). Where("user_id = ?", userID). And("issue_id = ?", issueID). Get(iw) @@ -74,7 +71,7 @@ func getIssueWatch(e db.Engine, userID, issueID int64) (iw *IssueWatch, exists b // CheckIssueWatch check if an user is watching an issue // it takes participants and repo watch into account func CheckIssueWatch(user *user_model.User, issue *Issue) (bool, error) { - iw, exist, err := getIssueWatch(db.GetEngine(db.DefaultContext), user.ID, issue.ID) + iw, exist, err := GetIssueWatch(db.DefaultContext, user.ID, issue.ID) if err != nil { return false, err } @@ -91,13 +88,9 @@ func CheckIssueWatch(user *user_model.User, issue *Issue) (bool, error) { // GetIssueWatchersIDs returns IDs of subscribers or explicit unsubscribers to a given issue id // but avoids joining with `user` for performance reasons // User permissions must be verified elsewhere if required -func GetIssueWatchersIDs(issueID int64, watching bool) ([]int64, error) { - return getIssueWatchersIDs(db.GetEngine(db.DefaultContext), issueID, watching) -} - -func getIssueWatchersIDs(e db.Engine, issueID int64, watching bool) ([]int64, error) { +func GetIssueWatchersIDs(ctx context.Context, issueID int64, watching bool) ([]int64, error) { ids := make([]int64, 0, 64) - return ids, e.Table("issue_watch"). + return ids, db.GetEngine(ctx).Table("issue_watch"). Where("issue_id=?", issueID). And("is_watching = ?", watching). Select("user_id"). @@ -105,12 +98,8 @@ func getIssueWatchersIDs(e db.Engine, issueID int64, watching bool) ([]int64, er } // GetIssueWatchers returns watchers/unwatchers of a given issue -func GetIssueWatchers(issueID int64, listOptions db.ListOptions) (IssueWatchList, error) { - return getIssueWatchers(db.GetEngine(db.DefaultContext), issueID, listOptions) -} - -func getIssueWatchers(e db.Engine, issueID int64, listOptions db.ListOptions) (IssueWatchList, error) { - sess := e. +func GetIssueWatchers(ctx context.Context, issueID int64, listOptions db.ListOptions) (IssueWatchList, error) { + sess := db.GetEngine(ctx). Where("`issue_watch`.issue_id = ?", issueID). And("`issue_watch`.is_watching = ?", true). And("`user`.is_active = ?", true). @@ -127,12 +116,8 @@ func getIssueWatchers(e db.Engine, issueID int64, listOptions db.ListOptions) (I } // CountIssueWatchers count watchers/unwatchers of a given issue -func CountIssueWatchers(issueID int64) (int64, error) { - return countIssueWatchers(db.GetEngine(db.DefaultContext), issueID) -} - -func countIssueWatchers(e db.Engine, issueID int64) (int64, error) { - return e. +func CountIssueWatchers(ctx context.Context, issueID int64) (int64, error) { + return db.GetEngine(ctx). Where("`issue_watch`.issue_id = ?", issueID). And("`issue_watch`.is_watching = ?", true). And("`user`.is_active = ?", true). @@ -140,8 +125,8 @@ func countIssueWatchers(e db.Engine, issueID int64) (int64, error) { Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id").Count(new(IssueWatch)) } -func removeIssueWatchersByRepoID(e db.Engine, userID, repoID int64) error { - _, err := e. +func removeIssueWatchersByRepoID(ctx context.Context, userID, repoID int64) error { + _, err := db.GetEngine(ctx). Join("INNER", "issue", "`issue`.id = `issue_watch`.issue_id AND `issue`.repo_id = ?", repoID). Where("`issue_watch`.user_id = ?", userID). Delete(new(IssueWatch)) diff --git a/models/issue_watch_test.go b/models/issue_watch_test.go index f75677d68c..b686196ae1 100644 --- a/models/issue_watch_test.go +++ b/models/issue_watch_test.go @@ -28,16 +28,16 @@ func TestCreateOrUpdateIssueWatch(t *testing.T) { func TestGetIssueWatch(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - _, exists, err := GetIssueWatch(9, 1) + _, exists, err := GetIssueWatch(db.DefaultContext, 9, 1) assert.True(t, exists) assert.NoError(t, err) - iw, exists, err := GetIssueWatch(2, 2) + iw, exists, err := GetIssueWatch(db.DefaultContext, 2, 2) assert.True(t, exists) assert.NoError(t, err) assert.False(t, iw.IsWatching) - _, exists, err = GetIssueWatch(3, 1) + _, exists, err = GetIssueWatch(db.DefaultContext, 3, 1) assert.False(t, exists) assert.NoError(t, err) } @@ -45,22 +45,22 @@ func TestGetIssueWatch(t *testing.T) { func TestGetIssueWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - iws, err := GetIssueWatchers(1, db.ListOptions{}) + iws, err := GetIssueWatchers(db.DefaultContext, 1, db.ListOptions{}) assert.NoError(t, err) // Watcher is inactive, thus 0 assert.Len(t, iws, 0) - iws, err = GetIssueWatchers(2, db.ListOptions{}) + iws, err = GetIssueWatchers(db.DefaultContext, 2, db.ListOptions{}) assert.NoError(t, err) // Watcher is explicit not watching assert.Len(t, iws, 0) - iws, err = GetIssueWatchers(5, db.ListOptions{}) + iws, err = GetIssueWatchers(db.DefaultContext, 5, db.ListOptions{}) assert.NoError(t, err) // Issue has no Watchers assert.Len(t, iws, 0) - iws, err = GetIssueWatchers(7, db.ListOptions{}) + iws, err = GetIssueWatchers(db.DefaultContext, 7, db.ListOptions{}) assert.NoError(t, err) // Issue has one watcher assert.Len(t, iws, 1) diff --git a/models/issue_xref.go b/models/issue_xref.go index cd1c122252..0c1623b5a4 100644 --- a/models/issue_xref.go +++ b/models/issue_xref.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -29,16 +30,16 @@ type crossReferencesContext struct { RemoveOld bool } -func findOldCrossReferences(e db.Engine, issueID, commentID int64) ([]*Comment, error) { +func findOldCrossReferences(ctx context.Context, issueID, commentID int64) ([]*Comment, error) { active := make([]*Comment, 0, 10) - return active, e.Where("`ref_action` IN (?, ?, ?)", references.XRefActionNone, references.XRefActionCloses, references.XRefActionReopens). + return active, db.GetEngine(ctx).Where("`ref_action` IN (?, ?, ?)", references.XRefActionNone, references.XRefActionCloses, references.XRefActionReopens). And("`ref_issue_id` = ?", issueID). And("`ref_comment_id` = ?", commentID). Find(&active) } -func neuterCrossReferences(e db.Engine, issueID, commentID int64) error { - active, err := findOldCrossReferences(e, issueID, commentID) +func neuterCrossReferences(ctx context.Context, issueID, commentID int64) error { + active, err := findOldCrossReferences(ctx, issueID, commentID) if err != nil { return err } @@ -46,11 +47,11 @@ func neuterCrossReferences(e db.Engine, issueID, commentID int64) error { for i, c := range active { ids[i] = c.ID } - return neuterCrossReferencesIds(e, ids) + return neuterCrossReferencesIds(ctx, ids) } -func neuterCrossReferencesIds(e db.Engine, ids []int64) error { - _, err := e.In("id", ids).Cols("`ref_action`").Update(&Comment{RefAction: references.XRefActionNeutered}) +func neuterCrossReferencesIds(ctx context.Context, ids []int64) error { + _, err := db.GetEngine(ctx).In("id", ids).Cols("`ref_action`").Update(&Comment{RefAction: references.XRefActionNeutered}) return err } @@ -79,7 +80,6 @@ func (issue *Issue) addCrossReferences(stdCtx context.Context, doer *user_model. } func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossReferencesContext, plaincontent, mdcontent string) error { - e := db.GetEngine(stdCtx) xreflist, err := ctx.OrigIssue.getCrossReferences(stdCtx, ctx, plaincontent, mdcontent) if err != nil { return err @@ -89,7 +89,7 @@ func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossRefe if ctx.OrigComment != nil { commentID = ctx.OrigComment.ID } - active, err := findOldCrossReferences(e, ctx.OrigIssue.ID, commentID) + active, err := findOldCrossReferences(stdCtx, ctx.OrigIssue.ID, commentID) if err != nil { return err } @@ -108,7 +108,7 @@ func (issue *Issue) createCrossReferences(stdCtx context.Context, ctx *crossRefe } } if len(ids) > 0 { - if err = neuterCrossReferencesIds(e, ids); err != nil { + if err = neuterCrossReferencesIds(stdCtx, ids); err != nil { return err } } @@ -215,7 +215,7 @@ func (issue *Issue) verifyReferencedIssue(stdCtx context.Context, ctx *crossRefe // Check doer permissions; set action to None if the doer can't change the destination if refIssue.RepoID != ctx.OrigIssue.RepoID || ref.Action != references.XRefActionNone { - perm, err := GetUserRepoPermission(stdCtx, refIssue.Repo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(stdCtx, refIssue.Repo, ctx.Doer) if err != nil { return nil, references.XRefActionNone, err } @@ -262,8 +262,8 @@ func (comment *Comment) addCrossReferences(stdCtx context.Context, doer *user_mo return comment.Issue.createCrossReferences(stdCtx, ctx, "", comment.Content) } -func (comment *Comment) neuterCrossReferences(e db.Engine) error { - return neuterCrossReferences(e, comment.IssueID, comment.ID) +func (comment *Comment) neuterCrossReferences(ctx context.Context) error { + return neuterCrossReferences(ctx, comment.IssueID, comment.ID) } // LoadRefComment loads comment that created this reference from database @@ -271,7 +271,7 @@ func (comment *Comment) LoadRefComment() (err error) { if comment.RefComment != nil { return nil } - comment.RefComment, err = GetCommentByID(comment.RefCommentID) + comment.RefComment, err = GetCommentByID(db.DefaultContext, comment.RefCommentID) return } @@ -294,8 +294,9 @@ func CommentTypeIsRef(t CommentType) bool { // RefCommentHTMLURL returns the HTML URL for the comment that created this reference func (comment *Comment) RefCommentHTMLURL() string { + // Edge case for when the reference is inside the title or the description of the referring issue if comment.RefCommentID == 0 { - return "" + return comment.RefIssueHTMLURL() } if err := comment.LoadRefComment(); err != nil { // Silently dropping errors :unamused: log.Error("LoadRefComment(%d): %v", comment.RefCommentID, err) diff --git a/models/issue_xref_test.go b/models/issue_xref_test.go index 677caa48ba..b4ad5b2708 100644 --- a/models/issue_xref_test.go +++ b/models/issue_xref_test.go @@ -150,7 +150,7 @@ func testCreateIssue(t *testing.T, repo, doer int64, title, content string, ispu Issue: i, }) assert.NoError(t, err) - i, err = getIssueByID(db.GetEngine(ctx), i.ID) + i, err = getIssueByID(ctx, i.ID) assert.NoError(t, err) assert.NoError(t, i.addCrossReferences(ctx, d, false)) assert.NoError(t, committer.Commit()) diff --git a/models/issues/content_history.go b/models/issues/content_history.go index 13aadcb1ea..4c5af13db7 100644 --- a/models/issues/content_history.go +++ b/models/issues/content_history.go @@ -38,7 +38,7 @@ func init() { } // SaveIssueContentHistory save history -func SaveIssueContentHistory(e db.Engine, posterID, issueID, commentID int64, editTime timeutil.TimeStamp, contentText string, isFirstCreated bool) error { +func SaveIssueContentHistory(ctx context.Context, posterID, issueID, commentID int64, editTime timeutil.TimeStamp, contentText string, isFirstCreated bool) error { ch := &ContentHistory{ PosterID: posterID, IssueID: issueID, @@ -47,27 +47,26 @@ func SaveIssueContentHistory(e db.Engine, posterID, issueID, commentID int64, ed EditedUnix: editTime, IsFirstCreated: isFirstCreated, } - _, err := e.Insert(ch) - if err != nil { + if err := db.Insert(ctx, ch); err != nil { log.Error("can not save issue content history. err=%v", err) return err } // We only keep at most 20 history revisions now. It is enough in most cases. // If there is a special requirement to keep more, we can consider introducing a new setting option then, but not now. - keepLimitedContentHistory(e, issueID, commentID, 20) + keepLimitedContentHistory(ctx, issueID, commentID, 20) return nil } // keepLimitedContentHistory keeps at most `limit` history revisions, it will hard delete out-dated revisions, sorting by revision interval // we can ignore all errors in this function, so we just log them -func keepLimitedContentHistory(e db.Engine, issueID, commentID int64, limit int) { +func keepLimitedContentHistory(ctx context.Context, issueID, commentID int64, limit int) { type IDEditTime struct { ID int64 EditedUnix timeutil.TimeStamp } var res []*IDEditTime - err := e.Select("id, edited_unix").Table("issue_content_history"). + err := db.GetEngine(ctx).Select("id, edited_unix").Table("issue_content_history"). Where(builder.Eq{"issue_id": issueID, "comment_id": commentID}). OrderBy("edited_unix ASC"). Find(&res) @@ -96,7 +95,7 @@ func keepLimitedContentHistory(e db.Engine, issueID, commentID int64, limit int) } // hard delete the found one - _, err = e.Delete(&ContentHistory{ID: res[indexToDelete].ID}) + _, err = db.GetEngine(ctx).Delete(&ContentHistory{ID: res[indexToDelete].ID}) if err != nil { log.Error("can not delete out-dated content history, err=%v", err) break diff --git a/models/issues/content_history_test.go b/models/issues/content_history_test.go index 71ccc6e6a7..3cbc0ad5e0 100644 --- a/models/issues/content_history_test.go +++ b/models/issues/content_history_test.go @@ -18,18 +18,17 @@ func TestContentHistory(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) dbCtx := db.DefaultContext - dbEngine := db.GetEngine(dbCtx) timeStampNow := timeutil.TimeStampNow() - _ = SaveIssueContentHistory(dbEngine, 1, 10, 0, timeStampNow, "i-a", true) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 0, timeStampNow.Add(2), "i-b", false) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 0, timeStampNow.Add(7), "i-c", false) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow, "i-a", true) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow.Add(2), "i-b", false) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 0, timeStampNow.Add(7), "i-c", false) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 100, timeStampNow, "c-a", true) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 100, timeStampNow.Add(5), "c-b", false) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 100, timeStampNow.Add(20), "c-c", false) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 100, timeStampNow.Add(50), "c-d", false) - _ = SaveIssueContentHistory(dbEngine, 1, 10, 100, timeStampNow.Add(51), "c-e", false) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow, "c-a", true) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(5), "c-b", false) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(20), "c-c", false) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(50), "c-d", false) + _ = SaveIssueContentHistory(dbCtx, 1, 10, 100, timeStampNow.Add(51), "c-e", false) h1, _ := GetIssueContentHistoryByID(dbCtx, 1) assert.EqualValues(t, 1, h1.ID) @@ -47,7 +46,7 @@ func TestContentHistory(t *testing.T) { Name string FullName string } - _ = dbEngine.Sync2(&User{}) + _ = db.GetEngine(dbCtx).Sync2(&User{}) list1, _ := FetchIssueContentHistoryList(dbCtx, 10, 0) assert.Len(t, list1, 3) @@ -70,7 +69,7 @@ func TestContentHistory(t *testing.T) { assert.EqualValues(t, 4, h6Prev.ID) // only keep 3 history revisions for comment_id=100, the first and the last should never be deleted - keepLimitedContentHistory(dbEngine, 10, 100, 3) + keepLimitedContentHistory(dbCtx, 10, 100, 3) list1, _ = FetchIssueContentHistoryList(dbCtx, 10, 0) assert.Len(t, list1, 3) list2, _ = FetchIssueContentHistoryList(dbCtx, 10, 100) diff --git a/models/issues/milestone.go b/models/issues/milestone.go index 07c38754d4..f7172f6448 100644 --- a/models/issues/milestone.go +++ b/models/issues/milestone.go @@ -292,11 +292,11 @@ func DeleteMilestoneByRepoID(repoID, id int64) error { return err } - numMilestones, err := countRepoMilestones(sess, repo.ID) + numMilestones, err := countRepoMilestones(ctx, repo.ID) if err != nil { return err } - numClosedMilestones, err := countRepoClosedMilestones(sess, repo.ID) + numClosedMilestones, err := countRepoClosedMilestones(ctx, repo.ID) if err != nil { return err } @@ -503,21 +503,21 @@ func GetMilestonesStatsByRepoCondAndKw(repoCond builder.Cond, keyword string) (* return stats, nil } -func countRepoMilestones(e db.Engine, repoID int64) (int64, error) { - return e. +func countRepoMilestones(ctx context.Context, repoID int64) (int64, error) { + return db.GetEngine(ctx). Where("repo_id=?", repoID). Count(new(Milestone)) } -func countRepoClosedMilestones(e db.Engine, repoID int64) (int64, error) { - return e. +func countRepoClosedMilestones(ctx context.Context, repoID int64) (int64, error) { + return db.GetEngine(ctx). Where("repo_id=? AND is_closed=?", repoID, true). Count(new(Milestone)) } // CountRepoClosedMilestones returns number of closed milestones in given repository. func CountRepoClosedMilestones(repoID int64) (int64, error) { - return countRepoClosedMilestones(db.GetEngine(db.DefaultContext), repoID) + return countRepoClosedMilestones(db.DefaultContext, repoID) } // CountMilestonesByRepoCond map from repo conditions to number of milestones matching the options` @@ -590,7 +590,7 @@ func updateRepoMilestoneNum(ctx context.Context, repoID int64) error { // |_||_| \__,_|\___|_|\_\___|\__,_| |_| |_|_| |_| |_|\___||___/ // -func (milestones MilestoneList) loadTotalTrackedTimes(e db.Engine) error { +func (milestones MilestoneList) loadTotalTrackedTimes(ctx context.Context) error { type totalTimesByMilestone struct { MilestoneID int64 Time int64 @@ -601,7 +601,7 @@ func (milestones MilestoneList) loadTotalTrackedTimes(e db.Engine) error { trackedTimes := make(map[int64]int64, len(milestones)) // Get total tracked time by milestone_id - rows, err := e.Table("issue"). + rows, err := db.GetEngine(ctx).Table("issue"). Join("INNER", "milestone", "issue.milestone_id = milestone.id"). Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id"). Where("tracked_time.deleted = ?", false). @@ -630,13 +630,13 @@ func (milestones MilestoneList) loadTotalTrackedTimes(e db.Engine) error { return nil } -func (m *Milestone) loadTotalTrackedTime(e db.Engine) error { +func (m *Milestone) loadTotalTrackedTime(ctx context.Context) error { type totalTimesByMilestone struct { MilestoneID int64 Time int64 } totalTime := &totalTimesByMilestone{MilestoneID: m.ID} - has, err := e.Table("issue"). + has, err := db.GetEngine(ctx).Table("issue"). Join("INNER", "milestone", "issue.milestone_id = milestone.id"). Join("LEFT", "tracked_time", "tracked_time.issue_id = issue.id"). Where("tracked_time.deleted = ?", false). @@ -655,10 +655,10 @@ func (m *Milestone) loadTotalTrackedTime(e db.Engine) error { // LoadTotalTrackedTimes loads for every milestone in the list the TotalTrackedTime by a batch request func (milestones MilestoneList) LoadTotalTrackedTimes() error { - return milestones.loadTotalTrackedTimes(db.GetEngine(db.DefaultContext)) + return milestones.loadTotalTrackedTimes(db.DefaultContext) } // LoadTotalTrackedTime loads the tracked time for the milestone func (m *Milestone) LoadTotalTrackedTime() error { - return m.loadTotalTrackedTime(db.GetEngine(db.DefaultContext)) + return m.loadTotalTrackedTime(db.DefaultContext) } diff --git a/models/issues/milestone_test.go b/models/issues/milestone_test.go index 09f51de45c..e087318320 100644 --- a/models/issues/milestone_test.go +++ b/models/issues/milestone_test.go @@ -149,7 +149,7 @@ func TestCountRepoMilestones(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) test := func(repoID int64) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) - count, err := countRepoMilestones(db.GetEngine(db.DefaultContext), repoID) + count, err := countRepoMilestones(db.DefaultContext, repoID) assert.NoError(t, err) assert.EqualValues(t, repo.NumMilestones, count) } @@ -157,7 +157,7 @@ func TestCountRepoMilestones(t *testing.T) { test(2) test(3) - count, err := countRepoMilestones(db.GetEngine(db.DefaultContext), unittest.NonexistentID) + count, err := countRepoMilestones(db.DefaultContext, unittest.NonexistentID) assert.NoError(t, err) assert.EqualValues(t, 0, count) } diff --git a/models/lfs.go b/models/lfs.go index 037ed8556b..d9eea6bb89 100644 --- a/models/lfs.go +++ b/models/lfs.go @@ -142,7 +142,7 @@ func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) { count, err := db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) return count > 0, err } - cond := accessibleRepositoryCondition(user) + cond := repo_model.AccessibleRepositoryCondition(user) count, err := db.GetEngine(db.DefaultContext).Where(cond).Join("INNER", "repository", "`lfs_meta_object`.repository_id = `repository`.id").Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) return count > 0, err } @@ -173,7 +173,7 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6 newMetas := make([]*LFSMetaObject, 0, len(metas)) cond := builder.In( "`lfs_meta_object`.repository_id", - builder.Select("`repository`.id").From("repository").Where(accessibleRepositoryCondition(user)), + builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user)), ) err = sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas) if err != nil { @@ -246,3 +246,12 @@ func CopyLFS(ctx context.Context, newRepo, oldRepo *repo_model.Repository) error return nil } + +// GetRepoLFSSize return a repository's lfs files size +func GetRepoLFSSize(ctx context.Context, repoID int64) (int64, error) { + lfsSize, err := db.GetEngine(ctx).Where("repository_id = ?", repoID).SumInt(new(LFSMetaObject), "size") + if err != nil { + return 0, fmt.Errorf("updateSize: GetLFSMetaObjects: %v", err) + } + return lfsSize, nil +} diff --git a/models/lfs_lock.go b/models/lfs_lock.go index b5f8e4907f..4995305393 100644 --- a/models/lfs_lock.go +++ b/models/lfs_lock.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -171,7 +172,7 @@ func CheckLFSAccessForRepo(ctx context.Context, ownerID int64, repo *repo_model. if err != nil { return err } - perm, err := GetUserRepoPermission(ctx, repo, u) + perm, err := access_model.GetUserRepoPermission(ctx, repo, u) if err != nil { return err } diff --git a/models/migrations/testlogger_test.go b/models/migrations/testlogger_test.go index c087e311c2..adbf19c0db 100644 --- a/models/migrations/testlogger_test.go +++ b/models/migrations/testlogger_test.go @@ -111,7 +111,7 @@ func PrintCurrentTest(t testing.TB, skip ...int) func() { if log.CanColorStdout { fmt.Fprintf(os.Stdout, "+++ %s is a slow test (took %v)\n", fmt.Formatter(log.NewColoredValue(t.Name(), log.Bold, log.FgYellow)), fmt.Formatter(log.NewColoredValue(took, log.Bold, log.FgYellow))) } else { - fmt.Fprintf(os.Stdout, "+++ %s is a slow tets (took %v)\n", t.Name(), took) + fmt.Fprintf(os.Stdout, "+++ %s is a slow test (took %v)\n", t.Name(), took) } } timer := time.AfterFunc(slowFlush, func() { diff --git a/models/migrations/v151.go b/models/migrations/v151.go index ba6eee3440..50314d8162 100644 --- a/models/migrations/v151.go +++ b/models/migrations/v151.go @@ -5,6 +5,7 @@ package migrations import ( + "context" "fmt" "strings" @@ -86,21 +87,23 @@ func setDefaultPasswordToArgon2(x *xorm.Engine) error { } return x.Sync2(new(User)) } + + tempTableName := "tmp_recreate__user" + column.Default = "'argon2'" + + createTableSQL, _, err := x.Dialect().CreateTableSQL(context.Background(), x.DB(), table, tempTableName) + if err != nil { + return err + } + sess := x.NewSession() defer sess.Close() if err := sess.Begin(); err != nil { return err } - - tempTableName := "tmp_recreate__user" - column.Default = "'argon2'" - - createTableSQL, _ := x.Dialect().CreateTableSQL(table, tempTableName) - for _, sql := range createTableSQL { - if _, err := sess.Exec(sql); err != nil { - log.Error("Unable to create table %s. Error: %v\n", tempTableName, err, createTableSQL) - return err - } + if _, err := sess.Exec(createTableSQL); err != nil { + log.Error("Unable to create table %s. Error: %v\n", tempTableName, err, createTableSQL) + return err } for _, index := range table.Indexes { if _, err := sess.Exec(x.Dialect().CreateIndexSQL(tempTableName, index)); err != nil { diff --git a/models/migrations/v165.go b/models/migrations/v165.go index d7df0f07a9..87e1a24f28 100644 --- a/models/migrations/v165.go +++ b/models/migrations/v165.go @@ -24,8 +24,9 @@ func convertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error { SQLType: schemas.SQLType{ Name: "VARCHAR", }, - Length: 16, - Nullable: true, // To keep compatible as nullable + Length: 16, + Nullable: true, // To keep compatible as nullable + DefaultIsEmpty: true, }); err != nil { return err } @@ -49,8 +50,9 @@ func convertHookTaskTypeToVarcharAndTrim(x *xorm.Engine) error { SQLType: schemas.SQLType{ Name: "VARCHAR", }, - Length: 16, - Nullable: true, // To keep compatible as nullable + Length: 16, + Nullable: true, // To keep compatible as nullable + DefaultIsEmpty: true, }); err != nil { return err } diff --git a/models/migrations/v179.go b/models/migrations/v179.go index 735e6b62dd..e6dddef273 100644 --- a/models/migrations/v179.go +++ b/models/migrations/v179.go @@ -21,6 +21,7 @@ func convertAvatarURLToText(x *xorm.Engine) error { SQLType: schemas.SQLType{ Name: schemas.Text, }, - Nullable: true, + Nullable: true, + DefaultIsEmpty: true, }) } diff --git a/models/migrations/v205.go b/models/migrations/v205.go index 755cb10245..7aefa0431a 100644 --- a/models/migrations/v205.go +++ b/models/migrations/v205.go @@ -23,7 +23,8 @@ func migrateUserPasswordSalt(x *xorm.Engine) error { }, Length: 32, // MySQL will like us again. - Nullable: true, + Nullable: true, + DefaultIsEmpty: true, }); err != nil { return err } @@ -33,7 +34,8 @@ func migrateUserPasswordSalt(x *xorm.Engine) error { SQLType: schemas.SQLType{ Name: "VARCHAR", }, - Length: 32, - Nullable: true, + Length: 32, + Nullable: true, + DefaultIsEmpty: true, }) } diff --git a/models/notification.go b/models/notification.go index d0b7852cd2..ac5abc6f92 100644 --- a/models/notification.go +++ b/models/notification.go @@ -119,22 +119,18 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond { } // ToSession will convert the given options to a xorm Session by using the conditions from ToCond and joining with issue table if required -func (opts *FindNotificationOptions) ToSession(e db.Engine) *xorm.Session { - sess := e.Where(opts.ToCond()) +func (opts *FindNotificationOptions) ToSession(ctx context.Context) *xorm.Session { + sess := db.GetEngine(ctx).Where(opts.ToCond()) if opts.Page != 0 { sess = db.SetSessionPagination(sess, opts) } return sess } -func getNotifications(e db.Engine, options *FindNotificationOptions) (nl NotificationList, err error) { - err = options.ToSession(e).OrderBy("notification.updated_unix DESC").Find(&nl) - return -} - // GetNotifications returns all notifications that fit to the given options. -func GetNotifications(opts *FindNotificationOptions) (NotificationList, error) { - return getNotifications(db.GetEngine(db.DefaultContext), opts) +func GetNotifications(ctx context.Context, options *FindNotificationOptions) (nl NotificationList, err error) { + err = options.ToSession(ctx).OrderBy("notification.updated_unix DESC").Find(&nl) + return } // CountNotifications count all notifications that fit to the given options and ignore pagination. @@ -201,15 +197,14 @@ func CreateOrUpdateIssueNotifications(issueID, commentID, notificationAuthorID, } func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, notificationAuthorID, receiverID int64) error { - e := db.GetEngine(ctx) // init var toNotify map[int64]struct{} - notifications, err := getNotificationsByIssueID(e, issueID) + notifications, err := getNotificationsByIssueID(ctx, issueID) if err != nil { return err } - issue, err := getIssueByID(e, issueID) + issue, err := getIssueByID(ctx, issueID) if err != nil { return err } @@ -219,7 +214,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n toNotify[receiverID] = struct{}{} } else { toNotify = make(map[int64]struct{}, 32) - issueWatches, err := getIssueWatchersIDs(e, issueID, true) + issueWatches, err := GetIssueWatchersIDs(ctx, issueID, true) if err != nil { return err } @@ -235,7 +230,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n toNotify[id] = struct{}{} } } - issueParticipants, err := issue.getParticipantIDsByIssue(e) + issueParticipants, err := issue.getParticipantIDsByIssue(ctx) if err != nil { return err } @@ -246,7 +241,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n // dont notify user who cause notification delete(toNotify, notificationAuthorID) // explicit unwatch on issue - issueUnWatches, err := getIssueWatchersIDs(e, issueID, false) + issueUnWatches, err := GetIssueWatchersIDs(ctx, issueID, false) if err != nil { return err } @@ -263,7 +258,7 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n // notify for userID := range toNotify { issue.Repo.Units = nil - user, err := user_model.GetUserByIDEngine(e, userID) + user, err := user_model.GetUserByIDCtx(ctx, userID) if err != nil { if user_model.IsErrUserNotExist(err) { continue @@ -271,28 +266,28 @@ func createOrUpdateIssueNotifications(ctx context.Context, issueID, commentID, n return err } - if issue.IsPull && !checkRepoUnitUser(ctx, issue.Repo, user, unit.TypePullRequests) { + if issue.IsPull && !CheckRepoUnitUser(ctx, issue.Repo, user, unit.TypePullRequests) { continue } - if !issue.IsPull && !checkRepoUnitUser(ctx, issue.Repo, user, unit.TypeIssues) { + if !issue.IsPull && !CheckRepoUnitUser(ctx, issue.Repo, user, unit.TypeIssues) { continue } if notificationExists(notifications, issue.ID, userID) { - if err = updateIssueNotification(e, userID, issue.ID, commentID, notificationAuthorID); err != nil { + if err = updateIssueNotification(ctx, userID, issue.ID, commentID, notificationAuthorID); err != nil { return err } continue } - if err = createIssueNotification(e, userID, issue, commentID, notificationAuthorID); err != nil { + if err = createIssueNotification(ctx, userID, issue, commentID, notificationAuthorID); err != nil { return err } } return nil } -func getNotificationsByIssueID(e db.Engine, issueID int64) (notifications []*Notification, err error) { - err = e. +func getNotificationsByIssueID(ctx context.Context, issueID int64) (notifications []*Notification, err error) { + err = db.GetEngine(ctx). Where("issue_id = ?", issueID). Find(¬ifications) return @@ -308,7 +303,7 @@ func notificationExists(notifications []*Notification, issueID, userID int64) bo return false } -func createIssueNotification(e db.Engine, userID int64, issue *Issue, commentID, updatedByID int64) error { +func createIssueNotification(ctx context.Context, userID int64, issue *Issue, commentID, updatedByID int64) error { notification := &Notification{ UserID: userID, RepoID: issue.RepoID, @@ -324,12 +319,11 @@ func createIssueNotification(e db.Engine, userID int64, issue *Issue, commentID, notification.Source = NotificationSourceIssue } - _, err := e.Insert(notification) - return err + return db.Insert(ctx, notification) } -func updateIssueNotification(e db.Engine, userID, issueID, commentID, updatedByID int64) error { - notification, err := getIssueNotification(e, userID, issueID) +func updateIssueNotification(ctx context.Context, userID, issueID, commentID, updatedByID int64) error { + notification, err := getIssueNotification(ctx, userID, issueID) if err != nil { return err } @@ -346,13 +340,13 @@ func updateIssueNotification(e db.Engine, userID, issueID, commentID, updatedByI cols = []string{"update_by"} } - _, err = e.ID(notification.ID).Cols(cols...).Update(notification) + _, err = db.GetEngine(ctx).ID(notification.ID).Cols(cols...).Update(notification) return err } -func getIssueNotification(e db.Engine, userID, issueID int64) (*Notification, error) { +func getIssueNotification(ctx context.Context, userID, issueID int64) (*Notification, error) { notification := new(Notification) - _, err := e. + _, err := db.GetEngine(ctx). Where("user_id = ?", userID). And("issue_id = ?", issueID). Get(notification) @@ -360,16 +354,12 @@ func getIssueNotification(e db.Engine, userID, issueID int64) (*Notification, er } // NotificationsForUser returns notifications for a given user and status -func NotificationsForUser(user *user_model.User, statuses []NotificationStatus, page, perPage int) (NotificationList, error) { - return notificationsForUser(db.GetEngine(db.DefaultContext), user, statuses, page, perPage) -} - -func notificationsForUser(e db.Engine, user *user_model.User, statuses []NotificationStatus, page, perPage int) (notifications []*Notification, err error) { +func NotificationsForUser(ctx context.Context, user *user_model.User, statuses []NotificationStatus, page, perPage int) (notifications NotificationList, err error) { if len(statuses) == 0 { return } - sess := e. + sess := db.GetEngine(ctx). Where("user_id = ?", user.ID). In("status", statuses). OrderBy("updated_unix DESC") @@ -383,12 +373,8 @@ func notificationsForUser(e db.Engine, user *user_model.User, statuses []Notific } // CountUnread count unread notifications for a user -func CountUnread(user *user_model.User) int64 { - return countUnread(db.GetEngine(db.DefaultContext), user.ID) -} - -func countUnread(e db.Engine, userID int64) int64 { - exist, err := e.Where("user_id = ?", userID).And("status = ?", NotificationStatusUnread).Count(new(Notification)) +func CountUnread(ctx context.Context, userID int64) int64 { + exist, err := db.GetEngine(ctx).Where("user_id = ?", userID).And("status = ?", NotificationStatusUnread).Count(new(Notification)) if err != nil { log.Error("countUnread", err) return 0 @@ -402,17 +388,16 @@ func (n *Notification) LoadAttributes() (err error) { } func (n *Notification) loadAttributes(ctx context.Context) (err error) { - e := db.GetEngine(ctx) if err = n.loadRepo(ctx); err != nil { return } if err = n.loadIssue(ctx); err != nil { return } - if err = n.loadUser(e); err != nil { + if err = n.loadUser(ctx); err != nil { return } - if err = n.loadComment(e); err != nil { + if err = n.loadComment(ctx); err != nil { return } return @@ -430,7 +415,7 @@ func (n *Notification) loadRepo(ctx context.Context) (err error) { func (n *Notification) loadIssue(ctx context.Context) (err error) { if n.Issue == nil && n.IssueID != 0 { - n.Issue, err = getIssueByID(db.GetEngine(ctx), n.IssueID) + n.Issue, err = getIssueByID(ctx, n.IssueID) if err != nil { return fmt.Errorf("getIssueByID [%d]: %v", n.IssueID, err) } @@ -439,9 +424,9 @@ func (n *Notification) loadIssue(ctx context.Context) (err error) { return nil } -func (n *Notification) loadComment(e db.Engine) (err error) { +func (n *Notification) loadComment(ctx context.Context) (err error) { if n.Comment == nil && n.CommentID != 0 { - n.Comment, err = getCommentByID(e, n.CommentID) + n.Comment, err = GetCommentByID(ctx, n.CommentID) if err != nil { if IsErrCommentNotExist(err) { return ErrCommentNotExist{ @@ -455,9 +440,9 @@ func (n *Notification) loadComment(e db.Engine) (err error) { return nil } -func (n *Notification) loadUser(e db.Engine) (err error) { +func (n *Notification) loadUser(ctx context.Context) (err error) { if n.User == nil { - n.User, err = user_model.GetUserByIDEngine(e, n.UserID) + n.User, err = user_model.GetUserByIDCtx(ctx, n.UserID) if err != nil { return fmt.Errorf("getUserByID [%d]: %v", n.UserID, err) } @@ -525,9 +510,9 @@ func (nl NotificationList) getPendingRepoIDs() []int64 { } // LoadRepos loads repositories from database -func (nl NotificationList) LoadRepos() (RepositoryList, []int, error) { +func (nl NotificationList) LoadRepos() (repo_model.RepositoryList, []int, error) { if len(nl) == 0 { - return RepositoryList{}, []int{}, nil + return repo_model.RepositoryList{}, []int{}, nil } repoIDs := nl.getPendingRepoIDs() @@ -563,7 +548,7 @@ func (nl NotificationList) LoadRepos() (RepositoryList, []int, error) { failed := []int{} - reposList := make(RepositoryList, 0, len(repoIDs)) + reposList := make(repo_model.RepositoryList, 0, len(repoIDs)) for i, notification := range nl { if notification.Repository == nil { notification.Repository = repos[notification.RepoID] @@ -739,12 +724,8 @@ func (nl NotificationList) LoadComments() ([]int, error) { } // GetNotificationCount returns the notification count for user -func GetNotificationCount(user *user_model.User, status NotificationStatus) (int64, error) { - return getNotificationCount(db.GetEngine(db.DefaultContext), user, status) -} - -func getNotificationCount(e db.Engine, user *user_model.User, status NotificationStatus) (count int64, err error) { - count, err = e. +func GetNotificationCount(ctx context.Context, user *user_model.User, status NotificationStatus) (count int64, err error) { + count, err = db.GetEngine(ctx). Where("user_id = ?", user.ID). And("status = ?", status). Count(&Notification{}) @@ -766,8 +747,8 @@ func GetUIDsAndNotificationCounts(since, until timeutil.TimeStamp) ([]UserIDCoun return res, db.GetEngine(db.DefaultContext).SQL(sql, since, until, NotificationStatusUnread).Find(&res) } -func setIssueNotificationStatusReadIfUnread(e db.Engine, userID, issueID int64) error { - notification, err := getIssueNotification(e, userID, issueID) +func setIssueNotificationStatusReadIfUnread(ctx context.Context, userID, issueID int64) error { + notification, err := getIssueNotification(ctx, userID, issueID) // ignore if not exists if err != nil { return nil @@ -779,12 +760,13 @@ func setIssueNotificationStatusReadIfUnread(e db.Engine, userID, issueID int64) notification.Status = NotificationStatusRead - _, err = e.ID(notification.ID).Update(notification) + _, err = db.GetEngine(ctx).ID(notification.ID).Update(notification) return err } -func setRepoNotificationStatusReadIfUnread(e db.Engine, userID, repoID int64) error { - _, err := e.Where(builder.Eq{ +// SetRepoReadBy sets repo to be visited by given user. +func SetRepoReadBy(ctx context.Context, userID, repoID int64) error { + _, err := db.GetEngine(ctx).Where(builder.Eq{ "user_id": userID, "status": NotificationStatusUnread, "source": NotificationSourceRepository, @@ -795,7 +777,7 @@ func setRepoNotificationStatusReadIfUnread(e db.Engine, userID, repoID int64) er // SetNotificationStatus change the notification status func SetNotificationStatus(notificationID int64, user *user_model.User, status NotificationStatus) (*Notification, error) { - notification, err := getNotificationByID(db.GetEngine(db.DefaultContext), notificationID) + notification, err := getNotificationByID(db.DefaultContext, notificationID) if err != nil { return notification, err } @@ -812,12 +794,12 @@ func SetNotificationStatus(notificationID int64, user *user_model.User, status N // GetNotificationByID return notification by ID func GetNotificationByID(notificationID int64) (*Notification, error) { - return getNotificationByID(db.GetEngine(db.DefaultContext), notificationID) + return getNotificationByID(db.DefaultContext, notificationID) } -func getNotificationByID(e db.Engine, notificationID int64) (*Notification, error) { +func getNotificationByID(ctx context.Context, notificationID int64) (*Notification, error) { notification := new(Notification) - ok, err := e. + ok, err := db.GetEngine(ctx). Where("id = ?", notificationID). Get(notification) if err != nil { diff --git a/models/notification_test.go b/models/notification_test.go index 3b05f34c55..15c29389c8 100644 --- a/models/notification_test.go +++ b/models/notification_test.go @@ -7,6 +7,7 @@ package models import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -32,7 +33,7 @@ func TestNotificationsForUser(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) statuses := []NotificationStatus{NotificationStatusRead, NotificationStatusUnread} - notfs, err := NotificationsForUser(user, statuses, 1, 10) + notfs, err := NotificationsForUser(db.DefaultContext, user, statuses, 1, 10) assert.NoError(t, err) if assert.Len(t, notfs, 3) { assert.EqualValues(t, 5, notfs[0].ID) @@ -65,11 +66,11 @@ func TestNotification_GetIssue(t *testing.T) { func TestGetNotificationCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - cnt, err := GetNotificationCount(user, NotificationStatusRead) + cnt, err := GetNotificationCount(db.DefaultContext, user, NotificationStatusRead) assert.NoError(t, err) assert.EqualValues(t, 0, cnt) - cnt, err = GetNotificationCount(user, NotificationStatusUnread) + cnt, err = GetNotificationCount(db.DefaultContext, user, NotificationStatusUnread) assert.NoError(t, err) assert.EqualValues(t, 1, cnt) } diff --git a/models/org.go b/models/org.go index 1e5b403f12..009fe758b5 100644 --- a/models/org.go +++ b/models/org.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -53,7 +54,7 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) { Join("LEFT", builder. Select("id as repo_id, owner_id as repo_owner_id"). From("repository"). - Where(accessibleRepositoryCondition(user)), "`repository`.repo_owner_id = `team`.org_id"). + Where(repo_model.AccessibleRepositoryCondition(user)), "`repository`.repo_owner_id = `team`.org_id"). Where("`team_user`.uid = ?", user.ID). GroupBy(groupByStr) @@ -94,7 +95,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error { return nil } - org, err := organization.GetOrgByIDCtx(ctx, orgID) + org, err := organization.GetOrgByID(ctx, orgID) if err != nil { return fmt.Errorf("GetUserByID [%d]: %v", orgID, err) } @@ -119,7 +120,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error { if _, err := sess.ID(ou.ID).Delete(ou); err != nil { return err - } else if _, err = sess.Exec("UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil { + } else if _, err = db.Exec(ctx, "UPDATE `user` SET num_members=num_members-1 WHERE id=?", orgID); err != nil { return err } @@ -133,7 +134,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error { return fmt.Errorf("GetUserRepositories [%d]: %v", userID, err) } for _, repoID := range repoIDs { - if err = repo_model.WatchRepoCtx(ctx, userID, repoID, false); err != nil { + if err = repo_model.WatchRepo(ctx, userID, repoID, false); err != nil { return err } } @@ -142,7 +143,7 @@ func removeOrgUser(ctx context.Context, orgID, userID int64) error { if _, err = sess. Where("user_id = ?", userID). In("repo_id", repoIDs). - Delete(new(Access)); err != nil { + Delete(new(access_model.Access)); err != nil { return err } } diff --git a/models/org_team.go b/models/org_team.go index 695f803dbf..f1d35ee189 100644 --- a/models/org_team.go +++ b/models/org_team.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -33,7 +34,7 @@ func addRepository(ctx context.Context, t *organization.Team, repo *repo_model.R t.NumRepos++ - if err = recalculateTeamAccesses(ctx, repo, 0); err != nil { + if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil { return fmt.Errorf("recalculateAccesses: %v", err) } @@ -43,7 +44,7 @@ func addRepository(ctx context.Context, t *organization.Team, repo *repo_model.R return fmt.Errorf("getMembers: %v", err) } for _, u := range t.Members { - if err = repo_model.WatchRepoCtx(ctx, u.ID, repo.ID, true); err != nil { + if err = repo_model.WatchRepo(ctx, u.ID, repo.ID, true); err != nil { return fmt.Errorf("watchRepo: %v", err) } } @@ -62,7 +63,7 @@ func addAllRepositories(ctx context.Context, t *organization.Team) error { } for _, repo := range orgRepos { - if !hasRepository(ctx, t, repo.ID) { + if !organization.HasTeamRepo(ctx, t.OrgID, t.ID, repo.ID) { if err := addRepository(ctx, t, &repo); err != nil { return fmt.Errorf("addRepository: %v", err) } @@ -108,11 +109,6 @@ func AddRepository(t *organization.Team, repo *repo_model.Repository) (err error return committer.Commit() } -// HasRepository returns true if given repository belong to team. -func HasRepository(t *organization.Team, repoID int64) bool { - return hasRepository(db.DefaultContext, t, repoID) -} - // RemoveAllRepositories removes all repositories from team and recalculates access func RemoveAllRepositories(t *organization.Team) (err error) { if t.IncludesAllRepositories { @@ -138,25 +134,25 @@ func removeAllRepositories(ctx context.Context, t *organization.Team) (err error e := db.GetEngine(ctx) // Delete all accesses. for _, repo := range t.Repos { - if err := recalculateTeamAccesses(ctx, repo, t.ID); err != nil { + if err := access_model.RecalculateTeamAccesses(ctx, repo, t.ID); err != nil { return err } // Remove watches from all users and now unaccessible repos for _, user := range t.Members { - has, err := hasAccess(ctx, user.ID, repo) + has, err := access_model.HasAccess(ctx, user.ID, repo) if err != nil { return err } else if has { continue } - if err = repo_model.WatchRepoCtx(ctx, user.ID, repo.ID, false); err != nil { + if err = repo_model.WatchRepo(ctx, user.ID, repo.ID, false); err != nil { return err } // Remove all IssueWatches a user has subscribed to in the repositories - if err = removeIssueWatchersByRepoID(e, user.ID, repo.ID); err != nil { + if err = removeIssueWatchersByRepoID(ctx, user.ID, repo.ID); err != nil { return err } } @@ -177,8 +173,9 @@ func removeAllRepositories(ctx context.Context, t *organization.Team) (err error return nil } -func hasRepository(ctx context.Context, t *organization.Team, repoID int64) bool { - return organization.HasTeamRepo(ctx, t.OrgID, t.ID, repoID) +// HasRepository returns true if given repository belong to team. +func HasRepository(t *organization.Team, repoID int64) bool { + return organization.HasTeamRepo(db.DefaultContext, t.OrgID, t.ID, repoID) } // removeRepository removes a repository from a team and recalculates access @@ -196,7 +193,7 @@ func removeRepository(ctx context.Context, t *organization.Team, repo *repo_mode // Don't need to recalculate when delete a repository from organization. if recalculate { - if err = recalculateTeamAccesses(ctx, repo, t.ID); err != nil { + if err = access_model.RecalculateTeamAccesses(ctx, repo, t.ID); err != nil { return err } } @@ -206,19 +203,19 @@ func removeRepository(ctx context.Context, t *organization.Team, repo *repo_mode return fmt.Errorf("getTeamUsersByTeamID: %v", err) } for _, teamUser := range teamUsers { - has, err := hasAccess(ctx, teamUser.UID, repo) + has, err := access_model.HasAccess(ctx, teamUser.UID, repo) if err != nil { return err } else if has { continue } - if err = repo_model.WatchRepoCtx(ctx, teamUser.UID, repo.ID, false); err != nil { + if err = repo_model.WatchRepo(ctx, teamUser.UID, repo.ID, false); err != nil { return err } // Remove all IssueWatches a user has subscribed to in the repositories - if err := removeIssueWatchersByRepoID(e, teamUser.UID, repo.ID); err != nil { + if err := removeIssueWatchersByRepoID(ctx, teamUser.UID, repo.ID); err != nil { return err } } @@ -378,7 +375,7 @@ func UpdateTeam(t *organization.Team, authChanged, includeAllChanged bool) (err } for _, repo := range t.Repos { - if err = recalculateTeamAccesses(ctx, repo, 0); err != nil { + if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil { return fmt.Errorf("recalculateTeamAccesses: %v", err) } } @@ -499,6 +496,12 @@ func AddTeamMember(team *organization.Team, userID int64) error { } defer committer.Close() + // check in transaction + isAlreadyMember, err = organization.IsTeamMember(ctx, team.OrgID, team.ID, userID) + if err != nil || isAlreadyMember { + return err + } + sess := db.GetEngine(ctx) if err := db.Insert(ctx, &organization.TeamUser{ @@ -522,7 +525,7 @@ func AddTeamMember(team *organization.Team, userID int64) error { In("repo_id", subQuery). And("mode < ?", team.AccessMode). SetExpr("mode", team.AccessMode). - Update(new(Access)); err != nil { + Update(new(access_model.Access)); err != nil { return fmt.Errorf("update user accesses: %v", err) } @@ -533,9 +536,9 @@ func AddTeamMember(team *organization.Team, userID int64) error { return fmt.Errorf("select id accesses: %v", err) } - accesses := make([]*Access, 0, 100) + accesses := make([]*access_model.Access, 0, 100) for i, repoID := range repoIDs { - accesses = append(accesses, &Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode}) + accesses = append(accesses, &access_model.Access{RepoID: repoID, UserID: userID, Mode: team.AccessMode}) if (i%100 == 0 || i == len(repoIDs)-1) && len(accesses) > 0 { if err = db.Insert(ctx, accesses); err != nil { return fmt.Errorf("insert new user accesses: %v", err) @@ -552,7 +555,7 @@ func AddTeamMember(team *organization.Team, userID int64) error { } go func(repos []*repo_model.Repository) { for _, repo := range repos { - if err = repo_model.WatchRepoCtx(db.DefaultContext, userID, repo.ID, true); err != nil { + if err = repo_model.WatchRepo(db.DefaultContext, userID, repo.ID, true); err != nil { log.Error("watch repo failed: %v", err) } } @@ -595,7 +598,7 @@ func removeTeamMember(ctx context.Context, team *organization.Team, userID int64 // Delete access to team repositories. for _, repo := range team.Repos { - if err := recalculateUserAccess(ctx, repo, userID); err != nil { + if err := access_model.RecalculateUserAccess(ctx, repo, userID); err != nil { return err } diff --git a/models/org_team_test.go b/models/org_team_test.go index e125f3c65b..35ee9af85a 100644 --- a/models/org_team_test.go +++ b/models/org_team_test.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -129,7 +130,7 @@ func TestUpdateTeam(t *testing.T) { team = unittest.AssertExistsAndLoadBean(t, &organization.Team{Name: "newName"}).(*organization.Team) assert.True(t, strings.HasPrefix(team.Description, "A long description!")) - access := unittest.AssertExistsAndLoadBean(t, &Access{UserID: 4, RepoID: 3}).(*Access) + access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: 3}).(*access_model.Access) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) unittest.CheckConsistencyFor(t, &organization.Team{ID: team.ID}) @@ -161,7 +162,7 @@ func TestDeleteTeam(t *testing.T) { // check that team members don't have "leftover" access to repos user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) - accessMode, err := AccessLevel(user, repo) + accessMode, err := access_model.AccessLevel(user, repo) assert.NoError(t, err) assert.True(t, accessMode < perm.AccessModeWrite) } @@ -198,3 +199,21 @@ func TestRemoveTeamMember(t *testing.T) { err := RemoveTeamMember(team, 2) assert.True(t, organization.IsErrLastOrgOwner(err)) } + +func TestRepository_RecalculateAccesses3(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + team5 := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) + user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User) + + has, err := db.GetEngine(db.DefaultContext).Get(&access_model.Access{UserID: 29, RepoID: 23}) + assert.NoError(t, err) + assert.False(t, has) + + // adding user29 to team5 should add an explicit access row for repo 23 + // even though repo 23 is public + assert.NoError(t, AddTeamMember(team5, user29.ID)) + + has, err = db.GetEngine(db.DefaultContext).Get(&access_model.Access{UserID: 29, RepoID: 23}) + assert.NoError(t, err) + assert.True(t, has) +} diff --git a/models/organization/org.go b/models/organization/org.go index 3761335922..0d4a5e337b 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -102,7 +102,7 @@ func (org *Organization) CanCreateOrgRepo(uid int64) (bool, error) { } func (org *Organization) getTeam(ctx context.Context, name string) (*Team, error) { - return getTeam(ctx, org.ID, name) + return GetTeam(ctx, org.ID, name) } // GetTeam returns named team of organization. @@ -203,7 +203,7 @@ func CountOrgMembers(opts *FindOrgMembersOpts) (int64, error) { // FindOrgMembers loads organization members according conditions func FindOrgMembers(opts *FindOrgMembersOpts) (user_model.UserList, map[int64]bool, error) { - ous, err := GetOrgUsersByOrgID(opts) + ous, err := GetOrgUsersByOrgID(db.DefaultContext, opts) if err != nil { return nil, nil, err } @@ -248,7 +248,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) { return err } - isExist, err := user_model.IsUserExist(0, org.Name) + isExist, err := user_model.IsUserExist(db.DefaultContext, 0, org.Name) if err != nil { return err } else if isExist { @@ -281,7 +281,7 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) { if err = db.Insert(ctx, org); err != nil { return fmt.Errorf("insert organization: %v", err) } - if err = user_model.GenerateRandomAvatarCtx(ctx, org.AsUser()); err != nil { + if err = user_model.GenerateRandomAvatar(ctx, org.AsUser()); err != nil { return fmt.Errorf("generate random avatar: %v", err) } @@ -350,14 +350,6 @@ func GetOrgByName(name string) (*Organization, error) { return u, nil } -// CountOrganizations returns number of organizations. -func CountOrganizations() int64 { - count, _ := db.GetEngine(db.DefaultContext). - Where("type=1"). - Count(new(Organization)) - return count -} - // DeleteOrganization deletes models associated to an organization. func DeleteOrganization(ctx context.Context, org *Organization) error { if org.Type != user_model.UserTypeOrganization { @@ -425,7 +417,7 @@ func queryUserOrgIDs(userID int64, includePrivate bool) *builder.Builder { } func (opts FindOrgOptions) toConds() builder.Cond { - cond := builder.NewCond() + var cond builder.Cond = builder.Eq{"`user`.`type`": user_model.UserTypeOrganization} if opts.UserID > 0 { cond = cond.And(builder.In("`user`.`id`", queryUserOrgIDs(opts.UserID, opts.IncludePrivate))) } @@ -451,18 +443,7 @@ func FindOrgs(opts FindOrgOptions) ([]*Organization, error) { func CountOrgs(opts FindOrgOptions) (int64, error) { return db.GetEngine(db.DefaultContext). Where(opts.toConds()). - Count(new(user_model.User)) -} - -func getOwnedOrgsByUserID(sess db.Engine, userID int64) ([]*Organization, error) { - orgs := make([]*Organization, 0, 10) - return orgs, sess. - Join("INNER", "`team_user`", "`team_user`.org_id=`user`.id"). - Join("INNER", "`team`", "`team`.id=`team_user`.team_id"). - Where("`team_user`.uid=?", userID). - And("`team`.authorize=?", perm.AccessModeOwner). - Asc("`user`.name"). - Find(&orgs) + Count(new(Organization)) } // HasOrgOrUserVisible tells if the given user can see the given org or user @@ -496,17 +477,6 @@ func HasOrgsVisible(orgs []*Organization, user *user_model.User) bool { return false } -// GetOwnedOrgsByUserID returns a list of organizations are owned by given user ID. -func GetOwnedOrgsByUserID(userID int64) ([]*Organization, error) { - return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext), userID) -} - -// GetOwnedOrgsByUserIDDesc returns a list of organizations are owned by -// given user ID, ordered descending by the given condition. -func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*Organization, error) { - return getOwnedOrgsByUserID(db.GetEngine(db.DefaultContext).Desc(desc), userID) -} - // GetOrgsCanCreateRepoByUserID returns a list of organizations where given user ID // are allowed to create repos. func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) { @@ -543,12 +513,8 @@ func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUse } // GetOrgUsersByOrgID returns all organization-user relations by organization ID. -func GetOrgUsersByOrgID(opts *FindOrgMembersOpts) ([]*OrgUser, error) { - return getOrgUsersByOrgID(db.GetEngine(db.DefaultContext), opts) -} - -func getOrgUsersByOrgID(e db.Engine, opts *FindOrgMembersOpts) ([]*OrgUser, error) { - sess := e.Where("org_id=?", opts.OrgID) +func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) { + sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) if opts.PublicOnly { sess.And("is_public = ?", true) } @@ -594,6 +560,12 @@ func AddOrgUser(orgID, uid int64) error { } defer committer.Close() + // check in transaction + isAlreadyMember, err = IsOrganizationMember(ctx, orgID, uid) + if err != nil || isAlreadyMember { + return err + } + ou := &OrgUser{ UID: uid, OrgID: orgID, @@ -609,8 +581,8 @@ func AddOrgUser(orgID, uid int64) error { return committer.Commit() } -// GetOrgByIDCtx returns the user object by given ID if exists. -func GetOrgByIDCtx(ctx context.Context, id int64) (*Organization, error) { +// GetOrgByID returns the user object by given ID if exists. +func GetOrgByID(ctx context.Context, id int64) (*Organization, error) { u := new(Organization) has, err := db.GetEngine(ctx).ID(id).Get(u) if err != nil { @@ -625,11 +597,6 @@ func GetOrgByIDCtx(ctx context.Context, id int64) (*Organization, error) { return u, nil } -// GetOrgByID returns the user object by given ID if exists. -func GetOrgByID(id int64) (*Organization, error) { - return GetOrgByIDCtx(db.DefaultContext, id) -} - // RemoveOrgRepo removes all team-repository relations of organization. func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error { teamRepos := make([]*TeamRepo, 0, 10) @@ -658,9 +625,9 @@ func RemoveOrgRepo(ctx context.Context, orgID, repoID int64) error { return err } -func (org *Organization) getUserTeams(e db.Engine, userID int64, cols ...string) ([]*Team, error) { +func (org *Organization) getUserTeams(ctx context.Context, userID int64, cols ...string) ([]*Team, error) { teams := make([]*Team, 0, org.NumTeams) - return teams, e. + return teams, db.GetEngine(ctx). Where("`team_user`.org_id = ?", org.ID). Join("INNER", "team_user", "`team_user`.team_id = team.id"). Join("INNER", "`user`", "`user`.id=team_user.uid"). @@ -694,7 +661,7 @@ func (org *Organization) GetUserTeamIDs(userID int64) ([]int64, error) { // GetUserTeams returns all teams that belong to user, // and that the user has joined. func (org *Organization) GetUserTeams(userID int64) ([]*Team, error) { - return org.getUserTeams(db.GetEngine(db.DefaultContext), userID) + return org.getUserTeams(db.DefaultContext, userID) } // AccessibleReposEnvironment operations involving the repositories that are diff --git a/models/organization/org_test.go b/models/organization/org_test.go index 71cdbd869f..b408a2f36e 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -128,9 +128,11 @@ func TestGetOrgByName(t *testing.T) { func TestCountOrganizations(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&user_model.User{}) + expected, err := db.GetEngine(db.DefaultContext).Where("type=?", user_model.UserTypeOrganization).Count(&Organization{}) assert.NoError(t, err) - assert.Equal(t, expected, CountOrganizations()) + cnt, err := CountOrgs(FindOrgOptions{IncludePrivate: true}) + assert.NoError(t, err) + assert.Equal(t, expected, cnt) } func TestIsOrganizationOwner(t *testing.T) { @@ -204,35 +206,6 @@ func TestFindOrgs(t *testing.T) { assert.EqualValues(t, 1, total) } -func TestGetOwnedOrgsByUserID(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - orgs, err := GetOwnedOrgsByUserID(2) - assert.NoError(t, err) - if assert.Len(t, orgs, 1) { - assert.EqualValues(t, 3, orgs[0].ID) - } - - orgs, err = GetOwnedOrgsByUserID(4) - assert.NoError(t, err) - assert.Len(t, orgs, 0) -} - -func TestGetOwnedOrgsByUserIDDesc(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - orgs, err := GetOwnedOrgsByUserIDDesc(5, "id") - assert.NoError(t, err) - if assert.Len(t, orgs, 2) { - assert.EqualValues(t, 7, orgs[0].ID) - assert.EqualValues(t, 6, orgs[1].ID) - } - - orgs, err = GetOwnedOrgsByUserIDDesc(4, "id") - assert.NoError(t, err) - assert.Len(t, orgs, 0) -} - func TestGetOrgUsersByUserID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) @@ -266,7 +239,7 @@ func TestGetOrgUsersByUserID(t *testing.T) { func TestGetOrgUsersByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - orgUsers, err := GetOrgUsersByOrgID(&FindOrgMembersOpts{ + orgUsers, err := GetOrgUsersByOrgID(db.DefaultContext, &FindOrgMembersOpts{ ListOptions: db.ListOptions{}, OrgID: 3, PublicOnly: false, @@ -287,7 +260,7 @@ func TestGetOrgUsersByOrgID(t *testing.T) { }, *orgUsers[1]) } - orgUsers, err = GetOrgUsersByOrgID(&FindOrgMembersOpts{ + orgUsers, err = GetOrgUsersByOrgID(db.DefaultContext, &FindOrgMembersOpts{ ListOptions: db.ListOptions{}, OrgID: unittest.NonexistentID, PublicOnly: false, diff --git a/models/organization/org_user.go b/models/organization/org_user.go index b679246d0b..a7bc8f7d4c 100644 --- a/models/organization/org_user.go +++ b/models/organization/org_user.go @@ -6,6 +6,7 @@ package organization import ( "context" + "fmt" "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" @@ -81,3 +82,43 @@ func CanCreateOrgRepo(orgID, uid int64) (bool, error) { And("team_user.org_id = ?", orgID). Exist(new(Team)) } + +// IsUserOrgOwner returns true if user is in the owner team of given organization. +func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool { + results := make(map[int64]bool, len(users)) + for _, user := range users { + results[user.ID] = false // Set default to false + } + ownerMaps, err := loadOrganizationOwners(db.DefaultContext, users, orgID) + if err == nil { + for _, owner := range ownerMaps { + results[owner.UID] = true + } + } + return results +} + +func loadOrganizationOwners(ctx context.Context, users user_model.UserList, orgID int64) (map[int64]*TeamUser, error) { + if len(users) == 0 { + return nil, nil + } + ownerTeam, err := GetOwnerTeam(ctx, orgID) + if err != nil { + if IsErrTeamNotExist(err) { + log.Error("Organization does not have owner team: %d", orgID) + return nil, nil + } + return nil, err + } + + userIDs := users.GetUserIDs() + ownerMaps := make(map[int64]*TeamUser) + err = db.GetEngine(ctx).In("uid", userIDs). + And("org_id=?", orgID). + And("team_id=?", ownerTeam.ID). + Find(&ownerMaps) + if err != nil { + return nil, fmt.Errorf("find team users: %v", err) + } + return ownerMaps, nil +} diff --git a/models/organization/org_user_test.go b/models/organization/org_user_test.go index b323002934..1e85f4ed22 100644 --- a/models/organization/org_user_test.go +++ b/models/organization/org_user_test.go @@ -70,3 +70,57 @@ func testIsUserOrgOwner(t *testing.T, uid, orgID int64, expected bool) { assert.NoError(t, err) assert.Equal(t, expected, is) } + +func TestUserListIsPublicMember(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + tt := []struct { + orgid int64 + expected map[int64]bool + }{ + {3, map[int64]bool{2: true, 4: false, 28: true}}, + {6, map[int64]bool{5: true, 28: true}}, + {7, map[int64]bool{5: false}}, + {25, map[int64]bool{24: true}}, + {22, map[int64]bool{}}, + } + for _, v := range tt { + t.Run(fmt.Sprintf("IsPublicMemberOfOrdIg%d", v.orgid), func(t *testing.T) { + testUserListIsPublicMember(t, v.orgid, v.expected) + }) + } +} + +func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) { + org, err := GetOrgByID(db.DefaultContext, orgID) + assert.NoError(t, err) + _, membersIsPublic, err := org.GetMembers() + assert.NoError(t, err) + assert.Equal(t, expected, membersIsPublic) +} + +func TestUserListIsUserOrgOwner(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + tt := []struct { + orgid int64 + expected map[int64]bool + }{ + {3, map[int64]bool{2: true, 4: false, 28: false}}, + {6, map[int64]bool{5: true, 28: false}}, + {7, map[int64]bool{5: true}}, + {25, map[int64]bool{24: false}}, // ErrTeamNotExist + {22, map[int64]bool{}}, // No member + } + for _, v := range tt { + t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrdIg%d", v.orgid), func(t *testing.T) { + testUserListIsUserOrgOwner(t, v.orgid, v.expected) + }) + } +} + +func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) { + org, err := GetOrgByID(db.DefaultContext, orgID) + assert.NoError(t, err) + members, _, err := org.GetMembers() + assert.NoError(t, err) + assert.Equal(t, expected, IsUserOrgOwner(members, orgID)) +} diff --git a/models/organization/team.go b/models/organization/team.go index 077fba6a60..b32ffa6ca7 100644 --- a/models/organization/team.go +++ b/models/organization/team.go @@ -272,7 +272,8 @@ func IsUsableTeamName(name string) error { } } -func getTeam(ctx context.Context, orgID int64, name string) (*Team, error) { +// GetTeam returns team by given team name and organization. +func GetTeam(ctx context.Context, orgID int64, name string) (*Team, error) { t := &Team{ OrgID: orgID, LowerName: strings.ToLower(name), @@ -286,16 +287,11 @@ func getTeam(ctx context.Context, orgID int64, name string) (*Team, error) { return t, nil } -// GetTeam returns team by given team name and organization. -func GetTeam(orgID int64, name string) (*Team, error) { - return getTeam(db.DefaultContext, orgID, name) -} - // GetTeamIDsByNames returns a slice of team ids corresponds to names. func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]int64, error) { ids := make([]int64, 0, len(names)) for _, name := range names { - u, err := GetTeam(orgID, name) + u, err := GetTeam(db.DefaultContext, orgID, name) if err != nil { if ignoreNonExistent { continue @@ -310,11 +306,11 @@ func GetTeamIDsByNames(orgID int64, names []string, ignoreNonExistent bool) ([]i // GetOwnerTeam returns team by given team name and organization. func GetOwnerTeam(ctx context.Context, orgID int64) (*Team, error) { - return getTeam(ctx, orgID, OwnerTeamName) + return GetTeam(ctx, orgID, OwnerTeamName) } -// GetTeamByIDCtx returns team by given ID. -func GetTeamByIDCtx(ctx context.Context, teamID int64) (*Team, error) { +// GetTeamByID returns team by given ID. +func GetTeamByID(ctx context.Context, teamID int64) (*Team, error) { t := new(Team) has, err := db.GetEngine(ctx).ID(teamID).Get(t) if err != nil { @@ -325,11 +321,6 @@ func GetTeamByIDCtx(ctx context.Context, teamID int64) (*Team, error) { return t, nil } -// GetTeamByID returns team by given ID. -func GetTeamByID(teamID int64) (*Team, error) { - return GetTeamByIDCtx(db.DefaultContext, teamID) -} - // GetTeamNamesByID returns team's lower name from a list of team ids. func GetTeamNamesByID(teamIDs []int64) ([]string, error) { if len(teamIDs) == 0 { @@ -346,16 +337,12 @@ func GetTeamNamesByID(teamIDs []int64) ([]string, error) { return teamNames, err } -func getRepoTeams(e db.Engine, repo *repo_model.Repository) (teams []*Team, err error) { - return teams, e. +// GetRepoTeams gets the list of teams that has access to the repository +func GetRepoTeams(ctx context.Context, repo *repo_model.Repository) (teams []*Team, err error) { + return teams, db.GetEngine(ctx). Join("INNER", "team_repo", "team_repo.team_id = team.id"). Where("team.org_id = ?", repo.OwnerID). And("team_repo.repo_id=?", repo.ID). OrderBy("CASE WHEN name LIKE '" + OwnerTeamName + "' THEN '' ELSE name END"). Find(&teams) } - -// GetRepoTeams gets the list of teams that has access to the repository -func GetRepoTeams(repo *repo_model.Repository) ([]*Team, error) { - return getRepoTeams(db.GetEngine(db.DefaultContext), repo) -} diff --git a/models/organization/team_test.go b/models/organization/team_test.go index bbf9f789f6..860a7107ec 100644 --- a/models/organization/team_test.go +++ b/models/organization/team_test.go @@ -71,7 +71,7 @@ func TestGetTeam(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(orgID int64, name string) { - team, err := GetTeam(orgID, name) + team, err := GetTeam(db.DefaultContext, orgID, name) assert.NoError(t, err) assert.EqualValues(t, orgID, team.OrgID) assert.Equal(t, name, team.Name) @@ -79,9 +79,9 @@ func TestGetTeam(t *testing.T) { testSuccess(3, "Owners") testSuccess(3, "team1") - _, err := GetTeam(3, "nonexistent") + _, err := GetTeam(db.DefaultContext, 3, "nonexistent") assert.Error(t, err) - _, err = GetTeam(unittest.NonexistentID, "Owners") + _, err = GetTeam(db.DefaultContext, unittest.NonexistentID, "Owners") assert.Error(t, err) } @@ -89,7 +89,7 @@ func TestGetTeamByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) testSuccess := func(teamID int64) { - team, err := GetTeamByID(teamID) + team, err := GetTeamByID(db.DefaultContext, teamID) assert.NoError(t, err) assert.EqualValues(t, teamID, team.ID) } @@ -98,7 +98,7 @@ func TestGetTeamByID(t *testing.T) { testSuccess(3) testSuccess(4) - _, err := GetTeamByID(unittest.NonexistentID) + _, err := GetTeamByID(db.DefaultContext, unittest.NonexistentID) assert.Error(t, err) } diff --git a/models/access.go b/models/perm/access/access.go similarity index 77% rename from models/access.go rename to models/perm/access/access.go index d49d3430dc..7647519025 100644 --- a/models/access.go +++ b/models/perm/access/access.go @@ -3,7 +3,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package access import ( "context" @@ -30,7 +30,7 @@ func init() { db.RegisterModel(new(Access)) } -func accessLevel(e db.Engine, user *user_model.User, repo *repo_model.Repository) (perm.AccessMode, error) { +func accessLevel(ctx context.Context, user *user_model.User, repo *repo_model.Repository) (perm.AccessMode, error) { mode := perm.AccessModeNone var userID int64 restricted := false @@ -53,7 +53,7 @@ func accessLevel(e db.Engine, user *user_model.User, repo *repo_model.Repository } a := &Access{UserID: userID, RepoID: repo.ID} - if has, err := e.Get(a); !has || err != nil { + if has, err := db.GetByBean(ctx, a); !has || err != nil { return mode, err } return a.Mode, nil @@ -84,7 +84,7 @@ func updateUserAccess(accessMap map[int64]*userAccess, user *user_model.User, mo } // FIXME: do cross-comparison so reduce deletions and additions to the minimum? -func refreshAccesses(e db.Engine, repo *repo_model.Repository, accessMap map[int64]*userAccess) (err error) { +func refreshAccesses(ctx context.Context, repo *repo_model.Repository, accessMap map[int64]*userAccess) (err error) { minMode := perm.AccessModeRead if !repo.IsPrivate { minMode = perm.AccessModeWrite @@ -104,22 +104,22 @@ func refreshAccesses(e db.Engine, repo *repo_model.Repository, accessMap map[int } // Delete old accesses and insert new ones for repository. - if _, err = e.Delete(&Access{RepoID: repo.ID}); err != nil { + if _, err = db.DeleteByBean(ctx, &Access{RepoID: repo.ID}); err != nil { return fmt.Errorf("delete old accesses: %v", err) } if len(newAccesses) == 0 { return nil } - if _, err = e.Insert(newAccesses); err != nil { + if err = db.Insert(ctx, newAccesses); err != nil { return fmt.Errorf("insert new accesses: %v", err) } return nil } // refreshCollaboratorAccesses retrieves repository collaborations with their access modes. -func refreshCollaboratorAccesses(e db.Engine, repoID int64, accessMap map[int64]*userAccess) error { - collaborators, err := getCollaborators(e, repoID, db.ListOptions{}) +func refreshCollaboratorAccesses(ctx context.Context, repoID int64, accessMap map[int64]*userAccess) error { + collaborators, err := repo_model.GetCollaborators(ctx, repoID, db.ListOptions{}) if err != nil { return fmt.Errorf("getCollaborations: %v", err) } @@ -132,10 +132,10 @@ func refreshCollaboratorAccesses(e db.Engine, repoID int64, accessMap map[int64] return nil } -// recalculateTeamAccesses recalculates new accesses for teams of an organization +// RecalculateTeamAccesses recalculates new accesses for teams of an organization // except the team whose ID is given. It is used to assign a team ID when // remove repository from that team. -func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, ignTeamID int64) (err error) { +func RecalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, ignTeamID int64) (err error) { accessMap := make(map[int64]*userAccess, 20) if err = repo.GetOwner(ctx); err != nil { @@ -144,9 +144,7 @@ func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i return fmt.Errorf("owner is not an organization: %d", repo.OwnerID) } - e := db.GetEngine(ctx) - - if err = refreshCollaboratorAccesses(e, repo.ID, accessMap); err != nil { + if err = refreshCollaboratorAccesses(ctx, repo.ID, accessMap); err != nil { return fmt.Errorf("refreshCollaboratorAccesses: %v", err) } @@ -164,7 +162,7 @@ func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i // have relations with repository. if t.IsOwnerTeam() { t.AccessMode = perm.AccessModeOwner - } else if !hasRepository(ctx, t, repo.ID) { + } else if !organization.HasTeamRepo(ctx, t.OrgID, t.ID, repo.ID) { continue } @@ -176,12 +174,12 @@ func recalculateTeamAccesses(ctx context.Context, repo *repo_model.Repository, i } } - return refreshAccesses(e, repo, accessMap) + return refreshAccesses(ctx, repo, accessMap) } -// recalculateUserAccess recalculates new access for a single user +// RecalculateUserAccess recalculates new access for a single user // Usable if we know access only affected one user -func recalculateUserAccess(ctx context.Context, repo *repo_model.Repository, uid int64) (err error) { +func RecalculateUserAccess(ctx context.Context, repo *repo_model.Repository, uid int64) (err error) { minMode := perm.AccessModeRead if !repo.IsPrivate { minMode = perm.AccessModeWrite @@ -189,7 +187,7 @@ func recalculateUserAccess(ctx context.Context, repo *repo_model.Repository, uid accessMode := perm.AccessModeNone e := db.GetEngine(ctx) - collaborator, err := getCollaboration(e, repo.ID, uid) + collaborator, err := repo_model.GetCollaboration(ctx, repo.ID, uid) if err != nil { return err } else if collaborator != nil { @@ -222,27 +220,22 @@ func recalculateUserAccess(ctx context.Context, repo *repo_model.Repository, uid if _, err = e.Delete(&Access{RepoID: repo.ID, UserID: uid}); err != nil { return fmt.Errorf("delete old user accesses: %v", err) } else if accessMode >= minMode { - if _, err = e.Insert(&Access{RepoID: repo.ID, UserID: uid, Mode: accessMode}); err != nil { + if err = db.Insert(ctx, &Access{RepoID: repo.ID, UserID: uid, Mode: accessMode}); err != nil { return fmt.Errorf("insert new user accesses: %v", err) } } return nil } -func recalculateAccesses(ctx context.Context, repo *repo_model.Repository) error { +// RecalculateAccesses recalculates all accesses for repository. +func RecalculateAccesses(ctx context.Context, repo *repo_model.Repository) error { if repo.Owner.IsOrganization() { - return recalculateTeamAccesses(ctx, repo, 0) + return RecalculateTeamAccesses(ctx, repo, 0) } - e := db.GetEngine(ctx) accessMap := make(map[int64]*userAccess, 20) - if err := refreshCollaboratorAccesses(e, repo.ID, accessMap); err != nil { + if err := refreshCollaboratorAccesses(ctx, repo.ID, accessMap); err != nil { return fmt.Errorf("refreshCollaboratorAccesses: %v", err) } - return refreshAccesses(e, repo, accessMap) -} - -// RecalculateAccesses recalculates all accesses for repository. -func RecalculateAccesses(repo *repo_model.Repository) error { - return recalculateAccesses(db.DefaultContext, repo) + return refreshAccesses(ctx, repo, accessMap) } diff --git a/models/access_test.go b/models/perm/access/access_test.go similarity index 77% rename from models/access_test.go rename to models/perm/access/access_test.go index 7533381dca..a9ae9a30f4 100644 --- a/models/access_test.go +++ b/models/perm/access/access_test.go @@ -2,13 +2,12 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package access import ( "testing" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" @@ -80,17 +79,17 @@ func TestHasAccess(t *testing.T) { repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) assert.True(t, repo2.IsPrivate) - has, err := HasAccess(user1.ID, repo1) + has, err := HasAccess(db.DefaultContext, user1.ID, repo1) assert.NoError(t, err) assert.True(t, has) - _, err = HasAccess(user1.ID, repo2) + _, err = HasAccess(db.DefaultContext, user1.ID, repo2) assert.NoError(t, err) - _, err = HasAccess(user2.ID, repo1) + _, err = HasAccess(db.DefaultContext, user2.ID, repo1) assert.NoError(t, err) - _, err = HasAccess(user2.ID, repo2) + _, err = HasAccess(db.DefaultContext, user2.ID, repo2) assert.NoError(t, err) } @@ -100,9 +99,9 @@ func TestRepository_RecalculateAccesses(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) assert.NoError(t, repo1.GetOwner(db.DefaultContext)) - _, err := db.GetEngine(db.DefaultContext).Delete(&Collaboration{UserID: 2, RepoID: 3}) + _, err := db.GetEngine(db.DefaultContext).Delete(&repo_model.Collaboration{UserID: 2, RepoID: 3}) assert.NoError(t, err) - assert.NoError(t, RecalculateAccesses(repo1)) + assert.NoError(t, RecalculateAccesses(db.DefaultContext, repo1)) access := &Access{UserID: 2, RepoID: 3} has, err := db.GetEngine(db.DefaultContext).Get(access) @@ -117,29 +116,11 @@ func TestRepository_RecalculateAccesses2(t *testing.T) { repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) assert.NoError(t, repo1.GetOwner(db.DefaultContext)) - _, err := db.GetEngine(db.DefaultContext).Delete(&Collaboration{UserID: 4, RepoID: 4}) + _, err := db.GetEngine(db.DefaultContext).Delete(&repo_model.Collaboration{UserID: 4, RepoID: 4}) assert.NoError(t, err) - assert.NoError(t, RecalculateAccesses(repo1)) + assert.NoError(t, RecalculateAccesses(db.DefaultContext, repo1)) has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 4, RepoID: 4}) assert.NoError(t, err) assert.False(t, has) } - -func TestRepository_RecalculateAccesses3(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - team5 := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) - user29 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 29}).(*user_model.User) - - has, err := db.GetEngine(db.DefaultContext).Get(&Access{UserID: 29, RepoID: 23}) - assert.NoError(t, err) - assert.False(t, has) - - // adding user29 to team5 should add an explicit access row for repo 23 - // even though repo 23 is public - assert.NoError(t, AddTeamMember(team5, user29.ID)) - - has, err = db.GetEngine(db.DefaultContext).Get(&Access{UserID: 29, RepoID: 23}) - assert.NoError(t, err) - assert.True(t, has) -} diff --git a/models/perm/access/main_test.go b/models/perm/access/main_test.go new file mode 100644 index 0000000000..153ac2540d --- /dev/null +++ b/models/perm/access/main_test.go @@ -0,0 +1,32 @@ +// Copyright 2020 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package access + +import ( + "path/filepath" + "testing" + + "code.gitea.io/gitea/models/unittest" + + _ "code.gitea.io/gitea/models/repo" +) + +func TestMain(m *testing.M) { + unittest.MainTest(m, &unittest.TestOptions{ + GiteaRootPath: filepath.Join("..", "..", ".."), + FixtureFiles: []string{ + "access.yml", + "user.yml", + "repository.yml", + "collaboration.yml", + "org_user.yml", + "repo_unit.yml", + "team_user.yml", + "team_repo.yml", + "team.yml", + "team_unit.yml", + }, + }) +} diff --git a/models/repo_permission.go b/models/perm/access/repo_permission.go similarity index 83% rename from models/repo_permission.go rename to models/perm/access/repo_permission.go index 8ba6b86145..6bc1c82703 100644 --- a/models/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package access import ( "context" @@ -103,39 +103,6 @@ func (p *Permission) CanWriteIssuesOrPulls(isPull bool) bool { return p.CanWrite(unit.TypeIssues) } -// CanWriteToBranch checks if the branch is writable by the user -func (p *Permission) CanWriteToBranch(user *user_model.User, branch string) bool { - if p.CanWrite(unit.TypeCode) { - return true - } - - if len(p.Units) < 1 { - return false - } - - prs, err := GetUnmergedPullRequestsByHeadInfo(p.Units[0].RepoID, branch) - if err != nil { - return false - } - - for _, pr := range prs { - if pr.AllowMaintainerEdit { - err = pr.LoadBaseRepo() - if err != nil { - continue - } - prPerm, err := GetUserRepoPermission(db.DefaultContext, pr.BaseRepo, user) - if err != nil { - continue - } - if prPerm.CanWrite(unit.TypeCode) { - return true - } - } - } - return false -} - // ColorFormat writes a colored string for these Permissions func (p *Permission) ColorFormat(s fmt.State) { noColor := log.ColorBytes(log.Reset) @@ -201,11 +168,9 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use return } - e := db.GetEngine(ctx) - var is bool if user != nil { - is, err = isCollaborator(e, repo.ID, user.ID) + is, err = repo_model.IsCollaborator(ctx, repo.ID, user.ID) if err != nil { return perm, err } @@ -241,7 +206,7 @@ func GetUserRepoPermission(ctx context.Context, repo *repo_model.Repository, use } // plain user - perm.AccessMode, err = accessLevel(e, user, repo) + perm.AccessMode, err = accessLevel(ctx, user, repo) if err != nil { return } @@ -321,7 +286,7 @@ func IsUserRealRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bo return false, err } - accessMode, err := accessLevel(db.GetEngine(db.DefaultContext), user, repo) + accessMode, err := accessLevel(db.DefaultContext, user, repo) if err != nil { return false, err } @@ -330,12 +295,7 @@ func IsUserRealRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bo } // IsUserRepoAdmin return true if user has admin right of a repo -func IsUserRepoAdmin(repo *repo_model.Repository, user *user_model.User) (bool, error) { - return IsUserRepoAdminCtx(db.DefaultContext, repo, user) -} - -// IsUserRepoAdminCtx return true if user has admin right of a repo -func IsUserRepoAdminCtx(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (bool, error) { +func IsUserRepoAdmin(ctx context.Context, repo *repo_model.Repository, user *user_model.User) (bool, error) { if user == nil || repo == nil { return false, nil } @@ -343,8 +303,7 @@ func IsUserRepoAdminCtx(ctx context.Context, repo *repo_model.Repository, user * return true, nil } - e := db.GetEngine(ctx) - mode, err := accessLevel(e, user, repo) + mode, err := accessLevel(ctx, user, repo) if err != nil { return false, err } @@ -367,13 +326,13 @@ func IsUserRepoAdminCtx(ctx context.Context, repo *repo_model.Repository, user * // AccessLevel returns the Access a user has to a repository. Will return NoneAccess if the // user does not have access. -func AccessLevel(user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { - return accessLevelUnit(db.DefaultContext, user, repo, unit.TypeCode) +func AccessLevel(user *user_model.User, repo *repo_model.Repository) (perm_model.AccessMode, error) { //nolint + return AccessLevelUnit(user, repo, unit.TypeCode) } // AccessLevelUnit returns the Access a user has to a repository's. Will return NoneAccess if the // user does not have access. -func AccessLevelUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { +func AccessLevelUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type) (perm_model.AccessMode, error) { //nolint return accessLevelUnit(db.DefaultContext, user, repo, unitType) } @@ -385,24 +344,16 @@ func accessLevelUnit(ctx context.Context, user *user_model.User, repo *repo_mode return perm.UnitAccessMode(unitType), nil } -func hasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { +// HasAccessUnit returns true if user has testMode to the unit of the repository +func HasAccessUnit(ctx context.Context, user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { mode, err := accessLevelUnit(ctx, user, repo, unitType) return testMode <= mode, err } -// HasAccessUnit returns true if user has testMode to the unit of the repository -func HasAccessUnit(user *user_model.User, repo *repo_model.Repository, unitType unit.Type, testMode perm_model.AccessMode) (bool, error) { - return hasAccessUnit(db.DefaultContext, user, repo, unitType, testMode) -} - // CanBeAssigned return true if user can be assigned to issue or pull requests in repo // Currently any write access (code, issues or pr's) is assignable, to match assignee list in user interface. // FIXME: user could send PullRequest also could be assigned??? -func CanBeAssigned(user *user_model.User, repo *repo_model.Repository, isPull bool) (bool, error) { - return canBeAssigned(db.DefaultContext, user, repo, isPull) -} - -func canBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) { +func CanBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model.Repository, _ bool) (bool, error) { if user.IsOrganization() { return false, fmt.Errorf("Organization can't be added as assignee [user_id: %d, repo_id: %d]", user.ID, repo.ID) } @@ -413,11 +364,12 @@ func canBeAssigned(ctx context.Context, user *user_model.User, repo *repo_model. return perm.CanAccessAny(perm_model.AccessModeWrite, unit.TypeCode, unit.TypeIssues, unit.TypePullRequests), nil } -func hasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) { +// HasAccess returns true if user has access to repo +func HasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) (bool, error) { var user *user_model.User var err error if userID > 0 { - user, err = user_model.GetUserByIDEngine(db.GetEngine(ctx), userID) + user, err = user_model.GetUserByIDCtx(ctx, userID) if err != nil { return false, err } @@ -429,9 +381,36 @@ func hasAccess(ctx context.Context, userID int64, repo *repo_model.Repository) ( return perm.HasAccess(), nil } -// HasAccess returns true if user has access to repo -func HasAccess(userID int64, repo *repo_model.Repository) (bool, error) { - return hasAccess(db.DefaultContext, userID, repo) +// getUsersWithAccessMode returns users that have at least given access mode to the repository. +func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm_model.AccessMode) (_ []*user_model.User, err error) { + if err = repo.GetOwner(ctx); err != nil { + return nil, err + } + + e := db.GetEngine(ctx) + accesses := make([]*Access, 0, 10) + if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil { + return nil, err + } + + // Leave a seat for owner itself to append later, but if owner is an organization + // and just waste 1 unit is cheaper than re-allocate memory once. + users := make([]*user_model.User, 0, len(accesses)+1) + if len(accesses) > 0 { + userIDs := make([]int64, len(accesses)) + for i := 0; i < len(accesses); i++ { + userIDs[i] = accesses[i].UserID + } + + if err = e.In("id", userIDs).Find(&users); err != nil { + return nil, err + } + } + if !repo.Owner.IsOrganization() { + users = append(users, repo.Owner) + } + + return users, nil } // GetRepoReaders returns all users that have explicit read access or higher to the repository. diff --git a/models/project/board.go b/models/project/board.go index f770a18f59..be7119ee4d 100644 --- a/models/project/board.go +++ b/models/project/board.go @@ -147,8 +147,7 @@ func DeleteBoardByID(boardID int64) error { } func deleteBoardByID(ctx context.Context, boardID int64) error { - e := db.GetEngine(ctx) - board, err := getBoard(e, boardID) + board, err := GetBoard(ctx, boardID) if err != nil { if IsErrProjectBoardNotExist(err) { return nil @@ -157,30 +156,26 @@ func deleteBoardByID(ctx context.Context, boardID int64) error { return err } - if err = board.removeIssues(e); err != nil { + if err = board.removeIssues(ctx); err != nil { return err } - if _, err := e.ID(board.ID).Delete(board); err != nil { + if _, err := db.GetEngine(ctx).ID(board.ID).NoAutoCondition().Delete(board); err != nil { return err } return nil } -func deleteBoardByProjectID(e db.Engine, projectID int64) error { - _, err := e.Where("project_id=?", projectID).Delete(&Board{}) +func deleteBoardByProjectID(ctx context.Context, projectID int64) error { + _, err := db.GetEngine(ctx).Where("project_id=?", projectID).Delete(&Board{}) return err } // GetBoard fetches the current board of a project -func GetBoard(boardID int64) (*Board, error) { - return getBoard(db.GetEngine(db.DefaultContext), boardID) -} - -func getBoard(e db.Engine, boardID int64) (*Board, error) { +func GetBoard(ctx context.Context, boardID int64) (*Board, error) { board := new(Board) - has, err := e.ID(boardID).Get(board) + has, err := db.GetEngine(ctx).ID(boardID).Get(board) if err != nil { return nil, err } else if !has { @@ -191,11 +186,7 @@ func getBoard(e db.Engine, boardID int64) (*Board, error) { } // UpdateBoard updates a project board -func UpdateBoard(board *Board) error { - return updateBoard(db.GetEngine(db.DefaultContext), board) -} - -func updateBoard(e db.Engine, board *Board) error { +func UpdateBoard(ctx context.Context, board *Board) error { var fieldToUpdate []string if board.Sorting != 0 { @@ -211,25 +202,21 @@ func updateBoard(e db.Engine, board *Board) error { } fieldToUpdate = append(fieldToUpdate, "color") - _, err := e.ID(board.ID).Cols(fieldToUpdate...).Update(board) + _, err := db.GetEngine(ctx).ID(board.ID).Cols(fieldToUpdate...).Update(board) return err } // GetBoards fetches all boards related to a project // if no default board set, first board is a temporary "Uncategorized" board -func GetBoards(projectID int64) (BoardList, error) { - return getBoards(db.GetEngine(db.DefaultContext), projectID) -} - -func getBoards(e db.Engine, projectID int64) ([]*Board, error) { +func GetBoards(ctx context.Context, projectID int64) (BoardList, error) { boards := make([]*Board, 0, 5) - if err := e.Where("project_id=? AND `default`=?", projectID, false).OrderBy("Sorting").Find(&boards); err != nil { + if err := db.GetEngine(ctx).Where("project_id=? AND `default`=?", projectID, false).OrderBy("Sorting").Find(&boards); err != nil { return nil, err } - defaultB, err := getDefaultBoard(e, projectID) + defaultB, err := getDefaultBoard(ctx, projectID) if err != nil { return nil, err } @@ -238,9 +225,9 @@ func getBoards(e db.Engine, projectID int64) ([]*Board, error) { } // getDefaultBoard return default board and create a dummy if none exist -func getDefaultBoard(e db.Engine, projectID int64) (*Board, error) { +func getDefaultBoard(ctx context.Context, projectID int64) (*Board, error) { var board Board - exist, err := e.Where("project_id=? AND `default`=?", projectID, true).Get(&board) + exist, err := db.GetEngine(ctx).Where("project_id=? AND `default`=?", projectID, true).Get(&board) if err != nil { return nil, err } diff --git a/models/project/issue.go b/models/project/issue.go index 6bde91668f..04efc0e749 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -28,8 +28,8 @@ func init() { db.RegisterModel(new(ProjectIssue)) } -func deleteProjectIssuesByProjectID(e db.Engine, projectID int64) error { - _, err := e.Where("project_id=?", projectID).Delete(&ProjectIssue{}) +func deleteProjectIssuesByProjectID(ctx context.Context, projectID int64) error { + _, err := db.GetEngine(ctx).Where("project_id=?", projectID).Delete(&ProjectIssue{}) return err } @@ -97,7 +97,7 @@ func MoveIssuesOnProjectBoard(board *Board, sortedIssueIDs map[int64]int64) erro }) } -func (pb *Board) removeIssues(e db.Engine) error { - _, err := e.Exec("UPDATE `project_issue` SET project_board_id = 0 WHERE project_board_id = ? ", pb.ID) +func (pb *Board) removeIssues(ctx context.Context) error { + _, err := db.GetEngine(ctx).Exec("UPDATE `project_issue` SET project_board_id = 0 WHERE project_board_id = ? ", pb.ID) return err } diff --git a/models/project/project.go b/models/project/project.go index a639879e78..0aa37cc5c9 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -121,12 +121,7 @@ type SearchOptions struct { } // GetProjects returns a list of all projects that have been created in the repository -func GetProjects(opts SearchOptions) ([]*Project, int64, error) { - return GetProjectsCtx(db.DefaultContext, opts) -} - -// GetProjectsCtx returns a list of all projects that have been created in the repository -func GetProjectsCtx(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) { +func GetProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) { e := db.GetEngine(ctx) projects := make([]*Project, 0, setting.UI.IssuePagingNum) @@ -199,14 +194,10 @@ func NewProject(p *Project) error { } // GetProjectByID returns the projects in a repository -func GetProjectByID(id int64) (*Project, error) { - return getProjectByID(db.GetEngine(db.DefaultContext), id) -} - -func getProjectByID(e db.Engine, id int64) (*Project, error) { +func GetProjectByID(ctx context.Context, id int64) (*Project, error) { p := new(Project) - has, err := e.ID(id).Get(p) + has, err := db.GetEngine(ctx).ID(id).Get(p) if err != nil { return nil, err } else if !has { @@ -217,20 +208,16 @@ func getProjectByID(e db.Engine, id int64) (*Project, error) { } // UpdateProject updates project properties -func UpdateProject(p *Project) error { - return updateProject(db.GetEngine(db.DefaultContext), p) -} - -func updateProject(e db.Engine, p *Project) error { - _, err := e.ID(p.ID).Cols( +func UpdateProject(ctx context.Context, p *Project) error { + _, err := db.GetEngine(ctx).ID(p.ID).Cols( "title", "description", ).Update(p) return err } -func updateRepositoryProjectCount(e db.Engine, repoID int64) error { - if _, err := e.Exec(builder.Update( +func updateRepositoryProjectCount(ctx context.Context, repoID int64) error { + if _, err := db.GetEngine(ctx).Exec(builder.Update( builder.Eq{ "`num_projects`": builder.Select("count(*)").From("`project`"). Where(builder.Eq{"`project`.`repo_id`": repoID}. @@ -239,7 +226,7 @@ func updateRepositoryProjectCount(e db.Engine, repoID int64) error { return err } - if _, err := e.Exec(builder.Update( + if _, err := db.GetEngine(ctx).Exec(builder.Update( builder.Eq{ "`num_closed_projects`": builder.Select("count(*)").From("`project`"). Where(builder.Eq{"`project`.`repo_id`": repoID}. @@ -293,8 +280,7 @@ func ChangeProjectStatus(p *Project, isClosed bool) error { func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error { p.IsClosed = isClosed p.ClosedDateUnix = timeutil.TimeStampNow() - e := db.GetEngine(ctx) - count, err := e.ID(p.ID).Where("repo_id = ? AND is_closed = ?", p.RepoID, !isClosed).Cols("is_closed", "closed_date_unix").Update(p) + count, err := db.GetEngine(ctx).ID(p.ID).Where("repo_id = ? AND is_closed = ?", p.RepoID, !isClosed).Cols("is_closed", "closed_date_unix").Update(p) if err != nil { return err } @@ -302,7 +288,7 @@ func changeProjectStatus(ctx context.Context, p *Project, isClosed bool) error { return nil } - return updateRepositoryProjectCount(e, p.RepoID) + return updateRepositoryProjectCount(ctx, p.RepoID) } // DeleteProjectByID deletes a project from a repository. @@ -322,8 +308,7 @@ func DeleteProjectByID(id int64) error { // DeleteProjectByIDCtx deletes a project from a repository. func DeleteProjectByIDCtx(ctx context.Context, id int64) error { - e := db.GetEngine(ctx) - p, err := getProjectByID(e, id) + p, err := GetProjectByID(ctx, id) if err != nil { if IsErrProjectNotExist(err) { return nil @@ -331,17 +316,17 @@ func DeleteProjectByIDCtx(ctx context.Context, id int64) error { return err } - if err := deleteProjectIssuesByProjectID(e, id); err != nil { + if err := deleteProjectIssuesByProjectID(ctx, id); err != nil { return err } - if err := deleteBoardByProjectID(e, id); err != nil { + if err := deleteBoardByProjectID(ctx, id); err != nil { return err } - if _, err = e.ID(p.ID).Delete(new(Project)); err != nil { + if _, err = db.GetEngine(ctx).ID(p.ID).Delete(new(Project)); err != nil { return err } - return updateRepositoryProjectCount(e, p.RepoID) + return updateRepositoryProjectCount(ctx, p.RepoID) } diff --git a/models/project/project_test.go b/models/project/project_test.go index 211a890874..f33fb3351a 100644 --- a/models/project/project_test.go +++ b/models/project/project_test.go @@ -7,6 +7,7 @@ package project import ( "testing" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/timeutil" @@ -34,13 +35,13 @@ func TestIsProjectTypeValid(t *testing.T) { func TestGetProjects(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - projects, _, err := GetProjects(SearchOptions{RepoID: 1}) + projects, _, err := GetProjects(db.DefaultContext, SearchOptions{RepoID: 1}) assert.NoError(t, err) // 1 value for this repo exists in the fixtures assert.Len(t, projects, 1) - projects, _, err = GetProjects(SearchOptions{RepoID: 3}) + projects, _, err = GetProjects(db.DefaultContext, SearchOptions{RepoID: 3}) assert.NoError(t, err) // 1 value for this repo exists in the fixtures @@ -61,14 +62,14 @@ func TestProject(t *testing.T) { assert.NoError(t, NewProject(project)) - _, err := GetProjectByID(project.ID) + _, err := GetProjectByID(db.DefaultContext, project.ID) assert.NoError(t, err) // Update project project.Title = "Updated title" - assert.NoError(t, UpdateProject(project)) + assert.NoError(t, UpdateProject(db.DefaultContext, project)) - projectFromDB, err := GetProjectByID(project.ID) + projectFromDB, err := GetProjectByID(db.DefaultContext, project.ID) assert.NoError(t, err) assert.Equal(t, project.Title, projectFromDB.Title) @@ -76,7 +77,7 @@ func TestProject(t *testing.T) { assert.NoError(t, ChangeProjectStatus(project, true)) // Retrieve from DB afresh to check if it is truly closed - projectFromDB, err = GetProjectByID(project.ID) + projectFromDB, err = GetProjectByID(db.DefaultContext, project.ID) assert.NoError(t, err) assert.True(t, projectFromDB.IsClosed) diff --git a/models/pull.go b/models/pull.go index 8eab7569cd..df96e2dc74 100644 --- a/models/pull.go +++ b/models/pull.go @@ -97,22 +97,22 @@ func init() { db.RegisterModel(new(PullRequest)) } -func deletePullsByBaseRepoID(sess db.Engine, repoID int64) error { +func deletePullsByBaseRepoID(ctx context.Context, repoID int64) error { deleteCond := builder.Select("id").From("pull_request").Where(builder.Eq{"pull_request.base_repo_id": repoID}) // Delete scheduled auto merges - if _, err := sess.In("pull_id", deleteCond). + if _, err := db.GetEngine(ctx).In("pull_id", deleteCond). Delete(&pull_model.AutoMerge{}); err != nil { return err } // Delete review states - if _, err := sess.In("pull_id", deleteCond). + if _, err := db.GetEngine(ctx).In("pull_id", deleteCond). Delete(&pull_model.ReviewState{}); err != nil { return err } - _, err := sess.Delete(&PullRequest{BaseRepoID: repoID}) + _, err := db.DeleteByBean(ctx, &PullRequest{BaseRepoID: repoID}) return err } @@ -133,9 +133,9 @@ func (pr *PullRequest) MustHeadUserName() string { } // Note: don't try to get Issue because will end up recursive querying. -func (pr *PullRequest) loadAttributes(e db.Engine) (err error) { +func (pr *PullRequest) loadAttributes(ctx context.Context) (err error) { if pr.HasMerged && pr.Merger == nil { - pr.Merger, err = user_model.GetUserByIDEngine(e, pr.MergerID) + pr.Merger, err = user_model.GetUserByIDCtx(ctx, pr.MergerID) if user_model.IsErrUserNotExist(err) { pr.MergerID = -1 pr.Merger = user_model.NewGhostUser() @@ -149,7 +149,7 @@ func (pr *PullRequest) loadAttributes(e db.Engine) (err error) { // LoadAttributes loads pull request attributes from database func (pr *PullRequest) LoadAttributes() error { - return pr.loadAttributes(db.GetEngine(db.DefaultContext)) + return pr.loadAttributes(db.DefaultContext) } // LoadHeadRepoCtx loads the head repository @@ -218,7 +218,7 @@ func (pr *PullRequest) LoadIssueCtx(ctx context.Context) (err error) { return nil } - pr.Issue, err = getIssueByID(db.GetEngine(ctx), pr.IssueID) + pr.Issue, err = getIssueByID(ctx, pr.IssueID) if err == nil { pr.Issue.PullRequest = pr } @@ -242,7 +242,7 @@ func (pr *PullRequest) LoadProtectedBranchCtx(ctx context.Context) (err error) { return } } - pr.ProtectedBranch, err = getProtectedBranchBy(db.GetEngine(ctx), pr.BaseRepo.ID, pr.BaseBranch) + pr.ProtectedBranch, err = GetProtectedBranchBy(ctx, pr.BaseRepo.ID, pr.BaseBranch) } return } @@ -256,13 +256,9 @@ type ReviewCount struct { // GetApprovalCounts returns the approval counts by type // FIXME: Only returns official counts due to double counting of non-official counts -func (pr *PullRequest) GetApprovalCounts() ([]*ReviewCount, error) { - return pr.getApprovalCounts(db.GetEngine(db.DefaultContext)) -} - -func (pr *PullRequest) getApprovalCounts(e db.Engine) ([]*ReviewCount, error) { +func (pr *PullRequest) GetApprovalCounts(ctx context.Context) ([]*ReviewCount, error) { rCounts := make([]*ReviewCount, 0, 6) - sess := e.Where("issue_id = ?", pr.IssueID) + sess := db.GetEngine(ctx).Where("issue_id = ?", pr.IssueID) return rCounts, sess.Select("issue_id, type, count(id) as `count`").Where("official = ? AND dismissed = ?", true, false).GroupBy("issue_id, type").Table("review").Find(&rCounts) } @@ -289,10 +285,9 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error { return err } defer committer.Close() - sess := db.GetEngine(ctx) // Note: This doesn't page as we only expect a very limited number of reviews - reviews, err := findReviews(sess, FindReviewOptions{ + reviews, err := FindReviews(ctx, FindReviewOptions{ Type: ReviewTypeApprove, IssueID: pr.IssueID, OfficialOnly: setting.Repository.PullRequest.DefaultMergeMessageOfficialApproversOnly, @@ -309,7 +304,7 @@ func (pr *PullRequest) getReviewedByLines(writer io.Writer) error { break } - if err := review.loadReviewer(sess); err != nil && !user_model.IsErrUserNotExist(err) { + if err := review.loadReviewer(ctx); err != nil && !user_model.IsErrUserNotExist(err) { log.Error("Unable to LoadReviewer[%d] for PR ID %d : %v", review.ReviewerID, pr.ID, err) return err } else if review.Reviewer == nil { @@ -374,7 +369,7 @@ func (pr *PullRequest) SetMerged(ctx context.Context) (bool, error) { return false, err } - if tmpPr, err := getPullRequestByID(sess, pr.ID); err != nil { + if tmpPr, err := GetPullRequestByID(ctx, pr.ID); err != nil { return false, err } else if tmpPr.HasMerged { if pr.Issue.IsClosed { @@ -484,12 +479,7 @@ func GetLatestPullRequestByHeadInfo(repoID int64, branch string) (*PullRequest, } // GetPullRequestByIndex returns a pull request by the given index -func GetPullRequestByIndex(repoID, index int64) (*PullRequest, error) { - return GetPullRequestByIndexCtx(db.DefaultContext, repoID, index) -} - -// GetPullRequestByIndexCtx returns a pull request by the given index -func GetPullRequestByIndexCtx(ctx context.Context, repoID, index int64) (*PullRequest, error) { +func GetPullRequestByIndex(ctx context.Context, repoID, index int64) (*PullRequest, error) { if index < 1 { return nil, ErrPullRequestNotExist{} } @@ -505,7 +495,7 @@ func GetPullRequestByIndexCtx(ctx context.Context, repoID, index int64) (*PullRe return nil, ErrPullRequestNotExist{0, 0, 0, repoID, "", ""} } - if err = pr.loadAttributes(db.GetEngine(ctx)); err != nil { + if err = pr.loadAttributes(ctx); err != nil { return nil, err } if err = pr.LoadIssueCtx(ctx); err != nil { @@ -515,20 +505,16 @@ func GetPullRequestByIndexCtx(ctx context.Context, repoID, index int64) (*PullRe return pr, nil } -func getPullRequestByID(e db.Engine, id int64) (*PullRequest, error) { +// GetPullRequestByID returns a pull request by given ID. +func GetPullRequestByID(ctx context.Context, id int64) (*PullRequest, error) { pr := new(PullRequest) - has, err := e.ID(id).Get(pr) + has, err := db.GetEngine(ctx).ID(id).Get(pr) if err != nil { return nil, err } else if !has { return nil, ErrPullRequestNotExist{id, 0, 0, 0, "", ""} } - return pr, pr.loadAttributes(e) -} - -// GetPullRequestByID returns a pull request by given ID. -func GetPullRequestByID(ctx context.Context, id int64) (*PullRequest, error) { - return getPullRequestByID(db.GetEngine(ctx), id) + return pr, pr.loadAttributes(ctx) } // GetPullRequestByIssueIDWithNoAttributes returns pull request with no attributes loaded by given issue ID. @@ -544,17 +530,18 @@ func GetPullRequestByIssueIDWithNoAttributes(issueID int64) (*PullRequest, error return &pr, nil } -func getPullRequestByIssueID(e db.Engine, issueID int64) (*PullRequest, error) { +// GetPullRequestByIssueID returns pull request by given issue ID. +func GetPullRequestByIssueID(ctx context.Context, issueID int64) (*PullRequest, error) { pr := &PullRequest{ IssueID: issueID, } - has, err := e.Get(pr) + has, err := db.GetByBean(ctx, pr) if err != nil { return nil, err } else if !has { return nil, ErrPullRequestNotExist{0, issueID, 0, 0, "", ""} } - return pr, pr.loadAttributes(e) + return pr, pr.loadAttributes(ctx) } // GetAllUnmergedAgitPullRequestByPoster get all unmerged agit flow pull request @@ -571,11 +558,6 @@ func GetAllUnmergedAgitPullRequestByPoster(uid int64) ([]*PullRequest, error) { return pulls, err } -// GetPullRequestByIssueID returns pull request by given issue ID. -func GetPullRequestByIssueID(issueID int64) (*PullRequest, error) { - return getPullRequestByIssueID(db.GetEngine(db.DefaultContext), issueID) -} - // Update updates all fields of pull request. func (pr *PullRequest) Update() error { _, err := db.GetEngine(db.DefaultContext).ID(pr.ID).AllCols().Update(pr) @@ -606,7 +588,7 @@ func (pr *PullRequest) IsWorkInProgress() bool { // HasWorkInProgressPrefix determines if the given PR title has a Work In Progress prefix func HasWorkInProgressPrefix(title string) bool { for _, prefix := range setting.Repository.PullRequest.WorkInProgressPrefixes { - if strings.HasPrefix(strings.ToUpper(title), prefix) { + if strings.HasPrefix(strings.ToUpper(title), strings.ToUpper(prefix)) { return true } } @@ -627,7 +609,7 @@ func (pr *PullRequest) GetWorkInProgressPrefix() string { } for _, prefix := range setting.Repository.PullRequest.WorkInProgressPrefixes { - if strings.HasPrefix(strings.ToUpper(pr.Issue.Title), prefix) { + if strings.HasPrefix(strings.ToUpper(pr.Issue.Title), strings.ToUpper(prefix)) { return pr.Issue.Title[0:len(prefix)] } } @@ -635,17 +617,13 @@ func (pr *PullRequest) GetWorkInProgressPrefix() string { } // UpdateCommitDivergence update Divergence of a pull request -func (pr *PullRequest) UpdateCommitDivergence(ahead, behind int) error { - return pr.updateCommitDivergence(db.GetEngine(db.DefaultContext), ahead, behind) -} - -func (pr *PullRequest) updateCommitDivergence(e db.Engine, ahead, behind int) error { +func (pr *PullRequest) UpdateCommitDivergence(ctx context.Context, ahead, behind int) error { if pr.ID == 0 { return fmt.Errorf("pull ID is 0") } pr.CommitsAhead = ahead pr.CommitsBehind = behind - _, err := e.ID(pr.ID).Cols("commits_ahead", "commits_behind").Update(pr) + _, err := db.GetEngine(ctx).ID(pr.ID).Cols("commits_ahead", "commits_behind").Update(pr) return err } diff --git a/models/pull_list.go b/models/pull_list.go index ca09e28a93..fb14d3beac 100644 --- a/models/pull_list.go +++ b/models/pull_list.go @@ -9,6 +9,8 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/git" @@ -60,6 +62,39 @@ func GetUnmergedPullRequestsByHeadInfo(repoID int64, branch string) ([]*PullRequ Find(&prs) } +// CanMaintainerWriteToBranch check whether user is a matainer and could write to the branch +func CanMaintainerWriteToBranch(p access_model.Permission, branch string, user *user_model.User) bool { + if p.CanWrite(unit.TypeCode) { + return true + } + + if len(p.Units) < 1 { + return false + } + + prs, err := GetUnmergedPullRequestsByHeadInfo(p.Units[0].RepoID, branch) + if err != nil { + return false + } + + for _, pr := range prs { + if pr.AllowMaintainerEdit { + err = pr.LoadBaseRepo() + if err != nil { + continue + } + prPerm, err := access_model.GetUserRepoPermission(db.DefaultContext, pr.BaseRepo, user) + if err != nil { + continue + } + if prPerm.CanWrite(unit.TypeCode) { + return true + } + } + } + return false +} + // HasUnmergedPullRequestsByHeadInfo checks if there are open and not merged pull request // by given head information (repo and branch) func HasUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch string) (bool, error) { @@ -121,7 +156,7 @@ func PullRequests(baseRepoID int64, opts *PullRequestsOptions) ([]*PullRequest, // PullRequestList defines a list of pull requests type PullRequestList []*PullRequest -func (prs PullRequestList) loadAttributes(e db.Engine) error { +func (prs PullRequestList) loadAttributes(ctx context.Context) error { if len(prs) == 0 { return nil } @@ -129,7 +164,7 @@ func (prs PullRequestList) loadAttributes(e db.Engine) error { // Load issues. issueIDs := prs.getIssueIDs() issues := make([]*Issue, 0, len(issueIDs)) - if err := e. + if err := db.GetEngine(ctx). Where("id > 0"). In("id", issueIDs). Find(&issues); err != nil { @@ -156,7 +191,7 @@ func (prs PullRequestList) getIssueIDs() []int64 { // LoadAttributes load all the prs attributes func (prs PullRequestList) LoadAttributes() error { - return prs.loadAttributes(db.GetEngine(db.DefaultContext)) + return prs.loadAttributes(db.DefaultContext) } // InvalidateCodeComments will lookup the prs for code comments which got invalidated by change diff --git a/models/pull_test.go b/models/pull_test.go index 6119bca692..00bbfc798a 100644 --- a/models/pull_test.go +++ b/models/pull_test.go @@ -140,16 +140,16 @@ func TestGetUnmergedPullRequestsByBaseInfo(t *testing.T) { func TestGetPullRequestByIndex(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr, err := GetPullRequestByIndex(1, 2) + pr, err := GetPullRequestByIndex(db.DefaultContext, 1, 2) assert.NoError(t, err) assert.Equal(t, int64(1), pr.BaseRepoID) assert.Equal(t, int64(2), pr.Index) - _, err = GetPullRequestByIndex(9223372036854775807, 9223372036854775807) + _, err = GetPullRequestByIndex(db.DefaultContext, 9223372036854775807, 9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) - _, err = GetPullRequestByIndex(1, 0) + _, err = GetPullRequestByIndex(db.DefaultContext, 1, 0) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } @@ -168,11 +168,11 @@ func TestGetPullRequestByID(t *testing.T) { func TestGetPullRequestByIssueID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - pr, err := GetPullRequestByIssueID(2) + pr, err := GetPullRequestByIssueID(db.DefaultContext, 2) assert.NoError(t, err) assert.Equal(t, int64(2), pr.IssueID) - _, err = GetPullRequestByIssueID(9223372036854775807) + _, err = GetPullRequestByIssueID(db.DefaultContext, 9223372036854775807) assert.Error(t, err) assert.True(t, IsErrPullRequestNotExist(err)) } diff --git a/models/release.go b/models/release.go index 0285f6bd5e..94e803c716 100644 --- a/models/release.go +++ b/models/release.go @@ -52,16 +52,16 @@ func init() { db.RegisterModel(new(Release)) } -func (r *Release) loadAttributes(e db.Engine) error { +func (r *Release) loadAttributes(ctx context.Context) error { var err error if r.Repo == nil { - r.Repo, err = repo_model.GetRepositoryByID(r.RepoID) + r.Repo, err = repo_model.GetRepositoryByIDCtx(ctx, r.RepoID) if err != nil { return err } } if r.Publisher == nil { - r.Publisher, err = user_model.GetUserByIDEngine(e, r.PublisherID) + r.Publisher, err = user_model.GetUserByIDCtx(ctx, r.PublisherID) if err != nil { if user_model.IsErrUserNotExist(err) { r.Publisher = user_model.NewGhostUser() @@ -70,12 +70,12 @@ func (r *Release) loadAttributes(e db.Engine) error { } } } - return getReleaseAttachments(e, r) + return GetReleaseAttachments(ctx, r) } // LoadAttributes load repo and publisher attributes for a release func (r *Release) LoadAttributes() error { - return r.loadAttributes(db.GetEngine(db.DefaultContext)) + return r.loadAttributes(db.DefaultContext) } // APIURL the api url for a release. release must have attributes loaded @@ -99,24 +99,12 @@ func (r *Release) HTMLURL() string { } // IsReleaseExist returns true if release with given tag name already exists. -func IsReleaseExist(repoID int64, tagName string) (bool, error) { +func IsReleaseExist(ctx context.Context, repoID int64, tagName string) (bool, error) { if len(tagName) == 0 { return false, nil } - return db.GetEngine(db.DefaultContext).Get(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}) -} - -// InsertRelease inserts a release -func InsertRelease(rel *Release) error { - _, err := db.GetEngine(db.DefaultContext).Insert(rel) - return err -} - -// InsertReleasesContext insert releases -func InsertReleasesContext(ctx context.Context, rels []*Release) error { - _, err := db.GetEngine(ctx).Insert(rels) - return err + return db.GetEngine(ctx).Exist(&Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)}) } // UpdateRelease updates all columns of a release @@ -149,22 +137,20 @@ func AddReleaseAttachments(ctx context.Context, releaseID int64, attachmentUUIDs // GetRelease returns release by given ID. func GetRelease(repoID int64, tagName string) (*Release, error) { - isExist, err := IsReleaseExist(repoID, tagName) + rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)} + has, err := db.GetEngine(db.DefaultContext).Get(rel) if err != nil { return nil, err - } else if !isExist { + } else if !has { return nil, ErrReleaseNotExist{0, tagName} } - - rel := &Release{RepoID: repoID, LowerTagName: strings.ToLower(tagName)} - _, err = db.GetEngine(db.DefaultContext).Get(rel) - return rel, err + return rel, nil } // GetReleaseByID returns release with given ID. -func GetReleaseByID(id int64) (*Release, error) { +func GetReleaseByID(ctx context.Context, id int64) (*Release, error) { rel := new(Release) - has, err := db.GetEngine(db.DefaultContext). + has, err := db.GetEngine(ctx). ID(id). Get(rel) if err != nil { @@ -282,11 +268,7 @@ func (s releaseMetaSearch) Less(i, j int) bool { } // GetReleaseAttachments retrieves the attachments for releases -func GetReleaseAttachments(rels ...*Release) (err error) { - return getReleaseAttachments(db.GetEngine(db.DefaultContext), rels...) -} - -func getReleaseAttachments(e db.Engine, rels ...*Release) (err error) { +func GetReleaseAttachments(ctx context.Context, rels ...*Release) (err error) { if len(rels) == 0 { return } @@ -306,7 +288,7 @@ func getReleaseAttachments(e db.Engine, rels ...*Release) (err error) { sort.Sort(sortedRels) // Select attachments - err = e. + err = db.GetEngine(ctx). Asc("release_id", "name"). In("release_id", sortedRels.ID). Find(&attachments, repo_model.Attachment{}) @@ -373,10 +355,6 @@ func UpdateReleasesMigrationsByType(gitServiceType structs.GitServiceType, origi // PushUpdateDeleteTagsContext updates a number of delete tags with context func PushUpdateDeleteTagsContext(ctx context.Context, repo *repo_model.Repository, tags []string) error { - return pushUpdateDeleteTags(db.GetEngine(ctx), repo, tags) -} - -func pushUpdateDeleteTags(e db.Engine, repo *repo_model.Repository, tags []string) error { if len(tags) == 0 { return nil } @@ -385,14 +363,14 @@ func pushUpdateDeleteTags(e db.Engine, repo *repo_model.Repository, tags []strin lowerTags = append(lowerTags, strings.ToLower(tag)) } - if _, err := e. + if _, err := db.GetEngine(ctx). Where("repo_id = ? AND is_tag = ?", repo.ID, true). In("lower_tag_name", lowerTags). Delete(new(Release)); err != nil { return fmt.Errorf("Delete: %v", err) } - if _, err := e. + if _, err := db.GetEngine(ctx). Where("repo_id = ? AND is_tag = ?", repo.ID, false). In("lower_tag_name", lowerTags). Cols("is_draft", "num_commits", "sha1"). diff --git a/models/repo.go b/models/repo.go index fb7bbba1e1..fff9cc5271 100644 --- a/models/repo.go +++ b/models/repo.go @@ -8,11 +8,7 @@ package models import ( "context" "fmt" - "os" - "path" "strconv" - "strings" - "unicode/utf8" _ "image/jpeg" // Needed for jpeg support @@ -22,6 +18,7 @@ import ( issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + 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" "code.gitea.io/gitea/models/unit" @@ -46,15 +43,11 @@ func NewRepoContext() { } // CheckRepoUnitUser check whether user could visit the unit of this repository -func CheckRepoUnitUser(repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { - return checkRepoUnitUser(db.DefaultContext, repo, user, unitType) -} - -func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { +func CheckRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *user_model.User, unitType unit.Type) bool { if user != nil && user.IsAdmin { return true } - perm, err := GetUserRepoPermission(ctx, repo, user) + perm, err := access_model.GetUserRepoPermission(ctx, repo, user) if err != nil { log.Error("GetUserRepoPermission(): %v", err) return false @@ -63,282 +56,6 @@ func checkRepoUnitUser(ctx context.Context, repo *repo_model.Repository, user *u return perm.CanRead(unitType) } -func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*user_model.User, err error) { - if err = repo.GetOwner(ctx); err != nil { - return nil, err - } - - e := db.GetEngine(ctx) - userIDs := make([]int64, 0, 10) - if err = e.Table("access"). - Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite). - Select("user_id"). - Find(&userIDs); err != nil { - return nil, err - } - - additionalUserIDs := make([]int64, 0, 10) - if err = e.Table("team_user"). - Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id"). - Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id"). - Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite). - Distinct("`team_user`.uid"). - Select("`team_user`.uid"). - Find(&additionalUserIDs); err != nil { - return nil, err - } - - uidMap := map[int64]bool{} - i := 0 - for _, uid := range userIDs { - if uidMap[uid] { - continue - } - uidMap[uid] = true - userIDs[i] = uid - i++ - } - userIDs = userIDs[:i] - userIDs = append(userIDs, additionalUserIDs...) - - for _, uid := range additionalUserIDs { - if uidMap[uid] { - continue - } - userIDs[i] = uid - i++ - } - userIDs = userIDs[:i] - - // Leave a seat for owner itself to append later, but if owner is an organization - // and just waste 1 unit is cheaper than re-allocate memory once. - users := make([]*user_model.User, 0, len(userIDs)+1) - if len(userIDs) > 0 { - if err = e.In("id", userIDs).Find(&users); err != nil { - return nil, err - } - } - if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] { - users = append(users, repo.Owner) - } - - return users, nil -} - -// GetRepoAssignees returns all users that have write access and can be assigned to issues -// of the repository, -func GetRepoAssignees(repo *repo_model.Repository) (_ []*user_model.User, err error) { - return getRepoAssignees(db.DefaultContext, repo) -} - -func getReviewers(ctx context.Context, repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) { - // Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries - if err := repo.GetOwner(ctx); err != nil { - return nil, err - } - - cond := builder.And(builder.Neq{"`user`.id": posterID}) - - if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate { - // This a private repository: - // Anyone who can read the repository is a requestable reviewer - - cond = cond.And(builder.In("`user`.id", - builder.Select("user_id").From("access").Where( - builder.Eq{"repo_id": repo.ID}. - And(builder.Gte{"mode": perm.AccessModeRead}), - ), - )) - - if repo.Owner.Type == user_model.UserTypeIndividual && repo.Owner.ID != posterID { - // as private *user* repos don't generate an entry in the `access` table, - // the owner of a private repo needs to be explicitly added. - cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID}) - } - - } else { - // This is a "public" repository: - // Any user that has read access, is a watcher or organization member can be requested to review - cond = cond.And(builder.And(builder.In("`user`.id", - builder.Select("user_id").From("access"). - Where(builder.Eq{"repo_id": repo.ID}. - And(builder.Gte{"mode": perm.AccessModeRead})), - ).Or(builder.In("`user`.id", - builder.Select("user_id").From("watch"). - Where(builder.Eq{"repo_id": repo.ID}. - And(builder.In("mode", repo_model.WatchModeNormal, repo_model.WatchModeAuto))), - ).Or(builder.In("`user`.id", - builder.Select("uid").From("org_user"). - Where(builder.Eq{"org_id": repo.OwnerID}), - ))))) - } - - users := make([]*user_model.User, 0, 8) - return users, db.GetEngine(ctx).Where(cond).OrderBy("name").Find(&users) -} - -// GetReviewers get all users can be requested to review: -// * for private repositories this returns all users that have read access or higher to the repository. -// * for public repositories this returns all users that have read access or higher to the repository, -// all repo watchers and all organization members. -// TODO: may be we should have a busy choice for users to block review request to them. -func GetReviewers(repo *repo_model.Repository, doerID, posterID int64) ([]*user_model.User, error) { - return getReviewers(db.DefaultContext, repo, doerID, posterID) -} - -// GetReviewerTeams get all teams can be requested to review -func GetReviewerTeams(repo *repo_model.Repository) ([]*organization.Team, error) { - if err := repo.GetOwner(db.DefaultContext); err != nil { - return nil, err - } - if !repo.Owner.IsOrganization() { - return nil, nil - } - - teams, err := organization.GetTeamsWithAccessToRepo(db.DefaultContext, repo.OwnerID, repo.ID, perm.AccessModeRead) - if err != nil { - return nil, err - } - - return teams, err -} - -func updateRepoSize(e db.Engine, repo *repo_model.Repository) error { - size, err := util.GetDirectorySize(repo.RepoPath()) - if err != nil { - return fmt.Errorf("updateSize: %v", err) - } - - lfsSize, err := e.Where("repository_id = ?", repo.ID).SumInt(new(LFSMetaObject), "size") - if err != nil { - return fmt.Errorf("updateSize: GetLFSMetaObjects: %v", err) - } - - repo.Size = size + lfsSize - _, err = e.ID(repo.ID).Cols("size").NoAutoTime().Update(repo) - return err -} - -// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize -func UpdateRepoSize(ctx context.Context, repo *repo_model.Repository) error { - return updateRepoSize(db.GetEngine(ctx), repo) -} - -// CanUserForkRepo returns true if specified user can fork repository. -func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool, error) { - if user == nil { - return false, nil - } - if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) { - return true, nil - } - ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID) - if err != nil { - return false, err - } - for _, org := range ownedOrgs { - if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, repo.ID) { - return true, nil - } - } - return false, nil -} - -// FindUserOrgForks returns the forked repositories for one user from a repository -func FindUserOrgForks(ctx context.Context, repoID, userID int64) ([]*repo_model.Repository, error) { - cond := builder.And( - builder.Eq{"fork_id": repoID}, - builder.In("owner_id", - builder.Select("org_id"). - From("org_user"). - Where(builder.Eq{"uid": userID}), - ), - ) - - var repos []*repo_model.Repository - return repos, db.GetEngine(ctx).Table("repository").Where(cond).Find(&repos) -} - -// GetForksByUserAndOrgs return forked repos of the user and owned orgs -func GetForksByUserAndOrgs(ctx context.Context, user *user_model.User, repo *repo_model.Repository) ([]*repo_model.Repository, error) { - var repoList []*repo_model.Repository - if user == nil { - return repoList, nil - } - forkedRepo, err := repo_model.GetUserFork(ctx, repo.ID, user.ID) - if err != nil { - return repoList, err - } - if forkedRepo != nil { - repoList = append(repoList, forkedRepo) - } - orgForks, err := FindUserOrgForks(ctx, repo.ID, user.ID) - if err != nil { - return nil, err - } - repoList = append(repoList, orgForks...) - return repoList, nil -} - -// CanUserDelete returns true if user could delete the repository -func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, error) { - if user.IsAdmin || user.ID == repo.OwnerID { - return true, nil - } - - if err := repo.GetOwner(db.DefaultContext); err != nil { - return false, err - } - - if repo.Owner.IsOrganization() { - isOwner, err := organization.OrgFromUser(repo.Owner).IsOwnedBy(user.ID) - if err != nil { - return false, err - } else if isOwner { - return true, nil - } - } - - return false, nil -} - -// getUsersWithAccessMode returns users that have at least given access mode to the repository. -func getUsersWithAccessMode(ctx context.Context, repo *repo_model.Repository, mode perm.AccessMode) (_ []*user_model.User, err error) { - if err = repo.GetOwner(ctx); err != nil { - return nil, err - } - - e := db.GetEngine(ctx) - accesses := make([]*Access, 0, 10) - if err = e.Where("repo_id = ? AND mode >= ?", repo.ID, mode).Find(&accesses); err != nil { - return nil, err - } - - // Leave a seat for owner itself to append later, but if owner is an organization - // and just waste 1 unit is cheaper than re-allocate memory once. - users := make([]*user_model.User, 0, len(accesses)+1) - if len(accesses) > 0 { - userIDs := make([]int64, len(accesses)) - for i := 0; i < len(accesses); i++ { - userIDs[i] = accesses[i].UserID - } - - if err = e.In("id", userIDs).Find(&users); err != nil { - return nil, err - } - } - if !repo.Owner.IsOrganization() { - users = append(users, repo.Owner) - } - - return users, nil -} - -// SetRepoReadBy sets repo to be visited by given user. -func SetRepoReadBy(repoID, userID int64) error { - return setRepoNotificationStatusReadIfUnread(db.GetEngine(db.DefaultContext), userID, repoID) -} - // CreateRepoOptions contains the create repository options type CreateRepoOptions struct { Name string @@ -365,7 +82,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_ return err } - has, err := repo_model.IsRepositoryExistCtx(ctx, u, repo.Name) + has, err := repo_model.IsRepositoryExist(ctx, u, repo.Name) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { @@ -413,7 +130,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_ units = append(units, repo_model.RepoUnit{ RepoID: repo.ID, Type: tp, - Config: &repo_model.PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, DefaultMergeStyle: repo_model.MergeStyleMerge, AllowRebaseUpdate: true}, + Config: &repo_model.PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowRebaseMerge: true, AllowSquash: true, DefaultMergeStyle: repo_model.MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle), AllowRebaseUpdate: true}, }) } else { units = append(units, repo_model.RepoUnit{ @@ -429,7 +146,7 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_ // Remember visibility preference. u.LastRepoVisibility = repo.IsPrivate - if err = user_model.UpdateUserColsEngine(db.GetEngine(ctx), u, "last_repo_visibility"); err != nil { + if err = user_model.UpdateUserCols(ctx, u, "last_repo_visibility"); err != nil { return fmt.Errorf("updateUser: %v", err) } @@ -452,24 +169,24 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_ } } - if isAdmin, err := IsUserRepoAdminCtx(ctx, repo, doer); err != nil { + if isAdmin, err := access_model.IsUserRepoAdmin(ctx, repo, doer); err != nil { return fmt.Errorf("IsUserRepoAdminCtx: %v", 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: %v", err) } - if err = changeCollaborationAccessMode(db.GetEngine(ctx), repo, doer.ID, perm.AccessModeAdmin); err != nil { + if err = repo_model.ChangeCollaborationAccessModeCtx(ctx, repo, doer.ID, perm.AccessModeAdmin); err != nil { return fmt.Errorf("ChangeCollaborationAccessMode: %v", err) } } - } else if err = recalculateAccesses(ctx, repo); err != nil { + } else if err = access_model.RecalculateAccesses(ctx, repo); err != nil { // Organization automatically called this in addRepository method. return fmt.Errorf("recalculateAccesses: %v", err) } if setting.Service.AutoWatchNewRepos { - if err = repo_model.WatchRepoCtx(ctx, doer.ID, repo.ID, true); err != nil { + if err = repo_model.WatchRepo(ctx, doer.ID, repo.ID, true); err != nil { return fmt.Errorf("watchRepo: %v", err) } } @@ -481,126 +198,6 @@ func CreateRepository(ctx context.Context, doer, u *user_model.User, repo *repo_ return nil } -// CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... -func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error { - if err := repo.GetOwner(ctx); err != nil { - return err - } - - // Create/Remove git-daemon-export-ok for git-daemon... - daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`) - - isExist, err := util.IsExist(daemonExportFile) - if err != nil { - log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err) - return err - } - - isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic - if !isPublic && isExist { - if err = util.Remove(daemonExportFile); err != nil { - log.Error("Failed to remove %s: %v", daemonExportFile, err) - } - } else if isPublic && !isExist { - if f, err := os.Create(daemonExportFile); err != nil { - log.Error("Failed to create %s: %v", daemonExportFile, err) - } else { - f.Close() - } - } - - return nil -} - -// IncrementRepoForkNum increment repository fork number -func IncrementRepoForkNum(ctx context.Context, repoID int64) error { - _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", repoID) - return err -} - -// DecrementRepoForkNum decrement repository fork number -func DecrementRepoForkNum(ctx context.Context, repoID int64) error { - _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repoID) - return err -} - -// UpdateRepositoryCtx updates a repository with db context -func UpdateRepositoryCtx(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) { - repo.LowerName = strings.ToLower(repo.Name) - - if utf8.RuneCountInString(repo.Description) > 255 { - repo.Description = string([]rune(repo.Description)[:255]) - } - if utf8.RuneCountInString(repo.Website) > 255 { - repo.Website = string([]rune(repo.Website)[:255]) - } - - e := db.GetEngine(ctx) - - if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil { - return fmt.Errorf("update: %v", err) - } - - if err = updateRepoSize(e, repo); err != nil { - log.Error("Failed to update size for repository: %v", err) - } - - if visibilityChanged { - if err = repo.GetOwner(ctx); err != nil { - return fmt.Errorf("getOwner: %v", err) - } - if repo.Owner.IsOrganization() { - // Organization repository need to recalculate access table when visibility is changed. - if err = recalculateTeamAccesses(ctx, repo, 0); err != nil { - return fmt.Errorf("recalculateTeamAccesses: %v", err) - } - } - - // If repo has become private, we need to set its actions to private. - if repo.IsPrivate { - _, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&Action{ - IsPrivate: true, - }) - if err != nil { - return err - } - } - - // Create/Remove git-daemon-export-ok for git-daemon... - if err := CheckDaemonExportOK(db.WithEngine(ctx, e), repo); err != nil { - return err - } - - forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID) - if err != nil { - return fmt.Errorf("getRepositoriesByForkID: %v", err) - } - for i := range forkRepos { - forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate - if err = UpdateRepositoryCtx(ctx, forkRepos[i], true); err != nil { - return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err) - } - } - } - - return nil -} - -// UpdateRepository updates a repository -func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err error) { - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err = UpdateRepositoryCtx(ctx, repo, visibilityChanged); err != nil { - return fmt.Errorf("updateRepository: %v", err) - } - - return committer.Commit() -} - // DeleteRepository deletes a repository for a user or organization. // make sure if you call this func to close open sessions (sqlite will otherwise get a deadlock) func DeleteRepository(doer *user_model.User, uid, repoID int64) error { @@ -612,7 +209,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { sess := db.GetEngine(ctx) // In case is a organization. - org, err := user_model.GetUserByIDEngine(sess, uid) + org, err := user_model.GetUserByIDCtx(ctx, uid) if err != nil { return err } @@ -659,7 +256,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { return err } for _, t := range teams { - if !hasRepository(ctx, t, repoID) { + if !organization.HasTeamRepo(ctx, t.OrgID, t.ID, repoID) { continue } else if err = removeRepository(ctx, t, repo, false); err != nil { return err @@ -678,14 +275,14 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { releaseAttachments = append(releaseAttachments, attachments[i].RelativePath()) } - if _, err := sess.Exec("UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repo.ID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repo.ID); err != nil { return err } if err := db.DeleteBeans(ctx, - &Access{RepoID: repo.ID}, + &access_model.Access{RepoID: repo.ID}, &Action{RepoID: repo.ID}, - &Collaboration{RepoID: repoID}, + &repo_model.Collaboration{RepoID: repoID}, &Comment{RefRepoID: repoID}, &CommitStatus{RepoID: repoID}, &DeletedBranch{RepoID: repoID}, @@ -711,33 +308,33 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { } // Delete Labels and related objects - if err := deleteLabelsByRepoID(sess, repoID); err != nil { + if err := deleteLabelsByRepoID(ctx, repoID); err != nil { return err } // Delete Pulls and related objects - if err := deletePullsByBaseRepoID(sess, repoID); err != nil { + if err := deletePullsByBaseRepoID(ctx, repoID); err != nil { return err } // Delete Issues and related objects var attachmentPaths []string - if attachmentPaths, err = deleteIssuesByRepoID(sess, repoID); err != nil { + if attachmentPaths, err = deleteIssuesByRepoID(ctx, repoID); err != nil { return err } // Delete issue index - if err := db.DeleteResouceIndex(sess, "issue_index", repoID); err != nil { + if err := db.DeleteResouceIndex(ctx, "issue_index", repoID); err != nil { return err } if repo.IsFork { - if _, err := sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkID); err != nil { return fmt.Errorf("decrease fork count: %v", err) } } - if _, err := sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", uid); err != nil { + if _, err := db.Exec(ctx, "UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", uid); err != nil { return err } @@ -747,7 +344,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { } } - projects, _, err := project_model.GetProjectsCtx(ctx, project_model.SearchOptions{ + projects, _, err := project_model.GetProjects(ctx, project_model.SearchOptions{ RepoID: repoID, }) if err != nil { @@ -767,7 +364,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { lfsPaths := make([]string, 0, len(lfsObjects)) for _, v := range lfsObjects { - count, err := sess.Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: v.Oid}}) + count, err := db.CountByBean(ctx, &LFSMetaObject{Pointer: lfs.Pointer{Oid: v.Oid}}) if err != nil { return err } @@ -778,7 +375,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { lfsPaths = append(lfsPaths, v.RelativePath()) } - if _, err := sess.Delete(&LFSMetaObject{RepositoryID: repoID}); err != nil { + if _, err := db.DeleteByBean(ctx, &LFSMetaObject{RepositoryID: repoID}); err != nil { return err } @@ -794,7 +391,7 @@ func DeleteRepository(doer *user_model.User, uid, repoID int64) error { archivePaths = append(archivePaths, p) } - if _, err := sess.Delete(&repo_model.RepoArchiver{RepoID: repoID}); err != nil { + if _, err := db.DeleteByBean(ctx, &repo_model.RepoArchiver{RepoID: repoID}); err != nil { return err } @@ -1092,14 +689,14 @@ func CheckRepoStats(ctx context.Context) error { continue } - rawResult, err := db.GetEngine(db.DefaultContext).Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID) + rawResult, err := e.Query("SELECT COUNT(*) FROM `repository` WHERE fork_id=?", repo.ID) if err != nil { log.Error("Select count of forks[%d]: %v", repo.ID, err) continue } repo.NumForks = int(parseCountResult(rawResult)) - if err = UpdateRepository(repo, false); err != nil { + if _, err = e.ID(repo.ID).Cols("num_forks").Update(repo); err != nil { log.Error("UpdateRepository[%d]: %v", id, err) continue } @@ -1170,30 +767,6 @@ func DoctorUserStarNum() (err error) { return } -// LinkedRepository returns the linked repo if any -func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { - if a.IssueID != 0 { - iss, err := GetIssueByID(a.IssueID) - if err != nil { - return nil, unit.TypeIssues, err - } - repo, err := repo_model.GetRepositoryByID(iss.RepoID) - unitType := unit.TypeIssues - if iss.IsPull { - unitType = unit.TypePullRequests - } - return repo, unitType, err - } else if a.ReleaseID != 0 { - rel, err := GetReleaseByID(a.ReleaseID) - if err != nil { - return nil, unit.TypeReleases, err - } - repo, err := repo_model.GetRepositoryByID(rel.RepoID) - return repo, unit.TypeReleases, err - } - return nil, -1, nil -} - // DeleteDeployKey delete deploy keys func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error { key, err := asymkey_model.GetDeployKeyByID(ctx, id) @@ -1204,15 +777,13 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error return fmt.Errorf("GetDeployKeyByID: %v", err) } - sess := db.GetEngine(ctx) - // Check if user has access to delete this key. if !doer.IsAdmin { repo, err := repo_model.GetRepositoryByIDCtx(ctx, key.RepoID) if err != nil { return fmt.Errorf("GetRepositoryByID: %v", err) } - has, err := IsUserRepoAdminCtx(ctx, repo, doer) + has, err := access_model.IsUserRepoAdmin(ctx, repo, doer) if err != nil { return fmt.Errorf("GetUserRepoPermission: %v", err) } else if !has { @@ -1224,14 +795,14 @@ func DeleteDeployKey(ctx context.Context, doer *user_model.User, id int64) error } } - if _, err = sess.ID(key.ID).Delete(new(asymkey_model.DeployKey)); err != nil { + if _, err := db.DeleteByBean(ctx, &asymkey_model.DeployKey{ + ID: key.ID, + }); err != nil { return fmt.Errorf("delete deploy key [%d]: %v", key.ID, err) } // Check if this is the last reference to same key content. - has, err := sess. - Where("key_id = ?", key.KeyID). - Get(new(asymkey_model.DeployKey)) + has, err := asymkey_model.IsDeployKeyExistByKeyID(ctx, key.KeyID) if err != nil { return err } else if !has { diff --git a/models/repo/attachment.go b/models/repo/attachment.go index f5351578fb..ddddac2c3d 100644 --- a/models/repo/attachment.go +++ b/models/repo/attachment.go @@ -60,11 +60,6 @@ func (a *Attachment) DownloadURL() string { return setting.AppURL + "attachments/" + url.PathEscape(a.UUID) } -// GetAttachmentByID returns attachment by given id -func GetAttachmentByID(id int64) (*Attachment, error) { - return getAttachmentByID(db.GetEngine(db.DefaultContext), id) -} - // _____ __ __ .__ __ // / _ \_/ |__/ |______ ____ | |__ _____ ____ _____/ |_ // / /_\ \ __\ __\__ \ _/ ___\| | \ / \_/ __ \ / \ __\ @@ -88,9 +83,10 @@ func (err ErrAttachmentNotExist) Error() string { return fmt.Sprintf("attachment does not exist [id: %d, uuid: %s]", err.ID, err.UUID) } -func getAttachmentByID(e db.Engine, id int64) (*Attachment, error) { +// GetAttachmentByID returns attachment by given id +func GetAttachmentByID(ctx context.Context, id int64) (*Attachment, error) { attach := &Attachment{} - if has, err := e.ID(id).Get(attach); err != nil { + if has, err := db.GetEngine(ctx).ID(id).Get(attach); err != nil { return nil, err } else if !has { return nil, ErrAttachmentNotExist{ID: id, UUID: ""} @@ -98,9 +94,10 @@ func getAttachmentByID(e db.Engine, id int64) (*Attachment, error) { return attach, nil } -func getAttachmentByUUID(e db.Engine, uuid string) (*Attachment, error) { +// GetAttachmentByUUID returns attachment by given UUID. +func GetAttachmentByUUID(ctx context.Context, uuid string) (*Attachment, error) { attach := &Attachment{} - has, err := e.Where("uuid=?", uuid).Get(attach) + has, err := db.GetEngine(ctx).Where("uuid=?", uuid).Get(attach) if err != nil { return nil, err } else if !has { @@ -111,22 +108,13 @@ func getAttachmentByUUID(e db.Engine, uuid string) (*Attachment, error) { // GetAttachmentsByUUIDs returns attachment by given UUID list. func GetAttachmentsByUUIDs(ctx context.Context, uuids []string) ([]*Attachment, error) { - return getAttachmentsByUUIDs(db.GetEngine(ctx), uuids) -} - -func getAttachmentsByUUIDs(e db.Engine, uuids []string) ([]*Attachment, error) { if len(uuids) == 0 { return []*Attachment{}, nil } // Silently drop invalid uuids. attachments := make([]*Attachment, 0, len(uuids)) - return attachments, e.In("uuid", uuids).Find(&attachments) -} - -// GetAttachmentByUUID returns attachment by given UUID. -func GetAttachmentByUUID(uuid string) (*Attachment, error) { - return getAttachmentByUUID(db.GetEngine(db.DefaultContext), uuid) + return attachments, db.GetEngine(ctx).In("uuid", uuids).Find(&attachments) } // ExistAttachmentsByUUID returns true if attachment is exist by given UUID @@ -134,37 +122,22 @@ func ExistAttachmentsByUUID(uuid string) (bool, error) { return db.GetEngine(db.DefaultContext).Where("`uuid`=?", uuid).Exist(new(Attachment)) } -// GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName. -func GetAttachmentByReleaseIDFileName(releaseID int64, fileName string) (*Attachment, error) { - return getAttachmentByReleaseIDFileName(db.GetEngine(db.DefaultContext), releaseID, fileName) -} - -// GetAttachmentsByIssueIDCtx returns all attachments of an issue. -func GetAttachmentsByIssueIDCtx(ctx context.Context, issueID int64) ([]*Attachment, error) { +// GetAttachmentsByIssueID returns all attachments of an issue. +func GetAttachmentsByIssueID(ctx context.Context, issueID int64) ([]*Attachment, error) { attachments := make([]*Attachment, 0, 10) return attachments, db.GetEngine(ctx).Where("issue_id = ? AND comment_id = 0", issueID).Find(&attachments) } -// GetAttachmentsByIssueID returns all attachments of an issue. -func GetAttachmentsByIssueID(issueID int64) ([]*Attachment, error) { - return GetAttachmentsByIssueIDCtx(db.DefaultContext, issueID) -} - // GetAttachmentsByCommentID returns all attachments if comment by given ID. -func GetAttachmentsByCommentID(commentID int64) ([]*Attachment, error) { - return GetAttachmentsByCommentIDCtx(db.DefaultContext, commentID) -} - -// GetAttachmentsByCommentIDCtx returns all attachments if comment by given ID. -func GetAttachmentsByCommentIDCtx(ctx context.Context, commentID int64) ([]*Attachment, error) { +func GetAttachmentsByCommentID(ctx context.Context, commentID int64) ([]*Attachment, error) { attachments := make([]*Attachment, 0, 10) return attachments, db.GetEngine(ctx).Where("comment_id=?", commentID).Find(&attachments) } -// getAttachmentByReleaseIDFileName return a file based on the the following infos: -func getAttachmentByReleaseIDFileName(e db.Engine, releaseID int64, fileName string) (*Attachment, error) { +// GetAttachmentByReleaseIDFileName returns attachment by given releaseId and fileName. +func GetAttachmentByReleaseIDFileName(ctx context.Context, releaseID int64, fileName string) (*Attachment, error) { attach := &Attachment{ReleaseID: releaseID, Name: fileName} - has, err := e.Get(attach) + has, err := db.GetEngine(ctx).Get(attach) if err != nil { return nil, err } else if !has { @@ -207,7 +180,7 @@ func DeleteAttachments(ctx context.Context, attachments []*Attachment, remove bo // DeleteAttachmentsByIssue deletes all attachments associated with the given issue. func DeleteAttachmentsByIssue(issueID int64, remove bool) (int, error) { - attachments, err := GetAttachmentsByIssueID(issueID) + attachments, err := GetAttachmentsByIssueID(db.DefaultContext, issueID) if err != nil { return 0, err } @@ -217,7 +190,7 @@ func DeleteAttachmentsByIssue(issueID int64, remove bool) (int, error) { // DeleteAttachmentsByComment deletes all attachments associated with the given comment. func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) { - attachments, err := GetAttachmentsByCommentID(commentID) + attachments, err := GetAttachmentsByCommentID(db.DefaultContext, commentID) if err != nil { return 0, err } @@ -225,11 +198,6 @@ func DeleteAttachmentsByComment(commentID int64, remove bool) (int, error) { return DeleteAttachments(db.DefaultContext, attachments, remove) } -// UpdateAttachment updates the given attachment in database -func UpdateAttachment(atta *Attachment) error { - return UpdateAttachmentCtx(db.DefaultContext, atta) -} - // UpdateAttachmentByUUID Updates attachment via uuid func UpdateAttachmentByUUID(ctx context.Context, attach *Attachment, cols ...string) error { if attach.UUID == "" { @@ -239,8 +207,8 @@ func UpdateAttachmentByUUID(ctx context.Context, attach *Attachment, cols ...str return err } -// UpdateAttachmentCtx updates the given attachment in database -func UpdateAttachmentCtx(ctx context.Context, atta *Attachment) error { +// UpdateAttachment updates the given attachment in database +func UpdateAttachment(ctx context.Context, atta *Attachment) error { sess := db.GetEngine(ctx).Cols("name", "issue_id", "release_id", "comment_id", "download_count") if atta.ID != 0 && atta.UUID == "" { sess = sess.ID(atta.ID) diff --git a/models/repo/attachment_test.go b/models/repo/attachment_test.go index 53c28d5324..d7c2f529db 100644 --- a/models/repo/attachment_test.go +++ b/models/repo/attachment_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -16,7 +17,7 @@ import ( func TestIncreaseDownloadCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - attachment, err := GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") + attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") assert.NoError(t, err) assert.Equal(t, int64(0), attachment.DownloadCount) @@ -24,7 +25,7 @@ func TestIncreaseDownloadCount(t *testing.T) { err = attachment.IncreaseDownloadCount() assert.NoError(t, err) - attachment, err = GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") + attachment, err = repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") assert.NoError(t, err) assert.Equal(t, int64(1), attachment.DownloadCount) } @@ -33,11 +34,11 @@ func TestGetByCommentOrIssueID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // count of attachments from issue ID - attachments, err := GetAttachmentsByIssueID(1) + attachments, err := repo_model.GetAttachmentsByIssueID(db.DefaultContext, 1) assert.NoError(t, err) assert.Len(t, attachments, 1) - attachments, err = GetAttachmentsByCommentID(1) + attachments, err = repo_model.GetAttachmentsByCommentID(db.DefaultContext, 1) assert.NoError(t, err) assert.Len(t, attachments, 2) } @@ -45,33 +46,33 @@ func TestGetByCommentOrIssueID(t *testing.T) { func TestDeleteAttachments(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err := DeleteAttachmentsByIssue(4, false) + count, err := repo_model.DeleteAttachmentsByIssue(4, false) assert.NoError(t, err) assert.Equal(t, 2, count) - count, err = DeleteAttachmentsByComment(2, false) + count, err = repo_model.DeleteAttachmentsByComment(2, false) assert.NoError(t, err) assert.Equal(t, 2, count) - err = DeleteAttachment(&Attachment{ID: 8}, false) + err = repo_model.DeleteAttachment(&repo_model.Attachment{ID: 8}, false) assert.NoError(t, err) - attachment, err := GetAttachmentByUUID("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18") + attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a18") assert.Error(t, err) - assert.True(t, IsErrAttachmentNotExist(err)) + assert.True(t, repo_model.IsErrAttachmentNotExist(err)) assert.Nil(t, attachment) } func TestGetAttachmentByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - attach, err := GetAttachmentByID(1) + attach, err := repo_model.GetAttachmentByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID) } func TestAttachment_DownloadURL(t *testing.T) { - attach := &Attachment{ + attach := &repo_model.Attachment{ UUID: "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", ID: 1, } @@ -81,20 +82,20 @@ func TestAttachment_DownloadURL(t *testing.T) { func TestUpdateAttachment(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - attach, err := GetAttachmentByID(1) + attach, err := repo_model.GetAttachmentByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attach.UUID) attach.Name = "new_name" - assert.NoError(t, UpdateAttachment(attach)) + assert.NoError(t, repo_model.UpdateAttachment(db.DefaultContext, attach)) - unittest.AssertExistsAndLoadBean(t, &Attachment{Name: "new_name"}) + unittest.AssertExistsAndLoadBean(t, &repo_model.Attachment{Name: "new_name"}) } func TestGetAttachmentsByUUIDs(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - attachList, err := GetAttachmentsByUUIDs(db.DefaultContext, []string{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", "not-existing-uuid"}) + attachList, err := repo_model.GetAttachmentsByUUIDs(db.DefaultContext, []string{"a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a17", "not-existing-uuid"}) assert.NoError(t, err) assert.Len(t, attachList, 2) assert.Equal(t, "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11", attachList[0].UUID) diff --git a/models/repo/avatar.go b/models/repo/avatar.go index f11f868d63..cdf85bf1ac 100644 --- a/models/repo/avatar.go +++ b/models/repo/avatar.go @@ -5,6 +5,7 @@ package repo import ( + "context" "fmt" "image/png" "io" @@ -25,11 +26,11 @@ func (repo *Repository) CustomAvatarRelativePath() string { // RelAvatarLink returns a relative link to the repository's avatar. func (repo *Repository) RelAvatarLink() string { - return repo.relAvatarLink(db.GetEngine(db.DefaultContext)) + return repo.relAvatarLink(db.DefaultContext) } // generateRandomAvatar generates a random avatar for repository. -func generateRandomAvatar(e db.Engine, repo *Repository) error { +func generateRandomAvatar(ctx context.Context, repo *Repository) error { idToString := fmt.Sprintf("%d", repo.ID) seed := idToString @@ -51,14 +52,14 @@ func generateRandomAvatar(e db.Engine, repo *Repository) error { log.Info("New random avatar created for repository: %d", repo.ID) - if _, err := e.ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil { + if _, err := db.GetEngine(ctx).ID(repo.ID).Cols("avatar").NoAutoTime().Update(repo); err != nil { return err } return nil } -func (repo *Repository) relAvatarLink(e db.Engine) string { +func (repo *Repository) relAvatarLink(ctx context.Context) string { // If no avatar - path is empty avatarPath := repo.CustomAvatarRelativePath() if len(avatarPath) == 0 { @@ -66,7 +67,7 @@ func (repo *Repository) relAvatarLink(e db.Engine) string { case "image": return setting.RepoAvatar.FallbackImage case "random": - if err := generateRandomAvatar(e, repo); err != nil { + if err := generateRandomAvatar(ctx, repo); err != nil { log.Error("generateRandomAvatar: %v", err) } default: @@ -79,12 +80,12 @@ func (repo *Repository) relAvatarLink(e db.Engine) string { // AvatarLink returns a link to the repository's avatar. func (repo *Repository) AvatarLink() string { - return repo.avatarLink(db.GetEngine(db.DefaultContext)) + return repo.avatarLink(db.DefaultContext) } // avatarLink returns user avatar absolute link. -func (repo *Repository) avatarLink(e db.Engine) string { - link := repo.relAvatarLink(e) +func (repo *Repository) avatarLink(ctx context.Context) string { + link := repo.relAvatarLink(ctx) // we only prepend our AppURL to our known (relative, internal) avatar link to get an absolute URL if strings.HasPrefix(link, "/") && !strings.HasPrefix(link, "//") { return setting.AppURL + strings.TrimPrefix(link, setting.AppSubURL)[1:] diff --git a/models/repo/collaboration.go b/models/repo/collaboration.go new file mode 100644 index 0000000000..09397dd172 --- /dev/null +++ b/models/repo/collaboration.go @@ -0,0 +1,151 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo + +import ( + "context" + "fmt" + + "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/log" + "code.gitea.io/gitea/modules/timeutil" +) + +// Collaboration represent the relation between an individual and a repository. +type Collaboration struct { + ID int64 `xorm:"pk autoincr"` + RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` + Mode perm.AccessMode `xorm:"DEFAULT 2 NOT NULL"` + CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` + UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` +} + +func init() { + db.RegisterModel(new(Collaboration)) +} + +// Collaborator represents a user with collaboration details. +type Collaborator struct { + *user_model.User + Collaboration *Collaboration +} + +// GetCollaborators returns the collaborators for a repository +func GetCollaborators(ctx context.Context, repoID int64, listOptions db.ListOptions) ([]*Collaborator, error) { + collaborations, err := getCollaborations(ctx, repoID, listOptions) + if err != nil { + return nil, fmt.Errorf("getCollaborations: %v", err) + } + + collaborators := make([]*Collaborator, 0, len(collaborations)) + for _, c := range collaborations { + user, err := user_model.GetUserByIDCtx(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) + user = user_model.NewGhostUser() + } else { + return nil, err + } + } + collaborators = append(collaborators, &Collaborator{ + User: user, + Collaboration: c, + }) + } + return collaborators, nil +} + +// CountCollaborators returns total number of collaborators for a repository +func CountCollaborators(repoID int64) (int64, error) { + return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repoID).Count(&Collaboration{}) +} + +// GetCollaboration get collaboration for a repository id with a user id +func GetCollaboration(ctx context.Context, repoID, uid int64) (*Collaboration, error) { + collaboration := &Collaboration{ + RepoID: repoID, + UserID: uid, + } + has, err := db.GetEngine(ctx).Get(collaboration) + if !has { + collaboration = nil + } + return collaboration, err +} + +// IsCollaborator check if a user is a collaborator of a repository +func IsCollaborator(ctx context.Context, repoID, userID int64) (bool, error) { + return db.GetEngine(ctx).Get(&Collaboration{RepoID: repoID, UserID: userID}) +} + +func getCollaborations(ctx context.Context, repoID int64, listOptions db.ListOptions) ([]*Collaboration, error) { + if listOptions.Page == 0 { + collaborations := make([]*Collaboration, 0, 8) + return collaborations, db.GetEngine(ctx).Find(&collaborations, &Collaboration{RepoID: repoID}) + } + + e := db.GetEngine(ctx) + + e = db.SetEnginePagination(e, &listOptions) + + collaborations := make([]*Collaboration, 0, listOptions.PageSize) + return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repoID}) +} + +// ChangeCollaborationAccessMode sets new access mode for the collaboration. +func ChangeCollaborationAccessModeCtx(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: %v", 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: %v", 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: %v", err) + } + + 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() + if err != nil { + return err + } + defer committer.Close() + + if err := ChangeCollaborationAccessModeCtx(ctx, repo, uid, mode); err != nil { + return err + } + + return committer.Commit() +} diff --git a/models/repo/collaboration_test.go b/models/repo/collaboration_test.go new file mode 100644 index 0000000000..8cb7980a75 --- /dev/null +++ b/models/repo/collaboration_test.go @@ -0,0 +1,50 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestRepository_GetCollaborators(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + test := func(repoID int64) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + collaborators, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{}) + assert.NoError(t, err) + expectedLen, err := db.GetEngine(db.DefaultContext).Count(&repo_model.Collaboration{RepoID: repoID}) + assert.NoError(t, err) + assert.Len(t, collaborators, int(expectedLen)) + for _, collaborator := range collaborators { + assert.EqualValues(t, collaborator.User.ID, collaborator.Collaboration.UserID) + assert.EqualValues(t, repoID, collaborator.Collaboration.RepoID) + } + } + test(1) + test(2) + test(3) + test(4) +} + +func TestRepository_IsCollaborator(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + test := func(repoID, userID int64, expected bool) { + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) + actual, err := repo_model.IsCollaborator(db.DefaultContext, repo.ID, userID) + assert.NoError(t, err) + assert.Equal(t, expected, actual) + } + test(3, 2, true) + test(3, unittest.NonexistentID, false) + test(4, 2, false) + test(4, 4, true) +} diff --git a/models/repo/fork.go b/models/repo/fork.go index ae7882a02e..b54c61c425 100644 --- a/models/repo/fork.go +++ b/models/repo/fork.go @@ -8,18 +8,17 @@ import ( "context" "code.gitea.io/gitea/models/db" -) + user_model "code.gitea.io/gitea/models/user" -func getRepositoriesByForkID(e db.Engine, forkID int64) ([]*Repository, error) { - repos := make([]*Repository, 0, 10) - return repos, e. - Where("fork_id=?", forkID). - Find(&repos) -} + "xorm.io/builder" +) // GetRepositoriesByForkID returns all repositories with given fork ID. func GetRepositoriesByForkID(ctx context.Context, forkID int64) ([]*Repository, error) { - return getRepositoriesByForkID(db.GetEngine(ctx), forkID) + repos := make([]*Repository, 0, 10) + return repos, db.GetEngine(ctx). + Where("fork_id=?", forkID). + Find(&repos) } // GetForkedRepo checks if given user has already forked a repository with given ID. @@ -67,3 +66,51 @@ func GetForks(repo *Repository, listOptions db.ListOptions) ([]*Repository, erro forks := make([]*Repository, 0, listOptions.PageSize) return forks, sess.Find(&forks, &Repository{ForkID: repo.ID}) } + +// IncrementRepoForkNum increment repository fork number +func IncrementRepoForkNum(ctx context.Context, repoID int64) error { + _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks+1 WHERE id=?", repoID) + return err +} + +// DecrementRepoForkNum decrement repository fork number +func DecrementRepoForkNum(ctx context.Context, repoID int64) error { + _, err := db.GetEngine(ctx).Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repoID) + return err +} + +// FindUserOrgForks returns the forked repositories for one user from a repository +func FindUserOrgForks(ctx context.Context, repoID, userID int64) ([]*Repository, error) { + cond := builder.And( + builder.Eq{"fork_id": repoID}, + builder.In("owner_id", + builder.Select("org_id"). + From("org_user"). + Where(builder.Eq{"uid": userID}), + ), + ) + + var repos []*Repository + return repos, db.GetEngine(ctx).Table("repository").Where(cond).Find(&repos) +} + +// GetForksByUserAndOrgs return forked repos of the user and owned orgs +func GetForksByUserAndOrgs(ctx context.Context, user *user_model.User, repo *Repository) ([]*Repository, error) { + var repoList []*Repository + if user == nil { + return repoList, nil + } + forkedRepo, err := GetUserFork(ctx, repo.ID, user.ID) + if err != nil { + return repoList, err + } + if forkedRepo != nil { + repoList = append(repoList, forkedRepo) + } + orgForks, err := FindUserOrgForks(ctx, repo.ID, user.ID) + if err != nil { + return nil, err + } + repoList = append(repoList, orgForks...) + return repoList, nil +} diff --git a/models/repo/fork_test.go b/models/repo/fork_test.go index 263aec4e3a..9e08d8136e 100644 --- a/models/repo/fork_test.go +++ b/models/repo/fork_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -17,17 +18,17 @@ func TestGetUserFork(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // User13 has repo 11 forked from repo10 - repo, err := GetRepositoryByID(10) + repo, err := repo_model.GetRepositoryByID(10) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = GetUserFork(db.DefaultContext, repo.ID, 13) + repo, err = repo_model.GetUserFork(db.DefaultContext, repo.ID, 13) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = GetRepositoryByID(9) + repo, err = repo_model.GetRepositoryByID(9) assert.NoError(t, err) assert.NotNil(t, repo) - repo, err = GetUserFork(db.DefaultContext, repo.ID, 13) + repo, err = repo_model.GetUserFork(db.DefaultContext, repo.ID, 13) assert.NoError(t, err) assert.Nil(t, repo) } diff --git a/models/repo/language_stats.go b/models/repo/language_stats.go index 3b0888b6bd..b047046aeb 100644 --- a/models/repo/language_stats.go +++ b/models/repo/language_stats.go @@ -5,6 +5,7 @@ package repo import ( + "context" "math" "strings" @@ -66,22 +67,18 @@ func (stats LanguageStatList) getLanguagePercentages() map[string]float32 { return langPerc } -func getLanguageStats(e db.Engine, repo *Repository) (LanguageStatList, error) { +// GetLanguageStats returns the language statistics for a repository +func GetLanguageStats(ctx context.Context, repo *Repository) (LanguageStatList, error) { stats := make(LanguageStatList, 0, 6) - if err := e.Where("`repo_id` = ?", repo.ID).Desc("`size`").Find(&stats); err != nil { + if err := db.GetEngine(ctx).Where("`repo_id` = ?", repo.ID).Desc("`size`").Find(&stats); err != nil { return nil, err } return stats, nil } -// GetLanguageStats returns the language statistics for a repository -func GetLanguageStats(repo *Repository) (LanguageStatList, error) { - return getLanguageStats(db.GetEngine(db.DefaultContext), repo) -} - // GetTopLanguageStats returns the top language statistics for a repository func GetTopLanguageStats(repo *Repository, limit int) (LanguageStatList, error) { - stats, err := getLanguageStats(db.GetEngine(db.DefaultContext), repo) + stats, err := GetLanguageStats(db.DefaultContext, repo) if err != nil { return nil, err } @@ -120,7 +117,7 @@ func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int defer committer.Close() sess := db.GetEngine(ctx) - oldstats, err := getLanguageStats(sess, repo) + oldstats, err := GetLanguageStats(ctx, repo) if err != nil { return err } @@ -151,7 +148,7 @@ func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int } // Insert new language if !upd { - if _, err := sess.Insert(&LanguageStat{ + if err := db.Insert(ctx, &LanguageStat{ RepoID: repo.ID, CommitID: commitID, IsPrimary: llang == topLang, @@ -176,7 +173,7 @@ func UpdateLanguageStats(repo *Repository, commitID string, stats map[string]int } // Update indexer status - if err = updateIndexerStatus(sess, repo, RepoIndexerTypeStats, commitID); err != nil { + if err = UpdateIndexerStatus(ctx, repo, RepoIndexerTypeStats, commitID); err != nil { return err } @@ -190,10 +187,9 @@ func CopyLanguageStat(originalRepo, destRepo *Repository) error { return err } defer committer.Close() - sess := db.GetEngine(ctx) RepoLang := make(LanguageStatList, 0, 6) - if err := sess.Where("`repo_id` = ?", originalRepo.ID).Desc("`size`").Find(&RepoLang); err != nil { + if err := db.GetEngine(ctx).Where("`repo_id` = ?", originalRepo.ID).Desc("`size`").Find(&RepoLang); err != nil { return err } if len(RepoLang) > 0 { @@ -204,10 +200,10 @@ func CopyLanguageStat(originalRepo, destRepo *Repository) error { } // update destRepo's indexer status tmpCommitID := RepoLang[0].CommitID - if err := updateIndexerStatus(sess, destRepo, RepoIndexerTypeStats, tmpCommitID); err != nil { + if err := UpdateIndexerStatus(ctx, destRepo, RepoIndexerTypeStats, tmpCommitID); err != nil { return err } - if _, err := sess.Insert(&RepoLang); err != nil { + if err := db.Insert(ctx, &RepoLang); err != nil { return err } } diff --git a/models/repo/main_test.go b/models/repo/main_test.go index e375e8a9f3..f6d704ca65 100644 --- a/models/repo/main_test.go +++ b/models/repo/main_test.go @@ -2,30 +2,22 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "path/filepath" "testing" "code.gitea.io/gitea/models/unittest" + + _ "code.gitea.io/gitea/models" // register table model + _ "code.gitea.io/gitea/models/perm/access" // register table model + _ "code.gitea.io/gitea/models/repo" // register table model + _ "code.gitea.io/gitea/models/user" // register table model ) func TestMain(m *testing.M) { unittest.MainTest(m, &unittest.TestOptions{ GiteaRootPath: filepath.Join("..", ".."), - FixtureFiles: []string{ - "attachment.yml", - "repo_archiver.yml", - "repository.yml", - "repo_unit.yml", - "repo_indexer_status.yml", - "repo_redirect.yml", - "watch.yml", - "star.yml", - "topic.yml", - "repo_topic.yml", - "user.yml", - }, }) } diff --git a/models/repo/mirror.go b/models/repo/mirror.go index df4e320752..bd83d24424 100644 --- a/models/repo/mirror.go +++ b/models/repo/mirror.go @@ -14,8 +14,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" - - "xorm.io/xorm" ) // ErrMirrorNotExist mirror does not exist error @@ -56,21 +54,16 @@ func (m *Mirror) BeforeInsert() { } } -// AfterLoad is invoked from XORM after setting the values of all fields of this object. -func (m *Mirror) AfterLoad(session *xorm.Session) { - if m == nil { - return +// GetRepository returns the repository. +func (m *Mirror) GetRepository() *Repository { + if m.Repo != nil { + return m.Repo } - var err error - m.Repo, err = getRepositoryByID(session, m.RepoID) + m.Repo, err = GetRepositoryByIDCtx(db.DefaultContext, m.RepoID) if err != nil { log.Error("getRepositoryByID[%d]: %v", m.ID, err) } -} - -// GetRepository returns the repository. -func (m *Mirror) GetRepository() *Repository { return m.Repo } @@ -88,9 +81,10 @@ func (m *Mirror) ScheduleNextUpdate() { } } -func getMirrorByRepoID(e db.Engine, repoID int64) (*Mirror, error) { +// GetMirrorByRepoID returns mirror information of a repository. +func GetMirrorByRepoID(ctx context.Context, repoID int64) (*Mirror, error) { m := &Mirror{RepoID: repoID} - has, err := e.Get(m) + has, err := db.GetEngine(ctx).Get(m) if err != nil { return nil, err } else if !has { @@ -99,19 +93,10 @@ func getMirrorByRepoID(e db.Engine, repoID int64) (*Mirror, error) { return m, nil } -// GetMirrorByRepoID returns mirror information of a repository. -func GetMirrorByRepoID(repoID int64) (*Mirror, error) { - return getMirrorByRepoID(db.GetEngine(db.DefaultContext), repoID) -} - -func updateMirror(e db.Engine, m *Mirror) error { - _, err := e.ID(m.ID).AllCols().Update(m) - return err -} - // UpdateMirror updates the mirror -func UpdateMirror(m *Mirror) error { - return updateMirror(db.GetEngine(db.DefaultContext), m) +func UpdateMirror(ctx context.Context, m *Mirror) error { + _, err := db.GetEngine(ctx).ID(m.ID).AllCols().Update(m) + return err } // TouchMirror updates the mirror updatedUnix @@ -138,15 +123,15 @@ func MirrorsIterate(limit int, f func(idx int, bean interface{}) error) error { } // InsertMirror inserts a mirror to database -func InsertMirror(mirror *Mirror) error { - _, err := db.GetEngine(db.DefaultContext).Insert(mirror) +func InsertMirror(ctx context.Context, mirror *Mirror) error { + _, err := db.GetEngine(ctx).Insert(mirror) return err } // MirrorRepositoryList contains the mirror repositories type MirrorRepositoryList []*Repository -func (repos MirrorRepositoryList) loadAttributes(e db.Engine) error { +func (repos MirrorRepositoryList) loadAttributes(ctx context.Context) error { if len(repos) == 0 { return nil } @@ -161,7 +146,7 @@ func (repos MirrorRepositoryList) loadAttributes(e db.Engine) error { repoIDs = append(repoIDs, repos[i].ID) } mirrors := make([]*Mirror, 0, len(repoIDs)) - if err := e. + if err := db.GetEngine(ctx). Where("id > 0"). In("repo_id", repoIDs). Find(&mirrors); err != nil { @@ -174,11 +159,21 @@ func (repos MirrorRepositoryList) loadAttributes(e db.Engine) error { } for i := range repos { repos[i].Mirror = set[repos[i].ID] + repos[i].Mirror.Repo = repos[i] } return nil } // LoadAttributes loads the attributes for the given MirrorRepositoryList func (repos MirrorRepositoryList) LoadAttributes() error { - return repos.loadAttributes(db.GetEngine(db.DefaultContext)) + return repos.loadAttributes(db.DefaultContext) +} + +// GetUserMirrorRepositories returns a list of mirror repositories of given user. +func GetUserMirrorRepositories(userID int64) ([]*Repository, error) { + repos := make([]*Repository, 0, 10) + return repos, db.GetEngine(db.DefaultContext). + Where("owner_id = ?", userID). + And("is_mirror = ?", true). + Find(&repos) } diff --git a/models/repo/pushmirror.go b/models/repo/pushmirror.go index b5c6411bd6..048c0c3487 100644 --- a/models/repo/pushmirror.go +++ b/models/repo/pushmirror.go @@ -11,8 +11,6 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/timeutil" - - "xorm.io/xorm" ) // ErrPushMirrorNotExist mirror does not exist error @@ -35,21 +33,16 @@ func init() { db.RegisterModel(new(PushMirror)) } -// AfterLoad is invoked from XORM after setting the values of all fields of this object. -func (m *PushMirror) AfterLoad(session *xorm.Session) { - if m == nil { - return +// GetRepository returns the path of the repository. +func (m *PushMirror) GetRepository() *Repository { + if m.Repo != nil { + return m.Repo } - var err error - m.Repo, err = getRepositoryByID(session, m.RepoID) + m.Repo, err = GetRepositoryByIDCtx(db.DefaultContext, m.RepoID) if err != nil { log.Error("getRepositoryByID[%d]: %v", m.ID, err) } -} - -// GetRepository returns the path of the repository. -func (m *PushMirror) GetRepository() *Repository { return m.Repo } diff --git a/models/repo/pushmirror_test.go b/models/repo/pushmirror_test.go index 83cf86131f..d36a48547e 100644 --- a/models/repo/pushmirror_test.go +++ b/models/repo/pushmirror_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "time" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/timeutil" @@ -19,20 +20,20 @@ func TestPushMirrorsIterate(t *testing.T) { now := timeutil.TimeStampNow() - InsertPushMirror(&PushMirror{ + repo_model.InsertPushMirror(&repo_model.PushMirror{ RemoteName: "test-1", LastUpdateUnix: now, Interval: 1, }) long, _ := time.ParseDuration("24h") - InsertPushMirror(&PushMirror{ + repo_model.InsertPushMirror(&repo_model.PushMirror{ RemoteName: "test-2", LastUpdateUnix: now, Interval: long, }) - InsertPushMirror(&PushMirror{ + repo_model.InsertPushMirror(&repo_model.PushMirror{ RemoteName: "test-3", LastUpdateUnix: now, Interval: 0, @@ -40,8 +41,8 @@ func TestPushMirrorsIterate(t *testing.T) { time.Sleep(1 * time.Millisecond) - PushMirrorsIterate(1, func(idx int, bean interface{}) error { - m, ok := bean.(*PushMirror) + repo_model.PushMirrorsIterate(1, func(idx int, bean interface{}) error { + m, ok := bean.(*repo_model.PushMirror) assert.True(t, ok) assert.Equal(t, "test-1", m.RemoteName) assert.Equal(t, m.RemoteName, m.GetRemoteName()) diff --git a/models/repo/redirect_test.go b/models/repo/redirect_test.go index 2dca2cbbfd..05b105cf63 100644 --- a/models/repo/redirect_test.go +++ b/models/repo/redirect_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -16,27 +17,27 @@ import ( func TestLookupRedirect(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repoID, err := LookupRedirect(2, "oldrepo1") + repoID, err := repo_model.LookupRedirect(2, "oldrepo1") assert.NoError(t, err) assert.EqualValues(t, 1, repoID) - _, err = LookupRedirect(unittest.NonexistentID, "doesnotexist") - assert.True(t, IsErrRedirectNotExist(err)) + _, err = repo_model.LookupRedirect(unittest.NonexistentID, "doesnotexist") + assert.True(t, repo_model.IsErrRedirectNotExist(err)) } func TestNewRedirect(t *testing.T) { // redirect to a completely new name assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame")) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame")) - unittest.AssertExistsAndLoadBean(t, &Redirect{ + unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ OwnerID: repo.OwnerID, LowerName: repo.LowerName, RedirectRepoID: repo.ID, }) - unittest.AssertExistsAndLoadBean(t, &Redirect{ + unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ OwnerID: repo.OwnerID, LowerName: "oldrepo1", RedirectRepoID: repo.ID, @@ -47,15 +48,15 @@ func TestNewRedirect2(t *testing.T) { // redirect to previously used name assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "oldrepo1")) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "oldrepo1")) - unittest.AssertExistsAndLoadBean(t, &Redirect{ + unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ OwnerID: repo.OwnerID, LowerName: repo.LowerName, RedirectRepoID: repo.ID, }) - unittest.AssertNotExistsBean(t, &Redirect{ + unittest.AssertNotExistsBean(t, &repo_model.Redirect{ OwnerID: repo.OwnerID, LowerName: "oldrepo1", RedirectRepoID: repo.ID, @@ -66,10 +67,10 @@ func TestNewRedirect3(t *testing.T) { // redirect for a previously-unredirected repo assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) - assert.NoError(t, NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame")) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + assert.NoError(t, repo_model.NewRedirect(db.DefaultContext, repo.OwnerID, repo.ID, repo.Name, "newreponame")) - unittest.AssertExistsAndLoadBean(t, &Redirect{ + unittest.AssertExistsAndLoadBean(t, &repo_model.Redirect{ OwnerID: repo.OwnerID, LowerName: repo.LowerName, RedirectRepoID: repo.ID, diff --git a/models/repo/repo.go b/models/repo/repo.go index 8af6357bf3..3fd6b94eb1 100644 --- a/models/repo/repo.go +++ b/models/repo/repo.go @@ -289,7 +289,7 @@ func (repo *Repository) LoadUnits(ctx context.Context) (err error) { return nil } - repo.Units, err = getUnitsByRepoID(db.GetEngine(ctx), repo.ID) + repo.Units, err = getUnitsByRepoID(ctx, repo.ID) if log.IsTrace() { unitTypeStrings := make([]string, len(repo.Units)) for i, unit := range repo.Units { @@ -383,7 +383,7 @@ func (repo *Repository) GetOwner(ctx context.Context) (err error) { return nil } - repo.Owner, err = user_model.GetUserByIDEngine(db.GetEngine(ctx), repo.OwnerID) + repo.Owner, err = user_model.GetUserByIDCtx(ctx, repo.OwnerID) return err } @@ -454,15 +454,15 @@ func (repo *Repository) ComposeDocumentMetas() map[string]string { // 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.GetEngine(db.DefaultContext)) + return repo.getBaseRepo(db.DefaultContext) } -func (repo *Repository) getBaseRepo(e db.Engine) (err error) { +func (repo *Repository) getBaseRepo(ctx context.Context) (err error) { if !repo.IsFork { return nil } - repo.BaseRepo, err = getRepositoryByID(e, repo.ForkID) + repo.BaseRepo, err = GetRepositoryByIDCtx(ctx, repo.ForkID) return err } @@ -481,16 +481,6 @@ func (repo *Repository) RepoPath() string { return RepoPath(repo.OwnerName, repo.Name) } -// GitConfigPath returns the path to a repository's git config/ directory -func GitConfigPath(repoPath string) string { - return filepath.Join(repoPath, "config") -} - -// GitConfigPath returns the repository git config path -func (repo *Repository) GitConfigPath() string { - return GitConfigPath(repo.RepoPath()) -} - // Link returns the repository link func (repo *Repository) Link() string { return setting.AppSubURL + "/" + url.PathEscape(repo.OwnerName) + "/" + url.PathEscape(repo.Name) @@ -669,9 +659,10 @@ func GetRepositoryByName(ownerID int64, name string) (*Repository, error) { return repo, err } -func getRepositoryByID(e db.Engine, id int64) (*Repository, error) { +// GetRepositoryByIDCtx returns the repository by given id if exists. +func GetRepositoryByIDCtx(ctx context.Context, id int64) (*Repository, error) { repo := new(Repository) - has, err := e.ID(id).Get(repo) + has, err := db.GetEngine(ctx).ID(id).Get(repo) if err != nil { return nil, err } else if !has { @@ -682,12 +673,7 @@ func getRepositoryByID(e db.Engine, id int64) (*Repository, error) { // GetRepositoryByID returns the repository by given id if exists. func GetRepositoryByID(id int64) (*Repository, error) { - return getRepositoryByID(db.GetEngine(db.DefaultContext), id) -} - -// GetRepositoryByIDCtx returns the repository by given id if exists. -func GetRepositoryByIDCtx(ctx context.Context, id int64) (*Repository, error) { - return getRepositoryByID(db.GetEngine(ctx), id) + return GetRepositoryByIDCtx(db.DefaultContext, id) } // GetRepositoriesMapByIDs returns the repositories by given id slice. @@ -696,8 +682,8 @@ func GetRepositoriesMapByIDs(ids []int64) (map[int64]*Repository, error) { return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos) } -// IsRepositoryExistCtx returns true if the repository with given name under user has already existed. -func IsRepositoryExistCtx(ctx context.Context, u *user_model.User, repoName string) (bool, error) { +// IsRepositoryExist returns true if the repository with given name under user has already existed. +func IsRepositoryExist(ctx context.Context, u *user_model.User, repoName string) (bool, error) { has, err := db.GetEngine(ctx).Get(&Repository{ OwnerID: u.ID, LowerName: strings.ToLower(repoName), @@ -709,29 +695,20 @@ func IsRepositoryExistCtx(ctx context.Context, u *user_model.User, repoName stri return has && isDir, err } -// IsRepositoryExist returns true if the repository with given name under user has already existed. -func IsRepositoryExist(u *user_model.User, repoName string) (bool, error) { - return IsRepositoryExistCtx(db.DefaultContext, u, repoName) -} - // GetTemplateRepo populates repo.TemplateRepo for a generated repository and // returns an error on failure (NOTE: no error is returned for // non-generated repositories, and TemplateRepo will be left untouched) -func GetTemplateRepo(repo *Repository) (*Repository, error) { - return getTemplateRepo(db.GetEngine(db.DefaultContext), repo) -} - -func getTemplateRepo(e db.Engine, repo *Repository) (*Repository, error) { +func GetTemplateRepo(ctx context.Context, repo *Repository) (*Repository, error) { if !repo.IsGenerated() { return nil, nil } - return getRepositoryByID(e, repo.TemplateID) + return GetRepositoryByIDCtx(ctx, repo.TemplateID) } // TemplateRepo returns the repository, which is template of this repository func (repo *Repository) TemplateRepo() *Repository { - repo, err := GetTemplateRepo(repo) + repo, err := GetTemplateRepo(db.DefaultContext, repo) if err != nil { log.Error("TemplateRepo: %v", err) return nil @@ -739,26 +716,27 @@ func (repo *Repository) TemplateRepo() *Repository { return repo } -func countRepositories(userID int64, private bool) int64 { - sess := db.GetEngine(db.DefaultContext).Where("id > 0") - - if userID > 0 { - sess.And("owner_id = ?", userID) - } - if !private { - sess.And("is_private=?", false) - } - - count, err := sess.Count(new(Repository)) - if err != nil { - log.Error("countRepositories: %v", err) - } - return count +type CountRepositoryOptions struct { + OwnerID int64 + Private util.OptionalBool } // CountRepositories returns number of repositories. // Argument private only takes effect when it is false, // set it true to count all repositories. -func CountRepositories(private bool) int64 { - return countRepositories(-1, private) +func CountRepositories(ctx context.Context, opts CountRepositoryOptions) (int64, error) { + sess := db.GetEngine(ctx).Where("id > 0") + + if opts.OwnerID > 0 { + sess.And("owner_id = ?", opts.OwnerID) + } + if !opts.Private.IsNone() { + sess.And("is_private=?", opts.Private.IsTrue()) + } + + count, err := sess.Count(new(Repository)) + if err != nil { + return 0, fmt.Errorf("countRepositories: %v", err) + } + return count, nil } diff --git a/models/repo/repo_indexer.go b/models/repo/repo_indexer.go index f442cad4d1..cba70a14e5 100644 --- a/models/repo/repo_indexer.go +++ b/models/repo/repo_indexer.go @@ -5,6 +5,7 @@ package repo import ( + "context" "fmt" "code.gitea.io/gitea/models/db" @@ -62,8 +63,8 @@ func GetUnindexedRepos(indexerType RepoIndexerType, maxRepoID int64, page, pageS return ids, err } -// getIndexerStatus loads repo codes indxer status -func getIndexerStatus(e db.Engine, repo *Repository, indexerType RepoIndexerType) (*RepoIndexerStatus, error) { +// GetIndexerStatus loads repo codes indxer status +func GetIndexerStatus(ctx context.Context, repo *Repository, indexerType RepoIndexerType) (*RepoIndexerStatus, error) { switch indexerType { case RepoIndexerTypeCode: if repo.CodeIndexerStatus != nil { @@ -75,7 +76,7 @@ func getIndexerStatus(e db.Engine, repo *Repository, indexerType RepoIndexerType } } status := &RepoIndexerStatus{RepoID: repo.ID} - if has, err := e.Where("`indexer_type` = ?", indexerType).Get(status); err != nil { + if has, err := db.GetEngine(ctx).Where("`indexer_type` = ?", indexerType).Get(status); err != nil { return nil, err } else if !has { status.IndexerType = indexerType @@ -90,36 +91,25 @@ func getIndexerStatus(e db.Engine, repo *Repository, indexerType RepoIndexerType return status, nil } -// GetIndexerStatus loads repo codes indxer status -func GetIndexerStatus(repo *Repository, indexerType RepoIndexerType) (*RepoIndexerStatus, error) { - return getIndexerStatus(db.GetEngine(db.DefaultContext), repo, indexerType) -} - -// updateIndexerStatus updates indexer status -func updateIndexerStatus(e db.Engine, repo *Repository, indexerType RepoIndexerType, sha string) error { - status, err := getIndexerStatus(e, repo, indexerType) +// UpdateIndexerStatus updates indexer status +func UpdateIndexerStatus(ctx context.Context, repo *Repository, indexerType RepoIndexerType, sha string) error { + status, err := GetIndexerStatus(ctx, repo, indexerType) if err != nil { return fmt.Errorf("UpdateIndexerStatus: Unable to getIndexerStatus for repo: %s Error: %v", repo.FullName(), err) } if len(status.CommitSha) == 0 { status.CommitSha = sha - _, err := e.Insert(status) - if err != nil { + if err := db.Insert(ctx, status); err != nil { return fmt.Errorf("UpdateIndexerStatus: Unable to insert repoIndexerStatus for repo: %s Sha: %s Error: %v", repo.FullName(), sha, err) } return nil } status.CommitSha = sha - _, err = e.ID(status.ID).Cols("commit_sha"). + _, err = db.GetEngine(ctx).ID(status.ID).Cols("commit_sha"). Update(status) if err != nil { return fmt.Errorf("UpdateIndexerStatus: Unable to update repoIndexerStatus for repo: %s Sha: %s Error: %v", repo.FullName(), sha, err) } return nil } - -// UpdateIndexerStatus updates indexer status -func UpdateIndexerStatus(repo *Repository, indexerType RepoIndexerType, sha string) error { - return updateIndexerStatus(db.GetEngine(db.DefaultContext), repo, indexerType, sha) -} diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 571604a2c2..1bec35d571 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -5,26 +5,30 @@ package repo import ( - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/setting" -) + "context" + "fmt" + "strings" -// GetUserMirrorRepositories returns a list of mirror repositories of given user. -func GetUserMirrorRepositories(userID int64) ([]*Repository, error) { - repos := make([]*Repository, 0, 10) - return repos, db.GetEngine(db.DefaultContext). - Where("owner_id = ?", userID). - And("is_mirror = ?", true). - Find(&repos) -} + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" + "code.gitea.io/gitea/models/unit" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" + + "xorm.io/builder" +) // IterateRepository iterate repositories func IterateRepository(f func(repo *Repository) error) error { var start int batchSize := setting.Database.IterateBufferSize + sess := db.GetEngine(db.DefaultContext) for { repos := make([]*Repository, 0, batchSize) - if err := db.GetEngine(db.DefaultContext).Limit(batchSize, start).Find(&repos); err != nil { + if err := sess.Limit(batchSize, start).Find(&repos); err != nil { return err } if len(repos) == 0 { @@ -44,3 +48,643 @@ func IterateRepository(f func(repo *Repository) error) error { func FindReposMapByIDs(repoIDs []int64, res map[int64]*Repository) error { return db.GetEngine(db.DefaultContext).In("id", repoIDs).Find(&res) } + +// RepositoryListDefaultPageSize is the default number of repositories +// to load in memory when running administrative tasks on all (or almost +// all) of them. +// The number should be low enough to avoid filling up all RAM with +// repository data... +const RepositoryListDefaultPageSize = 64 + +// RepositoryList contains a list of repositories +type RepositoryList []*Repository + +func (repos RepositoryList) Len() int { + return len(repos) +} + +func (repos RepositoryList) Less(i, j int) bool { + return repos[i].FullName() < repos[j].FullName() +} + +func (repos RepositoryList) Swap(i, j int) { + repos[i], repos[j] = repos[j], repos[i] +} + +// ValuesRepository converts a repository map to a list +// FIXME: Remove in favor of maps.values when MIN_GO_VERSION >= 1.18 +func ValuesRepository(m map[int64]*Repository) []*Repository { + values := make([]*Repository, 0, len(m)) + for _, v := range m { + values = append(values, v) + } + return values +} + +// RepositoryListOfMap make list from values of map +func RepositoryListOfMap(repoMap map[int64]*Repository) RepositoryList { + return RepositoryList(ValuesRepository(repoMap)) +} + +func (repos RepositoryList) loadAttributes(ctx context.Context) error { + if len(repos) == 0 { + return nil + } + + set := make(map[int64]struct{}) + repoIDs := make([]int64, len(repos)) + for i := range repos { + set[repos[i].OwnerID] = struct{}{} + repoIDs[i] = repos[i].ID + } + + // Load owners. + users := make(map[int64]*user_model.User, len(set)) + if err := db.GetEngine(ctx). + Where("id > 0"). + In("id", container.KeysInt64(set)). + Find(&users); err != nil { + return fmt.Errorf("find users: %v", err) + } + for i := range repos { + repos[i].Owner = users[repos[i].OwnerID] + } + + // Load primary language. + stats := make(LanguageStatList, 0, len(repos)) + if err := db.GetEngine(ctx). + Where("`is_primary` = ? AND `language` != ?", true, "other"). + In("`repo_id`", repoIDs). + Find(&stats); err != nil { + return fmt.Errorf("find primary languages: %v", err) + } + stats.LoadAttributes() + for i := range repos { + for _, st := range stats { + if st.RepoID == repos[i].ID { + repos[i].PrimaryLanguage = st + break + } + } + } + + return nil +} + +// LoadAttributes loads the attributes for the given RepositoryList +func (repos RepositoryList) LoadAttributes() error { + return repos.loadAttributes(db.DefaultContext) +} + +// SearchRepoOptions holds the search options +type SearchRepoOptions struct { + db.ListOptions + Actor *user_model.User + Keyword string + OwnerID int64 + PriorityOwnerID int64 + TeamID int64 + OrderBy db.SearchOrderBy + Private bool // Include private repositories in results + StarredByID int64 + WatchedByID int64 + AllPublic bool // Include also all public repositories of users and public organisations + AllLimited bool // Include also all public repositories of limited organisations + // None -> include public and private + // True -> include just private + // False -> include just public + IsPrivate util.OptionalBool + // None -> include collaborative AND non-collaborative + // True -> include just collaborative + // False -> include just non-collaborative + Collaborate util.OptionalBool + // None -> include forks AND non-forks + // True -> include just forks + // False -> include just non-forks + Fork util.OptionalBool + // None -> include templates AND non-templates + // True -> include just templates + // False -> include just non-templates + Template util.OptionalBool + // None -> include mirrors AND non-mirrors + // True -> include just mirrors + // False -> include just non-mirrors + Mirror util.OptionalBool + // None -> include archived AND non-archived + // True -> include just archived + // False -> include just non-archived + Archived util.OptionalBool + // only search topic name + TopicOnly bool + // only search repositories with specified primary language + Language string + // include description in keyword search + IncludeDescription bool + // None -> include has milestones AND has no milestone + // True -> include just has milestones + // False -> include just has no milestone + HasMilestones util.OptionalBool + // LowerNames represents valid lower names to restrict to + LowerNames []string +} + +// SearchOrderBy is used to sort the result +type SearchOrderBy string + +func (s SearchOrderBy) String() string { + return string(s) +} + +// Strings for sorting result +const ( + SearchOrderByAlphabetically SearchOrderBy = "name ASC" + SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" + SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" + SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" + SearchOrderByOldest SearchOrderBy = "created_unix ASC" + SearchOrderByNewest SearchOrderBy = "created_unix DESC" + SearchOrderBySize SearchOrderBy = "size ASC" + SearchOrderBySizeReverse SearchOrderBy = "size DESC" + SearchOrderByID SearchOrderBy = "id ASC" + SearchOrderByIDReverse SearchOrderBy = "id DESC" + SearchOrderByStars SearchOrderBy = "num_stars ASC" + SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" + SearchOrderByForks SearchOrderBy = "num_forks ASC" + SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" +) + +// UserOwnedRepoCond returns user ownered repositories +func UserOwnedRepoCond(userID int64) builder.Cond { + return builder.Eq{ + "repository.owner_id": userID, + } +} + +// UserAssignedRepoCond return user as assignee repositories list +func UserAssignedRepoCond(id string, userID int64) builder.Cond { + return builder.And( + builder.Eq{ + "repository.is_private": false, + }, + builder.In(id, + builder.Select("issue.repo_id").From("issue_assignees"). + InnerJoin("issue", "issue.id = issue_assignees.issue_id"). + Where(builder.Eq{ + "issue_assignees.assignee_id": userID, + }), + ), + ) +} + +// UserCreateIssueRepoCond return user created issues repositories list +func UserCreateIssueRepoCond(id string, userID int64, isPull bool) builder.Cond { + return builder.And( + builder.Eq{ + "repository.is_private": false, + }, + builder.In(id, + builder.Select("issue.repo_id").From("issue"). + Where(builder.Eq{ + "issue.poster_id": userID, + "issue.is_pull": isPull, + }), + ), + ) +} + +// UserMentionedRepoCond return user metinoed repositories list +func UserMentionedRepoCond(id string, userID int64) builder.Cond { + return builder.And( + builder.Eq{ + "repository.is_private": false, + }, + builder.In(id, + builder.Select("issue.repo_id").From("issue_user"). + InnerJoin("issue", "issue.id = issue_user.issue_id"). + Where(builder.Eq{ + "issue_user.is_mentioned": true, + "issue_user.uid": userID, + }), + ), + ) +} + +// UserCollaborationRepoCond returns user as collabrators repositories list +func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond { + return builder.In(idStr, builder.Select("repo_id"). + From("`access`"). + Where(builder.And( + builder.Eq{"`access`.user_id": userID}, + builder.Gt{"`access`.mode": int(perm.AccessModeNone)}, + )), + ) +} + +// userOrgTeamRepoCond selects repos that the given user has access to through team membership +func userOrgTeamRepoCond(idStr string, userID int64) builder.Cond { + return builder.In(idStr, userOrgTeamRepoBuilder(userID)) +} + +// userOrgTeamRepoBuilder returns repo ids where user's teams can access. +func userOrgTeamRepoBuilder(userID int64) *builder.Builder { + return builder.Select("`team_repo`.repo_id"). + From("team_repo"). + Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"). + Where(builder.Eq{"`team_user`.uid": userID}) +} + +// userOrgTeamUnitRepoBuilder returns repo ids where user's teams can access the special unit. +func userOrgTeamUnitRepoBuilder(userID int64, unitType unit.Type) *builder.Builder { + return userOrgTeamRepoBuilder(userID). + Join("INNER", "team_unit", "`team_unit`.team_id = `team_repo`.team_id"). + Where(builder.Eq{"`team_unit`.`type`": unitType}) +} + +// UserOrgUnitRepoCond selects repos that the given user has access to through org and the special unit +func UserOrgUnitRepoCond(idStr string, userID, orgID int64, unitType unit.Type) builder.Cond { + return builder.In(idStr, + userOrgTeamUnitRepoBuilder(userID, unitType). + And(builder.Eq{"`team_unit`.org_id": orgID}), + ) +} + +// userOrgPublicRepoCond returns the condition that one user could access all public repositories in organizations +func userOrgPublicRepoCond(userID int64) builder.Cond { + return builder.And( + builder.Eq{"`repository`.is_private": false}, + builder.In("`repository`.owner_id", + builder.Select("`org_user`.org_id"). + From("org_user"). + Where(builder.Eq{"`org_user`.uid": userID}), + ), + ) +} + +// userOrgPublicRepoCondPrivate returns the condition that one user could access all public repositories in private organizations +func userOrgPublicRepoCondPrivate(userID int64) builder.Cond { + return builder.And( + builder.Eq{"`repository`.is_private": false}, + builder.In("`repository`.owner_id", + builder.Select("`org_user`.org_id"). + From("org_user"). + Join("INNER", "`user`", "`user`.id = `org_user`.org_id"). + Where(builder.Eq{ + "`org_user`.uid": userID, + "`user`.`type`": user_model.UserTypeOrganization, + "`user`.visibility": structs.VisibleTypePrivate, + }), + ), + ) +} + +// UserOrgPublicUnitRepoCond returns the condition that one user could access all public repositories in the special organization +func UserOrgPublicUnitRepoCond(userID, orgID int64) builder.Cond { + return userOrgPublicRepoCond(userID). + And(builder.Eq{"`repository`.owner_id": orgID}) +} + +// SearchRepositoryCondition creates a query condition according search repository options +func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { + cond := builder.NewCond() + + if opts.Private { + if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID { + // OK we're in the context of a User + cond = cond.And(AccessibleRepositoryCondition(opts.Actor)) + } + } else { + // Not looking at private organisations and users + // We should be able to see all non-private repositories that + // isn't in a private or limited organisation. + cond = cond.And( + builder.Eq{"is_private": false}, + builder.NotIn("owner_id", builder.Select("id").From("`user`").Where( + builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}), + ))) + } + + if opts.IsPrivate != util.OptionalBoolNone { + cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()}) + } + + if opts.Template != util.OptionalBoolNone { + cond = cond.And(builder.Eq{"is_template": opts.Template == util.OptionalBoolTrue}) + } + + // Restrict to starred repositories + if opts.StarredByID > 0 { + cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID}))) + } + + // Restrict to watched repositories + if opts.WatchedByID > 0 { + cond = cond.And(builder.In("id", builder.Select("repo_id").From("watch").Where(builder.Eq{"user_id": opts.WatchedByID}))) + } + + // Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate + if opts.OwnerID > 0 { + accessCond := builder.NewCond() + if opts.Collaborate != util.OptionalBoolTrue { + accessCond = builder.Eq{"owner_id": opts.OwnerID} + } + + if opts.Collaborate != util.OptionalBoolFalse { + // A Collaboration is: + collaborateCond := builder.And( + // 1. Repository we don't own + builder.Neq{"owner_id": opts.OwnerID}, + // 2. But we can see because of: + builder.Or( + // A. We have access + UserCollaborationRepoCond("`repository`.id", opts.OwnerID), + // B. We are in a team for + userOrgTeamRepoCond("`repository`.id", opts.OwnerID), + // C. Public repositories in organizations that we are member of + userOrgPublicRepoCondPrivate(opts.OwnerID), + ), + ) + if !opts.Private { + collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false)) + } + + accessCond = accessCond.Or(collaborateCond) + } + + if opts.AllPublic { + accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypePublic})))) + } + + if opts.AllLimited { + accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited})))) + } + + cond = cond.And(accessCond) + } + + if opts.TeamID > 0 { + cond = cond.And(builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").From("team_repo").Where(builder.Eq{"`team_repo`.team_id": opts.TeamID}))) + } + + if opts.Keyword != "" { + // separate keyword + subQueryCond := builder.NewCond() + for _, v := range strings.Split(opts.Keyword, ",") { + if opts.TopicOnly { + subQueryCond = subQueryCond.Or(builder.Eq{"topic.name": strings.ToLower(v)}) + } else { + subQueryCond = subQueryCond.Or(builder.Like{"topic.name", strings.ToLower(v)}) + } + } + subQuery := builder.Select("repo_topic.repo_id").From("repo_topic"). + Join("INNER", "topic", "topic.id = repo_topic.topic_id"). + Where(subQueryCond). + GroupBy("repo_topic.repo_id") + + keywordCond := builder.In("id", subQuery) + if !opts.TopicOnly { + likes := builder.NewCond() + for _, v := range strings.Split(opts.Keyword, ",") { + likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)}) + + // If the string looks like "org/repo", match against that pattern too + if opts.TeamID == 0 && strings.Count(opts.Keyword, "/") == 1 { + pieces := strings.Split(opts.Keyword, "/") + ownerName := pieces[0] + repoName := pieces[1] + likes = likes.Or(builder.And(builder.Like{"owner_name", strings.ToLower(ownerName)}, builder.Like{"lower_name", strings.ToLower(repoName)})) + } + + if opts.IncludeDescription { + likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) + } + } + keywordCond = keywordCond.Or(likes) + } + cond = cond.And(keywordCond) + } + + if opts.Language != "" { + cond = cond.And(builder.In("id", builder. + Select("repo_id"). + From("language_stat"). + Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true}))) + } + + if opts.Fork != util.OptionalBoolNone { + cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue}) + } + + if opts.Mirror != util.OptionalBoolNone { + cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue}) + } + + if opts.Actor != nil && opts.Actor.IsRestricted { + cond = cond.And(AccessibleRepositoryCondition(opts.Actor)) + } + + if opts.Archived != util.OptionalBoolNone { + cond = cond.And(builder.Eq{"is_archived": opts.Archived == util.OptionalBoolTrue}) + } + + switch opts.HasMilestones { + case util.OptionalBoolTrue: + cond = cond.And(builder.Gt{"num_milestones": 0}) + case util.OptionalBoolFalse: + cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"})) + } + + return cond +} + +// SearchRepository returns repositories based on search options, +// it returns results in given range and number of total results. +func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) { + cond := SearchRepositoryCondition(opts) + return SearchRepositoryByCondition(opts, cond, true) +} + +// SearchRepositoryByCondition search repositories by condition +func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) { + ctx := db.DefaultContext + sess, count, err := searchRepositoryByCondition(ctx, opts, cond) + if err != nil { + return nil, 0, err + } + + defaultSize := 50 + if opts.PageSize > 0 { + defaultSize = opts.PageSize + } + repos := make(RepositoryList, 0, defaultSize) + if err := sess.Find(&repos); err != nil { + return nil, 0, fmt.Errorf("Repo: %v", err) + } + + if opts.PageSize <= 0 { + count = int64(len(repos)) + } + + if loadAttributes { + if err := repos.loadAttributes(ctx); err != nil { + return nil, 0, fmt.Errorf("LoadAttributes: %v", err) + } + } + + return repos, count, nil +} + +func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, cond builder.Cond) (db.Engine, int64, error) { + if opts.Page <= 0 { + opts.Page = 1 + } + + if len(opts.OrderBy) == 0 { + opts.OrderBy = db.SearchOrderByAlphabetically + } + + args := make([]interface{}, 0) + if opts.PriorityOwnerID > 0 { + opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = ? THEN 0 ELSE owner_id END, %s", opts.OrderBy)) + args = append(args, opts.PriorityOwnerID) + } else if strings.Count(opts.Keyword, "/") == 1 { + // With "owner/repo" search times, prioritise results which match the owner field + orgName := strings.Split(opts.Keyword, "/")[0] + opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_name LIKE ? THEN 0 ELSE 1 END, %s", opts.OrderBy)) + args = append(args, orgName) + } + + sess := db.GetEngine(ctx) + + var count int64 + if opts.PageSize > 0 { + var err error + count, err = sess. + Where(cond). + Count(new(Repository)) + if err != nil { + return nil, 0, fmt.Errorf("Count: %v", err) + } + } + + sess = sess.Where(cond).OrderBy(opts.OrderBy.String(), args...) + if opts.PageSize > 0 { + sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) + } + return sess, count, nil +} + +// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible +func AccessibleRepositoryCondition(user *user_model.User) builder.Cond { + cond := builder.NewCond() + + if user == nil || !user.IsRestricted || user.ID <= 0 { + orgVisibilityLimit := []structs.VisibleType{structs.VisibleTypePrivate} + if user == nil || user.ID <= 0 { + orgVisibilityLimit = append(orgVisibilityLimit, structs.VisibleTypeLimited) + } + // 1. Be able to see all non-private repositories that either: + cond = cond.Or(builder.And( + builder.Eq{"`repository`.is_private": false}, + // 2. Aren't in an private organisation or limited organisation if we're not logged in + builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where( + builder.And( + builder.Eq{"type": user_model.UserTypeOrganization}, + builder.In("visibility", orgVisibilityLimit)), + )))) + } + + if user != nil { + cond = cond.Or( + // 2. Be able to see all repositories that we have access to + UserCollaborationRepoCond("`repository`.id", user.ID), + // 3. Repositories that we directly own + builder.Eq{"`repository`.owner_id": user.ID}, + // 4. Be able to see all repositories that we are in a team + userOrgTeamRepoCond("`repository`.id", user.ID), + // 5. Be able to see all public repos in private organizations that we are an org_user of + userOrgPublicRepoCond(user.ID), + ) + } + + return cond +} + +// SearchRepositoryByName takes keyword and part of repository name to search, +// it returns results in given range and number of total results. +func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) { + opts.IncludeDescription = false + return SearchRepository(opts) +} + +// SearchRepositoryIDs takes keyword and part of repository name to search, +// it returns results in given range and number of total results. +func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) { + opts.IncludeDescription = false + + cond := SearchRepositoryCondition(opts) + + sess, count, err := searchRepositoryByCondition(db.DefaultContext, opts, cond) + if err != nil { + return nil, 0, err + } + + defaultSize := 50 + if opts.PageSize > 0 { + defaultSize = opts.PageSize + } + + ids := make([]int64, 0, defaultSize) + err = sess.Select("id").Table("repository").Find(&ids) + if opts.PageSize <= 0 { + count = int64(len(ids)) + } + + return ids, count, err +} + +// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered. +func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder { + // NB: Please note this code needs to still work if user is nil + return builder.Select("id").From("repository").Where(AccessibleRepositoryCondition(user)) +} + +// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id +func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) { + repoIDs := make([]int64, 0, 10) + if err := db.GetEngine(db.DefaultContext). + Table("repository"). + Cols("id"). + Where(AccessibleRepositoryCondition(user)). + Find(&repoIDs); err != nil { + return nil, fmt.Errorf("FindUserAccesibleRepoIDs: %v", err) + } + return repoIDs, nil +} + +// GetUserRepositories returns a list of repositories of given user. +func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error) { + if len(opts.OrderBy) == 0 { + opts.OrderBy = "updated_unix DESC" + } + + cond := builder.NewCond() + cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID}) + if !opts.Private { + cond = cond.And(builder.Eq{"is_private": false}) + } + + if opts.LowerNames != nil && len(opts.LowerNames) > 0 { + cond = cond.And(builder.In("lower_name", opts.LowerNames)) + } + + sess := db.GetEngine(db.DefaultContext) + + count, err := sess.Where(cond).Count(new(Repository)) + if err != nil { + return nil, 0, fmt.Errorf("Count: %v", err) + } + + sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) + repos := make(RepositoryList, 0, opts.PageSize) + return repos, count, db.SetSessionPagination(sess, opts).Find(&repos) +} diff --git a/models/repo_list_test.go b/models/repo/repo_list_test.go similarity index 51% rename from models/repo_list_test.go rename to models/repo/repo_list_test.go index 4722b073a3..f9c84a0f3f 100644 --- a/models/repo_list_test.go +++ b/models/repo/repo_list_test.go @@ -2,12 +2,14 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repo_test import ( + "strings" "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/util" @@ -18,7 +20,7 @@ func TestSearchRepository(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // test search public repository on explore page - repos, count, err := SearchRepositoryByName(&SearchRepoOptions{ + repos, count, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -33,7 +35,7 @@ func TestSearchRepository(t *testing.T) { } assert.Equal(t, int64(1), count) - repos, count, err = SearchRepositoryByName(&SearchRepoOptions{ + repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -47,7 +49,7 @@ func TestSearchRepository(t *testing.T) { assert.Len(t, repos, 2) // test search private repository on explore page - repos, count, err = SearchRepositoryByName(&SearchRepoOptions{ + repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -63,7 +65,7 @@ func TestSearchRepository(t *testing.T) { } assert.Equal(t, int64(1), count) - repos, count, err = SearchRepositoryByName(&SearchRepoOptions{ + repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -78,14 +80,14 @@ func TestSearchRepository(t *testing.T) { assert.Len(t, repos, 3) // Test non existing owner - repos, count, err = SearchRepositoryByName(&SearchRepoOptions{OwnerID: unittest.NonexistentID}) + repos, count, err = repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{OwnerID: unittest.NonexistentID}) assert.NoError(t, err) assert.Empty(t, repos) assert.Equal(t, int64(0), count) // Test search within description - repos, count, err = SearchRepository(&SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -102,7 +104,7 @@ func TestSearchRepository(t *testing.T) { assert.Equal(t, int64(1), count) // Test NOT search within description - repos, count, err = SearchRepository(&SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: 1, PageSize: 10, @@ -118,154 +120,164 @@ func TestSearchRepository(t *testing.T) { testCases := []struct { name string - opts *SearchRepoOptions + opts *repo_model.SearchRepoOptions count int }{ { name: "PublicRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, Collaborate: util.OptionalBoolFalse}, count: 7, }, { name: "PublicAndPrivateRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFirstPage", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitSecondPage", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 2, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitThirdPage", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14, }, { name: "PublicAndPrivateRepositoriesByNameWithPagesizeLimitFourthPage", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 3, PageSize: 5}, Private: true, Collaborate: util.OptionalBoolFalse}, count: 14, }, { name: "PublicRepositoriesOfUser", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Collaborate: util.OptionalBoolFalse}, count: 2, }, { name: "PublicRepositoriesOfUser2", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Collaborate: util.OptionalBoolFalse}, count: 0, }, { name: "PublicRepositoriesOfUser3", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Collaborate: util.OptionalBoolFalse}, count: 2, }, { name: "PublicAndPrivateRepositoriesOfUser", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, Collaborate: util.OptionalBoolFalse}, count: 4, }, { name: "PublicAndPrivateRepositoriesOfUser2", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, Collaborate: util.OptionalBoolFalse}, count: 0, }, { name: "PublicAndPrivateRepositoriesOfUser3", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true, Collaborate: util.OptionalBoolFalse}, count: 4, }, { name: "PublicRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15}, count: 5, }, { name: "PublicRepositoriesOfUser2IncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18}, count: 1, }, { name: "PublicRepositoriesOfUser3IncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20}, count: 3, }, { name: "PublicAndPrivateRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true}, count: 9, }, { name: "PublicAndPrivateRepositoriesOfUser2IncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true}, count: 4, }, { name: "PublicAndPrivateRepositoriesOfUser3IncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 20, Private: true}, count: 7, }, { name: "PublicRepositoriesOfOrganization", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Collaborate: util.OptionalBoolFalse}, count: 1, }, { name: "PublicAndPrivateRepositoriesOfOrganization", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, Private: true, Collaborate: util.OptionalBoolFalse}, count: 2, }, { name: "AllPublic/PublicRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{PageSize: 10}, AllPublic: true, Collaborate: util.OptionalBoolFalse}, count: 7, }, { name: "AllPublic/PublicAndPrivateRepositoriesByName", - opts: &SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{Keyword: "big_test_", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, AllPublic: true, Collaborate: util.OptionalBoolFalse}, count: 14, }, { name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, AllPublic: true, Template: util.OptionalBoolFalse}, count: 28, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true, AllLimited: true, Template: util.OptionalBoolFalse}, count: 33, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName", - opts: &SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true}, + opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 15, Private: true, AllPublic: true}, count: 15, }, { name: "AllPublic/PublicAndPrivateRepositoriesOfUser2IncludingCollaborativeByName", - opts: &SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, AllPublic: true}, + opts: &repo_model.SearchRepoOptions{Keyword: "test", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 18, Private: true, AllPublic: true}, count: 13, }, { name: "AllPublic/PublicRepositoriesOfOrganization", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse, Template: util.OptionalBoolFalse}, count: 28, }, { name: "AllTemplates", - opts: &SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue}, + opts: &repo_model.SearchRepoOptions{ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Template: util.OptionalBoolTrue}, count: 2, }, + { + name: "OwnerSlashRepoSearch", + opts: &repo_model.SearchRepoOptions{Keyword: "user/repo2", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0}, + count: 3, + }, + { + name: "OwnerSlashSearch", + opts: &repo_model.SearchRepoOptions{Keyword: "user20/", ListOptions: db.ListOptions{Page: 1, PageSize: 10}, Private: true, OwnerID: 0}, + count: 4, + }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - repos, count, err := SearchRepositoryByName(testCase.opts) + repos, count, err := repo_model.SearchRepositoryByName(testCase.opts) assert.NoError(t, err) assert.Equal(t, int64(testCase.count), count) @@ -285,7 +297,21 @@ func TestSearchRepository(t *testing.T) { assert.NotEmpty(t, repo.Name) if len(testCase.opts.Keyword) > 0 { - assert.Contains(t, repo.Name, testCase.opts.Keyword) + // Keyword match condition is different for search terms of form "owner/repo" + if strings.Count(testCase.opts.Keyword, "/") == 1 { + // May still match as a whole... + wholeMatch := strings.Contains(repo.Name, testCase.opts.Keyword) + + pieces := strings.Split(testCase.opts.Keyword, "/") + ownerName := pieces[0] + repoName := pieces[1] + // ... or match in parts + splitMatch := strings.Contains(repo.OwnerName, ownerName) && strings.Contains(repo.Name, repoName) + + assert.True(t, wholeMatch || splitMatch, "Keyword '%s' does not match repo '%s/%s'", testCase.opts.Keyword, repo.Owner.Name, repo.Name) + } else { + assert.Contains(t, repo.Name, testCase.opts.Keyword) + } } if !testCase.opts.Private { @@ -329,29 +355,29 @@ func TestSearchRepositoryByTopicName(t *testing.T) { testCases := []struct { name string - opts *SearchRepoOptions + opts *repo_model.SearchRepoOptions count int }{ { name: "AllPublic/SearchPublicRepositoriesFromTopicAndName", - opts: &SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql"}, + opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql"}, count: 2, }, { name: "AllPublic/OnlySearchPublicRepositoriesFromTopic", - opts: &SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true}, + opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true}, count: 1, }, { name: "AllPublic/OnlySearchMultipleKeywordPublicRepositoriesFromTopic", - opts: &SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true}, + opts: &repo_model.SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true}, count: 2, }, } for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { - _, count, err := SearchRepositoryByName(testCase.opts) + _, count, err := repo_model.SearchRepositoryByName(testCase.opts) assert.NoError(t, err) assert.Equal(t, int64(testCase.count), count) }) diff --git a/models/repo/repo_test.go b/models/repo/repo_test.go index 92b95f1d41..8ae84eab52 100644 --- a/models/repo/repo_test.go +++ b/models/repo/repo_test.go @@ -2,24 +2,32 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test 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" + "code.gitea.io/gitea/modules/util" "github.com/stretchr/testify/assert" ) +var ( + countRepospts = repo_model.CountRepositoryOptions{OwnerID: 10} + countReposptsPublic = repo_model.CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolFalse} + countReposptsPrivate = repo_model.CountRepositoryOptions{OwnerID: 10, Private: util.OptionalBoolTrue} +) + func TestGetRepositoryCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err1 := GetRepositoryCount(db.DefaultContext, 10) - privateCount, err2 := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)}) - publicCount, err3 := GetPublicRepositoryCount(&user_model.User{ID: int64(10)}) + ctx := db.DefaultContext + count, err1 := repo_model.CountRepositories(ctx, countRepospts) + privateCount, err2 := repo_model.CountRepositories(ctx, countReposptsPrivate) + publicCount, err3 := repo_model.CountRepositories(ctx, countReposptsPublic) assert.NoError(t, err1) assert.NoError(t, err2) assert.NoError(t, err3) @@ -30,7 +38,7 @@ func TestGetRepositoryCount(t *testing.T) { func TestGetPublicRepositoryCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err := GetPublicRepositoryCount(&user_model.User{ID: int64(10)}) + count, err := repo_model.CountRepositories(db.DefaultContext, countReposptsPublic) assert.NoError(t, err) assert.Equal(t, int64(1), count) } @@ -38,14 +46,14 @@ func TestGetPublicRepositoryCount(t *testing.T) { func TestGetPrivateRepositoryCount(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - count, err := GetPrivateRepositoryCount(&user_model.User{ID: int64(10)}) + count, err := repo_model.CountRepositories(db.DefaultContext, countReposptsPrivate) assert.NoError(t, err) assert.Equal(t, int64(2), count) } func TestRepoAPIURL(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 10}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 10}).(*repo_model.Repository) assert.Equal(t, "https://try.gitea.io/api/v1/repos/user12/repo10", repo.APIURL()) } diff --git a/models/repo/repo_unit.go b/models/repo/repo_unit.go index 0f6b41933d..8c17d6138c 100644 --- a/models/repo/repo_unit.go +++ b/models/repo/repo_unit.go @@ -5,11 +5,13 @@ package repo import ( + "context" "fmt" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/json" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "xorm.io/xorm" @@ -147,25 +149,11 @@ func (cfg *PullRequestsConfig) GetDefaultMergeStyle() MergeStyle { return cfg.DefaultMergeStyle } - return MergeStyleMerge -} + if setting.Repository.PullRequest.DefaultMergeStyle != "" { + return MergeStyle(setting.Repository.PullRequest.DefaultMergeStyle) + } -// AllowedMergeStyleCount returns the total count of allowed merge styles for the PullRequestsConfig -func (cfg *PullRequestsConfig) AllowedMergeStyleCount() int { - count := 0 - if cfg.AllowMerge { - count++ - } - if cfg.AllowRebase { - count++ - } - if cfg.AllowRebaseMerge { - count++ - } - if cfg.AllowSquash { - count++ - } - return count + return MergeStyleMerge } // BeforeSet is invoked from XORM before setting the value of a field of this object. @@ -224,9 +212,9 @@ func (r *RepoUnit) ExternalTrackerConfig() *ExternalTrackerConfig { return r.Config.(*ExternalTrackerConfig) } -func getUnitsByRepoID(e db.Engine, repoID int64) (units []*RepoUnit, err error) { +func getUnitsByRepoID(ctx context.Context, repoID int64) (units []*RepoUnit, err error) { var tmpUnits []*RepoUnit - if err := e.Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil { + if err := db.GetEngine(ctx).Where("repo_id = ?", repoID).Find(&tmpUnits); err != nil { return nil, err } diff --git a/models/repo/star.go b/models/repo/star.go index 8db297e3b4..113b56f595 100644 --- a/models/repo/star.go +++ b/models/repo/star.go @@ -5,6 +5,8 @@ package repo import ( + "context" + "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/timeutil" @@ -29,7 +31,7 @@ func StarRepo(userID, repoID int64, star bool) error { return err } defer committer.Close() - staring := isStaring(db.GetEngine(ctx), userID, repoID) + staring := IsStaring(ctx, userID, repoID) if star { if staring { @@ -65,12 +67,8 @@ func StarRepo(userID, repoID int64, star bool) error { } // IsStaring checks if user has starred given repository. -func IsStaring(userID, repoID int64) bool { - return isStaring(db.GetEngine(db.DefaultContext), userID, repoID) -} - -func isStaring(e db.Engine, userID, repoID int64) bool { - has, _ := e.Get(&Star{UID: userID, RepoID: repoID}) +func IsStaring(ctx context.Context, userID, repoID int64) bool { + has, _ := db.GetEngine(ctx).Get(&Star{UID: userID, RepoID: repoID}) return has } diff --git a/models/repo/star_test.go b/models/repo/star_test.go index 20c4b6bef4..aa72b1dac8 100644 --- a/models/repo/star_test.go +++ b/models/repo/star_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -17,26 +18,26 @@ func TestStarRepo(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) const userID = 2 const repoID = 1 - unittest.AssertNotExistsBean(t, &Star{UID: userID, RepoID: repoID}) - assert.NoError(t, StarRepo(userID, repoID, true)) - unittest.AssertExistsAndLoadBean(t, &Star{UID: userID, RepoID: repoID}) - assert.NoError(t, StarRepo(userID, repoID, true)) - unittest.AssertExistsAndLoadBean(t, &Star{UID: userID, RepoID: repoID}) - assert.NoError(t, StarRepo(userID, repoID, false)) - unittest.AssertNotExistsBean(t, &Star{UID: userID, RepoID: repoID}) + unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) + assert.NoError(t, repo_model.StarRepo(userID, repoID, true)) + unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) + assert.NoError(t, repo_model.StarRepo(userID, repoID, true)) + unittest.AssertExistsAndLoadBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) + assert.NoError(t, repo_model.StarRepo(userID, repoID, false)) + unittest.AssertNotExistsBean(t, &repo_model.Star{UID: userID, RepoID: repoID}) } func TestIsStaring(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.True(t, IsStaring(2, 4)) - assert.False(t, IsStaring(3, 4)) + assert.True(t, repo_model.IsStaring(db.DefaultContext, 2, 4)) + assert.False(t, repo_model.IsStaring(db.DefaultContext, 3, 4)) } func TestRepository_GetStargazers(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 4}).(*Repository) - gazers, err := GetStargazers(repo, db.ListOptions{Page: 0}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) + gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) assert.NoError(t, err) if assert.Len(t, gazers, 1) { assert.Equal(t, int64(2), gazers[0].ID) @@ -46,8 +47,8 @@ func TestRepository_GetStargazers(t *testing.T) { func TestRepository_GetStargazers2(t *testing.T) { // repo with stargazers assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 3}).(*Repository) - gazers, err := GetStargazers(repo, db.ListOptions{Page: 0}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + gazers, err := repo_model.GetStargazers(repo, db.ListOptions{Page: 0}) assert.NoError(t, err) assert.Len(t, gazers, 0) } diff --git a/models/repo/topic.go b/models/repo/topic.go index 121863519b..2a16467215 100644 --- a/models/repo/topic.go +++ b/models/repo/topic.go @@ -99,8 +99,9 @@ func GetTopicByName(name string) (*Topic, error) { // addTopicByNameToRepo adds a topic name to a repo and increments the topic count. // Returns topic after the addition -func addTopicByNameToRepo(e db.Engine, repoID int64, topicName string) (*Topic, error) { +func addTopicByNameToRepo(ctx context.Context, repoID int64, topicName string) (*Topic, error) { var topic Topic + e := db.GetEngine(ctx) has, err := e.Where("name = ?", topicName).Get(&topic) if err != nil { return nil, err @@ -108,7 +109,7 @@ func addTopicByNameToRepo(e db.Engine, repoID int64, topicName string) (*Topic, if !has { topic.Name = topicName topic.RepoCount = 1 - if _, err := e.Insert(&topic); err != nil { + if err := db.Insert(ctx, &topic); err != nil { return nil, err } } else { @@ -118,7 +119,7 @@ func addTopicByNameToRepo(e db.Engine, repoID int64, topicName string) (*Topic, } } - if _, err := e.Insert(&RepoTopic{ + if err := db.Insert(ctx, &RepoTopic{ RepoID: repoID, TopicID: topic.ID, }); err != nil { @@ -129,8 +130,9 @@ func addTopicByNameToRepo(e db.Engine, repoID int64, topicName string) (*Topic, } // removeTopicFromRepo remove a topic from a repo and decrements the topic repo count -func removeTopicFromRepo(e db.Engine, repoID int64, topic *Topic) error { +func removeTopicFromRepo(ctx context.Context, repoID int64, topic *Topic) error { topic.RepoCount-- + e := db.GetEngine(ctx) if _, err := e.ID(topic.ID).Cols("repo_count").Update(topic); err != nil { return err } @@ -208,17 +210,13 @@ func CountTopics(opts *FindTopicOptions) (int64, error) { } // GetRepoTopicByName retrieves topic from name for a repo if it exist -func GetRepoTopicByName(repoID int64, topicName string) (*Topic, error) { - return getRepoTopicByName(db.GetEngine(db.DefaultContext), repoID, topicName) -} - -func getRepoTopicByName(e db.Engine, repoID int64, topicName string) (*Topic, error) { +func GetRepoTopicByName(ctx context.Context, repoID int64, topicName string) (*Topic, error) { cond := builder.NewCond() var topic Topic cond = cond.And(builder.Eq{"repo_topic.repo_id": repoID}).And(builder.Eq{"topic.name": topicName}) - sess := e.Table("topic").Where(cond) + sess := db.GetEngine(ctx).Table("topic").Where(cond) sess.Join("INNER", "repo_topic", "repo_topic.topic_id = topic.id") - has, err := sess.Get(&topic) + has, err := sess.Select("topic.*").Get(&topic) if has { return &topic, err } @@ -234,7 +232,7 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { defer committer.Close() sess := db.GetEngine(ctx) - topic, err := getRepoTopicByName(sess, repoID, topicName) + topic, err := GetRepoTopicByName(ctx, repoID, topicName) if err != nil { return nil, err } @@ -243,7 +241,7 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { return topic, nil } - topic, err = addTopicByNameToRepo(sess, repoID, topicName) + topic, err = addTopicByNameToRepo(ctx, repoID, topicName) if err != nil { return nil, err } @@ -266,7 +264,7 @@ func AddTopic(repoID int64, topicName string) (*Topic, error) { // DeleteTopic removes a topic name from a repository (if it has it) func DeleteTopic(repoID int64, topicName string) (*Topic, error) { - topic, err := GetRepoTopicByName(repoID, topicName) + topic, err := GetRepoTopicByName(db.DefaultContext, repoID, topicName) if err != nil { return nil, err } @@ -275,7 +273,7 @@ func DeleteTopic(repoID int64, topicName string) (*Topic, error) { return nil, nil } - err = removeTopicFromRepo(db.GetEngine(db.DefaultContext), repoID, topic) + err = removeTopicFromRepo(db.DefaultContext, repoID, topic) return topic, err } @@ -329,14 +327,14 @@ func SaveTopics(repoID int64, topicNames ...string) error { } for _, topicName := range addedTopicNames { - _, err := addTopicByNameToRepo(sess, repoID, topicName) + _, err := addTopicByNameToRepo(ctx, repoID, topicName) if err != nil { return err } } for _, topic := range removeTopics { - err := removeTopicFromRepo(sess, repoID, topic) + err := removeTopicFromRepo(ctx, repoID, topic) if err != nil { return err } @@ -361,7 +359,7 @@ func SaveTopics(repoID int64, topicNames ...string) error { // GenerateTopics generates topics from a template repository func GenerateTopics(ctx context.Context, templateRepo, generateRepo *Repository) error { for _, topic := range templateRepo.Topics { - if _, err := addTopicByNameToRepo(db.GetEngine(ctx), generateRepo.ID, topic); err != nil { + if _, err := addTopicByNameToRepo(ctx, generateRepo.ID, topic); err != nil { return err } } diff --git a/models/repo/topic_test.go b/models/repo/topic_test.go index 353d96ef3e..8187addb81 100644 --- a/models/repo/topic_test.go +++ b/models/repo/topic_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "github.com/stretchr/testify/assert" @@ -19,47 +20,47 @@ func TestAddTopic(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - topics, _, err := FindTopics(&FindTopicOptions{}) + topics, _, err := repo_model.FindTopics(&repo_model.FindTopicOptions{}) assert.NoError(t, err) assert.Len(t, topics, totalNrOfTopics) - topics, total, err := FindTopics(&FindTopicOptions{ + topics, total, err := repo_model.FindTopics(&repo_model.FindTopicOptions{ ListOptions: db.ListOptions{Page: 1, PageSize: 2}, }) assert.NoError(t, err) assert.Len(t, topics, 2) assert.EqualValues(t, 6, total) - topics, _, err = FindTopics(&FindTopicOptions{ + topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{ RepoID: 1, }) assert.NoError(t, err) assert.Len(t, topics, repo1NrOfTopics) - assert.NoError(t, SaveTopics(2, "golang")) + assert.NoError(t, repo_model.SaveTopics(2, "golang")) repo2NrOfTopics := 1 - topics, _, err = FindTopics(&FindTopicOptions{}) + topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{}) assert.NoError(t, err) assert.Len(t, topics, totalNrOfTopics) - topics, _, err = FindTopics(&FindTopicOptions{ + topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{ RepoID: 2, }) assert.NoError(t, err) assert.Len(t, topics, repo2NrOfTopics) - assert.NoError(t, SaveTopics(2, "golang", "gitea")) + assert.NoError(t, repo_model.SaveTopics(2, "golang", "gitea")) repo2NrOfTopics = 2 totalNrOfTopics++ - topic, err := GetTopicByName("gitea") + topic, err := repo_model.GetTopicByName("gitea") assert.NoError(t, err) assert.EqualValues(t, 1, topic.RepoCount) - topics, _, err = FindTopics(&FindTopicOptions{}) + topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{}) assert.NoError(t, err) assert.Len(t, topics, totalNrOfTopics) - topics, _, err = FindTopics(&FindTopicOptions{ + topics, _, err = repo_model.FindTopics(&repo_model.FindTopicOptions{ RepoID: 2, }) assert.NoError(t, err) @@ -67,14 +68,14 @@ func TestAddTopic(t *testing.T) { } func TestTopicValidator(t *testing.T) { - assert.True(t, ValidateTopic("12345")) - assert.True(t, ValidateTopic("2-test")) - assert.True(t, ValidateTopic("test-3")) - assert.True(t, ValidateTopic("first")) - assert.True(t, ValidateTopic("second-test-topic")) - assert.True(t, ValidateTopic("third-project-topic-with-max-length")) + assert.True(t, repo_model.ValidateTopic("12345")) + assert.True(t, repo_model.ValidateTopic("2-test")) + assert.True(t, repo_model.ValidateTopic("test-3")) + assert.True(t, repo_model.ValidateTopic("first")) + assert.True(t, repo_model.ValidateTopic("second-test-topic")) + assert.True(t, repo_model.ValidateTopic("third-project-topic-with-max-length")) - assert.False(t, ValidateTopic("$fourth-test,topic")) - assert.False(t, ValidateTopic("-fifth-test-topic")) - assert.False(t, ValidateTopic("sixth-go-project-topic-with-excess-length")) + assert.False(t, repo_model.ValidateTopic("$fourth-test,topic")) + assert.False(t, repo_model.ValidateTopic("-fifth-test-topic")) + assert.False(t, repo_model.ValidateTopic("sixth-go-project-topic-with-excess-length")) } diff --git a/models/repo/update.go b/models/repo/update.go index efc562a405..07776ebc01 100644 --- a/models/repo/update.go +++ b/models/repo/update.go @@ -42,17 +42,12 @@ func UpdateRepositoryUpdatedTime(repoID int64, updateTime time.Time) error { return err } -// UpdateRepositoryColsCtx updates repository's columns -func UpdateRepositoryColsCtx(ctx context.Context, repo *Repository, cols ...string) error { +// UpdateRepositoryCols updates repository's columns +func UpdateRepositoryCols(ctx context.Context, repo *Repository, cols ...string) error { _, err := db.GetEngine(ctx).ID(repo.ID).Cols(cols...).Update(repo) return err } -// UpdateRepositoryCols updates repository's columns -func UpdateRepositoryCols(repo *Repository, cols ...string) error { - return UpdateRepositoryColsCtx(db.DefaultContext, repo, cols...) -} - // ErrReachLimitOfRepo represents a "ReachLimitOfRepo" kind of error. type ErrReachLimitOfRepo struct { Limit int @@ -110,7 +105,7 @@ func CheckCreateRepository(doer, u *user_model.User, name string, overwriteOrAdo return err } - has, err := IsRepositoryExist(u, name) + has, err := IsRepositoryExist(db.DefaultContext, u, name) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { @@ -141,7 +136,7 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s return err } - has, err := IsRepositoryExist(repo.Owner, newRepoName) + has, err := IsRepositoryExist(db.DefaultContext, repo.Owner, newRepoName) if err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { @@ -177,3 +172,11 @@ func ChangeRepositoryName(doer *user_model.User, repo *Repository, newRepoName s return committer.Commit() } + +// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize +func UpdateRepoSize(ctx context.Context, repoID, size int64) error { + _, err := db.GetEngine(ctx).ID(repoID).Cols("size").NoAutoTime().Update(&Repository{ + Size: size, + }) + return err +} diff --git a/models/repo/user_repo.go b/models/repo/user_repo.go index 18a04f7267..e697505b81 100644 --- a/models/repo/user_repo.go +++ b/models/repo/user_repo.go @@ -8,7 +8,11 @@ import ( "context" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" + api "code.gitea.io/gitea/modules/structs" + + "xorm.io/builder" ) // GetStarredRepos returns the repos starred by a particular user @@ -52,36 +56,117 @@ func GetWatchedRepos(userID int64, private bool, listOptions db.ListOptions) ([] return repos, total, err } -// CountUserRepositories returns number of repositories user owns. -// Argument private only takes effect when it is false, -// set it true to count all repositories. -func CountUserRepositories(userID int64, private bool) int64 { - return countRepositories(userID, private) +// GetRepoAssignees returns all users that have write access and can be assigned to issues +// of the repository, +func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.User, err error) { + if err = repo.GetOwner(ctx); err != nil { + return nil, err + } + + e := db.GetEngine(ctx) + userIDs := make([]int64, 0, 10) + if err = e.Table("access"). + Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite). + Select("user_id"). + Find(&userIDs); err != nil { + return nil, err + } + + additionalUserIDs := make([]int64, 0, 10) + if err = e.Table("team_user"). + Join("INNER", "team_repo", "`team_repo`.team_id = `team_user`.team_id"). + Join("INNER", "team_unit", "`team_unit`.team_id = `team_user`.team_id"). + Where("`team_repo`.repo_id = ? AND `team_unit`.access_mode >= ?", repo.ID, perm.AccessModeWrite). + Distinct("`team_user`.uid"). + Select("`team_user`.uid"). + Find(&additionalUserIDs); err != nil { + return nil, err + } + + uidMap := map[int64]bool{} + i := 0 + for _, uid := range userIDs { + if uidMap[uid] { + continue + } + uidMap[uid] = true + userIDs[i] = uid + i++ + } + userIDs = userIDs[:i] + userIDs = append(userIDs, additionalUserIDs...) + + for _, uid := range additionalUserIDs { + if uidMap[uid] { + continue + } + userIDs[i] = uid + i++ + } + userIDs = userIDs[:i] + + // Leave a seat for owner itself to append later, but if owner is an organization + // and just waste 1 unit is cheaper than re-allocate memory once. + users := make([]*user_model.User, 0, len(userIDs)+1) + if len(userIDs) > 0 { + if err = e.In("id", userIDs).Find(&users); err != nil { + return nil, err + } + } + if !repo.Owner.IsOrganization() && !uidMap[repo.OwnerID] { + users = append(users, repo.Owner) + } + + return users, nil } -func getRepositoryCount(e db.Engine, ownerID int64) (int64, error) { - return e.Count(&Repository{OwnerID: ownerID}) -} +// GetReviewers get all users can be requested to review: +// * for private repositories this returns all users that have read access or higher to the repository. +// * for public repositories this returns all users that have read access or higher to the repository, +// all repo watchers and all organization members. +// TODO: may be we should have a busy choice for users to block review request to them. +func GetReviewers(ctx context.Context, repo *Repository, doerID, posterID int64) ([]*user_model.User, error) { + // Get the owner of the repository - this often already pre-cached and if so saves complexity for the following queries + if err := repo.GetOwner(ctx); err != nil { + return nil, err + } -func getPublicRepositoryCount(e db.Engine, u *user_model.User) (int64, error) { - return e.Where("is_private = ?", false).Count(&Repository{OwnerID: u.ID}) -} + cond := builder.And(builder.Neq{"`user`.id": posterID}) -func getPrivateRepositoryCount(e db.Engine, u *user_model.User) (int64, error) { - return e.Where("is_private = ?", true).Count(&Repository{OwnerID: u.ID}) -} + if repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate { + // This a private repository: + // Anyone who can read the repository is a requestable reviewer -// GetRepositoryCount returns the total number of repositories of user. -func GetRepositoryCount(ctx context.Context, ownerID int64) (int64, error) { - return getRepositoryCount(db.GetEngine(ctx), ownerID) -} + cond = cond.And(builder.In("`user`.id", + builder.Select("user_id").From("access").Where( + builder.Eq{"repo_id": repo.ID}. + And(builder.Gte{"mode": perm.AccessModeRead}), + ), + )) -// GetPublicRepositoryCount returns the total number of public repositories of user. -func GetPublicRepositoryCount(u *user_model.User) (int64, error) { - return getPublicRepositoryCount(db.GetEngine(db.DefaultContext), u) -} + if repo.Owner.Type == user_model.UserTypeIndividual && repo.Owner.ID != posterID { + // as private *user* repos don't generate an entry in the `access` table, + // the owner of a private repo needs to be explicitly added. + cond = cond.Or(builder.Eq{"`user`.id": repo.Owner.ID}) + } -// GetPrivateRepositoryCount returns the total number of private repositories of user. -func GetPrivateRepositoryCount(u *user_model.User) (int64, error) { - return getPrivateRepositoryCount(db.GetEngine(db.DefaultContext), u) + } else { + // This is a "public" repository: + // Any user that has read access, is a watcher or organization member can be requested to review + cond = cond.And(builder.And(builder.In("`user`.id", + builder.Select("user_id").From("access"). + Where(builder.Eq{"repo_id": repo.ID}. + And(builder.Gte{"mode": perm.AccessModeRead})), + ).Or(builder.In("`user`.id", + builder.Select("user_id").From("watch"). + Where(builder.Eq{"repo_id": repo.ID}. + And(builder.In("mode", WatchModeNormal, WatchModeAuto))), + ).Or(builder.In("`user`.id", + builder.Select("uid").From("org_user"). + Where(builder.Eq{"org_id": repo.OwnerID}), + ))))) + } + + users := make([]*user_model.User, 0, 8) + return users, db.GetEngine(ctx).Where(cond).OrderBy("name").Find(&users) } diff --git a/models/repo/user_repo_test.go b/models/repo/user_repo_test.go new file mode 100644 index 0000000000..d024729b9c --- /dev/null +++ b/models/repo/user_repo_test.go @@ -0,0 +1,74 @@ +// Copyright 2017 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo_test + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestRepoAssignees(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + users, err := repo_model.GetRepoAssignees(db.DefaultContext, repo2) + assert.NoError(t, err) + assert.Len(t, users, 1) + assert.Equal(t, users[0].ID, int64(2)) + + repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository) + users, err = repo_model.GetRepoAssignees(db.DefaultContext, repo21) + assert.NoError(t, err) + assert.Len(t, users, 3) + assert.Equal(t, users[0].ID, int64(15)) + assert.Equal(t, users[1].ID, int64(18)) + assert.Equal(t, users[2].ID, int64(16)) +} + +func TestRepoGetReviewers(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // test public repo + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + + ctx := db.DefaultContext + reviewers, err := repo_model.GetReviewers(ctx, repo1, 2, 2) + assert.NoError(t, err) + assert.Len(t, reviewers, 4) + + // should include doer if doer is not PR poster. + reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 2) + assert.NoError(t, err) + assert.Len(t, reviewers, 4) + + // should not include PR poster, if PR poster would be otherwise eligible + reviewers, err = repo_model.GetReviewers(ctx, repo1, 11, 4) + assert.NoError(t, err) + assert.Len(t, reviewers, 3) + + // test private user repo + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + + reviewers, err = repo_model.GetReviewers(ctx, repo2, 2, 4) + assert.NoError(t, err) + assert.Len(t, reviewers, 1) + assert.EqualValues(t, reviewers[0].ID, 2) + + // test private org repo + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + + reviewers, err = repo_model.GetReviewers(ctx, repo3, 2, 1) + assert.NoError(t, err) + assert.Len(t, reviewers, 2) + + reviewers, err = repo_model.GetReviewers(ctx, repo3, 2, 2) + assert.NoError(t, err) + assert.Len(t, reviewers, 1) +} diff --git a/models/repo/watch.go b/models/repo/watch.go index 8e54f0970d..ecc25ee32b 100644 --- a/models/repo/watch.go +++ b/models/repo/watch.go @@ -116,8 +116,8 @@ func WatchRepoMode(userID, repoID int64, mode WatchMode) (err error) { return watchRepoMode(db.DefaultContext, watch, mode) } -// WatchRepoCtx watch or unwatch repository. -func WatchRepoCtx(ctx context.Context, userID, repoID int64, doWatch bool) (err error) { +// WatchRepo watch or unwatch repository. +func WatchRepo(ctx context.Context, userID, repoID int64, doWatch bool) (err error) { var watch Watch if watch, err = GetWatch(ctx, userID, repoID); err != nil { return err @@ -132,11 +132,6 @@ func WatchRepoCtx(ctx context.Context, userID, repoID int64, doWatch bool) (err return err } -// WatchRepo watch or unwatch repository. -func WatchRepo(userID, repoID int64, watch bool) (err error) { - return WatchRepoCtx(db.DefaultContext, userID, repoID, watch) -} - // GetWatchers returns all watchers of given repository. func GetWatchers(ctx context.Context, repoID int64) ([]*Watch, error) { watches := make([]*Watch, 0, 10) @@ -176,7 +171,8 @@ func GetRepoWatchers(repoID int64, opts db.ListOptions) ([]*user_model.User, err return users, sess.Find(&users) } -func watchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error { +// WatchIfAuto subscribes to repo if AutoWatchOnChanges is set +func WatchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error { if !isWrite || !setting.Service.AutoWatchOnChanges { return nil } @@ -189,8 +185,3 @@ func watchIfAuto(ctx context.Context, userID, repoID int64, isWrite bool) error } return watchRepoMode(ctx, watch, WatchModeAuto) } - -// WatchIfAuto subscribes to repo if AutoWatchOnChanges is set -func WatchIfAuto(userID, repoID int64, isWrite bool) error { - return watchIfAuto(db.DefaultContext, userID, repoID, isWrite) -} diff --git a/models/repo/watch_test.go b/models/repo/watch_test.go index 2ff3ced2dc..3875e63fd8 100644 --- a/models/repo/watch_test.go +++ b/models/repo/watch_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "testing" "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" @@ -17,20 +18,20 @@ import ( func TestIsWatching(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.True(t, IsWatching(1, 1)) - assert.True(t, IsWatching(4, 1)) - assert.True(t, IsWatching(11, 1)) + assert.True(t, repo_model.IsWatching(1, 1)) + assert.True(t, repo_model.IsWatching(4, 1)) + assert.True(t, repo_model.IsWatching(11, 1)) - assert.False(t, IsWatching(1, 5)) - assert.False(t, IsWatching(8, 1)) - assert.False(t, IsWatching(unittest.NonexistentID, unittest.NonexistentID)) + assert.False(t, repo_model.IsWatching(1, 5)) + assert.False(t, repo_model.IsWatching(8, 1)) + assert.False(t, repo_model.IsWatching(unittest.NonexistentID, unittest.NonexistentID)) } func TestGetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watches, err := GetWatchers(db.DefaultContext, repo.ID) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + watches, err := repo_model.GetWatchers(db.DefaultContext, repo.ID) assert.NoError(t, err) // One watchers are inactive, thus minus 1 assert.Len(t, watches, repo.NumWatches-1) @@ -38,7 +39,7 @@ func TestGetWatchers(t *testing.T) { assert.EqualValues(t, repo.ID, watch.RepoID) } - watches, err = GetWatchers(db.DefaultContext, unittest.NonexistentID) + watches, err = repo_model.GetWatchers(db.DefaultContext, unittest.NonexistentID) assert.NoError(t, err) assert.Len(t, watches, 0) } @@ -46,16 +47,16 @@ func TestGetWatchers(t *testing.T) { func TestRepository_GetWatchers(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) for _, watcher := range watchers { - unittest.AssertExistsAndLoadBean(t, &Watch{UserID: watcher.ID, RepoID: repo.ID}) + unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{UserID: watcher.ID, RepoID: repo.ID}) } - repo = unittest.AssertExistsAndLoadBean(t, &Repository{ID: 9}).(*Repository) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + repo = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 9}).(*repo_model.Repository) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, 0) } @@ -63,8 +64,8 @@ func TestRepository_GetWatchers(t *testing.T) { func TestWatchIfAuto(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) - watchers, err := GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + watchers, err := repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, repo.NumWatches) @@ -73,46 +74,46 @@ func TestWatchIfAuto(t *testing.T) { prevCount := repo.NumWatches // Must not add watch - assert.NoError(t, WatchIfAuto(8, 1, true)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 8, 1, true)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch - assert.NoError(t, WatchIfAuto(10, 1, true)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 10, 1, true)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) setting.Service.AutoWatchOnChanges = true // Must not add watch - assert.NoError(t, WatchIfAuto(8, 1, true)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 8, 1, true)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should not add watch - assert.NoError(t, WatchIfAuto(12, 1, false)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, false)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Should add watch - assert.NoError(t, WatchIfAuto(12, 1, true)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, true)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount+1) // Should remove watch, inhibit from adding auto - assert.NoError(t, WatchRepo(12, 1, false)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, 12, 1, false)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) // Must not add watch - assert.NoError(t, WatchIfAuto(12, 1, true)) - watchers, err = GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) + assert.NoError(t, repo_model.WatchIfAuto(db.DefaultContext, 12, 1, true)) + watchers, err = repo_model.GetRepoWatchers(repo.ID, db.ListOptions{Page: 1}) assert.NoError(t, err) assert.Len(t, watchers, prevCount) } @@ -120,20 +121,20 @@ func TestWatchIfAuto(t *testing.T) { func TestWatchRepoMode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 0) - assert.NoError(t, WatchRepoMode(12, 1, WatchModeAuto)) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeAuto}, 1) + assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeAuto)) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 1) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1, Mode: repo_model.WatchModeAuto}, 1) - assert.NoError(t, WatchRepoMode(12, 1, WatchModeNormal)) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeNormal}, 1) + assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeNormal)) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 1) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1, Mode: repo_model.WatchModeNormal}, 1) - assert.NoError(t, WatchRepoMode(12, 1, WatchModeDont)) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 1) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1, Mode: WatchModeDont}, 1) + assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeDont)) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 1) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1, Mode: repo_model.WatchModeDont}, 1) - assert.NoError(t, WatchRepoMode(12, 1, WatchModeNone)) - unittest.AssertCount(t, &Watch{UserID: 12, RepoID: 1}, 0) + assert.NoError(t, repo_model.WatchRepoMode(12, 1, repo_model.WatchModeNone)) + unittest.AssertCount(t, &repo_model.Watch{UserID: 12, RepoID: 1}, 0) } diff --git a/models/repo/wiki_test.go b/models/repo/wiki_test.go index f5e61e5ae3..339289e05d 100644 --- a/models/repo/wiki_test.go +++ b/models/repo/wiki_test.go @@ -2,12 +2,13 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package repo +package repo_test import ( "path/filepath" "testing" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" @@ -17,7 +18,7 @@ import ( func TestRepository_WikiCloneLink(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) cloneLink := repo.WikiCloneLink() assert.Equal(t, "ssh://sshuser@try.gitea.io:3000/user2/repo1.wiki.git", cloneLink.SSH) assert.Equal(t, "https://try.gitea.io/user2/repo1.wiki.git", cloneLink.HTTPS) @@ -26,20 +27,20 @@ func TestRepository_WikiCloneLink(t *testing.T) { func TestWikiPath(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) expected := filepath.Join(setting.RepoRootPath, "user2/repo1.wiki.git") - assert.Equal(t, expected, WikiPath("user2", "repo1")) + assert.Equal(t, expected, repo_model.WikiPath("user2", "repo1")) } func TestRepository_WikiPath(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - repo := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) expected := filepath.Join(setting.RepoRootPath, "user2/repo1.wiki.git") assert.Equal(t, expected, repo.WikiPath()) } func TestRepository_HasWiki(t *testing.T) { unittest.PrepareTestEnv(t) - repo1 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) assert.True(t, repo1.HasWiki()) - repo2 := unittest.AssertExistsAndLoadBean(t, &Repository{ID: 2}).(*Repository) + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) assert.False(t, repo2.HasWiki()) } diff --git a/models/repo_collaboration.go b/models/repo_collaboration.go index d94b61b449..8cbd836a42 100644 --- a/models/repo_collaboration.go +++ b/models/repo_collaboration.go @@ -12,37 +12,21 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" - "code.gitea.io/gitea/modules/timeutil" "xorm.io/builder" ) -// Collaboration represent the relation between an individual and a repository. -type Collaboration struct { - ID int64 `xorm:"pk autoincr"` - RepoID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - UserID int64 `xorm:"UNIQUE(s) INDEX NOT NULL"` - Mode perm.AccessMode `xorm:"DEFAULT 2 NOT NULL"` - CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"` - UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"` -} - -func init() { - db.RegisterModel(new(Collaboration)) -} - func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_model.User) error { - collaboration := &Collaboration{ + collaboration := &repo_model.Collaboration{ RepoID: repo.ID, UserID: u.ID, } - e := db.GetEngine(ctx) - has, err := e.Get(collaboration) + has, err := db.GetByBean(ctx, collaboration) if err != nil { return err } else if has { @@ -50,11 +34,11 @@ func addCollaborator(ctx context.Context, repo *repo_model.Repository, u *user_m } collaboration.Mode = perm.AccessModeWrite - if _, err = e.InsertOne(collaboration); err != nil { + if err = db.Insert(ctx, collaboration); err != nil { return err } - return recalculateUserAccess(ctx, repo, u.ID) + return access_model.RecalculateUserAccess(ctx, repo, u.ID) } // AddCollaborator adds new collaboration to a repository with default access mode. @@ -72,132 +56,9 @@ func AddCollaborator(repo *repo_model.Repository, u *user_model.User) error { return committer.Commit() } -func getCollaborations(e db.Engine, repoID int64, listOptions db.ListOptions) ([]*Collaboration, error) { - if listOptions.Page == 0 { - collaborations := make([]*Collaboration, 0, 8) - return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repoID}) - } - - e = db.SetEnginePagination(e, &listOptions) - - collaborations := make([]*Collaboration, 0, listOptions.PageSize) - return collaborations, e.Find(&collaborations, &Collaboration{RepoID: repoID}) -} - -// Collaborator represents a user with collaboration details. -type Collaborator struct { - *user_model.User - Collaboration *Collaboration -} - -func getCollaborators(e db.Engine, repoID int64, listOptions db.ListOptions) ([]*Collaborator, error) { - collaborations, err := getCollaborations(e, repoID, listOptions) - if err != nil { - return nil, fmt.Errorf("getCollaborations: %v", err) - } - - collaborators := make([]*Collaborator, 0, len(collaborations)) - for _, c := range collaborations { - user, err := user_model.GetUserByIDEngine(e, 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) - user = user_model.NewGhostUser() - } else { - return nil, err - } - } - collaborators = append(collaborators, &Collaborator{ - User: user, - Collaboration: c, - }) - } - return collaborators, nil -} - -// GetCollaborators returns the collaborators for a repository -func GetCollaborators(repoID int64, listOptions db.ListOptions) ([]*Collaborator, error) { - return getCollaborators(db.GetEngine(db.DefaultContext), repoID, listOptions) -} - -// CountCollaborators returns total number of collaborators for a repository -func CountCollaborators(repoID int64) (int64, error) { - return db.GetEngine(db.DefaultContext).Where("repo_id = ? ", repoID).Count(&Collaboration{}) -} - -func getCollaboration(e db.Engine, repoID, uid int64) (*Collaboration, error) { - collaboration := &Collaboration{ - RepoID: repoID, - UserID: uid, - } - has, err := e.Get(collaboration) - if !has { - collaboration = nil - } - return collaboration, err -} - -func isCollaborator(e db.Engine, repoID, userID int64) (bool, error) { - return e.Get(&Collaboration{RepoID: repoID, UserID: userID}) -} - -// IsCollaborator check if a user is a collaborator of a repository -func IsCollaborator(repoID, userID int64) (bool, error) { - return isCollaborator(db.GetEngine(db.DefaultContext), repoID, userID) -} - -func changeCollaborationAccessMode(e db.Engine, repo *repo_model.Repository, uid int64, mode perm.AccessMode) error { - // Discard invalid input - if mode <= perm.AccessModeNone || mode > perm.AccessModeOwner { - return nil - } - - collaboration := &Collaboration{ - RepoID: repo.ID, - UserID: uid, - } - has, err := e.Get(collaboration) - if err != nil { - return fmt.Errorf("get collaboration: %v", 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: %v", 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: %v", err) - } - - return nil -} - -// ChangeCollaborationAccessMode sets new access mode for the collaboration. -func ChangeCollaborationAccessMode(repo *repo_model.Repository, uid int64, mode perm.AccessMode) error { - ctx, committer, err := db.TxContext() - if err != nil { - return err - } - defer committer.Close() - - if err := changeCollaborationAccessMode(db.GetEngine(ctx), repo, uid, mode); err != nil { - return err - } - - return committer.Commit() -} - // DeleteCollaboration removes collaboration relation between the user and repository. func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) { - collaboration := &Collaboration{ + collaboration := &repo_model.Collaboration{ RepoID: repo.ID, UserID: uid, } @@ -210,11 +71,11 @@ func DeleteCollaboration(repo *repo_model.Repository, uid int64) (err error) { if has, err := db.GetEngine(ctx).Delete(collaboration); err != nil || has == 0 { return err - } else if err = recalculateAccesses(ctx, repo); err != nil { + } else if err = access_model.RecalculateAccesses(ctx, repo); err != nil { return err } - if err = repo_model.WatchRepoCtx(ctx, uid, repo.ID, false); err != nil { + if err = repo_model.WatchRepo(ctx, uid, repo.ID, false); err != nil { return err } @@ -231,12 +92,12 @@ 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.GetUserByIDEngine(db.GetEngine(ctx), uid) + user, err := user_model.GetUserByIDCtx(ctx, uid) if err != nil { return err } - if canAssigned, err := canBeAssigned(ctx, user, repo, true); err != nil || canAssigned { + if canAssigned, err := access_model.CanBeAssigned(ctx, user, repo, true); err != nil || canAssigned { return err } @@ -249,15 +110,15 @@ func reconsiderRepoIssuesAssignee(ctx context.Context, repo *repo_model.Reposito } func reconsiderWatches(ctx context.Context, repo *repo_model.Repository, uid int64) error { - if has, err := hasAccess(ctx, uid, repo); err != nil || has { + if has, err := access_model.HasAccess(ctx, uid, repo); err != nil || has { return err } - if err := repo_model.WatchRepoCtx(ctx, uid, repo.ID, false); err != nil { + if err := repo_model.WatchRepo(ctx, uid, repo.ID, false); err != nil { return err } // Remove all IssueWatches a user has subscribed to in the repository - return removeIssueWatchersByRepoID(db.GetEngine(ctx), uid, repo.ID) + return removeIssueWatchersByRepoID(ctx, uid, repo.ID) } // IsOwnerMemberCollaborator checks if a provided user is the owner, a collaborator or a member of a team in a repository @@ -277,5 +138,5 @@ func IsOwnerMemberCollaborator(repo *repo_model.Repository, userID int64) (bool, return true, nil } - return db.GetEngine(db.DefaultContext).Get(&Collaboration{RepoID: repo.ID, UserID: userID}) + return db.GetEngine(db.DefaultContext).Get(&repo_model.Collaboration{RepoID: repo.ID, UserID: userID}) } diff --git a/models/repo_collaboration_test.go b/models/repo_collaboration_test.go index 8b4c712f07..b90490de92 100644 --- a/models/repo_collaboration_test.go +++ b/models/repo_collaboration_test.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -31,56 +32,21 @@ func TestRepository_AddCollaborator(t *testing.T) { testSuccess(3, 4) } -func TestRepository_GetCollaborators(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - test := func(repoID int64) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) - collaborators, err := GetCollaborators(repo.ID, db.ListOptions{}) - assert.NoError(t, err) - expectedLen, err := db.GetEngine(db.DefaultContext).Count(&Collaboration{RepoID: repoID}) - assert.NoError(t, err) - assert.Len(t, collaborators, int(expectedLen)) - for _, collaborator := range collaborators { - assert.EqualValues(t, collaborator.User.ID, collaborator.Collaboration.UserID) - assert.EqualValues(t, repoID, collaborator.Collaboration.RepoID) - } - } - test(1) - test(2) - test(3) - test(4) -} - -func TestRepository_IsCollaborator(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - test := func(repoID, userID int64, expected bool) { - repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: repoID}).(*repo_model.Repository) - actual, err := IsCollaborator(repo.ID, userID) - assert.NoError(t, err) - assert.Equal(t, expected, actual) - } - test(3, 2, true) - test(3, unittest.NonexistentID, false) - test(4, 2, false) - test(4, 4, true) -} - func TestRepository_ChangeCollaborationAccessMode(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) - assert.NoError(t, ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) - collaboration := unittest.AssertExistsAndLoadBean(t, &Collaboration{RepoID: repo.ID, UserID: 4}).(*Collaboration) + collaboration := unittest.AssertExistsAndLoadBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}).(*repo_model.Collaboration) assert.EqualValues(t, perm.AccessModeAdmin, collaboration.Mode) - access := unittest.AssertExistsAndLoadBean(t, &Access{UserID: 4, RepoID: repo.ID}).(*Access) + access := unittest.AssertExistsAndLoadBean(t, &access_model.Access{UserID: 4, RepoID: repo.ID}).(*access_model.Access) assert.EqualValues(t, perm.AccessModeAdmin, access.Mode) - assert.NoError(t, ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, 4, perm.AccessModeAdmin)) - assert.NoError(t, ChangeCollaborationAccessMode(repo, unittest.NonexistentID, perm.AccessModeAdmin)) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, unittest.NonexistentID, perm.AccessModeAdmin)) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } @@ -91,10 +57,10 @@ func TestRepository_DeleteCollaboration(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4}).(*repo_model.Repository) assert.NoError(t, repo.GetOwner(db.DefaultContext)) assert.NoError(t, DeleteCollaboration(repo, 4)) - unittest.AssertNotExistsBean(t, &Collaboration{RepoID: repo.ID, UserID: 4}) + unittest.AssertNotExistsBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) assert.NoError(t, DeleteCollaboration(repo, 4)) - unittest.AssertNotExistsBean(t, &Collaboration{RepoID: repo.ID, UserID: 4}) + unittest.AssertNotExistsBean(t, &repo_model.Collaboration{RepoID: repo.ID, UserID: 4}) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID}) } diff --git a/models/repo_generate.go b/models/repo_generate.go deleted file mode 100644 index 7d6d262aab..0000000000 --- a/models/repo_generate.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "bufio" - "bytes" - "context" - "strings" - - "code.gitea.io/gitea/models/db" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/webhook" - "code.gitea.io/gitea/modules/log" - - "github.com/gobwas/glob" -) - -// GenerateRepoOptions contains the template units to generate -type GenerateRepoOptions struct { - Name string - DefaultBranch string - Description string - Private bool - GitContent bool - Topics bool - GitHooks bool - Webhooks bool - Avatar bool - IssueLabels bool -} - -// IsValid checks whether at least one option is chosen for generation -func (gro GenerateRepoOptions) IsValid() bool { - return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added -} - -// GiteaTemplate holds information about a .gitea/template file -type GiteaTemplate struct { - Path string - Content []byte - - globs []glob.Glob -} - -// Globs parses the .gitea/template globs or returns them if they were already parsed -func (gt GiteaTemplate) Globs() []glob.Glob { - if gt.globs != nil { - return gt.globs - } - - gt.globs = make([]glob.Glob, 0) - scanner := bufio.NewScanner(bytes.NewReader(gt.Content)) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - g, err := glob.Compile(line, '/') - if err != nil { - log.Info("Invalid glob expression '%s' (skipped): %v", line, err) - continue - } - gt.globs = append(gt.globs, g) - } - return gt.globs -} - -// GenerateWebhooks generates webhooks from a template repository -func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { - templateWebhooks, err := webhook.ListWebhooksByOpts(&webhook.ListWebhookOptions{RepoID: templateRepo.ID}) - if err != nil { - return err - } - - for _, templateWebhook := range templateWebhooks { - generateWebhook := &webhook.Webhook{ - RepoID: generateRepo.ID, - URL: templateWebhook.URL, - HTTPMethod: templateWebhook.HTTPMethod, - ContentType: templateWebhook.ContentType, - Secret: templateWebhook.Secret, - HookEvent: templateWebhook.HookEvent, - IsActive: templateWebhook.IsActive, - Type: templateWebhook.Type, - OrgID: templateWebhook.OrgID, - Events: templateWebhook.Events, - Meta: templateWebhook.Meta, - } - if err := webhook.CreateWebhook(ctx, generateWebhook); err != nil { - return err - } - } - return nil -} - -// GenerateIssueLabels generates issue labels from a template repository -func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { - templateLabels, err := getLabelsByRepoID(db.GetEngine(ctx), templateRepo.ID, "", db.ListOptions{}) - if err != nil { - return err - } - - for _, templateLabel := range templateLabels { - generateLabel := &Label{ - RepoID: generateRepo.ID, - Name: templateLabel.Name, - Description: templateLabel.Description, - Color: templateLabel.Color, - } - if err := db.Insert(ctx, generateLabel); err != nil { - return err - } - } - return nil -} diff --git a/models/repo_list.go b/models/repo_list.go deleted file mode 100644 index 35b2ab5bf8..0000000000 --- a/models/repo_list.go +++ /dev/null @@ -1,670 +0,0 @@ -// Copyright 2017 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "fmt" - "strings" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/perm" - repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/container" - "code.gitea.io/gitea/modules/structs" - "code.gitea.io/gitea/modules/util" - - "xorm.io/builder" -) - -// RepositoryListDefaultPageSize is the default number of repositories -// to load in memory when running administrative tasks on all (or almost -// all) of them. -// The number should be low enough to avoid filling up all RAM with -// repository data... -const RepositoryListDefaultPageSize = 64 - -// RepositoryList contains a list of repositories -type RepositoryList []*repo_model.Repository - -func (repos RepositoryList) Len() int { - return len(repos) -} - -func (repos RepositoryList) Less(i, j int) bool { - return repos[i].FullName() < repos[j].FullName() -} - -func (repos RepositoryList) Swap(i, j int) { - repos[i], repos[j] = repos[j], repos[i] -} - -// FIXME: Remove in favor of maps.values when MIN_GO_VERSION >= 1.18 -func valuesRepository(m map[int64]*repo_model.Repository) []*repo_model.Repository { - values := make([]*repo_model.Repository, 0, len(m)) - for _, v := range m { - values = append(values, v) - } - return values -} - -// RepositoryListOfMap make list from values of map -func RepositoryListOfMap(repoMap map[int64]*repo_model.Repository) RepositoryList { - return RepositoryList(valuesRepository(repoMap)) -} - -func (repos RepositoryList) loadAttributes(e db.Engine) error { - if len(repos) == 0 { - return nil - } - - set := make(map[int64]struct{}) - repoIDs := make([]int64, len(repos)) - for i := range repos { - set[repos[i].OwnerID] = struct{}{} - repoIDs[i] = repos[i].ID - } - - // Load owners. - users := make(map[int64]*user_model.User, len(set)) - if err := e. - Where("id > 0"). - In("id", container.KeysInt64(set)). - Find(&users); err != nil { - return fmt.Errorf("find users: %v", err) - } - for i := range repos { - repos[i].Owner = users[repos[i].OwnerID] - } - - // Load primary language. - stats := make(repo_model.LanguageStatList, 0, len(repos)) - if err := e. - Where("`is_primary` = ? AND `language` != ?", true, "other"). - In("`repo_id`", repoIDs). - Find(&stats); err != nil { - return fmt.Errorf("find primary languages: %v", err) - } - stats.LoadAttributes() - for i := range repos { - for _, st := range stats { - if st.RepoID == repos[i].ID { - repos[i].PrimaryLanguage = st - break - } - } - } - - return nil -} - -// LoadAttributes loads the attributes for the given RepositoryList -func (repos RepositoryList) LoadAttributes() error { - return repos.loadAttributes(db.GetEngine(db.DefaultContext)) -} - -// SearchRepoOptions holds the search options -type SearchRepoOptions struct { - db.ListOptions - Actor *user_model.User - Keyword string - OwnerID int64 - PriorityOwnerID int64 - TeamID int64 - OrderBy db.SearchOrderBy - Private bool // Include private repositories in results - StarredByID int64 - WatchedByID int64 - AllPublic bool // Include also all public repositories of users and public organisations - AllLimited bool // Include also all public repositories of limited organisations - // None -> include public and private - // True -> include just private - // False -> include just public - IsPrivate util.OptionalBool - // None -> include collaborative AND non-collaborative - // True -> include just collaborative - // False -> include just non-collaborative - Collaborate util.OptionalBool - // None -> include forks AND non-forks - // True -> include just forks - // False -> include just non-forks - Fork util.OptionalBool - // None -> include templates AND non-templates - // True -> include just templates - // False -> include just non-templates - Template util.OptionalBool - // None -> include mirrors AND non-mirrors - // True -> include just mirrors - // False -> include just non-mirrors - Mirror util.OptionalBool - // None -> include archived AND non-archived - // True -> include just archived - // False -> include just non-archived - Archived util.OptionalBool - // only search topic name - TopicOnly bool - // only search repositories with specified primary language - Language string - // include description in keyword search - IncludeDescription bool - // None -> include has milestones AND has no milestone - // True -> include just has milestones - // False -> include just has no milestone - HasMilestones util.OptionalBool - // LowerNames represents valid lower names to restrict to - LowerNames []string -} - -// SearchOrderBy is used to sort the result -type SearchOrderBy string - -func (s SearchOrderBy) String() string { - return string(s) -} - -// Strings for sorting result -const ( - SearchOrderByAlphabetically SearchOrderBy = "name ASC" - SearchOrderByAlphabeticallyReverse SearchOrderBy = "name DESC" - SearchOrderByLeastUpdated SearchOrderBy = "updated_unix ASC" - SearchOrderByRecentUpdated SearchOrderBy = "updated_unix DESC" - SearchOrderByOldest SearchOrderBy = "created_unix ASC" - SearchOrderByNewest SearchOrderBy = "created_unix DESC" - SearchOrderBySize SearchOrderBy = "size ASC" - SearchOrderBySizeReverse SearchOrderBy = "size DESC" - SearchOrderByID SearchOrderBy = "id ASC" - SearchOrderByIDReverse SearchOrderBy = "id DESC" - SearchOrderByStars SearchOrderBy = "num_stars ASC" - SearchOrderByStarsReverse SearchOrderBy = "num_stars DESC" - SearchOrderByForks SearchOrderBy = "num_forks ASC" - SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" -) - -// userOwnedRepoCond returns user ownered repositories -func userOwnedRepoCond(userID int64) builder.Cond { - return builder.Eq{ - "repository.owner_id": userID, - } -} - -// userAssignedRepoCond return user as assignee repositories list -func userAssignedRepoCond(id string, userID int64) builder.Cond { - return builder.And( - builder.Eq{ - "repository.is_private": false, - }, - builder.In(id, - builder.Select("issue.repo_id").From("issue_assignees"). - InnerJoin("issue", "issue.id = issue_assignees.issue_id"). - Where(builder.Eq{ - "issue_assignees.assignee_id": userID, - }), - ), - ) -} - -// userCreateIssueRepoCond return user created issues repositories list -func userCreateIssueRepoCond(id string, userID int64, isPull bool) builder.Cond { - return builder.And( - builder.Eq{ - "repository.is_private": false, - }, - builder.In(id, - builder.Select("issue.repo_id").From("issue"). - Where(builder.Eq{ - "issue.poster_id": userID, - "issue.is_pull": isPull, - }), - ), - ) -} - -// userMentionedRepoCond return user metinoed repositories list -func userMentionedRepoCond(id string, userID int64) builder.Cond { - return builder.And( - builder.Eq{ - "repository.is_private": false, - }, - builder.In(id, - builder.Select("issue.repo_id").From("issue_user"). - InnerJoin("issue", "issue.id = issue_user.issue_id"). - Where(builder.Eq{ - "issue_user.is_mentioned": true, - "issue_user.uid": userID, - }), - ), - ) -} - -// teamUnitsRepoCond returns query condition for those repo id in the special org team with special units access -func teamUnitsRepoCond(id string, userID, orgID, teamID int64, units ...unit.Type) builder.Cond { - return builder.In(id, - builder.Select("repo_id").From("team_repo").Where( - builder.Eq{ - "team_id": teamID, - }.And( - builder.In( - "team_id", builder.Select("team_id").From("team_user").Where( - builder.Eq{ - "uid": userID, - }, - ), - )).And( - builder.In( - "team_id", builder.Select("team_id").From("team_unit").Where( - builder.Eq{ - "`team_unit`.org_id": orgID, - }.And( - builder.In("`team_unit`.type", units), - ), - ), - ), - ), - )) -} - -// userCollaborationRepoCond returns user as collabrators repositories list -func userCollaborationRepoCond(idStr string, userID int64) builder.Cond { - return builder.In(idStr, builder.Select("repo_id"). - From("`access`"). - Where(builder.And( - builder.Eq{"`access`.user_id": userID}, - builder.Gt{"`access`.mode": int(perm.AccessModeNone)}, - )), - ) -} - -// userOrgTeamRepoCond selects repos that the given user has access to through team membership -func userOrgTeamRepoCond(idStr string, userID int64) builder.Cond { - return builder.In(idStr, userOrgTeamRepoBuilder(userID)) -} - -// userOrgTeamRepoBuilder returns repo ids where user's teams can access. -func userOrgTeamRepoBuilder(userID int64) *builder.Builder { - return builder.Select("`team_repo`.repo_id"). - From("team_repo"). - Join("INNER", "team_user", "`team_user`.team_id = `team_repo`.team_id"). - Where(builder.Eq{"`team_user`.uid": userID}) -} - -// userOrgTeamUnitRepoBuilder returns repo ids where user's teams can access the special unit. -func userOrgTeamUnitRepoBuilder(userID int64, unitType unit.Type) *builder.Builder { - return userOrgTeamRepoBuilder(userID). - Join("INNER", "team_unit", "`team_unit`.team_id = `team_repo`.team_id"). - Where(builder.Eq{"`team_unit`.`type`": unitType}) -} - -// userOrgUnitRepoCond selects repos that the given user has access to through org and the special unit -func userOrgUnitRepoCond(idStr string, userID, orgID int64, unitType unit.Type) builder.Cond { - return builder.In(idStr, - userOrgTeamUnitRepoBuilder(userID, unitType). - And(builder.Eq{"`team_unit`.org_id": orgID}), - ) -} - -// userOrgPublicRepoCond returns the condition that one user could access all public repositories in organizations -func userOrgPublicRepoCond(userID int64) builder.Cond { - return builder.And( - builder.Eq{"`repository`.is_private": false}, - builder.In("`repository`.owner_id", - builder.Select("`org_user`.org_id"). - From("org_user"). - Where(builder.Eq{"`org_user`.uid": userID}), - ), - ) -} - -// userOrgPublicRepoCondPrivate returns the condition that one user could access all public repositories in private organizations -func userOrgPublicRepoCondPrivate(userID int64) builder.Cond { - return builder.And( - builder.Eq{"`repository`.is_private": false}, - builder.In("`repository`.owner_id", - builder.Select("`org_user`.org_id"). - From("org_user"). - Join("INNER", "`user`", "`user`.id = `org_user`.org_id"). - Where(builder.Eq{ - "`org_user`.uid": userID, - "`user`.`type`": user_model.UserTypeOrganization, - "`user`.visibility": structs.VisibleTypePrivate, - }), - ), - ) -} - -// userOrgPublicUnitRepoCond returns the condition that one user could access all public repositories in the special organization -func userOrgPublicUnitRepoCond(userID, orgID int64) builder.Cond { - return userOrgPublicRepoCond(userID). - And(builder.Eq{"`repository`.owner_id": orgID}) -} - -// SearchRepositoryCondition creates a query condition according search repository options -func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { - cond := builder.NewCond() - - if opts.Private { - if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID { - // OK we're in the context of a User - cond = cond.And(accessibleRepositoryCondition(opts.Actor)) - } - } else { - // Not looking at private organisations and users - // We should be able to see all non-private repositories that - // isn't in a private or limited organisation. - cond = cond.And( - builder.Eq{"is_private": false}, - builder.NotIn("owner_id", builder.Select("id").From("`user`").Where( - builder.Or(builder.Eq{"visibility": structs.VisibleTypeLimited}, builder.Eq{"visibility": structs.VisibleTypePrivate}), - ))) - } - - if opts.IsPrivate != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_private": opts.IsPrivate.IsTrue()}) - } - - if opts.Template != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_template": opts.Template == util.OptionalBoolTrue}) - } - - // Restrict to starred repositories - if opts.StarredByID > 0 { - cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.StarredByID}))) - } - - // Restrict to watched repositories - if opts.WatchedByID > 0 { - cond = cond.And(builder.In("id", builder.Select("repo_id").From("watch").Where(builder.Eq{"user_id": opts.WatchedByID}))) - } - - // Restrict repositories to those the OwnerID owns or contributes to as per opts.Collaborate - if opts.OwnerID > 0 { - accessCond := builder.NewCond() - if opts.Collaborate != util.OptionalBoolTrue { - accessCond = builder.Eq{"owner_id": opts.OwnerID} - } - - if opts.Collaborate != util.OptionalBoolFalse { - // A Collaboration is: - collaborateCond := builder.And( - // 1. Repository we don't own - builder.Neq{"owner_id": opts.OwnerID}, - // 2. But we can see because of: - builder.Or( - // A. We have access - userCollaborationRepoCond("`repository`.id", opts.OwnerID), - // B. We are in a team for - userOrgTeamRepoCond("`repository`.id", opts.OwnerID), - // C. Public repositories in organizations that we are member of - userOrgPublicRepoCondPrivate(opts.OwnerID), - ), - ) - if !opts.Private { - collaborateCond = collaborateCond.And(builder.Expr("owner_id NOT IN (SELECT org_id FROM org_user WHERE org_user.uid = ? AND org_user.is_public = ?)", opts.OwnerID, false)) - } - - accessCond = accessCond.Or(collaborateCond) - } - - if opts.AllPublic { - accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypePublic})))) - } - - if opts.AllLimited { - accessCond = accessCond.Or(builder.Eq{"is_private": false}.And(builder.In("owner_id", builder.Select("`user`.id").From("`user`").Where(builder.Eq{"`user`.visibility": structs.VisibleTypeLimited})))) - } - - cond = cond.And(accessCond) - } - - if opts.TeamID > 0 { - cond = cond.And(builder.In("`repository`.id", builder.Select("`team_repo`.repo_id").From("team_repo").Where(builder.Eq{"`team_repo`.team_id": opts.TeamID}))) - } - - if opts.Keyword != "" { - // separate keyword - subQueryCond := builder.NewCond() - for _, v := range strings.Split(opts.Keyword, ",") { - if opts.TopicOnly { - subQueryCond = subQueryCond.Or(builder.Eq{"topic.name": strings.ToLower(v)}) - } else { - subQueryCond = subQueryCond.Or(builder.Like{"topic.name", strings.ToLower(v)}) - } - } - subQuery := builder.Select("repo_topic.repo_id").From("repo_topic"). - Join("INNER", "topic", "topic.id = repo_topic.topic_id"). - Where(subQueryCond). - GroupBy("repo_topic.repo_id") - - keywordCond := builder.In("id", subQuery) - if !opts.TopicOnly { - likes := builder.NewCond() - for _, v := range strings.Split(opts.Keyword, ",") { - likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)}) - if opts.IncludeDescription { - likes = likes.Or(builder.Like{"LOWER(description)", strings.ToLower(v)}) - } - } - keywordCond = keywordCond.Or(likes) - } - cond = cond.And(keywordCond) - } - - if opts.Language != "" { - cond = cond.And(builder.In("id", builder. - Select("repo_id"). - From("language_stat"). - Where(builder.Eq{"language": opts.Language}).And(builder.Eq{"is_primary": true}))) - } - - if opts.Fork != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_fork": opts.Fork == util.OptionalBoolTrue}) - } - - if opts.Mirror != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_mirror": opts.Mirror == util.OptionalBoolTrue}) - } - - if opts.Actor != nil && opts.Actor.IsRestricted { - cond = cond.And(accessibleRepositoryCondition(opts.Actor)) - } - - if opts.Archived != util.OptionalBoolNone { - cond = cond.And(builder.Eq{"is_archived": opts.Archived == util.OptionalBoolTrue}) - } - - switch opts.HasMilestones { - case util.OptionalBoolTrue: - cond = cond.And(builder.Gt{"num_milestones": 0}) - case util.OptionalBoolFalse: - cond = cond.And(builder.Eq{"num_milestones": 0}.Or(builder.IsNull{"num_milestones"})) - } - - return cond -} - -// SearchRepository returns repositories based on search options, -// it returns results in given range and number of total results. -func SearchRepository(opts *SearchRepoOptions) (RepositoryList, int64, error) { - cond := SearchRepositoryCondition(opts) - return SearchRepositoryByCondition(opts, cond, true) -} - -// SearchRepositoryByCondition search repositories by condition -func SearchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond, loadAttributes bool) (RepositoryList, int64, error) { - sess, count, err := searchRepositoryByCondition(opts, cond) - if err != nil { - return nil, 0, err - } - - defaultSize := 50 - if opts.PageSize > 0 { - defaultSize = opts.PageSize - } - repos := make(RepositoryList, 0, defaultSize) - if err := sess.Find(&repos); err != nil { - return nil, 0, fmt.Errorf("Repo: %v", err) - } - - if opts.PageSize <= 0 { - count = int64(len(repos)) - } - - if loadAttributes { - if err := repos.loadAttributes(sess); err != nil { - return nil, 0, fmt.Errorf("LoadAttributes: %v", err) - } - } - - return repos, count, nil -} - -func searchRepositoryByCondition(opts *SearchRepoOptions, cond builder.Cond) (db.Engine, int64, error) { - if opts.Page <= 0 { - opts.Page = 1 - } - - if len(opts.OrderBy) == 0 { - opts.OrderBy = db.SearchOrderByAlphabetically - } - - if opts.PriorityOwnerID > 0 { - opts.OrderBy = db.SearchOrderBy(fmt.Sprintf("CASE WHEN owner_id = %d THEN 0 ELSE owner_id END, %s", opts.PriorityOwnerID, opts.OrderBy)) - } - - sess := db.GetEngine(db.DefaultContext) - - var count int64 - if opts.PageSize > 0 { - var err error - count, err = sess. - Where(cond). - Count(new(repo_model.Repository)) - if err != nil { - return nil, 0, fmt.Errorf("Count: %v", err) - } - } - - sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) - if opts.PageSize > 0 { - sess = sess.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize) - } - return sess, count, nil -} - -// accessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible -func accessibleRepositoryCondition(user *user_model.User) builder.Cond { - cond := builder.NewCond() - - if user == nil || !user.IsRestricted || user.ID <= 0 { - orgVisibilityLimit := []structs.VisibleType{structs.VisibleTypePrivate} - if user == nil || user.ID <= 0 { - orgVisibilityLimit = append(orgVisibilityLimit, structs.VisibleTypeLimited) - } - // 1. Be able to see all non-private repositories that either: - cond = cond.Or(builder.And( - builder.Eq{"`repository`.is_private": false}, - // 2. Aren't in an private organisation or limited organisation if we're not logged in - builder.NotIn("`repository`.owner_id", builder.Select("id").From("`user`").Where( - builder.And( - builder.Eq{"type": user_model.UserTypeOrganization}, - builder.In("visibility", orgVisibilityLimit)), - )))) - } - - if user != nil { - cond = cond.Or( - // 2. Be able to see all repositories that we have access to - userCollaborationRepoCond("`repository`.id", user.ID), - // 3. Repositories that we directly own - builder.Eq{"`repository`.owner_id": user.ID}, - // 4. Be able to see all repositories that we are in a team - userOrgTeamRepoCond("`repository`.id", user.ID), - // 5. Be able to see all public repos in private organizations that we are an org_user of - userOrgPublicRepoCond(user.ID), - ) - } - - return cond -} - -// SearchRepositoryByName takes keyword and part of repository name to search, -// it returns results in given range and number of total results. -func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, error) { - opts.IncludeDescription = false - return SearchRepository(opts) -} - -// SearchRepositoryIDs takes keyword and part of repository name to search, -// it returns results in given range and number of total results. -func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) { - opts.IncludeDescription = false - - cond := SearchRepositoryCondition(opts) - - sess, count, err := searchRepositoryByCondition(opts, cond) - if err != nil { - return nil, 0, err - } - - defaultSize := 50 - if opts.PageSize > 0 { - defaultSize = opts.PageSize - } - - ids := make([]int64, 0, defaultSize) - err = sess.Select("id").Table("repository").Find(&ids) - if opts.PageSize <= 0 { - count = int64(len(ids)) - } - - return ids, count, err -} - -// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered. -func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder { - // NB: Please note this code needs to still work if user is nil - return builder.Select("id").From("repository").Where(accessibleRepositoryCondition(user)) -} - -// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id -func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) { - repoIDs := make([]int64, 0, 10) - if err := db.GetEngine(db.DefaultContext). - Table("repository"). - Cols("id"). - Where(accessibleRepositoryCondition(user)). - Find(&repoIDs); err != nil { - return nil, fmt.Errorf("FindUserAccesibleRepoIDs: %v", err) - } - return repoIDs, nil -} - -// GetUserRepositories returns a list of repositories of given user. -func GetUserRepositories(opts *SearchRepoOptions) (RepositoryList, int64, error) { - if len(opts.OrderBy) == 0 { - opts.OrderBy = "updated_unix DESC" - } - - cond := builder.NewCond() - cond = cond.And(builder.Eq{"owner_id": opts.Actor.ID}) - if !opts.Private { - cond = cond.And(builder.Eq{"is_private": false}) - } - - if opts.LowerNames != nil && len(opts.LowerNames) > 0 { - cond = cond.And(builder.In("lower_name", opts.LowerNames)) - } - - sess := db.GetEngine(db.DefaultContext) - - count, err := sess.Where(cond).Count(new(repo_model.Repository)) - if err != nil { - return nil, 0, fmt.Errorf("Count: %v", err) - } - - sess = sess.Where(cond).OrderBy(opts.OrderBy.String()) - repos := make(RepositoryList, 0, opts.PageSize) - return repos, count, db.SetSessionPagination(sess, opts).Find(&repos) -} diff --git a/models/repo_permission_test.go b/models/repo_permission_test.go index 7e22437f99..80919e7cf1 100644 --- a/models/repo_permission_test.go +++ b/models/repo_permission_test.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" perm_model "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/models/unittest" @@ -27,7 +28,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -36,7 +37,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // change to collaborator assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -45,7 +46,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // collaborator collaborator := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, collaborator) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, collaborator) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -54,7 +55,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -63,7 +64,7 @@ func TestRepoPermissionPublicNonOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -80,7 +81,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}).(*user_model.User) - perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.False(t, perm.CanRead(unit.Type)) @@ -89,15 +90,15 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // change to collaborator to default write access assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -106,7 +107,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -115,7 +116,7 @@ func TestRepoPermissionPrivateNonOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -132,7 +133,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -141,15 +142,15 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // change to collaborator to default write access assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -158,7 +159,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // org member team owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -167,7 +168,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // org member team tester member := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, member) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, member) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -177,7 +178,7 @@ func TestRepoPermissionPublicOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -194,7 +195,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // plain user user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - perm, err := GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.False(t, perm.CanRead(unit.Type)) @@ -203,15 +204,15 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // change to collaborator to default write access assert.NoError(t, AddCollaborator(repo, user)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) assert.True(t, perm.CanWrite(unit.Type)) } - assert.NoError(t, ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, user) + assert.NoError(t, repo_model.ChangeCollaborationAccessMode(repo, user.ID, perm_model.AccessModeRead)) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, user) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -220,7 +221,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team owner owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 15}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -231,7 +232,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 5}).(*organization.Team) err = organization.UpdateTeamUnits(team, nil) assert.NoError(t, err) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, owner) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, owner) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) @@ -240,7 +241,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team tester tester := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, tester) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, tester) assert.NoError(t, err) assert.True(t, perm.CanWrite(unit.TypeIssues)) assert.False(t, perm.CanWrite(unit.TypeCode)) @@ -248,7 +249,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // org member team reviewer reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 20}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, reviewer) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, reviewer) assert.NoError(t, err) assert.False(t, perm.CanRead(unit.TypeIssues)) assert.False(t, perm.CanWrite(unit.TypeCode)) @@ -256,7 +257,7 @@ func TestRepoPermissionPrivateOrgRepo(t *testing.T) { // admin admin := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - perm, err = GetUserRepoPermission(db.DefaultContext, repo, admin) + perm, err = access_model.GetUserRepoPermission(db.DefaultContext, repo, admin) assert.NoError(t, err) for _, unit := range repo.Units { assert.True(t, perm.CanRead(unit.Type)) diff --git a/models/repo_test.go b/models/repo_test.go index a93d84b81b..c9e66398d1 100644 --- a/models/repo_test.go +++ b/models/repo_test.go @@ -27,11 +27,11 @@ func TestWatchRepo(t *testing.T) { const repoID = 3 const userID = 2 - assert.NoError(t, repo_model.WatchRepo(userID, repoID, true)) + assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, userID, repoID, true)) unittest.AssertExistsAndLoadBean(t, &repo_model.Watch{RepoID: repoID, UserID: userID}) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}) - assert.NoError(t, repo_model.WatchRepo(userID, repoID, false)) + assert.NoError(t, repo_model.WatchRepo(db.DefaultContext, userID, repoID, false)) unittest.AssertNotExistsBean(t, &repo_model.Watch{RepoID: repoID, UserID: userID}) unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repoID}) } @@ -84,127 +84,8 @@ func TestMetas(t *testing.T) { assert.Equal(t, ",owners,team1,", metas["teams"]) } -func TestUpdateRepositoryVisibilityChanged(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - // Get sample repo and change visibility - repo, err := repo_model.GetRepositoryByID(9) - assert.NoError(t, err) - repo.IsPrivate = true - - // Update it - err = UpdateRepository(repo, true) - assert.NoError(t, err) - - // Check visibility of action has become private - act := Action{} - _, err = db.GetEngine(db.DefaultContext).ID(3).Get(&act) - - assert.NoError(t, err) - assert.True(t, act.IsPrivate) -} - func TestDoctorUserStarNum(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) assert.NoError(t, DoctorUserStarNum()) } - -func TestRepoGetReviewers(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - // test public repo - repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) - - reviewers, err := GetReviewers(repo1, 2, 2) - assert.NoError(t, err) - assert.Len(t, reviewers, 4) - - // should include doer if doer is not PR poster. - reviewers, err = GetReviewers(repo1, 11, 2) - assert.NoError(t, err) - assert.Len(t, reviewers, 4) - - // should not include PR poster, if PR poster would be otherwise eligible - reviewers, err = GetReviewers(repo1, 11, 4) - assert.NoError(t, err) - assert.Len(t, reviewers, 3) - - // test private user repo - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - - reviewers, err = GetReviewers(repo2, 2, 4) - assert.NoError(t, err) - assert.Len(t, reviewers, 1) - assert.EqualValues(t, reviewers[0].ID, 2) - - // test private org repo - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) - - reviewers, err = GetReviewers(repo3, 2, 1) - assert.NoError(t, err) - assert.Len(t, reviewers, 2) - - reviewers, err = GetReviewers(repo3, 2, 2) - assert.NoError(t, err) - assert.Len(t, reviewers, 1) -} - -func TestRepoGetReviewerTeams(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - teams, err := GetReviewerTeams(repo2) - assert.NoError(t, err) - assert.Empty(t, teams) - - repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) - teams, err = GetReviewerTeams(repo3) - assert.NoError(t, err) - assert.Len(t, teams, 2) -} - -func TestLinkedRepository(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - testCases := []struct { - name string - attachID int64 - expectedRepo *repo_model.Repository - expectedUnitType unit.Type - }{ - {"LinkedIssue", 1, &repo_model.Repository{ID: 1}, unit.TypeIssues}, - {"LinkedComment", 3, &repo_model.Repository{ID: 1}, unit.TypePullRequests}, - {"LinkedRelease", 9, &repo_model.Repository{ID: 1}, unit.TypeReleases}, - {"Notlinked", 10, nil, -1}, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - attach, err := repo_model.GetAttachmentByID(tc.attachID) - assert.NoError(t, err) - repo, unitType, err := LinkedRepository(attach) - assert.NoError(t, err) - if tc.expectedRepo != nil { - assert.Equal(t, tc.expectedRepo.ID, repo.ID) - } - assert.Equal(t, tc.expectedUnitType, unitType) - }) - } -} - -func TestRepoAssignees(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) - users, err := GetRepoAssignees(repo2) - assert.NoError(t, err) - assert.Len(t, users, 1) - assert.Equal(t, users[0].ID, int64(2)) - - repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository) - users, err = GetRepoAssignees(repo21) - assert.NoError(t, err) - assert.Len(t, users, 3) - assert.Equal(t, users[0].ID, int64(15)) - assert.Equal(t, users[1].ID, int64(18)) - assert.Equal(t, users[2].ID, int64(16)) -} diff --git a/models/repo_transfer.go b/models/repo_transfer.go index f9a758a20b..79cfc699c8 100644 --- a/models/repo_transfer.go +++ b/models/repo_transfer.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -50,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(v) + team, err := organization.GetTeamByID(db.DefaultContext, v) if err != nil { return err } @@ -129,7 +130,7 @@ func CancelRepositoryTransfer(repo *repo_model.Repository) error { defer committer.Close() repo.Status = repo_model.RepositoryReady - if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "status"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { return err } @@ -171,12 +172,12 @@ func CreatePendingRepositoryTransfer(doer, newOwner *user_model.User, repoID int } repo.Status = repo_model.RepositoryPendingTransfer - if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "status"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { return err } // Check if new owner has repository with same name. - if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil { + if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return repo_model.ErrRepoAlreadyExist{ @@ -249,14 +250,14 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo sess := db.GetEngine(ctx) - newOwner, err := user_model.GetUserByNameCtx(ctx, newOwnerName) + newOwner, err := user_model.GetUserByName(ctx, newOwnerName) if err != nil { return fmt.Errorf("get new owner '%s': %v", newOwnerName, err) } newOwnerName = newOwner.Name // ensure capitalisation matches // Check if new owner has repository with same name. - if has, err := repo_model.IsRepositoryExistCtx(ctx, newOwner, repo.Name); err != nil { + if has, err := repo_model.IsRepositoryExist(ctx, newOwner, repo.Name); err != nil { return fmt.Errorf("IsRepositoryExist: %v", err) } else if has { return repo_model.ErrRepoAlreadyExist{ @@ -280,13 +281,13 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo } // Remove redundant collaborators. - collaborators, err := getCollaborators(sess, repo.ID, db.ListOptions{}) + collaborators, err := repo_model.GetCollaborators(ctx, repo.ID, db.ListOptions{}) if err != nil { return fmt.Errorf("getCollaborators: %v", err) } // Dummy object. - collaboration := &Collaboration{RepoID: repo.ID} + collaboration := &repo_model.Collaboration{RepoID: repo.ID} for _, c := range collaborators { if c.IsGhost() { collaboration.ID = c.Collaboration.ID @@ -330,7 +331,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo } } } - } else if err := recalculateAccesses(ctx, repo); err != nil { + } else if err := access_model.RecalculateAccesses(ctx, repo); err != nil { // Organization called this in addRepository method. return fmt.Errorf("recalculateAccesses: %v", err) } @@ -342,13 +343,13 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo return fmt.Errorf("decrease old owner repository count: %v", err) } - if err := repo_model.WatchRepoCtx(ctx, doer.ID, repo.ID, true); err != nil { + if err := repo_model.WatchRepo(ctx, doer.ID, repo.ID, true); err != nil { return fmt.Errorf("watchRepo: %v", err) } // Remove watch for organization. if oldOwner.IsOrganization() { - if err := repo_model.WatchRepoCtx(ctx, oldOwner.ID, repo.ID, false); err != nil { + if err := repo_model.WatchRepo(ctx, oldOwner.ID, repo.ID, false); err != nil { return fmt.Errorf("watchRepo [false]: %v", err) } } @@ -409,7 +410,7 @@ func TransferOwnership(doer *user_model.User, newOwnerName string, repo *repo_mo return fmt.Errorf("deleteRepositoryTransfer: %v", err) } repo.Status = repo_model.RepositoryReady - if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "status"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, repo, "status"); err != nil { return err } diff --git a/models/review.go b/models/review.go index a9e29a10e0..296c9ce040 100644 --- a/models/review.go +++ b/models/review.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" @@ -92,26 +93,26 @@ func (r *Review) LoadCodeComments(ctx context.Context) (err error) { if r.CodeComments != nil { return } - if err = r.loadIssue(db.GetEngine(ctx)); err != nil { + if err = r.loadIssue(ctx); err != nil { return } r.CodeComments, err = fetchCodeCommentsByReview(ctx, r.Issue, nil, r) return } -func (r *Review) loadIssue(e db.Engine) (err error) { +func (r *Review) loadIssue(ctx context.Context) (err error) { if r.Issue != nil { return } - r.Issue, err = getIssueByID(e, r.IssueID) + r.Issue, err = getIssueByID(ctx, r.IssueID) return } -func (r *Review) loadReviewer(e db.Engine) (err error) { +func (r *Review) loadReviewer(ctx context.Context) (err error) { if r.ReviewerID == 0 || r.Reviewer != nil { return } - r.Reviewer, err = user_model.GetUserByIDEngine(e, r.ReviewerID) + r.Reviewer, err = user_model.GetUserByIDCtx(ctx, r.ReviewerID) return } @@ -120,13 +121,13 @@ func (r *Review) loadReviewerTeam(ctx context.Context) (err error) { return } - r.ReviewerTeam, err = organization.GetTeamByIDCtx(ctx, r.ReviewerTeamID) + r.ReviewerTeam, err = organization.GetTeamByID(ctx, r.ReviewerTeamID) return } // LoadReviewer loads reviewer func (r *Review) LoadReviewer() error { - return r.loadReviewer(db.GetEngine(db.DefaultContext)) + return r.loadReviewer(db.DefaultContext) } // LoadReviewerTeam loads reviewer team @@ -136,14 +137,13 @@ func (r *Review) LoadReviewerTeam() error { // LoadAttributes loads all attributes except CodeComments func (r *Review) LoadAttributes(ctx context.Context) (err error) { - e := db.GetEngine(ctx) - if err = r.loadIssue(e); err != nil { + if err = r.loadIssue(ctx); err != nil { return } if err = r.LoadCodeComments(ctx); err != nil { return } - if err = r.loadReviewer(e); err != nil { + if err = r.loadReviewer(ctx); err != nil { return } if err = r.loadReviewerTeam(ctx); err != nil { @@ -152,9 +152,10 @@ func (r *Review) LoadAttributes(ctx context.Context) (err error) { return } -func getReviewByID(e db.Engine, id int64) (*Review, error) { +// GetReviewByID returns the review by the given ID +func GetReviewByID(ctx context.Context, id int64) (*Review, error) { review := new(Review) - if has, err := e.ID(id).Get(review); err != nil { + if has, err := db.GetEngine(ctx).ID(id).Get(review); err != nil { return nil, err } else if !has { return nil, ErrReviewNotExist{ID: id} @@ -163,11 +164,6 @@ func getReviewByID(e db.Engine, id int64) (*Review, error) { } } -// GetReviewByID returns the review by the given ID -func GetReviewByID(id int64) (*Review, error) { - return getReviewByID(db.GetEngine(db.DefaultContext), id) -} - // FindReviewOptions represent possible filters to find reviews type FindReviewOptions struct { db.ListOptions @@ -194,9 +190,10 @@ func (opts *FindReviewOptions) toCond() builder.Cond { return cond } -func findReviews(e db.Engine, opts FindReviewOptions) ([]*Review, error) { +// FindReviews returns reviews passing FindReviewOptions +func FindReviews(ctx context.Context, opts FindReviewOptions) ([]*Review, error) { reviews := make([]*Review, 0, 10) - sess := e.Where(opts.toCond()) + sess := db.GetEngine(ctx).Where(opts.toCond()) if opts.Page > 0 { sess = db.SetSessionPagination(sess, &opts) } @@ -206,11 +203,6 @@ func findReviews(e db.Engine, opts FindReviewOptions) ([]*Review, error) { Find(&reviews) } -// FindReviews returns reviews passing FindReviewOptions -func FindReviews(opts FindReviewOptions) ([]*Review, error) { - return findReviews(db.GetEngine(db.DefaultContext), opts) -} - // CountReviews returns count of reviews passing FindReviewOptions func CountReviews(opts FindReviewOptions) (int64, error) { return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Review{}) @@ -229,12 +221,8 @@ type CreateReviewOptions struct { } // IsOfficialReviewer check if at least one of the provided reviewers can make official reviews in issue (counts towards required approvals) -func IsOfficialReviewer(issue *Issue, reviewers ...*user_model.User) (bool, error) { - return isOfficialReviewer(db.DefaultContext, issue, reviewers...) -} - -func isOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_model.User) (bool, error) { - pr, err := getPullRequestByIssueID(db.GetEngine(ctx), issue.ID) +func IsOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_model.User) (bool, error) { + pr, err := GetPullRequestByIssueID(ctx, issue.ID) if err != nil { return false, err } @@ -256,12 +244,8 @@ func isOfficialReviewer(ctx context.Context, issue *Issue, reviewers ...*user_mo } // IsOfficialReviewerTeam check if reviewer in this team can make official reviews in issue (counts towards required approvals) -func IsOfficialReviewerTeam(issue *Issue, team *organization.Team) (bool, error) { - return isOfficialReviewerTeam(db.DefaultContext, issue, team) -} - -func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organization.Team) (bool, error) { - pr, err := getPullRequestByIssueID(db.GetEngine(ctx), issue.ID) +func IsOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organization.Team) (bool, error) { + pr, err := GetPullRequestByIssueID(ctx, issue.ID) if err != nil { return false, err } @@ -279,7 +263,8 @@ func isOfficialReviewerTeam(ctx context.Context, issue *Issue, team *organizatio return base.Int64sContains(pr.ProtectedBranch.ApprovalsWhitelistTeamIDs, team.ID), nil } -func createReview(e db.Engine, opts CreateReviewOptions) (*Review, error) { +// CreateReview creates a new review based on opts +func CreateReview(ctx context.Context, opts CreateReviewOptions) (*Review, error) { review := &Review{ Type: opts.Type, Issue: opts.Issue, @@ -299,23 +284,15 @@ func createReview(e db.Engine, opts CreateReviewOptions) (*Review, error) { } review.ReviewerTeamID = opts.ReviewerTeam.ID } - if _, err := e.Insert(review); err != nil { - return nil, err - } - - return review, nil + return review, db.Insert(ctx, review) } -// CreateReview creates a new review based on opts -func CreateReview(opts CreateReviewOptions) (*Review, error) { - return createReview(db.GetEngine(db.DefaultContext), opts) -} - -func getCurrentReview(e db.Engine, reviewer *user_model.User, issue *Issue) (*Review, error) { +// GetCurrentReview returns the current pending review of reviewer for given issue +func GetCurrentReview(ctx context.Context, reviewer *user_model.User, issue *Issue) (*Review, error) { if reviewer == nil { return nil, nil } - reviews, err := findReviews(e, FindReviewOptions{ + reviews, err := FindReviews(ctx, FindReviewOptions{ Type: ReviewTypePending, IssueID: issue.ID, ReviewerID: reviewer.ID, @@ -336,11 +313,6 @@ func ReviewExists(issue *Issue, treePath string, line int64) (bool, error) { return db.GetEngine(db.DefaultContext).Cols("id").Exist(&Comment{IssueID: issue.ID, TreePath: treePath, Line: line, Type: CommentTypeCode}) } -// GetCurrentReview returns the current pending review of reviewer for given issue -func GetCurrentReview(reviewer *user_model.User, issue *Issue) (*Review, error) { - return getCurrentReview(db.GetEngine(db.DefaultContext), reviewer, issue) -} - // ContentEmptyErr represents an content empty error type ContentEmptyErr struct{} @@ -365,7 +337,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co official := false - review, err := getCurrentReview(sess, doer, issue) + review, err := GetCurrentReview(ctx, doer, issue) if err != nil { if !IsErrReviewNotExist(err) { return nil, nil, err @@ -377,16 +349,16 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co if reviewType == ReviewTypeApprove || reviewType == ReviewTypeReject { // Only reviewers latest review of type approve and reject shall count as "official", so existing reviews needs to be cleared - if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, doer.ID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, doer.ID); err != nil { return nil, nil, err } - if official, err = isOfficialReviewer(ctx, issue, doer); err != nil { + if official, err = IsOfficialReviewer(ctx, issue, doer); err != nil { return nil, nil, err } } // No current review. Create a new one! - if review, err = createReview(sess, CreateReviewOptions{ + if review, err = CreateReview(ctx, CreateReviewOptions{ Type: reviewType, Issue: issue, Reviewer: doer, @@ -407,10 +379,10 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co if reviewType == ReviewTypeApprove || reviewType == ReviewTypeReject { // Only reviewers latest review of type approve and reject shall count as "official", so existing reviews needs to be cleared - if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, doer.ID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_id=?", false, issue.ID, doer.ID); err != nil { return nil, nil, err } - if official, err = isOfficialReviewer(ctx, issue, doer); err != nil { + if official, err = IsOfficialReviewer(ctx, issue, doer); err != nil { return nil, nil, err } } @@ -455,7 +427,7 @@ func SubmitReview(doer *user_model.User, issue *Issue, reviewType ReviewType, co continue } - if _, err := sess.Delete(teamReviewRequest); err != nil { + if _, err := sess.ID(teamReviewRequest.ID).NoAutoCondition().Delete(teamReviewRequest); err != nil { return nil, nil, err } } @@ -507,14 +479,10 @@ func GetReviewersFromOriginalAuthorsByIssueID(issueID int64) ([]*Review, error) } // GetReviewByIssueIDAndUserID get the latest review of reviewer for a pull request -func GetReviewByIssueIDAndUserID(issueID, userID int64) (*Review, error) { - return getReviewByIssueIDAndUserID(db.GetEngine(db.DefaultContext), issueID, userID) -} - -func getReviewByIssueIDAndUserID(e db.Engine, issueID, userID int64) (*Review, error) { +func GetReviewByIssueIDAndUserID(ctx context.Context, issueID, userID int64) (*Review, error) { review := new(Review) - has, err := e.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_id = ? AND original_author_id = 0 AND type in (?, ?, ?))", + has, err := db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_id = ? AND original_author_id = 0 AND type in (?, ?, ?))", issueID, userID, ReviewTypeApprove, ReviewTypeReject, ReviewTypeRequest). Get(review) if err != nil { @@ -529,15 +497,11 @@ func getReviewByIssueIDAndUserID(e db.Engine, issueID, userID int64) (*Review, e } // GetTeamReviewerByIssueIDAndTeamID get the latest review request of reviewer team for a pull request -func GetTeamReviewerByIssueIDAndTeamID(issueID, teamID int64) (review *Review, err error) { - return getTeamReviewerByIssueIDAndTeamID(db.GetEngine(db.DefaultContext), issueID, teamID) -} - -func getTeamReviewerByIssueIDAndTeamID(e db.Engine, issueID, teamID int64) (review *Review, err error) { +func GetTeamReviewerByIssueIDAndTeamID(ctx context.Context, issueID, teamID int64) (review *Review, err error) { review = new(Review) has := false - if has, err = e.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = ?)", + if has, err = db.GetEngine(ctx).SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id = ? AND reviewer_team_id = ?)", issueID, teamID). Get(review); err != nil { return nil, err @@ -632,7 +596,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, defer committer.Close() sess := db.GetEngine(ctx) - review, err := getReviewByIssueIDAndUserID(sess, issue.ID, reviewer.ID) + review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID) if err != nil && !IsErrReviewNotExist(err) { return nil, err } @@ -642,7 +606,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, return nil, nil } - official, err := isOfficialReviewer(ctx, issue, reviewer, doer) + official, err := IsOfficialReviewer(ctx, issue, reviewer, doer) if err != nil { return nil, err } else if official { @@ -651,7 +615,7 @@ func AddReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Comment, } } - review, err = createReview(sess, CreateReviewOptions{ + review, err = CreateReview(ctx, CreateReviewOptions{ Type: ReviewTypeRequest, Issue: issue, Reviewer: reviewer, @@ -685,9 +649,8 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) - review, err := getReviewByIssueIDAndUserID(sess, issue.ID, reviewer.ID) + review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID) if err != nil && !IsErrReviewNotExist(err) { return nil, err } @@ -696,22 +659,22 @@ func RemoveReviewRequest(issue *Issue, reviewer, doer *user_model.User) (*Commen return nil, nil } - if _, err = sess.Delete(review); err != nil { + if _, err = db.DeleteByBean(ctx, review); err != nil { return nil, err } - official, err := isOfficialReviewer(ctx, issue, reviewer) + official, err := IsOfficialReviewer(ctx, issue, reviewer) if err != nil { return nil, err } else if official { // recalculate the latest official review for reviewer - review, err := getReviewByIssueIDAndUserID(sess, issue.ID, reviewer.ID) + review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID) if err != nil && !IsErrReviewNotExist(err) { return nil, err } if review != nil { - if _, err := sess.Exec("UPDATE `review` SET official=? WHERE id=?", true, review.ID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE id=?", true, review.ID); err != nil { return nil, err } } @@ -739,9 +702,8 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) - review, err := getTeamReviewerByIssueIDAndTeamID(sess, issue.ID, reviewer.ID) + review, err := GetTeamReviewerByIssueIDAndTeamID(ctx, issue.ID, reviewer.ID) if err != nil && !IsErrReviewNotExist(err) { return nil, err } @@ -751,16 +713,16 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ return nil, nil } - official, err := isOfficialReviewerTeam(ctx, issue, reviewer) + official, err := IsOfficialReviewerTeam(ctx, issue, reviewer) if err != nil { return nil, fmt.Errorf("isOfficialReviewerTeam(): %v", err) } else if !official { - if official, err = isOfficialReviewer(ctx, issue, doer); err != nil { + if official, err = IsOfficialReviewer(ctx, issue, doer); err != nil { return nil, fmt.Errorf("isOfficialReviewer(): %v", err) } } - if review, err = createReview(sess, CreateReviewOptions{ + if review, err = CreateReview(ctx, CreateReviewOptions{ Type: ReviewTypeRequest, Issue: issue, ReviewerTeam: reviewer, @@ -771,7 +733,7 @@ func AddTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *user_ } if official { - if _, err := sess.Exec("UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_team_id=?", false, issue.ID, reviewer.ID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE issue_id=? AND reviewer_team_id=?", false, issue.ID, reviewer.ID); err != nil { return nil, err } } @@ -799,9 +761,8 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us return nil, err } defer committer.Close() - sess := db.GetEngine(ctx) - review, err := getTeamReviewerByIssueIDAndTeamID(sess, issue.ID, reviewer.ID) + review, err := GetTeamReviewerByIssueIDAndTeamID(ctx, issue.ID, reviewer.ID) if err != nil && !IsErrReviewNotExist(err) { return nil, err } @@ -810,24 +771,24 @@ func RemoveTeamReviewRequest(issue *Issue, reviewer *organization.Team, doer *us return nil, nil } - if _, err = sess.Delete(review); err != nil { + if _, err = db.DeleteByBean(ctx, review); err != nil { return nil, err } - official, err := isOfficialReviewerTeam(ctx, issue, reviewer) + official, err := IsOfficialReviewerTeam(ctx, issue, reviewer) if err != nil { return nil, fmt.Errorf("isOfficialReviewerTeam(): %v", err) } if official { // recalculate which is the latest official review from that team - review, err := getReviewByIssueIDAndUserID(sess, issue.ID, -reviewer.ID) + review, err := GetReviewByIssueIDAndUserID(ctx, issue.ID, -reviewer.ID) if err != nil && !IsErrReviewNotExist(err) { return nil, err } if review != nil { - if _, err := sess.Exec("UPDATE `review` SET official=? WHERE id=?", true, review.ID); err != nil { + if _, err := db.Exec(ctx, "UPDATE `review` SET official=? WHERE id=?", true, review.ID); err != nil { return nil, err } } @@ -891,14 +852,14 @@ func CanMarkConversation(issue *Issue, doer *user_model.User) (permResult bool, return false, err } - p, err := GetUserRepoPermission(db.DefaultContext, issue.Repo, doer) + p, err := access_model.GetUserRepoPermission(db.DefaultContext, issue.Repo, doer) if err != nil { return false, err } permResult = p.CanAccess(perm.AccessModeWrite, unit.TypePullRequests) if !permResult { - if permResult, err = IsOfficialReviewer(issue, doer); err != nil { + if permResult, err = IsOfficialReviewer(db.DefaultContext, issue, doer); err != nil { return false, err } } diff --git a/models/review_test.go b/models/review_test.go index a4a71cc709..93291f9f57 100644 --- a/models/review_test.go +++ b/models/review_test.go @@ -16,12 +16,12 @@ import ( func TestGetReviewByID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - review, err := GetReviewByID(1) + review, err := GetReviewByID(db.DefaultContext, 1) assert.NoError(t, err) assert.Equal(t, "Demo Review", review.Content) assert.Equal(t, ReviewTypeApprove, review.Type) - _, err = GetReviewByID(23892) + _, err = GetReviewByID(db.DefaultContext, 23892) assert.Error(t, err) assert.True(t, IsErrReviewNotExist(err), "IsErrReviewNotExist") } @@ -61,7 +61,7 @@ func TestReviewType_Icon(t *testing.T) { func TestFindReviews(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - reviews, err := FindReviews(FindReviewOptions{ + reviews, err := FindReviews(db.DefaultContext, FindReviewOptions{ Type: ReviewTypeApprove, IssueID: 2, ReviewerID: 1, @@ -76,14 +76,14 @@ func TestGetCurrentReview(t *testing.T) { issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - review, err := GetCurrentReview(user, issue) + review, err := GetCurrentReview(db.DefaultContext, user, issue) assert.NoError(t, err) assert.NotNil(t, review) assert.Equal(t, ReviewTypePending, review.Type) assert.Equal(t, "Pending Review", review.Content) user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 7}).(*user_model.User) - review2, err := GetCurrentReview(user2, issue) + review2, err := GetCurrentReview(db.DefaultContext, user2, issue) assert.Error(t, err) assert.True(t, IsErrReviewNotExist(err)) assert.Nil(t, review2) @@ -95,7 +95,7 @@ func TestCreateReview(t *testing.T) { issue := unittest.AssertExistsAndLoadBean(t, &Issue{ID: 2}).(*Issue) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) - review, err := CreateReview(CreateReviewOptions{ + review, err := CreateReview(db.DefaultContext, CreateReviewOptions{ Content: "New Review", Type: ReviewTypePending, Issue: issue, diff --git a/models/statistic.go b/models/statistic.go index d858102be8..dfc236ec58 100644 --- a/models/statistic.go +++ b/models/statistic.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + 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" user_model "code.gitea.io/gitea/models/user" @@ -50,13 +51,13 @@ type IssueByRepositoryCount struct { func GetStatistic() (stats Statistic) { e := db.GetEngine(db.DefaultContext) stats.Counter.User = user_model.CountUsers(nil) - stats.Counter.Org = organization.CountOrganizations() + stats.Counter.Org, _ = organization.CountOrgs(organization.FindOrgOptions{IncludePrivate: true}) stats.Counter.PublicKey, _ = e.Count(new(asymkey_model.PublicKey)) - stats.Counter.Repo = repo_model.CountRepositories(true) + stats.Counter.Repo, _ = repo_model.CountRepositories(db.DefaultContext, repo_model.CountRepositoryOptions{}) stats.Counter.Watch, _ = e.Count(new(repo_model.Watch)) stats.Counter.Star, _ = e.Count(new(repo_model.Star)) - stats.Counter.Action, _ = e.Count(new(Action)) - stats.Counter.Access, _ = e.Count(new(Access)) + stats.Counter.Action, _ = db.EstimateCount(db.DefaultContext, new(Action)) + stats.Counter.Access, _ = e.Count(new(access_model.Access)) type IssueCount struct { Count int64 diff --git a/models/task.go b/models/task.go index 5528573ca5..cabb96c608 100644 --- a/models/task.go +++ b/models/task.go @@ -5,6 +5,7 @@ package models import ( + "context" "fmt" "code.gitea.io/gitea/models/db" @@ -51,15 +52,15 @@ type TranslatableMessage struct { // LoadRepo loads repository of the task func (task *Task) LoadRepo() error { - return task.loadRepo(db.GetEngine(db.DefaultContext)) + return task.loadRepo(db.DefaultContext) } -func (task *Task) loadRepo(e db.Engine) error { +func (task *Task) loadRepo(ctx context.Context) error { if task.Repo != nil { return nil } var repo repo_model.Repository - has, err := e.ID(task.RepoID).Get(&repo) + has, err := db.GetEngine(ctx).ID(task.RepoID).Get(&repo) if err != nil { return err } else if !has { @@ -233,12 +234,7 @@ func FindTasks(opts FindTaskOptions) ([]*Task, error) { // CreateTask creates a task on database func CreateTask(task *Task) error { - return createTask(db.GetEngine(db.DefaultContext), task) -} - -func createTask(e db.Engine, task *Task) error { - _, err := e.Insert(task) - return err + return db.Insert(db.DefaultContext, task) } // FinishMigrateTask updates database when migrate task finished diff --git a/models/unit/unit.go b/models/unit/unit.go index 9d3cae5f25..e94775413e 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -284,7 +284,7 @@ var ( TypePackages, "repo.packages", "/packages", - "repo.packages.desc", + "packages.desc", 6, perm.AccessModeRead, } diff --git a/models/unittest/consistency.go b/models/unittest/consistency.go index af05348868..46f889746a 100644 --- a/models/unittest/consistency.go +++ b/models/unittest/consistency.go @@ -73,8 +73,8 @@ func init() { AssertCountByCond(t, "follow", builder.Eq{"user_id": user.int("ID")}, user.int("NumFollowing")) AssertCountByCond(t, "follow", builder.Eq{"follow_id": user.int("ID")}, user.int("NumFollowers")) if user.int("Type") != modelsUserTypeOrganization { - assert.EqualValues(t, 0, user.int("NumMembers")) - assert.EqualValues(t, 0, user.int("NumTeams")) + assert.EqualValues(t, 0, user.int("NumMembers"), "Unexpected number of members for user id: %d", user.int("ID")) + assert.EqualValues(t, 0, user.int("NumTeams"), "Unexpected number of teams for user id: %d", user.int("ID")) } } @@ -91,37 +91,37 @@ func init() { actual := GetCountByCond(t, "watch", builder.Eq{"repo_id": repo.int("ID")}. And(builder.Neq{"mode": modelsRepoWatchModeDont})) assert.EqualValues(t, repo.int("NumWatches"), actual, - "Unexpected number of watches for repo %+v", repo) + "Unexpected number of watches for repo id: %d", repo.int("ID")) actual = GetCountByCond(t, "issue", builder.Eq{"is_pull": false, "repo_id": repo.int("ID")}) assert.EqualValues(t, repo.int("NumIssues"), actual, - "Unexpected number of issues for repo %+v", repo) + "Unexpected number of issues for repo id: %d", repo.int("ID")) actual = GetCountByCond(t, "issue", builder.Eq{"is_pull": false, "is_closed": true, "repo_id": repo.int("ID")}) assert.EqualValues(t, repo.int("NumClosedIssues"), actual, - "Unexpected number of closed issues for repo %+v", repo) + "Unexpected number of closed issues for repo id: %d", repo.int("ID")) actual = GetCountByCond(t, "issue", builder.Eq{"is_pull": true, "repo_id": repo.int("ID")}) assert.EqualValues(t, repo.int("NumPulls"), actual, - "Unexpected number of pulls for repo %+v", repo) + "Unexpected number of pulls for repo id: %d", repo.int("ID")) actual = GetCountByCond(t, "issue", builder.Eq{"is_pull": true, "is_closed": true, "repo_id": repo.int("ID")}) assert.EqualValues(t, repo.int("NumClosedPulls"), actual, - "Unexpected number of closed pulls for repo %+v", repo) + "Unexpected number of closed pulls for repo id: %d", repo.int("ID")) actual = GetCountByCond(t, "milestone", builder.Eq{"is_closed": true, "repo_id": repo.int("ID")}) assert.EqualValues(t, repo.int("NumClosedMilestones"), actual, - "Unexpected number of closed milestones for repo %+v", repo) + "Unexpected number of closed milestones for repo id: %d", repo.int("ID")) } checkForIssueConsistency := func(t assert.TestingT, bean interface{}) { issue := reflectionWrap(bean) typeComment := modelsCommentTypeComment actual := GetCountByCond(t, "comment", builder.Eq{"`type`": typeComment, "issue_id": issue.int("ID")}) - assert.EqualValues(t, issue.int("NumComments"), actual, "Unexpected number of comments for issue %+v", issue) + assert.EqualValues(t, issue.int("NumComments"), actual, "Unexpected number of comments for issue id: %d", issue.int("ID")) if issue.bool("IsPull") { prRow := AssertExistsAndLoadMap(t, "pull_request", builder.Eq{"issue_id": issue.int("ID")}) - assert.EqualValues(t, parseInt(prRow["index"]), issue.int("Index")) + assert.EqualValues(t, parseInt(prRow["index"]), issue.int("Index"), "Unexpected index for issue id: %d", issue.int("ID")) } } @@ -129,7 +129,7 @@ func init() { pr := reflectionWrap(bean) issueRow := AssertExistsAndLoadMap(t, "issue", builder.Eq{"id": pr.int("IssueID")}) assert.True(t, parseBool(issueRow["is_pull"])) - assert.EqualValues(t, parseInt(issueRow["index"]), pr.int("Index")) + assert.EqualValues(t, parseInt(issueRow["index"]), pr.int("Index"), "Unexpected index for pull request id: %d", pr.int("ID")) } checkForMilestoneConsistency := func(t assert.TestingT, bean interface{}) { @@ -137,7 +137,7 @@ func init() { AssertCountByCond(t, "issue", builder.Eq{"milestone_id": milestone.int("ID")}, milestone.int("NumIssues")) actual := GetCountByCond(t, "issue", builder.Eq{"is_closed": true, "milestone_id": milestone.int("ID")}) - assert.EqualValues(t, milestone.int("NumClosedIssues"), actual, "Unexpected number of closed issues for milestone %+v", milestone) + assert.EqualValues(t, milestone.int("NumClosedIssues"), actual, "Unexpected number of closed issues for milestone id: %d", milestone.int("ID")) completeness := 0 if milestone.int("NumIssues") > 0 { @@ -153,7 +153,7 @@ func init() { Query() assert.NoError(t, err) - assert.EqualValues(t, label.int("NumIssues"), len(issueLabels), "Unexpected number of issue for label %+v", label) + assert.EqualValues(t, label.int("NumIssues"), len(issueLabels), "Unexpected number of issue for label id: %d", label.int("ID")) issueIDs := make([]int, len(issueLabels)) for i, issueLabel := range issueLabels { @@ -164,7 +164,7 @@ func init() { if len(issueIDs) > 0 { expected = GetCountByCond(t, "issue", builder.In("id", issueIDs).And(builder.Eq{"is_closed": true})) } - assert.EqualValues(t, expected, label.int("NumClosedIssues"), "Unexpected number of closed issues for label %+v", label) + assert.EqualValues(t, expected, label.int("NumClosedIssues"), "Unexpected number of closed issues for label id: %d", label.int("ID")) } checkForTeamConsistency := func(t assert.TestingT, bean interface{}) { @@ -177,7 +177,7 @@ func init() { action := reflectionWrap(bean) if action.int("RepoID") != 1700 { // dangling intentional repoRow := AssertExistsAndLoadMap(t, "repository", builder.Eq{"id": action.int("RepoID")}) - assert.Equal(t, parseBool(repoRow["is_private"]), action.bool("IsPrivate"), "action: %+v", action) + assert.Equal(t, parseBool(repoRow["is_private"]), action.bool("IsPrivate"), "Unexpected is_private field for action id: %d", action.int("ID")) } } diff --git a/models/user.go b/models/user.go index 11234a881d..e8a412ca29 100644 --- a/models/user.go +++ b/models/user.go @@ -13,9 +13,11 @@ import ( _ "image/jpeg" // Needed for jpeg support asymkey_model "code.gitea.io/gitea/models/asymkey" + auth_model "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -68,8 +70,8 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { if err = db.DeleteBeans(ctx, &AccessToken{UID: u.ID}, - &Collaboration{UserID: u.ID}, - &Access{UserID: u.ID}, + &repo_model.Collaboration{UserID: u.ID}, + &access_model.Access{UserID: u.ID}, &repo_model.Watch{UserID: u.ID}, &repo_model.Star{UID: u.ID}, &user_model.Follow{UserID: u.ID}, @@ -80,7 +82,6 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { &user_model.UserOpenID{UID: u.ID}, &issues.Reaction{UserID: u.ID}, &organization.TeamUser{UID: u.ID}, - &Collaboration{UserID: u.ID}, &Stopwatch{UserID: u.ID}, &user_model.Setting{UserID: u.ID}, &pull_model.AutoMerge{DoerID: u.ID}, @@ -89,6 +90,10 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { return fmt.Errorf("deleteBeans: %v", err) } + if err := auth_model.DeleteOAuth2RelictsByUserID(ctx, u.ID); err != nil { + return err + } + if setting.Service.UserDeleteWithCommentsMaxTime != 0 && u.CreatedUnix.AsTime().Add(setting.Service.UserDeleteWithCommentsMaxTime).After(time.Now()) { @@ -161,7 +166,7 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { // ***** END: Branch Protections ***** // ***** START: PublicKey ***** - if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil { + if _, err = db.DeleteByBean(ctx, &asymkey_model.PublicKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deletePublicKeys: %v", err) } // ***** END: PublicKey ***** @@ -173,17 +178,17 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) { } // Delete GPGKeyImport(s). for _, key := range keys { - if _, err = e.Delete(&asymkey_model.GPGKeyImport{KeyID: key.KeyID}); err != nil { + if _, err = db.DeleteByBean(ctx, &asymkey_model.GPGKeyImport{KeyID: key.KeyID}); err != nil { return fmt.Errorf("deleteGPGKeyImports: %v", err) } } - if _, err = e.Delete(&asymkey_model.GPGKey{OwnerID: u.ID}); err != nil { + if _, err = db.DeleteByBean(ctx, &asymkey_model.GPGKey{OwnerID: u.ID}); err != nil { return fmt.Errorf("deleteGPGKeys: %v", err) } // ***** END: GPGPublicKey ***** // Clear assignee. - if err = clearAssigneeByUserID(e, u.ID); err != nil { + if _, err = db.DeleteByBean(ctx, &IssueAssignees{AssigneeID: u.ID}); err != nil { return fmt.Errorf("clear assignee: %v", err) } diff --git a/models/user/avatar.go b/models/user/avatar.go index c881642b56..6a44a3bcb3 100644 --- a/models/user/avatar.go +++ b/models/user/avatar.go @@ -26,12 +26,7 @@ func (u *User) CustomAvatarRelativePath() string { } // GenerateRandomAvatar generates a random avatar for user. -func GenerateRandomAvatar(u *User) error { - return GenerateRandomAvatarCtx(db.DefaultContext, u) -} - -// GenerateRandomAvatarCtx generates a random avatar for user. -func GenerateRandomAvatarCtx(ctx context.Context, u *User) error { +func GenerateRandomAvatar(ctx context.Context, u *User) error { seed := u.Email if len(seed) == 0 { seed = u.Name @@ -82,7 +77,7 @@ func (u *User) AvatarLinkWithSize(size int) string { if useLocalAvatar { if u.Avatar == "" && autoGenerateAvatar { - if err := GenerateRandomAvatar(u); err != nil { + if err := GenerateRandomAvatar(db.DefaultContext, u); err != nil { log.Error("GenerateRandomAvatar: %v", err) } } diff --git a/models/user/email_address.go b/models/user/email_address.go index 564d018dac..c931db9c16 100644 --- a/models/user/email_address.go +++ b/models/user/email_address.go @@ -207,7 +207,8 @@ func IsEmailUsed(ctx context.Context, email string) (bool, error) { return db.GetEngine(ctx).Where("lower_email=?", strings.ToLower(email)).Get(&EmailAddress{}) } -func addEmailAddress(ctx context.Context, email *EmailAddress) error { +// AddEmailAddress adds an email address to given user. +func AddEmailAddress(ctx context.Context, email *EmailAddress) error { email.Email = strings.TrimSpace(email.Email) used, err := IsEmailUsed(ctx, email.Email) if err != nil { @@ -223,11 +224,6 @@ func addEmailAddress(ctx context.Context, email *EmailAddress) error { return db.Insert(ctx, email) } -// AddEmailAddress adds an email address to given user. -func AddEmailAddress(email *EmailAddress) error { - return addEmailAddress(db.DefaultContext, email) -} - // AddEmailAddresses adds an email address to given user. func AddEmailAddresses(emails []*EmailAddress) error { if len(emails) == 0 { @@ -311,14 +307,14 @@ func ActivateEmail(email *EmailAddress) error { return err } defer committer.Close() - if err := updateActivation(db.GetEngine(ctx), email, true); err != nil { + if err := updateActivation(ctx, email, true); err != nil { return err } return committer.Commit() } -func updateActivation(e db.Engine, email *EmailAddress, activate bool) error { - user, err := GetUserByIDEngine(e, email.UID) +func updateActivation(ctx context.Context, email *EmailAddress, activate bool) error { + user, err := GetUserByIDCtx(ctx, email.UID) if err != nil { return err } @@ -326,10 +322,10 @@ func updateActivation(e db.Engine, email *EmailAddress, activate bool) error { return err } email.IsActivated = activate - if _, err := e.ID(email.ID).Cols("is_activated").Update(email); err != nil { + if _, err := db.GetEngine(ctx).ID(email.ID).Cols("is_activated").Update(email); err != nil { return err } - return UpdateUserColsEngine(e, user, "rands") + return UpdateUserCols(ctx, user, "rands") } // MakeEmailPrimary sets primary email address of given user. @@ -500,12 +496,11 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) { return err } defer committer.Close() - sess := db.GetEngine(ctx) // Activate/deactivate a user's secondary email address // First check if there's another user active with the same address addr := EmailAddress{UID: userID, LowerEmail: strings.ToLower(email)} - if has, err := sess.Get(&addr); err != nil { + if has, err := db.GetByBean(ctx, &addr); err != nil { return err } else if !has { return fmt.Errorf("no such email: %d (%s)", userID, email) @@ -521,14 +516,14 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) { return ErrEmailAlreadyUsed{Email: email} } } - if err = updateActivation(sess, &addr, activate); err != nil { + if err = updateActivation(ctx, &addr, activate); err != nil { return fmt.Errorf("unable to updateActivation() for %d:%s: %w", addr.ID, addr.Email, err) } // Activate/deactivate a user's primary email address and account if addr.IsPrimary { user := User{ID: userID, Email: email} - if has, err := sess.Get(&user); err != nil { + if has, err := db.GetByBean(ctx, &user); err != nil { return err } else if !has { return fmt.Errorf("no user with ID: %d and Email: %s", userID, email) @@ -539,7 +534,7 @@ func ActivateUserEmail(userID int64, email string, activate bool) (err error) { if user.Rands, err = GetUserSalt(); err != nil { return fmt.Errorf("unable to generate salt: %v", err) } - if err = UpdateUserColsEngine(sess, &user, "is_active", "rands"); err != nil { + if err = UpdateUserCols(ctx, &user, "is_active", "rands"); err != nil { return fmt.Errorf("unable to updateUserCols() for user ID: %d: %v", userID, err) } } diff --git a/models/user/email_address_test.go b/models/user/email_address_test.go index 7eeb469b26..79de4c0b48 100644 --- a/models/user/email_address_test.go +++ b/models/user/email_address_test.go @@ -45,7 +45,7 @@ func TestIsEmailUsed(t *testing.T) { func TestAddEmailAddress(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - assert.NoError(t, AddEmailAddress(&EmailAddress{ + assert.NoError(t, AddEmailAddress(db.DefaultContext, &EmailAddress{ Email: "user1234567890@example.com", LowerEmail: "user1234567890@example.com", IsPrimary: true, @@ -53,7 +53,7 @@ func TestAddEmailAddress(t *testing.T) { })) // ErrEmailAlreadyUsed - err := AddEmailAddress(&EmailAddress{ + err := AddEmailAddress(db.DefaultContext, &EmailAddress{ Email: "user1234567890@example.com", LowerEmail: "user1234567890@example.com", }) diff --git a/models/user/list.go b/models/user/list.go index 5cdc92ba4a..68e62ca15d 100644 --- a/models/user/list.go +++ b/models/user/list.go @@ -5,6 +5,7 @@ package user import ( + "context" "fmt" "code.gitea.io/gitea/models/auth" @@ -31,13 +32,13 @@ func (users UserList) GetTwoFaStatus() map[int64]bool { results[user.ID] = false // Set default to false } - if tokenMaps, err := users.loadTwoFactorStatus(db.GetEngine(db.DefaultContext)); err == nil { + if tokenMaps, err := users.loadTwoFactorStatus(db.DefaultContext); err == nil { for _, token := range tokenMaps { results[token.UID] = true } } - if ids, err := users.userIDsWithWebAuthn(db.GetEngine(db.DefaultContext)); err == nil { + if ids, err := users.userIDsWithWebAuthn(db.DefaultContext); err == nil { for _, id := range ids { results[id] = true } @@ -46,25 +47,25 @@ func (users UserList) GetTwoFaStatus() map[int64]bool { return results } -func (users UserList) loadTwoFactorStatus(e db.Engine) (map[int64]*auth.TwoFactor, error) { +func (users UserList) loadTwoFactorStatus(ctx context.Context) (map[int64]*auth.TwoFactor, error) { if len(users) == 0 { return nil, nil } userIDs := users.GetUserIDs() tokenMaps := make(map[int64]*auth.TwoFactor, len(userIDs)) - if err := e.In("uid", userIDs).Find(&tokenMaps); err != nil { + if err := db.GetEngine(ctx).In("uid", userIDs).Find(&tokenMaps); err != nil { return nil, fmt.Errorf("find two factor: %v", err) } return tokenMaps, nil } -func (users UserList) userIDsWithWebAuthn(e db.Engine) ([]int64, error) { +func (users UserList) userIDsWithWebAuthn(ctx context.Context) ([]int64, error) { if len(users) == 0 { return nil, nil } ids := make([]int64, 0, len(users)) - if err := e.Table(new(auth.WebAuthnCredential)).In("user_id", users.GetUserIDs()).Select("user_id").Distinct("user_id").Find(&ids); err != nil { + if err := db.GetEngine(ctx).Table(new(auth.WebAuthnCredential)).In("user_id", users.GetUserIDs()).Select("user_id").Distinct("user_id").Find(&ids); err != nil { return nil, fmt.Errorf("find two factor: %v", err) } return ids, nil diff --git a/models/user/openid.go b/models/user/openid.go index 8ca3c7f2c8..8ef0ce5ed7 100644 --- a/models/user/openid.go +++ b/models/user/openid.go @@ -5,6 +5,7 @@ package user import ( + "context" "errors" "fmt" @@ -41,12 +42,12 @@ func GetUserOpenIDs(uid int64) ([]*UserOpenID, error) { } // isOpenIDUsed returns true if the openid has been used. -func isOpenIDUsed(e db.Engine, uri string) (bool, error) { +func isOpenIDUsed(ctx context.Context, uri string) (bool, error) { if len(uri) == 0 { return true, nil } - return e.Get(&UserOpenID{URI: uri}) + return db.GetEngine(ctx).Get(&UserOpenID{URI: uri}) } // ErrOpenIDAlreadyUsed represents a "OpenIDAlreadyUsed" kind of error. @@ -64,22 +65,17 @@ func (err ErrOpenIDAlreadyUsed) Error() string { return fmt.Sprintf("OpenID already in use [oid: %s]", err.OpenID) } +// AddUserOpenID adds an pre-verified/normalized OpenID URI to given user. // NOTE: make sure openid.URI is normalized already -func addUserOpenID(e db.Engine, openid *UserOpenID) error { - used, err := isOpenIDUsed(e, openid.URI) +func AddUserOpenID(ctx context.Context, openid *UserOpenID) error { + used, err := isOpenIDUsed(ctx, openid.URI) if err != nil { return err } else if used { return ErrOpenIDAlreadyUsed{openid.URI} } - _, err = e.Insert(openid) - return err -} - -// AddUserOpenID adds an pre-verified/normalized OpenID URI to given user. -func AddUserOpenID(openid *UserOpenID) error { - return addUserOpenID(db.GetEngine(db.DefaultContext), openid) + return db.Insert(ctx, openid) } // DeleteUserOpenID deletes an openid address of given user. diff --git a/models/user/user.go b/models/user/user.go index 6aa63a0a56..f7d457b91b 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -509,21 +509,17 @@ func SetEmailNotifications(u *User, set string) error { return nil } -func isUserExist(e db.Engine, uid int64, name string) (bool, error) { - if len(name) == 0 { - return false, nil - } - return e. - Where("id!=?", uid). - Get(&User{LowerName: strings.ToLower(name)}) -} - // IsUserExist checks if given user name exist, // the user name should be noncased unique. // If uid is presented, then check will rule out that one, // it is used when update a user name in settings page. -func IsUserExist(uid int64, name string) (bool, error) { - return isUserExist(db.GetEngine(db.DefaultContext), uid, name) +func IsUserExist(ctx context.Context, uid int64, name string) (bool, error) { + if len(name) == 0 { + return false, nil + } + return db.GetEngine(ctx). + Where("id!=?", uid). + Get(&User{LowerName: strings.ToLower(name)}) } // Note: As of the beginning of 2022, it is recommended to use at least @@ -691,9 +687,7 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e } defer committer.Close() - sess := db.GetEngine(ctx) - - isExist, err := isUserExist(sess, 0, u.Name) + isExist, err := IsUserExist(ctx, 0, u.Name) if err != nil { return err } else if isExist { @@ -774,7 +768,7 @@ func GetVerifyUser(code string) (user *User) { // use tail hex username query user hexStr := code[base.TimeLimitCodeLength:] if b, err := hex.DecodeString(hexStr); err == nil { - if user, err = GetUserByName(string(b)); user != nil { + if user, err = GetUserByName(db.DefaultContext, string(b)); user != nil { return user } log.Error("user.getVerifyUser: %v", err) @@ -811,16 +805,15 @@ func ChangeUserName(u *User, newUserName string) (err error) { return err } defer committer.Close() - sess := db.GetEngine(ctx) - isExist, err := isUserExist(sess, 0, newUserName) + isExist, err := IsUserExist(ctx, 0, newUserName) if err != nil { return err } else if isExist { return ErrUserAlreadyExist{newUserName} } - if _, err = sess.Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, oldUserName); err != nil { + if _, err = db.GetEngine(ctx).Exec("UPDATE `repository` SET owner_name=? WHERE owner_name=?", newUserName, oldUserName); err != nil { return fmt.Errorf("Change repo owner name: %v", err) } @@ -845,9 +838,9 @@ func ChangeUserName(u *User, newUserName string) (err error) { } // checkDupEmail checks whether there are the same email with the user -func checkDupEmail(e db.Engine, u *User) error { +func checkDupEmail(ctx context.Context, u *User) error { u.Email = strings.ToLower(u.Email) - has, err := e. + has, err := db.GetEngine(ctx). Where("id!=?", u.ID). And("type=?", u.Type). And("email=?", u.Email). @@ -872,7 +865,8 @@ func validateUser(u *User) error { return ValidateEmail(u.Email) } -func updateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...string) error { +// UpdateUser updates user's information. +func UpdateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...string) error { err := validateUser(u) if err != nil { return err @@ -932,27 +926,13 @@ func updateUser(ctx context.Context, u *User, changePrimaryEmail bool, cols ...s return err } -// UpdateUser updates user's information. -func UpdateUser(u *User, emailChanged bool, cols ...string) error { - return updateUser(db.DefaultContext, u, emailChanged, cols...) -} - // UpdateUserCols update user according special columns func UpdateUserCols(ctx context.Context, u *User, cols ...string) error { - return updateUserCols(db.GetEngine(ctx), u, cols...) -} - -// UpdateUserColsEngine update user according special columns -func UpdateUserColsEngine(e db.Engine, u *User, cols ...string) error { - return updateUserCols(e, u, cols...) -} - -func updateUserCols(e db.Engine, u *User, cols ...string) error { if err := validateUser(u); err != nil { return err } - _, err := e.ID(u.ID).Cols(cols...).Update(u) + _, err := db.GetEngine(ctx).ID(u.ID).Cols(cols...).Update(u) return err } @@ -965,11 +945,11 @@ func UpdateUserSetting(u *User) (err error) { defer committer.Close() if !u.IsOrganization() { - if err = checkDupEmail(db.GetEngine(ctx), u); err != nil { + if err = checkDupEmail(ctx, u); err != nil { return err } } - if err = updateUser(ctx, u, false); err != nil { + if err = UpdateUser(ctx, u, false); err != nil { return err } return committer.Commit() @@ -994,10 +974,15 @@ func UserPath(userName string) string { //revive:disable-line:exported return filepath.Join(setting.RepoRootPath, strings.ToLower(userName)) } -// GetUserByIDEngine returns the user object by given ID if exists. -func GetUserByIDEngine(e db.Engine, id int64) (*User, error) { +// 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) { u := new(User) - has, err := e.ID(id).Get(u) + has, err := db.GetEngine(ctx).ID(id).Get(u) if err != nil { return nil, err } else if !has { @@ -1006,23 +991,8 @@ func GetUserByIDEngine(e db.Engine, id int64) (*User, error) { return u, nil } -// 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) { - return GetUserByIDEngine(db.GetEngine(ctx), id) -} - -// GetUserByName returns user by given name. -func GetUserByName(name string) (*User, error) { - return GetUserByNameCtx(db.DefaultContext, name) -} - // GetUserByNameCtx returns user by given name. -func GetUserByNameCtx(ctx context.Context, name string) (*User, error) { +func GetUserByName(ctx context.Context, name string) (*User, error) { if len(name) == 0 { return nil, ErrUserNotExist{0, name, 0} } @@ -1038,14 +1008,10 @@ func GetUserByNameCtx(ctx context.Context, name string) (*User, error) { // GetUserEmailsByNames returns a list of e-mails corresponds to names of users // that have their email notifications set to enabled or onmention. -func GetUserEmailsByNames(names []string) []string { - return getUserEmailsByNames(db.DefaultContext, names) -} - -func getUserEmailsByNames(ctx context.Context, names []string) []string { +func GetUserEmailsByNames(ctx context.Context, names []string) []string { mails := make([]string, 0, len(names)) for _, name := range names { - u, err := GetUserByNameCtx(ctx, name) + u, err := GetUserByName(ctx, name) if err != nil { continue } @@ -1108,7 +1074,7 @@ func GetUserNameByID(ctx context.Context, id int64) (string, error) { func GetUserIDsByNames(names []string, ignoreNonExistent bool) ([]int64, error) { ids := make([]int64, 0, len(names)) for _, name := range names { - u, err := GetUserByName(name) + u, err := GetUserByName(db.DefaultContext, name) if err != nil { if ignoreNonExistent { continue @@ -1254,11 +1220,7 @@ func GetAdminUser() (*User, error) { } // IsUserVisibleToViewer check if viewer is able to see user profile -func IsUserVisibleToViewer(u, viewer *User) bool { - return isUserVisibleToViewer(db.GetEngine(db.DefaultContext), u, viewer) -} - -func isUserVisibleToViewer(e db.Engine, u, viewer *User) bool { +func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool { if viewer != nil && viewer.IsAdmin { return true } @@ -1283,7 +1245,7 @@ func isUserVisibleToViewer(e db.Engine, u, viewer *User) bool { } // Now we need to check if they in some organization together - count, err := e.Table("team_user"). + count, err := db.GetEngine(ctx).Table("team_user"). Where( builder.And( builder.Eq{"uid": viewer.ID}, diff --git a/models/user/user_test.go b/models/user/user_test.go index 335537aa13..0dbf2fc205 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -31,10 +31,10 @@ func TestGetUserEmailsByNames(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) // ignore none active user email - assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user9"})) - assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames([]string{"user8", "user5"})) + assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user9"})) + assert.Equal(t, []string{"user8@example.com", "user5@example.com"}, GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user5"})) - assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames([]string{"user8", "user7"})) + assert.Equal(t, []string{"user8@example.com"}, GetUserEmailsByNames(db.DefaultContext, []string{"user8", "user7"})) } func TestCanCreateOrganization(t *testing.T) { @@ -287,19 +287,19 @@ func TestUpdateUser(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) user.KeepActivityPrivate = true - assert.NoError(t, UpdateUser(user, false)) + assert.NoError(t, UpdateUser(db.DefaultContext, user, false)) user = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) assert.True(t, user.KeepActivityPrivate) setting.Service.AllowedUserVisibilityModesSlice = []bool{true, false, false} user.KeepActivityPrivate = false user.Visibility = structs.VisibleTypePrivate - assert.Error(t, UpdateUser(user, false)) + assert.Error(t, UpdateUser(db.DefaultContext, user, false)) user = unittest.AssertExistsAndLoadBean(t, &User{ID: 2}).(*User) assert.True(t, user.KeepActivityPrivate) user.Email = "no mail@mail.org" - assert.Error(t, UpdateUser(user, true)) + assert.Error(t, UpdateUser(db.DefaultContext, user, true)) } func TestNewUserRedirect(t *testing.T) { diff --git a/models/userlist.go b/models/userlist.go deleted file mode 100644 index fbe1995b40..0000000000 --- a/models/userlist.go +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "context" - "fmt" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - user_model "code.gitea.io/gitea/models/user" - "code.gitea.io/gitea/modules/log" -) - -// IsUserOrgOwner returns true if user is in the owner team of given organization. -func IsUserOrgOwner(users user_model.UserList, orgID int64) map[int64]bool { - results := make(map[int64]bool, len(users)) - for _, user := range users { - results[user.ID] = false // Set default to false - } - ownerMaps, err := loadOrganizationOwners(db.DefaultContext, users, orgID) - if err == nil { - for _, owner := range ownerMaps { - results[owner.UID] = true - } - } - return results -} - -func loadOrganizationOwners(ctx context.Context, users user_model.UserList, orgID int64) (map[int64]*organization.TeamUser, error) { - if len(users) == 0 { - return nil, nil - } - ownerTeam, err := organization.GetOwnerTeam(ctx, orgID) - if err != nil { - if organization.IsErrTeamNotExist(err) { - log.Error("Organization does not have owner team: %d", orgID) - return nil, nil - } - return nil, err - } - - userIDs := users.GetUserIDs() - ownerMaps := make(map[int64]*organization.TeamUser) - err = db.GetEngine(ctx).In("uid", userIDs). - And("org_id=?", orgID). - And("team_id=?", ownerTeam.ID). - Find(&ownerMaps) - if err != nil { - return nil, fmt.Errorf("find team users: %v", err) - } - return ownerMaps, nil -} diff --git a/models/userlist_test.go b/models/userlist_test.go deleted file mode 100644 index 9b3c796e64..0000000000 --- a/models/userlist_test.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2019 The Gitea Authors. All rights reserved. -// Use of this source code is governed by a MIT-style -// license that can be found in the LICENSE file. - -package models - -import ( - "fmt" - "testing" - - "code.gitea.io/gitea/models/organization" - "code.gitea.io/gitea/models/unittest" - - "github.com/stretchr/testify/assert" -) - -func TestUserListIsPublicMember(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - tt := []struct { - orgid int64 - expected map[int64]bool - }{ - {3, map[int64]bool{2: true, 4: false, 28: true}}, - {6, map[int64]bool{5: true, 28: true}}, - {7, map[int64]bool{5: false}}, - {25, map[int64]bool{24: true}}, - {22, map[int64]bool{}}, - } - for _, v := range tt { - t.Run(fmt.Sprintf("IsPublicMemberOfOrdIg%d", v.orgid), func(t *testing.T) { - testUserListIsPublicMember(t, v.orgid, v.expected) - }) - } -} - -func testUserListIsPublicMember(t *testing.T, orgID int64, expected map[int64]bool) { - org, err := organization.GetOrgByID(orgID) - assert.NoError(t, err) - _, membersIsPublic, err := org.GetMembers() - assert.NoError(t, err) - assert.Equal(t, expected, membersIsPublic) -} - -func TestUserListIsUserOrgOwner(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - tt := []struct { - orgid int64 - expected map[int64]bool - }{ - {3, map[int64]bool{2: true, 4: false, 28: false}}, - {6, map[int64]bool{5: true, 28: false}}, - {7, map[int64]bool{5: true}}, - {25, map[int64]bool{24: false}}, // ErrTeamNotExist - {22, map[int64]bool{}}, // No member - } - for _, v := range tt { - t.Run(fmt.Sprintf("IsUserOrgOwnerOfOrdIg%d", v.orgid), func(t *testing.T) { - testUserListIsUserOrgOwner(t, v.orgid, v.expected) - }) - } -} - -func testUserListIsUserOrgOwner(t *testing.T, orgID int64, expected map[int64]bool) { - org, err := organization.GetOrgByID(orgID) - assert.NoError(t, err) - members, _, err := org.GetMembers() - assert.NoError(t, err) - assert.Equal(t, expected, IsUserOrgOwner(members, orgID)) -} diff --git a/models/webhook/webhook.go b/models/webhook/webhook.go index 941a3f15c7..1b79a414ad 100644 --- a/models/webhook/webhook.go +++ b/models/webhook/webhook.go @@ -397,6 +397,14 @@ func CreateWebhook(ctx context.Context, w *Webhook) error { return db.Insert(ctx, w) } +// CreateWebhooks creates multiple web hooks +func CreateWebhooks(ctx context.Context, ws []*Webhook) error { + for i := 0; i < len(ws); i++ { + ws[i].Type = strings.TrimSpace(ws[i].Type) + } + return db.Insert(ctx, ws) +} + // getWebhook uses argument bean as query condition, // ID must be specified and do not assign unnecessary fields. func getWebhook(bean *Webhook) (*Webhook, error) { @@ -454,8 +462,9 @@ func (opts *ListWebhookOptions) toCond() builder.Cond { return cond } -func listWebhooksByOpts(e db.Engine, opts *ListWebhookOptions) ([]*Webhook, error) { - sess := e.Where(opts.toCond()) +// ListWebhooksByOpts return webhooks based on options +func ListWebhooksByOpts(ctx context.Context, opts *ListWebhookOptions) ([]*Webhook, error) { + sess := db.GetEngine(ctx).Where(opts.toCond()) if opts.Page != 0 { sess = db.SetSessionPagination(sess, opts) @@ -469,22 +478,13 @@ func listWebhooksByOpts(e db.Engine, opts *ListWebhookOptions) ([]*Webhook, erro return webhooks, err } -// ListWebhooksByOpts return webhooks based on options -func ListWebhooksByOpts(opts *ListWebhookOptions) ([]*Webhook, error) { - return listWebhooksByOpts(db.GetEngine(db.DefaultContext), opts) -} - // CountWebhooksByOpts count webhooks based on options and ignore pagination func CountWebhooksByOpts(opts *ListWebhookOptions) (int64, error) { return db.GetEngine(db.DefaultContext).Where(opts.toCond()).Count(&Webhook{}) } // GetDefaultWebhooks returns all admin-default webhooks. -func GetDefaultWebhooks() ([]*Webhook, error) { - return getDefaultWebhooks(db.DefaultContext) -} - -func getDefaultWebhooks(ctx context.Context) ([]*Webhook, error) { +func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) { webhooks := make([]*Webhook, 0, 5) return webhooks, db.GetEngine(ctx). Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false). @@ -506,18 +506,14 @@ func GetSystemOrDefaultWebhook(id int64) (*Webhook, error) { } // GetSystemWebhooks returns all admin system webhooks. -func GetSystemWebhooks(isActive util.OptionalBool) ([]*Webhook, error) { - return getSystemWebhooks(db.GetEngine(db.DefaultContext), isActive) -} - -func getSystemWebhooks(e db.Engine, isActive util.OptionalBool) ([]*Webhook, error) { +func GetSystemWebhooks(ctx context.Context, isActive util.OptionalBool) ([]*Webhook, error) { webhooks := make([]*Webhook, 0, 5) if isActive.IsNone() { - return webhooks, e. + return webhooks, db.GetEngine(ctx). Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true). Find(&webhooks) } - return webhooks, e. + return webhooks, db.GetEngine(ctx). Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()). Find(&webhooks) } @@ -596,7 +592,7 @@ func DeleteDefaultSystemWebhook(id int64) error { // CopyDefaultWebhooksToRepo creates copies of the default webhooks in a new repo func CopyDefaultWebhooksToRepo(ctx context.Context, repoID int64) error { - ws, err := getDefaultWebhooks(ctx) + ws, err := GetDefaultWebhooks(ctx) if err != nil { return fmt.Errorf("GetDefaultWebhooks: %v", err) } diff --git a/models/webhook/webhook_test.go b/models/webhook/webhook_test.go index 5ce564b775..4bc811586d 100644 --- a/models/webhook/webhook_test.go +++ b/models/webhook/webhook_test.go @@ -122,7 +122,7 @@ func TestGetWebhookByOrgID(t *testing.T) { func TestGetActiveWebhooksByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(&ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue}) + hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{RepoID: 1, IsActive: util.OptionalBoolTrue}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(1), hooks[0].ID) @@ -132,7 +132,7 @@ func TestGetActiveWebhooksByRepoID(t *testing.T) { func TestGetWebhooksByRepoID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(&ListWebhookOptions{RepoID: 1}) + hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{RepoID: 1}) assert.NoError(t, err) if assert.Len(t, hooks, 2) { assert.Equal(t, int64(1), hooks[0].ID) @@ -142,7 +142,7 @@ func TestGetWebhooksByRepoID(t *testing.T) { func TestGetActiveWebhooksByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(&ListWebhookOptions{OrgID: 3, IsActive: util.OptionalBoolTrue}) + hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OrgID: 3, IsActive: util.OptionalBoolTrue}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(3), hooks[0].ID) @@ -152,7 +152,7 @@ func TestGetActiveWebhooksByOrgID(t *testing.T) { func TestGetWebhooksByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - hooks, err := ListWebhooksByOpts(&ListWebhookOptions{OrgID: 3}) + hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OrgID: 3}) assert.NoError(t, err) if assert.Len(t, hooks, 1) { assert.Equal(t, int64(3), hooks[0].ID) diff --git a/modules/cache/cache.go b/modules/cache/cache.go index fd32aa153b..21d0cd0a04 100644 --- a/modules/cache/cache.go +++ b/modules/cache/cache.go @@ -5,11 +5,9 @@ package cache import ( - "errors" "fmt" "strconv" - "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" mc "gitea.com/go-chi/cache" @@ -35,7 +33,7 @@ func NewContext() error { if conn, err = newCache(setting.CacheService.Cache); err != nil { return err } - if err = Ping(); err != nil { + if err = conn.Ping(); err != nil { return err } } @@ -43,29 +41,6 @@ func NewContext() error { return err } -// Ping checks if the cache service works or not, it not, it returns an error -func Ping() error { - if conn == nil { - return errors.New("cache not available") - } - var err error - const testKey = "__gitea_cache_test" - const testVal = "test-value" - if err = conn.Put(testKey, testVal, 10); err != nil { - return err - } - val := conn.Get(testKey) - if valStr, ok := val.(string); !ok || valStr != testVal { - // If the cache is full, the Get may not read the expected value stored by Put. - // Since we have checked that Put can success, so we just show a warning here, do not return an error to panic. - log.Warn("cache (adapter:%s, config:%s) doesn't seem to work correctly, set test value '%v' but get '%v'", - setting.CacheService.Cache.Adapter, setting.CacheService.Cache.Conn, - testVal, val, - ) - } - return nil -} - // GetCache returns the currently configured cache func GetCache() mc.Cache { return conn diff --git a/modules/cache/cache_redis.go b/modules/cache/cache_redis.go index ff6c8d424c..7bb71f08ce 100644 --- a/modules/cache/cache_redis.go +++ b/modules/cache/cache_redis.go @@ -153,6 +153,11 @@ func (c *RedisCacher) StartAndGC(opts cache.Options) error { return c.c.Ping(graceful.GetManager().HammerContext()).Err() } +// Ping tests if the cache is alive. +func (c *RedisCacher) Ping() error { + return c.c.Ping(graceful.GetManager().HammerContext()).Err() +} + func init() { cache.Register("redis", &RedisCacher{}) } diff --git a/modules/cache/cache_twoqueue.go b/modules/cache/cache_twoqueue.go index 275b73f068..9c26b011b6 100644 --- a/modules/cache/cache_twoqueue.go +++ b/modules/cache/cache_twoqueue.go @@ -199,6 +199,11 @@ func (c *TwoQueueCache) StartAndGC(opts mc.Options) error { return err } +// Ping tests if the cache is alive. +func (c *TwoQueueCache) Ping() error { + return mc.GenericPing(c) +} + func init() { mc.Register("twoqueue", &TwoQueueCache{}) } diff --git a/modules/charset/charset.go b/modules/charset/charset.go index cf8aa0cb75..89bbf1f8c9 100644 --- a/modules/charset/charset.go +++ b/modules/charset/charset.go @@ -131,7 +131,26 @@ func RemoveBOMIfPresent(content []byte) []byte { // DetectEncoding detect the encoding of content func DetectEncoding(content []byte) (string, error) { - if utf8.Valid(content) { + // First we check if the content represents valid utf8 content excepting a truncated character at the end. + + // Now we could decode all the runes in turn but this is not necessarily the cheapest thing to do + // instead we walk backwards from the end to trim off a the incomplete character + toValidate := content + end := len(toValidate) - 1 + + if end < 0 { + // no-op + } else if toValidate[end]>>5 == 0b110 { + // Incomplete 1 byte extension e.g. © which has been truncated to + toValidate = toValidate[:end] + } else if end > 0 && toValidate[end]>>6 == 0b10 && toValidate[end-1]>>4 == 0b1110 { + // Incomplete 2 byte extension e.g. ⛔ <9b><94> which has been truncated to <9b> + toValidate = toValidate[:end-1] + } else if end > 1 && toValidate[end]>>6 == 0b10 && toValidate[end-1]>>6 == 0b10 && toValidate[end-2]>>3 == 0b11110 { + // Incomplete 3 byte extension e.g. 💩 <9f><92> which has been truncated to <9f><92> + toValidate = toValidate[:end-2] + } + if utf8.Valid(toValidate) { log.Debug("Detected encoding: utf-8 (fast)") return "UTF-8", nil } diff --git a/modules/charset/charset_test.go b/modules/charset/charset_test.go index 8376a0698a..cfd5fb5696 100644 --- a/modules/charset/charset_test.go +++ b/modules/charset/charset_test.go @@ -5,6 +5,8 @@ package charset import ( + "bytes" + "io" "strings" "testing" @@ -304,3 +306,145 @@ func stringMustEndWith(t *testing.T, expected, value string) { func bytesMustStartWith(t *testing.T, expected, value []byte) { assert.Equal(t, expected, value[:len(expected)]) } + +func TestToUTF8WithFallbackReader(t *testing.T) { + resetDefaultCharsetsOrder() + + for testLen := 0; testLen < 2048; testLen++ { + pattern := " test { () }\n" + input := "" + for len(input) < testLen { + input += pattern + } + input = input[:testLen] + input += "// Выключаем" + rd := ToUTF8WithFallbackReader(bytes.NewReader([]byte(input))) + r, _ := io.ReadAll(rd) + assert.EqualValuesf(t, input, string(r), "testing string len=%d", testLen) + } + + truncatedOneByteExtension := failFastBytes + encoding, _ := DetectEncoding(truncatedOneByteExtension) + assert.Equal(t, "UTF-8", encoding) + + truncatedTwoByteExtension := failFastBytes + truncatedTwoByteExtension[len(failFastBytes)-1] = 0x9b + truncatedTwoByteExtension[len(failFastBytes)-2] = 0xe2 + + encoding, _ = DetectEncoding(truncatedTwoByteExtension) + assert.Equal(t, "UTF-8", encoding) + + truncatedThreeByteExtension := failFastBytes + truncatedThreeByteExtension[len(failFastBytes)-1] = 0x92 + truncatedThreeByteExtension[len(failFastBytes)-2] = 0x9f + truncatedThreeByteExtension[len(failFastBytes)-3] = 0xf0 + + encoding, _ = DetectEncoding(truncatedThreeByteExtension) + assert.Equal(t, "UTF-8", encoding) +} + +var failFastBytes = []byte{ + 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x67, 0x2e, 0x61, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2e, 0x74, 0x6f, + 0x6f, 0x6c, 0x73, 0x2e, 0x61, 0x6e, 0x74, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x64, 0x65, 0x66, 0x73, 0x2e, 0x63, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x4f, 0x73, 0x0a, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x67, + 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, + 0x74, 0x2e, 0x67, 0x72, 0x61, 0x64, 0x6c, 0x65, 0x2e, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x72, 0x75, 0x6e, 0x2e, 0x42, + 0x6f, 0x6f, 0x74, 0x52, 0x75, 0x6e, 0x0a, 0x0a, 0x70, 0x6c, 0x75, 0x67, 0x69, 0x6e, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x64, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, + 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x22, 0x29, 0x0a, 0x7d, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x61, 0x70, 0x69, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x61, 0x70, 0x69, 0x2d, 0x64, 0x6f, 0x63, 0x73, 0x22, 0x29, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x64, 0x62, + 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, + 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x66, + 0x73, 0x22, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x28, 0x22, 0x3a, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, + 0x3a, 0x69, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2d, 0x6d, 0x71, 0x22, 0x29, 0x29, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, + 0x6a, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2d, 0x61, 0x75, 0x74, 0x68, 0x2d, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2d, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x72, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6a, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2d, 0x68, 0x61, 0x6c, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6a, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, + 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2d, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x29, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, + 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, + 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x2d, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x77, 0x65, 0x62, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, + 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x3a, 0x73, 0x70, 0x72, + 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x2d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x61, 0x6f, 0x70, + 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, + 0x72, 0x6b, 0x2e, 0x62, 0x6f, 0x6f, 0x74, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x2d, + 0x73, 0x74, 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x61, 0x63, 0x74, 0x75, 0x61, 0x74, 0x6f, 0x72, 0x22, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, + 0x72, 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x73, 0x74, + 0x61, 0x72, 0x74, 0x65, 0x72, 0x2d, 0x62, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x22, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, + 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x65, 0x72, 0x2d, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2d, 0x61, 0x6c, 0x6c, 0x22, 0x29, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, + 0x67, 0x2e, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x3a, 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x65, 0x72, 0x2d, 0x73, 0x6c, 0x65, 0x75, 0x74, 0x68, 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, + 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6f, 0x72, 0x67, 0x2e, 0x73, 0x70, + 0x72, 0x69, 0x6e, 0x67, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x77, 0x6f, 0x72, 0x6b, 0x2e, 0x72, 0x65, 0x74, 0x72, 0x79, 0x3a, + 0x73, 0x70, 0x72, 0x69, 0x6e, 0x67, 0x2d, 0x72, 0x65, 0x74, 0x72, 0x79, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x63, 0x68, 0x2e, 0x71, + 0x6f, 0x73, 0x2e, 0x6c, 0x6f, 0x67, 0x62, 0x61, 0x63, 0x6b, 0x3a, 0x6c, 0x6f, 0x67, 0x62, 0x61, 0x63, 0x6b, 0x2d, 0x63, + 0x6c, 0x61, 0x73, 0x73, 0x69, 0x63, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, + 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x69, 0x6f, 0x2e, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x3a, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x2d, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x2d, 0x70, 0x72, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x65, 0x75, 0x73, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6b, 0x6f, 0x74, + 0x6c, 0x69, 0x6e, 0x28, 0x22, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x22, 0x29, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0x54, 0x65, 0x73, 0x74, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x65, 0x6e, 0x63, 0x69, 0x65, 0x73, 0x2e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, + 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x74, + 0x65, 0x73, 0x74, 0x49, 0x6d, 0x70, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x22, 0x6a, + 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x65, 0x3a, 0x70, 0x65, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2d, + 0x74, 0x65, 0x73, 0x74, 0x22, 0x29, 0x0a, 0x7d, 0x0a, 0x0a, 0x76, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x63, 0x68, 0x4a, + 0x61, 0x72, 0x20, 0x62, 0x79, 0x20, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x2e, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x69, 0x6e, 0x67, 0x28, 0x4a, 0x61, 0x72, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x69, 0x66, 0x69, 0x65, 0x72, 0x2e, + 0x73, 0x65, 0x74, 0x28, 0x22, 0x70, 0x61, 0x74, 0x63, 0x68, 0x65, 0x64, 0x22, 0x29, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x76, 0x61, 0x6c, 0x20, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x70, 0x61, 0x74, 0x68, + 0x20, 0x62, 0x79, 0x20, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x67, + 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x0a, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, + 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, + 0x73, 0x28, 0x22, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x2d, 0x50, 0x61, 0x74, 0x68, 0x22, 0x20, 0x74, 0x6f, 0x20, 0x6f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, + 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x76, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x20, 0x3d, + 0x20, 0x22, 0x66, 0x69, 0x6c, 0x65, 0x3a, 0x2f, 0x2b, 0x22, 0x2e, 0x74, 0x6f, 0x52, 0x65, 0x67, 0x65, 0x78, 0x28, 0x29, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, + 0x65, 0x20, 0x66, 0x75, 0x6e, 0x20, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x3a, 0x20, 0x53, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x3d, 0x20, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x70, + 0x61, 0x74, 0x68, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x6a, 0x6f, 0x69, 0x6e, 0x54, 0x6f, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x28, 0x22, 0x20, 0x22, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x74, 0x2e, 0x74, 0x6f, 0x55, 0x52, 0x49, 0x28, 0x29, 0x2e, 0x74, 0x6f, 0x55, + 0x52, 0x4c, 0x28, 0x29, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x28, 0x29, 0x2e, 0x72, 0x65, 0x70, 0x6c, + 0x61, 0x63, 0x65, 0x46, 0x69, 0x72, 0x73, 0x74, 0x28, 0x70, 0x61, 0x74, 0x74, 0x65, 0x72, 0x6e, 0x2c, 0x20, 0x22, 0x2f, + 0x22, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x7d, 0x0a, 0x0a, 0x74, 0x61, 0x73, + 0x6b, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x3c, 0x42, 0x6f, 0x6f, 0x74, 0x52, 0x75, 0x6e, 0x3e, 0x28, 0x22, 0x62, + 0x6f, 0x6f, 0x74, 0x52, 0x75, 0x6e, 0x22, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x4f, + 0x73, 0x2e, 0x69, 0x73, 0x46, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x28, 0x4f, 0x73, 0x2e, 0x46, 0x41, 0x4d, 0x49, 0x4c, 0x59, + 0x5f, 0x57, 0x49, 0x4e, 0x44, 0x4f, 0x57, 0x53, 0x29, 0x29, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x70, 0x61, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x28, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x74, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x64, 0x28, 0x22, 0x6d, 0x61, 0x69, + 0x6e, 0x22, 0x29, 0x2e, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x69, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x20, + 0x7d, 0x2c, 0x20, 0x70, 0x61, 0x74, 0x63, 0x68, 0x4a, 0x61, 0x72, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x2f, 0x2f, 0x20, 0xd0, +} diff --git a/modules/context/package.go b/modules/context/package.go index cb352fb18a..4c52907dc5 100644 --- a/modules/context/package.go +++ b/modules/context/package.go @@ -12,6 +12,7 @@ import ( packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/perm" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/structs" ) // Package contains owner, access mode and optional the package descriptor @@ -50,22 +51,29 @@ func packageAssignment(ctx *Context, errCb func(int, string, interface{})) { Owner: ctx.ContextUser, } - if ctx.Doer != nil && ctx.Doer.ID == ctx.ContextUser.ID { - ctx.Package.AccessMode = perm.AccessModeOwner - } else { - if ctx.Package.Owner.IsOrganization() { - if organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) { - ctx.Package.AccessMode = perm.AccessModeRead - if ctx.Doer != nil { - var err error - ctx.Package.AccessMode, err = organization.OrgFromUser(ctx.Package.Owner).GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID) - if err != nil { - errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err) - return - } - } + if ctx.Package.Owner.IsOrganization() { + // 1. Get user max authorize level for the org (may be none, if user is not member of the org) + if ctx.Doer != nil { + var err error + ctx.Package.AccessMode, err = organization.OrgFromUser(ctx.Package.Owner).GetOrgUserMaxAuthorizeLevel(ctx.Doer.ID) + if err != nil { + errCb(http.StatusInternalServerError, "GetOrgUserMaxAuthorizeLevel", err) + return } - } else { + } + // 2. If authorize level is none, check if org is visible to user + if ctx.Package.AccessMode == perm.AccessModeNone && organization.HasOrgOrUserVisible(ctx, ctx.Package.Owner, ctx.Doer) { + ctx.Package.AccessMode = perm.AccessModeRead + } + } else { + if ctx.Doer != nil && !ctx.Doer.IsGhost() { + // 1. Check if user is package owner + if ctx.Doer.ID == ctx.Package.Owner.ID { + ctx.Package.AccessMode = perm.AccessModeOwner + } else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic || ctx.Package.Owner.Visibility == structs.VisibleTypeLimited { // 2. Check if package owner is public or limited + ctx.Package.AccessMode = perm.AccessModeRead + } + } else if ctx.Package.Owner.Visibility == structs.VisibleTypePublic { // 3. Check if package owner is public ctx.Package.AccessMode = perm.AccessModeRead } } diff --git a/modules/context/permission.go b/modules/context/permission.go index 8dc3b3cd46..fd2263c75f 100644 --- a/modules/context/permission.go +++ b/modules/context/permission.go @@ -32,7 +32,7 @@ func RequireRepoWriter(unitType unit.Type) func(ctx *Context) { // CanEnableEditor checks if the user is allowed to write to the branch of the repo func CanEnableEditor() func(ctx *Context) { return func(ctx *Context) { - if !ctx.Repo.Permission.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { + if !ctx.Repo.CanWriteToBranch(ctx.Doer, ctx.Repo.BranchName) { ctx.NotFound("CanWriteToBranch denies permission", nil) return } diff --git a/modules/context/repo.go b/modules/context/repo.go index 3dc8e51392..5f4af114ff 100644 --- a/modules/context/repo.go +++ b/modules/context/repo.go @@ -16,6 +16,8 @@ import ( "strings" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -24,6 +26,7 @@ import ( code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup/markdown" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" @@ -54,7 +57,7 @@ type PullRequest struct { // Repository contains information to operate a repository type Repository struct { - models.Permission + access_model.Permission IsWatching bool IsViewBranch bool IsViewTag bool @@ -77,9 +80,14 @@ type Repository struct { PullRequest *PullRequest } +// CanWriteToBranch checks if the branch is writable by the user +func (r *Repository) CanWriteToBranch(user *user_model.User, branch string) bool { + return models.CanMaintainerWriteToBranch(r.Permission, branch, user) +} + // CanEnableEditor returns true if repository is editable and user has proper access level. func (r *Repository) CanEnableEditor(user *user_model.User) bool { - return r.IsViewBranch && r.Permission.CanWriteToBranch(user, r.BranchName) && r.Repository.CanEnableEditor() && !r.Repository.IsArchived + return r.IsViewBranch && r.CanWriteToBranch(user, r.BranchName) && r.Repository.CanEnableEditor() && !r.Repository.IsArchived } // CanCreateBranch returns true if repository is editable and user has proper access level. @@ -110,7 +118,7 @@ type CanCommitToBranchResults struct { // CanCommitToBranch returns true if repository is editable and user has proper access level // and branch is not protected for push func (r *Repository) CanCommitToBranch(ctx context.Context, doer *user_model.User) (CanCommitToBranchResults, error) { - protectedBranch, err := models.GetProtectedBranchBy(r.Repository.ID, r.BranchName) + protectedBranch, err := models.GetProtectedBranchBy(ctx, r.Repository.ID, r.BranchName) if err != nil { return CanCommitToBranchResults{}, err } @@ -153,7 +161,7 @@ func (r *Repository) CanUseTimetracker(issue *models.Issue, user *user_model.Use // Checking for following: // 1. Is timetracker enabled // 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this? - isAssigned, _ := models.IsUserAssignedToIssue(issue, user) + isAssigned, _ := models.IsUserAssignedToIssue(db.DefaultContext, issue, user) return r.Repository.IsTimetrackerEnabled() && (!r.Repository.AllowOnlyContributorsToTrackTime() || r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned) } @@ -272,7 +280,7 @@ func RetrieveBaseRepo(ctx *Context, repo *repo_model.Repository) { // RetrieveTemplateRepo retrieves template repository used to generate this repository func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) { // Non-generated repository will not return error in this method. - templateRepo, err := repo_model.GetTemplateRepo(repo) + templateRepo, err := repo_model.GetTemplateRepo(ctx, repo) if err != nil { if repo_model.IsErrRepoNotExist(err) { repo.TemplateID = 0 @@ -285,7 +293,7 @@ func RetrieveTemplateRepo(ctx *Context, repo *repo_model.Repository) { return } - perm, err := models.GetUserRepoPermission(ctx, templateRepo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, templateRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -351,7 +359,7 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { return } - ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx, repo, ctx.Doer) + ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -379,11 +387,12 @@ func repoAssignment(ctx *Context, repo *repo_model.Repository) { return } if finishedMigrating { - ctx.Repo.Mirror, err = repo_model.GetMirrorByRepoID(repo.ID) + ctx.Repo.Mirror, err = repo_model.GetMirrorByRepoID(ctx, repo.ID) if err != nil { ctx.ServerError("GetMirrorByRepoID", err) return } + ctx.Repo.Mirror.Repo = repo ctx.Data["MirrorEnablePrune"] = ctx.Repo.Mirror.EnablePrune ctx.Data["MirrorInterval"] = ctx.Repo.Mirror.Interval ctx.Data["Mirror"] = ctx.Repo.Mirror @@ -445,7 +454,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) { owner = ctx.Doer } else { - owner, err = user_model.GetUserByName(userName) + owner, err = user_model.GetUserByName(ctx, userName) if err != nil { if user_model.IsErrUserNotExist(err) { if ctx.FormString("go-get") == "1" { @@ -543,14 +552,14 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues) ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests) - canSignedUserFork, err := models.CanUserForkRepo(ctx.Doer, ctx.Repo.Repository) + canSignedUserFork, err := repo_module.CanUserForkRepo(ctx.Doer, ctx.Repo.Repository) if err != nil { ctx.ServerError("CanUserForkRepo", err) return } ctx.Data["CanSignedUserFork"] = canSignedUserFork - userAndOrgForks, err := models.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository) + userAndOrgForks, err := repo_model.GetForksByUserAndOrgs(ctx, ctx.Doer, ctx.Repo.Repository) if err != nil { ctx.ServerError("GetForksByUserAndOrgs", err) return @@ -581,7 +590,7 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) { if ctx.IsSigned { ctx.Data["IsWatchingRepo"] = repo_model.IsWatching(ctx.Doer.ID, repo.ID) - ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx.Doer.ID, repo.ID) + ctx.Data["IsStaringRepo"] = repo_model.IsStaring(ctx, ctx.Doer.ID, repo.ID) } if repo.IsFork { diff --git a/modules/convert/convert.go b/modules/convert/convert.go index 3a12ed8f1f..67b3902cd7 100644 --- a/modules/convert/convert.go +++ b/modules/convert/convert.go @@ -17,6 +17,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -44,16 +45,16 @@ func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *mod var canPush bool var err error if user != nil { - hasPerm, err = models.HasAccessUnit(user, repo, unit.TypeCode, perm.AccessModeWrite) + hasPerm, err = access_model.HasAccessUnit(db.DefaultContext, user, repo, unit.TypeCode, perm.AccessModeWrite) if err != nil { return nil, err } - perms, err := models.GetUserRepoPermission(db.DefaultContext, repo, user) + perms, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) if err != nil { return nil, err } - canPush = perms.CanWriteToBranch(user, b.Name) + canPush = models.CanMaintainerWriteToBranch(perms, b.Name, user) } return &api.Branch{ @@ -82,7 +83,7 @@ func ToBranch(repo *repo_model.Repository, b *git.Branch, c *git.Commit, bp *mod } if user != nil { - permission, err := models.GetUserRepoPermission(db.DefaultContext, repo, user) + permission, err := access_model.GetUserRepoPermission(db.DefaultContext, repo, user) if err != nil { return nil, err } @@ -303,22 +304,53 @@ func ToOrganization(org *organization.Organization) *api.Organization { } } -// ToTeam convert organization.Team to api.Team -func ToTeam(team *organization.Team) *api.Team { - if team == nil { - return nil +// ToTeam convert models.Team to api.Team +func ToTeam(team *organization.Team, loadOrg ...bool) (*api.Team, error) { + teams, err := ToTeams([]*organization.Team{team}, len(loadOrg) != 0 && loadOrg[0]) + if err != nil || len(teams) == 0 { + return nil, err + } + return teams[0], nil +} + +// ToTeams convert models.Team list to api.Team list +func ToTeams(teams []*organization.Team, loadOrgs bool) ([]*api.Team, error) { + if len(teams) == 0 || teams[0] == nil { + return nil, nil } - return &api.Team{ - ID: team.ID, - Name: team.Name, - Description: team.Description, - IncludesAllRepositories: team.IncludesAllRepositories, - CanCreateOrgRepo: team.CanCreateOrgRepo, - Permission: team.AccessMode.String(), - Units: team.GetUnitNames(), - UnitsMap: team.GetUnitsMap(), + cache := make(map[int64]*api.Organization) + apiTeams := make([]*api.Team, len(teams)) + for i := range teams { + if err := teams[i].GetUnits(); err != nil { + return nil, err + } + + apiTeams[i] = &api.Team{ + ID: teams[i].ID, + Name: teams[i].Name, + Description: teams[i].Description, + IncludesAllRepositories: teams[i].IncludesAllRepositories, + CanCreateOrgRepo: teams[i].CanCreateOrgRepo, + Permission: teams[i].AccessMode.String(), + Units: teams[i].GetUnitNames(), + UnitsMap: teams[i].GetUnitsMap(), + } + + if loadOrgs { + apiOrg, ok := cache[teams[i].OrgID] + if !ok { + org, err := organization.GetOrgByID(db.DefaultContext, teams[i].OrgID) + if err != nil { + return nil, err + } + apiOrg = ToOrganization(org) + cache[teams[i].OrgID] = apiOrg + } + apiTeams[i].Organization = apiOrg + } } + return apiTeams, nil } // ToAnnotatedTag convert git.Tag to api.AnnotatedTag diff --git a/modules/convert/issue.go b/modules/convert/issue.go index bf116e2283..a4512e424f 100644 --- a/modules/convert/issue.go +++ b/modules/convert/issue.go @@ -72,7 +72,7 @@ func ToAPIIssue(issue *models.Issue) *api.Issue { apiIssue.Milestone = ToAPIMilestone(issue.Milestone) } - if err := issue.LoadAssignees(); err != nil { + if err := issue.LoadAssignees(db.DefaultContext); err != nil { return &api.Issue{} } if len(issue.Assignees) > 0 { diff --git a/modules/convert/issue_comment.go b/modules/convert/issue_comment.go index caba2b506e..eaa7f64ea3 100644 --- a/modules/convert/issue_comment.go +++ b/modules/convert/issue_comment.go @@ -6,6 +6,7 @@ package convert import ( "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -113,7 +114,7 @@ func ToTimelineComment(c *models.Comment, doer *user_model.User) *api.TimelineCo } if c.RefCommentID != 0 { - com, err := models.GetCommentByID(c.RefCommentID) + com, err := models.GetCommentByID(db.DefaultContext, c.RefCommentID) if err != nil { log.Error("GetCommentByID(%d): %v", c.RefCommentID, err) return nil @@ -152,7 +153,7 @@ func ToTimelineComment(c *models.Comment, doer *user_model.User) *api.TimelineCo comment.Assignee = ToUser(c.Assignee, nil) } if c.AssigneeTeam != nil { - comment.AssigneeTeam = ToTeam(c.AssigneeTeam) + comment.AssigneeTeam, _ = ToTeam(c.AssigneeTeam) } if c.ResolveDoer != nil { diff --git a/modules/convert/notification.go b/modules/convert/notification.go index f304eadf69..1efba5745c 100644 --- a/modules/convert/notification.go +++ b/modules/convert/notification.go @@ -25,6 +25,11 @@ func ToNotificationThread(n *models.Notification) *api.NotificationThread { // 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) + + // This permission is not correct and we should not be reporting it + for repository := result.Repository; repository != nil; repository = repository.Parent { + repository.Permissions = nil + } } // handle Subject diff --git a/modules/convert/package.go b/modules/convert/package.go index a4ea41d522..9713cda48b 100644 --- a/modules/convert/package.go +++ b/modules/convert/package.go @@ -7,8 +7,8 @@ package convert import ( "context" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/packages" + access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" ) @@ -17,7 +17,7 @@ import ( func ToPackage(ctx context.Context, pd *packages.PackageDescriptor, doer *user_model.User) (*api.Package, error) { var repo *api.Repository if pd.Repository != nil { - permission, err := models.GetUserRepoPermission(ctx, pd.Repository, doer) + permission, err := access_model.GetUserRepoPermission(ctx, pd.Repository, doer) if err != nil { return nil, err } diff --git a/modules/convert/pull.go b/modules/convert/pull.go index a2f54270e4..310a7626c9 100644 --- a/modules/convert/pull.go +++ b/modules/convert/pull.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" @@ -43,7 +44,7 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo return nil } - p, err := models.GetUserRepoPermission(ctx, pr.BaseRepo, doer) + p, err := access_model.GetUserRepoPermission(ctx, pr.BaseRepo, doer) if err != nil { log.Error("GetUserRepoPermission[%d]: %v", pr.BaseRepoID, err) p.AccessMode = perm.AccessModeNone @@ -132,7 +133,7 @@ func ToAPIPullRequest(ctx context.Context, pr *models.PullRequest, doer *user_mo } if pr.HeadRepo != nil && pr.Flow == models.PullRequestFlowGithub { - p, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, doer) + p, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer) if err != nil { log.Error("GetUserRepoPermission[%d]: %v", pr.HeadRepoID, err) p.AccessMode = perm.AccessModeNone diff --git a/modules/convert/pull_review.go b/modules/convert/pull_review.go index 962aae58bb..907ccafb66 100644 --- a/modules/convert/pull_review.go +++ b/modules/convert/pull_review.go @@ -22,10 +22,15 @@ func ToPullReview(ctx context.Context, r *models.Review, doer *user_model.User) r.Reviewer = user_model.NewGhostUser() } + apiTeam, err := ToTeam(r.ReviewerTeam) + if err != nil { + return nil, err + } + result := &api.PullReview{ ID: r.ID, Reviewer: ToUser(r.Reviewer, doer), - ReviewerTeam: ToTeam(r.ReviewerTeam), + ReviewerTeam: apiTeam, State: api.ReviewStateUnknown, Body: r.Content, CommitID: r.CommitID, diff --git a/modules/convert/repository.go b/modules/convert/repository.go index 1f11fda7ac..eb6bb37707 100644 --- a/modules/convert/repository.go +++ b/modules/convert/repository.go @@ -104,7 +104,7 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo var mirrorUpdated time.Time if repo.IsMirror { var err error - repo.Mirror, err = repo_model.GetMirrorByRepoID(repo.ID) + repo.Mirror, err = repo_model.GetMirrorByRepoID(db.DefaultContext, repo.ID) if err == nil { mirrorInterval = repo.Mirror.Interval.String() mirrorUpdated = repo.Mirror.UpdatedUnix.AsTime() @@ -186,10 +186,7 @@ func innerToRepo(repo *repo_model.Repository, mode perm.AccessMode, isParent boo // ToRepoTransfer convert a models.RepoTransfer to a structs.RepeTransfer func ToRepoTransfer(t *models.RepoTransfer) *api.RepoTransfer { - var teams []*api.Team - for _, v := range t.Teams { - teams = append(teams, ToTeam(v)) - } + teams, _ := ToTeams(t.Teams, false) return &api.RepoTransfer{ Doer: ToUser(t.Doer, nil), diff --git a/modules/doctor/authorizedkeys.go b/modules/doctor/authorizedkeys.go index 18e7a3cbf4..34dfe939d3 100644 --- a/modules/doctor/authorizedkeys.go +++ b/modules/doctor/authorizedkeys.go @@ -54,7 +54,7 @@ func checkAuthorizedKeys(ctx context.Context, logger log.Logger, autofix bool) e // now we regenerate and check if there are any lines missing regenerated := &bytes.Buffer{} - if err := asymkey_model.RegeneratePublicKeys(regenerated); err != nil { + if err := asymkey_model.RegeneratePublicKeys(ctx, regenerated); err != nil { logger.Critical("Unable to regenerate authorized_keys file. ERROR: %v", err) return fmt.Errorf("Unable to regenerate authorized_keys file. ERROR: %v", err) } diff --git a/modules/doctor/breaking.go b/modules/doctor/breaking.go new file mode 100644 index 0000000000..c4b58d20fb --- /dev/null +++ b/modules/doctor/breaking.go @@ -0,0 +1,69 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package doctor + +import ( + "context" + "fmt" + + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + + "xorm.io/builder" +) + +func iterateUserAccounts(ctx context.Context, each func(*user.User) error) error { + err := db.Iterate( + ctx, + new(user.User), + builder.Gt{"id": 0}, + func(idx int, bean interface{}) error { + return each(bean.(*user.User)) + }, + ) + return err +} + +// Since 1.16.4 new restrictions has been set on email addresses. However users with invalid email +// addresses would be currently facing a error due to their invalid email address. +// Ref: https://github.com/go-gitea/gitea/pull/19085 & https://github.com/go-gitea/gitea/pull/17688 +func checkUserEmail(ctx context.Context, logger log.Logger, _ bool) error { + // We could use quirky SQL to get all users that start without a [a-zA-Z0-9], but that would mean + // DB provider-specific SQL and only works _now_. So instead we iterate trough all user accounts and + // use the user.ValidateEmail function to be future-proof. + var invalidUserCount int64 + if err := iterateUserAccounts(ctx, func(u *user.User) error { + // Only check for users, skip + if u.Type != user.UserTypeIndividual { + return nil + } + + if err := user.ValidateEmail(u.Email); err != nil { + invalidUserCount++ + logger.Warn("User[id=%d name=%q] have not a valid e-mail: %v", u.ID, u.Name, err) + } + return nil + }); err != nil { + return fmt.Errorf("iterateUserAccounts: %v", err) + } + + if invalidUserCount == 0 { + logger.Info("All users have a valid e-mail.") + } else { + logger.Warn("%d user(s) have a non-valid e-mail.", invalidUserCount) + } + return nil +} + +func init() { + Register(&Check{ + Title: "Check if users has an valid email address", + Name: "check-user-email", + IsDefault: false, + Run: checkUserEmail, + Priority: 9, + }) +} diff --git a/modules/doctor/dbconsistency.go b/modules/doctor/dbconsistency.go index 953a05fcd1..18cb2cdac6 100644 --- a/modules/doctor/dbconsistency.go +++ b/modules/doctor/dbconsistency.go @@ -105,6 +105,9 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er // find pulls without existing issues genericOrphanCheck("Orphaned PullRequests without existing issue", "pull_request", "issue", "pull_request.issue_id=issue.id"), + // find pull requests without base repository + genericOrphanCheck("Pull request entries without existing base repository", + "pull_request", "repository", "pull_request.base_repo_id=repository.id"), // find tracked times without existing issues/pulls genericOrphanCheck("Orphaned TrackedTimes without existing issue", "tracked_time", "issue", "tracked_time.issue_id=issue.id"), @@ -142,6 +145,12 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er Fixer: models.FixIssueLabelWithOutsideLabels, FixedMessage: "Removed", }, + { + Name: "Action with created_unix set as an empty string", + Counter: models.CountActionCreatedUnixString, + Fixer: models.FixActionCreatedUnixString, + FixedMessage: "Set to zero", + }, } // TODO: function to recalc all counters @@ -177,6 +186,18 @@ func checkDBConsistency(ctx context.Context, logger log.Logger, autofix bool) er // find access without repository genericOrphanCheck("Access entries without existing repository", "access", "repository", "access.repo_id=repository.id"), + // find action without repository + genericOrphanCheck("Action entries without existing repository", + "action", "repository", "action.repo_id=repository.id"), + // find OAuth2Grant without existing user + genericOrphanCheck("Orphaned OAuth2Grant without existing User", + "oauth2_grant", "user", "oauth2_grant.user_id=`user`.id"), + // find OAuth2Application without existing user + genericOrphanCheck("Orphaned OAuth2Application without existing User", + "oauth2_application", "user", "oauth2_application.uid=`user`.id"), + // find OAuth2AuthorizationCode without existing OAuth2Grant + genericOrphanCheck("Orphaned OAuth2AuthorizationCode without existing OAuth2Grant", + "oauth2_authorization_code", "oauth2_grant", "oauth2_authorization_code.grant_id=oauth2_grant.id"), ) for _, c := range consistencyChecks { diff --git a/modules/doctor/fix16961.go b/modules/doctor/fix16961.go index 92c77ba80f..92c4418505 100644 --- a/modules/doctor/fix16961.go +++ b/modules/doctor/fix16961.go @@ -302,7 +302,11 @@ func fixBrokenRepoUnits16961(ctx context.Context, logger log.Logger, autofix boo } if !autofix { - logger.Warn("Found %d broken repo_units", count) + if count == 0 { + logger.Info("Found no broken repo_units") + } else { + logger.Warn("Found %d broken repo_units", count) + } return nil } logger.Info("Fixed %d broken repo_units", count) diff --git a/modules/doctor/mergebase.go b/modules/doctor/mergebase.go index 8f5c61a5da..61ee9e212b 100644 --- a/modules/doctor/mergebase.go +++ b/modules/doctor/mergebase.go @@ -92,12 +92,14 @@ func checkPRMergeBase(ctx context.Context, logger log.Logger, autofix bool) erro if autofix { logger.Info("%d PR mergebases updated of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) } else { - if numPRsUpdated > 0 && err == nil { + if numPRsUpdated == 0 { + logger.Info("All %d PRs in %d repos have a correct mergebase", numPRs, numRepos) + } else if err == nil { logger.Critical("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) return fmt.Errorf("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) + } else { + logger.Warn("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) } - - logger.Warn("%d PRs with incorrect mergebases of %d PRs total in %d repos", numPRsUpdated, numPRs, numRepos) } return err diff --git a/modules/doctor/misc.go b/modules/doctor/misc.go index 60c190cf98..9bee78303e 100644 --- a/modules/doctor/misc.go +++ b/modules/doctor/misc.go @@ -75,9 +75,14 @@ func checkHooks(ctx context.Context, logger log.Logger, autofix bool) error { } func checkUserStarNum(ctx context.Context, logger log.Logger, autofix bool) error { - if err := models.DoctorUserStarNum(); err != nil { - logger.Critical("Unable update User Stars numbers") - return err + if autofix { + if err := models.DoctorUserStarNum(); err != nil { + logger.Critical("Unable update User Stars numbers") + return err + } + logger.Info("Updated User Stars numbers.") + } else { + logger.Info("No check available for User Stars numbers (skipped)") } return nil } @@ -207,7 +212,7 @@ func init() { Priority: 6, }) Register(&Check{ - Title: "Enable push options", + Title: "Check that all git repositories have receive.advertisePushOptions set to true", Name: "enable-push-options", IsDefault: false, Run: checkEnablePushOptions, diff --git a/modules/git/blame.go b/modules/git/blame.go index 40e3d4e885..1653ecbf85 100644 --- a/modules/git/blame.go +++ b/modules/git/blame.go @@ -124,6 +124,7 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla cmd := exec.CommandContext(ctx, command[0], command[1:]...) cmd.Dir = dir cmd.Stderr = os.Stderr + process.SetSysProcAttribute(cmd) stdout, err := cmd.StdoutPipe() if err != nil { diff --git a/modules/git/command.go b/modules/git/command.go index 3dd12e421e..f6344dbfd1 100644 --- a/modules/git/command.go +++ b/modules/git/command.go @@ -157,6 +157,7 @@ func (c *Command) Run(opts *RunOpts) error { "GIT_NO_REPLACE_OBJECTS=1", ) + process.SetSysProcAttribute(cmd) cmd.Dir = opts.Dir cmd.Stdout = opts.Stdout cmd.Stderr = opts.Stderr diff --git a/modules/git/notes_nogogit.go b/modules/git/notes_nogogit.go index e3f0a3fee9..1476805dcd 100644 --- a/modules/git/notes_nogogit.go +++ b/modules/git/notes_nogogit.go @@ -46,7 +46,10 @@ func GetNote(ctx context.Context, repo *Repository, commitID string, note *Note) commitID = commitID[2:] } if err != nil { - log.Error("Unable to find git note corresponding to the commit %q. Error: %v", originalCommitID, err) + // Err may have been updated by the SubTree we need to recheck if it's again an ErrNotExist + if !IsErrNotExist(err) { + log.Error("Unable to find git note corresponding to the commit %q. Error: %v", originalCommitID, err) + } return err } } diff --git a/modules/gitgraph/graph_models.go b/modules/gitgraph/graph_models.go index 653384252d..551e56f63e 100644 --- a/modules/gitgraph/graph_models.go +++ b/modules/gitgraph/graph_models.go @@ -120,7 +120,7 @@ func (graph *Graph) LoadAndProcessCommits(repository *repo_model.Repository, git return models.IsOwnerMemberCollaborator(repository, user.ID) }, &keyMap) - statuses, _, err := models.GetLatestCommitStatus(repository.ID, c.Commit.ID.String(), db.ListOptions{}) + statuses, _, err := models.GetLatestCommitStatus(db.DefaultContext, repository.ID, c.Commit.ID.String(), db.ListOptions{}) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } else { diff --git a/modules/indexer/code/git.go b/modules/indexer/code/git.go index 60018af20c..66d76377ad 100644 --- a/modules/indexer/code/git.go +++ b/modules/indexer/code/git.go @@ -38,7 +38,7 @@ func getDefaultBranchSha(ctx context.Context, repo *repo_model.Repository) (stri // getRepoChanges returns changes to repo since last indexer update func getRepoChanges(ctx context.Context, repo *repo_model.Repository, revision string) (*repoChanges, error) { - status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeCode) + status, err := repo_model.GetIndexerStatus(ctx, repo, repo_model.RepoIndexerTypeCode) if err != nil { return nil, err } diff --git a/modules/indexer/code/indexer.go b/modules/indexer/code/indexer.go index f15b8d8651..9845ade3dd 100644 --- a/modules/indexer/code/indexer.go +++ b/modules/indexer/code/indexer.go @@ -108,7 +108,7 @@ func index(ctx context.Context, indexer Indexer, repoID int64) error { return err } - return repo_model.UpdateIndexerStatus(repo, repo_model.RepoIndexerTypeCode, sha) + return repo_model.UpdateIndexerStatus(ctx, repo, repo_model.RepoIndexerTypeCode, sha) } // Init initialize the repo indexer diff --git a/modules/indexer/issues/indexer.go b/modules/indexer/issues/indexer.go index d4df4f8a4f..85de4c75b3 100644 --- a/modules/indexer/issues/indexer.go +++ b/modules/indexer/issues/indexer.go @@ -291,8 +291,8 @@ func populateIssueIndexer(ctx context.Context) { return default: } - repos, _, err := models.SearchRepositoryByName(&models.SearchRepoOptions{ - ListOptions: db.ListOptions{Page: page, PageSize: models.RepositoryListDefaultPageSize}, + repos, _, err := repo_model.SearchRepositoryByName(&repo_model.SearchRepoOptions{ + ListOptions: db.ListOptions{Page: page, PageSize: repo_model.RepositoryListDefaultPageSize}, OrderBy: db.SearchOrderByID, Private: true, Collaborate: util.OptionalBoolFalse, @@ -362,7 +362,7 @@ func UpdateIssueIndexer(issue *models.Issue) { // DeleteRepoIssueIndexer deletes repo's all issues indexes func DeleteRepoIssueIndexer(repo *repo_model.Repository) { var ids []int64 - ids, err := models.GetIssueIDsByRepoID(repo.ID) + ids, err := models.GetIssueIDsByRepoID(db.DefaultContext, repo.ID) if err != nil { log.Error("getIssueIDsByRepoID failed: %v", err) return diff --git a/modules/indexer/stats/db.go b/modules/indexer/stats/db.go index bb3385ab63..d39b1dcf2a 100644 --- a/modules/indexer/stats/db.go +++ b/modules/indexer/stats/db.go @@ -30,7 +30,7 @@ func (db *DBIndexer) Index(id int64) error { return nil } - status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeStats) + status, err := repo_model.GetIndexerStatus(ctx, repo, repo_model.RepoIndexerTypeStats) if err != nil { return err } diff --git a/modules/indexer/stats/indexer_test.go b/modules/indexer/stats/indexer_test.go index c8bd8d1783..9d9de5413c 100644 --- a/modules/indexer/stats/indexer_test.go +++ b/modules/indexer/stats/indexer_test.go @@ -10,6 +10,7 @@ import ( "testing" "time" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/git" @@ -49,7 +50,7 @@ func TestRepoStatsIndex(t *testing.T) { queue.GetManager().FlushAll(context.Background(), 5*time.Second) - status, err := repo_model.GetIndexerStatus(repo, repo_model.RepoIndexerTypeStats) + status, err := repo_model.GetIndexerStatus(db.DefaultContext, repo, repo_model.RepoIndexerTypeStats) assert.NoError(t, err) assert.Equal(t, "65f1bf27bc3bf70f64657658635e66094edbcb4d", status.CommitSha) langs, err := repo_model.GetTopLanguageStats(repo, 5) diff --git a/modules/markup/console/console.go b/modules/markup/console/console.go new file mode 100644 index 0000000000..b59594acb7 --- /dev/null +++ b/modules/markup/console/console.go @@ -0,0 +1,95 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package console + +import ( + "bytes" + "io" + "path/filepath" + "regexp" + "strings" + + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/setting" + + trend "github.com/buildkite/terminal-to-html/v3" + "github.com/go-enry/go-enry/v2" +) + +// MarkupName describes markup's name +var MarkupName = "console" + +func init() { + markup.RegisterRenderer(Renderer{}) +} + +// Renderer implements markup.Renderer +type Renderer struct{} + +// Name implements markup.Renderer +func (Renderer) Name() string { + return MarkupName +} + +// NeedPostProcess implements markup.Renderer +func (Renderer) NeedPostProcess() bool { return false } + +// Extensions implements markup.Renderer +func (Renderer) Extensions() []string { + return []string{".sh-session"} +} + +// SanitizerRules implements markup.Renderer +func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { + return []setting.MarkupSanitizerRule{ + {Element: "span", AllowAttr: "class", Regexp: regexp.MustCompile(`^term-((fg[ix]?|bg)\d+|container)$`)}, + } +} + +// SanitizerDisabled disabled sanitize if return true +func (Renderer) SanitizerDisabled() bool { + return false +} + +// CanRender implements markup.RendererContentDetector +func (Renderer) CanRender(filename string, input io.Reader) bool { + buf, err := io.ReadAll(input) + if err != nil { + return false + } + if enry.GetLanguage(filepath.Base(filename), buf) != enry.OtherLanguage { + return false + } + return bytes.ContainsRune(buf, '\x1b') +} + +// Render renders terminal colors to HTML with all specific handling stuff. +func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error { + buf, err := io.ReadAll(input) + if err != nil { + return err + } + buf = trend.Render(buf) + buf = bytes.ReplaceAll(buf, []byte("\n"), []byte(`
`)) + _, err = output.Write(buf) + return err +} + +// Render renders terminal colors to HTML with all specific handling stuff. +func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error { + if ctx.Type == "" { + ctx.Type = MarkupName + } + return markup.Render(ctx, input, output) +} + +// RenderString renders terminal colors in string to HTML with all specific handling stuff and return string +func RenderString(ctx *markup.RenderContext, content string) (string, error) { + var buf strings.Builder + if err := Render(ctx, strings.NewReader(content), &buf); err != nil { + return "", err + } + return buf.String(), nil +} diff --git a/modules/markup/console/console_test.go b/modules/markup/console/console_test.go new file mode 100644 index 0000000000..282fbb0598 --- /dev/null +++ b/modules/markup/console/console_test.go @@ -0,0 +1,31 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package console + +import ( + "strings" + "testing" + + "code.gitea.io/gitea/modules/markup" + + "github.com/stretchr/testify/assert" +) + +func TestRenderConsole(t *testing.T) { + var render Renderer + kases := map[string]string{ + "\x1b[37m\x1b[40mnpm\x1b[0m \x1b[0m\x1b[32minfo\x1b[0m \x1b[0m\x1b[35mit worked if it ends with\x1b[0m ok": "npm info it worked if it ends with ok", + } + + for k, v := range kases { + var buf strings.Builder + canRender := render.CanRender("test", strings.NewReader(k)) + assert.True(t, canRender) + + err := render.Render(&markup.RenderContext{}, strings.NewReader(k), &buf) + assert.NoError(t, err) + assert.EqualValues(t, v, buf.String()) + } +} diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index 4fdd4315bc..a587abcc3b 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -124,6 +124,8 @@ func (p *Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io. cmd.Stdin = input } cmd.Stdout = output + process.SetSysProcAttribute(cmd) + if err := cmd.Run(); err != nil { return fmt.Errorf("%s render run command %s %v failed: %v", p.Name(), commands[0], args, err) } diff --git a/modules/markup/markdown/goldmark.go b/modules/markup/markdown/goldmark.go index 9b6cd3aaef..1750128dec 100644 --- a/modules/markup/markdown/goldmark.go +++ b/modules/markup/markdown/goldmark.go @@ -27,13 +27,6 @@ import ( var byteMailto = []byte("mailto:") -// Header holds the data about a header. -type Header struct { - Level int - Text string - ID string -} - // ASTTransformer is a default transformer of the goldmark tree. type ASTTransformer struct{} @@ -42,12 +35,13 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa metaData := meta.GetItems(pc) firstChild := node.FirstChild() createTOC := false - toc := []Header{} + ctx := pc.Get(renderContextKey).(*markup.RenderContext) rc := &RenderConfig{ Meta: "table", Icon: "table", Lang: "", } + if metaData != nil { rc.ToRenderConfig(metaData) @@ -56,7 +50,7 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa node.InsertBefore(node, firstChild, metaNode) } createTOC = rc.TOC - toc = make([]Header, 0, 100) + ctx.TableOfContents = make([]markup.Header, 0, 100) } _ = ast.Walk(node, func(n ast.Node, entering bool) (ast.WalkStatus, error) { @@ -66,23 +60,20 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa switch v := n.(type) { case *ast.Heading: - if createTOC { - text := n.Text(reader.Source()) - header := Header{ - Text: util.BytesToReadOnlyString(text), - Level: v.Level, - } - if id, found := v.AttributeString("id"); found { - header.ID = util.BytesToReadOnlyString(id.([]byte)) - } - toc = append(toc, header) - } else { - for _, attr := range v.Attributes() { - if _, ok := attr.Value.([]byte); !ok { - v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value))) - } + for _, attr := range v.Attributes() { + if _, ok := attr.Value.([]byte); !ok { + v.SetAttribute(attr.Name, []byte(fmt.Sprintf("%v", attr.Value))) } } + text := n.Text(reader.Source()) + header := markup.Header{ + Text: util.BytesToReadOnlyString(text), + Level: v.Level, + } + if id, found := v.AttributeString("id"); found { + header.ID = util.BytesToReadOnlyString(id.([]byte)) + } + ctx.TableOfContents = append(ctx.TableOfContents, header) case *ast.Image: // Images need two things: // @@ -199,12 +190,12 @@ func (g *ASTTransformer) Transform(node *ast.Document, reader text.Reader, pc pa return ast.WalkContinue, nil }) - if createTOC && len(toc) > 0 { + if createTOC && len(ctx.TableOfContents) > 0 { lang := rc.Lang if len(lang) == 0 { lang = setting.Langs[0] } - tocNode := createTOCNode(toc, lang) + tocNode := createTOCNode(ctx.TableOfContents, lang) if tocNode != nil { node.InsertBefore(node, firstChild, tocNode) } diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 320c2f7f82..7ebdfea6c4 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -34,9 +34,10 @@ var ( ) var ( - urlPrefixKey = parser.NewContextKey() - isWikiKey = parser.NewContextKey() - renderMetasKey = parser.NewContextKey() + urlPrefixKey = parser.NewContextKey() + isWikiKey = parser.NewContextKey() + renderMetasKey = parser.NewContextKey() + renderContextKey = parser.NewContextKey() ) type limitWriter struct { @@ -67,6 +68,7 @@ func newParserContext(ctx *markup.RenderContext) parser.Context { pc.Set(urlPrefixKey, ctx.URLPrefix) pc.Set(isWikiKey, ctx.IsWiki) pc.Set(renderMetasKey, ctx.Metas) + pc.Set(renderContextKey, ctx) return pc } diff --git a/modules/markup/markdown/toc.go b/modules/markup/markdown/toc.go index 9d11b771f7..fec45103e5 100644 --- a/modules/markup/markdown/toc.go +++ b/modules/markup/markdown/toc.go @@ -8,12 +8,13 @@ import ( "fmt" "net/url" + "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/translation/i18n" "github.com/yuin/goldmark/ast" ) -func createTOCNode(toc []Header, lang string) ast.Node { +func createTOCNode(toc []markup.Header, lang string) ast.Node { details := NewDetails() summary := NewSummary() diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index cf8b9bace7..6e4ae4e08c 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -5,6 +5,7 @@ package markup import ( + "bytes" "context" "errors" "fmt" @@ -33,18 +34,26 @@ func Init() { } } +// Header holds the data about a header. +type Header struct { + Level int + Text string + ID string +} + // RenderContext represents a render context type RenderContext struct { - Ctx context.Context - Filename string - Type string - IsWiki bool - URLPrefix string - Metas map[string]string - DefaultLink string - GitRepo *git.Repository - ShaExistCache map[string]bool - cancelFn func() + Ctx context.Context + Filename string + Type string + IsWiki bool + URLPrefix string + Metas map[string]string + DefaultLink string + GitRepo *git.Repository + ShaExistCache map[string]bool + cancelFn func() + TableOfContents []Header } // Cancel runs any cleanup functions that have been registered for this Ctx @@ -85,6 +94,12 @@ type Renderer interface { Render(ctx *RenderContext, input io.Reader, output io.Writer) error } +// RendererContentDetector detects if the content can be rendered +// by specified renderer +type RendererContentDetector interface { + CanRender(filename string, input io.Reader) bool +} + var ( extRenderers = make(map[string]Renderer) renderers = make(map[string]Renderer) @@ -109,6 +124,20 @@ func GetRendererByType(tp string) Renderer { return renderers[tp] } +// DetectRendererType detects the markup type of the content +func DetectRendererType(filename string, input io.Reader) string { + buf, err := io.ReadAll(input) + if err != nil { + return "" + } + for _, renderer := range renderers { + if detector, ok := renderer.(RendererContentDetector); ok && detector.CanRender(filename, bytes.NewReader(buf)) { + return renderer.Name() + } + } + return "" +} + // Render renders markup file to HTML with all specific handling stuff. func Render(ctx *RenderContext, input io.Reader, output io.Writer) error { if ctx.Type != "" { diff --git a/modules/migration/review.go b/modules/migration/review.go index e4db33d98f..b5a054c642 100644 --- a/modules/migration/review.go +++ b/modules/migration/review.go @@ -18,6 +18,7 @@ const ( ReviewStateApproved = "APPROVED" ReviewStateChangesRequested = "CHANGES_REQUESTED" ReviewStateCommented = "COMMENTED" + ReviewStateRequestReview = "REQUEST_REVIEW" ) // Review is a standard review information diff --git a/modules/notification/webhook/webhook.go b/modules/notification/webhook/webhook.go index c59e972ed6..38077f2180 100644 --- a/modules/notification/webhook/webhook.go +++ b/modules/notification/webhook/webhook.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -52,7 +53,7 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *m return } - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) var err error if issue.IsPull { if err = issue.LoadPullRequest(); err != nil { @@ -82,8 +83,8 @@ func (m *webhookNotifier) NotifyIssueClearLabels(doer *user_model.User, issue *m } func (m *webhookNotifier) NotifyForkRepository(doer *user_model.User, oldRepo, repo *repo_model.Repository) { - oldMode, _ := models.AccessLevel(doer, oldRepo) - mode, _ := models.AccessLevel(doer, repo) + oldMode, _ := access_model.AccessLevel(doer, oldRepo) + mode, _ := access_model.AccessLevel(doer, repo) // forked webhook if err := webhook_services.PrepareWebhooks(oldRepo, webhook.HookEventFork, &api.ForkPayload{ @@ -151,7 +152,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue defer finished() if issue.IsPull { - mode, _ := models.AccessLevelUnit(doer, issue.Repo, unit.TypePullRequests) + mode, _ := access_model.AccessLevelUnit(doer, issue.Repo, unit.TypePullRequests) if err := issue.LoadPullRequest(); err != nil { log.Error("LoadPullRequest failed: %v", err) @@ -175,7 +176,7 @@ func (m *webhookNotifier) NotifyIssueChangeAssignee(doer *user_model.User, issue return } } else { - mode, _ := models.AccessLevelUnit(doer, issue.Repo, unit.TypeIssues) + mode, _ := access_model.AccessLevelUnit(doer, issue.Repo, unit.TypeIssues) apiIssue := &api.IssuePayload{ Index: issue.Index, Issue: convert.ToAPIIssue(issue), @@ -199,7 +200,7 @@ func (m *webhookNotifier) NotifyIssueChangeTitle(doer *user_model.User, issue *m ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeTitle User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) defer finished() - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) var err error if issue.IsPull { if err = issue.LoadPullRequest(); err != nil { @@ -243,7 +244,7 @@ func (m *webhookNotifier) NotifyIssueChangeStatus(doer *user_model.User, issue * ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeStatus User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) defer finished() - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) var err error if issue.IsPull { if err = issue.LoadPullRequest(); err != nil { @@ -292,7 +293,7 @@ func (m *webhookNotifier) NotifyNewIssue(issue *models.Issue, mentions []*user_m return } - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) if err := webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventIssues, &api.IssuePayload{ Action: api.HookIssueOpened, Index: issue.Index, @@ -321,7 +322,7 @@ func (m *webhookNotifier) NotifyNewPullRequest(pull *models.PullRequest, mention return } - mode, _ := models.AccessLevel(pull.Issue.Poster, pull.Issue.Repo) + mode, _ := access_model.AccessLevel(pull.Issue.Poster, pull.Issue.Repo) if err := webhook_services.PrepareWebhooks(pull.Issue.Repo, webhook.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueOpened, Index: pull.Issue.Index, @@ -337,7 +338,7 @@ func (m *webhookNotifier) NotifyIssueChangeContent(doer *user_model.User, issue ctx, _, finished := process.GetManager().AddContext(graceful.GetManager().HammerContext(), fmt.Sprintf("webhook.NotifyIssueChangeContent User: %s[%d] Issue[%d] #%d in [%d]", doer.Name, doer.ID, issue.ID, issue.Index, issue.RepoID)) defer finished() - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) var err error if issue.IsPull { issue.PullRequest.Issue = issue @@ -389,7 +390,7 @@ func (m *webhookNotifier) NotifyUpdateComment(doer *user_model.User, c *models.C return } - mode, _ := models.AccessLevel(doer, c.Issue.Repo) + mode, _ := access_model.AccessLevel(doer, c.Issue.Repo) if c.Issue.IsPull { err = webhook_services.PrepareWebhooks(c.Issue.Repo, webhook.HookEventPullRequestComment, &api.IssueCommentPayload{ Action: api.HookIssueCommentEdited, @@ -428,7 +429,7 @@ func (m *webhookNotifier) NotifyUpdateComment(doer *user_model.User, c *models.C func (m *webhookNotifier) NotifyCreateIssueComment(doer *user_model.User, repo *repo_model.Repository, issue *models.Issue, comment *models.Comment, mentions []*user_model.User, ) { - mode, _ := models.AccessLevel(doer, repo) + mode, _ := access_model.AccessLevel(doer, repo) var err error if issue.IsPull { @@ -473,7 +474,7 @@ func (m *webhookNotifier) NotifyDeleteComment(doer *user_model.User, comment *mo return } - mode, _ := models.AccessLevel(doer, comment.Issue.Repo) + mode, _ := access_model.AccessLevel(doer, comment.Issue.Repo) if comment.Issue.IsPull { err = webhook_services.PrepareWebhooks(comment.Issue.Repo, webhook.HookEventPullRequestComment, &api.IssueCommentPayload{ @@ -518,7 +519,7 @@ func (m *webhookNotifier) NotifyIssueChangeLabels(doer *user_model.User, issue * return } - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) if issue.IsPull { if err = issue.LoadPullRequest(); err != nil { log.Error("loadPullRequest: %v", err) @@ -566,7 +567,7 @@ func (m *webhookNotifier) NotifyIssueChangeMilestone(doer *user_model.User, issu return } - mode, _ := models.AccessLevel(doer, issue.Repo) + mode, _ := access_model.AccessLevel(doer, issue.Repo) if issue.IsPull { err = issue.PullRequest.LoadIssue() if err != nil { @@ -640,7 +641,7 @@ func (*webhookNotifier) NotifyMergePullRequest(pr *models.PullRequest, doer *use return } - mode, err := models.AccessLevel(doer, pr.Issue.Repo) + mode, err := access_model.AccessLevel(doer, pr.Issue.Repo) if err != nil { log.Error("models.AccessLevel: %v", err) return @@ -676,7 +677,7 @@ func (m *webhookNotifier) NotifyPullRequestChangeTargetBranch(doer *user_model.U return } issue.PullRequest.Issue = issue - mode, _ := models.AccessLevel(issue.Poster, issue.Repo) + mode, _ := access_model.AccessLevel(issue.Poster, issue.Repo) err = webhook_services.PrepareWebhooks(issue.Repo, webhook.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueEdited, Index: issue.Index, @@ -719,7 +720,7 @@ func (m *webhookNotifier) NotifyPullRequestReview(pr *models.PullRequest, review return } - mode, err := models.AccessLevel(review.Issue.Poster, review.Issue.Repo) + mode, err := access_model.AccessLevel(review.Issue.Poster, review.Issue.Repo) if err != nil { log.Error("models.AccessLevel: %v", err) return @@ -801,7 +802,7 @@ func sendReleaseHook(doer *user_model.User, rel *models.Release, action api.Hook return } - mode, _ := models.AccessLevel(doer, rel.Repo) + mode, _ := access_model.AccessLevel(doer, rel.Repo) if err := webhook_services.PrepareWebhooks(rel.Repo, webhook.HookEventRelease, &api.ReleasePayload{ Action: action, Release: convert.ToRelease(rel), diff --git a/modules/process/manager_exec.go b/modules/process/manager_exec.go index 61ddae646f..77e3d3193a 100644 --- a/modules/process/manager_exec.go +++ b/modules/process/manager_exec.go @@ -58,6 +58,7 @@ func (pm *Manager) ExecDirEnvStdIn(ctx context.Context, timeout time.Duration, d if stdIn != nil { cmd.Stdin = stdIn } + SetSysProcAttribute(cmd) if err := cmd.Start(); err != nil { return "", "", err diff --git a/modules/process/manager_unix.go b/modules/process/manager_unix.go new file mode 100644 index 0000000000..1e7c77fdbf --- /dev/null +++ b/modules/process/manager_unix.go @@ -0,0 +1,18 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build !windows + +package process + +import ( + "os/exec" + "syscall" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // When Gitea runs SubProcessA -> SubProcessB and SubProcessA gets killed by context timeout, use setpgid to make sure the sub processes can be reaped instead of leaving defunct(zombie) processes. + cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} +} diff --git a/modules/process/manager_windows.go b/modules/process/manager_windows.go new file mode 100644 index 0000000000..35f66d9fa5 --- /dev/null +++ b/modules/process/manager_windows.go @@ -0,0 +1,16 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +//go:build windows + +package process + +import ( + "os/exec" +) + +// SetSysProcAttribute sets the common SysProcAttrs for commands +func SetSysProcAttribute(cmd *exec.Cmd) { + // Do nothing +} diff --git a/modules/repository/create.go b/modules/repository/create.go index 21d45c896e..95bb825403 100644 --- a/modules/repository/create.go +++ b/modules/repository/create.go @@ -7,15 +7,20 @@ package repository import ( "context" "fmt" + "os" + "path" "strings" + "unicode/utf8" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" 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/log" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" ) @@ -108,7 +113,7 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) ( } } - if err := models.CheckDaemonExportOK(ctx, repo); err != nil { + if err := CheckDaemonExportOK(ctx, repo); err != nil { return fmt.Errorf("checkDaemonExportOK: %v", err) } @@ -133,3 +138,111 @@ func CreateRepository(doer, u *user_model.User, opts models.CreateRepoOptions) ( return repo, nil } + +// UpdateRepoSize updates the repository size, calculating it using util.GetDirectorySize +func UpdateRepoSize(ctx context.Context, repo *repo_model.Repository) error { + size, err := util.GetDirectorySize(repo.RepoPath()) + if err != nil { + return fmt.Errorf("updateSize: %v", err) + } + + lfsSize, err := models.GetRepoLFSSize(ctx, repo.ID) + if err != nil { + return fmt.Errorf("updateSize: GetLFSMetaObjects: %v", err) + } + + return repo_model.UpdateRepoSize(ctx, repo.ID, size+lfsSize) +} + +// CheckDaemonExportOK creates/removes git-daemon-export-ok for git-daemon... +func CheckDaemonExportOK(ctx context.Context, repo *repo_model.Repository) error { + if err := repo.GetOwner(ctx); err != nil { + return err + } + + // Create/Remove git-daemon-export-ok for git-daemon... + daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`) + + isExist, err := util.IsExist(daemonExportFile) + if err != nil { + log.Error("Unable to check if %s exists. Error: %v", daemonExportFile, err) + return err + } + + isPublic := !repo.IsPrivate && repo.Owner.Visibility == api.VisibleTypePublic + if !isPublic && isExist { + if err = util.Remove(daemonExportFile); err != nil { + log.Error("Failed to remove %s: %v", daemonExportFile, err) + } + } else if isPublic && !isExist { + if f, err := os.Create(daemonExportFile); err != nil { + log.Error("Failed to create %s: %v", daemonExportFile, err) + } else { + f.Close() + } + } + + return nil +} + +// UpdateRepository updates a repository with db context +func UpdateRepository(ctx context.Context, repo *repo_model.Repository, visibilityChanged bool) (err error) { + repo.LowerName = strings.ToLower(repo.Name) + + if utf8.RuneCountInString(repo.Description) > 255 { + repo.Description = string([]rune(repo.Description)[:255]) + } + if utf8.RuneCountInString(repo.Website) > 255 { + repo.Website = string([]rune(repo.Website)[:255]) + } + + e := db.GetEngine(ctx) + + if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil { + return fmt.Errorf("update: %v", err) + } + + if err = UpdateRepoSize(ctx, repo); err != nil { + log.Error("Failed to update size for repository: %v", err) + } + + if visibilityChanged { + if err = repo.GetOwner(ctx); err != nil { + return fmt.Errorf("getOwner: %v", err) + } + if repo.Owner.IsOrganization() { + // Organization repository need to recalculate access table when visibility is changed. + if err = access_model.RecalculateTeamAccesses(ctx, repo, 0); err != nil { + return fmt.Errorf("recalculateTeamAccesses: %v", err) + } + } + + // If repo has become private, we need to set its actions to private. + if repo.IsPrivate { + _, err = e.Where("repo_id = ?", repo.ID).Cols("is_private").Update(&models.Action{ + IsPrivate: true, + }) + if err != nil { + return err + } + } + + // Create/Remove git-daemon-export-ok for git-daemon... + if err := CheckDaemonExportOK(db.WithEngine(ctx, e), repo); err != nil { + return err + } + + forkRepos, err := repo_model.GetRepositoriesByForkID(ctx, repo.ID) + if err != nil { + return fmt.Errorf("getRepositoriesByForkID: %v", err) + } + for i := range forkRepos { + forkRepos[i].IsPrivate = repo.IsPrivate || repo.Owner.Visibility == api.VisibleTypePrivate + if err = UpdateRepository(ctx, forkRepos[i], true); err != nil { + return fmt.Errorf("updateRepository[%d]: %v", forkRepos[i].ID, err) + } + } + } + + return nil +} diff --git a/modules/repository/create_test.go b/modules/repository/create_test.go index b6a89a7ed6..2a47e93631 100644 --- a/modules/repository/create_test.go +++ b/modules/repository/create_test.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/structs" @@ -147,3 +148,23 @@ func TestIncludesAllRepositoriesTeams(t *testing.T) { } assert.NoError(t, organization.DeleteOrganization(db.DefaultContext, org), "DeleteOrganization") } + +func TestUpdateRepositoryVisibilityChanged(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // Get sample repo and change visibility + repo, err := repo_model.GetRepositoryByID(9) + assert.NoError(t, err) + repo.IsPrivate = true + + // Update it + err = UpdateRepository(db.DefaultContext, repo, true) + assert.NoError(t, err) + + // Check visibility of action has become private + act := models.Action{} + _, err = db.GetEngine(db.DefaultContext).ID(3).Get(&act) + + assert.NoError(t, err) + assert.True(t, act.IsPrivate) +} diff --git a/modules/repository/delete.go b/modules/repository/delete.go new file mode 100644 index 0000000000..25fb15e300 --- /dev/null +++ b/modules/repository/delete.go @@ -0,0 +1,33 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repository + +import ( + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" +) + +// CanUserDelete returns true if user could delete the repository +func CanUserDelete(repo *repo_model.Repository, user *user_model.User) (bool, error) { + if user.IsAdmin || user.ID == repo.OwnerID { + return true, nil + } + + if err := repo.GetOwner(db.DefaultContext); err != nil { + return false, err + } + + if repo.Owner.IsOrganization() { + isOwner, err := organization.OrgFromUser(repo.Owner).IsOwnedBy(user.ID) + if err != nil { + return false, err + } + return isOwner, nil + } + + return false, nil +} diff --git a/modules/repository/fork.go b/modules/repository/fork.go new file mode 100644 index 0000000000..c967d3b741 --- /dev/null +++ b/modules/repository/fork.go @@ -0,0 +1,31 @@ +// Copyright 2019 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repository + +import ( + "code.gitea.io/gitea/models/organization" + repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" +) + +// CanUserForkRepo returns true if specified user can fork repository. +func CanUserForkRepo(user *user_model.User, repo *repo_model.Repository) (bool, error) { + if user == nil { + return false, nil + } + if repo.OwnerID != user.ID && !repo_model.HasForkedRepo(user.ID, repo.ID) { + return true, nil + } + ownedOrgs, err := organization.GetOrgsCanCreateRepoByUserID(user.ID) + if err != nil { + return false, err + } + for _, org := range ownedOrgs { + if repo.OwnerID != org.ID && !repo_model.HasForkedRepo(org.ID, repo.ID) { + return true, nil + } + } + return false, nil +} diff --git a/modules/repository/generate.go b/modules/repository/generate.go index 1436d764f0..94bb6e6429 100644 --- a/modules/repository/generate.go +++ b/modules/repository/generate.go @@ -5,6 +5,8 @@ package repository import ( + "bufio" + "bytes" "context" "fmt" "os" @@ -20,6 +22,7 @@ import ( "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/util" + "github.com/gobwas/glob" "github.com/huandu/xstrings" ) @@ -43,7 +46,7 @@ var defaultTransformers = []transformer{ {Name: "PASCAL", Transform: xstrings.ToCamelCase}, {Name: "LOWER", Transform: strings.ToLower}, {Name: "UPPER", Transform: strings.ToUpper}, - {Name: "TITLE", Transform: strings.Title}, + {Name: "TITLE", Transform: util.ToTitleCase}, } func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository) string { @@ -78,7 +81,38 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi }) } -func checkGiteaTemplate(tmpDir string) (*models.GiteaTemplate, error) { +// GiteaTemplate holds information about a .gitea/template file +type GiteaTemplate struct { + Path string + Content []byte + + globs []glob.Glob +} + +// Globs parses the .gitea/template globs or returns them if they were already parsed +func (gt GiteaTemplate) Globs() []glob.Glob { + if gt.globs != nil { + return gt.globs + } + + gt.globs = make([]glob.Glob, 0) + scanner := bufio.NewScanner(bytes.NewReader(gt.Content)) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" || strings.HasPrefix(line, "#") { + continue + } + g, err := glob.Compile(line, '/') + if err != nil { + log.Info("Invalid glob expression '%s' (skipped): %v", line, err) + continue + } + gt.globs = append(gt.globs, g) + } + return gt.globs +} + +func checkGiteaTemplate(tmpDir string) (*GiteaTemplate, error) { gtPath := filepath.Join(tmpDir, ".gitea", "template") if _, err := os.Stat(gtPath); os.IsNotExist(err) { return nil, nil @@ -91,7 +125,7 @@ func checkGiteaTemplate(tmpDir string) (*models.GiteaTemplate, error) { return nil, err } - gt := &models.GiteaTemplate{ + gt := &GiteaTemplate{ Path: gtPath, Content: content, } @@ -227,7 +261,7 @@ func generateGitContent(ctx context.Context, repo, templateRepo, generateRepo *r if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil { return fmt.Errorf("setDefaultBranch: %v", err) } - if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil { + if err = UpdateRepository(ctx, repo, false); err != nil { return fmt.Errorf("updateRepository: %v", err) } @@ -240,7 +274,7 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo return err } - if err := models.UpdateRepoSize(ctx, generateRepo); err != nil { + if err := UpdateRepoSize(ctx, generateRepo); err != nil { return fmt.Errorf("failed to update size for repository: %v", err) } @@ -250,8 +284,27 @@ func GenerateGitContent(ctx context.Context, templateRepo, generateRepo *repo_mo return nil } +// GenerateRepoOptions contains the template units to generate +type GenerateRepoOptions struct { + Name string + DefaultBranch string + Description string + Private bool + GitContent bool + Topics bool + GitHooks bool + Webhooks bool + Avatar bool + IssueLabels bool +} + +// IsValid checks whether at least one option is chosen for generation +func (gro GenerateRepoOptions) IsValid() bool { + return gro.GitContent || gro.Topics || gro.GitHooks || gro.Webhooks || gro.Avatar || gro.IssueLabels // or other items as they are added +} + // GenerateRepository generates a repository from a template -func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts models.GenerateRepoOptions) (_ *repo_model.Repository, err error) { +func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templateRepo *repo_model.Repository, opts GenerateRepoOptions) (_ *repo_model.Repository, err error) { generateRepo := &repo_model.Repository{ OwnerID: owner.ID, Owner: owner, @@ -288,7 +341,7 @@ func GenerateRepository(ctx context.Context, doer, owner *user_model.User, templ return generateRepo, err } - if err = models.CheckDaemonExportOK(ctx, generateRepo); err != nil { + if err = CheckDaemonExportOK(ctx, generateRepo); err != nil { return generateRepo, fmt.Errorf("checkDaemonExportOK: %v", err) } diff --git a/models/repo_generate_test.go b/modules/repository/generate_test.go similarity index 98% rename from models/repo_generate_test.go rename to modules/repository/generate_test.go index e7a93433a7..139fa4c918 100644 --- a/models/repo_generate_test.go +++ b/modules/repository/generate_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package models +package repository import ( "testing" diff --git a/modules/repository/init.go b/modules/repository/init.go index 845a61ed0a..f8c7a89552 100644 --- a/modules/repository/init.go +++ b/modules/repository/init.go @@ -444,7 +444,7 @@ func initRepository(ctx context.Context, repoPath string, u *user_model.User, re } } - if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil { + if err = UpdateRepository(ctx, repo, false); err != nil { return fmt.Errorf("updateRepository: %v", err) } diff --git a/modules/repository/repo.go b/modules/repository/repo.go index 30ca6fdff8..281999a1eb 100644 --- a/modules/repository/repo.go +++ b/modules/repository/repo.go @@ -116,7 +116,7 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, repo.Owner = u } - if err = models.CheckDaemonExportOK(ctx, repo); err != nil { + if err = CheckDaemonExportOK(ctx, repo); err != nil { return repo, fmt.Errorf("checkDaemonExportOK: %v", err) } @@ -168,9 +168,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } } - if err = models.UpdateRepoSize(ctx, repo); err != nil { - log.Error("Failed to update size for repository: %v", err) + ctx, committer, err := db.TxContext() + if err != nil { + return nil, err } + defer committer.Close() if opts.Mirror { mirrorModel := repo_model.Mirror{ @@ -203,17 +205,24 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User, } } - if err = repo_model.InsertMirror(&mirrorModel); err != nil { + if err = repo_model.InsertMirror(ctx, &mirrorModel); err != nil { return repo, fmt.Errorf("InsertOne: %v", err) } repo.IsMirror = true - err = models.UpdateRepository(repo, false) + if err = UpdateRepository(ctx, repo, false); err != nil { + return nil, err + } } else { - repo, err = CleanUpMigrateInfo(ctx, repo) + if err = UpdateRepoSize(ctx, repo); err != nil { + log.Error("Failed to update size for repository: %v", err) + } + if repo, err = CleanUpMigrateInfo(ctx, repo); err != nil { + return nil, err + } } - return repo, err + return repo, committer.Commit() } // cleanUpMigrateGitConfig removes mirror info which prevents "push --all". @@ -253,7 +262,7 @@ func CleanUpMigrateInfo(ctx context.Context, repo *repo_model.Repository) (*repo } } - return repo, models.UpdateRepository(repo, false) + return repo, UpdateRepository(ctx, repo, false) } // SyncReleasesWithTags synchronizes release table with repository tags diff --git a/modules/setting/log.go b/modules/setting/log.go index 008a419b09..d69b5c6888 100644 --- a/modules/setting/log.go +++ b/modules/setting/log.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/util" ini "gopkg.in/ini.v1" ) @@ -245,7 +246,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription Provider: provider, Config: config, }) - log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName) + log.Info("%s Log: %s(%s:%s)", util.ToTitleCase(key), util.ToTitleCase(name), provider, levelName) } AddLogDescription(key, &description) @@ -331,7 +332,7 @@ func newLogService() { Provider: provider, Config: config, }) - log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName) + log.Info("Gitea Log Mode: %s(%s:%s)", util.ToTitleCase(name), util.ToTitleCase(provider), levelName) } AddLogDescription(log.DEFAULT, &description) diff --git a/modules/setting/repository.go b/modules/setting/repository.go index f24bc841d6..0b90fbc67c 100644 --- a/modules/setting/repository.go +++ b/modules/setting/repository.go @@ -71,6 +71,7 @@ var ( WorkInProgressPrefixes []string CloseKeywords []string ReopenKeywords []string + DefaultMergeStyle string DefaultMergeMessageCommitsLimit int DefaultMergeMessageSize int DefaultMergeMessageAllAuthors bool @@ -192,6 +193,7 @@ var ( WorkInProgressPrefixes []string CloseKeywords []string ReopenKeywords []string + DefaultMergeStyle string DefaultMergeMessageCommitsLimit int DefaultMergeMessageSize int DefaultMergeMessageAllAuthors bool @@ -205,6 +207,7 @@ var ( // https://help.github.com/articles/closing-issues-via-commit-messages CloseKeywords: strings.Split("close,closes,closed,fix,fixes,fixed,resolve,resolves,resolved", ","), ReopenKeywords: strings.Split("reopen,reopens,reopened", ","), + DefaultMergeStyle: "merge", DefaultMergeMessageCommitsLimit: 50, DefaultMergeMessageSize: 5 * 1024, DefaultMergeMessageAllAuthors: false, @@ -295,7 +298,7 @@ func newRepository() { log.Fatal("Failed to map Repository.PullRequest settings: %v", err) } - if !Cfg.Section("packages").Key("ENABLED").MustBool(false) { + if !Cfg.Section("packages").Key("ENABLED").MustBool(true) { Repository.DisabledRepoUnits = append(Repository.DisabledRepoUnits, "repo.packages") } diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 5e317b39ea..88f306b3fa 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -478,6 +478,18 @@ func getWorkPath(appPath string) string { workPath = appPath[:i] } } + workPath = strings.ReplaceAll(workPath, "\\", "/") + if !filepath.IsAbs(workPath) { + log.Info("Provided work path %s is not absolute - will be made absolute against the current working directory", workPath) + + absPath, err := filepath.Abs(workPath) + if err != nil { + log.Error("Unable to absolute %s against the current working directory %v. Will absolute against the AppPath %s", workPath, err, appPath) + workPath = filepath.Join(appPath, workPath) + } else { + workPath = absPath + } + } return strings.ReplaceAll(workPath, "\\", "/") } @@ -769,6 +781,10 @@ func loadFromConf(allowEmpty bool, extraConfig string) { StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(StaticRootPath) StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour) AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data")) + if !filepath.IsAbs(AppDataPath) { + log.Info("The provided APP_DATA_PATH: %s is not absolute - it will be made absolute against the work path: %s", AppDataPath, AppWorkPath) + AppDataPath = filepath.ToSlash(filepath.Join(AppWorkPath, AppDataPath)) + } EnableGzip = sec.Key("ENABLE_GZIP").MustBool() EnablePprof = sec.Key("ENABLE_PPROF").MustBool(false) diff --git a/modules/ssh/ssh.go b/modules/ssh/ssh.go index 44ed431c93..2affeb781a 100644 --- a/modules/ssh/ssh.go +++ b/modules/ssh/ssh.go @@ -102,6 +102,8 @@ func sessionHandler(session ssh.Session) { } defer stdin.Close() + process.SetSysProcAttribute(cmd) + wg := &sync.WaitGroup{} wg.Add(2) @@ -174,7 +176,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { // look for the exact principal principalLoop: for _, principal := range cert.ValidPrincipals { - pkey, err := asymkey_model.SearchPublicKeyByContentExact(principal) + pkey, err := asymkey_model.SearchPublicKeyByContentExact(ctx, principal) if err != nil { if asymkey_model.IsErrKeyNotExist(err) { log.Debug("Principal Rejected: %s Unknown Principal: %s", ctx.RemoteAddr(), principal) @@ -186,8 +188,9 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { c := &gossh.CertChecker{ IsUserAuthority: func(auth gossh.PublicKey) bool { + marshaled := auth.Marshal() for _, k := range setting.SSH.TrustedUserCAKeysParsed { - if bytes.Equal(auth.Marshal(), k.Marshal()) { + if bytes.Equal(marshaled, k.Marshal()) { return true } } @@ -234,7 +237,7 @@ func publicKeyHandler(ctx ssh.Context, key ssh.PublicKey) bool { log.Debug("Handle Public Key: %s Fingerprint: %s is not a certificate", ctx.RemoteAddr(), gossh.FingerprintSHA256(key)) } - pkey, err := asymkey_model.SearchPublicKeyByContent(strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))) + pkey, err := asymkey_model.SearchPublicKeyByContent(ctx, strings.TrimSpace(string(gossh.MarshalAuthorizedKey(key)))) if err != nil { if asymkey_model.IsErrKeyNotExist(err) { if log.IsWarn() { diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 682459d94a..ef7b70c09f 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -18,6 +18,7 @@ import ( "reflect" "regexp" "runtime" + "strconv" "strings" texttmpl "text/template" "time" @@ -52,7 +53,7 @@ var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}[\s]*$`) func NewFuncMap() []template.FuncMap { return []template.FuncMap{map[string]interface{}{ "GoVer": func() string { - return strings.Title(runtime.Version()) + return util.ToTitleCase(runtime.Version()) }, "UseHTTPS": func() bool { return strings.HasPrefix(setting.AppURL, "https") @@ -390,6 +391,66 @@ func NewFuncMap() []template.FuncMap { "Join": strings.Join, "QueryEscape": url.QueryEscape, "DotEscape": DotEscape, + "Iterate": func(arg interface{}) (items []uint64) { + count := uint64(0) + switch val := arg.(type) { + case uint64: + count = val + case *uint64: + count = *val + case int64: + if val < 0 { + val = 0 + } + count = uint64(val) + case *int64: + if *val < 0 { + *val = 0 + } + count = uint64(*val) + case int: + if val < 0 { + val = 0 + } + count = uint64(val) + case *int: + if *val < 0 { + *val = 0 + } + count = uint64(*val) + case uint: + count = uint64(val) + case *uint: + count = uint64(*val) + case int32: + if val < 0 { + val = 0 + } + count = uint64(val) + case *int32: + if *val < 0 { + *val = 0 + } + count = uint64(*val) + case uint32: + count = uint64(val) + case *uint32: + count = uint64(*val) + case string: + cnt, _ := strconv.ParseInt(val, 10, 64) + if cnt < 0 { + cnt = 0 + } + count = uint64(cnt) + } + if count <= 0 { + return items + } + for i := uint64(0); i < count; i++ { + items = append(items, i) + } + return items + }, }} } @@ -398,7 +459,7 @@ func NewFuncMap() []template.FuncMap { func NewTextFuncMap() []texttmpl.FuncMap { return []texttmpl.FuncMap{map[string]interface{}{ "GoVer": func() string { - return strings.Title(runtime.Version()) + return util.ToTitleCase(runtime.Version()) }, "AppName": func() string { return setting.AppName @@ -574,7 +635,7 @@ func Avatar(item interface{}, others ...interface{}) template.HTML { if src != "" { return AvatarHTML(src, size, class, t.DisplayName()) } - case *models.Collaborator: + case *repo_model.Collaborator: src := t.AvatarLinkWithSize(size * setting.Avatar.RenderedSizeFactor) if src != "" { return AvatarHTML(src, size, class, t.DisplayName()) diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index c745a106c5..a08439e93f 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -13,7 +13,7 @@ import ( "net/url" "testing" - "code.gitea.io/gitea/models" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -61,7 +61,7 @@ func LoadRepo(t *testing.T, ctx *context.Context, repoID int64) { ctx.Repo.Owner, err = user_model.GetUserByID(ctx.Repo.Repository.OwnerID) assert.NoError(t, err) ctx.Repo.RepoLink = ctx.Repo.Repository.Link() - ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx, ctx.Repo.Repository, ctx.Doer) + ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, ctx.Repo.Repository, ctx.Doer) assert.NoError(t, err) } diff --git a/modules/typesniffer/typesniffer.go b/modules/typesniffer/typesniffer.go index e4bed6595a..b6a6646d50 100644 --- a/modules/typesniffer/typesniffer.go +++ b/modules/typesniffer/typesniffer.go @@ -17,8 +17,12 @@ import ( // Use at most this many bytes to determine Content Type. const sniffLen = 1024 -// SvgMimeType MIME type of SVG images. -const SvgMimeType = "image/svg+xml" +const ( + // SvgMimeType MIME type of SVG images. + SvgMimeType = "image/svg+xml" + // ApplicationOctetStream MIME type of binary files. + ApplicationOctetStream = "application/octet-stream" +) var ( svgTagRegex = regexp.MustCompile(`(?si)\A\s*(?:(||>))\s*)*\/]`) diff --git a/modules/util/util.go b/modules/util/util.go index af6581f7cd..351a345473 100644 --- a/modules/util/util.go +++ b/modules/util/util.go @@ -11,6 +11,9 @@ import ( "math/big" "strconv" "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" ) // OptionalBool a boolean that can be "null" @@ -181,3 +184,10 @@ func ToUpperASCII(s string) string { } return string(b) } + +var titleCaser = cases.Title(language.English) + +// ToTitleCase returns s with all english words capitalized +func ToTitleCase(s string) string { + return titleCaser.String(s) +} diff --git a/modules/util/util_test.go b/modules/util/util_test.go index 0c2792a9cb..ca5bd87eae 100644 --- a/modules/util/util_test.go +++ b/modules/util/util_test.go @@ -220,3 +220,8 @@ func BenchmarkToUpper(b *testing.B) { }) } } + +func TestToTitleCase(t *testing.T) { + assert.Equal(t, ToTitleCase(`foo bar baz`), `Foo Bar Baz`) + assert.Equal(t, ToTitleCase(`FOO BAR BAZ`), `Foo Bar Baz`) +} diff --git a/modules/web/wrap_convert.go b/modules/web/wrap_convert.go index 8dc4e6d62b..b7bcbc6439 100644 --- a/modules/web/wrap_convert.go +++ b/modules/web/wrap_convert.go @@ -21,6 +21,9 @@ func convertHandler(handler interface{}) wrappedHandlerFunc { case http.HandlerFunc: return func(resp http.ResponseWriter, req *http.Request, others ...wrappedHandlerFunc) (done bool, deferrable func()) { routing.UpdateFuncInfo(req.Context(), funcInfo) + if _, ok := resp.(context.ResponseWriter); !ok { + resp = context.NewResponse(resp) + } t(resp, req) if r, ok := resp.(context.ResponseWriter); ok && r.Status() > 0 { done = true @@ -92,6 +95,9 @@ func convertHandler(handler interface{}) wrappedHandlerFunc { next = wrapInternal(others) } routing.UpdateFuncInfo(req.Context(), funcInfo) + if _, ok := resp.(context.ResponseWriter); !ok { + resp = context.NewResponse(resp) + } t(next).ServeHTTP(resp, req) if r, ok := resp.(context.ResponseWriter); ok && r.Status() > 0 { done = true diff --git a/options/gitignore/Umbraco b/options/gitignore/Umbraco index 86b91f300d..1dc3da526c 100644 --- a/options/gitignore/Umbraco +++ b/options/gitignore/Umbraco @@ -39,6 +39,9 @@ #ignore umbraco backoffice assest from wwwroot **/wwwroot/umbraco/ +# SQLite files +*.sqlite.db* + #ignore umbraco data/views/settings **/umbraco/ @@ -46,4 +49,4 @@ !**/umbraco/models #include default location for packages -!**/umbraco/Data/packages \ No newline at end of file +!**/umbraco/Data/packages diff --git a/options/license/Bitstream-Vera b/options/license/Bitstream-Vera new file mode 100644 index 0000000000..f353aa2d04 --- /dev/null +++ b/options/license/Bitstream-Vera @@ -0,0 +1,15 @@ +Copyright Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 098d47020e..ab59766d6c 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -833,7 +833,6 @@ default_branch=Výchozí větev default_branch_helper=Výchozí větev je základní větev pro požadavky na natažení a commity kódu. mirror_prune=Vyčistit mirror_prune_desc=Odstranit zastaralé reference na vzdálené sledování -mirror_interval=Interval zrcadlení (platné časové jednotky jsou „h“, „m“ a „s“). 0 zakáže automatickou synchronizaci. mirror_interval_invalid=Interval zrcadlení není platný. mirror_address=Klonovat z URL mirror_address_desc=Zadejte požadované přístupové údaje do sekce Ověření. @@ -902,7 +901,6 @@ need_auth=Ověření migrate_options=Možnosti migrace migrate_service=Migrační služba migrate_options_mirror_helper=Tento repozitář bude zrcadlem -migrate_options_mirror_disabled=Administrátor vašeho webu zakázal nová zrcadla. migrate_options_lfs=Migrovat LFS soubory migrate_options_lfs_endpoint.label=Koncový bod LFS migrate_options_lfs_endpoint.description=Migrace se pokusí použít váš vzdálený Git pro určení LFS serveru. Můžete také zadat vlastní koncový bod, pokud jsou data LFS repozitáře uložena někde jinde. @@ -2323,7 +2321,6 @@ total=Celkem: %d dashboard.statistic=Souhrn dashboard.operations=Operace údržby dashboard.system_status=Status systému -dashboard.statistic_info=Databáze Gitea obsahuje %d uživatelů, %d organizací, %d veřejných klíčů, %d repozitářů, %d hlídání, %d oblíbení, %d akcí, %d přístupů, %d úkolů, %d komentářů, %d účtů sociálních sítí, %d sledování, %d zrcadel, %d vydání, %d zdrojů ověřování, %d webových háčků, %d milníků, %d štítků, %d háčků, %d týmů, %d úkolů změn, %d příloh. dashboard.operation_name=Název operace dashboard.operation_switch=Přepnout dashboard.operation_run=Spustit diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 576117672d..d15b2104b8 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -286,7 +286,7 @@ sign_up_successful=Konto wurde erfolgreich erstellt. confirmation_mail_sent_prompt=Eine neue Bestätigungs-E-Mail wurde an %s gesendet. Bitte überprüfe dein Postfach innerhalb der nächsten %s, um die Registrierung abzuschließen. must_change_password=Aktualisiere dein Passwort allow_password_change=Verlange vom Benutzer das Passwort zu ändern (empfohlen) -reset_password_mail_sent_prompt=Eine Bestätigungs-E-Mail wurde an%s gesendet. Bitte überprüfe dein Postfach innerhalb von %s um den Wiederherstellungsprozess abzuschließen. +reset_password_mail_sent_prompt=Eine Bestätigungs-E-Mail wurde an %s gesendet. Bitte überprüfe dein Postfach innerhalb von %s, um den Wiederherstellungsprozess abzuschließen. active_your_account=Aktiviere dein Konto account_activated=Konto wurde aktiviert prohibit_login=Anmelden verboten @@ -845,7 +845,6 @@ default_branch=Standardbranch default_branch_helper=Der default Branch ist der Basisbranch für Pull-Requests und Commits. mirror_prune=Entfernen mirror_prune_desc=Entferne veraltete remote-tracking Referenzen -mirror_interval=Spiegel-Intervall (gültige Zeiteinheiten sind 'h', 'm', 's'). 0 schaltet die automatische Synchronisierung aus. mirror_interval_invalid=Das Spiegel-Intervall ist ungültig. mirror_address=Klonen via URL mirror_address_desc=Gib alle erforderlichen Anmeldedaten im Abschnitt "Authentifizierung" ein. @@ -916,7 +915,6 @@ need_auth=Authentifizierung migrate_options=Migrationsoptionen migrate_service=Migrationsdienst migrate_options_mirror_helper=Dieses Repository wird ein Mirror sein -migrate_options_mirror_disabled=Dein Administrator hat neue Mirrors deaktiviert. migrate_options_lfs=LFS-Dateien migrieren migrate_options_lfs_endpoint.label=LFS-Endpunkt migrate_options_lfs_endpoint.description=Migration wird versuchen, über den entfernten Git-Server den LFS-Server zu bestimmen. Du kannst auch einen eigenen Endpunkt angeben, wenn die LFS-Dateien woanders gespeichert werden. @@ -2360,7 +2358,6 @@ total=Gesamt: %d dashboard.statistic=Übersicht dashboard.operations=Wartungsoperationen dashboard.system_status=System-Status -dashboard.statistic_info=Giteas Datenbank hat %d Benutzer, %d Organisationen, %d öffentliche Schlüssel, %d Repositorys, %d Beobachtungen, %d Favoriten, %d Aktionen, %d Zugriffe, %d Issues, %d Kommentare, %d Konten sozialer Netzwerke, %d Gefolgte, %d Mirrors, %d Releases, %d Login-Quellen, %d Webhooks, %d Meilensteine, %d Label, %d Hook-Tasks, %d Teams, %d Aktualisierungs-Tasks, %d Anhänge. dashboard.operation_name=Name der Operation dashboard.operation_switch=Wechseln dashboard.operation_run=Ausführen diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index f802f50cfa..7459576914 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -93,7 +93,7 @@ copy_branch=Αντιγραφή ονόματος κλάδου copy_success=Αντιγράφηκε! copy_error=Η αντιγραφή απέτυχε -write=Εγγραφή +write=Σύνταξη preview=Προεπισκόπηση loading=Φόρτωση… @@ -105,6 +105,7 @@ error404=Η σελίδα που προσπαθείτε να φτάσετε εί never=Ποτέ +rss_feed=Ροή RSS [error] occurred=Παρουσιάστηκε ένα σφάλμα @@ -283,6 +284,7 @@ register_helper_msg=Έχετε ήδη λογαριασμό? Συνδεθείτε social_register_helper_msg=Έχετε ήδη λογαριασμό? Συνδέστε το τώρα! disable_register_prompt=Η εγγραφή είναι απενεργοποιημένη. Παρακαλούμε επικοινωνήστε με το διαχειριστή του ιστοτόπου. disable_register_mail=Η Επιβεβαίωση email για την εγγραφή είναι απενεργοποιημένη. +manual_activation_only=Επικοινωνήστε με το διαχειριστή της υπηρεσίας για να ολοκληρώσετε την ενεργοποίηση. remember_me=Απομνημόνευση αυτής της συσκευής forgot_password_title=Ξέχασα Τον Κωδικό Πρόσβασης forgot_password=Ξεχάσατε τον κωδικό πρόσβασης; @@ -488,7 +490,9 @@ auth_failed=Αποτυχία ταυτοποίησης: %v still_own_repo=Ο λογαριασμός σας διαθέτει ένα ή περισσότερα αποθετήρια, διαγράψτε ή μεταφέρετε τα πρώτα. still_has_org=Ο λογαριασμός σας είναι μέλος ενός ή περισσοτέρων οργανισμών, αποχωρήστε απο αυτούς πρώτα. +still_own_packages=Ο λογαριασμός σας κατέχει ένα ή περισσότερα πακέτα, διαγράψτε τα πρώτα. org_still_own_repo=Αυτός ο οργανισμός εξακολουθεί να κατέχει έναν ή περισσότερα αποθετήρια, διαγράψτε ή μεταφέρετε τα πρώτα. +org_still_own_packages=Αυτός ο οργανισμός εξακολουθεί να κατέχει ένα ή περισσότερα πακέτα, διαγράψτε τα πρώτα. target_branch_not_exist=Ο κλάδος προορισμού δεν υπάρχει. @@ -501,7 +505,7 @@ followers=Ακόλουθοι starred=Αγαπημένα Αποθετήρια watched=Ακολουθούμενα Αποθετήρια projects=Έργα -following=Ακολουθούν +following=Ακολουθεί follow=Ακολουθήστε unfollow=Να μην ακολουθώ heatmap.loading=Φόρτωση heatmap… @@ -551,6 +555,7 @@ continue=Συνέχεια cancel=Ακύρωση language=Γλώσσα ui=Θέμα Διεπαφής +hidden_comment_types=Κρυμμένοι τύποι σχολίων comment_type_group_reference=Αναφορά comment_type_group_label=Σήμα comment_type_group_milestone=Ορόσημο @@ -560,7 +565,9 @@ comment_type_group_branch=Κλάδος comment_type_group_time_tracking=Καταγραφή Χρόνου comment_type_group_deadline=Προθεσμία comment_type_group_dependency=Εξάρτηση +comment_type_group_lock=Κατάσταση Κλειδώματος comment_type_group_review_request=Αίτηση αξιολόγησης +comment_type_group_pull_request_push=Προστέθηκαν υποβολές comment_type_group_project=Έργο comment_type_group_issue_ref=Αναφορά ζητήματος saved_successfully=Οι ρυθμίσεις σας αποθηκεύτηκαν επιτυχώς. @@ -582,7 +589,7 @@ update_user_avatar_success=Το avatar του χρήστη ενημερώθηκ change_password=Ενημέρωση Κωδικού Πρόσβασης old_password=Τρέχων Κωδικός Πρόσβασης new_password=Νέος Κωδικός Πρόσβασης -retype_new_password=Επανεισάγετε Νέο Κωδικό Πρόσβασης +retype_new_password=Επανεισάγετε το Νέο Κωδικό Πρόσβασης password_incorrect=Ο τρέχων κωδικός πρόσβασης είναι λάθος. change_password_success=Ο κωδικός πρόσβασής σας έχει ενημερωθεί. Από εδώ και τώρα συνδέεστε χρησιμοποιώντας τον νέο κωδικό πρόσβασής σας. password_change_disabled=Οι μη τοπικοί χρήστες δεν μπορούν να ενημερώσουν τον κωδικό πρόσβασής τους μέσω του διεπαφής web του Gitea. @@ -591,7 +598,7 @@ emails=Διευθύνσεις Email manage_emails=Διαχείριση Διευθύνσεων Email manage_themes=Επιλέξτε προεπιλεγμένο θέμα διεπαφής manage_openid=Διαχείριση Διευθύνσεων OpenID -email_desc=Η κύρια διεύθυνση email σας θα χρησιμοποιηθεί για ειδοποιήσεις και άλλες λειτουργίες. +email_desc=Η κύριο email σας θα χρησιμοποιηθεί για ειδοποιήσεις και άλλες λειτουργίες. theme_desc=Αυτό θα είναι το προεπιλεγμένο θέμα διεπαφής σας σε όλη την ιστοσελίδα. primary=Κύριο activated=Ενεργό @@ -771,6 +778,7 @@ webauthn_delete_key_desc=Αν αφαιρέσετε ένα κλειδί ασφα manage_account_links=Διαχείριση Συνδεδεμένων Λογαριασμών manage_account_links_desc=Αυτοί οι εξωτερικοί λογαριασμοί είναι συνδεδεμένοι στον Gitea λογαριασμό σας. account_links_not_available=Προς το παρόν δεν υπάρχουν εξωτερικοί λογαριασμοί συνδεδεμένοι με τον λογαριασμό σας στο Gitea. +link_account=Σύνδεση Λογαριασμού remove_account_link=Αφαίρεση Συνδεδεμένου Λογαριασμού remove_account_link_desc=Η κατάργηση ενός συνδεδεμένου λογαριασμού θα ανακαλέσει την πρόσβασή του στο λογαριασμό σας στο Gitea. Συνέχεια; remove_account_link_success=Ο συνδεδεμένος λογαριασμός έχει αφαιρεθεί. @@ -807,7 +815,7 @@ repo_name_helper=Τα καλά ονόματα αποθετηρίων χρησι repo_size=Μέγεθος Αποθετηρίου template=Πρότυπο template_select=Επιλέξτε πρότυπο. -template_helper=Κάντε το αποθετήριο πρότυπο +template_helper=Μετατροπή σε πρότυπο αποθετήριο template_description=Τα πρότυπα αποθετήρια επιτρέπουν στους χρήστες να δημιουργήσουν νέα αποθετήρια με την ίδια δομή, αρχεία και προαιρετικές ρυθμίσεις. visibility=Ορατότητα visibility_description=Μόνο ο ιδιοκτήτης ή τα μέλη του οργανισμού εάν έχουν δικαιώματα, θα είναι σε θέση να το δουν. @@ -851,7 +859,6 @@ default_branch=Προεπιλεγμένος Κλάδος default_branch_helper=Ο προεπιλεγμένος κλάδος είναι ο βασικός κλάδος για pull requests και υποβολές κώδικα. mirror_prune=Καθαρισμός mirror_prune_desc=Αφαίρεση παρωχημένων αναφορών απομακρυσμένης-παρακολούθησης -mirror_interval=Διάστημα ανανέωσης ειδώλου (έγκυρες μονάδες ώρας είναι 'h', 'm', 's'). 0 για να απενεργοποιήσετε τον αυτόματο συγχρονισμό. mirror_interval_invalid=Το χρονικό διάστημα του ειδώλου δεν είναι έγκυρο. mirror_address=Κλωνοποίηση Από Το URL mirror_address_desc=Τοποθετήστε όλα τα απαιτούμενα διαπιστευτήρια στην ενότητα Εξουσιοδότηση. @@ -922,7 +929,6 @@ need_auth=Εξουσιοδότηση migrate_options=Επιλογές Μεταφοράς migrate_service=Υπηρεσία Μεταφοράς migrate_options_mirror_helper=Αυτό το αποθετήριο θα είναι ένα είδωλο -migrate_options_mirror_disabled=Ο διαχειριστής έχει απενεργοποιήσει τα νέα είδωλα. migrate_options_lfs=Μεταφορά αρχείων LFS migrate_options_lfs_endpoint.label=LFS Endpoint migrate_options_lfs_endpoint.description=Η μεταφορά θα προσπαθήσει να χρησιμοποιήσει το Git remote για να καθορίσει τον διακομιστή LFS. Μπορείτε επίσης να καθορίσετε ένα δικό σας endpoint αν τα δεδομένα LFS του αποθετηρίου αποθηκεύονται κάπου αλλού. @@ -997,13 +1003,14 @@ code.desc=Πρόσβαση στον πηγαίο κώδικα, αρχεία, υ branch=Κλάδος tree=Δέντρο clear_ref=`Καθαρισμός τρέχουσας αναφοράς` -filter_branch_and_tag=Φιλτράρισμα κλάδου ή ετικέτας +filter_branch_and_tag=Φίλτρο κλάδου ή ετικέτας find_tag=Εύρεση ετικέτας branches=Κλάδοι tags=Ετικέτες issues=Ζητήματα pulls=Pull Requests project_board=Έργα +packages=Πακέτα labels=Σήματα org_labels_desc=Τα σήματα στο επίπεδο οργανισμού, που μπορούν να χρησιμοποιηθούν με όλα τα αποθετήρια κάτω από αυτόν τον οργανισμό org_labels_desc_manage=διαχείριση @@ -1034,6 +1041,7 @@ line_unicode=`Αυτή η γραμμή έχει κρυφούς χαρακτήρ escape_control_characters=Escape unescape_control_characters=Unescape file_copy_permalink=Αντιγραφή Permalink +view_git_blame=Προβολή Git Blame video_not_supported_in_browser=Το πρόγραμμα περιήγησής σας δεν υποστηρίζει την ετικέτα HTML5 'video'. audio_not_supported_in_browser=Το πρόγραμμα περιήγησής σας δεν υποστηρίζει την ετικέτα HTML5 'audio'. stored_lfs=Αποθηκεύτηκε με το Git LFS @@ -1072,6 +1080,10 @@ editor.add_tmpl=Προσθήκη '' editor.add=Προσθήκη '%s' editor.update=Ενημέρωση '%s' editor.delete=Διαγραφή του '%s' +editor.patch=Εφαρμογή Διόρθωσης +editor.patching=Επιδιόρθωση: +editor.fail_to_apply_patch=Δεν είναι δυνατή η εφαρμογή της διόρθωσης '%s' +editor.new_patch=Νέα Διόρθωση editor.commit_message_desc=Προσθήκη προαιρετικής εκτενούς περιγραφής… editor.signoff_desc=Προσθέστε ένα πρόσθετο Signed-off-by στο τέλος του μηνύματος καταγραφής της υποβολής. editor.commit_directly_to_this_branch=Υποβολή απευθείας στο κλάδο %s. @@ -1107,6 +1119,8 @@ editor.cannot_commit_to_protected_branch=Αδυναμία υποβολής στ editor.no_commit_to_branch=Δεν είναι δυνατή η απευθείας υποβολή στο κλάδο επειδή: editor.user_no_push_to_branch=Ο χρήστης δεν μπορεί να κάνει push στο κλάδο editor.require_signed_commit=Ο κλάδος απαιτεί υπογεγραμμένη υποβολή +editor.cherry_pick=Ανθολόγηση (cherry-pic) του %s στο: +editor.revert=Απόσυρση του %s στο: commits.desc=Δείτε το ιστορικό αλλαγών του πηγαίου κώδικα. commits.commits=Υποβολές @@ -1127,6 +1141,13 @@ commits.signed_by_untrusted_user_unmatched=Υπογράφηκε από ένα μ commits.gpg_key_id=ID Κλειδιού GPG commits.ssh_key_fingerprint=Αποτύπωμα Κλειδιού SSH +commit.actions=Δράσεις +commit.revert=Απόσυρση +commit.revert-header=Απόσυρση: %s +commit.revert-content=Επιλέξτε κλάδο για απόσυρση σε αυτό: +commit.cherry-pick=Cherry-pick +commit.cherry-pick-header=Ανθολόγηση: %s +commit.cherry-pick-content=Επιλέξτε κλάδο για να κάνετε ανθολόγηση σε αυτό: ext_issues=Πρόσβαση στα Εξωτερικά Ζητήματα ext_issues.desc=Σύνδεση σε εξωτερικό εφαρμογή ζητημάτων. @@ -1165,6 +1186,7 @@ projects.board.deletion_desc=Η διαγραφή ενός πίνακα έργο projects.board.color=Χρώμα projects.open=Άνοιγμα projects.close=Κλείσιμο +projects.board.assigned_to=Ανατέθηκε σε issues.desc=Οργανώστε αναφορές σφαλμάτων, εργασίες και ορόσημα. issues.filter_assignees=Φίλτρο Αποδέκτη @@ -1176,12 +1198,12 @@ issues.new=Νέο Ζήτημα issues.new.title_empty=Ο τίτλος δεν μπορεί να είναι κενός issues.new.labels=Σήματα issues.new.add_labels_title=Εφαρμογή σημάτων -issues.new.no_label=Κανένα Σήμα +issues.new.no_label=Χωρίς Σήμα issues.new.clear_labels=Καθαρισμός σημάτων issues.new.projects=Έργα issues.new.add_project_title=Ορισμός Έργου issues.new.clear_projects=Εκκαθάριση έργων -issues.new.no_projects=Κανένα έργο +issues.new.no_projects=Χωρίς έργα issues.new.open_projects=Ανοιχτά Έργα issues.new.closed_projects=Κλειστά Έργα issues.new.no_items=Δεν υπάρχουν αντικείμενα @@ -1194,7 +1216,7 @@ issues.new.closed_milestone=Κλειστά Ορόσημα issues.new.assignees=Αποδέκτες issues.new.add_assignees_title=Ανάθεση χρηστών issues.new.clear_assignees=Εκκαθάριση αποδεκτών -issues.new.no_assignees=Κανένας Αποδέκτης +issues.new.no_assignees=Χωρίς Αποδέκτη issues.new.no_reviewers=Δεν υπάρχουν εξεταστές issues.new.add_reviewer_title=Αίτηση επανεξέτασης issues.choose.get_started=Ας Αρχίσουμε @@ -1211,11 +1233,11 @@ issues.label_templates.info=Δεν υπάρχουν σήματα ακόμα. Δ issues.label_templates.helper=Επιλέξτε ένα σύνολο σημάτων issues.label_templates.use=Χρήση Συνόλου Σημάτων issues.label_templates.fail_to_load_file=Αποτυχία φόρτωσης αρχείου προτύπου σημάτων '%s': %v -issues.add_label=προστέθηκε η %s ετικέτα %s -issues.add_labels=πρόσθεσε τα %s σήματα %s +issues.add_label=πρόσθεσε τη σήμανση %s %s +issues.add_labels=πρόσθεσε τα σήματα %s %s issues.remove_label=αφαίρεσε το σήμα %s %s issues.remove_labels=αφαίρεσε τα %s σήματα %s -issues.add_remove_labels=πρόσθεσε %s και αφαίρεσε %s σήματα %s +issues.add_remove_labels=πρόσθεσε τα %s και αφαίρεσε τα %s σήματα %s issues.add_milestone_at=`το πρόσθεσε στο %s ορόσημο %s` issues.add_project_at=`το πρόσθεσε στο έργο %s %s` issues.change_milestone_at=`τροποποίησε το ορόσημο από %s σε %s %s` @@ -1269,7 +1291,7 @@ issues.action_milestone=Ορόσημο issues.action_milestone_no_select=Χωρίς ορόσημο issues.action_assignee=Αποδέκτης issues.action_assignee_no_select=Κανένας Αποδέκτης -issues.opened_by=άνοιξαν %[1]s από %[3]s +issues.opened_by=ανοίχτηκε %[1]s από %[3]s pulls.merged_by=από %[3]s συγχωνεύθηκε %[1]s pulls.merged_by_fake=από %[2]s συγχωνεύθηκε %[1]s issues.closed_by=από %[3]s έκλεισαν %[1]s @@ -1294,7 +1316,7 @@ issues.manually_pull_merged_at=`συγχώνευσε την υποβολή %[2]s` issues.reopened_at=`ξανά άνοιξε αυτό το ζήτημα %[2]s` issues.commit_ref_at=`αναφορά σε αυτό το ζήτημα από την παραπομπή %[2]s` @@ -1357,6 +1379,9 @@ issues.lock.reason=Λόγος κλειδώματος issues.lock.title=Κλείδωμα συνομιλίας σε αυτό το ζήτημα. issues.unlock.title=Ξεκλείδωμα συνομιλίας σε αυτό το ζήτημα. issues.comment_on_locked=Δεν μπορείτε να σχολιάσετε ένα κλειδωμένο ζήτημα. +issues.delete=Διαγραφή +issues.delete.title=Διαγραφή αυτού του ζητήματος; +issues.delete.text=Θέλετε πραγματικά να διαγράψετε αυτό το ζήτημα; (Αυτό θα καταργήσει οριστικά όλο το περιεχόμενο. Επιλέξτε το κλείσιμο, αν σκοπεύετε να το αρχειοθετήσετε) issues.tracker=Καταγραφή Χρόνου issues.start_tracking_short=Εκκίνηση Χρονομέτρου issues.start_tracking=Εκκίνηση Καταγραφής Χρόνου @@ -1397,6 +1422,8 @@ issues.due_date_remove=αφαίρεσε την ημερομηνία παράδο issues.due_date_overdue=Εκπρόθεσμο issues.due_date_invalid=Η ημερομηνία παράδοσης δεν είναι έγκυρη ή εκτός εύρους. Παρακαλούμε χρησιμοποιήστε τη μορφή 'εεεε-μμ-ηη'. issues.dependency.title=Εξαρτήσεις +issues.dependency.issue_no_dependencies=Δεν έχουν οριστεί εξαρτήσεις. +issues.dependency.pr_no_dependencies=Δεν έχουν οριστεί εξαρτήσεις. issues.dependency.add=Προσθήκη εξάρτησης… issues.dependency.cancel=Ακύρωση issues.dependency.remove=Διαγραφή @@ -1435,6 +1462,7 @@ issues.review.add_review_request=ζητήθηκε αναθεώρηση από %s issues.review.remove_review_request=αφαιρέθηκε αίτηση αναθεώρησης για %s %s issues.review.remove_review_request_self=αρνήθηκε να αναθεωρήσει %s issues.review.pending=Εκκρεμεί +issues.review.pending.tooltip=Αυτό το σχόλιο δεν είναι προς το παρόν ορατό σε άλλους χρήστες. Για να υποβάλετε τα σχόλιά σας, επιλέξτε '%s' -> '%s/%s/%s' στο πάνω μέρος της σελίδας. issues.review.review=Αξιολόγηση issues.review.reviewers=Εξεταστές issues.review.outdated=Παρωχημένο @@ -1453,6 +1481,7 @@ issues.content_history.created=δημιουργήθηκε issues.content_history.delete_from_history=Διαγραφή από το ιστορικό issues.content_history.delete_from_history_confirm=Διαγραφή από το ιστορικό; issues.content_history.options=Επιλογές +issues.reference_link=Αναφορά: %s compare.compare_base=βάση compare.compare_head=σύγκριση @@ -1461,7 +1490,13 @@ pulls.desc=Ενεργοποίηση των pull requests και της αξιο pulls.new=Νέο Pull Request pulls.view=Προβολή Pull Request pulls.compare_changes=Νέο Pull Request +pulls.allow_edits_from_maintainers=Επιτρέπεται η επεξεργασία από συντηρητές +pulls.allow_edits_from_maintainers_desc=Οι χρήστες με πρόσβαση εγγραφής στον βασικό κλάδο μπορούν επίσης να ωθήσουν και σε αυτό τον κλάδο +pulls.allow_edits_from_maintainers_err=Η ενημέρωση απέτυχε pulls.compare_changes_desc=Επιλέξτε τον κλάδο που θα συγχωνευθεί και τον κλάδο από τον οποίο θα τραβηχτεί. +pulls.has_viewed_file=Είδαν +pulls.has_changed_since_last_review=Άλλαξε από τη τελευταία κριτική +pulls.viewed_files_label=%[1]d / %[2]d αρχεία εμφανίστηκαν pulls.compare_base=συγχώνευση σε pulls.compare_compare=τράβηγμα από pulls.switch_comparison_type=Αλλαγή τύπου σύγκρισης @@ -1472,7 +1507,7 @@ pulls.nothing_to_compare=Αυτοί οι κλάδοι είναι όμοιοι. pulls.nothing_to_compare_and_allow_empty_pr=Αυτοί οι κλάδοι είναι ίσοι. Αυτό το PR θα είναι κενό. pulls.has_pull_request=`Υπάρχει ήδη pull request μεταξύ αυτών των κλάδων: %[2]s#%[3]d` pulls.create=Δημιουργία Pull Request -pulls.title_desc=θέλει να συγχωνεύσει %[1] υποβολές από %[2]s σε %[3]s +pulls.title_desc=θέλει να συγχωνεύσει %[1]d υποβολές από %[2]s σε %[3]s pulls.merged_title_desc=συγχώνευσε %[1]d υποβολές από %[2]s σε %[3]s %[4]s pulls.change_target_branch_at=`άλλαξε τον κλάδο στόχο από %s σε %s %s` pulls.tab_conversation=Συζήτηση @@ -1492,8 +1527,8 @@ pulls.still_in_progress=Ακόμα είναι σε εξέλιξη; pulls.add_prefix=Προσθήκη %s προθέματος pulls.remove_prefix=Αφαίρεση %s προθέματος pulls.data_broken=Αυτό το pull request είναι κατεστραμμένο λόγω των πληροφοριών του fork που λείπουν. -pulls.files_conflicted=Αυτό το pull request έχει αλλαγές που έρχονται σε σύγκρουση με το κλάδο που στοχεύει. -pulls.is_checking=Η συγχώνευση ελέγχου σύγκρουσης είναι σε εξέλιξη. Δοκιμάστε ξανά σε λίγα λεπτά. +pulls.files_conflicted=Αυτό το pull request περιέχει αλλαγές που συγκρούονται με το κλάδο προορισμού. +pulls.is_checking=Ο έλεγχος συγκρούσεων κατά την συγχώνευση είναι σε εξέλιξη. Δοκιμάστε ξανά σε λίγα λεπτά. pulls.is_empty=Αυτός ο κλάδος είναι ίσος με τον κλάδο-στόχο. pulls.required_status_check_failed=Ορισμένοι απαιτούμενοι έλεγχοι δεν ήταν επιτυχείς. pulls.required_status_check_missing=Λείπουν ορισμένοι απαιτούμενοι έλεγχοι. @@ -1506,9 +1541,9 @@ pulls.blocked_by_changed_protected_files_1=Αυτό το Pull Request έχει pulls.blocked_by_changed_protected_files_n=Αυτό το Pull Request έχει αποκλειστεί επειδή αλλάζει προστατευμένα αρχεία: pulls.can_auto_merge_desc=Αυτό το Pull Request μπορεί να συγχωνευθεί αυτόματα. pulls.cannot_auto_merge_desc=Αυτό το pull request δεν μπορεί να συγχωνευθεί αυτόματα λόγω συγκρούσεων. -pulls.cannot_auto_merge_helper=Συγχώνευση χειροκίνητα για την επίλυση των συγκρούσεων. -pulls.num_conflicting_files_1=%d αλληλοσυγκρουόμενο αρχείο -pulls.num_conflicting_files_n=%d αλληλοσυγκρουόμενα αρχεία +pulls.cannot_auto_merge_helper=Χειροκίνητη Συγχώνευση για την επίλυση των συγκρούσεων. +pulls.num_conflicting_files_1=%d αρχείο σε σύγκρουση +pulls.num_conflicting_files_n=%d αρχεία σε σύγκρουση pulls.approve_count_1=%d έγκριση pulls.approve_count_n=%d εγκρίσεις pulls.reject_count_1=%d αίτημα αλλαγής @@ -1523,16 +1558,24 @@ pulls.no_merge_wip=Αυτό το pull request δεν μπορεί να συγχ pulls.no_merge_not_ready=Αυτό το pull request δεν είναι έτοιμο για συγχώνευση, ελέγξτε την κατάσταση εξέτασης και τους ελέγχους κατάστασης. pulls.no_merge_access=Δεν είστε εξουσιοδοτημένοι να συγχωνεύσετε αυτό το pull request. pulls.merge_pull_request=Δημιουργία υποβολής συγχώνευσης -pulls.rebase_merge_pull_request=Rebase και μετά γρήγορα-μπροστά -pulls.rebase_merge_commit_pull_request=Rebase, και στη συνέχεια, δημιουργία υποβολής συγχώνευσης +pulls.rebase_merge_pull_request=Αλλαγή βάσης και μετά γρήγορα-μπροστά +pulls.rebase_merge_commit_pull_request=Αλλαγής βάσης και δημιουργία υποβολής συγχώνευσης pulls.squash_merge_pull_request=Δημιουργία υποβολής squash pulls.merge_manually=Συγχωνεύτηκαν χειροκίνητα pulls.merge_commit_id=Το ID της υποβολής συγχώνευσης pulls.require_signed_wont_sign=Ο κλάδος απαιτεί υπογεγραμμένες υποβολές αλλά αυτή η συγχώνευση δεν θα υπογραφεί +pulls.merge_pull_request_now=Συγχώνευση του Pull Request Τώρα +pulls.rebase_merge_pull_request_now=Αλλαγή Βάσης και Συγχώνευση Τώρα +pulls.rebase_merge_commit_pull_request_now=Αλλαγή Βάσης και Συγχώνευση Τώρα (--no-ff) +pulls.squash_merge_pull_request_now=Στρίμωγμα και Συγχώνευση τώρα +pulls.merge_pull_request_on_status_success=Συγχώνευση Του Pull Request Όταν Όλοι Οι Έλεγχοι Επιτύχουν +pulls.rebase_merge_pull_request_on_status_success=Αλλαγή Βάσης και Συγχώνευση Όταν Όλοι Οι Έλεγχοι Πετύχουν +pulls.rebase_merge_commit_pull_request_on_status_success=Αλλαγή Βάσης και Συγχώνευση (--no-ff) Όταν Όλοι Οι Έλεγχοι Πετύχουν +pulls.squash_merge_pull_request_on_status_success=Στρίμωγμα και Συγχώνευση Όταν Όλοι Οι Έλεγχοι Επιτύχουν pulls.invalid_merge_option=Δεν μπορείτε να χρησιμοποιήσετε αυτήν την επιλογή συγχώνευσης για αυτό το pull request. pulls.merge_conflict=Η Συγχώνευση Απέτυχε: Υπήρξε μια διένεξη κατά τη συγχώνευση. Υπόδειξη: Δοκιμάστε μια διαφορετική στρατηγική pulls.merge_conflict_summary=Μήνυμα Σφάλματος -pulls.rebase_conflict=Η Συγχώνευση Απέτυχε: Υπήρξε μια διένεξη κατά το rebase της υποβολής: %[1]s. Υπόδειξη: Δοκιμάστε μια διαφορετική στρατηγική +pulls.rebase_conflict=Η Συγχώνευση Απέτυχε: Υπήρξε μια σύγκρουση κατά την αλλαγή βάσης της υποβολής: %[1]s. Υπόδειξη: Δοκιμάστε μια διαφορετική στρατηγική pulls.rebase_conflict_summary=Μήνυμα Σφάλματος ; %[2]s
%[3]s
pulls.unrelated_histories=H Συγχώνευση Απέτυχε: Η κεφαλή και η βάση της συγχώνευσης δεν μοιράζονται μια κοινή ιστορία. Συμβουλή: Δοκιμάστε μια διαφορετική στρατηγική @@ -1559,6 +1602,14 @@ pulls.reopened_at=`άνοιξε ξανά αυτό το pull request τις οδηγίες της γραμμής εντολών.` pulls.merge_instruction_step1_desc=Από το αποθετήριο του έργου σας, ελέγξτε έναν νέο κλάδο και τεστάρετε τις αλλαγές. pulls.merge_instruction_step2_desc=Συγχώνευσε τις αλλαγές και ενημέρωσε στο Gitea. +pulls.merge_on_status_success=Το pull request προγραμματίστηκε για συγχώνευση όταν πετύχουν όλοι οι έλεγχοι. +pulls.merge_on_status_success_already_scheduled=Αυτό το αίτημα έλξης έχει ήδη προγραμματιστεί για συγχώνευση όταν πετύχουν όλοι οι έλεγχοι. +pulls.pr_has_pending_merge_on_success=%[1]s έχει προγραμματίσει αυτό το pull request για αυτόματη συγχώνευση όταν όλοι οι έλεγχοι επιτύχουν %[2]s. +pulls.merge_pull_on_success_cancel=Ακύρωση αυτόματης συγχώνευσης +pulls.pull_request_not_scheduled=Αυτό το pull request δεν είναι προγραμματισμένο να συγχωνευτεί αυτόματα. +pulls.pull_request_schedule_canceled=Η αυτόματη συγχώνευση ακυρώθηκε για αυτό το pull request. +pulls.pull_request_scheduled_auto_merge=`έχει προγραμματισεί αυτό το pull request για αυτόματη συγχώνευση όταν όλοι οι έλεγχοι πετύχουν %[1]s` +pulls.pull_request_canceled_scheduled_auto_merge=`ακύρωσε την αυτόματη συγχώνευση αυτού του pull request όταν όλοι οι έλεγχοι πετύχουν %[1]s` milestones.new=Νέο Ορόσημο milestones.open_tab=%d Ανοιχτά @@ -1678,16 +1729,16 @@ activity.title.releases_n=%d Εκδόσεις activity.title.releases_published_by=%s δημοσιεύτηκε από %s activity.published_release_label=Δημοσιεύθηκε activity.no_git_activity=Δεν έχει υπάρξει καμία δραστηριότητα υποβολών σε αυτήν την περίοδο. -activity.git_stats_exclude_merges=Εξαιρούνται οι συγχωνεύσεις, +activity.git_stats_exclude_merges=Εκτός τις συγχωνεύσεις, activity.git_stats_author_1=%d συγγραφέας activity.git_stats_author_n=%d συγγραφείς activity.git_stats_pushed_1=έχει ωθήσει activity.git_stats_pushed_n=έχουν ωθήσει activity.git_stats_commit_1=%d υποβολή activity.git_stats_commit_n=%d υποβολές -activity.git_stats_push_to_branch=σε %s και +activity.git_stats_push_to_branch=στο %s και activity.git_stats_push_to_all_branches=σε όλους τους κλάδους. -activity.git_stats_on_default_branch=Στις %s, +activity.git_stats_on_default_branch=Στο %s, activity.git_stats_file_1=%d αρχείο activity.git_stats_file_n=%d αρχεία activity.git_stats_files_changed_1=έχει αλλάξει @@ -1720,7 +1771,7 @@ settings.hooks=Webhooks settings.githooks=Git Hooks settings.basic_settings=Βασικές Ρυθμίσεις settings.mirror_settings=Ρυθμίσεις Ειδώλου -settings.mirror_settings.docs=Ρυθμίστε το έργο σας για να κάνει push ή / και pull αλλαγές σε/από άλλο αποθετήριο. Οι κλάδοι, οι ετικέτες και οι υποβολές θα συγχρονιστούν αυτόματα. Πώς μπορώ να καθρεπτίσω τα αποθετήρια; +settings.mirror_settings.docs=Ρυθμίστε το έργο σας για να ωθεί ή/και να τραβά αλλαγές σε/από άλλο αποθετήριο. Οι κλάδοι, οι ετικέτες και οι υποβολές θα συγχρονίζονται αυτόματα. Πώς μπορώ να καθρεπτίσω τα αποθετήρια; settings.mirror_settings.mirrored_repository=Είδωλο αποθετηρίου settings.mirror_settings.direction=Κατεύθυνση settings.mirror_settings.direction.pull=Pull @@ -1739,7 +1790,7 @@ settings.site=Ιστοσελίδα settings.update_settings=Ενημέρωση Ρυθμίσεων settings.branches.update_default_branch=Ενημέρωση Προεπιλεγμένου Κλάδου settings.advanced_settings=Ρυθμίσεις Για Προχωρημένους -settings.wiki_desc=Ενεργοποίηση Wiki Αποθετηρίου +settings.wiki_desc=Ενεργοποίηση Wiki settings.use_internal_wiki=Χρήση Εσωτερικού Wiki settings.use_external_wiki=Χρήση Εξωτερικού Wiki settings.external_wiki_url=URL Εξωτερικού Wiki @@ -1753,7 +1804,7 @@ settings.external_tracker_url_error=Το URL της εξωτερικής υπη settings.external_tracker_url_desc=Οι επισκέπτες ανακατευθύνονται στο URL εξωτερικής υπηρεσίας ζητημάτων όταν κάνετε κλικ στην καρτέλα ζητήματα. settings.tracker_url_format=Μορφή URL Εξωτερικής Υπηρεσίας Ζητημάτων settings.tracker_url_format_error=Η μορφή URL της εξωτερικής υπηρεσίας ζητήματων δεν είναι έγκυρη διεύθυνση URL. -settings.tracker_issue_style=Μορφή Αριθμών Εξωτερικής Υπηρεσίας Ζητημάτων +settings.tracker_issue_style=Αρίθμηση Εξωτερικής Υπηρεσίας Ζητημάτων settings.tracker_issue_style.numeric=Αριθμητικό settings.tracker_issue_style.alphanumeric=Αλφαριθμητικό settings.tracker_url_format_desc=Χρησιμοποιήστε τα {user}, {repo} και {index} για το όνομα χρήστη, το όνομα αποθετηρίου και το ευρετήριο ζητημάτων. @@ -1762,12 +1813,14 @@ settings.allow_only_contributors_to_track_time=Μόνο οι Συμμετέχο settings.pulls_desc=Ενεργοποίηση Pull Requests στο Αποθετήριο settings.pulls.ignore_whitespace=Αγνόηση των Κενών Χαρακτήρων στις Συγκρούσεις settings.pulls.allow_merge_commits=Ενεργοποίηση Υποβολών Συγχώνευσης -settings.pulls.allow_rebase_merge=Ενεργοποίηση Rebasing για Υποβολές Συγχώνευσης -settings.pulls.allow_rebase_merge_commit=Ενεργοποίηση Rebasing με ρητές υποβολές συγχώνευσης (--no-ff) +settings.pulls.allow_rebase_merge=Ενεργοποίηση Αλλαγής Βάσης για τις Υποβολές Συγχώνευσης +settings.pulls.allow_rebase_merge_commit=Ενεργοποίηση Αλλαγής Βάσης με ρητές υποβολές συγχώνευσης (--no-ff) settings.pulls.allow_squash_commits=Ενεργοποίηση Squashing για Υποβολές Συγχώνευσης settings.pulls.allow_manual_merge=Ενεργοποίηση Σημείωσης του PR ως μη αυτόματα συγχωνευμένο settings.pulls.enable_autodetect_manual_merge=Ενεργοποίηση αυτόματης ανίχνευσης συγχώνευσης (Σημείωση: σε ορισμένες ειδικές περιπτώσεις, μπορεί να προκύψουν εσφαλμένες κρίσεις) +settings.pulls.allow_rebase_update=Ενεργοποίηση της ενημέρωσης του κλάδου του pull request μέσω rebase settings.pulls.default_delete_branch_after_merge=Διαγραφή του κλάδου του pull request μετά τη συγχώνευση από προεπιλογή +settings.packages_desc=Ενεργοποίηση Μητρώου Πακέτων Αποθετηρίου settings.projects_desc=Ενεργοποίηση Έργων Αποθετηρίου settings.admin_settings=Ρυθμίσεις Διαχειριστή settings.admin_enable_health_check=Ενεργοποίηση Ελέγχων Υγείας του Αποθετηρίου (git fsck) @@ -1925,6 +1978,8 @@ settings.event_pull_request_review=Pull Request Αξιολογήθηκε settings.event_pull_request_review_desc=Το pull request εγκρίθηκε, απορρίφθηκε ή προστέθηκε αξιολόγηση. settings.event_pull_request_sync=Pull Request Συγχρονίστηκε settings.event_pull_request_sync_desc=Το pull request συγχρονίστηκε. +settings.event_package=Πακέτο +settings.event_package_desc=Το πακέτο δημιουργήθηκε ή διαγράφηκε σε ένα αποθετήριο. settings.branch_filter=Φίλτρο κλάδου settings.branch_filter_desc=Λίστα επιτρεπόμενων κλάδων για ωθήσεις, δημιουργία κλάδων και γεγονότα διαγραφής κλάδων, που ορίζονται ως μοτίβο glob. Εάν είναι κενό ή *, αναφέρονται συμβάντα για όλους τους κλάδους. Δείτε τη τεκμηρίωσηgithub.com/gobwas/glob για σύνταξη. Παραδείγματα: master, {master,release*}. settings.active=Ενεργό @@ -2102,10 +2157,10 @@ diff.show_split_view=Διαιρεμένη Προβολή diff.show_unified_view=Ενοποιημένη Προβολή diff.whitespace_button=Κενοί Χαρακτήρες diff.whitespace_show_everything=Εμφάνιση όλων -diff.whitespace_ignore_all_whitespace=Παράβλεψη κενών χαρακτήρων κατά τη σύγκριση γραμμών -diff.whitespace_ignore_amount_changes=Παράβλεψη αλλαγών σε ποσό των κενών χαρακτήρων +diff.whitespace_ignore_all_whitespace=Παράβλεψη κενών κατά τη σύγκριση γραμμών +diff.whitespace_ignore_amount_changes=Παράβλεψη αλλαγών σε ποσό των κενών diff.whitespace_ignore_at_eol=Παράβλεψη αλλαγών στα κενά στο EOL -diff.stats_desc= %d άλλαξε αρχεία με %d προσθήκες και %d διαγραφές +diff.stats_desc= %d αρχεία άλλαξαν με %d προσθήκες και %d διαγραφές diff.stats_desc_file=%d αλλαγές: %d προσθήκες και %d διαγραφές diff.bin=BIN diff.bin_not_shown=Το δυαδικό αρχείο δεν εμφανίζεται. @@ -2210,11 +2265,15 @@ branch.included_desc=Αυτός ο κλάδος είναι μέρος του π branch.included=Περιλαμβάνεται branch.create_new_branch=Δημιουργία κλάδου από κλάδο: branch.confirm_create_branch=Δημιουργία κλάδου +branch.create_branch_operation=Δημιουργία κλάδου branch.new_branch=Δημιουργία νέου κλάδου branch.new_branch_from=Δημιουργία νέου κλάδου από '%s' branch.renamed=Ο κλάδος %s μετονομάστηκε σε %s. tag.create_tag=Δημιουργία ετικέτας %s +tag.create_tag_operation=Δημιουργία ετικέτας +tag.confirm_create_tag=Δημιουργία ετικέτας +tag.create_tag_from=Δημιουργία νέας ετικέτας από '%s' tag.create_success=Η ετικέτα '%s' έχει δημιουργηθεί. @@ -2359,10 +2418,11 @@ first_page=Πρώτο last_page=Τελευταίο total=Σύνολο: %d +dashboard.new_version_hint=Το Gitea %s είναι διαθέσιμο, τώρα εκτελείτε το %s. Ελέγξτε το blog για περισσότερες λεπτομέρειες. dashboard.statistic=Περίληψη dashboard.operations=Λειτουργίες Συντήρησης dashboard.system_status=Κατάσταση Συστήματος -dashboard.statistic_info=Η βάση δεδομένων του Gitea περιέχει %d χρήστες, %d οργανισμούς, %d δημόσια κλειδιά, %d αποθετήρια, %d παρακολουθήσεις, %d αστέρια, %d δράσεις, %d προσβάσεις, %d ζητήματα, %d σχόλια, %d λογαριασμούς κοινωνικών, %d ακόλουθους, %d είδωλα, %d εκδόσεις, %d πηγές ταυτοποίησης, %d webhooks, %d ορόσημα, %d σήματα, %d εργασίες hook, %d ομάδες, %d εργασίες ενημέρωσης, %d συνημμένα. +dashboard.statistic_info=Η βάση δεδομένων του Gitea περιέχει %d χρήστες, %d οργανισμούς, %d δημόσια κλειδιά, %d αποθετήρια, %d όψεις, %d αστέρια, ~%d ενέργειες, %d προσβάσεις, %d ζητήματα, %d σχόλια, %d λογαριασμούς κοινωνικών δικτύων, %d ακολουθήσεις, %d κατοπτρισμένα αποθετήρια, %d εκδόσεις, %d πηγές ελέγχου ταυτότητας, %d webhooks, %d ορόσημα, %d ετικέτες, %d εργασίες hooks, %d ομάδες, %d εργασίες ενημέρωσης, %d συνημμένα. dashboard.operation_name=Όνομα Λειτουργίας dashboard.operation_switch=Αλλαγή dashboard.operation_run=Εκτέλεση @@ -2401,7 +2461,8 @@ dashboard.resync_all_hooks=Επανασυγχρονισμός των hook pre-re dashboard.reinit_missing_repos=Επανεκκινήστε όλα τα αποθετήρια Git που λείπουν και για τα οποία υπάρχουν εγγραφές dashboard.sync_external_users=Συγχρονισμός δεδομένων εξωτερικών χρηστών dashboard.cleanup_hook_task_table=Εκκαθάριση πίνακα hook_task -dashboard.server_uptime=Uptime Διακομιστή +dashboard.cleanup_packages=Εκκαθάριση ληγμένων πακέτων +dashboard.server_uptime=Διάρκεια Διακομιστή dashboard.current_goroutine=Τρέχουσες Goroutines dashboard.current_memory_usage=Τρέχουσα Χρήση Μνήμης dashboard.total_memory_allocated=Συνολική Μνήμη Που Χρησιμοποιείται @@ -2414,7 +2475,7 @@ dashboard.heap_memory_obtained=Μνήμη Heap Που Λαμβάνεται dashboard.heap_memory_idle=Αδρανής Μνήμη Heap dashboard.heap_memory_in_use=Μνήμη Heap Σε Χρήση dashboard.heap_memory_released=Μνήμη Heap Που Απελευθερώθηκε -dashboard.heap_objects=Αντικείμενα Heap +dashboard.heap_objects=Αντικείμενα στο Heap dashboard.bootstrap_stack_usage=Χρήση Στοίβας Bootstrap dashboard.stack_memory_obtained=Μνήμη Στοίβας Που Λαμβάνεται dashboard.mspan_structures_usage=Χρήση Δομών Mspan @@ -2432,6 +2493,8 @@ dashboard.last_gc_pause=Τελευταία Παύση GC dashboard.gc_times=Πλήθος GC dashboard.delete_old_actions=Διαγραφή όλων των παλαιών ενεργειών από τη βάση δεδομένων dashboard.delete_old_actions.started=Η διαγραφή όλων των παλιών ενεργειών από τη βάση δεδομένων ξεκίνησε. +dashboard.update_checker=Ελεγκτής ενημερώσεων +dashboard.delete_old_system_notices=Διαγραφή όλων των παλιών ειδοποιήσεων συστήματος από τη βάση δεδομένων users.user_manage_panel=Διαχείριση Λογαριασμών Χρηστών users.new_account=Δημιουργία Λογαριασμού Χρήστη @@ -2466,8 +2529,10 @@ users.allow_import_local=Μπορεί Να Εισάγει Τοπικά Αποθ users.allow_create_organization=Μπορεί Να Δημιουργεί Οργανισμούς users.update_profile=Ενημέρωση Λογαριασμού Χρήστη users.delete_account=Διαγραφή Λογαριασμού Χρήστη +users.cannot_delete_self=Δεν μπορείτε να διαγράψετε τον εαυτό σας users.still_own_repo=Αυτός ο χρήστης εξακολουθεί να κατέχει ένα ή περισσότερα αποθετήρια. Διαγράψτε ή μεταφέρετε αυτά τα αποθετήρια πρώτα. users.still_has_org=Αυτός ο χρήστης είναι μέλος ενός οργανισμού. Αφαιρέστε πρώτα τον χρήστη από οποιονδήποτε οργανισμό. +users.still_own_packages=Αυτός ο χρήστης εξακολουθεί να κατέχει ένα ή περισσότερα πακέτα. Διαγράψτε πρώτα αυτά τα πακέτα. users.deletion_success=Ο λογαριασμός χρήστη έχει διαγραφεί. users.reset_2fa=Επαναφορά 2FA users.list_status_filter.menu_text=Φίλτρο @@ -2514,6 +2579,16 @@ repos.forks=Forks repos.issues=Ζητήματα repos.size=Μέγεθος +packages.package_manage_panel=Διαχείριση Πακέτων +packages.total_size=Συνολικό Μέγεθος: %s +packages.owner=Ιδιοκτήτης +packages.creator=Δημιουργός +packages.name=Όνομα +packages.version=Έκδοση +packages.type=Τύπος +packages.repository=Αποθετήριο +packages.size=Μέγεθος +packages.published=Δημοσιευμένα defaulthooks=Προεπιλεγμένα Webhooks defaulthooks.desc=Τα Webhooks κάνουν αυτόματα αιτήσεις HTTP POST σε ένα διακομιστή όταν συμβαίνουν ορισμένα γεγονότα στο Gitea. Τα Webhooks που ορίζονται εδώ είναι προεπιλογή και θα αντιγραφούν σε όλα τα νέα αποθετήρια. Διαβάστε περισσότερα στον οδηγό webhooks. @@ -2548,7 +2623,7 @@ auths.attribute_name=Χαρακτηριστικό Ονόματος auths.attribute_surname=Χαρακτηριστικό Επωνύμου auths.attribute_mail=Χαρακτηριστικό Email auths.attribute_ssh_public_key=Χαρακτηριστικό Δημόσιου Κλειδιού SSH -auths.attribute_avatar=Παράμετρος Εικόνας +auths.attribute_avatar=Χαρακτηριστικό Εικόνας auths.attributes_in_bind=Λήψη χαρακτηριστικών μέσα στο πλαίσιο του Bind DN auths.allow_deactivate_all=Επιτρέψτε σε ένα κενό αποτέλεσμα αναζήτησης να απενεργοποιήσει όλους τους χρήστες auths.use_paged_search=Χρήση Σελιδοποιημένης Αναζήτησης @@ -2557,9 +2632,13 @@ auths.filter=Φίλτρο Χρηστών auths.admin_filter=Φίλτρο Διαχειριστών auths.restricted_filter=Φίλτρο Περιορισμένων auths.restricted_filter_helper=Αφήστε κενό για να μην ορίσετε κανέναν χρήστη ως περιορισμένο. Χρησιμοποιήστε έναν αστερίσκο ('*') για να ορίσετε όλους τους χρήστες που δεν ταιριάζουν με το φίλτρο διαχειριστή ως περιορισμένους. +auths.verify_group_membership=Επαλήθευση της συμμετοχής σε ομάδα στο LDAP (αφήστε το φίλτρο κενό για παράλειψη) auths.group_search_base=DN Βάσης Αναζήτησης Ομάδων auths.group_attribute_list_users=Χαρακτηριστικό Ομάδας Που Περιέχει Τη Λίστα Χρηστών auths.user_attribute_in_group=Χαρακτηριστικό Χρήστη Στην Ομάδα +auths.map_group_to_team=Αντιστοίχιση ομάδων LDAP σε ομάδες στους Οργανισμούς (αφήστε το πεδίο κενό για παράλειψη) +auths.map_group_to_team_removal=Αφαίρεση χρηστών από τις συγχρονισμένες ομάδες αν ο χρήστης δεν ανήκει στην αντίστοιχη ομάδα LDAP +auths.enable_ldap_groups=Ενεργοποίηση ομάδων LDAP auths.ms_ad_sa=Χαρακτηριστικά Αναζήτησης Στο MS AD auths.smtp_auth=Τύπος Ταυτοποίησης SMTP auths.smtphost=Διακομιστής SMTP @@ -2778,9 +2857,12 @@ monitor.next=Επόμενη Ώρα monitor.previous=Προηγούμενη Ώρα monitor.execute_times=Εκτελέσεις monitor.process=Εκτελούμενες Διεργασίες +monitor.stacktrace=Ιχνηλατήσεις Στοίβας +monitor.goroutines=%d Goroutines monitor.desc=Περιγραφή monitor.start=Ώρα Έναρξης monitor.execute_time=Χρόνος Εκτέλεσης +monitor.last_execution_result=Αποτέλεσμα monitor.process.cancel=Ακύρωση διαδικασίας monitor.process.cancel_desc=Η ακύρωση μιας διαδικασίας μπορεί να προκαλέσει απώλεια δεδομένων monitor.process.cancel_notices=Ακύρωση: %s; @@ -2792,6 +2874,7 @@ monitor.queue.type=Τύπος monitor.queue.exemplar=Τύπος Υποδείγματος monitor.queue.numberworkers=Αριθμός Εργατών monitor.queue.maxnumberworkers=Μέγιστος Αριθμός Εργατών +monitor.queue.numberinqueue=Πλήθος Ουράς monitor.queue.review=Εξέταση Ρυθμίσεων monitor.queue.review_add=Εξέταση/Προσθήκη Εργατών monitor.queue.configuration=Αρχική Ρύθμιση @@ -2947,4 +3030,94 @@ error.no_unit_allowed_repo=Δεν σας επιτρέπεται να έχετε error.unit_not_allowed=Δεν σας επιτρέπεται να έχετε πρόσβαση σε αυτήν την ενότητα αποθετηρίου. [packages] +title=Πακέτα +desc=Διαχείριση πακέτων μητρώου. +empty=Δεν υπάρχουν πακέτα ακόμα. +empty.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο πακέτων, ανατρέξτε στην τεκμηρίωση. +filter.type=Τύπος +filter.type.all=Όλα +filter.no_result=Το φίλτρο δεν παρήγαγε αποτελέσματα. +filter.container.tagged=Επισημάνθηκαν +filter.container.untagged=Χωρίς Επισήμανση +published_by=Δημοσιεύθηκε %[1]s από %[3]s +published_by_in=Δημοσιεύθηκε %[1]s κατά %[3]s σε %[5]s +installation=Εγκατάσταση +about=Σχετικά με αυτό το πακέτο +requirements=Απαιτήσεις +dependencies=Εξαρτήσεις +keywords=Λέξεις κλειδιά +details=Λεπτομέρειες +details.author=Συγγραφέας +details.project_site=Ιστοσελίδα Έργου +details.license=Άδεια +assets=Πόροι +versions=Εκδόσεις +versions.on=τη +versions.view_all=Προβολή όλων +dependency.id=ID +dependency.version=Έκδοση +composer.registry=Ρυθμίστε αυτό το μητρώο στο αρχείο ~/.composer/config.json: +composer.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το Composer, εκτελέστε την ακόλουθη εντολή: +composer.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Composer, διαβάστε τη τεκμηρίωση. +composer.dependencies=Εξαρτήσεις +composer.dependencies.development=Εξαρτήσεις Ανάπτυξης +conan.details.repository=Αποθετήριο +conan.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμή εντολών: +conan.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το Conan, εκτελέστε την ακόλουθη εντολή: +conan.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Conan, ανατρέξτε στην τεκμηρίωση. +container.details.type=Τύπος Εικόνας +container.details.platform=Πλατφόρμα +container.details.repository_site=Ιστοσελίδα Αποθετηρίου +container.details.documentation_site=Ιστοσελίδα Τεκμηρίωσης +container.pull=Κατεβάστε την εικόνα από τη γραμμή εντολών: +container.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο για Container, ανατρέξτε στην τεκμηρίωση. +container.multi_arch=ΛΣ / Αρχιτεκτονική +container.layers=Στρώματα Εικόνας +container.labels=Ετικέτες +container.labels.key=Κλειδί +container.labels.value=Τιμή +generic.download=Λήψη πακέτου από τη γραμμή εντολών: +generic.documentation=Για περισσότερες πληροφορίες σχετικά με το γενικό μητρώο, ανατρέξτε στην τεκμηρίωση. +helm.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμή εντολών: +helm.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: +helm.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Helm, ανατρέξτε στην τεκμηρίωση. +maven.registry=Ρυθμίστε αυτό το μητρώο στο αρχείο pom.xml του έργου σας: +maven.install=Για να χρησιμοποιήσετε το πακέτο, συμπεριλάβετε τα ακόλουθα στη περιοχή dependencies στο αρχείο pom.xml: +maven.install2=Εκτέλεση μέσω γραμμής εντολών: +maven.download=Για να κατεβάσετε την εξάρτηση, εκτελέστε μέσω της γραμμής εντολών: +maven.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Maven, ανατρέξτε στην τεκμηρίωση. +nuget.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμή εντολών: +nuget.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το NuGet, εκτελέστε την ακόλουθη εντολή: +nuget.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο NuGet δείτε την τεκμηρίωση. +nuget.dependency.framework=Πλαίσιο Ανάπτυξης +npm.registry=Ρυθμίστε αυτό το μητρώο στο αρχείο .npmrc του έργου σας: +npm.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας npm, εκτελέστε την ακόλουθη εντολή: +npm.install2=ή προσθέστε το στο αρχείο package.json: +npm.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο npm, ανατρέξτε στην τεκμηρίωση. +npm.dependencies=Εξαρτήσεις +npm.dependencies.development=Εξαρτήσεις Ανάπτυξης +npm.dependencies.peer=Εξαρτήσεις Ομότιμου +npm.dependencies.optional=Προαιρετικές Εξαρτήσεις +npm.details.tag=Σήμανση +pypi.requires=Απαιτεί Python +pypi.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το pip, εκτελέστε την ακόλουθη εντολή: +pypi.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο PyPI, ανατρέξτε στην τεκμηρίωση. +rubygems.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το gem, εκτελέστε την ακόλουθη εντολή: +rubygems.install2=ή προσθέστε το στο Gemfile: +rubygems.dependencies.runtime=Εξαρτήσεις Εκτέλεσης +rubygems.dependencies.development=Εξαρτήσεις Ανάπτυξης +rubygems.required.ruby=Απαιτεί την έκδοση Ruby +rubygems.required.rubygems=Απαιτεί έκδοση RubyGem +rubygems.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο RubyGems, ανατρέξτε στην τεκμηρίωση. +settings.link=Σύνδεση αυτού του πακέτου με ένα αποθετήριο +settings.link.description=Εάν συνδέσετε ένα πακέτο με ένα αποθετήριο, το πακέτο περιλαμβάνεται στη λίστα πακέτων του αποθετηρίου. +settings.link.select=Επιλογή Αποθετηρίου +settings.link.button=Ενημέρωση Συνδέσμου Αποθετηρίου +settings.link.success=Ο σύνδεσμος αποθετηρίου ενημερώθηκε επιτυχώς. +settings.link.error=Αποτυχία ενημέρωσης συνδέσμου αποθετηρίου. +settings.delete=Διαγραφή πακέτου +settings.delete.description=Η διαγραφή ενός πακέτου είναι μόνιμη και δεν μπορεί να αναιρεθεί. +settings.delete.notice=Πρόκειται να διαγράψετε %s (%s). Αυτή η λειτουργία είναι μη αναστρέψιμη, είστε σίγουροι; +settings.delete.success=Το πακέτο έχει διαγραφεί. +settings.delete.error=Αποτυχία διαγραφής του πακέτου. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d43e34dd82..b9ba6e1136 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2,6 +2,7 @@ home = Home dashboard = Dashboard explore = Explore help = Help +logo = Logo sign_in = Sign In sign_in_with = Sign In With sign_out = Sign Out @@ -716,7 +717,9 @@ generate_token_success = Your new token has been generated. Copy it now as it wi generate_token_name_duplicate = %s has been used as an application name already. Please use a new one. delete_token = Delete access_token_deletion = Delete Access Token -access_token_deletion_desc = Deleting a token will revoke access to your account for applications using it. Continue? +access_token_deletion_cancel_action = Cancel +access_token_deletion_confirm_action = Delete +access_token_deletion_desc = Deleting a token will revoke access to your account for applications using it. This cannot be undone. Continue? delete_token_success = The token has been deleted. Applications using it no longer have access to your account. manage_oauth2_applications = Manage OAuth2 Applications @@ -778,6 +781,7 @@ webauthn_delete_key_desc = If you remove a security key you can no longer sign i manage_account_links = Manage Linked Accounts manage_account_links_desc = These external accounts are linked to your Gitea account. account_links_not_available = There are currently no external accounts linked to your Gitea account. +link_account = Link Account remove_account_link = Remove Linked Account remove_account_link_desc = Removing a linked account will revoke its access to your Gitea account. Continue? remove_account_link_success = The linked account has been removed. @@ -858,7 +862,7 @@ default_branch = Default Branch default_branch_helper = The default branch is the base branch for pull requests and code commits. mirror_prune = Prune mirror_prune_desc = Remove obsolete remote-tracking references -mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync. +mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync. (Minimum interval: %s) mirror_interval_invalid = The mirror interval is not valid. mirror_address = Clone From URL mirror_address_desc = Put any required credentials in the Authorization section. @@ -929,7 +933,6 @@ need_auth = Authorization migrate_options = Migration Options migrate_service = Migration Service migrate_options_mirror_helper = This repository will be a mirror -migrate_options_mirror_disabled = Your site administrator has disabled new mirrors. migrate_options_lfs = Migrate LFS files migrate_options_lfs_endpoint.label = LFS Endpoint migrate_options_lfs_endpoint.description = Migration will attempt to use your Git remote to determine the LFS server. You can also specify a custom endpoint if the repository LFS data is stored somewhere else. @@ -1463,6 +1466,7 @@ issues.review.add_review_request = "requested review from %s %s" issues.review.remove_review_request = "removed review request for %s %s" issues.review.remove_review_request_self = "refused to review %s" issues.review.pending = Pending +issues.review.pending.tooltip = This comment is not currently visible to other users. To submit your pending comments, select '%s' -> '%s/%s/%s' at the top of the page. issues.review.review = Review issues.review.reviewers = Reviewers issues.review.outdated = Outdated @@ -2282,6 +2286,9 @@ topic.done = Done topic.count_prompt = You can not select more than 25 topics topic.format_prompt = Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long. +find_file.go_to_file = Go to file +find_file.no_matching = No matching file found + error.csv.too_large = Can't render this file because it is too large. error.csv.unexpected = Can't render this file because it contains an unexpected character in line %d and column %d. error.csv.invalid_field_count = Can't render this file because it has a wrong number of fields in line %d. @@ -2422,7 +2429,7 @@ dashboard.new_version_hint = Gitea %s is now available, you are running %s. Chec dashboard.statistic = Summary dashboard.operations = Maintenance Operations dashboard.system_status = System Status -dashboard.statistic_info = The Gitea database holds %d users, %d organizations, %d public keys, %d repositories, %d watches, %d stars, %d actions, %d accesses, %d issues, %d comments, %d social accounts, %d follows, %d mirrors, %d releases, %d authentication sources, %d webhooks, %d milestones, %d labels, %d hook tasks, %d teams, %d update tasks, %d attachments. +dashboard.statistic_info = The Gitea database holds %d users, %d organizations, %d public keys, %d repositories, %d watches, %d stars, ~%d actions, %d accesses, %d issues, %d comments, %d social accounts, %d follows, %d mirrors, %d releases, %d authentication sources, %d webhooks, %d milestones, %d labels, %d hook tasks, %d teams, %d update tasks, %d attachments. dashboard.operation_name = Operation Name dashboard.operation_switch = Switch dashboard.operation_run = Run diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index d8f0deabe0..eba3a8c1f2 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -849,7 +849,6 @@ default_branch=Rama por defecto default_branch_helper=La rama por defecto es la rama base para pull requests y commits de código. mirror_prune=Purgar mirror_prune_desc=Eliminar referencias de seguimiento de remotes obsoletas -mirror_interval=Intervalo de réplica (Las unidades de tiempo válidas son 'h', 'm', 's'). Pone 0 para deshabilitar la sincronización automática. mirror_interval_invalid=El intervalo de réplica no es válido. mirror_address=Clonar desde URL mirror_address_desc=Ponga cualquier credencial requerida en la sección de Autorización. @@ -920,7 +919,6 @@ need_auth=Autorización migrate_options=Opciones de migración migrate_service=Servicio de Migración migrate_options_mirror_helper=Este repositorio será uno replicado -migrate_options_mirror_disabled=El administrador de tu sitio ha desactivado nuevos repositorios replicados. migrate_options_lfs=Migrar archivos LFS migrate_options_lfs_endpoint.label=Punto final de LFS migrate_options_lfs_endpoint.description=Migración intentará usar su mando Git para determinar el servidor LFS. También puede especificar un punto final personalizado si los datos LFS del repositorio se almacenan en otro lugar. @@ -2340,7 +2338,6 @@ total=Total: %d dashboard.statistic=Resumen dashboard.operations=Operaciones de mantenimiento dashboard.system_status=Estado del sistema -dashboard.statistic_info=La base de datos de Gitea contiene %d usuarios, %d organizaciones, %d claves públicas, %d repositorios, %d elementos observados, %d destacados, %d acciones, %d accesos, %d incidencias, %d comentarios, %d cuentas sociales, %d seguidos, %d réplicas, %d releases, %d orígenes de autenticación, %d webhooks, %d milestones, %d etiquetas, %d tareas de hook, %d equipos, %d tareas de actualización, %d adjuntos. dashboard.operation_name=Nombre de la operación dashboard.operation_switch=Interruptor dashboard.operation_run=Ejecutar diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 93a756fa5e..ef34c0e842 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -797,7 +797,6 @@ default_branch=شاخه پیش‌فرض default_branch_helper=شاخه پیش‌فرض، شاخه پایه برای درخواست‌های pull و کدهای commit است. mirror_prune=هرس کردن mirror_prune_desc=حذف منابع پیگیری‌راه‌دور منسوخ -mirror_interval=بازه زمانی قرینه سازی (mirror) با 'h', 'm', 's'. برای غیر فعال کردن همگام سازی خودکار 0 بگذارید. mirror_interval_invalid=بازه زمانی سازی قرینه نیست. mirror_address=همسان‌سازی از نشانی mirror_address_desc=هر گونه اعتبار مورد نیاز را در قسمت Authorization قرار دهید. @@ -867,7 +866,6 @@ need_auth=دسترسی migrate_options=تنظیمات مهاجرت migrate_service=سرویس مهاجرت migrate_options_mirror_helper=این مخزن یک آینه خواهد بود -migrate_options_mirror_disabled=سرپرست سایت آینه‌های جدید را غیرفعال کرده است. migrate_options_lfs=مهاجرت فایلهای LFS migrate_options_lfs_endpoint.label=نشانهای پایانی LFS migrate_options_lfs_endpoint.description=Migration سعی خواهد کرد از کنترل از راه دور Git شما برای تعیین سرور LFS استفاده کند. همچنین اگر داده های LFS مخزن در جای دیگری ذخیره شده باشد، می توانید یک نقطه پایانی سفارشی را مشخص کنید. @@ -2246,7 +2244,6 @@ total=مجموع: %d dashboard.statistic=چکیده dashboard.operations=عملیات‌های نگهداری dashboard.system_status=وضعیت سامانه -dashboard.statistic_info=پایگاه داده‌‌های gitgo شامل %d کاربران, %d سازمان ها, %d کلید های عمومی, %d مخازن, %d مشاهده ها, %d ستاره دار ها, %d فعالیت ها, %d دسترسی ها, %d مسائل, %d نظرات, %d حساب ها کاربری شبکه های اجتماعی, %d دنیال کردن ها, %dmirror, %d ریلیز ها, %d نقاط ورود به سیستم, %d webhooks, %d نقاط عطف یا milestone ها, %d برچسب, %d hook وظایف, %d تیم, %d به روزرسانی ها وظایف افراد, %d پیوست هاست. dashboard.operation_name=نام عملیات dashboard.operation_switch=تعویض dashboard.operation_run=اجرا diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 361ba76e74..da96086cdc 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -1062,7 +1062,6 @@ total=Yhteensä: %d dashboard.statistic=Yhteenveto dashboard.system_status=Järjestelmän tila -dashboard.statistic_info=Gitea tietokannassa on %d käyttäjää, %d organisaatiota, %d julkista avainta, %d varastoa, %d tarkkailijaa, %d tähteä, %d toimea, %d sisäänkirjautunutta, %d ongelmaa, %d kommenttia, %d sosiaalista tiliä, %d seuraajaa, %d peiliä, %d julkaisua, %d kirjautumis lähdettä, %d webkoukkua, %d merkkipaalua, %d tunnistetta, %d koukku tehtävää, %d tiimiä, %d päivitys tehtävää, %d liitetiedostoa. dashboard.operation_name=Toiminnon nimi dashboard.operation_switch=Vaihda dashboard.operation_run=Suorita diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 496b3b3c0f..66de56c3e6 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -750,7 +750,6 @@ default_branch=Branche par défaut default_branch_helper=La branche par défaut est la branche de base pour les demandes d'ajout et les révisions de code. mirror_prune=Purger mirror_prune_desc=Supprimer les références externes obsolètes -mirror_interval=Intervalle de synchronisation ('h', 'm', et 's' sont des unités valides), 0 pour désactiver. mirror_interval_invalid=L'intervalle de synchronisation est invalide. mirror_address=Cloner depuis une URL mirror_address_desc=Insérez tous les identifiants requis dans la section Autorisation. @@ -819,7 +818,6 @@ need_auth=Autorisation migrate_options=Options de migration migrate_service=Service de migration migrate_options_mirror_helper=Ce dépôt sera un miroir -migrate_options_mirror_disabled=L’administrateur du site a désactivé les nouveaux miroirs. migrate_options_lfs=Migrer les fichiers LFS migrate_options_lfs_endpoint.label=Point d'accès LFS migrate_options_lfs_endpoint.description=La migration va tenter d'utiliser votre dépôt Git distant pour déterminer le serveur LFS. Vous pouvez également spécifier un point d'accès personnalisé si les données LFS du dépôt sont stockées ailleurs. @@ -2098,7 +2096,6 @@ total=Total : %d dashboard.statistic=Résumé dashboard.operations=Opérations de maintenance dashboard.system_status=État du système -dashboard.statistic_info=La base de données Gitea contient %d utilisateurs, %d organisations, %d clés publiques, %d dépôts, %d surveillances de dépôts, %d votes, %d actions, %d accès, %d tickets, %d commentaires, %d comptes de réseaux sociaux, %d abonnements, %d miroirs, %d versions, %d sources d'authentification externes, %d webhooks, %d versions, %d labels, %d tâches hook, %d équipes, %d tâches de mise à jour, %d fichiers. dashboard.operation_name=Nom de l'Opération dashboard.operation_switch=Basculer dashboard.operation_run=Exécuter diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 9b85f57e16..a523e1e8cf 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -609,7 +609,6 @@ auto_init=Tároló inicializálása (Hozzáadja a .gitignore,License és README create_repo=Tároló létrehozása default_branch=Alapértelmezett ág mirror_prune=Tükörkapcsolat eltávolítása -mirror_interval=Tükör gyakorisága (időmértékegységek: 'h','m','s'). 0 ha nem szeretné automatikusan szinkronizálni. mirror_interval_invalid=A tükrözés gyakorisága hibás. mirror_address=Másolás URL-ről mirror_address_url_invalid=A megadott URL érvénytelen. Az URL minden részét megfelelően kell escapelni. @@ -1412,7 +1411,6 @@ total=Összesen: %d dashboard.statistic=Összefoglaló dashboard.operations=Karbantartási műveletek dashboard.system_status=Rendszer Állapota -dashboard.statistic_info=The Gitea adatbázisa %d felhasználót, %d szervezetet, %d publikus kulcsot, %d tárolót %d figyelőt, %d csillagot, %d műveletet, %d jogosultságot, %d hibajegyet %d hozzászólást, %d közösségi fiókot, %d követőt, %d tükröt, %d kiadást, %d hitelesítési forrást, %d webhook-ot, %d mérföldkövet, %d címkét, %d hook műveletet, %d csoportot, %d frissítési műveletet, %d csatolmányt tartalmaz. dashboard.operation_name=Művelet Neve dashboard.operation_switch=Váltás dashboard.operation_run=Futtatás diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index b3d570c801..2d0b62507f 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -1183,7 +1183,6 @@ total=Samtals: %d dashboard.new_version_hint=Gitea %s er nú í boði en þú ert að keyra %s. Athugaðu bloggsíðuna fyrir frekari upplýsingar. dashboard.statistic=Yfirlit -dashboard.statistic_info=Gagnasafn Gitea inniheldur %d notendur, %d stofnanir, %d dreifilykla, %d hugbúnaðarsöfn, %d áhorfir, %d eftirlæti, %d aðgerðir, %d aðganga, %d vandamál, %d ummæli, %d félagsreikningum, %d fylgjanir, %d speglanir, %d útgæfur, %d auðkenningarheimildir, %d vefkrókar, %d tímamót, %d skýringar, %d krókaverkefni, %d lið, %d uppfærsluaðgerðir, %d viðhengi. dashboard.operation_switch=Skipta dashboard.operation_run=Keyra dashboard.update_mirrors=Uppfæra Speglanir diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index c93606c6a9..bda0e8e7b5 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -683,7 +683,6 @@ create_repo=Crea Repository default_branch=Ramo (Branch) predefinito mirror_prune=Rimuovi mirror_prune_desc=Rimuovi i riferimenti di puntamento-remoto obsoleti -mirror_interval=Intervallo del Mirror (unità di tempo valide 'h', 'm', 's'). 0 per disabilitare la sincronizzazione automatica. mirror_interval_invalid=L'intervallo di aggiornamento dei mirror non è valido. mirror_address=Clona da URL mirror_address_url_invalid=L'url fornito non è valido. Devi effettuare l'escape completo tutti i componenti dell'Url. @@ -740,7 +739,6 @@ form.name_pattern_not_allowed=Il modello '%s' non è consentito come nome di un migrate_options=Opzioni di migrazione migrate_service=Servizio migrazione migrate_options_mirror_helper=Questo repository sarà un mirror -migrate_options_mirror_disabled=L'amministratore del sito ha disabilitato i nuovi mirror. migrate_items=Elementi di migrazione migrate_items_wiki=Wiki migrate_items_milestones=Milestone @@ -1907,7 +1905,6 @@ total=Totale: %d dashboard.statistic=Riepilogo dashboard.operations=Operazioni di manutenzione dashboard.system_status=Stato del sistema -dashboard.statistic_info=Il database di Gitea contiene %d utenti, %d organizzazioni, %d chiavi pubbliche, %d repository, %d visualizzazioni, %d voti, %d azioni, %d accessi, %d issue, %d commenti, %d account social, %d follow, %d mirror, %d release, %d fonti di autenticazione, %d webhook, %d pietre miliari, %d etichette, %d richieste di hook, %d team, %d richieste di aggiornamento, %d allegati. dashboard.operation_name=Nome Operazione dashboard.operation_switch=Cambia dashboard.operation_run=Esegui diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 63a2d95ed0..de8f989b6e 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -778,6 +778,7 @@ webauthn_delete_key_desc=セキュリティキーの登録を解除すると、 manage_account_links=連携アカウントの管理 manage_account_links_desc=これらの外部アカウントがGiteaアカウントと連携されています。 account_links_not_available=現在このGiteaアカウントが連携している外部アカウントはありません。 +link_account=アカウントをリンク remove_account_link=連携アカウントの削除 remove_account_link_desc=連携アカウントを削除し、Giteaアカウントへのアクセス権を取り消します。 続行しますか? remove_account_link_success=連携アカウントを削除しました。 @@ -858,7 +859,6 @@ default_branch=デフォルトブランチ default_branch_helper=デフォルトブランチはプルリクエストとコードコミットのベースブランチとなります。 mirror_prune=Prune mirror_prune_desc=不要になった古いリモートトラッキング参照を削除 -mirror_interval=ミラー間隔 (有効な時間の単位は'h'、'm'、's')。 自動的な同期を無効にする場合は0。 mirror_interval_invalid=ミラー間隔が不正です。 mirror_address=クローンするURL mirror_address_desc=必要な資格情報は「認証」セクションに設定してください。 @@ -929,7 +929,6 @@ need_auth=認証 migrate_options=移行オプション migrate_service=移行するサービス migrate_options_mirror_helper=このリポジトリをミラーにする -migrate_options_mirror_disabled=サイト管理者はミラーの新規作成を無効にしています。 migrate_options_lfs=LFS ファイルのマイグレート migrate_options_lfs_endpoint.label=LFS エンドポイント migrate_options_lfs_endpoint.description=マイグレーションでは、リモート側のGitをもとにLFSサーバーを決定しようとします。 リポジトリのLFSデータがほかの場所に保存されている場合は、独自のエンドポイントを指定することができます。 @@ -1011,6 +1010,7 @@ tags=タグ issues=イシュー pulls=プルリクエスト project_board=プロジェクト +packages=パッケージ labels=ラベル org_labels_desc=組織で定義されているラベル (組織のすべてのリポジトリで使用可能なもの) org_labels_desc_manage=編集 @@ -1462,6 +1462,7 @@ issues.review.add_review_request=が %s にレビューを依頼 %s issues.review.remove_review_request=が %s へのレビュー依頼を取り消し %s issues.review.remove_review_request_self=がレビューを拒否 %s issues.review.pending=保留 +issues.review.pending.tooltip=このコメントは現在他のユーザーに表示されていません。 保留中のコメントを送信するには、このページの上にある '%s' -> '%s/%s/%s' を選択してください。 issues.review.review=レビュー issues.review.reviewers=レビューア issues.review.outdated=古い内容 @@ -1480,6 +1481,7 @@ issues.content_history.created=作成済み issues.content_history.delete_from_history=履歴から削除 issues.content_history.delete_from_history_confirm=履歴から削除しますか? issues.content_history.options=オプション +issues.reference_link=リファレンス: %s compare.compare_base=基準 compare.compare_head=比較 @@ -1492,6 +1494,9 @@ pulls.allow_edits_from_maintainers=メンテナーからの編集を許可する pulls.allow_edits_from_maintainers_desc=ベースブランチへの書き込みアクセス権を持つユーザーは、このブランチにプッシュすることもできます pulls.allow_edits_from_maintainers_err=更新に失敗しました pulls.compare_changes_desc=マージ先ブランチとプル元ブランチを選択。 +pulls.has_viewed_file=閲覧済 +pulls.has_changed_since_last_review=前回のレビュー後に変更あり +pulls.viewed_files_label=%[1]d / %[2]d ファイル閲覧済み pulls.compare_base=マージ先 pulls.compare_compare=プル元 pulls.switch_comparison_type=比較の種類を切り替える @@ -1559,6 +1564,14 @@ pulls.squash_merge_pull_request=スカッシュコミットを作成 pulls.merge_manually=手動マージ済みにする pulls.merge_commit_id=マージコミットID pulls.require_signed_wont_sign=ブランチでは署名されたコミットが必須ですが、このマージでは署名がされません +pulls.merge_pull_request_now=今すぐプルリクエストをマージ +pulls.rebase_merge_pull_request_now=今すぐリベースしてマージ +pulls.rebase_merge_commit_pull_request_now=今すぐリベースしてマージ(--no-ff) +pulls.squash_merge_pull_request_now=今すぐスカッシュしてマージ +pulls.merge_pull_request_on_status_success=すべてのチェックが成功したときにプルリクエストをマージ +pulls.rebase_merge_pull_request_on_status_success=すべてのチェックが成功したときにリベースしてマージ +pulls.rebase_merge_commit_pull_request_on_status_success=すべてのチェックが成功したときにリベースしてマージ(--no-ff) +pulls.squash_merge_pull_request_on_status_success=すべてのチェックが成功したときにスカッシュしてマージ pulls.invalid_merge_option=このプルリクエストでは、指定したマージ方法は使えません。 pulls.merge_conflict=マージ失敗: マージ中にコンフリクトがありました。 ヒント: 別のストラテジーを試してみてください pulls.merge_conflict_summary=エラーメッセージ @@ -1589,6 +1602,14 @@ pulls.reopened_at=`がプルリクエストを再オープン コマンドラインの手順も確認できます。` pulls.merge_instruction_step1_desc=あなたのプロジェクトリポジトリで新しいブランチをチェックアウトし、変更内容をテストします。 pulls.merge_instruction_step2_desc=変更内容をマージして、Giteaに反映します。 +pulls.merge_on_status_success=このプルリクエストは、すべてのチェックが成功したときにマージされるようにスケジュールされました。 +pulls.merge_on_status_success_already_scheduled=このプルリクエストは、すべてのチェックが成功したときにマージされるようにスケジュールされています。 +pulls.pr_has_pending_merge_on_success=%[1]s が、すべてのチェックが成功すると自動マージを行うよう、このプルリクエストをスケジュール %[2]s。 +pulls.merge_pull_on_success_cancel=自動マージをキャンセル +pulls.pull_request_not_scheduled=このプルリクエストは自動マージとしてスケジュールされていません。 +pulls.pull_request_schedule_canceled=このプルリクエストの自動マージはキャンセルされました。 +pulls.pull_request_scheduled_auto_merge=`が、すべてのチェックが成功すると自動マージを行うよう、このプルリクエストをスケジュール %[1]s` +pulls.pull_request_canceled_scheduled_auto_merge=`が、すべてのチェックが成功したときのプルリクエストの自動マージをキャンセル %[1]s` milestones.new=新しいマイルストーン milestones.open_tab=%d件 オープン中 @@ -2401,7 +2422,7 @@ dashboard.new_version_hint=Gitea %s が入手可能になりました。 現在 dashboard.statistic=サマリー dashboard.operations=メンテナンス操作 dashboard.system_status=システム状況 -dashboard.statistic_info=Giteaデータベースは %d ユーザー, %d 組織, %d 公開鍵, %d リポジトリ, %d ウォッチ, %d スター, %d アクション, %d アクセス, %d イシュー, %d コメント, %d ソーシャルアカウント, %d フォロー, %d ミラー, %d リリース, %d 認証ソース, %d Webhook, %d マイルストーン, %d ラベル, %d フックタスク, %d チーム, %d 更新タスク, %d 添付ファイル の情報を持っています。 +dashboard.statistic_info=Giteaデータベースは %d ユーザー, %d 組織, %d 公開鍵, %d リポジトリ, %d ウォッチ, %d スター, ~%d アクション, %d アクセス, %d イシュー, %d コメント, %d ソーシャルアカウント, %d フォロー, %d ミラー, %d リリース, %d 認証ソース, %d Webhook, %d マイルストーン, %d ラベル, %d フックタスク, %d チーム, %d 更新タスク, %d 添付ファイル の情報を持っています。 dashboard.operation_name=操作の名称 dashboard.operation_switch=切り替え dashboard.operation_run=実行 @@ -2508,6 +2529,7 @@ users.allow_import_local=ローカルリポジトリをインポート可 users.allow_create_organization=組織を作成可 users.update_profile=ユーザーアカウントを更新 users.delete_account=ユーザーアカウントを削除 +users.cannot_delete_self=自分自身を削除することはできません users.still_own_repo=このユーザーはまだ1つ以上のリポジトリを所有しています。 先にそれらのリポジトリを削除するか移転してください。 users.still_has_org=このユーザーは組織のメンバーになっています。 先に組織からこのユーザーを削除してください。 users.still_own_packages=このユーザーはまだ1つ以上のパッケージを所有しています。最初にそれらのパッケージを削除してください。 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index 36f616990d..f5d32e7793 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -565,7 +565,6 @@ create_repo=저장소 만들기 default_branch=기본 브랜치 mirror_prune=정리 mirror_prune_desc=불필요하게된 원격 트래킹 참조 삭제 -mirror_interval=미러 간격 (올바른 시간 단위는 'h','m','s'). 0은 자동 동기화를 비활성화 합니다. mirror_interval_invalid=미러 간격이 올바르지 않습니다. mirror_address=URL로 부터 클론 mirror_last_synced=마지막 동기화 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 19c256b1e1..41b55f66de 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -837,7 +837,6 @@ default_branch=Noklusējuma atzars default_branch_helper=Noklusētais atzars nosaka pamata atzaru uz kuru tiks veidoti izmaiņu pieprasījumi un koda revīziju iesūtīšana. mirror_prune=Izmest mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē -mirror_interval=Spoguļošanas biežums (atļautās laika vienības 'h', 'm' un 's'). Ievadiet 0, lai atslēgtu automātisko spoguļošanu. mirror_interval_invalid=Nekorekts spoguļošanas intervāls. mirror_address=Spoguļa adrese mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā. @@ -908,7 +907,6 @@ need_auth=Autorizācija migrate_options=Migrācijas opcijas migrate_service=Migrācijas serviss migrate_options_mirror_helper=Šis repozitorijs būs spogulis -migrate_options_mirror_disabled=Lapas administrators ir atslēdzies iespēju viedot jaunus spoguļus. migrate_options_lfs=Migrēt LFS failus migrate_options_lfs_endpoint.label=LFS galapunkts migrate_options_lfs_endpoint.description=Migrācija mēģinās izmantot attālināto URL, lai noteiktu LFS serveri. Var norādīt arī citu galapunktu, ja repozitorija LFS dati ir izvietoti citā vietā. @@ -2328,7 +2326,6 @@ total=Kopā: %d dashboard.statistic=Kopsavilkums dashboard.operations=Uzturēšanas darbības dashboard.system_status=Sistēmas statuss -dashboard.statistic_info=Gitea datu bāze satur %d lietotājus, %d organizācijas, %d publiskās atslēgas, %d repozitorijus, %d vērošanas, %d atzīmētas zvaigznītes, %d darbības, %d piekļuves, %d problēmas, %d komentārus, %d sociālos kontus, %d sekošanas, %d spoguļošanas, %d izlaides, %d autorizācijas avotus, %d tīmekļa āķus, %d starpposmus, %d etiķetes, %d āķu uzdevumus, %d komandas, %d labotus uzdevumus, %d pielikumus. dashboard.operation_name=Darbības nosaukums dashboard.operation_switch=Pārslēgt dashboard.operation_run=Palaist diff --git a/options/locale/locale_ml-IN.ini b/options/locale/locale_ml-IN.ini index c5f7238de8..64638f5073 100644 --- a/options/locale/locale_ml-IN.ini +++ b/options/locale/locale_ml-IN.ini @@ -575,7 +575,6 @@ create_repo=കലവറ സൃഷ്ടിക്കുക default_branch=സ്ഥിരസ്ഥിതി ശാഖ mirror_prune=വെട്ടിഒതുക്കുക mirror_prune_desc=കാലഹരണപ്പെട്ട വിദൂര ട്രാക്കിംഗ് റഫറൻസുകൾ നീക്കംചെയ്യുക -mirror_interval=മിറർ ചെയ്യാനുള്ള ഇടവേള (സാധുവായ സമയ യൂണിറ്റുകൾ 'h', 'm', 's' എന്നിവയാണ്). യാന്ത്രിക സമന്വയം പ്രവർത്തനരഹിതമാക്കാൻ 0 നല്‍കുക. mirror_interval_invalid=മിറർ ചെയ്യാനുള്ള ഇടവേള സാധുവല്ല. mirror_address=URL- ൽ നിന്നുള്ള ക്ലോൺ mirror_address_url_invalid=നൽകിയ url അസാധുവാണ്. നിങ്ങൾ url- ന്റെ എല്ലാ ഘടകങ്ങളും ശരിയായി നല്‍കണം. diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 640c5364dd..516d31bee1 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -705,7 +705,6 @@ create_repo=Nieuwe repository default_branch=Standaard branch mirror_prune=Opschonen mirror_prune_desc=Verwijder verouderde remote-tracking-referenties -mirror_interval=Kopie-interval (geldige tijdseenheden zijn 'h', 'm' en 's'). 0 om automatische synchronisatie uit te schakelen. mirror_interval_invalid=Kloon-interval is niet geldig. mirror_address=Klonen van URL mirror_address_url_invalid=De opgegeven url is ongeldig. U dient alle componenten van de url correct te escapen. @@ -758,7 +757,6 @@ form.name_pattern_not_allowed=Het patroon '%s' is niet toegestaan in de naam van migrate_options=Migratie opties migrate_service=Migratie Service migrate_options_mirror_helper=Deze repository zal een kopie zijn -migrate_options_mirror_disabled=Uw sitebeheerder heeft nieuwe mirrors uitgeschakeld. migrate_items=Migratie Items migrate_items_wiki=Wiki migrate_items_milestones=Mijlpalen @@ -1958,7 +1956,6 @@ total=Totaal: %d dashboard.statistic=Overzicht dashboard.operations=Onderhoudswerkzaamheden dashboard.system_status=Systeemtatus -dashboard.statistic_info=De Gitea database heeft %d gebruikers, %d organisaties, %d openbare sleutels, %d repositories, %d volgers, %d sterren, %d acties, %d participanten, %d issues, %d reacties, %d sociale accounten, %d volgers, %d kopieën, %d publicaties, %d authenticatiebronnen, %d webhooks, %d mijlpalen, %d labels, %d hook taken, %d teams, %d bijgewerkte taken, %d bijlagen. dashboard.operation_name=Bewerking naam dashboard.operation_switch=Omschakelen dashboard.operation_run=Uitvoeren diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 6967a919af..0c1ca297cb 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -808,7 +808,6 @@ default_branch=Domyślna gałąź default_branch_helper=Domyślny branch jest podstawowym branch'em dla pull requestów i commit'ów kodu. mirror_prune=Wyczyść mirror_prune_desc=Usuń przestarzałe odwołania do zdalnych śledzeń -mirror_interval=Przedział czasowy dla tworzenia kopii lustrzanej (prawidłowe jednostki czasu to 'h' (godziny), 'm', 's'). 0, aby wyłączyć automatyczną synchronizację. mirror_interval_invalid=Interwał lustrzanej kopii jest niepoprawny. mirror_address=Sklonuj z adresu URL mirror_address_url_invalid=Podany adres URL jest niewłaściwy. Musisz poprawnie escape'ować wszystkie jego elementy. @@ -875,7 +874,6 @@ need_auth=Autoryzacja migrate_options=Opcje migracji migrate_service=Usługa migracji migrate_options_mirror_helper=To repozytorium będzie kopią lustrzaną -migrate_options_mirror_disabled=Administrator witryny wyłączył tworzenie nowych repozytoriów lustrzanych. migrate_options_lfs=Migruj pliki LFS migrate_options_lfs_endpoint.label=Punkt końcowy LFS migrate_options_lfs_endpoint.description=Migracja spróbuje użyć Git remote, aby określić serwer LFS. Możesz również określić niestandardowy punkt końcowy, jeśli dane repozytorium LFS są przechowywane gdzieś indziej. @@ -2191,7 +2189,6 @@ total=Ogółem: %d dashboard.statistic=Podsumowanie dashboard.operations=Operacje konserwacji dashboard.system_status=Status strony -dashboard.statistic_info=Baza danych Gitea zawiera %d użytkowników, %d organizacji, %d kluczy publicznych, %d repozytoriów, %d obserwujących repozytoria, %d polubionych repozytoriów, %d akcji, %d tokenów, %d zgłoszeń, %d komenatrzy, %d kont społecznościowych, %d obserwujących użytkowników, %d kopii lustrzanych, %d wydań, %d źródeł uwierzytelniania, %d Webhooków, %d kamieni milowych, %d etykiet, %d zadań hook'ów, %d zespołów, %d zadań aktualizacji, %d załączników. dashboard.operation_name=Nazwa operacji dashboard.operation_switch=Przełącz dashboard.operation_run=Uruchom diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 607a915645..20a4478b75 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -105,6 +105,7 @@ error404=A página que você está tentando acessar não existe never=Nunca +rss_feed=Feed RSS [error] occurred=Ocorreu um erro @@ -777,6 +778,7 @@ webauthn_delete_key_desc=Se você remover uma chave de segurança, não poderá manage_account_links=Gerenciar contas vinculadas manage_account_links_desc=Estas contas externas estão vinculadas a sua conta de Gitea. account_links_not_available=Não existem contas externas atualmente vinculadas a esta conta. +link_account=Vincular Conta remove_account_link=Remover conta vinculada remove_account_link_desc=A exclusão da chave SSH revogará o acesso à sua conta. Continuar? remove_account_link_success=A conta vinculada foi removida. @@ -857,7 +859,6 @@ default_branch=Branch Padrão default_branch_helper=O branch padrão é o branch base para pull requests e commits de código. mirror_prune=Varrer mirror_prune_desc=Remover referências obsoletas de controle remoto -mirror_interval=Intervalo de espelhamento (as unidades de tempo válidas são 'h', 'm', 's'). 0 para desativar a sincronização automática. mirror_interval_invalid=O intervalo do espelhamento não é válido. mirror_address=Clonar de URL mirror_address_desc=Coloque todas as credenciais necessárias na seção de autorização. @@ -928,7 +929,6 @@ need_auth=Autorização migrate_options=Opções de Migração migrate_service=Serviço de Migração migrate_options_mirror_helper=Este repositório será um espelho -migrate_options_mirror_disabled=O administrador do site desabilitou novos espelhamentos. migrate_options_lfs=Migrar arquivos LFS migrate_options_lfs_endpoint.label=Destino LFS migrate_options_lfs_endpoint.description=A migração tentará usar seu controle remoto Git para determinar o servidor LFS. Você também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados em outro lugar. @@ -1010,6 +1010,7 @@ tags=Tags issues=Issues pulls=Pull requests project_board=Projetos +packages=Pacotes labels=Etiquetas org_labels_desc=Rótulos de nível de organização que podem ser usados em todos os repositórios sob esta organização org_labels_desc_manage=gerenciar @@ -1461,6 +1462,7 @@ issues.review.add_review_request=solicitou revisão de %s %s issues.review.remove_review_request=removeu a solicitação de revisão para %s %s issues.review.remove_review_request_self=recusou revisar %s issues.review.pending=Pendente +issues.review.pending.tooltip=Este comentário não está atualmente visível para outros usuários. Para enviar seus comentários pendentes, selecione '%s' -> '%s/%s/%s' no topo da página. issues.review.review=Revisão issues.review.reviewers=Revisores issues.review.outdated=Desatualizado @@ -1488,8 +1490,11 @@ pulls.desc=Habilitar pull requests e revisões de código. pulls.new=Novo pull request pulls.view=Ver Pull Request pulls.compare_changes=Novo pull request +pulls.allow_edits_from_maintainers=Permitir edições de mantenedores pulls.compare_changes_desc=Selecione o branch de destino (push) e o branch de origem (pull) para o merge. pulls.has_viewed_file=Visto +pulls.has_changed_since_last_review=Alterado desde a última revisão +pulls.viewed_files_label=%[1]d / %[2]d arquivos visualizados pulls.compare_base=merge em pulls.compare_compare=pull de pulls.switch_comparison_type=Mudar tipo de comparação @@ -1557,6 +1562,10 @@ pulls.squash_merge_pull_request=Criar commit de squash pulls.merge_manually=Merge feito manualmente pulls.merge_commit_id=A ID de merge commit pulls.require_signed_wont_sign=O branch requer commits assinados, mas este merge não será assinado +pulls.merge_pull_request_now=Aplicar Pull Request Agora +pulls.rebase_merge_pull_request_now=Aplicar Rebase e Merge Agora +pulls.rebase_merge_commit_pull_request_now=Aplicar Rebase e Merge Agora (--no-ff) +pulls.squash_merge_pull_request_now=Aplicar Squash e Merge Agora pulls.invalid_merge_option=Você não pode usar esta opção de merge neste pull request. pulls.merge_conflict=O merge falhou: Houve um conflito ao fazer merge. Dica: Tente uma estratégia diferente pulls.merge_conflict_summary=Mensagem de erro @@ -2400,7 +2409,6 @@ dashboard.new_version_hint=Gitea %s está disponível, você está executando %s dashboard.statistic=Resumo dashboard.operations=Operações de manutenção dashboard.system_status=Status do sistema -dashboard.statistic_info=O banco de dados do Gitea contém %d usuários, %d organizações, %d chaves públicas, %d repositórios, %d observadores, %d favoritos, %d ações, %d acessos, %d questões, %d comentários, %d contas sociais, %d seguidores, %d espelhamentoss, %d versões, %d origens de login, %d Hooks da Web, %d marcos, %d etiquetas, %d tarefas hook, %d equipes, %d tarefas de atualização, %d anexos. dashboard.operation_name=Nome da operação dashboard.operation_switch=Trocar dashboard.operation_run=Executar @@ -2506,6 +2514,7 @@ users.allow_import_local=Pode importar repositórios locais users.allow_create_organization=Pode criar organizações users.update_profile=Atualizar conta de usuário users.delete_account=Excluir conta de usuário +users.cannot_delete_self=Você não pode excluir você mesmo users.still_own_repo=Este usuário ainda possui um ou mais repositórios. Exclua ou transfira esses repositórios primeiro. users.still_has_org=Este usuário é membro de uma organização. Remova o usuário de qualquer organização primeiro. users.still_own_packages=Este usuário ainda possui um ou mais pacotes. Exclua esses pacotes primeiro. diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 96d782a27f..301b596f5b 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -2,6 +2,7 @@ home=Página inicial dashboard=Painel de controlo explore=Explorar help=Ajuda +logo=Logótipo sign_in=Iniciar sessão sign_in_with=Inicie sessão com sign_out=Terminar sessão @@ -51,10 +52,10 @@ webauthn_reload=Recarregar repository=Repositório organization=Organização -mirror=Espelho +mirror=Réplica new_repo=Novo repositório new_migrate=Nova migração -new_mirror=Novo espelho +new_mirror=Nova réplica new_fork=Nova derivação do repositório new_org=Nova organização new_project=Novo planeamento @@ -69,7 +70,7 @@ your_settings=Configurações all=Todos sources=Fontes -mirrors=Espelhos +mirrors=Réplicas collaborative=Colaborativo forks=Derivações @@ -146,8 +147,8 @@ path=Caminho sqlite_helper=Localização do ficheiro da base de dados em SQLite3.
Insira um caminho absoluto se corre o Gitea como um serviço. reinstall_error=Está a tentar instalar numa base de dados do Gitea já existente reinstall_confirm_message=Reinstalar com uma base de dados do Gitea já existente pode causar múltiplos problemas. Na maioria dos casos deve usar o seu "app.ini" existente para correr o Gitea. Se souber o que está a fazer, confirme o seguinte: -reinstall_confirm_check_1=Os dados encriptados pela chave secreta (SECRET_KEY) no ficheiro app.ini poderão ser perdidos: utilizadores poderão não ser capazes de iniciar a sessão com autenticação em dois passos (2FA) ou com chaves de utilização única (OTP) e os espelhos poderão deixar de funcionar em condições. Ao marcar esta opção estará a confirmar que o ficheiro app.ini vigente contém a SECRET_KEY certa. -reinstall_confirm_check_2=Os repositórios e as configurações poderão ter de voltar a ser sincronizados. Ao marcar esta opção estará a confirmar que vai voltar a sincronizar os automatismos para os repositórios e o ficheiro authorized_keys manualmente. Estará também a confirmar que assegurará que as configurações do repositório e dos espelhos estão em condições. +reinstall_confirm_check_1=Os dados encriptados pela chave secreta (SECRET_KEY) no ficheiro app.ini poderão ser perdidos: utilizadores poderão não ser capazes de iniciar a sessão com autenticação em dois passos (2FA) ou com chaves de utilização única (OTP) e as réplicas poderão deixar de funcionar em condições. Ao marcar esta opção estará a confirmar que o ficheiro app.ini vigente contém a SECRET_KEY certa. +reinstall_confirm_check_2=Os repositórios e as configurações poderão ter de voltar a ser sincronizados. Ao marcar esta opção estará a confirmar que vai voltar a sincronizar os automatismos para os repositórios e o ficheiro authorized_keys manualmente. Estará também a confirmar que vai assegurar que as configurações do repositório e das réplicas estão em condições. reinstall_confirm_check_3=Você confirma que tem a certeza absoluta de que este Gitea está a correr com a localização certa do ficheiro app.ini e que tem a certeza de que tem de voltar a instalar. Você confirma que tomou conhecimento dos riscos acima descritos. err_empty_db_path=A localização da base de dados SQLite3 não pode estar vazia. no_admin_and_disable_registration=Não pode desabilitar a auto-inscrição de utilizadores sem criar uma conta de administrador. @@ -243,7 +244,7 @@ my_repos=Repositórios show_more_repos=Mostrar mais repositórios… collaborative_repos=Repositórios colaborativos my_orgs=As minhas organizações -my_mirrors=Os meus espelhos +my_mirrors=As minhas réplicas view_home=Ver %s search_repos=Procurar um repositório… filter=Outros filtros @@ -559,7 +560,7 @@ hidden_comment_types=Tipos de comentários ocultos comment_type_group_reference=Referência comment_type_group_label=Rótulo comment_type_group_milestone=Etapa -comment_type_group_assignee=Responsável +comment_type_group_assignee=Encarregado comment_type_group_title=Título comment_type_group_branch=Ramo comment_type_group_time_tracking=Contagem de tempo @@ -777,6 +778,7 @@ webauthn_delete_key_desc=Se remover uma chave de segurança, deixará de poder u manage_account_links=Gerir contas vinculadas manage_account_links_desc=Estas contas externas estão vinculadas à sua conta do Gitea. account_links_not_available=Neste momento não existem contas externas vinculadas à sua conta do Gitea. +link_account=Vincular conta remove_account_link=Remover conta vinculada remove_account_link_desc=A remoção de uma conta vinculada revogará o acesso dessa conta à sua conta do Gitea. Quer continuar? remove_account_link_success=A conta vinculada foi removida. @@ -785,7 +787,7 @@ orgs_none=Não é membro de nenhuma organização. repos_none=Não tem nenhum repositório delete_account=Eliminar a sua conta -delete_prompt=Esta operação irá eliminar permanentemente sua conta de utilizador. Isso NÃO PODERÁ ser desfeito. +delete_prompt=Esta operação irá eliminar permanentemente a sua conta de utilizador. Isso NÃO PODERÁ ser desfeito. delete_with_all_comments=A sua conta tem menos de %s. Para evitar comentários fantasma, todas os comentários em questões ou nos pedidos de integração serão também eliminados. confirm_delete_account=Confirme a eliminação delete_account_title=Eliminar conta de utilizador @@ -857,14 +859,14 @@ default_branch=Ramo principal default_branch_helper=O ramo principal é o ramo base para pedidos de integração e cometimentos. mirror_prune=Podar mirror_prune_desc=Remover referências obsoletas de seguimento remoto -mirror_interval=Intervalo de espelhamento (as unidades de tempo válidas são 'h', 'm' e 's'). O valor zero desabilita a sincronização automática. -mirror_interval_invalid=O intervalo do espelhamento não é válido. +mirror_interval=Intervalo entre sincronizações (as unidades de tempo válidas são 'h', 'm' e 's'). O valor zero desabilita a sincronização automática. (Intervalo mínimo: %s) +mirror_interval_invalid=O intervalo entre sincronizações não é válido. mirror_address=Clonar a partir do URL mirror_address_desc=Coloque, na secção de Autorização, as credenciais que, eventualmente, sejam necessárias. mirror_address_url_invalid=O URL fornecido é inválido. Tem que codificar adequadamente todos os componentes do URL. -mirror_address_protocol_invalid=O URL fornecido é inválido. Só se pode espelhar a partir de endereços http(s):// ou git://. +mirror_address_protocol_invalid=O URL fornecido é inválido. Só se pode replicar a partir de endereços http(s):// ou git://. mirror_lfs=Armazenamento de Ficheiros Grandes (LFS) -mirror_lfs_desc=Habilitar o espelhamento de dados LFS. +mirror_lfs_desc=Habilitar a réplica de dados LFS. mirror_lfs_endpoint=Destino LFS mirror_lfs_endpoint_desc=A sincronização irá tentar usar o URL de clonagem para determinar o servidor LFS. Também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados noutro lugar. mirror_last_synced=Última sincronização @@ -927,8 +929,7 @@ form.name_pattern_not_allowed=O padrão '%s' não é permitido no nome de um rep need_auth=Autorização migrate_options=Opções de migração migrate_service=Serviço de migração -migrate_options_mirror_helper=Este repositório irá ser um espelho -migrate_options_mirror_disabled=O administrador desabilitou novos espelhos. +migrate_options_mirror_helper=Este repositório irá ser uma réplica migrate_options_lfs=Migrar ficheiros LFS migrate_options_lfs_endpoint.label=Destino LFS migrate_options_lfs_endpoint.description=A migração irá tentar usar o seu controlo remoto do Git para determinar o servidor LFS. Também pode especificar um destino personalizado se os dados do repositório LFS forem armazenados noutro lugar. @@ -976,7 +977,7 @@ migrate.migrating_releases=Migrando lançamentos migrate.migrating_issues=Migrando questões migrate.migrating_pulls=Migrando pedidos de integração -mirror_from=espelho de +mirror_from=réplica de forked_from=derivado de generated_from=gerado a partir de fork_from_self=Não pode criar uma derivação de um repositório que já é seu. @@ -1010,6 +1011,7 @@ tags=Etiquetas issues=Questões pulls=Pedidos de integração project_board=Planeamentos +packages=Pacotes labels=Rótulos org_labels_desc=Rótulos ao nível da organização que podem ser usados em todos os repositórios desta organização org_labels_desc_manage=gerir @@ -1040,6 +1042,7 @@ line_unicode=`Esta linha tem caracteres unicode escondidos` escape_control_characters=Revelar unescape_control_characters=Esconder file_copy_permalink=Copiar ligação permanente +view_git_blame=Ver Git Blame video_not_supported_in_browser=O seu navegador não suporta a etiqueta 'video' do HTML5. audio_not_supported_in_browser=O seu navegador não suporta a etiqueta 'audio' do HTML5. stored_lfs=Armazenado com Git LFS @@ -1187,7 +1190,7 @@ projects.close=Fechar projects.board.assigned_to=Atribuído a issues.desc=Organize relatórios de erros, tarefas e etapas. -issues.filter_assignees=Filtrar responsável +issues.filter_assignees=Filtrar encarregado issues.filter_milestones=Filtrar etapa issues.filter_projects=Filtrar planeamento issues.filter_labels=Filtrar rótulo @@ -1211,10 +1214,10 @@ issues.new.no_milestone=Sem etapa issues.new.clear_milestone=Limpar etapa issues.new.open_milestone=Etapas abertas issues.new.closed_milestone=Etapas fechadas -issues.new.assignees=Responsáveis -issues.new.add_assignees_title=Definir responsáveis -issues.new.clear_assignees=Limpar responsáveis -issues.new.no_assignees=Sem responsáveis +issues.new.assignees=Encarregados +issues.new.add_assignees_title=Definir encarregados +issues.new.clear_assignees=Retirar todos os encarregados +issues.new.no_assignees=Sem encarregados issues.new.no_reviewers=Sem revisores issues.new.add_reviewer_title=Solicitar revisão issues.choose.get_started=Começar @@ -1260,8 +1263,8 @@ issues.filter_label_exclude=`Use alt + clique/enter pa issues.filter_label_no_select=Todos os rótulos issues.filter_milestone=Etapa issues.filter_milestone_no_select=Todas as etapas -issues.filter_assignee=Responsável -issues.filter_assginee_no_select=Todos os responsáveis +issues.filter_assignee=Encarregado +issues.filter_assginee_no_select=Todos os encarregados issues.filter_type=Tipo issues.filter_type.all_issues=Todas as questões issues.filter_type.assigned_to_you=Atribuídas a si @@ -1287,8 +1290,8 @@ issues.action_close=Fechar issues.action_label=Rótulo issues.action_milestone=Etapa issues.action_milestone_no_select=Sem etapa -issues.action_assignee=Responsável -issues.action_assignee_no_select=Sem responsável +issues.action_assignee=Encarregado +issues.action_assignee_no_select=Sem encarregado issues.opened_by=aberta %[1]s por %[3]s pulls.merged_by=por %[3]s foi executado %[1]s pulls.merged_by_fake=por %[2]s foi executado %[1]s @@ -1460,6 +1463,7 @@ issues.review.add_review_request=solicitou revisão de %s %s issues.review.remove_review_request=removeu a solicitação de revisão para %s %s issues.review.remove_review_request_self=recusou-se a rever %s issues.review.pending=Pendente +issues.review.pending.tooltip=Este comentário não está visível para os outros utilizadores, neste momento. Para submeter os seus comentários pendentes, escolha '%s' -> '%s/%s/%s' no topo da página. issues.review.review=Revisão issues.review.reviewers=Revisores issues.review.outdated=Obsoleta @@ -1470,7 +1474,7 @@ issues.review.hide_resolved=Ocultar os concluídos issues.review.resolve_conversation=Passar diálogo ao estado de resolvido issues.review.un_resolve_conversation=Passar diálogo ao estado de não resolvido issues.review.resolved_by=marcou este diálogo como estando concluído -issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado. +issues.assignee.error=Nem todos os encarregados foram adicionados devido a um erro inesperado. issues.reference_issue.body=Conteúdo issues.content_history.deleted=eliminado issues.content_history.edited=editado @@ -1487,6 +1491,7 @@ pulls.desc=Habilitar pedidos de integração e revisão de código. pulls.new=Novo pedido de integração pulls.view=Ver pedido de integração pulls.compare_changes=Novo pedido de integração +pulls.allow_edits_from_maintainers=Permitir edições por parte dos responsáveis pulls.allow_edits_from_maintainers_desc=Utilizadores com acesso de escrita no ramo base também podem fazer envios para este ramo pulls.allow_edits_from_maintainers_err=Não foi possível fazer a modificação pulls.compare_changes_desc=Escolha o ramo de destino e o ramo de origem. @@ -1556,18 +1561,18 @@ pulls.no_merge_access=Não tem autorização para executar a integração consta pulls.merge_pull_request=Criar um cometimento de integração pulls.rebase_merge_pull_request=Mudar a base e avançar rapidamente pulls.rebase_merge_commit_pull_request=Mudar a base e criar um cometimento de integração -pulls.squash_merge_pull_request=Criar cometimento de compressão +pulls.squash_merge_pull_request=Criar cometimento de compactação pulls.merge_manually=Integrado manualmente pulls.merge_commit_id=O ID de cometimento da integração pulls.require_signed_wont_sign=O ramo requer que os cometimentos sejam assinados mas esta integração não vai ser assinada pulls.merge_pull_request_now=Executar agora a integração constante no pedido pulls.rebase_merge_pull_request_now=Mudar a base e integrar agora pulls.rebase_merge_commit_pull_request_now=Mudar a base e integrar agora (--no-ff) -pulls.squash_merge_pull_request_now=Condensar e integrar agora +pulls.squash_merge_pull_request_now=Compactar e integrar agora pulls.merge_pull_request_on_status_success=Executar a integração constante no pedido quando todas as verificações forem bem sucedidas pulls.rebase_merge_pull_request_on_status_success=Mudar a base e integrar quando todas as verificações forem bem sucedidas pulls.rebase_merge_commit_pull_request_on_status_success=Mudar a base e integrar (--no-ff) quando todas as verificações forem bem sucedidas -pulls.squash_merge_pull_request_on_status_success=Condensar e integrar quando todas as verificações forem bem sucedidas +pulls.squash_merge_pull_request_on_status_success=Compactar e integrar quando todas as verificações forem bem sucedidas pulls.invalid_merge_option=Não pode usar esta opção de integração neste pedido de integração. pulls.merge_conflict=A integração falhou: Houve um conflito durante a integração. Dica: tente uma estratégia diferente pulls.merge_conflict_summary=Mensagem de erro @@ -1702,8 +1707,8 @@ activity.title.prs_1=%d pedido de integração activity.title.prs_n=%d Pedidos de integração activity.title.prs_merged_by=%s executado(s) por %s activity.title.prs_opened_by=%s proposto por %s -activity.merged_prs_label=Integrados -activity.opened_prs_label=Propostos +activity.merged_prs_label=Integrado +activity.opened_prs_label=Proposto activity.active_issues_count_1=%d questão vigente activity.active_issues_count_n=%d questões vigentes activity.closed_issues_count_1=questão encerrada @@ -1766,18 +1771,18 @@ settings.collaboration.undefined=Não definido settings.hooks=Automatismos web settings.githooks=Automatismos do Git settings.basic_settings=Configurações básicas -settings.mirror_settings=Configurações do espelhamento -settings.mirror_settings.docs=Configure o seu repositório para puxar e/ou enviar automaticamente as modificações de/para outro repositório. Ramos, etiquetas e cometimentos serão sincronizados automaticamente. Como é que eu faço um espelho de outro repositório? -settings.mirror_settings.mirrored_repository=Repositório espelhado +settings.mirror_settings=Configurações da réplica +settings.mirror_settings.docs=Configure o seu repositório para puxar e/ou enviar automaticamente as modificações de/para outro repositório. Ramos, etiquetas e cometimentos serão sincronizados automaticamente. Como é que eu faço uma réplica de outro repositório? +settings.mirror_settings.mirrored_repository=Repositório replicado settings.mirror_settings.direction=Sentido settings.mirror_settings.direction.pull=Puxada settings.mirror_settings.direction.push=Envio settings.mirror_settings.last_update=Última modificação -settings.mirror_settings.push_mirror.none=Não foram configurados quaisquer espelhos de envio +settings.mirror_settings.push_mirror.none=Não foram configuradas quaisquer réplicas de envio settings.mirror_settings.push_mirror.remote_url=URL do repositório remoto Git -settings.mirror_settings.push_mirror.add=Adicionar espelho de envio +settings.mirror_settings.push_mirror.add=Adicionar réplica de envio settings.sync_mirror=Sincronizar agora -settings.mirror_sync_in_progress=A sincronização do espelho está em andamento. Volte a verificar daqui a um minuto. +settings.mirror_sync_in_progress=A sincronização da réplica está em andamento. Volte a verificar daqui a um minuto. settings.email_notifications.enable=Habilitar notificações por email settings.email_notifications.onmention=Enviar email somente quando mencionado(a) settings.email_notifications.disable=Desabilitar notificações por email @@ -1811,7 +1816,7 @@ settings.pulls.ignore_whitespace=Ignorar espaços em branco nos conflitos settings.pulls.allow_merge_commits=Habilitar integração de cometimentos settings.pulls.allow_rebase_merge=Habilitar cometimentos de mudança de base para integrar settings.pulls.allow_rebase_merge_commit=Habilitar mudança de base com cometimentos de integração explícitos (--no-ff) -settings.pulls.allow_squash_commits=Habilitar cometimentos de condensação para integrar +settings.pulls.allow_squash_commits=Habilitar cometimentos de compactar para integrar settings.pulls.allow_manual_merge=Habilitar a marcação dos pedidos de integração como tendo sido executados manualmente settings.pulls.enable_autodetect_manual_merge=Habilitar a identificação automática de integrações manuais (obs.: nalguns casos especiais a avaliação pode ser errada) settings.pulls.allow_rebase_update=Habilitar a modificação do ramo do pedido de integração através da mudança de base @@ -1830,10 +1835,10 @@ settings.admin_enable_close_issues_via_commit_in_any_branch=Fechar uma questão settings.danger_zone=Zona de perigo settings.new_owner_has_same_repo=O novo dono já tem um repositório com o mesmo nome. Por favor, escolha outro nome. settings.convert=Converter para um repositório normal -settings.convert_desc=Pode converter este espelho num repositório normal. Esta operação não pode ser revertida. -settings.convert_notices_1=Esta operação irá converter o espelho num repositório normal e não poderá ser revertida. +settings.convert_desc=Pode converter esta réplica num repositório normal. Esta operação não pode ser revertida. +settings.convert_notices_1=Esta operação irá converter a réplica num repositório normal e não poderá ser revertida. settings.convert_confirm=Converter repositório -settings.convert_succeed=O espelho foi convertido num repositório normal. +settings.convert_succeed=A réplica foi convertida num repositório normal. settings.convert_fork=Converter para um repositório normal settings.convert_fork_desc=Pode converter esta derivação num repositório normal. Esta operação não pode ser revertida. settings.convert_fork_notices_1=Esta operação irá converter a derivação num repositório normal e não poderá ser revertida. @@ -1952,7 +1957,7 @@ settings.event_header_issue=Eventos da questão settings.event_issues=Questões settings.event_issues_desc=Questão aberta, fechada, reaberta ou editada. settings.event_issue_assign=Questão atribuída -settings.event_issue_assign_desc=Responsável atribuído ou retirado à questão. +settings.event_issue_assign_desc=Encarregado atribuído ou retirado à questão. settings.event_issue_label=Questão com rótulo settings.event_issue_label_desc=Rótulos modificados ou retirados às questões. settings.event_issue_milestone=Questão com etapa atribuída @@ -1962,8 +1967,8 @@ settings.event_issue_comment_desc=Comentário da questão criado, editado ou eli settings.event_header_pull_request=Eventos de pedidos de integração settings.event_pull_request=Pedido de integração settings.event_pull_request_desc=Pedido de integração aberto, fechado, reaberto ou editado. -settings.event_pull_request_assign=Responsável atribuído ao pedido de integração -settings.event_pull_request_assign_desc=Responsável atribuído ou retirado ao pedido de integração. +settings.event_pull_request_assign=Encarregado atribuído ao pedido de integração +settings.event_pull_request_assign_desc=Encarregado atribuído ou retirado ao pedido de integração. settings.event_pull_request_label=Rótulo atribuído ao pedido de integração settings.event_pull_request_label_desc=Rótulos modificados ou retirados aos pedidos de integração. settings.event_pull_request_milestone=Etapa atribuída ao pedido de integração @@ -2099,7 +2104,7 @@ settings.archive.header=Arquivar este repositório settings.archive.text=Arquivar um repositório fará com que fique inteira e exclusivamente de leitura. Não ficará visível no painel de controlo, não poderá receber cometimentos e não será possível criar questões ou pedidos de integração. settings.archive.success=O repositório foi arquivado com sucesso. settings.archive.error=Ocorreu um erro enquanto decorria o processo de arquivo do repositório. Veja os registo para obter mais detalhes. -settings.archive.error_ismirror=Não pode arquivar um repositório que tenha sido espelhado. +settings.archive.error_ismirror=Não pode arquivar um repositório que tenha sido replicado. settings.archive.branchsettings_unavailable=As configurações dos ramos não estão disponíveis quando o repositório está arquivado. settings.archive.tagsettings_unavailable=As configurações sobre etiquetas não estão disponíveis quando o repositório está arquivado. settings.unarchive.button=Desarquivar repositório @@ -2418,7 +2423,7 @@ dashboard.new_version_hint=O Gitea %s está agora disponível, você está a cor dashboard.statistic=Resumo dashboard.operations=Operações de manutenção dashboard.system_status=Estado do sistema -dashboard.statistic_info=A base de dados do Gitea contém %d utilizadores, %d organizações, %d chaves públicas, %d repositórios, %d vigilâncias, %d marcas de favoritos, %d operações, %d acessos, %d questões, %d comentários, %d contas sociais, %d seguimentos, %d espelhos, %d lançamentos, %d fontes de autenticação, %d automatismos web, %d etapas, %d rótulos, %d tarefas de automatismos %d equipas, %d tarefas de modificações e %d anexos. +dashboard.statistic_info=A base de dados do Gitea tem %d utilizadores, %d organizações, %d chaves públicas, %d repositórios, %d vigilâncias, %d marcas de favoritos, ~%d operações, %d acessos, %d questões, %d comentários, %d contas sociais, %d seguimentos, %d réplicas, %d lançamentos, %d fontes de autenticação, %d automatismos web, %d etapas, %d rótulos, %d tarefas de automatismos %d equipas, %d tarefas de modificações e %d anexos. dashboard.operation_name=Nome da operação dashboard.operation_switch=Comutar dashboard.operation_run=Executar @@ -2442,7 +2447,7 @@ dashboard.delete_repo_archives.started=Foi iniciada a tarefa de eliminação de dashboard.delete_missing_repos=Eliminar todos os repositórios que não tenham os seus ficheiros Git dashboard.delete_missing_repos.started=Foi iniciada a tarefa de eliminação de todos os repositórios que não têm ficheiros git. dashboard.delete_generated_repository_avatars=Eliminar avatares gerados do repositório -dashboard.update_mirrors=Sincronizar espelhos +dashboard.update_mirrors=Sincronizar réplicas dashboard.repo_health_check=Verificar a saúde de todos os repositórios dashboard.check_repo_stats=Verificar as estatísticas de todos os repositórios dashboard.archive_cleanup=Eliminar arquivos de repositórios antigos @@ -2525,6 +2530,7 @@ users.allow_import_local=Pode importar repositórios locais users.allow_create_organization=Pode criar organizações users.update_profile=Modificar conta do utilizador users.delete_account=Eliminar conta de utilizador +users.cannot_delete_self=Não se pode eliminar a si próprio users.still_own_repo=Este utilizador ainda possui um ou mais repositórios. Elimine ou transfira esses repositórios primeiro. users.still_has_org=Este utilizador é membro de uma organização. Remova, primeiro, o utilizador de todas as organizações. users.still_own_packages=Este utilizador ainda possui um ou mais pacotes. Elimine esses pacotes primeiro. @@ -2583,6 +2589,7 @@ packages.version=Versão packages.type=Tipo packages.repository=Repositório packages.size=Tamanho +packages.published=Publicado defaulthooks=Automatismos web padrão defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os padrões e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web. @@ -2827,7 +2834,7 @@ config.git_max_diff_line_characters=Número máximos de caracteres diff (por lin config.git_max_diff_files=Número máximo de ficheiros diff a serem apresentados config.git_gc_args=Argumentos da recolha de lixo config.git_migrate_timeout=Prazo da migração -config.git_mirror_timeout=Tempo limite do espelhamento +config.git_mirror_timeout=Tempo limite da réplica config.git_clone_timeout=Prazo da operação de clonagem config.git_pull_timeout=Prazo da operação de puxar config.git_gc_timeout=Prazo da operação de recolha de lixo @@ -2851,6 +2858,8 @@ monitor.next=Próxima execução monitor.previous=Execução anterior monitor.execute_times=Execuções monitor.process=Processos em execução +monitor.stacktrace=Vestígios da pilha +monitor.goroutines=%d Goroutines monitor.desc=Descrição monitor.start=Início monitor.execute_time=Tempo de execução @@ -2954,9 +2963,9 @@ delete_branch=eliminou o ramo %[2]s de %[3]s compare_branch=Comparar compare_commits=Comparar %d comentimentos compare_commits_general=Comparar comentimentos -mirror_sync_push=sincronizou os cometimentos para %[3]s em %[4]s do espelho -mirror_sync_create=sincronizou a nova referência %[3]s para %[4]s do espelho -mirror_sync_delete=sincronizou e eliminou a referência %[2]s em %[3]s do ficheiro +mirror_sync_push=sincronizou os cometimentos para %[3]s em %[4]s da réplica +mirror_sync_create=sincronizou a nova referência %[3]s para %[4]s da réplica +mirror_sync_delete=sincronizou e eliminou a referência %[2]s em %[3]s da réplica approve_pull_request=`aprovou %[3]s#%[2]s` reject_pull_request=`sugeriu modificações para %[3]s#%[2]s` publish_release=`lançou "%[4]s" em %[3]s` @@ -3029,6 +3038,8 @@ empty.documentation=Para obter mais informação sobre o registo de pacotes, vej filter.type=Tipo filter.type.all=Todos filter.no_result=O seu filtro não produziu quaisquer resultados. +filter.container.tagged=Com etiqueta +filter.container.untagged=Sem etiqueta published_by=Publicado %[1]s por %[3]s published_by_in=Publicado %[1]s por %[3]s em %[5]s installation=Instalação @@ -3038,9 +3049,11 @@ dependencies=Dependências keywords=Palavras-chave details=Detalhes details.author=Autor(a) +details.project_site=Página web do projecto details.license=Licença assets=Recursos versions=Versões +versions.on=ligado versions.view_all=Ver todas dependency.id=ID dependency.version=Versão @@ -3060,6 +3073,7 @@ container.details.documentation_site=Página web da documentação container.pull=Puxar a imagem usando a linha de comandos: container.documentation=Para obter mais informações sobre o registo do Container, consulte a documentação. container.multi_arch=S.O. / Arquit. +container.layers=Camadas de imagem container.labels=Rótulos container.labels.key=Chave container.labels.value=Valor @@ -3076,15 +3090,22 @@ maven.documentation=Para obter mais informações sobre o registo do Maven, cons nuget.registry=Configurar este registo usando a linha de comandos: nuget.install=Para instalar o pacote usando NuGet, execute o seguinte comando: nuget.documentation=Para obter mais informações sobre o registo do Nuget, consulte a documentação. +nuget.dependency.framework=Estrutura alvo +npm.registry=Configure este registo no seu ficheiro .npmrc do projecto: npm.install=Para instalar o pacote usando o npm, execute o seguinte comando: +npm.install2=ou adicione-o ao ficheiro package.json: npm.documentation=Para obter mais informações sobre o registo do npm, consulte a documentação. npm.dependencies=Dependências npm.dependencies.development=Dependências de desenvolvimento +npm.dependencies.peer=Dependências de pares npm.dependencies.optional=Dependências opcionais +npm.details.tag=Etiqueta pypi.requires=Requer Python pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando: pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação. rubygems.install=Para instalar o pacote usando o gem, execute o seguinte comando: +rubygems.install2=ou adicione-o ao ficheiro Gemfile: +rubygems.dependencies.runtime=Dependências do tempo de execução (runtime) rubygems.dependencies.development=Dependências de desenvolvimento rubygems.documentation=Para obter mais informações sobre o registo do RubyGems, consulte a documentação. settings.link=Vincular este pacote a um repositório diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index bf29e2b411..62399104dd 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -851,7 +851,6 @@ default_branch=Ветка по умолчанию default_branch_helper=Ветка по умолчанию является базовой веткой для запросов на слияние и коммитов кода. mirror_prune=Очистить mirror_prune_desc=Удаление устаревших отслеживаемых ссылок -mirror_interval=Интервал зеркалирования (допустимые единицы измерения 'h', 'm', 's'). Значение 0 отключает синхронизацию. mirror_interval_invalid=Недопустимый интервал зеркалирования. mirror_address=Клонировать по URL mirror_address_desc=Поместите необходимые учетные данные в секцию авторизации. @@ -922,7 +921,6 @@ need_auth=Авторизация migrate_options=Параметры миграции migrate_service=Сервис миграции migrate_options_mirror_helper=Этот репозиторий будет зеркалом -migrate_options_mirror_disabled=Администратор вашего сайта отключил новые зеркала. migrate_options_lfs=Перенос LFS файлов migrate_options_lfs_endpoint.label=LFS Endpoint migrate_options_lfs_endpoint.description=Миграция попытается использовать ваш Git удаленно, чтобы определить сервер LFS. Вы также можете указать пользовательскую конечную точку, если данные хранятся в другом месте. @@ -2341,7 +2339,6 @@ total=Всего: %d dashboard.statistic=Статистика dashboard.operations=Операции dashboard.system_status=Статус системного монитора -dashboard.statistic_info=В базе данных Gitea записано %d пользователей, %d организаций, %d публичных ключей, %d репозиториев, %d подписок на репозитории, %d добавлений в избранное, %d действий, %d доступов, %d задач, %d комментариев, %d социальных учетных записей, %d подписок на пользователей, %d зеркал, %d релизов, %d источников входа, %d вебхуков, %d этапов, %d меток, %d задач hook'ов, %d команд, %d задач по обновлению, %d присоединённых файлов. dashboard.operation_name=Имя операции dashboard.operation_switch=Переключить dashboard.operation_run=Запуск diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index f9aef5317c..70463997d3 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -778,7 +778,6 @@ default_branch=පෙරනිමි ශාඛාව default_branch_helper=පෙරනිමි ශාඛාව යනු අදින්න ඉල්ලීම් සහ කේත විවරණය සඳහා මූලික ශාඛාවයි. mirror_prune=කප්පාදු mirror_prune_desc=යල්පැන ගිය දුරස්ථ-ෙසොයා ගැනීෙම් යොමු ඉවත් කරන්න -mirror_interval=මිරර් පරතරය (වලංගු කාල ඒකක 'h', 'm', 's'). ස්වයංක්රීය සමමුහුර්ත අක්රිය කිරීමට 0. mirror_interval_invalid=දර්පණ පරතරය වලංගු නොවේ. mirror_address=URL එකෙන් පරිගණක ක්රිඩාවට සමාන mirror_address_desc=අවශ්ය ඕනෑම අක්තපත්ර බලය පැවරීමේ අංශයට දමන්න. @@ -823,7 +822,6 @@ template.topics=මාතෘකා -migrate_options_mirror_disabled=ඔබේ වෙබ් අඩවිය පරිපාලක නව දර්පණ අක්රීය කර ඇත. migrate_options_lfs=LFS ගොනු සංක්රමණය migrate_options_lfs_endpoint.label=LFS එන්පොයින්ට් migrate_options_lfs_endpoint.description=සංක්රමණය ඔබගේ Git දුරස්ථ භාවිතා කිරීමට උත්සාහ කරනු ඇත LFS සේවාදායකය තීරණය. නිධිය LFS දත්ත වෙන කොහේ හරි ගබඩා කර තිබේ නම් ඔබට අභිරුචි අන්ත ලක්ෂ්යයක් නියම කළ හැකිය. @@ -2182,7 +2180,6 @@ total=මුළු: %d dashboard.statistic=සාරාංශය dashboard.operations=නඩත්තු මෙහෙයුම් dashboard.system_status=පද්ධතියේ තත්වය -dashboard.statistic_info=Gitea දත්ත සමුදාය %d පරිශීලකයින්, %d ආයතන, %d පොදු යතුරු, %d ගබඩාව, %d ඔරලෝසු, %d තරු, %d ක්රියාවන්, %d ප්රවේශ, %d ගැටළු, %d අදහස්, %d සමාජ ගිණුම්, %d පහත සඳහන්, %d දර්පණ, %d නිකුත් කිරීම්, %d සත්යාපන ප්රභවයන්, %d වෙබ් කොකු, %d සන්ධිස්ථාන, %d ලේබල්, %d කොක්කෙන් කාර්යයන්, %d කණ්ඩායම්, %d යාවත්කාලීන කාර්යයන්, %d ඇමුණුම්. dashboard.operation_name=මෙහෙයුමේ නම dashboard.operation_switch=මාරුවන්න dashboard.operation_run=ධාවනය diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index e111a81d6a..831607e80f 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -657,7 +657,6 @@ create_repo=Skapa utvecklingskatalog default_branch=Standardgren mirror_prune=Rensa mirror_prune_desc=Ta bort förlegade fjärrföljande referenser -mirror_interval=Intervall för spegling (giltiga enheter är 'h', 'm', 's'). 0 stänger av automatisk synkronisering. mirror_interval_invalid=Speglingsintervallen är inte giltig. mirror_address=Klona Från URL mirror_address_url_invalid=Den angivna webbadressen är ogiltig. Du måste "escapa" alla delar av webbadressen korrekt. @@ -704,7 +703,6 @@ form.name_pattern_not_allowed=Mönstret '%s' är otillåtet i ett utvecklingskat migrate_options=Migrationsalternativ migrate_service=Migreringstjänst migrate_options_mirror_helper=Denna utvecklingskatalog kommer att vara en spegel -migrate_options_mirror_disabled=Din webbplatsadministratör har inaktiverat nya speglar. migrate_items=Migrationsobjekt migrate_items_wiki=Wiki migrate_items_milestones=Milstenar @@ -1743,7 +1741,6 @@ total=Totalt: %d dashboard.statistic=Översikt dashboard.operations=Operationer för underhåll dashboard.system_status=Status -dashboard.statistic_info=Gitea-databasen innehåller %d användare, %d organisationer, %d publika nyckar, %d utvecklingskataloger, %d bevakare, %d stjärnor, %d åtgärder, %d åtkomster, %d ärenden, %d kommentarer, %d sociala konton, %d följare, %d speglingar, %d releaser, %d autensieringskällor, %d webhooks, %d milstolpar, %d etiketter, %d hook-tjänster, %d teams, %d uppdateringstjänster, %d bilagor. dashboard.operation_name=Operationsnamn dashboard.operation_switch=Byt till dashboard.operation_run=Kör diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index df54622e43..7950b3b63f 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -780,7 +780,6 @@ default_branch=Varsayılan Dal default_branch_helper=Varsayılan dal, değişiklik istekleri ve kod işlemeleri için temel daldır. mirror_prune=Buda mirror_prune_desc=Kullanılmayan uzak depoları izleyen referansları kaldır -mirror_interval=Yansı Aralığı (geçerli zaman birimleri 'h', 'm', 's'). 0 otomatik senkronizasyonu devre dışı bırakmak için. mirror_interval_invalid=Yansı süre aralığı geçerli değil. mirror_address=URL'den Klonla mirror_address_desc=Yetkilendirme bölümüne gerekli tüm kimlik bilgilerini girin. @@ -850,7 +849,6 @@ need_auth=Yetkilendirme migrate_options=Göç Seçenekleri migrate_service=Göç Hizmeti migrate_options_mirror_helper=Bu depo bir yansı olacaktır -migrate_options_mirror_disabled=Site yöneticiniz yeni yansıları devre dışı bıraktı. migrate_options_lfs=LFS dosyalarını taşı migrate_options_lfs_endpoint.label=LFS Uç Noktası migrate_options_lfs_endpoint.description=Taşıma, LFS sunucusunu belirlemek için Git uzak sunucusunu kullanmaya çalışacak. Eğer LFS veri deposu başka yerdeyse özel bir uç nokta da belirtebilirsiniz. @@ -2193,7 +2191,6 @@ total=Toplam: %d dashboard.statistic=Özet dashboard.operations=Bakım İşlemleri dashboard.system_status=Sistem Durumu -dashboard.statistic_info=Gitea veritabanında %d kullanıcı, %d organizasyon, %d açık anahtar, %d depo, %d izleme, %d yıldız, %d eylem, %d erişim, %d konu, %d yorum, %d sosyal hesap, %d takip, %d yansı, %d sürüm, %d kimlik doğrulama kaynağı, %d web istemcisi, %d kilometre taşı, %d etiket, %d istemci görevi, %d takım, %d güncelleme görevi, %d ek bulunuyor. dashboard.operation_name=İşlem Adı dashboard.operation_switch=Geç dashboard.operation_run=Çalıştır diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 1b320c9463..e7b21a02bf 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -804,7 +804,6 @@ default_branch=Головна гілка default_branch_helper=Гілка за замовчуванням є базовою гілкою для запитів на злиття та комітів коду. mirror_prune=Очистити mirror_prune_desc=Видалення застарілих посилань які ви відслідковуєте -mirror_interval=Інтервал дзеркалювання (допустимі значення 'h', 'm', 's'). 0 - щоб вимкнути автоматичну синхронізацію. mirror_interval_invalid=Інтервал дзеркалювання є неприпустимим. mirror_address=Клонування з URL-адреси mirror_address_desc=Помістіть будь-які необхідні облікові дані у розділі Авторизація. @@ -874,7 +873,6 @@ need_auth=Авторизація migrate_options=Параметри міграції migrate_service=Сервіс міграції migrate_options_mirror_helper=Цей репозиторій буде дзеркалом -migrate_options_mirror_disabled=Адміністратор вашого сайту вимкнув створення нових дзеркал. migrate_options_lfs=Перенесення LFS файлів migrate_options_lfs_endpoint.label=Кінцева точка LFS migrate_options_lfs_endpoint.description=Міграція буде намагатися використовувати ваш Git віддалено, щоб визначати LFS сервер. Ви також можете вказати свою кінцеву точку, якщо дані репозиторію LFS зберігаються в іншому місці. @@ -2254,7 +2252,6 @@ total=Разом: %d dashboard.statistic=Підсумок dashboard.operations=Технічне обслуговування dashboard.system_status=Статус системи -dashboard.statistic_info=У базі даних Gitea записано %d користувачів, %d організацій, %d публічних ключів, %d репозиторіїв, %d підписок на репозиторії, %d додавань в обране, %d дій, %d доступів, %d задач, %d коментарів, %d соціальних облікових записів, %d підписок на користувачів, %d зеркал, %d релізів, %d джерел входу, %d веб-хуків, %d етапів, %d міток, %d задач хуків, %d команд, %d задач по оновленню, %d приєднаних файлів. dashboard.operation_name=Назва операції dashboard.operation_switch=Перемкнути dashboard.operation_run=Запустити diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 7a5d8250e5..65eb3b2c56 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -2,11 +2,12 @@ home=首页 dashboard=首页 explore=探索 help=帮助 +logo=徽标 sign_in=登录 sign_in_with=登录方式 sign_out=退出 sign_up=注册 -link_account=链接帐户 +link_account=链接账户 register=注册 website=官方网站 version=当前版本 @@ -41,7 +42,7 @@ webauthn_use_twofa=使用来自手机中的两步验证码 webauthn_error=无法读取安全密钥。 webauthn_unsupported_browser=你的浏览器目前不支持 WebAuthn。 webauthn_error_unknown=发生未知错误。请重试。 -webauthn_error_insecure=WebAuthn 仅支持安全连接。如果要在 HTTP 协议上进行测试,请使用 "localhost" 或 "127.0.0.0.1" 作为访问来源 +webauthn_error_insecure=WebAuthn 仅支持安全连接。如果要在 HTTP 协议上进行测试,请使用 "localhost" 或 "127.0.0.1" 作为访问来源 webauthn_error_unable_to_process=服务器无法处理您的请求。 webauthn_error_duplicated=此安全密钥未被许可用于这个请求。请确保该密钥尚未注册。 webauthn_error_empty=您必须为此密钥设置一个名称。 @@ -105,6 +106,7 @@ error404=您正尝试访问的页面 不存在您 never=从不 +rss_feed=RSS 订阅源 [error] occurred=发生了一个错误 @@ -777,6 +779,7 @@ webauthn_delete_key_desc=如果删除了安全密钥,则不能再使用它登 manage_account_links=管理绑定过的账号 manage_account_links_desc=这些外部帐户已经绑定到您的 Gitea 帐户。 account_links_not_available=当前没有与您的 Gitea 帐户绑定的外部帐户。 +link_account=链接账户 remove_account_link=删除已绑定的账号 remove_account_link_desc=删除已绑定帐户将吊销其对您的 Gitea 帐户的访问权限。继续? remove_account_link_success=已取消绑定帐户。 @@ -857,7 +860,7 @@ default_branch=默认分支 default_branch_helper=默认分支是用于合并请求和代码提交的基础分支。 mirror_prune=修剪 mirror_prune_desc=删除过时的远程跟踪引用 -mirror_interval=镜像间隔 (有效时间单位为 "h"、"m"、"s")。0将禁用自动同步。 +mirror_interval=镜像间隔 (有效的时间单位是 'h', 'm', 's')。0 禁用自动同步 (最短间隔: %s) mirror_interval_invalid=镜像间隔无效。 mirror_address=从URL克隆 mirror_address_desc=在授权框中输入必要的凭据。 @@ -928,7 +931,6 @@ need_auth=授权 migrate_options=迁移选项 migrate_service=迁移服务 migrate_options_mirror_helper=该仓库将是一个 镜像 -migrate_options_mirror_disabled=您的站点管理员已禁用创建新镜像。 migrate_options_lfs=迁移 LFS 文件 migrate_options_lfs_endpoint.label=LFS 网址 migrate_options_lfs_endpoint.description=迁移将尝试使用你的 Git remote 来 确定 LFS 服务器。如果仓库 LFS 数据存储在其他位置,你还可以指定自定义网址。 @@ -1010,6 +1012,7 @@ tags=标签列表 issues=工单 pulls=合并请求 project_board=项目 +packages=软件包 labels=标签 org_labels_desc=组织级别的标签,可以被本组织下的 所有仓库 使用 org_labels_desc_manage=管理 @@ -1040,6 +1043,7 @@ line_unicode=`这一行有隐藏的 Unicode 字符` escape_control_characters=Escape unescape_control_characters=Unescape file_copy_permalink=复制永久链接 +view_git_blame=查看 Git Blame video_not_supported_in_browser=您的浏览器不支持使用 HTML5 'video' 标签。 audio_not_supported_in_browser=您的浏览器不支持使用 HTML5 'video' 标签。 stored_lfs=存储到Git LFS @@ -1402,21 +1406,21 @@ issues.add_time_sum_to_small=没有输入时间。 issues.time_spent_total=总用时 issues.time_spent_from_all_authors=`总花费时间:%s` issues.due_date=到期时间 -issues.invalid_due_date_format=到期时间的格式错误,必须是 'yyyy-mm-dd' 的形式。 -issues.error_modifying_due_date=未能修改到期时间。 -issues.error_removing_due_date=未能删除到期时间。 +issues.invalid_due_date_format=到期时间的格式必须是 'yyyy-mm-dd' 的形式。 +issues.error_modifying_due_date=修改到期时间失败。 +issues.error_removing_due_date=删除到期时间失败。 issues.push_commit_1=于 %[2]s 推送了 %[1]d 个提交 issues.push_commits_n=于 %[2]s 推送了 %[1]d 个提交 issues.force_push_codes=`于 %[6]s 强制推送 %[1]s,从 %[2]s,至 %[4]s` issues.due_date_form=yyyy年mm月dd日 -issues.due_date_form_add=添加到期时间 +issues.due_date_form_add=设置到期时间 issues.due_date_form_edit=编辑 issues.due_date_form_remove=删除 -issues.due_date_not_writer=你需要仓库写入权限来更新工单到期时间。 +issues.due_date_not_writer=你需要仓库写入权限来修改工单到期时间。 issues.due_date_not_set=未设置到期时间。 -issues.due_date_added=到期时间 %s %s 已添加 -issues.due_date_modified=已将到期时间从 %s %s 修改为 %s -issues.due_date_remove=到期时间 %s %s 已删除 +issues.due_date_added=于 %[2]s 设置到期时间为 %[1]s +issues.due_date_modified=于 %[3]s 将到期时间从 %[2]s 修改为 %[1]s +issues.due_date_remove=于 %[2]s 删除了到期时间 %[1]s issues.due_date_overdue=过期 issues.due_date_invalid=到期日期无效或超出范围。请使用 'yyyy-mm-dd' 格式。 issues.dependency.title=依赖工单 @@ -1460,6 +1464,7 @@ issues.review.add_review_request=于 %[2]s 请求 %[1]s 评审 issues.review.remove_review_request=取消对 %s 的评审请求 %s issues.review.remove_review_request_self=拒绝审核 %s issues.review.pending=待定 +issues.review.pending.tooltip=此评论目前对其他用户不可见。 若要提交您的待定评论,请在页面顶部选择 '%s' -> '%s/%s/%s'。 issues.review.review=评审 issues.review.reviewers=评审人 issues.review.outdated=已过期 @@ -1478,6 +1483,7 @@ issues.content_history.created=创建于 issues.content_history.delete_from_history=从历史记录中删除 issues.content_history.delete_from_history_confirm=从历史记录中删除吗? issues.content_history.options=选项 +issues.reference_link=参考:%s compare.compare_base=基准分支 compare.compare_head=比较 @@ -1486,7 +1492,13 @@ pulls.desc=启用合并请求和代码评审。 pulls.new=创建合并请求 pulls.view=查看拉取请求 pulls.compare_changes=创建合并请求 +pulls.allow_edits_from_maintainers=允许维护者编辑 +pulls.allow_edits_from_maintainers_desc=对基础分支有写入权限的用户也可以推送到此分支 +pulls.allow_edits_from_maintainers_err=更新失败 pulls.compare_changes_desc=选择合并的目标分支和源分支。 +pulls.has_viewed_file=已查看 +pulls.has_changed_since_last_review=自您上次审核以来已更改 +pulls.viewed_files_label=%[1]d / %[2]d 文件已查看 pulls.compare_base=合并到 pulls.compare_compare=拉取从 pulls.switch_comparison_type=切换比较类型 @@ -1554,6 +1566,14 @@ pulls.squash_merge_pull_request=创建压缩提交 pulls.merge_manually=手动合并 pulls.merge_commit_id=合并提交 ID pulls.require_signed_wont_sign=分支需要签名的提交,但这个合并将不会被签名 +pulls.merge_pull_request_now=立即合并拉取请求 +pulls.rebase_merge_pull_request_now=立即变基并合并 +pulls.rebase_merge_commit_pull_request_now=立即变基并合并 (--no-ff) +pulls.squash_merge_pull_request_now=立即压缩提交并合并 +pulls.merge_pull_request_on_status_success=所有检查成功时自动合并拉取请求 +pulls.rebase_merge_pull_request_on_status_success=所有检查成功时自动变基并合并 +pulls.rebase_merge_commit_pull_request_on_status_success=所有检查成功时自动变基并合并 (--no-ff) +pulls.squash_merge_pull_request_on_status_success=所有检查成功时自动压缩提交并合并 pulls.invalid_merge_option=你可以在此合并请求中使用合并选项。 pulls.merge_conflict=合并失败:合并时有冲突发生。提示:采用其它合并策略 pulls.merge_conflict_summary=错误信息 @@ -1584,6 +1604,14 @@ pulls.reopened_at=`重新打开此合并请求 %[2]s pulls.merge_instruction_hint=`你也可以查看 命令行指令` pulls.merge_instruction_step1_desc=从你的仓库中签出一个新的分支并测试变更。 pulls.merge_instruction_step2_desc=合并变更并更新到 Gitea 上 +pulls.merge_on_status_success=合并请求计划在所有检查成功时合并。 +pulls.merge_on_status_success_already_scheduled=此拉取请求已安排在所有检查成功时合并。 +pulls.pr_has_pending_merge_on_success=%[1]s 安排此拉取请求在所有检查成功时自动合并 %[2]s。 +pulls.merge_pull_on_success_cancel=取消自动合并 +pulls.pull_request_not_scheduled=此拉取请求没有计划自动合并。 +pulls.pull_request_schedule_canceled=此拉取请求的自动合并已取消。 +pulls.pull_request_scheduled_auto_merge=`已安排此拉取请求在所有检查成功时自动合并 %[1]s` +pulls.pull_request_canceled_scheduled_auto_merge=`已取消当所有检查成功时自动合并此拉取请求 %[1]s` milestones.new=新的里程碑 milestones.open_tab=%d 开启中 @@ -1755,7 +1783,7 @@ settings.mirror_settings.push_mirror.none=未配置推送镜像 settings.mirror_settings.push_mirror.remote_url=Git 远程仓库链接 settings.mirror_settings.push_mirror.add=添加推送镜像 settings.sync_mirror=同步 -settings.mirror_sync_in_progress=镜像同步正在进行中,请稍后后再试。 +settings.mirror_sync_in_progress=镜像同步正在进行中,请稍后再试。 settings.email_notifications.enable=启用邮件通知 settings.email_notifications.onmention=只在被提到时邮件通知 settings.email_notifications.disable=停用邮件通知 @@ -2396,7 +2424,7 @@ dashboard.new_version_hint=Gitea %s 现已可用,您正在运行 %s。查看 < dashboard.statistic=摘要 dashboard.operations=维护操作 dashboard.system_status=系统状态 -dashboard.statistic_info=Gitea 数据库统计:%d 位用户,%d 个组织,%d 个公钥,%d 个仓库,%d 个仓库关注,%d 个赞,%d 次行为,%d 条权限记录,%d 张工单,%d 次评论,%d 个社交帐号,%d 个用户关注,%d 个镜像,%d 个版本发布,%d 个登录源,%d 个 Web 钩子,%d 个里程碑,%d 个标签,%d 个钩子任务,%d 个团队,%d 个更新任务,%d 个附件。 +dashboard.statistic_info=此 Gitea 数据库有 %d 位用户、%d 家组织、 %d 枚公钥、%d 个仓库、%d 个仓库关注、%d 个星标、~%d 个操作、 %d 次访问、%d 张工单、 %d 条评论、 %d 个社交账户、%d 个用户关注、%d 个镜像、%d 个发布、%d 个验证源、%d 个 webhooks、%d 个里程碑、 %d 个标签、%d 个 hook 任务、 %d 支团队、%d 个更新任务、%d 个附件。 dashboard.operation_name=操作名称 dashboard.operation_switch=开关 dashboard.operation_run=执行 @@ -2503,6 +2531,7 @@ users.allow_import_local=允许导入本地仓库 users.allow_create_organization=允许创建组织 users.update_profile=更新帐户 users.delete_account=删除帐户 +users.cannot_delete_self=你不能删除自己 users.still_own_repo=此用户仍然拥有一个或多个仓库。必须首先删除或转让这些仓库。 users.still_has_org=此用户是组织的成员。必须先从组织中删除用户。 users.still_own_packages=此用户仍然拥有一个或多个软件包。请先删除这些软件包。 @@ -2939,7 +2968,7 @@ mirror_sync_push=从镜像同步了提交至仓库 %[4]s 的 mirror_sync_create=从镜像同步了引用 %[3]s 至仓库 %[4]s mirror_sync_delete=从镜像同步并从 %[3]s 删除了引用 %[2]s approve_pull_request=`批准了 %[3]s#%[2]s` -reject_pull_request=`建议变更 %s#%[2]s` +reject_pull_request=`建议变更 %[3]s#%[2]s` publish_release=`在 %[3]s 发布了 "%[4]s" ` review_dismissed=`取消了 %[4]s%[3]s#%[2]s 的变更请求` review_dismissed_reason=原因: diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 7acfb5b810..f51ea14712 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -2,6 +2,7 @@ home=首頁 dashboard=資訊主頁 explore=探索 help=說明 +logo=標誌 sign_in=登入 sign_in_with=登入方式 sign_out=登出 @@ -105,6 +106,7 @@ error404=您正嘗試訪問的頁面 不存在您 never=從來沒有 +rss_feed=RSS 摘要 [error] occurred=發生錯誤 @@ -496,7 +498,7 @@ target_branch_not_exist=目標分支不存在 [user] change_avatar=更改大頭貼... join_on=加入於 -repositories=儲存庫列表 +repositories=儲存庫 activity=公開動態 followers=追蹤者 starred=已加星號 @@ -775,6 +777,7 @@ webauthn_delete_key_desc=如果您移除安全金鑰,將不能再使用它登 manage_account_links=管理已連結的帳戶 manage_account_links_desc=這些外部帳戶已連結到您的 Gitea 帳戶。 account_links_not_available=目前沒有連結到您的 Gitea 帳戶的外部帳戶 +link_account=連結帳戶 remove_account_link=刪除已連結的帳戶 remove_account_link_desc=刪除連結帳戶將撤銷其對 Gitea 帳戶的存取權限。是否繼續? remove_account_link_success=已移除連結的帳戶。 @@ -855,7 +858,6 @@ default_branch=預設分支 default_branch_helper=預設分支是合併請求和提交程式碼的基礎分支。 mirror_prune=裁減 mirror_prune_desc=刪除過時的遠端追蹤參考 -mirror_interval=鏡像間隔(有效時間單位為 'h'、'm'、's')。設為 0 以停用自動同步。 mirror_interval_invalid=鏡像週期無效 mirror_address=從 URL Clone mirror_address_desc=在授權資訊中填入必要的資料。 @@ -926,7 +928,6 @@ need_auth=授權 migrate_options=遷移選項 migrate_service=遷移服務 migrate_options_mirror_helper=將此儲存庫設定為鏡像儲存庫 -migrate_options_mirror_disabled=您的網站管理員已經停用新增鏡像儲存庫的功能。 migrate_options_lfs=遷移 LFS 檔案 migrate_options_lfs_endpoint.label=LFS 端點 migrate_options_lfs_endpoint.description=遷移將會嘗試使用您的 Git Remote 來確認 LFS 伺服器。如果存儲庫的 LFS 資料放在其他地方,您也可以指定自訂的端點。 @@ -1038,6 +1039,7 @@ line_unicode=`這一行有隱藏的 Unicode 字元` escape_control_characters=Escape unescape_control_characters=Unescape file_copy_permalink=複製固定連結 +view_git_blame=檢視 Git Blame video_not_supported_in_browser=您的瀏覽器不支援使用 HTML5 播放影片。 audio_not_supported_in_browser=您的瀏覽器不支援 HTML5 的「audio」標籤 stored_lfs=已使用 Git LFS 儲存 @@ -1458,6 +1460,7 @@ issues.review.add_review_request=請求了 %s 來審核 %s issues.review.remove_review_request=移除了對 %s 的審核請求 %s issues.review.remove_review_request_self=拒絕了審核 %s issues.review.pending=待處理 +issues.review.pending.tooltip=目前其他使用者還不能看見此留言。要送出您待定的留言請在頁面最上方選擇「%s」->「%s/%s/%s」。 issues.review.review=審核 issues.review.reviewers=審核者 issues.review.outdated=過時的 @@ -1476,6 +1479,7 @@ issues.content_history.created=建立 issues.content_history.delete_from_history=刪除歷程記錄 issues.content_history.delete_from_history_confirm=刪除歷程記錄? issues.content_history.options=選項 +issues.reference_link=參考: %s compare.compare_base=基底分支 compare.compare_head=比較 @@ -1484,6 +1488,9 @@ pulls.desc=啟用合併請求和程式碼審核。 pulls.new=建立合併請求 pulls.view=檢視合併請求 pulls.compare_changes=建立合併請求 +pulls.allow_edits_from_maintainers=允許維護者編輯 +pulls.allow_edits_from_maintainers_desc=對基礎分支有寫入權限的使用者也可以推送到此分支 +pulls.allow_edits_from_maintainers_err=更新失敗 pulls.compare_changes_desc=選擇合併的目標分支和來源分支。 pulls.compare_base=合併到 pulls.compare_compare=拉取自 @@ -2391,7 +2398,7 @@ dashboard.new_version_hint=現已推出 Gitea %s,您正在執行 %s。查看%d 位使用者,%d 個組織,%d 個公鑰,%d 個儲存庫,%d 個儲存庫關注,%d 個星號,%d 次行為,%d 條權限記錄,%d 個問題,%d 則留言,%d 個社群帳戶,%d 個用戶關注,%d 個鏡像,%d 個版本發佈,%d 個認證來源,%d 個 Webhook ,%d 個里程碑,%d 個標籤,%d 個 Hook 任務,%d 個團隊,%d 個更新任務,%d 個附件。 +dashboard.statistic_info=Gitea 資料庫統計: %d 位使用者,%d 個組織,%d 個公鑰,%d 個儲存庫,%d 個儲存庫關注,%d 個星號,~%d 次行為,%d 條權限記錄,%d 個問題,%d 則留言,%d 個社群帳戶,%d 個使用者關注,%d 個鏡像,%d 個版本發佈,%d 個認證來源,%d 個 Webhook ,%d 個里程碑,%d 個標籤,%d 個 Hook 任務,%d 個團隊,%d 個更新任務,%d 個附件。 dashboard.operation_name=作業名稱 dashboard.operation_switch=開關 dashboard.operation_run=執行 @@ -2497,6 +2504,7 @@ users.allow_import_local=可以匯入本地儲存庫 users.allow_create_organization=可以建立組織 users.update_profile=更新使用者帳戶 users.delete_account=刪除使用者帳戶 +users.cannot_delete_self=您無法刪除您自己 users.still_own_repo=這個使用者還擁有一個或更多的儲存庫。請先刪除或是轉移這些儲存庫。 users.still_has_org=此使用者是組織的成員。請先將他從組織中移除。 users.deletion_success=使用者帳戶已被刪除。 @@ -2813,6 +2821,8 @@ monitor.next=下次執行時間 monitor.previous=上次執行時間 monitor.execute_times=執行次數 monitor.process=執行中的處理程序 +monitor.stacktrace=堆疊追蹤 +monitor.goroutines=%d 個 Goroutines monitor.desc=描述 monitor.start=開始時間 monitor.execute_time=已執行時間 diff --git a/package-lock.json b/package-lock.json index 8b63409e28..8f8f7013a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,27 +8,27 @@ "license": "MIT", "dependencies": { "@claviska/jquery-minicolors": "2.3.6", - "@primer/octicons": "17.0.0", + "@primer/octicons": "17.2.0", "add-asset-webpack-plugin": "2.0.1", "css-loader": "6.7.1", "dropzone": "6.0.0-beta.2", "easymde": "2.16.1", - "esbuild-loader": "2.18.0", + "esbuild-loader": "2.19.0", "escape-goat": "4.0.0", "fast-glob": "3.2.11", "font-awesome": "4.7.0", "jquery": "3.6.0", "jquery.are-you-sure": "1.9.0", "less": "4.1.2", - "less-loader": "10.2.0", + "less-loader": "11.0.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "8.14.0", + "mermaid": "9.1.1", "mini-css-extract-plugin": "2.6.0", "monaco-editor": "0.33.0", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "7.0.1", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.10.0", + "swagger-ui-dist": "4.11.1", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vue": "2.6.14", @@ -36,39 +36,41 @@ "vue-calendar-heatmap": "0.8.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", - "webpack": "5.70.0", + "webpack": "5.72.1", "webpack-cli": "4.9.2", - "workbox-routing": "6.5.2", - "workbox-strategies": "6.5.2", + "workbox-routing": "6.5.3", + "workbox-strategies": "6.5.3", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { - "eslint": "8.12.0", + "@happy-dom/jest-environment": "4.0.1", + "eslint": "8.15.0", "eslint-plugin-html": "6.2.0", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-unicorn": "41.0.1", - "eslint-plugin-vue": "8.5.0", - "jest": "27.5.1", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-jquery": "1.5.1", + "eslint-plugin-unicorn": "42.0.0", + "eslint-plugin-vue": "9.0.1", + "jest": "28.1.0", "jest-extended": "2.0.0", - "jest-raw-loader": "1.0.1", "postcss-less": "6.0.0", - "stylelint": "14.6.1", + "stylelint": "14.8.2", "stylelint-config-standard": "25.0.0", "svgo": "2.8.0", - "updates": "13.0.4" + "updates": "13.0.5" }, "engines": { "node": ">= 14" } }, "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -87,34 +89,34 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz", + "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", + "@babel/generator": "^7.18.0", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.0", + "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", + "json5": "^2.2.1", "semver": "^6.3.0" }, "engines": { @@ -135,37 +137,42 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz", + "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==", "dev": true, "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.18.0", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/generator/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", + "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.10", "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", + "browserslist": "^4.20.2", "semver": "^6.3.0" }, "engines": { @@ -197,26 +204,13 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -247,40 +241,40 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", "dev": true, "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -317,23 +311,23 @@ } }, "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz", + "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==", "dev": true, "dependencies": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", @@ -416,9 +410,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -575,12 +569,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", + "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" }, "engines": { "node": ">=6.9.0" @@ -590,9 +584,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", - "integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -615,19 +609,19 @@ } }, "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz", + "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", + "@babel/generator": "^7.18.0", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -645,9 +639,9 @@ } }, "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz", + "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", @@ -664,9 +658,9 @@ "dev": true }, "node_modules/@braintree/sanitize-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-3.1.0.tgz", - "integrity": "sha512-GcIY79elgB+azP74j8vqkiXz8xLFfIzbQJdlwOPisgbKT00tviJQuEghOXSMVxJ00HoYJbGswr4kcllUc4xCcg==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz", + "integrity": "sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==" }, "node_modules/@claviska/jquery-minicolors": { "version": "2.3.6", @@ -677,37 +671,51 @@ } }, "node_modules/@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "engines": { "node": ">=10.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", - "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz", + "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.1", + "espree": "^9.3.2", "globals": "^13.9.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@happy-dom/jest-environment": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@happy-dom/jest-environment/-/jest-environment-4.0.1.tgz", + "integrity": "sha512-G6hwPF+JlTr4vcJ7xrJYKYrpXPv3ceoGfVX2ZKX9AH7GRQz6Zeq1OWRpEsSezxnwd/bbzsNP6wLakVzWy6jCTQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "happy-dom": "^4.0.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -851,59 +859,123 @@ } }, "node_modules/@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.0.tgz", + "integrity": "sha512-tscn3dlJFGay47kb4qVruQg/XWlmvU0xp3EJOjzzY+sBaI+YgwKcvAmTcyYU7xEiLLIY5HCdWRooAL8dqkFlDA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/console/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/console/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.0.tgz", + "integrity": "sha512-/2PTt0ywhjZ4NwNO4bUqD9IVJfmFVhVKGlhvSpmEfUCuxYf/3NHcKmRFI+I71lYzbTT3wMuYpETDCTHo81gC/g==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/reporters": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", + "jest-changed-files": "^28.0.2", + "jest-config": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-resolve-dependencies": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "jest-watcher": "^28.1.0", "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -914,6 +986,69 @@ } } }, + "node_modules/@jest/core/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/core/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/@jest/environment": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", @@ -929,6 +1064,31 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jest/expect": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-be9ETznPLaHOmeJqzYNIXv1ADEzENuQonIoobzThOYPuK/6GhrWNIJDVTgBLCrz3Am73PyEU2urQClZp0hLTtA==", + "dev": true, + "dependencies": { + "expect": "^28.1.0", + "jest-snapshot": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.0.tgz", + "integrity": "sha512-5BrG48dpC0sB80wpeIX5FU6kolDJI4K0n5BM9a5V38MGx0pyRvUBSS0u2aNTdDzmOrCjhOg8pGs6a20ivYkdmw==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/@jest/fake-timers": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", @@ -947,53 +1107,169 @@ } }, "node_modules/@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.0.tgz", + "integrity": "sha512-3m7sTg52OTQR6dPhsEQSxAvU+LOBbMivZBwOvKEZ+Rb+GyxVnXi9HKgOTYkx/S99T8yvh17U4tNNJPIEQmtwYw==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/types": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@jest/globals/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/globals/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.0.tgz", + "integrity": "sha512-qxbFfqap/5QlSpIizH9c/bFCDKsQlM4uAKSOvZrP+nIdrjqre3FmKzpTtYyhsaVcOSNK7TTt2kjm+4BJIjysFA==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "v8-to-istanbul": "^9.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -1004,74 +1280,198 @@ } } }, - "node_modules/@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "node_modules/@jest/reporters/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", "dev": true, "dependencies": { - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/reporters/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", + "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.23.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", + "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.7", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.0.tgz", + "integrity": "sha512-sBBFIyoPzrZho3N+80P35A5oAkSKlGfsEFfXFWuPGBsW40UAjCkGakZhn4UQK4iQlW2vgCDMRDOob9FGKV8YoQ==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/types": "^28.1.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" } }, "node_modules/@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.0.tgz", + "integrity": "sha512-tZCEiVWlWNTs/2iK9yi6o3AlMfbbYgV4uuZInSVdzZ7ftpHZhCMuhvk2HLYhCZzLgPFQ9MnM1YaxMnh3TILFiQ==", "dev": true, "dependencies": { - "@jest/test-result": "^27.5.1", + "@jest/test-result": "^28.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "jest-haste-map": "^28.1.0", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.0.tgz", + "integrity": "sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "write-file-atomic": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@jest/transform/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/types": { @@ -1090,25 +1490,47 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", @@ -1148,13 +1570,19 @@ } }, "node_modules/@primer/octicons": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.0.0.tgz", - "integrity": "sha512-DiIjtous4XPuR2deTctD3/RVZy/vRzVYBgYYvHV313MmTfkbVP60qLH5txrT3/bYNvnb0poNDelLS6U0kqlvHA==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.2.0.tgz", + "integrity": "sha512-A3YetVbJX5J4JGa2AfVrEl1lE3FtT+7HdSzphFRs1QF5OgsUpkNbyjvVxeCxVZaG6zXYbbbPWsPF06PtsIyUWQ==", "dependencies": { "object-assign": "^4.1.1" } }, + "node_modules/@sinclair/typebox": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", + "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "dev": true + }, "node_modules/@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -1178,15 +1606,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.2.14.tgz", "integrity": "sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA==" }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -1197,9 +1616,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1229,9 +1648,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dev": true, "dependencies": { "@babel/types": "^7.3.0" @@ -1245,10 +1664,19 @@ "@types/tern": "*" } }, + "node_modules/@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -1268,6 +1696,15 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" }, + "node_modules/@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -1302,20 +1739,20 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "node_modules/@types/marked": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.2.tgz", - "integrity": "sha512-auNrZ/c0w6wsM9DccwVxWHssrMDezHUAXNesdp2RQrCVCyrQbOiSq7yqdJKrUQQpw9VTm7CGYJH2A/YG7jjrjQ==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.3.tgz", + "integrity": "sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg==" }, "node_modules/@types/minimist": { "version": "1.2.2", @@ -1324,9 +1761,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", - "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", + "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -1341,9 +1778,15 @@ "dev": true }, "node_modules/@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, "node_modules/@types/stack-utils": { @@ -1370,9 +1813,9 @@ } }, "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "node_modules/@vue/component-compiler-utils": { @@ -1602,38 +2045,10 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, - "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - } - }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true, + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "bin": { "acorn": "bin/acorn" }, @@ -1658,15 +2073,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/add-asset-webpack-plugin": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/add-asset-webpack-plugin/-/add-asset-webpack-plugin-2.0.1.tgz", @@ -1681,18 +2087,6 @@ "webpack": ">=5" } }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1725,9 +2119,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -1823,20 +2217,20 @@ "node_modules/array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", "engines": { "node": ">=0.10.0" } }, "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" }, @@ -1857,14 +2251,15 @@ } }, "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -1876,12 +2271,18 @@ "node_modules/arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -1894,26 +2295,25 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", + "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", "dev": true, "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/transform": "^28.1.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", + "babel-preset-jest": "^28.0.2", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" @@ -1936,18 +2336,18 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", + "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", + "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/babel-preset-current-node-syntax": { @@ -1974,16 +2374,16 @@ } }, "node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", + "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", + "babel-plugin-jest-hoist": "^28.0.2", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -2010,7 +2410,7 @@ "node_modules/boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, "node_modules/brace-expansion": { @@ -2033,21 +2433,25 @@ "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.1", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" }, "bin": { @@ -2055,10 +2459,6 @@ }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/bser": { @@ -2076,9 +2476,9 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "node_modules/builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true, "engines": { "node": ">=6" @@ -2136,13 +2536,25 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001307", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001307.tgz", - "integrity": "sha512-+MXEMczJ4FuxJAUp0jvAl6Df0NI/OfW1RWEE61eSmzS7hw6lz4IKutbhbXendwq8BljfFuHtu26VWsg4afQ7Ng==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001341", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", + "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true }, "node_modules/chalk": { "version": "4.1.2", @@ -2178,9 +2590,9 @@ } }, "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", "dev": true }, "node_modules/cjs-module-lexer": { @@ -2192,7 +2604,7 @@ "node_modules/clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha1-jffHquUf02h06PjQW5GAvBGj/tc=", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", "dev": true, "dependencies": { "escape-string-regexp": "^1.0.5" @@ -2285,9 +2697,9 @@ } }, "node_modules/codemirror": { - "version": "5.65.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", - "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" + "version": "5.65.4", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.4.tgz", + "integrity": "sha512-tytrSm5Rh52b6j36cbDXN+FHwHCl9aroY4BrDZB2NFFL3Wjfq9nuYVLFFhaOYOczKAg3JXTr8BuT8LcE5QY4Iw==" }, "node_modules/codemirror-spell-checker": { "version": "1.1.2", @@ -2355,6 +2767,21 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "node_modules/consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", @@ -2386,6 +2813,12 @@ "url": "https://github.com/sponsors/mesqueeb" } }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, "node_modules/cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -2450,14 +2883,14 @@ } }, "node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, "dependencies": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" }, @@ -2479,9 +2912,9 @@ } }, "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true, "engines": { "node": ">= 6" @@ -2490,6 +2923,12 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", + "dev": true + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -2513,34 +2952,10 @@ "node": ">=8.0.0" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, "node_modules/d3": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.3.0.tgz", - "integrity": "sha512-MDRLJCMK232OJQRqGljQ/gCxtB8k3/sLKFjftMjzPB3nKVUODpdW9Rb3vcq7U8Ka5YKoZkAmp++Ur6I+6iNWIw==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.4.4.tgz", + "integrity": "sha512-97FE+MYdAlV3R9P74+R3Uar7wUKkIFu89UWMjEaDhiJ9VxKvqaMxauImy8PC2DdBkdM2BxJOIoLxPrcZUyrKoQ==", "dependencies": { "d3-array": "3", "d3-axis": "3", @@ -2578,9 +2993,9 @@ } }, "node_modules/d3-array": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.1.1.tgz", - "integrity": "sha512-33qQ+ZoZlli19IFiQx4QEpf2CBEayMRzhlisJHSCsSUbDXv6ZishqS1x7uFVClKG4Wr7rZVHvaAttoLow6GqdQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.1.6.tgz", + "integrity": "sha512-DCbBBNuKOeiR9h04ySRBMW52TFVc91O9wJziuyXw6Ztmy8D3oZbmCkOO3UHKC7ceNJsN2Mavo9+vwV8EAEUXzA==", "dependencies": { "internmap": "1 - 2" }, @@ -2628,9 +3043,9 @@ "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" }, "node_modules/d3-color": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.0.1.tgz", - "integrity": "sha512-6/SlHkDOBLyQSJ1j1Ghs82OIUXpKWlR0hCsw0XrLSQhuUPuCSmLQ1QPH98vpnQxMUQM2/gfAkUEWsupVpd9JGw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", "engines": { "node": ">=12" } @@ -2753,9 +3168,9 @@ } }, "node_modules/d3-hierarchy": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.1.tgz", - "integrity": "sha512-LtAIu54UctRmhGKllleflmHalttH3zkfSi4NlKrTAoFKjC+AFBJohsCAdgCBYQwH0F8hIOGY89X1pPqAchlMkA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", "engines": { "node": ">=12" } @@ -3218,20 +3633,6 @@ "node": ">=0.10.0" } }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -3285,12 +3686,6 @@ "node": ">=0.10.0" } }, - "node_modules/decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -3313,15 +3708,19 @@ } }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/delaunator": { @@ -3384,9 +3783,9 @@ } }, "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "dependencies": { "domelementtype": "^2.0.1", @@ -3407,9 +3806,9 @@ } }, "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { @@ -3418,31 +3817,10 @@ } ] }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "dependencies": { "domelementtype": "^2.2.0" @@ -3455,9 +3833,9 @@ } }, "node_modules/dompurify": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz", - "integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==" + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.6.tgz", + "integrity": "sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==" }, "node_modules/domutils": { "version": "2.8.0", @@ -3500,17 +3878,17 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.65", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.65.tgz", - "integrity": "sha512-0/d8Skk8sW3FxXP0Dd6MnBlrwx7Qo9cqQec3BlIAlvKnrmS3pHsIbaroEi+nd0kZkGpQ6apMEre7xndzjlEnLw==" + "version": "1.4.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", + "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==" }, "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -3530,9 +3908,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", + "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -3586,31 +3964,34 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -3624,6 +4005,15 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -3642,9 +4032,9 @@ } }, "node_modules/esbuild": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.18.tgz", - "integrity": "sha512-vCUoISSltnX7ax01w70pWOSQT+e55o+2P/a+A9MSTukJAt3T4aDZajcjeG4fnZbkvOEv+dkKgdkvljz6vVQD4A==", + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz", + "integrity": "sha512-2kKujuzvRWYtwvNjYDY444LQIA3TyJhJIX3Yo4+qkFlDDtGlSicWgeHVJqMUP/2sSfH10PGwfsj+O2ro1m10xQ==", "hasInstallScript": true, "bin": { "esbuild": "bin/esbuild" @@ -3653,45 +4043,32 @@ "node": ">=12" }, "optionalDependencies": { - "esbuild-android-arm64": "0.14.18", - "esbuild-darwin-64": "0.14.18", - "esbuild-darwin-arm64": "0.14.18", - "esbuild-freebsd-64": "0.14.18", - "esbuild-freebsd-arm64": "0.14.18", - "esbuild-linux-32": "0.14.18", - "esbuild-linux-64": "0.14.18", - "esbuild-linux-arm": "0.14.18", - "esbuild-linux-arm64": "0.14.18", - "esbuild-linux-mips64le": "0.14.18", - "esbuild-linux-ppc64le": "0.14.18", - "esbuild-linux-s390x": "0.14.18", - "esbuild-netbsd-64": "0.14.18", - "esbuild-openbsd-64": "0.14.18", - "esbuild-sunos-64": "0.14.18", - "esbuild-windows-32": "0.14.18", - "esbuild-windows-64": "0.14.18", - "esbuild-windows-arm64": "0.14.18" - } - }, - "node_modules/esbuild-android-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.18.tgz", - "integrity": "sha512-AuE8vIwc6QLquwykyscFk0Ji3RFczoOvjka64FJlcjLLhD6VsS584RYlQrSnPpRkv69PunUvyrBoEF7JFTJijg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" + "esbuild-android-64": "0.14.39", + "esbuild-android-arm64": "0.14.39", + "esbuild-darwin-64": "0.14.39", + "esbuild-darwin-arm64": "0.14.39", + "esbuild-freebsd-64": "0.14.39", + "esbuild-freebsd-arm64": "0.14.39", + "esbuild-linux-32": "0.14.39", + "esbuild-linux-64": "0.14.39", + "esbuild-linux-arm": "0.14.39", + "esbuild-linux-arm64": "0.14.39", + "esbuild-linux-mips64le": "0.14.39", + "esbuild-linux-ppc64le": "0.14.39", + "esbuild-linux-riscv64": "0.14.39", + "esbuild-linux-s390x": "0.14.39", + "esbuild-netbsd-64": "0.14.39", + "esbuild-openbsd-64": "0.14.39", + "esbuild-sunos-64": "0.14.39", + "esbuild-windows-32": "0.14.39", + "esbuild-windows-64": "0.14.39", + "esbuild-windows-arm64": "0.14.39" } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.18.tgz", - "integrity": "sha512-nN1XziZtDy8QYOggaXC3zu0vVh8YJpS8Bol7bHaxx0enTLDSFBCXUUJEKYpmAAJ4OZRPgjXv8NzEHHQWQvLzXg==", + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz", + "integrity": "sha512-ImT6eUw3kcGcHoUxEcdBpi6LfTRWaV6+qf32iYYAfwOeV+XaQ/Xp5XQIBiijLeo+LpGci9M0FVec09nUw41a5g==", "cpu": [ "x64" ], @@ -3703,162 +4080,12 @@ "node": ">=12" } }, - "node_modules/esbuild-darwin-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.18.tgz", - "integrity": "sha512-v0i2n6TCsbxco/W1fN8RgQt3RW00Q9zJO2eqiAdmLWg6Hx0HNHloZyfhF11i7nMUUgW8r5n++ZweIXjAFPE/gQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.18.tgz", - "integrity": "sha512-XLyJZTWbSuQJOqw867tBxvto6GjxULvWZYKs6RFHYQPCqgQ0ODLRtBmp4Fqqpde52yOe45npaaoup9IXNfr32A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.18.tgz", - "integrity": "sha512-0ItfrR8hePnDcUXxUQxY+VfICcBfeMJCdK6mcNUXnXw6LyHjyUYXWpFXF+J18pg1/YUWRWO1HbsJ7FEwELcQIA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-32": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.18.tgz", - "integrity": "sha512-mnG84D9NsEsoQdBpBT0IsFjm5iAwnd81SP4tRMXZLl09lPvIWjHHSq6LDlb4+L5H5K5y68WC//X5Dr2MtNY3DQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.18.tgz", - "integrity": "sha512-HvExRtkeA8l/p+7Lf6aBrnLH+jTCFJTUMJxGKExh2RD8lCXGTeDJFyP+BOEetP80fuuH+Syj79+LVQ9MihdBsg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.18.tgz", - "integrity": "sha512-+ZL8xfXVNaeaZ2Kxqlw2VYZWRDZ7NSK4zOV9GKNAtkkWURLsPUU84aUOBatRe9BH1O5FDo3LLQSlaA04ed6lhA==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.18.tgz", - "integrity": "sha512-CCWmilODE1ckw+M7RVqoqKWA4UB0alCyK2bv0ikEeEAwkzinlJeoe94t9CnT/ECSQ2sL+C16idsr+aUviGp7sg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-mips64le": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.18.tgz", - "integrity": "sha512-8LjO4+6Vxz5gbyCHO4OONYMF689nLderCtzb8lG1Bncs4ZXHpo6bjvuWeTMRbGUkvAhp+P6hMTzia7RHOC53wQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.18.tgz", - "integrity": "sha512-0OJk/6iYEmF1J7LXY6+cqf6Ga5vG4an7n1nubTKce7kYqaTyNGfYcTjDZce6lnDVlZTJtwntIMszq1+ZX7Kenw==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-linux-s390x": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.18.tgz", - "integrity": "sha512-UNY7YKZHjY31KcNanJK4QaT2/aoIQyS+jViP3QuDRIoYAogRnc6WydylzIkkEzGMaC4fzaXOmQ8fxwpLAXK4Yg==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/esbuild-loader": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.18.0.tgz", - "integrity": "sha512-AKqxM3bI+gvGPV8o6NAhR+cBxVO8+dh+O0OXBHIXXwuSGumckbPWHzZ17subjBGI2YEGyJ1STH7Haj8aCrwL/w==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.19.0.tgz", + "integrity": "sha512-urGNVE6Tl2rqx92ElKi/LiExXjGvcH6HfDBFzJ9Ppwqh4n6Jmx8x7RKAyMzSM78b6CAaJLhDncG5sPrL0ROh5Q==", "dependencies": { - "esbuild": "^0.14.6", + "esbuild": "^0.14.39", "joycon": "^3.0.1", "json5": "^2.2.0", "loader-utils": "^2.0.0", @@ -3872,96 +4099,6 @@ "webpack": "^4.40.0 || ^5.0.0" } }, - "node_modules/esbuild-netbsd-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.18.tgz", - "integrity": "sha512-wE/2xT9KNzLCfEBw24YbVmMmXH92cFIzrRPUlwWH9dIizjvEYYcyQ+peTMVkqzUum7pdlVLZ2CDDqAaZo/nW/w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-openbsd-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.18.tgz", - "integrity": "sha512-vdymE2jyuH/FRmTvrguCYSrq81/rUwuhMYyvt/6ibv9ac7xQ674c8qTdT+RH73sR9/2WUD/NsYxrBA/wUVTxcg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-sunos-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.18.tgz", - "integrity": "sha512-X/Tesy6K1MdJF1d5cbzFDxrIMMn0ye+VgTQRI8P5Vo2CcKxOdckwsKUwpRAvg+VDZ6MxrSOTYS9OOoggPUjxTg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-32": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.18.tgz", - "integrity": "sha512-glG23I/JzCL4lu7DWFUtVwqFwNwlL0g+ks+mcjjUisHcINoSXTeCNToUN0bHhzn6IlXXnggNQ38Ew/idHPM8+g==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.18.tgz", - "integrity": "sha512-zEiFKHgV/3z14wsVamV98/5mxeOwz+ecyg0pD3fWcBz9j4EOIT1Tg47axypD4QLwiKFvve9mUBYX1cD99qxOyw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/esbuild-windows-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.18.tgz", - "integrity": "sha512-Mh8lZFcPLat13dABN7lZThGUOn9YxoH5RYkhBq0U3WqQohHzKRhllYh7ibFixnkpMLnv8OZEbl8bGLMy03MpfA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3993,86 +4130,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/eslint": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.12.0.tgz", - "integrity": "sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz", + "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.2.1", + "@eslint/eslintrc": "^1.2.3", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -4083,7 +4147,7 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", + "espree": "^9.3.2", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -4099,7 +4163,7 @@ "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "regexpp": "^3.2.0", @@ -4169,9 +4233,9 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "dependencies": { "array-includes": "^3.1.4", @@ -4179,14 +4243,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "engines": { "node": ">=4" @@ -4222,10 +4286,19 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/eslint-plugin-jquery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jquery/-/eslint-plugin-jquery-1.5.1.tgz", + "integrity": "sha512-L7v1eaK5t80C0lvUXPFP9MKnBOqPSKhCOYyzy4LZ0+iK+TJwN8S9gAkzzP1AOhypRIwA88HF6phQ9C7jnOpW8w==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.4.0" + } + }, "node_modules/eslint-plugin-unicorn": { - "version": "41.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-41.0.1.tgz", - "integrity": "sha512-gF5vo2dIj0YdNMQ/IMegiBkQdQ22GBFFVpdkJP+0og3w7XD4ypea0xQVRv6iofkLVR2w0phAdikcnU01ybd4Ow==", + "version": "42.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-42.0.0.tgz", + "integrity": "sha512-ixBsbhgWuxVaNlPTT8AyfJMlhyC5flCJFjyK3oKE8TRrwBnaHvUbuIkCM1lqg8ryYrFStL/T557zfKzX4GKSlg==", "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.15.7", @@ -4254,18 +4327,21 @@ } }, "node_modules/eslint-plugin-vue": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.5.0.tgz", - "integrity": "sha512-i1uHCTAKOoEj12RDvdtONWrGzjFm/djkzqfhmQ0d6M/W8KM81mhswd/z+iTZ0jCpdUedW3YRgcVfQ37/J4zoYQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.0.1.tgz", + "integrity": "sha512-/w/9/vzz+4bSYtp5UqXgJ0CfycXTMtpp6lkz7/fMp0CcJxPWyRP6Pr88ihhrsNEcVt2ZweMupWRNYa+5Md41LQ==", "dev": true, "dependencies": { "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", "semver": "^7.3.5", - "vue-eslint-parser": "^8.0.1" + "vue-eslint-parser": "^9.0.1", + "xml-name-validator": "^4.0.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14.17.0 || >=16.0.0" }, "peerDependencies": { "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" @@ -4321,13 +4397,13 @@ } }, "node_modules/espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", "dev": true, "dependencies": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -4439,18 +4515,82 @@ } }, "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-qFXKl8Pmxk8TBGfaFKRtcQjfXEnKAs+dmlxdwvukJZorwrAabT7M3h8oLOG01I2utEhkmUTi17CHaPBovZsKdw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/expect-utils": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/expect/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/fast-deep-equal": { @@ -4580,17 +4720,17 @@ } }, "node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", "dev": true, "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 6" + "node": ">= 0.12" } }, "node_modules/fs.realpath": { @@ -4617,12 +4757,39 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -4664,6 +4831,15 @@ "node": ">=8.0.0" } }, + "node_modules/get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -4704,14 +4880,14 @@ } }, "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -4778,9 +4954,9 @@ } }, "node_modules/globals": { - "version": "13.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", - "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -4819,9 +4995,9 @@ "dev": true }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/graphlib": { "version": "2.1.8", @@ -4832,9 +5008,24 @@ } }, "node_modules/gsap": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.9.1.tgz", - "integrity": "sha512-JSGVYoC6da4pIjdF/yxFU6Rz8OojOIDkbooveZlfNg0+JIoFoRruyfWAEi6R/gUeNcuOiTqUIb0gi1nCNrHf8w==" + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.10.4.tgz", + "integrity": "sha512-6QatdkKxXCMfvCW4rM++0RqyLQAzFX5nwl3yHS0XPgkZBkiSEY3VZVbMltrdtsbER/xZonLtyHt684wRp4erlQ==" + }, + "node_modules/happy-dom": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-4.0.1.tgz", + "integrity": "sha512-GUj2ayfbWYHPeQfcK0N+lygRE/DsrjQbALJq0zrxHLc9KYzhFSCmaCOISuNgHV/21EEeVIX55KoPTqMcX362+g==", + "dev": true, + "dependencies": { + "css.escape": "^1.5.1", + "he": "^1.2.0", + "node-fetch": "^2.x.x", + "sync-request": "^6.1.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0" + } }, "node_modules/hard-rejection": { "version": "2.1.0", @@ -4857,9 +5048,9 @@ } }, "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4873,10 +5064,22 @@ "node": ">=8" } }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { "node": ">= 0.4" @@ -4919,18 +5122,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^1.0.5" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -4938,12 +5129,15 @@ "dev": true }, "node_modules/html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/htmlparser2": { @@ -4965,33 +5159,36 @@ "entities": "^3.0.1" } }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" }, "engines": { - "node": ">= 6" + "node": ">=6.0.0" } }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", "dev": true, "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" + "@types/node": "^10.0.3" } }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -5213,9 +5410,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dependencies": { "has": "^1.0.3" }, @@ -5295,9 +5492,9 @@ } }, "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "dependencies": { "has-tostringtag": "^1.0.0" @@ -5327,12 +5524,6 @@ "node": ">=0.10.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5359,10 +5550,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5408,12 +5602,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "node_modules/is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -5431,6 +5619,12 @@ "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -5454,9 +5648,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "dependencies": { "@babel/core": "^7.12.3", @@ -5520,20 +5714,20 @@ } }, "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", + "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", "dev": true, "dependencies": { - "@jest/core": "^27.5.1", + "@jest/core": "^28.1.0", "import-local": "^3.0.2", - "jest-cli": "^27.5.1" + "jest-cli": "^28.1.0" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -5545,73 +5739,189 @@ } }, "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", + "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", "execa": "^5.0.0", "throat": "^6.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.0.tgz", + "integrity": "sha512-rNYfqfLC0L0zQKRKsg4n4J+W1A2fbyGH7Ss/kDIocp9KXD9iaL111glsLu7+Z7FHuZxwzInMDXq+N1ZIBkI/TQ==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", + "jest-each": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-circus/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-circus/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.0.tgz", + "integrity": "sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==", "dev": true, "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/core": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-config": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", "prompts": "^2.0.1", - "yargs": "^16.2.0" + "yargs": "^17.3.1" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -5622,49 +5932,137 @@ } } }, - "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "node_modules/jest-cli/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", "dev": true, "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-cli/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-cli/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.0.tgz", + "integrity": "sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.0", + "@jest/types": "^28.1.0", + "babel-jest": "^28.1.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-circus": "^28.1.0", + "jest-environment-node": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", + "pretty-format": "^28.1.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { + "@types/node": "*", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "ts-node": { "optional": true } } }, + "node_modules/jest-config/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-config/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/jest-diff": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", @@ -5680,67 +6078,250 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/jest-docblock": { + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/jest-get-type": { "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-diff/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/jest-docblock": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", + "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.0.tgz", + "integrity": "sha512-a/XX02xF5NTspceMpHujmOexvJ4GftpYXqr6HhhmKmExtMXsyIN/fvanQlt/BcgFoRKN4OCXxLQKth9/n6OPFg==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "node_modules/jest-each/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-each/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.0.tgz", + "integrity": "sha512-gBLZNiyrPw9CSMlTXF1yJhaBgWDPVvH0Pq6bOEwGMXaYNzhzhw2kA/OijNF8egbCgDS0/veRv97249x2CX+udQ==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-environment-node/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-environment-node/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-extended": { @@ -5759,7 +6340,7 @@ "jest": ">=27.2.5" } }, - "node_modules/jest-get-type": { + "node_modules/jest-extended/node_modules/jest-get-type": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", @@ -5768,86 +6349,133 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.0.tgz", + "integrity": "sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", + "@jest/types": "^28.1.0", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", "micromatch": "^4.0.4", "walker": "^1.0.7" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "optionalDependencies": { "fsevents": "^2.3.2" } }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "node_modules/jest-haste-map/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-haste-map/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-haste-map/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.0.tgz", + "integrity": "sha512-uIJDQbxwEL2AMMs2xjhZl2hw8s77c3wrPaQ9v6tXJLGaaQ+4QrNJH5vuw7hA7w/uGT/iJ42a83opAqxGHeyRIA==", "dev": true, "dependencies": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-message-util": { @@ -5870,6 +6498,38 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, "node_modules/jest-mock": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", @@ -5900,165 +6560,509 @@ } } }, - "node_modules/jest-raw-loader": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz", - "integrity": "sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY=", - "dev": true - }, "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.0.tgz", + "integrity": "sha512-vvfN7+tPNnnhDvISuzD1P+CRVP8cK0FHXRwPAcdDaQv4zgvwvag2n55/h5VjYcM5UJG7L4TwE5tZlzcI0X2Lhw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", + "jest-haste-map": "^28.1.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.0.tgz", + "integrity": "sha512-Ue1VYoSZquPwEvng7Uefw8RmZR+me/1kr30H2jMINjGeHgeO/JgrR6wxj2ofkJ7KSAA11W3cOrhNCbj5Dqqd9g==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-resolve/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.0.tgz", + "integrity": "sha512-FBpmuh1HB2dsLklAlRdOxNTTHKFR6G1Qmd80pVDvwbZXTriqjWqjei5DKFC1UlM732KjYcE6yuCdiF0WUCOS2w==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/environment": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "emittery": "^0.10.2", "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", + "jest-docblock": "^28.0.2", + "jest-environment-node": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-leak-detector": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-resolve": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-util": "^28.1.0", + "jest-watcher": "^28.1.0", + "jest-worker": "^28.1.0", + "source-map-support": "0.5.13", "throat": "^6.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-runner/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runner/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.0.tgz", + "integrity": "sha512-wNYDiwhdH/TV3agaIyVF0lsJ33MhyujOe+lNTUiolqKt8pchy1Hq4+tDMGbtD5P/oNLA3zYrpx73T9dMTOCAcg==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/globals": "^28.1.0", + "@jest/source-map": "^28.0.2", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", + "node_modules/jest-runtime/node_modules/@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", "dev": true, "dependencies": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", - "graceful-fs": "^4.2.9" + "jest-mock": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/jest-runtime/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-runtime/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.0.tgz", + "integrity": "sha512-ex49M2ZrZsUyQLpLGxQtDbahvgBjlLPgklkqGM0hq/F7W/f8DyqZxVHjdy19QKBm4O93eDp+H5S23EiTbbUmHw==", "dev": true, "dependencies": { - "@babel/core": "^7.7.2", + "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.5.1", + "expect": "^28.1.0", "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" + "pretty-format": "^28.1.0", + "semver": "^7.3.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-util": { @@ -6079,20 +7083,46 @@ } }, "node_modules/jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.0.tgz", + "integrity": "sha512-Lly7CJYih3vQBfjLeANGgBSBJ7pEa18cxpQfQEq2go2xyEzehnHfQTjoUia8xUv4x4J80XKFIDwJJThXtRFQXQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", + "jest-get-type": "^28.0.2", "leven": "^3.1.0", - "pretty-format": "^27.5.1" + "pretty-format": "^28.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" } }, "node_modules/jest-validate/node_modules/camelcase": { @@ -6108,40 +7138,86 @@ } }, "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.0.tgz", + "integrity": "sha512-tNHMtfLE8Njcr2IRS+5rXYA4BhU90gAOwI9frTGOqd+jX0P/Au/JfRSNqsf5nUTcWdbVYuLxS1KjnzILSoR5hA==", "dev": true, "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.5.1", + "emittery": "^0.10.2", + "jest-util": "^28.1.0", "string-length": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-watcher/node_modules/@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/jest-watcher/node_modules/jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.0.tgz", + "integrity": "sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A==", + "dev": true, "dependencies": { "@types/node": "*", "merge-stream": "^2.0.0", "supports-color": "^8.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -6194,52 +7270,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -6252,16 +7282,10 @@ "node": ">=4" } }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema-traverse": { "version": "0.4.1", @@ -6275,12 +7299,9 @@ "dev": true }, "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "bin": { "json5": "lib/cli.js" }, @@ -6294,9 +7315,9 @@ "integrity": "sha512-b+z6yF1d4EOyDgylzQo5IminlUmzSeqR1hs/bzjBNjuGras4FXq/6TrzjxfN0j+TmI0ltJzTNlqXUMCniciwKQ==" }, "node_modules/khroma": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-1.4.1.tgz", - "integrity": "sha512-+GmxKvmiRuCcUYDgR7g5Ngo0JEDeOsGdNONdU2zsiBQaK4z19Y2NvXqfEDE0ZiIrg45GTZyAnPLVsLZZACYm3Q==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", + "integrity": "sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==" }, "node_modules/kind-of": { "version": "6.0.3", @@ -6324,9 +7345,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.24.0.tgz", - "integrity": "sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", + "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", "dev": true }, "node_modules/less": { @@ -6355,14 +7376,14 @@ } }, "node_modules/less-loader": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", - "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", "dependencies": { "klona": "^2.0.4" }, "engines": { - "node": ">= 12.13.0" + "node": ">= 14.15.0" }, "funding": { "type": "opencollective", @@ -6473,9 +7494,9 @@ "dev": true }, "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", "engines": { "node": ">=6.11.5" } @@ -6522,6 +7543,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -6602,9 +7628,9 @@ } }, "node_modules/marked": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz", - "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==", + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", + "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==", "bin": { "marked": "bin/marked.js" }, @@ -6715,28 +7741,28 @@ } }, "node_modules/mermaid": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.14.0.tgz", - "integrity": "sha512-ITSHjwVaby1Li738sxhF48sLTxcNyUAoWfoqyztL1f7J6JOLpHOuQPNLBb6lxGPUA0u7xP9IRULgvod0dKu35A==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.1.tgz", + "integrity": "sha512-2RVD+WkzZ4VDyO9gQvQAuQ/ux2gLigJtKDTlbwjYqOR/NwsVzTSfGm/kx648/qWJsg6Sv04tE9BWCO8s6a+pFA==", "dependencies": { - "@braintree/sanitize-url": "^3.1.0", + "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", "dagre": "^0.8.5", "dagre-d3": "^0.6.4", - "dompurify": "2.3.5", + "dompurify": "2.3.6", "graphlib": "^2.1.8", - "khroma": "^1.4.1", + "khroma": "^2.0.0", "moment-mini": "^2.24.0", "stylis": "^4.0.10" } }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -6755,19 +7781,19 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -6809,9 +7835,9 @@ } }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6867,9 +7893,9 @@ "devOptional": true }, "node_modules/nanoid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", - "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -6926,6 +7952,26 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -6933,9 +7979,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==" }, "node_modules/normalize-package-data": { "version": "2.5.0", @@ -6996,12 +8042,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7147,6 +8187,12 @@ "node": ">=6" } }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=", + "dev": true + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -7181,12 +8227,6 @@ "node": ">= 0.10" } }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -7355,9 +8395,9 @@ } }, "node_modules/postcss": { - "version": "8.4.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", - "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "funding": [ { "type": "opencollective", @@ -7369,7 +8409,7 @@ } ], "dependencies": { - "nanoid": "^3.3.1", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -7473,9 +8513,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7499,29 +8539,33 @@ } }, "node_modules/prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "optional": true, "bin": { "prettier": "bin-prettier.js" }, "engines": { "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", "dev": true, "dependencies": { + "@jest/schemas": "^28.0.2", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/pretty-format/node_modules/ansi-styles": { @@ -7550,6 +8594,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "dev": true, + "dependencies": { + "asap": "~2.0.6" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -7574,12 +8633,6 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, - "node_modules/psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, "node_modules/punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -7588,6 +8641,21 @@ "node": ">=6" } }, + "node_modules/qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -7625,9 +8693,9 @@ } }, "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", "dev": true }, "node_modules/read-pkg": { @@ -7750,6 +8818,21 @@ "node": ">=8" } }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "node_modules/rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -7788,6 +8871,23 @@ "regexp-tree": "bin/regexp-tree" } }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -7951,18 +9051,6 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -7982,9 +9070,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -8013,9 +9101,9 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -8142,9 +9230,10 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8254,6 +9343,15 @@ "node": ">=8" } }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -8281,26 +9379,28 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8365,9 +9465,9 @@ "dev": true }, "node_modules/stylelint": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.6.1.tgz", - "integrity": "sha512-FfNdvZUZdzh9KDQxDnO7Opp+prKh8OQVuSW8S13cBtxrooCbm6J6royhUeb++53WPMt04VB+ZbOz/QmzAijs6Q==", + "version": "14.8.2", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.8.2.tgz", + "integrity": "sha512-tjDfexCYfoPdl/xcDJ9Fv+Ko9cvzbDnmdiaqEn3ovXHXasi/hbkt5tSjsiReQ+ENqnz0eltaX/AOO+AlzVdcNA==", "dev": true, "dependencies": { "balanced-match": "^2.0.0", @@ -8383,23 +9483,23 @@ "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", - "html-tags": "^3.1.0", + "html-tags": "^3.2.0", "ignore": "^5.2.0", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.24.0", + "known-css-properties": "^0.25.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", - "micromatch": "^4.0.4", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", "picocolors": "^1.0.0", - "postcss": "^8.4.12", + "postcss": "^8.4.13", "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.9", + "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "specificity": "^0.4.1", @@ -8459,23 +9559,10 @@ "node": ">=8" } }, - "node_modules/stylelint/node_modules/write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16" - } - }, "node_modules/stylis": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", - "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.1.tgz", + "integrity": "sha512-lVrM/bNdhVX2OgBFNa2YJ9Lxj7kPzylieHd3TNjuGE0Re9JB7joL5VUKOVH1kdNNJTgGPpT8hmwIAPLaSyEVFQ==" }, "node_modules/superstruct": { "version": "0.10.13", @@ -8546,15 +9633,32 @@ } }, "node_modules/swagger-ui-dist": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.10.0.tgz", - "integrity": "sha512-+RBJA/beHLg0hO4rJZIhgUdxmZE7AaNfc11PCSzZdnzkmwSJv8Qg0HZbr7BQPQjkC6z4xVWq2h1itOPk1FQBrA==" + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.11.1.tgz", + "integrity": "sha512-pf3kfSTYdF9mYFY2VnfJ51wnXlSVhEGdtymhpHzfbFw2jTbiEWgBoVz5EB9aW2EaJvUGTM1YHAXYZX7Jk4RdAQ==" }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "node_modules/sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "dependencies": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "dependencies": { + "get-port": "^3.1.0" + } }, "node_modules/table": { "version": "6.8.0", @@ -8573,9 +9677,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", @@ -8619,12 +9723,13 @@ } }, "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", + "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", "dependencies": { + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", + "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "bin": { @@ -8632,14 +9737,6 @@ }, "engines": { "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } } }, "node_modules/terser-webpack-plugin": { @@ -8675,6 +9772,19 @@ } } }, + "node_modules/terser-webpack-plugin/node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -8692,19 +9802,76 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/terser-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, "node_modules/terser/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/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, "engines": { "node": ">= 8" } }, + "node_modules/terser/node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/terser/node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terser/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/terser/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/terser/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -8725,6 +9892,34 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "node_modules/then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "dependencies": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/then-request/node_modules/@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + }, "node_modules/throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -8757,31 +9952,11 @@ "node": ">=8.0" } }, - "node_modules/tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true }, "node_modules/tributejs": { "version": "5.1.3", @@ -8798,14 +9973,14 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, @@ -8831,9 +10006,9 @@ } }, "node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/type-check": { "version": "0.4.0", @@ -8868,14 +10043,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, "node_modules/typo-js": { "version": "1.2.1", @@ -8888,33 +10060,24 @@ "integrity": "sha512-r13jrghEYZAN99GeYpEjM107DOxqB65enskpwce8rRHVAGEtaWmsF5GqoGdPMf8DIXc9XyAJTdvlvRZi4LsszA==" }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/updates": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.0.4.tgz", - "integrity": "sha512-RgHZnmTlcoRdn2yA8FZUwlRj7ltEANZQvh3ISAoSZcxunIv2s5EpFnZh8jgU7DigtX4ogm4XSn0r5O4u+cF7sg==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.0.5.tgz", + "integrity": "sha512-ut7RIiH5Qys7jan4cS9i1Lqk6AAKGmVy1q0udDNJ4YXhvVoUdwQTAk5I9/wkSH6nHQtqhaqytCcZvS6hEJs8xg==", "dev": true, "bin": { "updates": "bin/updates.js" @@ -8954,28 +10117,19 @@ "dev": true }, "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", + "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.7", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^1.6.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -9009,21 +10163,21 @@ } }, "node_modules/vue-eslint-parser": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz", - "integrity": "sha512-hvl8OVT8imlKk/lQyhkshqwQQChzHETcBd5abiO4ePw7ib7QUZLfW+2TUrJHKUvFOCFRJrDin5KJO9OHzB5bRQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz", + "integrity": "sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA==", "dev": true, "dependencies": { - "debug": "^4.3.2", - "eslint-scope": "^7.0.0", - "eslint-visitor-keys": "^3.1.0", - "espree": "^9.0.0", + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", "esquery": "^1.4.0", "lodash": "^4.17.21", - "semver": "^7.3.5" + "semver": "^7.3.6" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^14.17.0 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/mysticatea" @@ -9143,27 +10297,6 @@ "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -9186,18 +10319,18 @@ } }, "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, "engines": { - "node": ">=10.4" + "node": ">=12" } }, "node_modules/webpack": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", - "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "version": "5.72.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", + "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -9208,13 +10341,13 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.9.3", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", @@ -9352,46 +10485,42 @@ } }, "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-encoding/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==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "iconv-lite": "0.6.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } }, "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "dev": true, "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, + "node_modules/whatwg-url/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9437,24 +10566,24 @@ } }, "node_modules/workbox-core": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.2.tgz", - "integrity": "sha512-IlxLGQf+wJHCR+NM0UWqDh4xe/Gu6sg2i4tfZk6WIij34IVk9BdOQgi6WvqSHd879jbQIUgL2fBdJUJyAP5ypQ==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.3.tgz", + "integrity": "sha512-Bb9ey5n/M9x+l3fBTlLpHt9ASTzgSGj6vxni7pY72ilB/Pb3XtN+cZ9yueboVhD5+9cNQrC9n/E1fSrqWsUz7Q==" }, "node_modules/workbox-routing": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.2.tgz", - "integrity": "sha512-nR1w5PjF6IVwo0SX3oE88LhmGFmTnqqU7zpGJQQPZiKJfEKgDENQIM9mh3L1ksdFd9Y3CZVkusopHfxQvit/BA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.3.tgz", + "integrity": "sha512-DFjxcuRAJjjt4T34RbMm3MCn+xnd36UT/2RfPRfa8VWJGItGJIn7tG+GwVTdHmvE54i/QmVTJepyAGWtoLPTmg==", "dependencies": { - "workbox-core": "6.5.2" + "workbox-core": "6.5.3" } }, "node_modules/workbox-strategies": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.2.tgz", - "integrity": "sha512-fgbwaUMxbG39BHjJIs2y2X21C0bmf1Oq3vMQxJ1hr6y5JMJIm8rvKCcf1EIdAr+PjKdSk4ddmgyBQ4oO8be4Uw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.3.tgz", + "integrity": "sha512-MgmGRrDVXs7rtSCcetZgkSZyMpRGw8HqL2aguszOc3nUmzGZsT238z/NN9ZouCxSzDu3PQ3ZSKmovAacaIhu1w==", "dependencies": { - "workbox-core": "6.5.2" + "workbox-core": "6.5.3" } }, "node_modules/worker-loader": { @@ -9537,9 +10666,9 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz", - "integrity": "sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -9572,49 +10701,26 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, + "signal-exit": "^3.0.7" + }, "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "node": "^12.13.0 || ^14.15.0 || >=16" } }, "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } }, "node_modules/y18n": { "version": "5.0.8", @@ -9640,21 +10746,21 @@ } }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { @@ -9665,16 +10771,26 @@ "engines": { "node": ">=10" } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true, + "engines": { + "node": ">=12" + } } }, "dependencies": { "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, "@babel/code-frame": { @@ -9687,31 +10803,31 @@ } }, "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", "dev": true }, "@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.0.tgz", + "integrity": "sha512-Xyw74OlJwDijToNi0+6BBI5mLLR5+5R3bcSH80LXzjzEGEUlvNzujEE71BaD/ApEZHAvFI/Mlmp4M5lIkdeeWw==", "dev": true, "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", + "@babel/generator": "^7.18.0", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.18.0", + "@babel/helpers": "^7.18.0", + "@babel/parser": "^7.18.0", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", + "json5": "^2.2.1", "semver": "^6.3.0" }, "dependencies": { @@ -9724,33 +10840,38 @@ } }, "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.0.tgz", + "integrity": "sha512-81YO9gGx6voPXlvYdZBliFXAZU8vZ9AZ6z+CjlmcnaeOcYSFbMTpdeDUO9xD9dh/68Vq03I8ZspfUTPfitcDHg==", "dev": true, "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.18.0", + "@jridgewell/gen-mapping": "^0.3.0", + "jsesc": "^2.5.1" }, "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "@jridgewell/gen-mapping": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", + "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } } } }, "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", + "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.10", "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", + "browserslist": "^4.20.2", "semver": "^6.3.0" }, "dependencies": { @@ -9772,23 +10893,13 @@ } }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-hoist-variables": { @@ -9810,34 +10921,34 @@ } }, "@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.0.tgz", + "integrity": "sha512-kclUYSUBIjlvnzN2++K9f2qzYKFgjmnmjwL4zlmU5f8ZtzgWe8s0rUPSTGy2HmK4P8T52MQsS+HTQAgZd3dMEA==", "dev": true, "requires": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" } }, "@babel/helper-plugin-utils": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz", - "integrity": "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", + "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", "dev": true }, "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dev": true, "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-split-export-declaration": { @@ -9862,20 +10973,20 @@ "dev": true }, "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.0.tgz", + "integrity": "sha512-AE+HMYhmlMIbho9nbvicHyxFwhrO+xhKB6AhRxzl8w46Yj0VXTZjEsAoBVC7rB2I0jzX+yWyVybnO08qkfx6kg==", "dev": true, "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", - "@babel/types": "^7.17.0" + "@babel/traverse": "^7.18.0", + "@babel/types": "^7.18.0" } }, "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.12.tgz", + "integrity": "sha512-7yykMVF3hfZY2jsHZEEgLc+3x4o1O+fYyULu11GynEUQNwB6lua+IIQn1FiJxNucd5UlyJryrwsOh8PL9Sn8Qg==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -9942,9 +11053,9 @@ } }, "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.0.tgz", + "integrity": "sha512-AqDccGC+m5O/iUStSJy3DGRIUFu7WbY/CppZYwrEUB4N0tZlnI8CSTsgL7v5fHVFmUbRv2sd+yy27o8Ydt4MGg==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -10056,18 +11167,18 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.17.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.12.tgz", + "integrity": "sha512-TYY0SXFiO31YXtNg3HtFwNJHjLsAyIIhAhNWkQ5whPPS7HWUFlg9z0Ta4qAQNjQbP1wsSt/oKkmZ/4/WWdMUpw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.7" + "@babel/helper-plugin-utils": "^7.17.12" } }, "@babel/runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.0.tgz", - "integrity": "sha512-etcO/ohMNaNA2UBdaXBBSX/3aEzFMRrVfaPv8Ptc0k+cWpWW0QFiGZ2XnVqQZI1Cf734LbPGmqBKWESfW4x/dQ==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -10084,19 +11195,19 @@ } }, "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.0.tgz", + "integrity": "sha512-oNOO4vaoIQoGjDQ84LgtF/IAlxlyqL4TUuoQ7xLkQETFaHkY1F7yazhB4Kt3VcZGL0ZF/jhrEpnXqUb0M7V3sw==", "dev": true, "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", + "@babel/generator": "^7.18.0", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/parser": "^7.18.0", + "@babel/types": "^7.18.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -10110,9 +11221,9 @@ } }, "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.0.tgz", + "integrity": "sha512-vhAmLPAiC8j9K2GnsnLPCIH5wCrPpYIVBCWRBFDCB7Y/BXLqi/O+1RSTTM2bsmg6U/551+FCf9PNPxjABmxHTw==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.16.7", @@ -10126,9 +11237,9 @@ "dev": true }, "@braintree/sanitize-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-3.1.0.tgz", - "integrity": "sha512-GcIY79elgB+azP74j8vqkiXz8xLFfIzbQJdlwOPisgbKT00tviJQuEghOXSMVxJ00HoYJbGswr4kcllUc4xCcg==" + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.0.tgz", + "integrity": "sha512-mgmE7XBYY/21erpzhexk4Cj1cyTQ9LzvnTxtzM17BJ7ERMNE6W72mQRo0I1Ud8eFJ+RVVIcBNhLFZ3GX4XFz5w==" }, "@claviska/jquery-minicolors": { "version": "2.3.6", @@ -10137,31 +11248,45 @@ "requires": {} }, "@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==" + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" }, "@eslint/eslintrc": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", - "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.3.tgz", + "integrity": "sha512-uGo44hIwoLGNyduRpjdEpovcbMdd+Nv7amtmJxnKmI8xj6yd5LncmSwDa5NgX/41lIFJtkjD6YdVfgEzPfJ5UA==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.1", + "espree": "^9.3.2", "globals": "^13.9.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "strip-json-comments": "^3.1.1" } }, + "@happy-dom/jest-environment": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@happy-dom/jest-environment/-/jest-environment-4.0.1.tgz", + "integrity": "sha512-G6hwPF+JlTr4vcJ7xrJYKYrpXPv3ceoGfVX2ZKX9AH7GRQz6Zeq1OWRpEsSezxnwd/bbzsNP6wLakVzWy6jCTQ==", + "dev": true, + "requires": { + "@jest/environment": "^27.5.1", + "@jest/fake-timers": "^27.5.1", + "@jest/types": "^27.5.1", + "happy-dom": "^4.0.1", + "jest-mock": "^27.5.1", + "jest-util": "^27.5.1" + } + }, "@humanwhocodes/config-array": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.3.tgz", - "integrity": "sha512-3xSMlXHh03hCcCmFc0rbKp3Ivt2PFEJnQUJDDMTJQ2wkECZWdq4GePs2ctc5H8zV+cHPaq8k2vU8mrQjA6iHdQ==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -10271,53 +11396,166 @@ "dev": true }, "@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.0.tgz", + "integrity": "sha512-tscn3dlJFGay47kb4qVruQg/XWlmvU0xp3EJOjzzY+sBaI+YgwKcvAmTcyYU7xEiLLIY5HCdWRooAL8dqkFlDA==", "dev": true, "requires": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.0", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.0.tgz", + "integrity": "sha512-/2PTt0ywhjZ4NwNO4bUqD9IVJfmFVhVKGlhvSpmEfUCuxYf/3NHcKmRFI+I71lYzbTT3wMuYpETDCTHo81gC/g==", "dev": true, "requires": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/reporters": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", + "jest-changed-files": "^28.0.2", + "jest-config": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-resolve-dependencies": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", + "jest-watcher": "^28.1.0", "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "@jest/environment": { @@ -10332,6 +11570,25 @@ "jest-mock": "^27.5.1" } }, + "@jest/expect": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-be9ETznPLaHOmeJqzYNIXv1ADEzENuQonIoobzThOYPuK/6GhrWNIJDVTgBLCrz3Am73PyEU2urQClZp0hLTtA==", + "dev": true, + "requires": { + "expect": "^28.1.0", + "jest-snapshot": "^28.1.0" + } + }, + "@jest/expect-utils": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.0.tgz", + "integrity": "sha512-5BrG48dpC0sB80wpeIX5FU6kolDJI4K0n5BM9a5V38MGx0pyRvUBSS0u2aNTdDzmOrCjhOg8pGs6a20ivYkdmw==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + } + }, "@jest/fake-timers": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", @@ -10347,105 +11604,317 @@ } }, "@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.0.tgz", + "integrity": "sha512-3m7sTg52OTQR6dPhsEQSxAvU+LOBbMivZBwOvKEZ+Rb+GyxVnXi9HKgOTYkx/S99T8yvh17U4tNNJPIEQmtwYw==", "dev": true, "requires": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/types": "^28.1.0" + }, + "dependencies": { + "@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + } + }, + "@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.0.tgz", + "integrity": "sha512-qxbFfqap/5QlSpIizH9c/bFCDKsQlM4uAKSOvZrP+nIdrjqre3FmKzpTtYyhsaVcOSNK7TTt2kjm+4BJIjysFA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "v8-to-istanbul": "^9.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } + } + }, + "@jest/schemas": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.0.2.tgz", + "integrity": "sha512-YVDJZjd4izeTDkij00vHHAymNXQ6WWsdChFRK86qck6Jpr3DCL5W3Is3vslviRlP+bLuMYRLbdp98amMvqudhA==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.23.3" } }, "@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.0.2.tgz", + "integrity": "sha512-Y9dxC8ZpN3kImkk0LkK5XCEneYMAXlZ8m5bflmSL5vrwyeUpJfentacCUg6fOb8NOpOO7hz2+l37MV77T6BFPw==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.7", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" + "graceful-fs": "^4.2.9" } }, "@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.0.tgz", + "integrity": "sha512-sBBFIyoPzrZho3N+80P35A5oAkSKlGfsEFfXFWuPGBsW40UAjCkGakZhn4UQK4iQlW2vgCDMRDOob9FGKV8YoQ==", "dev": true, "requires": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/types": "^28.1.0", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + } } }, "@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.0.tgz", + "integrity": "sha512-tZCEiVWlWNTs/2iK9yi6o3AlMfbbYgV4uuZInSVdzZ7ftpHZhCMuhvk2HLYhCZzLgPFQ9MnM1YaxMnh3TILFiQ==", "dev": true, "requires": { - "@jest/test-result": "^27.5.1", + "@jest/test-result": "^28.1.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "jest-haste-map": "^28.1.0", + "slash": "^3.0.0" } }, "@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.0.tgz", + "integrity": "sha512-omy2xe5WxlAfqmsTjTPxw+iXRTRnf+NtX0ToG+4S0tABeb4KsKmPUHq5UBuwunHg3tJRwgEQhEp0M/8oiatLEA==", "dev": true, "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.0", + "@jridgewell/trace-mapping": "^0.3.7", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "write-file-atomic": "^4.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "@jest/types": { @@ -10461,22 +11930,38 @@ "chalk": "^4.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", + "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", + "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", "dev": true }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==", + "version": "1.4.13", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", + "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", + "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.0.3", @@ -10507,13 +11992,19 @@ } }, "@primer/octicons": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.0.0.tgz", - "integrity": "sha512-DiIjtous4XPuR2deTctD3/RVZy/vRzVYBgYYvHV313MmTfkbVP60qLH5txrT3/bYNvnb0poNDelLS6U0kqlvHA==", + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/@primer/octicons/-/octicons-17.2.0.tgz", + "integrity": "sha512-A3YetVbJX5J4JGa2AfVrEl1lE3FtT+7HdSzphFRs1QF5OgsUpkNbyjvVxeCxVZaG6zXYbbbPWsPF06PtsIyUWQ==", "requires": { "object-assign": "^4.1.1" } }, + "@sinclair/typebox": { + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.23.5.tgz", + "integrity": "sha512-AFBVi/iT4g20DHoujvMH1aEDn8fGJh4xsRGCP6d8RpLPMqsNPvW01Jcn0QysXTsg++/xj25NmJsGyH9xug/wKg==", + "dev": true + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -10537,12 +12028,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.2.14.tgz", "integrity": "sha512-wpCQMhf5p5GhNg2MmGKXzUNwxe7zRiCsmqYsamez2beP7mKPCSiu+BjZcdN95yYSzO857kr0VfQewmGpS77nqA==" }, - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, "@trysound/sax": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", @@ -10550,9 +12035,9 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -10582,9 +12067,9 @@ } }, "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -10598,10 +12083,19 @@ "@types/tern": "*" } }, + "@types/concat-stream": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@types/concat-stream/-/concat-stream-1.6.1.tgz", + "integrity": "sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/eslint": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", - "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.2.tgz", + "integrity": "sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA==", "requires": { "@types/estree": "*", "@types/json-schema": "*" @@ -10621,6 +12115,15 @@ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==" }, + "@types/form-data": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-0.0.33.tgz", + "integrity": "sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, "@types/graceful-fs": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", @@ -10655,20 +12158,20 @@ } }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" }, "@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, "@types/marked": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.2.tgz", - "integrity": "sha512-auNrZ/c0w6wsM9DccwVxWHssrMDezHUAXNesdp2RQrCVCyrQbOiSq7yqdJKrUQQpw9VTm7CGYJH2A/YG7jjrjQ==" + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.3.tgz", + "integrity": "sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg==" }, "@types/minimist": { "version": "1.2.2", @@ -10677,9 +12180,9 @@ "dev": true }, "@types/node": { - "version": "17.0.15", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.15.tgz", - "integrity": "sha512-zWt4SDDv1S9WRBNxLFxFRHxdD9tvH8f5/kg5/IaLFdnSNXsDY4eL3Q3XXN+VxUnWIhyVFDwcsmAprvwXoM/ClA==" + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.35.tgz", + "integrity": "sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -10694,9 +12197,15 @@ "dev": true }, "@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.1.tgz", + "integrity": "sha512-XFjFHmaLVifrAKaZ+EKghFHtHSUonyw8P2Qmy2/+osBnrKbH9UYtlK10zg8/kCt47MFilll/DEDKy3DHfJ0URw==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", "dev": true }, "@types/stack-utils": { @@ -10723,9 +12232,9 @@ } }, "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", "dev": true }, "@vue/component-compiler-utils": { @@ -10935,34 +12444,10 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, - "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", - "dev": true - }, "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" - }, - "acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" - }, - "dependencies": { - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - } - } + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" }, "acorn-import-assertions": { "version": "1.8.0", @@ -10977,27 +12462,12 @@ "dev": true, "requires": {} }, - "acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true - }, "add-asset-webpack-plugin": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/add-asset-webpack-plugin/-/add-asset-webpack-plugin-2.0.1.tgz", "integrity": "sha512-Hx9EKnirCUfdh684y1yhx8QOFolpkIG2VRHHgNm8wFy1Cf7P3RGwS678hoN7Y1XvZRPpVXWa+6QnfL/2i0CMCA==", "requires": {} }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -11018,9 +12488,9 @@ }, "dependencies": { "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -11090,17 +12560,17 @@ "array-find-index": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==" }, "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" } @@ -11112,20 +12582,27 @@ "dev": true }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, "arrify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", "dev": true }, "astral-regex": { @@ -11137,20 +12614,19 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.0.tgz", + "integrity": "sha512-zNKk0yhDZ6QUwfxh9k07GII6siNGMJWVUU49gmFj5gfdqDKLqa2RArXOF2CODp4Dr7dLxN2cvAV+667dGJ4b4w==", "dev": true, "requires": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/transform": "^28.1.0", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", + "babel-preset-jest": "^28.0.2", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" @@ -11170,14 +12646,14 @@ } }, "babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.0.2.tgz", + "integrity": "sha512-Kizhn/ZL+68ZQHxSnHyuvJv8IchXD62KQxV77TBDV/xoBFBOfgRAk97GNs6hXdTTCiVES9nB2I6+7MXXrk5llQ==", "dev": true, "requires": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", + "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" } }, @@ -11202,12 +12678,12 @@ } }, "babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.0.2.tgz", + "integrity": "sha512-sYzXIdgIXXroJTFeB3S6sNDWtlJ2dllCdTEsnZ65ACrMojj3hVNFRmnJ1HZtomGi+Be7aqpY/HJ92fr8OhKVkQ==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.5.1", + "babel-plugin-jest-hoist": "^28.0.2", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -11229,7 +12705,7 @@ "boolbase": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "dev": true }, "brace-expansion": { @@ -11249,21 +12725,15 @@ "fill-range": "^7.0.1" } }, - "browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.1", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" } }, @@ -11282,9 +12752,9 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" }, "builtin-modules": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz", - "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", "dev": true }, "call-bind": { @@ -11321,9 +12791,15 @@ } }, "caniuse-lite": { - "version": "1.0.30001307", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001307.tgz", - "integrity": "sha512-+MXEMczJ4FuxJAUp0jvAl6Df0NI/OfW1RWEE61eSmzS7hw6lz4IKutbhbXendwq8BljfFuHtu26VWsg4afQ7Ng==" + "version": "1.0.30001341", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", + "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true }, "chalk": { "version": "4.1.2", @@ -11347,9 +12823,9 @@ "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" }, "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.1.tgz", + "integrity": "sha512-SXgeMX9VwDe7iFFaEWkA5AstuER9YKqy4EhHqr4DVqkwmD9rpVimkMKWHdjn30Ja45txyjhSn63lVX69eVCckg==", "dev": true }, "cjs-module-lexer": { @@ -11361,7 +12837,7 @@ "clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", - "integrity": "sha1-jffHquUf02h06PjQW5GAvBGj/tc=", + "integrity": "sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==", "dev": true, "requires": { "escape-string-regexp": "^1.0.5" @@ -11435,9 +12911,9 @@ "dev": true }, "codemirror": { - "version": "5.65.2", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.2.tgz", - "integrity": "sha512-SZM4Zq7XEC8Fhroqe3LxbEEX1zUPWH1wMr5zxiBuiUF64iYOUH/JI88v4tBag8MiBS8B8gRv8O1pPXGYXQ4ErA==" + "version": "5.65.4", + "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.4.tgz", + "integrity": "sha512-tytrSm5Rh52b6j36cbDXN+FHwHCl9aroY4BrDZB2NFFL3Wjfq9nuYVLFFhaOYOczKAg3JXTr8BuT8LcE5QY4Iw==" }, "codemirror-spell-checker": { "version": "1.1.2", @@ -11496,6 +12972,18 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, "consolidate": { "version": "0.15.1", "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", @@ -11521,6 +13009,12 @@ "is-what": "^3.14.1" } }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, "cosmiconfig": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", @@ -11566,14 +13060,14 @@ } }, "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dev": true, "requires": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } @@ -11589,9 +13083,15 @@ } }, "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s=", "dev": true }, "cssesc": { @@ -11608,33 +13108,10 @@ "css-tree": "^1.1.2" } }, - "cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "requires": { - "cssom": "~0.3.6" - }, - "dependencies": { - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - } - } - }, "d3": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/d3/-/d3-7.3.0.tgz", - "integrity": "sha512-MDRLJCMK232OJQRqGljQ/gCxtB8k3/sLKFjftMjzPB3nKVUODpdW9Rb3vcq7U8Ka5YKoZkAmp++Ur6I+6iNWIw==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.4.4.tgz", + "integrity": "sha512-97FE+MYdAlV3R9P74+R3Uar7wUKkIFu89UWMjEaDhiJ9VxKvqaMxauImy8PC2DdBkdM2BxJOIoLxPrcZUyrKoQ==", "requires": { "d3-array": "3", "d3-axis": "3", @@ -11669,9 +13146,9 @@ } }, "d3-array": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.1.1.tgz", - "integrity": "sha512-33qQ+ZoZlli19IFiQx4QEpf2CBEayMRzhlisJHSCsSUbDXv6ZishqS1x7uFVClKG4Wr7rZVHvaAttoLow6GqdQ==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.1.6.tgz", + "integrity": "sha512-DCbBBNuKOeiR9h04ySRBMW52TFVc91O9wJziuyXw6Ztmy8D3oZbmCkOO3UHKC7ceNJsN2Mavo9+vwV8EAEUXzA==", "requires": { "internmap": "1 - 2" } @@ -11707,9 +13184,9 @@ "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==" }, "d3-color": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.0.1.tgz", - "integrity": "sha512-6/SlHkDOBLyQSJ1j1Ghs82OIUXpKWlR0hCsw0XrLSQhuUPuCSmLQ1QPH98vpnQxMUQM2/gfAkUEWsupVpd9JGw==" + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" }, "d3-contour": { "version": "3.0.1", @@ -11788,9 +13265,9 @@ } }, "d3-hierarchy": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.1.tgz", - "integrity": "sha512-LtAIu54UctRmhGKllleflmHalttH3zkfSi4NlKrTAoFKjC+AFBJohsCAdgCBYQwH0F8hIOGY89X1pPqAchlMkA==" + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" }, "d3-interpolate": { "version": "3.0.1", @@ -12193,17 +13670,6 @@ } } }, - "data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "requires": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - } - }, "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -12242,12 +13708,6 @@ } } }, - "decimal.js": { - "version": "10.3.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", - "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", - "dev": true - }, "dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -12267,12 +13727,13 @@ "dev": true }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dev": true, "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "delaunator": { @@ -12320,9 +13781,9 @@ } }, "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", @@ -12339,41 +13800,24 @@ } }, "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, - "domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "requires": { - "webidl-conversions": "^5.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true - } - } - }, "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" } }, "dompurify": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.5.tgz", - "integrity": "sha512-kD+f8qEaa42+mjdOpKeztu9Mfx5bv9gVLO6K9jRx4uGvh6Wv06Srn4jr1wPNY2OOUGGSKHNFN+A8MA3v0E0QAQ==" + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.6.tgz", + "integrity": "sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==" }, "domutils": { "version": "2.8.0", @@ -12413,14 +13857,14 @@ } }, "electron-to-chromium": { - "version": "1.4.65", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.65.tgz", - "integrity": "sha512-0/d8Skk8sW3FxXP0Dd6MnBlrwx7Qo9cqQec3BlIAlvKnrmS3pHsIbaroEi+nd0kZkGpQ6apMEre7xndzjlEnLw==" + "version": "1.4.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", + "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==" }, "emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", "dev": true }, "emoji-regex": { @@ -12434,9 +13878,9 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" }, "enhanced-resolve": { - "version": "5.9.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", - "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", + "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", "requires": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -12472,31 +13916,34 @@ } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.1.tgz", + "integrity": "sha512-WEm2oBhfoI2sImeM4OF2zE2V3BYdSF+KnSi9Sidz51fQHd7+JuF8Xgcj9/0o+OWeIeIS/MiuNnlruQrJf16GQA==", "dev": true, "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" + "regexp.prototype.flags": "^1.4.3", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" } }, "es-module-lexer": { @@ -12504,6 +13951,15 @@ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -12516,108 +13972,44 @@ } }, "esbuild": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.18.tgz", - "integrity": "sha512-vCUoISSltnX7ax01w70pWOSQT+e55o+2P/a+A9MSTukJAt3T4aDZajcjeG4fnZbkvOEv+dkKgdkvljz6vVQD4A==", + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.39.tgz", + "integrity": "sha512-2kKujuzvRWYtwvNjYDY444LQIA3TyJhJIX3Yo4+qkFlDDtGlSicWgeHVJqMUP/2sSfH10PGwfsj+O2ro1m10xQ==", "requires": { - "esbuild-android-arm64": "0.14.18", - "esbuild-darwin-64": "0.14.18", - "esbuild-darwin-arm64": "0.14.18", - "esbuild-freebsd-64": "0.14.18", - "esbuild-freebsd-arm64": "0.14.18", - "esbuild-linux-32": "0.14.18", - "esbuild-linux-64": "0.14.18", - "esbuild-linux-arm": "0.14.18", - "esbuild-linux-arm64": "0.14.18", - "esbuild-linux-mips64le": "0.14.18", - "esbuild-linux-ppc64le": "0.14.18", - "esbuild-linux-s390x": "0.14.18", - "esbuild-netbsd-64": "0.14.18", - "esbuild-openbsd-64": "0.14.18", - "esbuild-sunos-64": "0.14.18", - "esbuild-windows-32": "0.14.18", - "esbuild-windows-64": "0.14.18", - "esbuild-windows-arm64": "0.14.18" + "esbuild-android-64": "0.14.39", + "esbuild-android-arm64": "0.14.39", + "esbuild-darwin-64": "0.14.39", + "esbuild-darwin-arm64": "0.14.39", + "esbuild-freebsd-64": "0.14.39", + "esbuild-freebsd-arm64": "0.14.39", + "esbuild-linux-32": "0.14.39", + "esbuild-linux-64": "0.14.39", + "esbuild-linux-arm": "0.14.39", + "esbuild-linux-arm64": "0.14.39", + "esbuild-linux-mips64le": "0.14.39", + "esbuild-linux-ppc64le": "0.14.39", + "esbuild-linux-riscv64": "0.14.39", + "esbuild-linux-s390x": "0.14.39", + "esbuild-netbsd-64": "0.14.39", + "esbuild-openbsd-64": "0.14.39", + "esbuild-sunos-64": "0.14.39", + "esbuild-windows-32": "0.14.39", + "esbuild-windows-64": "0.14.39", + "esbuild-windows-arm64": "0.14.39" } }, - "esbuild-android-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.18.tgz", - "integrity": "sha512-AuE8vIwc6QLquwykyscFk0Ji3RFczoOvjka64FJlcjLLhD6VsS584RYlQrSnPpRkv69PunUvyrBoEF7JFTJijg==", - "optional": true - }, "esbuild-darwin-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.18.tgz", - "integrity": "sha512-nN1XziZtDy8QYOggaXC3zu0vVh8YJpS8Bol7bHaxx0enTLDSFBCXUUJEKYpmAAJ4OZRPgjXv8NzEHHQWQvLzXg==", - "optional": true - }, - "esbuild-darwin-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.18.tgz", - "integrity": "sha512-v0i2n6TCsbxco/W1fN8RgQt3RW00Q9zJO2eqiAdmLWg6Hx0HNHloZyfhF11i7nMUUgW8r5n++ZweIXjAFPE/gQ==", - "optional": true - }, - "esbuild-freebsd-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.18.tgz", - "integrity": "sha512-XLyJZTWbSuQJOqw867tBxvto6GjxULvWZYKs6RFHYQPCqgQ0ODLRtBmp4Fqqpde52yOe45npaaoup9IXNfr32A==", - "optional": true - }, - "esbuild-freebsd-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.18.tgz", - "integrity": "sha512-0ItfrR8hePnDcUXxUQxY+VfICcBfeMJCdK6mcNUXnXw6LyHjyUYXWpFXF+J18pg1/YUWRWO1HbsJ7FEwELcQIA==", - "optional": true - }, - "esbuild-linux-32": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.18.tgz", - "integrity": "sha512-mnG84D9NsEsoQdBpBT0IsFjm5iAwnd81SP4tRMXZLl09lPvIWjHHSq6LDlb4+L5H5K5y68WC//X5Dr2MtNY3DQ==", - "optional": true - }, - "esbuild-linux-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.18.tgz", - "integrity": "sha512-HvExRtkeA8l/p+7Lf6aBrnLH+jTCFJTUMJxGKExh2RD8lCXGTeDJFyP+BOEetP80fuuH+Syj79+LVQ9MihdBsg==", - "optional": true - }, - "esbuild-linux-arm": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.18.tgz", - "integrity": "sha512-+ZL8xfXVNaeaZ2Kxqlw2VYZWRDZ7NSK4zOV9GKNAtkkWURLsPUU84aUOBatRe9BH1O5FDo3LLQSlaA04ed6lhA==", - "optional": true - }, - "esbuild-linux-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.18.tgz", - "integrity": "sha512-CCWmilODE1ckw+M7RVqoqKWA4UB0alCyK2bv0ikEeEAwkzinlJeoe94t9CnT/ECSQ2sL+C16idsr+aUviGp7sg==", - "optional": true - }, - "esbuild-linux-mips64le": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.18.tgz", - "integrity": "sha512-8LjO4+6Vxz5gbyCHO4OONYMF689nLderCtzb8lG1Bncs4ZXHpo6bjvuWeTMRbGUkvAhp+P6hMTzia7RHOC53wQ==", - "optional": true - }, - "esbuild-linux-ppc64le": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.18.tgz", - "integrity": "sha512-0OJk/6iYEmF1J7LXY6+cqf6Ga5vG4an7n1nubTKce7kYqaTyNGfYcTjDZce6lnDVlZTJtwntIMszq1+ZX7Kenw==", - "optional": true - }, - "esbuild-linux-s390x": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.18.tgz", - "integrity": "sha512-UNY7YKZHjY31KcNanJK4QaT2/aoIQyS+jViP3QuDRIoYAogRnc6WydylzIkkEzGMaC4fzaXOmQ8fxwpLAXK4Yg==", + "version": "0.14.39", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.39.tgz", + "integrity": "sha512-ImT6eUw3kcGcHoUxEcdBpi6LfTRWaV6+qf32iYYAfwOeV+XaQ/Xp5XQIBiijLeo+LpGci9M0FVec09nUw41a5g==", "optional": true }, "esbuild-loader": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.18.0.tgz", - "integrity": "sha512-AKqxM3bI+gvGPV8o6NAhR+cBxVO8+dh+O0OXBHIXXwuSGumckbPWHzZ17subjBGI2YEGyJ1STH7Haj8aCrwL/w==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/esbuild-loader/-/esbuild-loader-2.19.0.tgz", + "integrity": "sha512-urGNVE6Tl2rqx92ElKi/LiExXjGvcH6HfDBFzJ9Ppwqh4n6Jmx8x7RKAyMzSM78b6CAaJLhDncG5sPrL0ROh5Q==", "requires": { - "esbuild": "^0.14.6", + "esbuild": "^0.14.39", "joycon": "^3.0.1", "json5": "^2.2.0", "loader-utils": "^2.0.0", @@ -12625,42 +14017,6 @@ "webpack-sources": "^2.2.0" } }, - "esbuild-netbsd-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.18.tgz", - "integrity": "sha512-wE/2xT9KNzLCfEBw24YbVmMmXH92cFIzrRPUlwWH9dIizjvEYYcyQ+peTMVkqzUum7pdlVLZ2CDDqAaZo/nW/w==", - "optional": true - }, - "esbuild-openbsd-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.18.tgz", - "integrity": "sha512-vdymE2jyuH/FRmTvrguCYSrq81/rUwuhMYyvt/6ibv9ac7xQ674c8qTdT+RH73sR9/2WUD/NsYxrBA/wUVTxcg==", - "optional": true - }, - "esbuild-sunos-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.18.tgz", - "integrity": "sha512-X/Tesy6K1MdJF1d5cbzFDxrIMMn0ye+VgTQRI8P5Vo2CcKxOdckwsKUwpRAvg+VDZ6MxrSOTYS9OOoggPUjxTg==", - "optional": true - }, - "esbuild-windows-32": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.18.tgz", - "integrity": "sha512-glG23I/JzCL4lu7DWFUtVwqFwNwlL0g+ks+mcjjUisHcINoSXTeCNToUN0bHhzn6IlXXnggNQ38Ew/idHPM8+g==", - "optional": true - }, - "esbuild-windows-64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.18.tgz", - "integrity": "sha512-zEiFKHgV/3z14wsVamV98/5mxeOwz+ecyg0pD3fWcBz9j4EOIT1Tg47axypD4QLwiKFvve9mUBYX1cD99qxOyw==", - "optional": true - }, - "esbuild-windows-arm64": { - "version": "0.14.18", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.18.tgz", - "integrity": "sha512-Mh8lZFcPLat13dABN7lZThGUOn9YxoH5RYkhBq0U3WqQohHzKRhllYh7ibFixnkpMLnv8OZEbl8bGLMy03MpfA==", - "optional": true - }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -12677,67 +14033,13 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "escodegen": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", - "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - }, - "dependencies": { - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - } - } - }, "eslint": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.12.0.tgz", - "integrity": "sha512-it1oBL9alZg1S8UycLm5YDMAkIhtH6FtAzuZs6YvoGVldWjbS08BkAdb/ymP9LlAyq8koANu32U7Ib/w+UNh8Q==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.15.0.tgz", + "integrity": "sha512-GG5USZ1jhCu8HJkzGgeK8/+RGnHaNYZGrGDzUtigK3BsGESW/rs2az23XqE0WVwDxy1VRvvjSSGu5nB0Bu+6SA==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.2.1", + "@eslint/eslintrc": "^1.2.3", "@humanwhocodes/config-array": "^0.9.2", "ajv": "^6.10.0", "chalk": "^4.0.0", @@ -12748,7 +14050,7 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.1", + "espree": "^9.3.2", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -12764,7 +14066,7 @@ "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "regexpp": "^3.2.0", @@ -12826,9 +14128,9 @@ } }, "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dev": true, "requires": { "array-includes": "^3.1.4", @@ -12836,14 +14138,14 @@ "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { @@ -12872,10 +14174,17 @@ } } }, + "eslint-plugin-jquery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jquery/-/eslint-plugin-jquery-1.5.1.tgz", + "integrity": "sha512-L7v1eaK5t80C0lvUXPFP9MKnBOqPSKhCOYyzy4LZ0+iK+TJwN8S9gAkzzP1AOhypRIwA88HF6phQ9C7jnOpW8w==", + "dev": true, + "requires": {} + }, "eslint-plugin-unicorn": { - "version": "41.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-41.0.1.tgz", - "integrity": "sha512-gF5vo2dIj0YdNMQ/IMegiBkQdQ22GBFFVpdkJP+0og3w7XD4ypea0xQVRv6iofkLVR2w0phAdikcnU01ybd4Ow==", + "version": "42.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-42.0.0.tgz", + "integrity": "sha512-ixBsbhgWuxVaNlPTT8AyfJMlhyC5flCJFjyK3oKE8TRrwBnaHvUbuIkCM1lqg8ryYrFStL/T557zfKzX4GKSlg==", "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.15.7", @@ -12895,15 +14204,18 @@ } }, "eslint-plugin-vue": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-8.5.0.tgz", - "integrity": "sha512-i1uHCTAKOoEj12RDvdtONWrGzjFm/djkzqfhmQ0d6M/W8KM81mhswd/z+iTZ0jCpdUedW3YRgcVfQ37/J4zoYQ==", + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.0.1.tgz", + "integrity": "sha512-/w/9/vzz+4bSYtp5UqXgJ0CfycXTMtpp6lkz7/fMp0CcJxPWyRP6Pr88ihhrsNEcVt2ZweMupWRNYa+5Md41LQ==", "dev": true, "requires": { "eslint-utils": "^3.0.0", "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", "semver": "^7.3.5", - "vue-eslint-parser": "^8.0.1" + "vue-eslint-parser": "^9.0.1", + "xml-name-validator": "^4.0.0" } }, "eslint-scope": { @@ -12940,13 +14252,13 @@ "dev": true }, "espree": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", - "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", + "version": "9.3.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.2.tgz", + "integrity": "sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA==", "dev": true, "requires": { - "acorn": "^8.7.0", - "acorn-jsx": "^5.3.1", + "acorn": "^8.7.1", + "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" } }, @@ -13021,15 +14333,72 @@ "dev": true }, "expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.0.tgz", + "integrity": "sha512-qFXKl8Pmxk8TBGfaFKRtcQjfXEnKAs+dmlxdwvukJZorwrAabT7M3h8oLOG01I2utEhkmUTi17CHaPBovZsKdw==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/expect-utils": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "fast-deep-equal": { @@ -13140,13 +14509,13 @@ "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" }, "form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz", + "integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", + "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, @@ -13167,12 +14536,30 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, "functional-red-black-tree": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -13202,6 +14589,12 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-port": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-3.2.0.tgz", + "integrity": "sha1-3Xzn3hh8Bsi/NTeWrHHgmfCYDrw=", + "dev": true + }, "get-stdin": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", @@ -13224,14 +14617,14 @@ } }, "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -13282,9 +14675,9 @@ } }, "globals": { - "version": "13.13.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", - "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", + "version": "13.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.15.0.tgz", + "integrity": "sha512-bpzcOlgDhMG070Av0Vy5Owklpv1I6+j96GhUI7Rh7IzDCKLzboflLrrfqMu8NquDbiR4EOQk7XzJwqVJxicxog==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -13311,9 +14704,9 @@ "dev": true }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "graphlib": { "version": "2.1.8", @@ -13324,9 +14717,24 @@ } }, "gsap": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.9.1.tgz", - "integrity": "sha512-JSGVYoC6da4pIjdF/yxFU6Rz8OojOIDkbooveZlfNg0+JIoFoRruyfWAEi6R/gUeNcuOiTqUIb0gi1nCNrHf8w==" + "version": "3.10.4", + "resolved": "https://registry.npmjs.org/gsap/-/gsap-3.10.4.tgz", + "integrity": "sha512-6QatdkKxXCMfvCW4rM++0RqyLQAzFX5nwl3yHS0XPgkZBkiSEY3VZVbMltrdtsbER/xZonLtyHt684wRp4erlQ==" + }, + "happy-dom": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-4.0.1.tgz", + "integrity": "sha512-GUj2ayfbWYHPeQfcK0N+lygRE/DsrjQbALJq0zrxHLc9KYzhFSCmaCOISuNgHV/21EEeVIX55KoPTqMcX362+g==", + "dev": true, + "requires": { + "css.escape": "^1.5.1", + "he": "^1.2.0", + "node-fetch": "^2.x.x", + "sync-request": "^6.1.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0" + } }, "hard-rejection": { "version": "2.1.0", @@ -13343,9 +14751,9 @@ } }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "dev": true }, "has-flag": { @@ -13353,10 +14761,19 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, "has-tostringtag": { @@ -13384,15 +14801,6 @@ "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, - "html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.5" - } - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -13400,9 +14808,9 @@ "dev": true }, "html-tags": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz", - "integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.2.0.tgz", + "integrity": "sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==", "dev": true }, "htmlparser2": { @@ -13417,25 +14825,33 @@ "entities": "^3.0.1" } }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "http-basic": { + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/http-basic/-/http-basic-8.1.3.tgz", + "integrity": "sha512-/EcDMwJZh3mABI2NhGfHOGOeOZITqfkEO4p/xK+l3NpyncIHUQBoMvCSF/b5GqvKtySC2srL/GGG3+EtlqlmCw==", "dev": true, "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "caseless": "^0.12.0", + "concat-stream": "^1.6.2", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" } }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", "dev": true, "requires": { - "agent-base": "6", - "debug": "4" + "@types/node": "^10.0.3" + }, + "dependencies": { + "@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==", + "dev": true + } } }, "human-signals": { @@ -13588,9 +15004,9 @@ "dev": true }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "requires": { "has": "^1.0.3" } @@ -13640,9 +15056,9 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dev": true, "requires": { "has-tostringtag": "^1.0.0" @@ -13660,12 +15076,6 @@ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", "dev": true }, - "is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -13683,10 +15093,13 @@ "dev": true }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } }, "is-stream": { "version": "2.0.1", @@ -13711,12 +15124,6 @@ "has-symbols": "^1.0.2" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, "is-weakref": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", @@ -13731,6 +15138,12 @@ "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -13748,9 +15161,9 @@ "dev": true }, "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dev": true, "requires": { "@babel/core": "^7.12.3", @@ -13801,104 +15214,280 @@ } }, "jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.0.tgz", + "integrity": "sha512-TZR+tHxopPhzw3c3560IJXZWLNHgpcz1Zh0w5A65vynLGNcg/5pZ+VildAd7+XGOu6jd58XMY/HNn0IkZIXVXg==", "dev": true, "requires": { - "@jest/core": "^27.5.1", + "@jest/core": "^28.1.0", "import-local": "^3.0.2", - "jest-cli": "^27.5.1" + "jest-cli": "^28.1.0" } }, "jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.0.2.tgz", + "integrity": "sha512-QX9u+5I2s54ZnGoMEjiM2WeBvJR2J7w/8ZUmH2um/WLAuGAYFQcsVXY9+1YL6k0H/AGUdH8pXUAv6erDqEsvIA==", "dev": true, "requires": { - "@jest/types": "^27.5.1", "execa": "^5.0.0", "throat": "^6.0.1" } }, "jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.0.tgz", + "integrity": "sha512-rNYfqfLC0L0zQKRKsg4n4J+W1A2fbyGH7Ss/kDIocp9KXD9iaL111glsLu7+Z7FHuZxwzInMDXq+N1ZIBkI/TQ==", "dev": true, "requires": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.0", + "@jest/expect": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", + "jest-each": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" + }, + "dependencies": { + "@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + } + }, + "@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.0.tgz", + "integrity": "sha512-fDJRt6WPRriHrBsvvgb93OxgajHHsJbk4jZxiPqmZbMDRcHskfJBBfTyjFko0jjfprP544hOktdSi9HVgl4VUQ==", "dev": true, "requires": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/core": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-config": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", "prompts": "^2.0.1", - "yargs": "^16.2.0" + "yargs": "^17.3.1" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.0.tgz", + "integrity": "sha512-aOV80E9LeWrmflp7hfZNn/zGA4QKv/xsn2w8QCBP0t0+YqObuCWTSgNbHJ0j9YsTuCO08ZR/wsvlxqqHX20iUA==", "dev": true, "requires": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.0", + "@jest/types": "^28.1.0", + "babel-jest": "^28.1.0", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-circus": "^28.1.0", + "jest-environment-node": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-runner": "^28.1.0", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", + "pretty-format": "^28.1.0", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-diff": { @@ -13911,57 +15500,213 @@ "diff-sequences": "^27.5.1", "jest-get-type": "^27.5.1", "pretty-format": "^27.5.1" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } } }, "jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.0.2.tgz", + "integrity": "sha512-FH10WWw5NxLoeSdQlJwu+MTiv60aXV/t8KEwIRGEv74WARE1cXIqh1vGdy2CraHuWOOrnzTWj/azQKqW4fO7xg==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.0.tgz", + "integrity": "sha512-a/XX02xF5NTspceMpHujmOexvJ4GftpYXqr6HhhmKmExtMXsyIN/fvanQlt/BcgFoRKN4OCXxLQKth9/n6OPFg==", "dev": true, "requires": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" - } - }, - "jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.0", + "pretty-format": "^28.1.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.0.tgz", + "integrity": "sha512-gBLZNiyrPw9CSMlTXF1yJhaBgWDPVvH0Pq6bOEwGMXaYNzhzhw2kA/OijNF8egbCgDS0/veRv97249x2CX+udQ==", "dev": true, "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + }, + "dependencies": { + "@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + } + }, + "@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-extended": { @@ -13972,80 +15717,121 @@ "requires": { "jest-diff": "^27.2.5", "jest-get-type": "^27.0.6" + }, + "dependencies": { + "jest-get-type": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", + "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "dev": true + } } }, "jest-get-type": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.5.1.tgz", - "integrity": "sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", "dev": true }, "jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.0.tgz", + "integrity": "sha512-xyZ9sXV8PtKi6NCrJlmq53PyNVHzxmcfXNVvIRHpHmh1j/HChC4pwKgyjj7Z9us19JMw8PpQTJsFWOsIfT93Dw==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", + "@jest/types": "^28.1.0", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.0", + "jest-worker": "^28.1.0", "micromatch": "^4.0.4", "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", - "dev": true, - "requires": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.0.tgz", + "integrity": "sha512-uIJDQbxwEL2AMMs2xjhZl2hw8s77c3wrPaQ9v6tXJLGaaQ+4QrNJH5vuw7hA7w/uGT/iJ42a83opAqxGHeyRIA==", "dev": true, "requires": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" } }, "jest-matcher-utils": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", - "integrity": "sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.0.tgz", + "integrity": "sha512-onnax0n2uTLRQFKAjC7TuaxibrPSvZgKTcSCnNUz/tOjJ9UhxNm7ZmPpoQavmTDUjXvUQ8KesWk2/VdrxIFzTQ==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + }, + "dependencies": { + "diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true + }, + "jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + } } }, "jest-message-util": { @@ -14063,6 +15849,31 @@ "pretty-format": "^27.5.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + }, + "pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + } + }, + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + } } }, "jest-mock": { @@ -14082,144 +15893,442 @@ "dev": true, "requires": {} }, - "jest-raw-loader": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/jest-raw-loader/-/jest-raw-loader-1.0.1.tgz", - "integrity": "sha1-zp9W1UZQ8VfEp9FtIkul1hO81iY=", - "dev": true - }, "jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", "dev": true }, "jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.0.tgz", + "integrity": "sha512-vvfN7+tPNnnhDvISuzD1P+CRVP8cK0FHXRwPAcdDaQv4zgvwvag2n55/h5VjYcM5UJG7L4TwE5tZlzcI0X2Lhw==", "dev": true, "requires": { - "@jest/types": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", + "jest-haste-map": "^28.1.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-util": "^28.1.0", + "jest-validate": "^28.1.0", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.0.tgz", + "integrity": "sha512-Ue1VYoSZquPwEvng7Uefw8RmZR+me/1kr30H2jMINjGeHgeO/JgrR6wxj2ofkJ7KSAA11W3cOrhNCbj5Dqqd9g==", "dev": true, "requires": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.0" } }, "jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.0.tgz", + "integrity": "sha512-FBpmuh1HB2dsLklAlRdOxNTTHKFR6G1Qmd80pVDvwbZXTriqjWqjei5DKFC1UlM732KjYcE6yuCdiF0WUCOS2w==", "dev": true, "requires": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.0", + "@jest/environment": "^28.1.0", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "emittery": "^0.10.2", "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", + "jest-docblock": "^28.0.2", + "jest-environment-node": "^28.1.0", + "jest-haste-map": "^28.1.0", + "jest-leak-detector": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-resolve": "^28.1.0", + "jest-runtime": "^28.1.0", + "jest-util": "^28.1.0", + "jest-watcher": "^28.1.0", + "jest-worker": "^28.1.0", + "source-map-support": "0.5.13", "throat": "^6.0.1" + }, + "dependencies": { + "@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + } + }, + "@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.0.tgz", + "integrity": "sha512-wNYDiwhdH/TV3agaIyVF0lsJ33MhyujOe+lNTUiolqKt8pchy1Hq4+tDMGbtD5P/oNLA3zYrpx73T9dMTOCAcg==", "dev": true, "requires": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.0", + "@jest/fake-timers": "^28.1.0", + "@jest/globals": "^28.1.0", + "@jest/source-map": "^28.0.2", + "@jest/test-result": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.0", + "jest-snapshot": "^28.1.0", + "jest-util": "^28.1.0", "slash": "^3.0.0", "strip-bom": "^4.0.0" - } - }, - "jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "requires": { - "@types/node": "*", - "graceful-fs": "^4.2.9" + }, + "dependencies": { + "@jest/environment": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.0.tgz", + "integrity": "sha512-S44WGSxkRngzHslhV6RoAExekfF7Qhwa6R5+IYFa81mpcj0YgdBnRSmvHe3SNwOt64yXaE5GG8Y2xM28ii5ssA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/node": "*", + "jest-mock": "^28.1.0" + } + }, + "@jest/fake-timers": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.0.tgz", + "integrity": "sha512-Xqsf/6VLeAAq78+GNPzI7FZQRf5cCHj1qgQxCjws9n8rKw8r1UYoeaALwBvyuzOkpU3c1I6emeMySPa96rxtIg==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@sinonjs/fake-timers": "^9.1.1", + "@types/node": "*", + "jest-message-util": "^28.1.0", + "jest-mock": "^28.1.0", + "jest-util": "^28.1.0" + } + }, + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.0.tgz", + "integrity": "sha512-H7BrhggNn77WhdL7O1apG0Q/iwl0Bdd5E1ydhCJzL3oBLh/UYxAwR3EJLsBZ9XA3ZU4PA3UNw4tQjduBTCTmLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.0.tgz", + "integrity": "sha512-ex49M2ZrZsUyQLpLGxQtDbahvgBjlLPgklkqGM0hq/F7W/f8DyqZxVHjdy19QKBm4O93eDp+H5S23EiTbbUmHw==", "dev": true, "requires": { - "@babel/core": "^7.7.2", + "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.0", + "@jest/transform": "^28.1.0", + "@jest/types": "^28.1.0", + "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.5.1", + "expect": "^28.1.0", "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-diff": "^28.1.0", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.0", + "jest-matcher-utils": "^28.1.0", + "jest-message-util": "^28.1.0", + "jest-util": "^28.1.0", "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" + "pretty-format": "^28.1.0", + "semver": "^7.3.5" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "diff-sequences": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.0.2.tgz", + "integrity": "sha512-YtEoNynLDFCRznv/XDalsKGSZDoj0U5kLnXvY0JSq3nBboRrZXjD81+eSiwi+nzcZDwedMmcowcxNwwgFW23mQ==", + "dev": true + }, + "jest-diff": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.0.tgz", + "integrity": "sha512-8eFd3U3OkIKRtlasXfiAQfbovgFgRDb0Ngcs2E+FMeBZ4rUezqIaGjuyggJBp+llosQXNEWofk/Sz4Hr5gMUhA==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.0.2", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.0" + } + }, + "jest-message-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.0.tgz", + "integrity": "sha512-RpA8mpaJ/B2HphDMiDlrAZdDytkmwFqgjDZovM21F35lHGeUeCvYmm6W+sbQ0ydaLpg5bFAUuWG1cjqOl8vqrw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-util": { @@ -14237,19 +16346,42 @@ } }, "jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.0.tgz", + "integrity": "sha512-Lly7CJYih3vQBfjLeANGgBSBJ7pEa18cxpQfQEq2go2xyEzehnHfQTjoUia8xUv4x4J80XKFIDwJJThXtRFQXQ==", "dev": true, "requires": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.0", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", + "jest-get-type": "^28.0.2", "leven": "^3.1.0", - "pretty-format": "^27.5.1" + "pretty-format": "^28.1.0" }, "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", @@ -14259,24 +16391,65 @@ } }, "jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.0.tgz", + "integrity": "sha512-tNHMtfLE8Njcr2IRS+5rXYA4BhU90gAOwI9frTGOqd+jX0P/Au/JfRSNqsf5nUTcWdbVYuLxS1KjnzILSoR5hA==", "dev": true, "requires": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/test-result": "^28.1.0", + "@jest/types": "^28.1.0", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.5.1", + "emittery": "^0.10.2", + "jest-util": "^28.1.0", "string-length": "^4.0.1" + }, + "dependencies": { + "@jest/types": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.0.tgz", + "integrity": "sha512-xmEggMPr317MIOjjDoZ4ejCSr9Lpbt/u34+dvc99t7DS8YirW5rwZEhzKPC2BMUFkUhI48qs6qLUSGw5FuL0GA==", + "dev": true, + "requires": { + "@jest/schemas": "^28.0.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@types/yargs": { + "version": "17.0.10", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.10.tgz", + "integrity": "sha512-gmEaFwpj/7f/ROdtIlci1R1VYU1J4j95m8T+Tj3iBgiBFKg1foE/PSl93bBd5T9LDXNPo8UlNN6W0qwD8O5OaA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "jest-util": { + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.0.tgz", + "integrity": "sha512-qYdCKD77k4Hwkose2YBEqQk7PzUf/NSE+rutzceduFveQREeH6b+89Dc9+wjX9dAwHcgdx4yedGA3FQlU/qCTA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + } } }, "jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.0.tgz", + "integrity": "sha512-ZHwM6mNwaWBR52Snff8ZvsCTqQsvhCxP/bT1I6T6DAnb6ygkshsyLQIMxFwHpYxht0HOoqt23JlC01viI7T03A==", + "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", @@ -14287,6 +16460,7 @@ "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -14326,57 +16500,16 @@ "argparse": "^2.0.1" } }, - "jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "requires": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - } - }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" - }, "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema-traverse": { "version": "0.4.1", @@ -14390,12 +16523,9 @@ "dev": true }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, "just-extend": { "version": "5.1.1", @@ -14403,9 +16533,9 @@ "integrity": "sha512-b+z6yF1d4EOyDgylzQo5IminlUmzSeqR1hs/bzjBNjuGras4FXq/6TrzjxfN0j+TmI0ltJzTNlqXUMCniciwKQ==" }, "khroma": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/khroma/-/khroma-1.4.1.tgz", - "integrity": "sha512-+GmxKvmiRuCcUYDgR7g5Ngo0JEDeOsGdNONdU2zsiBQaK4z19Y2NvXqfEDE0ZiIrg45GTZyAnPLVsLZZACYm3Q==" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.0.0.tgz", + "integrity": "sha512-2J8rDNlQWbtiNYThZRvmMv5yt44ZakX+Tz5ZIp/mN1pt4snn+m030Va5Z4v8xA0cQFDXBwO/8i42xL4QPsVk3g==" }, "kind-of": { "version": "6.0.3", @@ -14424,9 +16554,9 @@ "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==" }, "known-css-properties": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.24.0.tgz", - "integrity": "sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==", + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.25.0.tgz", + "integrity": "sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==", "dev": true }, "less": { @@ -14465,9 +16595,9 @@ } }, "less-loader": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-10.2.0.tgz", - "integrity": "sha512-AV5KHWvCezW27GT90WATaDnfXBv99llDbtaj4bshq6DvAihMdNjaPDcUMa6EXKLRF+P2opFenJp89BXg91XLYg==", + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", "requires": { "klona": "^2.0.4" } @@ -14537,9 +16667,9 @@ "dev": true }, "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==" }, "loader-utils": { "version": "2.0.2", @@ -14577,6 +16707,11 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -14641,9 +16776,9 @@ "dev": true }, "marked": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.12.tgz", - "integrity": "sha512-hgibXWrEDNBWgGiK18j/4lkS6ihTe9sxtV4Q1OQppb/0zzyPSzoFANBa5MfsG/zgsWklmNnhm0XACZOH/0HBiQ==" + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.16.tgz", + "integrity": "sha512-wahonIQ5Jnyatt2fn8KqF/nIqZM8mh3oRu2+l5EANGMhu6RFjiSG52QNE2eWzFMI94HqYSgN184NurgNG6CztA==" }, "mathml-tag-names": { "version": "2.1.3", @@ -14725,28 +16860,28 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" }, "mermaid": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-8.14.0.tgz", - "integrity": "sha512-ITSHjwVaby1Li738sxhF48sLTxcNyUAoWfoqyztL1f7J6JOLpHOuQPNLBb6lxGPUA0u7xP9IRULgvod0dKu35A==", + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.1.tgz", + "integrity": "sha512-2RVD+WkzZ4VDyO9gQvQAuQ/ux2gLigJtKDTlbwjYqOR/NwsVzTSfGm/kx648/qWJsg6Sv04tE9BWCO8s6a+pFA==", "requires": { - "@braintree/sanitize-url": "^3.1.0", + "@braintree/sanitize-url": "^6.0.0", "d3": "^7.0.0", "dagre": "^0.8.5", "dagre-d3": "^0.6.4", - "dompurify": "2.3.5", + "dompurify": "2.3.6", "graphlib": "^2.1.8", - "khroma": "^1.4.1", + "khroma": "^2.0.0", "moment-mini": "^2.24.0", "stylis": "^4.0.10" } }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime": { @@ -14756,16 +16891,16 @@ "optional": true }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -14788,9 +16923,9 @@ } }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "requires": { "brace-expansion": "^1.1.7" } @@ -14836,9 +16971,9 @@ "devOptional": true }, "nanoid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.2.tgz", - "integrity": "sha512-CuHBogktKwpm5g2sRgv83jEy2ijFzBwMoYA60orPDR7ynsLijJDqgsi4RDGj3OJpy3Ieb+LYwiRmIOGyytgITA==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, "natural-compare": { "version": "1.4.0", @@ -14882,6 +17017,15 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dev": true, + "requires": { + "whatwg-url": "^5.0.0" + } + }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -14889,9 +17033,9 @@ "dev": true }, "node-releases": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", - "integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==" }, "normalize-package-data": { "version": "2.5.0", @@ -14942,12 +17086,6 @@ "boolbase": "^1.0.0" } }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -15051,6 +17189,12 @@ "callsites": "^3.0.0" } }, + "parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha1-juqz5U+laSD+Fro493+iGqzC104=", + "dev": true + }, "parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -15073,12 +17217,6 @@ "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -15193,11 +17331,11 @@ "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==" }, "postcss": { - "version": "8.4.12", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", - "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", "requires": { - "nanoid": "^3.3.1", + "nanoid": "^3.3.4", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -15261,9 +17399,9 @@ "requires": {} }, "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -15281,20 +17419,21 @@ "dev": true }, "prettier": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", - "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.2.tgz", + "integrity": "sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==", "optional": true }, "pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "28.1.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.0.tgz", + "integrity": "sha512-79Z4wWOYCdvQkEoEuSlBhHJqWeZ8D8YRPiPctJFCtvuaClGpiwiQYSCUOE6IEKUbbFukKOTFIUAXE8N4EQTo1Q==", "dev": true, "requires": { + "@jest/schemas": "^28.0.2", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "react-is": "^18.0.0" }, "dependencies": { "ansi-styles": { @@ -15313,6 +17452,21 @@ "parse-ms": "^2.1.0" } }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.1.0.tgz", + "integrity": "sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==", + "dev": true, + "requires": { + "asap": "~2.0.6" + } + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -15334,17 +17488,20 @@ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, - "psl": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", - "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", - "dev": true - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, + "qs": { + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -15365,9 +17522,9 @@ } }, "react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.1.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.1.0.tgz", + "integrity": "sha512-Fl7FuabXsJnV5Q1qIOQwx/sagGF18kogb4gpfcG4gjLBWO0WDiiz1ko/ExayuxE7InyQkBLkxRFG5oxY6Uu3Kg==", "dev": true }, "read-pkg": { @@ -15458,6 +17615,21 @@ } } }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, "rechoir": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", @@ -15487,6 +17659,17 @@ "integrity": "sha512-s2aEVuLhvnVJW6s/iPgEGK6R+/xngd2jNQ+xy4bXNDKxZKJH6jpPHY6kVeVv1IeLCHgswRj+Kl3ELaDjG6V1iw==", "dev": true }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, "regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", @@ -15598,15 +17781,6 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", "optional": true }, - "saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "requires": { - "xmlchars": "^2.2.0" - } - }, "schema-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", @@ -15619,9 +17793,9 @@ }, "dependencies": { "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -15645,9 +17819,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -15741,9 +17915,10 @@ "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" }, "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -15846,6 +18021,15 @@ } } }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -15867,23 +18051,25 @@ } }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "strip-ansi": { @@ -15927,9 +18113,9 @@ "dev": true }, "stylelint": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.6.1.tgz", - "integrity": "sha512-FfNdvZUZdzh9KDQxDnO7Opp+prKh8OQVuSW8S13cBtxrooCbm6J6royhUeb++53WPMt04VB+ZbOz/QmzAijs6Q==", + "version": "14.8.2", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.8.2.tgz", + "integrity": "sha512-tjDfexCYfoPdl/xcDJ9Fv+Ko9cvzbDnmdiaqEn3ovXHXasi/hbkt5tSjsiReQ+ENqnz0eltaX/AOO+AlzVdcNA==", "dev": true, "requires": { "balanced-match": "^2.0.0", @@ -15945,23 +18131,23 @@ "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", - "html-tags": "^3.1.0", + "html-tags": "^3.2.0", "ignore": "^5.2.0", "import-lazy": "^4.0.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.24.0", + "known-css-properties": "^0.25.0", "mathml-tag-names": "^2.1.3", "meow": "^9.0.0", - "micromatch": "^4.0.4", + "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "normalize-selector": "^0.2.0", "picocolors": "^1.0.0", - "postcss": "^8.4.12", + "postcss": "^8.4.13", "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.9", + "postcss-selector-parser": "^6.0.10", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "specificity": "^0.4.1", @@ -15986,16 +18172,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true - }, - "write-file-atomic": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", - "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } } } }, @@ -16016,9 +18192,9 @@ } }, "stylis": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", - "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.1.1.tgz", + "integrity": "sha512-lVrM/bNdhVX2OgBFNa2YJ9Lxj7kPzylieHd3TNjuGE0Re9JB7joL5VUKOVH1kdNNJTgGPpT8hmwIAPLaSyEVFQ==" }, "superstruct": { "version": "0.10.13", @@ -16071,15 +18247,29 @@ } }, "swagger-ui-dist": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.10.0.tgz", - "integrity": "sha512-+RBJA/beHLg0hO4rJZIhgUdxmZE7AaNfc11PCSzZdnzkmwSJv8Qg0HZbr7BQPQjkC6z4xVWq2h1itOPk1FQBrA==" + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.11.1.tgz", + "integrity": "sha512-pf3kfSTYdF9mYFY2VnfJ51wnXlSVhEGdtymhpHzfbFw2jTbiEWgBoVz5EB9aW2EaJvUGTM1YHAXYZX7Jk4RdAQ==" }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "sync-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sync-request/-/sync-request-6.1.0.tgz", + "integrity": "sha512-8fjNkrNlNCrVc/av+Jn+xxqfCjYaBoHqCsDz6mt030UMxJGr+GSfCV1dQt2gRtlL63+VPidwDVLr7V2OcTSdRw==", + "dev": true, + "requires": { + "http-response-object": "^3.0.1", + "sync-rpc": "^1.2.1", + "then-request": "^6.0.0" + } + }, + "sync-rpc": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/sync-rpc/-/sync-rpc-1.3.6.tgz", + "integrity": "sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==", + "dev": true, + "requires": { + "get-port": "^3.1.0" + } }, "table": { "version": "6.8.0", @@ -16095,9 +18285,9 @@ }, "dependencies": { "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dev": true, "requires": { "fast-deep-equal": "^3.1.1", @@ -16130,12 +18320,13 @@ } }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", + "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", "requires": { + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", + "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "dependencies": { @@ -16145,9 +18336,51 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" }, "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "requires": { + "whatwg-url": "^7.0.0" + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } } } }, @@ -16163,6 +18396,16 @@ "terser": "^5.7.2" }, "dependencies": { + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + } + }, "schema-utils": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", @@ -16172,6 +18415,14 @@ "ajv": "^6.12.5", "ajv-keywords": "^3.5.2" } + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -16192,6 +18443,33 @@ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, + "then-request": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/then-request/-/then-request-6.0.2.tgz", + "integrity": "sha512-3ZBiG7JvP3wbDzA9iNY5zJQcHL4jn/0BWtXIkagfz7QgOL/LqjCEOBQuJNZfu0XYnv5JhKh+cDxCPM4ILrqruA==", + "dev": true, + "requires": { + "@types/concat-stream": "^1.6.0", + "@types/form-data": "0.0.33", + "@types/node": "^8.0.0", + "@types/qs": "^6.2.31", + "caseless": "~0.12.0", + "concat-stream": "^1.6.0", + "form-data": "^2.2.0", + "http-basic": "^8.1.1", + "http-response-object": "^3.0.1", + "promise": "^8.0.0", + "qs": "^6.4.0" + }, + "dependencies": { + "@types/node": { + "version": "8.10.66", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.66.tgz", + "integrity": "sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==", + "dev": true + } + } + }, "throat": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", @@ -16218,25 +18496,11 @@ "is-number": "^7.0.0" } }, - "tough-cookie": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", - "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", - "dev": true, - "requires": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.1.2" - } - }, "tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true }, "tributejs": { "version": "5.1.3", @@ -16250,14 +18514,14 @@ "dev": true }, "tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dev": true, "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { @@ -16279,9 +18543,9 @@ } }, "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "type-check": { "version": "0.4.0", @@ -16304,14 +18568,11 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, - "typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "requires": { - "is-typedarray": "^1.0.0" - } + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true }, "typo-js": { "version": "1.2.1", @@ -16324,27 +18585,21 @@ "integrity": "sha512-r13jrghEYZAN99GeYpEjM107DOxqB65enskpwce8rRHVAGEtaWmsF5GqoGdPMf8DIXc9XyAJTdvlvRZi4LsszA==" }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dev": true, "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, - "universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true - }, "updates": { - "version": "13.0.4", - "resolved": "https://registry.npmjs.org/updates/-/updates-13.0.4.tgz", - "integrity": "sha512-RgHZnmTlcoRdn2yA8FZUwlRj7ltEANZQvh3ISAoSZcxunIv2s5EpFnZh8jgU7DigtX4ogm4XSn0r5O4u+cF7sg==", + "version": "13.0.5", + "resolved": "https://registry.npmjs.org/updates/-/updates-13.0.5.tgz", + "integrity": "sha512-ut7RIiH5Qys7jan4cS9i1Lqk6AAKGmVy1q0udDNJ4YXhvVoUdwQTAk5I9/wkSH6nHQtqhaqytCcZvS6hEJs8xg==", "dev": true }, "uri-js": { @@ -16378,22 +18633,14 @@ "dev": true }, "v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.0.0.tgz", + "integrity": "sha512-HcvgY/xaRm7isYmyx+lFKA4uQmfUbN0J4M0nNItvzTvH/iQ9kW5j/t4YSR+Ge323/lrgDAWJoF46tzGQHwBHFw==", "dev": true, "requires": { + "@jridgewell/trace-mapping": "^0.3.7", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } + "convert-source-map": "^1.6.0" } }, "validate-npm-package-license": { @@ -16429,18 +18676,18 @@ } }, "vue-eslint-parser": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.2.0.tgz", - "integrity": "sha512-hvl8OVT8imlKk/lQyhkshqwQQChzHETcBd5abiO4ePw7ib7QUZLfW+2TUrJHKUvFOCFRJrDin5KJO9OHzB5bRQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.0.2.tgz", + "integrity": "sha512-uCPQwTGjOtAYrwnU+76pYxalhjsh7iFBsHwBqDHiOPTxtICDaraO4Szw54WFTNZTAEsgHHzqFOu1mmnBOBRzDA==", "dev": true, "requires": { - "debug": "^4.3.2", - "eslint-scope": "^7.0.0", - "eslint-visitor-keys": "^3.1.0", - "espree": "^9.0.0", + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", "esquery": "^1.4.0", "lodash": "^4.17.21", - "semver": "^7.3.5" + "semver": "^7.3.6" } }, "vue-hot-reload-api": { @@ -16531,24 +18778,6 @@ "resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz", "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==" }, - "w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "dev": true, - "requires": { - "browser-process-hrtime": "^1.0.0" - } - }, - "w3c-xmlserializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "requires": { - "xml-name-validator": "^3.0.0" - } - }, "walker": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", @@ -16568,15 +18797,15 @@ } }, "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true }, "webpack": { - "version": "5.70.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", - "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "version": "5.72.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", + "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", "requires": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -16587,13 +18816,13 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.2", + "enhanced-resolve": "^5.9.3", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", "graceful-fs": "^4.2.9", - "json-parse-better-errors": "^1.0.2", + "json-parse-even-better-errors": "^2.3.1", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", @@ -16673,40 +18902,36 @@ } }, "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, "requires": { - "iconv-lite": "0.4.24" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } + "iconv-lite": "0.6.3" } }, "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true }, "whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "dev": true, "requires": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + }, + "dependencies": { + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", + "dev": true + } } }, "which": { @@ -16742,24 +18967,24 @@ "dev": true }, "workbox-core": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.2.tgz", - "integrity": "sha512-IlxLGQf+wJHCR+NM0UWqDh4xe/Gu6sg2i4tfZk6WIij34IVk9BdOQgi6WvqSHd879jbQIUgL2fBdJUJyAP5ypQ==" + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/workbox-core/-/workbox-core-6.5.3.tgz", + "integrity": "sha512-Bb9ey5n/M9x+l3fBTlLpHt9ASTzgSGj6vxni7pY72ilB/Pb3XtN+cZ9yueboVhD5+9cNQrC9n/E1fSrqWsUz7Q==" }, "workbox-routing": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.2.tgz", - "integrity": "sha512-nR1w5PjF6IVwo0SX3oE88LhmGFmTnqqU7zpGJQQPZiKJfEKgDENQIM9mh3L1ksdFd9Y3CZVkusopHfxQvit/BA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.5.3.tgz", + "integrity": "sha512-DFjxcuRAJjjt4T34RbMm3MCn+xnd36UT/2RfPRfa8VWJGItGJIn7tG+GwVTdHmvE54i/QmVTJepyAGWtoLPTmg==", "requires": { - "workbox-core": "6.5.2" + "workbox-core": "6.5.3" } }, "workbox-strategies": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.2.tgz", - "integrity": "sha512-fgbwaUMxbG39BHjJIs2y2X21C0bmf1Oq3vMQxJ1hr6y5JMJIm8rvKCcf1EIdAr+PjKdSk4ddmgyBQ4oO8be4Uw==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.5.3.tgz", + "integrity": "sha512-MgmGRrDVXs7rtSCcetZgkSZyMpRGw8HqL2aguszOc3nUmzGZsT238z/NN9ZouCxSzDu3PQ3ZSKmovAacaIhu1w==", "requires": { - "workbox-core": "6.5.2" + "workbox-core": "6.5.3" } }, "worker-loader": { @@ -16809,9 +19034,9 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "string-width": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.0.tgz", - "integrity": "sha512-7x54QnN21P+XL/v8SuNKvfgsUre6PXpN7mc77N3HlZv+f1SBRGmjxtOud2Z6FZ8DmdkD/IdjCaf9XXbnqmTZGQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "requires": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -16834,34 +19059,19 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz", + "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==", "dev": true, "requires": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" + "signal-exit": "^3.0.7" } }, - "ws": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", - "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "requires": {} - }, "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true }, "y18n": { @@ -16882,18 +19092,26 @@ "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" + }, + "dependencies": { + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", + "dev": true + } } }, "yargs-parser": { diff --git a/package.json b/package.json index db3d877dc2..addf5633fb 100644 --- a/package.json +++ b/package.json @@ -8,27 +8,27 @@ }, "dependencies": { "@claviska/jquery-minicolors": "2.3.6", - "@primer/octicons": "17.0.0", + "@primer/octicons": "17.2.0", "add-asset-webpack-plugin": "2.0.1", "css-loader": "6.7.1", "dropzone": "6.0.0-beta.2", "easymde": "2.16.1", - "esbuild-loader": "2.18.0", + "esbuild-loader": "2.19.0", "escape-goat": "4.0.0", "fast-glob": "3.2.11", "font-awesome": "4.7.0", "jquery": "3.6.0", "jquery.are-you-sure": "1.9.0", "less": "4.1.2", - "less-loader": "10.2.0", + "less-loader": "11.0.0", "license-checker-webpack-plugin": "0.2.1", - "mermaid": "8.14.0", + "mermaid": "9.1.1", "mini-css-extract-plugin": "2.6.0", "monaco-editor": "0.33.0", "monaco-editor-webpack-plugin": "7.0.1", "pretty-ms": "7.0.1", "sortablejs": "1.15.0", - "swagger-ui-dist": "4.10.0", + "swagger-ui-dist": "4.11.1", "tributejs": "5.1.3", "uint8-to-base64": "0.2.0", "vue": "2.6.14", @@ -36,27 +36,28 @@ "vue-calendar-heatmap": "0.8.4", "vue-loader": "15.9.8", "vue-template-compiler": "2.6.14", - "webpack": "5.70.0", + "webpack": "5.72.1", "webpack-cli": "4.9.2", - "workbox-routing": "6.5.2", - "workbox-strategies": "6.5.2", + "workbox-routing": "6.5.3", + "workbox-strategies": "6.5.3", "worker-loader": "3.0.8", "wrap-ansi": "8.0.1" }, "devDependencies": { - "eslint": "8.12.0", + "@happy-dom/jest-environment": "4.0.1", + "eslint": "8.15.0", "eslint-plugin-html": "6.2.0", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-unicorn": "41.0.1", - "eslint-plugin-vue": "8.5.0", - "jest": "27.5.1", + "eslint-plugin-import": "2.26.0", + "eslint-plugin-jquery": "1.5.1", + "eslint-plugin-unicorn": "42.0.0", + "eslint-plugin-vue": "9.0.1", + "jest": "28.1.0", "jest-extended": "2.0.0", - "jest-raw-loader": "1.0.1", "postcss-less": "6.0.0", - "stylelint": "14.6.1", + "stylelint": "14.8.2", "stylelint-config-standard": "25.0.0", "svgo": "2.8.0", - "updates": "13.0.4" + "updates": "13.0.5" }, "browserslist": [ "defaults", diff --git a/public/img/favicon.svg b/public/img/favicon.svg index dca9b4f4db..afeeacb77c 100644 --- a/public/img/favicon.svg +++ b/public/img/favicon.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/img/svg/octicon-cloud-offline.svg b/public/img/svg/octicon-cloud-offline.svg new file mode 100644 index 0000000000..7d34b8dff6 --- /dev/null +++ b/public/img/svg/octicon-cloud-offline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-cloud.svg b/public/img/svg/octicon-cloud.svg new file mode 100644 index 0000000000..fddfd2e424 --- /dev/null +++ b/public/img/svg/octicon-cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-file-added.svg b/public/img/svg/octicon-file-added.svg new file mode 100644 index 0000000000..c1ad23d296 --- /dev/null +++ b/public/img/svg/octicon-file-added.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-file-directory-open-fill.svg b/public/img/svg/octicon-file-directory-open-fill.svg new file mode 100644 index 0000000000..50809936e2 --- /dev/null +++ b/public/img/svg/octicon-file-directory-open-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-file-moved.svg b/public/img/svg/octicon-file-moved.svg new file mode 100644 index 0000000000..2e26b4cfd2 --- /dev/null +++ b/public/img/svg/octicon-file-moved.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-file-removed.svg b/public/img/svg/octicon-file-removed.svg new file mode 100644 index 0000000000..43c07295dd --- /dev/null +++ b/public/img/svg/octicon-file-removed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/img/svg/octicon-file.svg b/public/img/svg/octicon-file.svg index 4e05d6feb5..4037afad5e 100644 --- a/public/img/svg/octicon-file.svg +++ b/public/img/svg/octicon-file.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/public/img/svg/octicon-sliders.svg b/public/img/svg/octicon-sliders.svg new file mode 100644 index 0000000000..4ad22ab84b --- /dev/null +++ b/public/img/svg/octicon-sliders.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/routers/api/packages/container/container.go b/routers/api/packages/container/container.go index 08b6b421b0..2a564b3446 100644 --- a/routers/api/packages/container/container.go +++ b/routers/api/packages/container/container.go @@ -113,7 +113,6 @@ func apiErrorDefined(ctx *context.Context, err *namedError) { func ReqContainerAccess(ctx *context.Context) { if ctx.Doer == nil { ctx.Resp.Header().Add("WWW-Authenticate", `Bearer realm="`+setting.AppURL+`v2/token"`) - ctx.Resp.Header().Add("WWW-Authenticate", `Basic`) apiErrorDefined(ctx, errUnauthorized) } } diff --git a/routers/api/v1/admin/adopt.go b/routers/api/v1/admin/adopt.go index 3c39d7c2bc..8f11ab67f0 100644 --- a/routers/api/v1/admin/adopt.go +++ b/routers/api/v1/admin/adopt.go @@ -85,7 +85,7 @@ func AdoptRepository(ctx *context.APIContext) { ownerName := ctx.Params(":username") repoName := ctx.Params(":reponame") - ctxUser, err := user_model.GetUserByName(ownerName) + ctxUser, err := user_model.GetUserByName(ctx, ownerName) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound() @@ -96,7 +96,7 @@ func AdoptRepository(ctx *context.APIContext) { } // check not a repo - has, err := repo_model.IsRepositoryExist(ctxUser, repoName) + has, err := repo_model.IsRepositoryExist(ctx, ctxUser, repoName) if err != nil { ctx.InternalServerError(err) return @@ -147,7 +147,7 @@ func DeleteUnadoptedRepository(ctx *context.APIContext) { ownerName := ctx.Params(":username") repoName := ctx.Params(":reponame") - ctxUser, err := user_model.GetUserByName(ownerName) + ctxUser, err := user_model.GetUserByName(ctx, ownerName) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound() @@ -158,7 +158,7 @@ func DeleteUnadoptedRepository(ctx *context.APIContext) { } // check not a repo - has, err := repo_model.IsRepositoryExist(ctxUser, repoName) + has, err := repo_model.IsRepositoryExist(ctx, ctxUser, repoName) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/admin/user.go b/routers/api/v1/admin/user.go index 6263a67048..71932136b1 100644 --- a/routers/api/v1/admin/user.go +++ b/routers/api/v1/admin/user.go @@ -269,7 +269,7 @@ func EditUser(ctx *context.APIContext) { ctx.ContextUser.IsRestricted = *form.Restricted } - if err := user_model.UpdateUser(ctx.ContextUser, emailChanged); err != nil { + if err := user_model.UpdateUser(ctx, ctx.ContextUser, emailChanged); err != nil { if user_model.IsErrEmailAlreadyUsed(err) || user_model.IsErrEmailCharIsNotSupported(err) || user_model.IsErrEmailInvalid(err) { diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 0134790e2b..e1d13cd2dd 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -70,9 +70,9 @@ import ( "reflect" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -109,7 +109,7 @@ func sudo() func(ctx *context.APIContext) { if len(sudo) > 0 { if ctx.IsSigned && ctx.Doer.IsAdmin { - user, err := user_model.GetUserByName(sudo) + user, err := user_model.GetUserByName(ctx, sudo) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound() @@ -144,7 +144,7 @@ func repoAssignment() func(ctx *context.APIContext) { if ctx.IsSigned && ctx.Doer.LowerName == strings.ToLower(userName) { owner = ctx.Doer } else { - owner, err = user_model.GetUserByName(userName) + owner, err = user_model.GetUserByName(ctx, userName) if err != nil { if user_model.IsErrUserNotExist(err) { if redirectUserID, err := user_model.LookupUserRedirect(userName); err == nil { @@ -184,7 +184,7 @@ func repoAssignment() func(ctx *context.APIContext) { repo.Owner = owner ctx.Repo.Repository = repo - ctx.Repo.Permission, err = models.GetUserRepoPermission(ctx, repo, ctx.Doer) + ctx.Repo.Permission, err = access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return @@ -468,7 +468,7 @@ func orgAssignment(args ...bool) func(ctx *context.APIContext) { } if assignTeam { - ctx.Org.Team, err = organization.GetTeamByID(ctx.ParamsInt64(":teamid")) + ctx.Org.Team, err = organization.GetTeamByID(ctx, ctx.ParamsInt64(":teamid")) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.NotFound() @@ -593,6 +593,7 @@ func bind(obj interface{}) http.HandlerFunc { func buildAuthGroup() *auth.Group { group := auth.NewGroup( &auth.OAuth2{}, + &auth.HTTPSign{}, &auth.Basic{}, // FIXME: this should be removed once we don't allow basic auth in API ) if setting.Service.EnableReverseProxyAuth { @@ -831,6 +832,7 @@ func Routes() *web.Route { Delete(reqAdmin(), repo.DeleteTeam) }, reqToken()) m.Get("/raw/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFile) + m.Get("/media/*", context.ReferencesGitRepo(), context.RepoRefForAPI, reqRepoReader(unit.TypeCode), repo.GetRawFileOrLFS) m.Get("/archive/*", reqRepoReader(unit.TypeCode), repo.GetArchive) m.Combo("/forks").Get(repo.ListForks). Post(reqToken(), reqRepoReader(unit.TypeCode), bind(api.CreateForkOption{}), repo.CreateFork) diff --git a/routers/api/v1/misc/nodeinfo.go b/routers/api/v1/misc/nodeinfo.go index ce1f9ec0f7..c786544e14 100644 --- a/routers/api/v1/misc/nodeinfo.go +++ b/routers/api/v1/misc/nodeinfo.go @@ -30,8 +30,11 @@ func NodeInfo(ctx *context.APIContext) { nodeInfoUsage := structs.NodeInfoUsage{} if setting.Federation.ShareUserStatistics { - info, ok := ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage) - if !ok { + cached := false + if setting.CacheService.Enabled { + nodeInfoUsage, cached = ctx.Cache.Get(cacheKeyNodeInfoUsage).(structs.NodeInfoUsage) + } + if !cached { usersTotal := int(user_model.CountUsers(nil)) now := time.Now() timeOneMonthAgo := now.AddDate(0, -1, 0).Unix() @@ -42,7 +45,7 @@ func NodeInfo(ctx *context.APIContext) { allIssues, _ := models.CountIssues(&models.IssuesOptions{}) allComments, _ := models.CountComments(&models.FindCommentsOptions{}) - info = structs.NodeInfoUsage{ + nodeInfoUsage = structs.NodeInfoUsage{ Users: structs.NodeInfoUsageUsers{ Total: usersTotal, ActiveMonth: usersActiveMonth, @@ -51,12 +54,13 @@ func NodeInfo(ctx *context.APIContext) { LocalPosts: int(allIssues), LocalComments: int(allComments), } - if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil { - ctx.InternalServerError(err) - return + if setting.CacheService.Enabled { + if err := ctx.Cache.Put(cacheKeyNodeInfoUsage, nodeInfoUsage, 180); err != nil { + ctx.InternalServerError(err) + return + } } } - nodeInfoUsage = info } nodeInfo := &structs.NodeInfo{ diff --git a/routers/api/v1/notify/notifications.go b/routers/api/v1/notify/notifications.go index c707cf4524..0a3684fbe6 100644 --- a/routers/api/v1/notify/notifications.go +++ b/routers/api/v1/notify/notifications.go @@ -22,7 +22,7 @@ func NewAvailable(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/NotificationCount" - ctx.JSON(http.StatusOK, api.NotificationCount{New: models.CountUnread(ctx.Doer)}) + ctx.JSON(http.StatusOK, api.NotificationCount{New: models.CountUnread(ctx, ctx.Doer.ID)}) } func getFindNotificationOptions(ctx *context.APIContext) *models.FindNotificationOptions { diff --git a/routers/api/v1/notify/repo.go b/routers/api/v1/notify/repo.go index 0f6b90b05d..4e9dd806de 100644 --- a/routers/api/v1/notify/repo.go +++ b/routers/api/v1/notify/repo.go @@ -115,7 +115,7 @@ func ListRepoNotifications(ctx *context.APIContext) { return } - nl, err := models.GetNotifications(opts) + nl, err := models.GetNotifications(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -203,7 +203,7 @@ func ReadRepoNotifications(ctx *context.APIContext) { opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"}) log.Error("%v", opts.Status) } - nl, err := models.GetNotifications(opts) + nl, err := models.GetNotifications(ctx, opts) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/notify/user.go b/routers/api/v1/notify/user.go index ac3d0591d0..b923307783 100644 --- a/routers/api/v1/notify/user.go +++ b/routers/api/v1/notify/user.go @@ -75,7 +75,7 @@ func ListNotifications(ctx *context.APIContext) { return } - nl, err := models.GetNotifications(opts) + nl, err := models.GetNotifications(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -148,7 +148,7 @@ func ReadNotifications(ctx *context.APIContext) { statuses := ctx.FormStrings("status-types") opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"}) } - nl, err := models.GetNotifications(opts) + nl, err := models.GetNotifications(ctx, opts) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/org/hook.go b/routers/api/v1/org/hook.go index 67957430d1..ddf0ddefe6 100644 --- a/routers/api/v1/org/hook.go +++ b/routers/api/v1/org/hook.go @@ -51,7 +51,7 @@ func ListHooks(ctx *context.APIContext) { return } - orgHooks, err := webhook.ListWebhooksByOpts(opts) + orgHooks, err := webhook.ListWebhooksByOpts(ctx, opts) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/org/label.go b/routers/api/v1/org/label.go index d36b1d9a98..9844ea21d2 100644 --- a/routers/api/v1/org/label.go +++ b/routers/api/v1/org/label.go @@ -43,7 +43,7 @@ func ListLabels(ctx *context.APIContext) { // "200": // "$ref": "#/responses/LabelList" - labels, err := models.GetLabelsByOrgID(ctx.Org.Organization.ID, ctx.FormString("sort"), utils.GetListOptions(ctx)) + labels, err := models.GetLabelsByOrgID(ctx, ctx.Org.Organization.ID, ctx.FormString("sort"), utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsByOrgID", err) return @@ -136,9 +136,9 @@ func GetLabel(ctx *context.APIContext) { ) strID := ctx.Params(":id") if intID, err2 := strconv.ParseInt(strID, 10, 64); err2 != nil { - label, err = models.GetLabelInOrgByName(ctx.Org.Organization.ID, strID) + label, err = models.GetLabelInOrgByName(ctx, ctx.Org.Organization.ID, strID) } else { - label, err = models.GetLabelInOrgByID(ctx.Org.Organization.ID, intID) + label, err = models.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, intID) } if err != nil { if models.IsErrOrgLabelNotExist(err) { @@ -183,7 +183,7 @@ func EditLabel(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.EditLabelOption) - label, err := models.GetLabelInOrgByID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id")) + label, err := models.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrOrgLabelNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go index b24c8a6235..f8c37303d6 100644 --- a/routers/api/v1/org/team.go +++ b/routers/api/v1/org/team.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" @@ -57,14 +58,10 @@ func ListTeams(ctx *context.APIContext) { return } - apiTeams := make([]*api.Team, len(teams)) - for i := range teams { - if err := teams[i].GetUnits(); err != nil { - ctx.Error(http.StatusInternalServerError, "GetUnits", err) - return - } - - apiTeams[i] = convert.ToTeam(teams[i]) + apiTeams, err := convert.ToTeams(teams, false) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err) + return } ctx.SetTotalCountHeader(count) @@ -100,25 +97,10 @@ func ListUserTeams(ctx *context.APIContext) { return } - cache := make(map[int64]*api.Organization) - apiTeams := make([]*api.Team, len(teams)) - for i := range teams { - apiOrg, ok := cache[teams[i].OrgID] - if !ok { - org, err := organization.GetOrgByID(teams[i].OrgID) - if err != nil { - ctx.Error(http.StatusInternalServerError, "GetUserByID", err) - return - } - apiOrg = convert.ToOrganization(org) - cache[teams[i].OrgID] = apiOrg - } - if err := teams[i].GetUnits(); err != nil { - ctx.Error(http.StatusInternalServerError, "teams[i].GetUnits()", err) - return - } - apiTeams[i] = convert.ToTeam(teams[i]) - apiTeams[i].Organization = apiOrg + apiTeams, err := convert.ToTeams(teams, true) + if err != nil { + ctx.Error(http.StatusInternalServerError, "ConvertToTeams", err) + return } ctx.SetTotalCountHeader(count) @@ -143,12 +125,13 @@ func GetTeam(ctx *context.APIContext) { // "200": // "$ref": "#/responses/Team" - if err := ctx.Org.Team.GetUnits(); err != nil { - ctx.Error(http.StatusInternalServerError, "team.GetUnits", err) + apiTeam, err := convert.ToTeam(ctx.Org.Team) + if err != nil { + ctx.InternalServerError(err) return } - ctx.JSON(http.StatusOK, convert.ToTeam(ctx.Org.Team)) + ctx.JSON(http.StatusOK, apiTeam) } func attachTeamUnits(team *organization.Team, units []string) { @@ -240,7 +223,12 @@ func CreateTeam(ctx *context.APIContext) { return } - ctx.JSON(http.StatusCreated, convert.ToTeam(team)) + apiTeam, err := convert.ToTeam(team) + if err != nil { + ctx.InternalServerError(err) + return + } + ctx.JSON(http.StatusCreated, apiTeam) } // EditTeam api for edit a team @@ -317,7 +305,13 @@ func EditTeam(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "EditTeam", err) return } - ctx.JSON(http.StatusOK, convert.ToTeam(team)) + + apiTeam, err := convert.ToTeam(team) + if err != nil { + ctx.InternalServerError(err) + return + } + ctx.JSON(http.StatusOK, apiTeam) } // DeleteTeam api for delete a team @@ -547,7 +541,7 @@ func GetTeamRepos(ctx *context.APIContext) { } repos := make([]*api.Repository, len(teamRepos)) for i, repo := range teamRepos { - access, err := models.AccessLevel(ctx.Doer, repo) + access, err := access_model.AccessLevel(ctx.Doer, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) return @@ -598,7 +592,7 @@ func GetTeamRepo(ctx *context.APIContext) { return } - access, err := models.AccessLevel(ctx.Doer, repo) + access, err := access_model.AccessLevel(ctx.Doer, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTeamRepos", err) return @@ -655,7 +649,7 @@ func AddTeamRepository(ctx *context.APIContext) { if ctx.Written() { return } - if access, err := models.AccessLevel(ctx.Doer, repo); err != nil { + if access, err := access_model.AccessLevel(ctx.Doer, repo); err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return } else if access < perm.AccessModeAdmin { @@ -705,7 +699,7 @@ func RemoveTeamRepository(ctx *context.APIContext) { if ctx.Written() { return } - if access, err := models.AccessLevel(ctx.Doer, repo); err != nil { + if access, err := access_model.AccessLevel(ctx.Doer, repo); err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return } else if access < perm.AccessModeAdmin { @@ -781,17 +775,10 @@ func SearchTeam(ctx *context.APIContext) { return } - apiTeams := make([]*api.Team, len(teams)) - for i := range teams { - if err := teams[i].GetUnits(); err != nil { - log.Error("Team GetUnits failed: %v", err) - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "ok": false, - "error": "SearchTeam failed to get units", - }) - return - } - apiTeams[i] = convert.ToTeam(teams[i]) + apiTeams, err := convert.ToTeams(teams, false) + if err != nil { + ctx.InternalServerError(err) + return } ctx.SetLinkHeader(int(maxResults), listOptions.PageSize) diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index c030a896a7..09e6ccf238 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -70,7 +70,7 @@ func GetBranch(ctx *context.APIContext) { return } - branchProtection, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branchName) + branchProtection, err := models.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branchName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) return @@ -206,7 +206,7 @@ func CreateBranch(ctx *context.APIContext) { return } - branchProtection, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branch.Name) + branchProtection, err := models.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branch.Name) if err != nil { ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) return @@ -271,7 +271,7 @@ func ListBranches(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetCommit", err) return } - branchProtection, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branches[i].Name) + branchProtection, err := models.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branches[i].Name) if err != nil { ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err) return @@ -320,7 +320,7 @@ func GetBranchProtection(ctx *context.APIContext) { repo := ctx.Repo.Repository bpName := ctx.Params(":name") - bp, err := models.GetProtectedBranchBy(repo.ID, bpName) + bp, err := models.GetProtectedBranchBy(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) return @@ -412,7 +412,7 @@ func CreateBranchProtection(ctx *context.APIContext) { return } - protectBranch, err := models.GetProtectedBranchBy(repo.ID, form.BranchName) + protectBranch, err := models.GetProtectedBranchBy(ctx, repo.ID, form.BranchName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectBranchOfRepoByName", err) return @@ -523,7 +523,7 @@ func CreateBranchProtection(ctx *context.APIContext) { } // Reload from db to get all whitelists - bp, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, form.BranchName) + bp, err := models.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, form.BranchName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) return @@ -575,7 +575,7 @@ func EditBranchProtection(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.EditBranchProtectionOption) repo := ctx.Repo.Repository bpName := ctx.Params(":name") - protectBranch, err := models.GetProtectedBranchBy(repo.ID, bpName) + protectBranch, err := models.GetProtectedBranchBy(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) return @@ -758,7 +758,7 @@ func EditBranchProtection(ctx *context.APIContext) { } // Reload from db to ensure get all whitelists - bp, err := models.GetProtectedBranchBy(repo.ID, bpName) + bp, err := models.GetProtectedBranchBy(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchBy", err) return @@ -802,7 +802,7 @@ func DeleteBranchProtection(ctx *context.APIContext) { repo := ctx.Repo.Repository bpName := ctx.Params(":name") - bp, err := models.GetProtectedBranchBy(repo.ID, bpName) + bp, err := models.GetProtectedBranchBy(ctx, repo.ID, bpName) if err != nil { ctx.Error(http.StatusInternalServerError, "GetProtectedBranchByID", err) return diff --git a/routers/api/v1/repo/collaborators.go b/routers/api/v1/repo/collaborators.go index 2db1724b2a..aa425e5828 100644 --- a/routers/api/v1/repo/collaborators.go +++ b/routers/api/v1/repo/collaborators.go @@ -11,6 +11,8 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" + 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" @@ -49,13 +51,13 @@ func ListCollaborators(ctx *context.APIContext) { // "200": // "$ref": "#/responses/UserList" - count, err := models.CountCollaborators(ctx.Repo.Repository.ID) + count, err := repo_model.CountCollaborators(ctx.Repo.Repository.ID) if err != nil { ctx.InternalServerError(err) return } - collaborators, err := models.GetCollaborators(ctx.Repo.Repository.ID, utils.GetListOptions(ctx)) + collaborators, err := repo_model.GetCollaborators(ctx, ctx.Repo.Repository.ID, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "ListCollaborators", err) return @@ -101,7 +103,7 @@ func IsCollaborator(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - user, err := user_model.GetUserByName(ctx.Params(":collaborator")) + user, err := user_model.GetUserByName(ctx, ctx.Params(":collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -110,7 +112,7 @@ func IsCollaborator(ctx *context.APIContext) { } return } - isColab, err := models.IsCollaborator(ctx.Repo.Repository.ID, user.ID) + isColab, err := repo_model.IsCollaborator(ctx, ctx.Repo.Repository.ID, user.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "IsCollaborator", err) return @@ -157,7 +159,7 @@ func AddCollaborator(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.AddCollaboratorOption) - collaborator, err := user_model.GetUserByName(ctx.Params(":collaborator")) + collaborator, err := user_model.GetUserByName(ctx, ctx.Params(":collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -178,7 +180,7 @@ func AddCollaborator(ctx *context.APIContext) { } if form.Permission != nil { - if err := models.ChangeCollaborationAccessMode(ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil { + if err := repo_model.ChangeCollaborationAccessMode(ctx.Repo.Repository, collaborator.ID, perm.ParseAccessMode(*form.Permission)); err != nil { ctx.Error(http.StatusInternalServerError, "ChangeCollaborationAccessMode", err) return } @@ -216,7 +218,7 @@ func DeleteCollaborator(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - collaborator, err := user_model.GetUserByName(ctx.Params(":collaborator")) + collaborator, err := user_model.GetUserByName(ctx, ctx.Params(":collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -269,7 +271,7 @@ func GetRepoPermissions(ctx *context.APIContext) { return } - collaborator, err := user_model.GetUserByName(ctx.Params(":collaborator")) + collaborator, err := user_model.GetUserByName(ctx, ctx.Params(":collaborator")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusNotFound, "GetUserByName", err) @@ -279,7 +281,7 @@ func GetRepoPermissions(ctx *context.APIContext) { return } - permission, err := models.GetUserRepoPermission(ctx, ctx.Repo.Repository, collaborator) + permission, err := access_model.GetUserRepoPermission(ctx, ctx.Repo.Repository, collaborator) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return @@ -310,7 +312,7 @@ func GetReviewers(ctx *context.APIContext) { // "200": // "$ref": "#/responses/UserList" - reviewers, err := models.GetReviewers(ctx.Repo.Repository, ctx.Doer.ID, 0) + reviewers, err := repo_model.GetReviewers(ctx, ctx.Repo.Repository, ctx.Doer.ID, 0) if err != nil { ctx.Error(http.StatusInternalServerError, "ListCollaborators", err) return @@ -340,7 +342,7 @@ func GetAssignees(ctx *context.APIContext) { // "200": // "$ref": "#/responses/UserList" - assignees, err := models.GetRepoAssignees(ctx.Repo.Repository) + assignees, err := repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository) if err != nil { ctx.Error(http.StatusInternalServerError, "ListCollaborators", err) return diff --git a/routers/api/v1/repo/file.go b/routers/api/v1/repo/file.go index 2a4c4ad979..ab337e66e3 100644 --- a/routers/api/v1/repo/file.go +++ b/routers/api/v1/repo/file.go @@ -6,8 +6,10 @@ package repo import ( + "bytes" "encoding/base64" "fmt" + "io" "net/http" "path" "time" @@ -18,7 +20,11 @@ import ( "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/httpcache" + "code.gitea.io/gitea/modules/lfs" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/modules/storage" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/common" @@ -75,6 +81,142 @@ func GetRawFile(ctx *context.APIContext) { } } +// GetRawFileOrLFS get a file by repo's path, redirecting to LFS if necessary. +func GetRawFileOrLFS(ctx *context.APIContext) { + // swagger:operation GET /repos/{owner}/{repo}/media/{filepath} repository repoGetRawFileOrLFS + // --- + // summary: Get a file or it's LFS object from a repository + // 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: filepath + // in: path + // description: filepath of the file to get + // type: string + // required: true + // - name: ref + // in: query + // description: "The name of the commit/branch/tag. Default the repository’s default branch (usually master)" + // type: string + // required: false + // responses: + // 200: + // description: Returns raw file content. + // "404": + // "$ref": "#/responses/notFound" + + if ctx.Repo.Repository.IsEmpty { + ctx.NotFound() + return + } + + blob, lastModified := getBlobForEntry(ctx) + if ctx.Written() { + return + } + + // LFS Pointer files are at most 1024 bytes - so any blob greater than 1024 bytes cannot be an LFS file + if blob.Size() > 1024 { + // First handle caching for the blob + if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) { + return + } + + // OK not cached - serve! + if err := common.ServeBlob(ctx.Context, blob, lastModified); err != nil { + ctx.ServerError("ServeBlob", err) + } + return + } + + // OK, now the blob is known to have at most 1024 bytes we can simply read this in in one go (This saves reading it twice) + dataRc, err := blob.DataAsync() + if err != nil { + ctx.ServerError("DataAsync", err) + return + } + + buf, err := io.ReadAll(dataRc) + if err != nil { + _ = dataRc.Close() + ctx.ServerError("DataAsync", err) + return + } + + if err := dataRc.Close(); err != nil { + log.Error("Error whilst closing blob %s reader in %-v. Error: %v", blob.ID, ctx.Context.Repo.Repository, err) + } + + // Check if the blob represents a pointer + pointer, _ := lfs.ReadPointer(bytes.NewReader(buf)) + + // if its not a pointer just serve the data directly + if !pointer.IsValid() { + // First handle caching for the blob + if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) { + return + } + + // OK not cached - serve! + if err := common.ServeData(ctx.Context, ctx.Repo.TreePath, blob.Size(), bytes.NewReader(buf)); err != nil { + ctx.ServerError("ServeBlob", err) + } + return + } + + // Now check if there is a meta object for this pointer + meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, pointer.Oid) + + // If there isn't one just serve the data directly + if err == models.ErrLFSObjectNotExist { + // Handle caching for the blob SHA (not the LFS object OID) + if httpcache.HandleGenericETagTimeCache(ctx.Req, ctx.Resp, `"`+blob.ID.String()+`"`, lastModified) { + return + } + + if err := common.ServeData(ctx.Context, ctx.Repo.TreePath, blob.Size(), bytes.NewReader(buf)); err != nil { + ctx.ServerError("ServeBlob", err) + } + return + } else if err != nil { + ctx.ServerError("GetLFSMetaObjectByOid", err) + return + } + + // Handle caching for the LFS object OID + if httpcache.HandleGenericETagCache(ctx.Req, ctx.Resp, `"`+pointer.Oid+`"`) { + return + } + + if setting.LFS.ServeDirect { + // If we have a signed url (S3, object storage), redirect to this directly. + u, err := storage.LFS.URL(pointer.RelativePath(), blob.Name()) + if u != nil && err == nil { + ctx.Redirect(u.String()) + return + } + } + + lfsDataRc, err := lfs.ReadMetaObject(meta.Pointer) + if err != nil { + ctx.ServerError("ReadMetaObject", err) + return + } + defer lfsDataRc.Close() + + if err := common.ServeData(ctx.Context, ctx.Repo.TreePath, meta.Size, lfsDataRc); err != nil { + ctx.ServerError("ServeData", err) + } +} + func getBlobForEntry(ctx *context.APIContext) (blob *git.Blob, lastModified time.Time) { entry, err := ctx.Repo.Commit.GetTreeEntryByPath(ctx.Repo.TreePath) if err != nil { @@ -209,7 +351,7 @@ func GetEditorconfig(ctx *context.APIContext) { // canWriteFiles returns true if repository is editable and user has proper access level. func canWriteFiles(ctx *context.APIContext, branch string) bool { - return ctx.Repo.Permission.CanWriteToBranch(ctx.Doer, branch) && + return ctx.Repo.CanWriteToBranch(ctx.Doer, branch) && !ctx.Repo.Repository.IsMirror && !ctx.Repo.Repository.IsArchived } diff --git a/routers/api/v1/repo/fork.go b/routers/api/v1/repo/fork.go index 10c05e5503..112a9562f0 100644 --- a/routers/api/v1/repo/fork.go +++ b/routers/api/v1/repo/fork.go @@ -9,9 +9,9 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -59,7 +59,7 @@ func ListForks(ctx *context.APIContext) { } apiForks := make([]*api.Repository, len(forks)) for i, fork := range forks { - access, err := models.AccessLevel(ctx.Doer, fork) + access, err := access_model.AccessLevel(ctx.Doer, fork) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return diff --git a/routers/api/v1/repo/hook.go b/routers/api/v1/repo/hook.go index 7ec6cd88ab..8a546e581a 100644 --- a/routers/api/v1/repo/hook.go +++ b/routers/api/v1/repo/hook.go @@ -60,7 +60,7 @@ func ListHooks(ctx *context.APIContext) { return } - hooks, err := webhook.ListWebhooksByOpts(opts) + hooks, err := webhook.ListWebhooksByOpts(ctx, opts) if err != nil { ctx.InternalServerError(err) return diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 9654b270c0..c394ad1756 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -16,6 +16,8 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -129,7 +131,7 @@ func SearchIssues(ctx *context.APIContext) { } // find repos user can access (for issue search) - opts := &models.SearchRepoOptions{ + opts := &repo_model.SearchRepoOptions{ Private: false, AllPublic: true, TopicOnly: false, @@ -144,7 +146,7 @@ func SearchIssues(ctx *context.APIContext) { opts.AllLimited = true } if ctx.FormString("owner") != "" { - owner, err := user_model.GetUserByName(ctx.FormString("owner")) + owner, err := user_model.GetUserByName(ctx, ctx.FormString("owner")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusBadRequest, "Owner not found", err) @@ -163,7 +165,7 @@ func SearchIssues(ctx *context.APIContext) { ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team") return } - team, err := organization.GetTeam(opts.OwnerID, ctx.FormString("team")) + team, err := organization.GetTeam(ctx, opts.OwnerID, ctx.FormString("team")) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusBadRequest, "Team not found", err) @@ -175,8 +177,8 @@ func SearchIssues(ctx *context.APIContext) { opts.TeamID = team.ID } - repoCond := models.SearchRepositoryCondition(opts) - repoIDs, _, err := models.SearchRepositoryIDs(opts) + repoCond := repo_model.SearchRepositoryCondition(opts) + repoIDs, _, err := repo_model.SearchRepositoryIDs(opts) if err != nil { ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err) return @@ -501,7 +503,7 @@ func getUserIDForFilter(ctx *context.APIContext, queryName string) int64 { return 0 } - user, err := user_model.GetUserByName(userName) + user, err := user_model.GetUserByName(ctx, userName) if user_model.IsErrUserNotExist(err) { ctx.NotFound(err) return 0 @@ -629,7 +631,7 @@ func CreateIssue(ctx *context.APIContext) { return } - valid, err := models.CanBeAssigned(assignee, ctx.Repo.Repository, false) + valid, err := access_model.CanBeAssigned(ctx, assignee, ctx.Repo.Repository, false) if err != nil { ctx.Error(http.StatusInternalServerError, "canBeAssigned", err) return diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index bc68cb396b..22533c3810 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -11,6 +11,7 @@ import ( "net/http" "code.gitea.io/gitea/models" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -78,7 +79,7 @@ func ListIssueComments(ctx *context.APIContext) { Type: models.CommentTypeComment, } - comments, err := models.FindComments(opts) + comments, err := models.FindComments(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "FindComments", err) return @@ -171,7 +172,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { Type: models.CommentTypeUnknown, } - comments, err := models.FindComments(opts) + comments, err := models.FindComments(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "FindComments", err) return @@ -203,7 +204,7 @@ func isXRefCommentAccessible(ctx stdCtx.Context, user *user_model.User, c *model if err != nil { return false } - perm, err := models.GetUserRepoPermission(ctx, c.RefRepo, user) + perm, err := access_model.GetUserRepoPermission(ctx, c.RefRepo, user) if err != nil { return false } @@ -268,7 +269,7 @@ func ListRepoIssueComments(ctx *context.APIContext) { Before: before, } - comments, err := models.FindComments(opts) + comments, err := models.FindComments(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "FindComments", err) return @@ -398,7 +399,7 @@ func GetIssueComment(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -525,7 +526,7 @@ func EditIssueCommentDeprecated(ctx *context.APIContext) { } func editIssueComment(ctx *context.APIContext, form api.EditIssueCommentOption) { - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -628,7 +629,7 @@ func DeleteIssueCommentDeprecated(ctx *context.APIContext) { } func deleteIssueComment(ctx *context.APIContext) { - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrCommentNotExist(err) { ctx.NotFound(err) diff --git a/routers/api/v1/repo/issue_label.go b/routers/api/v1/repo/issue_label.go index e314e756dd..0193eb4230 100644 --- a/routers/api/v1/repo/issue_label.go +++ b/routers/api/v1/repo/issue_label.go @@ -111,7 +111,7 @@ func AddIssueLabels(ctx *context.APIContext) { return } - labels, err = models.GetLabelsByIssueID(issue.ID) + labels, err = models.GetLabelsByIssueID(ctx, issue.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsByIssueID", err) return @@ -173,7 +173,7 @@ func DeleteIssueLabel(ctx *context.APIContext) { return } - label, err := models.GetLabelByID(ctx.ParamsInt64(":id")) + label, err := models.GetLabelByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrLabelNotExist(err) { ctx.Error(http.StatusUnprocessableEntity, "", err) @@ -237,7 +237,7 @@ func ReplaceIssueLabels(ctx *context.APIContext) { return } - labels, err = models.GetLabelsByIssueID(issue.ID) + labels, err = models.GetLabelsByIssueID(ctx, issue.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsByIssueID", err) return diff --git a/routers/api/v1/repo/issue_reaction.go b/routers/api/v1/repo/issue_reaction.go index 5aa7366796..45be7a92dd 100644 --- a/routers/api/v1/repo/issue_reaction.go +++ b/routers/api/v1/repo/issue_reaction.go @@ -49,7 +49,7 @@ func GetIssueCommentReactions(ctx *context.APIContext) { // "403": // "$ref": "#/responses/forbidden" - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrCommentNotExist(err) { ctx.NotFound(err) @@ -176,7 +176,7 @@ func DeleteIssueCommentReaction(ctx *context.APIContext) { } func changeIssueCommentReaction(ctx *context.APIContext, form api.EditReactionOption, isCreateType bool) { - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrCommentNotExist(err) { ctx.NotFound(err) diff --git a/routers/api/v1/repo/issue_subscription.go b/routers/api/v1/repo/issue_subscription.go index f00c85b126..a608ba2278 100644 --- a/routers/api/v1/repo/issue_subscription.go +++ b/routers/api/v1/repo/issue_subscription.go @@ -116,7 +116,7 @@ func setIssueSubscription(ctx *context.APIContext, watch bool) { return } - user, err := user_model.GetUserByName(ctx.Params(":user")) + user, err := user_model.GetUserByName(ctx, ctx.Params(":user")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound() @@ -263,7 +263,7 @@ func GetIssueSubscribers(ctx *context.APIContext) { return } - iwl, err := models.GetIssueWatchers(issue.ID, utils.GetListOptions(ctx)) + iwl, err := models.GetIssueWatchers(ctx, issue.ID, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetIssueWatchers", err) return @@ -284,7 +284,7 @@ func GetIssueSubscribers(ctx *context.APIContext) { apiUsers = append(apiUsers, convert.ToUser(v, ctx.Doer)) } - count, err := models.CountIssueWatchers(issue.ID) + count, err := models.CountIssueWatchers(ctx, issue.ID) if err != nil { ctx.Error(http.StatusInternalServerError, "CountIssueWatchers", err) return diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 8ccad87838..19e1a82590 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -94,7 +94,7 @@ func ListTrackedTimes(ctx *context.APIContext) { qUser := ctx.FormTrim("user") if qUser != "" { - user, err := user_model.GetUserByName(qUser) + user, err := user_model.GetUserByName(ctx, qUser) if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusNotFound, "User does not exist", err) } else if err != nil { @@ -128,7 +128,7 @@ func ListTrackedTimes(ctx *context.APIContext) { return } - trackedTimes, err := models.GetTrackedTimes(opts) + trackedTimes, err := models.GetTrackedTimes(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTrackedTimes", err) return @@ -203,7 +203,7 @@ func AddTime(ctx *context.APIContext) { if form.User != "" { if (ctx.IsUserRepoAdmin() && ctx.Doer.Name != form.User) || ctx.Doer.IsAdmin { // allow only RepoAdmin, Admin and User to add time - user, err = user_model.GetUserByName(form.User) + user, err = user_model.GetUserByName(ctx, form.User) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserByName", err) } @@ -415,7 +415,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { ctx.Error(http.StatusBadRequest, "", "time tracking disabled") return } - user, err := user_model.GetUserByName(ctx.Params(":timetrackingusername")) + user, err := user_model.GetUserByName(ctx, ctx.Params(":timetrackingusername")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound(err) @@ -439,7 +439,7 @@ func ListTrackedTimesByUser(ctx *context.APIContext) { RepositoryID: ctx.Repo.Repository.ID, } - trackedTimes, err := models.GetTrackedTimes(opts) + trackedTimes, err := models.GetTrackedTimes(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTrackedTimes", err) return @@ -512,7 +512,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { // Filters qUser := ctx.FormTrim("user") if qUser != "" { - user, err := user_model.GetUserByName(qUser) + user, err := user_model.GetUserByName(ctx, qUser) if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusNotFound, "User does not exist", err) } else if err != nil { @@ -547,7 +547,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { return } - trackedTimes, err := models.GetTrackedTimes(opts) + trackedTimes, err := models.GetTrackedTimes(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTrackedTimes", err) return @@ -609,7 +609,7 @@ func ListMyTrackedTimes(ctx *context.APIContext) { return } - trackedTimes, err := models.GetTrackedTimes(opts) + trackedTimes, err := models.GetTrackedTimes(ctx, opts) if err != nil { ctx.Error(http.StatusInternalServerError, "GetTrackedTimesByUser", err) return diff --git a/routers/api/v1/repo/label.go b/routers/api/v1/repo/label.go index ab559a2eed..4332b8e627 100644 --- a/routers/api/v1/repo/label.go +++ b/routers/api/v1/repo/label.go @@ -49,7 +49,7 @@ func ListLabels(ctx *context.APIContext) { // "200": // "$ref": "#/responses/LabelList" - labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, ctx.FormString("sort"), utils.GetListOptions(ctx)) + labels, err := models.GetLabelsByRepoID(ctx, ctx.Repo.Repository.ID, ctx.FormString("sort"), utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLabelsByRepoID", err) return @@ -99,9 +99,9 @@ func GetLabel(ctx *context.APIContext) { ) strID := ctx.Params(":id") if intID, err2 := strconv.ParseInt(strID, 10, 64); err2 != nil { - label, err = models.GetLabelInRepoByName(ctx.Repo.Repository.ID, strID) + label, err = models.GetLabelInRepoByName(ctx, ctx.Repo.Repository.ID, strID) } else { - label, err = models.GetLabelInRepoByID(ctx.Repo.Repository.ID, intID) + label, err = models.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, intID) } if err != nil { if models.IsErrRepoLabelNotExist(err) { @@ -206,7 +206,7 @@ func EditLabel(ctx *context.APIContext) { // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.EditLabelOption) - label, err := models.GetLabelInRepoByID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")) + label, err := models.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrRepoLabelNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/language.go b/routers/api/v1/repo/language.go index f47b0a0e78..ca803cb68b 100644 --- a/routers/api/v1/repo/language.go +++ b/routers/api/v1/repo/language.go @@ -68,7 +68,7 @@ func GetLanguages(ctx *context.APIContext) { // "200": // "$ref": "#/responses/LanguageStatistics" - langs, err := repo_model.GetLanguageStats(ctx.Repo.Repository) + langs, err := repo_model.GetLanguageStats(ctx, ctx.Repo.Repository) if err != nil { log.Error("GetLanguageStats failed: %v", err) ctx.InternalServerError(err) diff --git a/routers/api/v1/repo/migrate.go b/routers/api/v1/repo/migrate.go index f5851bfcae..f868c53951 100644 --- a/routers/api/v1/repo/migrate.go +++ b/routers/api/v1/repo/migrate.go @@ -65,7 +65,7 @@ func Migrate(ctx *context.APIContext) { err error ) if len(form.RepoOwner) != 0 { - repoOwner, err = user_model.GetUserByName(form.RepoOwner) + repoOwner, err = user_model.GetUserByName(ctx, form.RepoOwner) } else if form.RepoOwnerID != 0 { repoOwner, err = user_model.GetUserByID(form.RepoOwnerID) } else { diff --git a/routers/api/v1/repo/mirror.go b/routers/api/v1/repo/mirror.go index d7facd24d9..1af63c55be 100644 --- a/routers/api/v1/repo/mirror.go +++ b/routers/api/v1/repo/mirror.go @@ -50,7 +50,7 @@ func MirrorSync(ctx *context.APIContext) { return } - if _, err := repo_model.GetMirrorByRepoID(repo.ID); err != nil { + if _, err := repo_model.GetMirrorByRepoID(ctx, repo.ID); err != nil { if errors.Is(err, repo_model.ErrMirrorNotExist) { ctx.Error(http.StatusBadRequest, "MirrorSync", "Repository is not a mirror") return diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index f95bc6b16b..393f2d1576 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models" issues_model "code.gitea.io/gitea/models/issues" + access_model "code.gitea.io/gitea/models/perm/access" pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -159,7 +160,7 @@ func GetPullRequest(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -219,7 +220,7 @@ func DownloadPullDiffOrPatch(ctx *context.APIContext) { // "$ref": "#/responses/string" // "404": // "$ref": "#/responses/notFound" - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -402,7 +403,7 @@ func CreatePullRequest(ctx *context.APIContext) { return } - valid, err := models.CanBeAssigned(assignee, repo, true) + valid, err := access_model.CanBeAssigned(ctx, assignee, repo, true) if err != nil { ctx.Error(http.StatusInternalServerError, "canBeAssigned", err) return @@ -469,7 +470,7 @@ func EditPullRequest(ctx *context.APIContext) { // "$ref": "#/responses/validationError" form := web.GetForm(ctx).(*api.EditPullRequestOption) - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -631,7 +632,7 @@ func EditPullRequest(ctx *context.APIContext) { } // Refetch from database - pr, err = models.GetPullRequestByIndex(ctx.Repo.Repository.ID, pr.Index) + pr, err = models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pr.Index) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -675,7 +676,7 @@ func IsPullRequestMerged(ctx *context.APIContext) { // "404": // description: pull request has not been merged - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -729,7 +730,7 @@ func MergePullRequest(ctx *context.APIContext) { form := web.GetForm(ctx).(*forms.MergePullRequestForm) - pr, err := models.GetPullRequestByIndexCtx(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -937,7 +938,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) headBranch = headInfos[0] } else if len(headInfos) == 2 { - headUser, err = user_model.GetUserByName(headInfos[0]) + headUser, err = user_model.GetUserByName(ctx, headInfos[0]) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound("GetUserByName") @@ -983,7 +984,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // user should have permission to read baseRepo's codes and pulls, NOT headRepo's - permBase, err := models.GetUserRepoPermission(ctx, baseRepo, ctx.Doer) + permBase, err := access_model.GetUserRepoPermission(ctx, baseRepo, ctx.Doer) if err != nil { headGitRepo.Close() ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) @@ -1002,7 +1003,7 @@ func parseCompareInfo(ctx *context.APIContext, form api.CreatePullRequestOption) } // user should have permission to read headrepo's codes - permHead, err := models.GetUserRepoPermission(ctx, headRepo, ctx.Doer) + permHead, err := access_model.GetUserRepoPermission(ctx, headRepo, ctx.Doer) if err != nil { headGitRepo.Close() ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) @@ -1078,7 +1079,7 @@ func UpdatePullRequest(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -1176,7 +1177,7 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { // "$ref": "#/responses/notFound" pullIndex := ctx.ParamsInt64(":index") - pull, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, pullIndex) + pull, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, pullIndex) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() @@ -1197,7 +1198,7 @@ func CancelScheduledAutoMerge(ctx *context.APIContext) { } if ctx.Doer.ID != autoMerge.DoerID { - allowed, err := models.IsUserRepoAdminCtx(ctx, ctx.Repo.Repository, ctx.Doer) + allowed, err := access_model.IsUserRepoAdmin(ctx, ctx.Repo.Repository, ctx.Doer) if err != nil { ctx.InternalServerError(err) return @@ -1253,7 +1254,7 @@ func GetPullRequestCommits(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound() diff --git a/routers/api/v1/repo/pull_review.go b/routers/api/v1/repo/pull_review.go index b3ebe49bf5..5175fa921f 100644 --- a/routers/api/v1/repo/pull_review.go +++ b/routers/api/v1/repo/pull_review.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" + 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" @@ -60,7 +61,7 @@ func ListPullReviews(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -86,7 +87,7 @@ func ListPullReviews(ctx *context.APIContext) { IssueID: pr.IssueID, } - allReviews, err := models.FindReviews(opts) + allReviews, err := models.FindReviews(ctx, opts) if err != nil { ctx.InternalServerError(err) return @@ -306,7 +307,7 @@ func CreatePullReview(ctx *context.APIContext) { // "$ref": "#/responses/validationError" opts := web.GetForm(ctx).(*api.CreatePullReviewOptions) - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -525,7 +526,7 @@ func preparePullReviewType(ctx *context.APIContext, pr *models.PullRequest, even // prepareSingleReview return review, related pull and false or nil, nil and true if an error happen func prepareSingleReview(ctx *context.APIContext) (*models.Review, *models.PullRequest, bool) { - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -535,7 +536,7 @@ func prepareSingleReview(ctx *context.APIContext) (*models.Review, *models.PullR return nil, nil, true } - review, err := models.GetReviewByID(ctx.ParamsInt64(":id")) + review, err := models.GetReviewByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if models.IsErrReviewNotExist(err) { ctx.NotFound("GetReviewByID", err) @@ -647,7 +648,7 @@ func DeleteReviewRequests(ctx *context.APIContext) { } func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions, isAdd bool) { - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -664,7 +665,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions reviewers := make([]*user_model.User, 0, len(opts.Reviewers)) - permDoer, err := models.GetUserRepoPermission(ctx, pr.Issue.Repo, ctx.Doer) + permDoer, err := access_model.GetUserRepoPermission(ctx, pr.Issue.Repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err) return @@ -675,7 +676,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions if strings.Contains(r, "@") { reviewer, err = user_model.GetUserByEmail(r) } else { - reviewer, err = user_model.GetUserByName(r) + reviewer, err = user_model.GetUserByName(ctx, r) } if err != nil { @@ -726,7 +727,7 @@ func apiReviewRequest(ctx *context.APIContext, opts api.PullReviewRequestOptions teamReviewers := make([]*organization.Team, 0, len(opts.TeamReviewers)) for _, t := range opts.TeamReviewers { var teamReviewer *organization.Team - teamReviewer, err = organization.GetTeam(ctx.Repo.Owner.ID, t) + teamReviewer, err = organization.GetTeam(ctx, ctx.Repo.Owner.ID, t) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.NotFound("TeamNotExist", fmt.Sprintf("Team '%s' not exist", t)) @@ -891,7 +892,7 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss bool) { return } - if review, err = models.GetReviewByID(review.ID); err != nil { + if review, err = models.GetReviewByID(ctx, review.ID); err != nil { ctx.Error(http.StatusInternalServerError, "GetReviewByID", err) return } diff --git a/routers/api/v1/repo/release.go b/routers/api/v1/repo/release.go index 7d23a38add..e454b418bb 100644 --- a/routers/api/v1/repo/release.go +++ b/routers/api/v1/repo/release.go @@ -15,7 +15,7 @@ import ( api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" - releaseservice "code.gitea.io/gitea/services/release" + release_service "code.gitea.io/gitea/services/release" ) // GetRelease get a single release of a repository @@ -49,7 +49,7 @@ func GetRelease(ctx *context.APIContext) { // "$ref": "#/responses/notFound" id := ctx.ParamsInt64(":id") - release, err := models.GetReleaseByID(id) + release, err := models.GetReleaseByID(ctx, id) if err != nil && !models.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return @@ -202,7 +202,7 @@ func CreateRelease(ctx *context.APIContext) { IsTag: false, Repo: ctx.Repo.Repository, } - if err := releaseservice.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil { + if err := release_service.CreateRelease(ctx.Repo.GitRepo, rel, nil, ""); err != nil { if models.IsErrReleaseAlreadyExist(err) { ctx.Error(http.StatusConflict, "ReleaseAlreadyExist", err) } else { @@ -225,7 +225,7 @@ func CreateRelease(ctx *context.APIContext) { rel.Repo = ctx.Repo.Repository rel.Publisher = ctx.Doer - if err = releaseservice.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { + if err = release_service.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateRelease", err) return } @@ -271,7 +271,7 @@ func EditRelease(ctx *context.APIContext) { form := web.GetForm(ctx).(*api.EditReleaseOption) id := ctx.ParamsInt64(":id") - rel, err := models.GetReleaseByID(id) + rel, err := models.GetReleaseByID(ctx, id) if err != nil && !models.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return @@ -300,12 +300,13 @@ func EditRelease(ctx *context.APIContext) { if form.IsPrerelease != nil { rel.IsPrerelease = *form.IsPrerelease } - if err := releaseservice.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { + if err := release_service.UpdateRelease(ctx.Doer, ctx.Repo.GitRepo, rel, nil, nil, nil); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateRelease", err) return } - rel, err = models.GetReleaseByID(id) + // reload data from database + rel, err = models.GetReleaseByID(ctx, id) if err != nil { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return @@ -346,7 +347,7 @@ func DeleteRelease(ctx *context.APIContext) { // "$ref": "#/responses/notFound" id := ctx.ParamsInt64(":id") - rel, err := models.GetReleaseByID(id) + rel, err := models.GetReleaseByID(ctx, id) if err != nil && !models.IsErrReleaseNotExist(err) { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return @@ -356,7 +357,7 @@ func DeleteRelease(ctx *context.APIContext) { ctx.NotFound() return } - if err := releaseservice.DeleteReleaseByID(ctx, id, ctx.Doer, false); err != nil { + if err := release_service.DeleteReleaseByID(ctx, id, ctx.Doer, false); err != nil { ctx.Error(http.StatusInternalServerError, "DeleteReleaseByID", err) return } diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go index c172b66127..8694653c06 100644 --- a/routers/api/v1/repo/release_attachment.go +++ b/routers/api/v1/repo/release_attachment.go @@ -55,7 +55,7 @@ func GetReleaseAttachment(ctx *context.APIContext) { releaseID := ctx.ParamsInt64(":id") attachID := ctx.ParamsInt64(":asset") - attach, err := repo_model.GetAttachmentByID(attachID) + attach, err := repo_model.GetAttachmentByID(ctx, attachID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetAttachmentByID", err) return @@ -98,7 +98,7 @@ func ListReleaseAttachments(ctx *context.APIContext) { // "$ref": "#/responses/AttachmentList" releaseID := ctx.ParamsInt64(":id") - release, err := models.GetReleaseByID(releaseID) + release, err := models.GetReleaseByID(ctx, releaseID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return @@ -164,7 +164,7 @@ func CreateReleaseAttachment(ctx *context.APIContext) { // Check if release exists an load release releaseID := ctx.ParamsInt64(":id") - release, err := models.GetReleaseByID(releaseID) + release, err := models.GetReleaseByID(ctx, releaseID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetReleaseByID", err) return @@ -242,7 +242,7 @@ func EditReleaseAttachment(ctx *context.APIContext) { // Check if release exists an load release releaseID := ctx.ParamsInt64(":id") attachID := ctx.ParamsInt64(":asset") - attach, err := repo_model.GetAttachmentByID(attachID) + attach, err := repo_model.GetAttachmentByID(ctx, attachID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetAttachmentByID", err) return @@ -257,7 +257,7 @@ func EditReleaseAttachment(ctx *context.APIContext) { attach.Name = form.Name } - if err := repo_model.UpdateAttachment(attach); err != nil { + if err := repo_model.UpdateAttachment(ctx, attach); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateAttachment", attach) } ctx.JSON(http.StatusCreated, convert.ToReleaseAttachment(attach)) @@ -300,7 +300,7 @@ func DeleteReleaseAttachment(ctx *context.APIContext) { // Check if release exists an load release releaseID := ctx.ParamsInt64(":id") attachID := ctx.ParamsInt64(":asset") - attach, err := repo_model.GetAttachmentByID(attachID) + attach, err := repo_model.GetAttachmentByID(ctx, attachID) if err != nil { ctx.Error(http.StatusInternalServerError, "GetAttachmentByID", err) return diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 29e8352142..cdd1f7d5c4 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -122,7 +123,7 @@ func Search(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" - opts := &models.SearchRepoOptions{ + opts := &repo_model.SearchRepoOptions{ ListOptions: utils.GetListOptions(ctx), Actor: ctx.Doer, Keyword: ctx.FormTrim("q"), @@ -191,7 +192,7 @@ func Search(ctx *context.APIContext) { } var err error - repos, count, err := models.SearchRepository(opts) + repos, count, err := repo_model.SearchRepository(opts) if err != nil { ctx.JSON(http.StatusInternalServerError, api.SearchError{ OK: false, @@ -209,7 +210,7 @@ func Search(ctx *context.APIContext) { }) return } - accessMode, err := models.AccessLevel(ctx.Doer, repo) + accessMode, err := access_model.AccessLevel(ctx.Doer, repo) if err != nil { ctx.JSON(http.StatusInternalServerError, api.SearchError{ OK: false, @@ -343,7 +344,7 @@ func Generate(ctx *context.APIContext) { return } - opts := models.GenerateRepoOptions{ + opts := repo_module.GenerateRepoOptions{ Name: form.Name, DefaultBranch: form.DefaultBranch, Description: form.Description, @@ -364,7 +365,7 @@ func Generate(ctx *context.APIContext) { ctxUser := ctx.Doer var err error if form.Owner != ctxUser.Name { - ctxUser, err = user_model.GetUserByName(form.Owner) + ctxUser, err = user_model.GetUserByName(ctx, form.Owner) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.JSON(http.StatusNotFound, map[string]interface{}{ @@ -555,7 +556,7 @@ func GetByID(ctx *context.APIContext) { return } - perm, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return @@ -716,7 +717,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err repo.DefaultBranch = *opts.DefaultBranch } - if err := models.UpdateRepository(repo, visibilityChanged); err != nil { + if err := repo_service.UpdateRepository(repo, visibilityChanged); err != nil { ctx.Error(http.StatusInternalServerError, "UpdateRepository", err) return err } @@ -961,7 +962,7 @@ func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error { } // get the mirror from the repo - mirror, err := repo_model.GetMirrorByRepoID(repo.ID) + mirror, err := repo_model.GetMirrorByRepoID(ctx, repo.ID) if err != nil { log.Error("Failed to get mirror: %s", err) ctx.Error(http.StatusInternalServerError, "MirrorInterval", err) @@ -999,7 +1000,7 @@ func updateMirror(ctx *context.APIContext, opts api.EditRepoOption) error { } // finally update the mirror in the DB - if err := repo_model.UpdateMirror(mirror); err != nil { + if err := repo_model.UpdateMirror(ctx, mirror); err != nil { log.Error("Failed to Set Mirror Interval: %s", err) ctx.Error(http.StatusUnprocessableEntity, "MirrorInterval", err) return err @@ -1035,7 +1036,7 @@ func Delete(ctx *context.APIContext) { owner := ctx.Repo.Owner repo := ctx.Repo.Repository - canDelete, err := models.CanUserDelete(repo, ctx.Doer) + canDelete, err := repo_module.CanUserDelete(repo, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "CanUserDelete", err) return diff --git a/routers/api/v1/repo/status.go b/routers/api/v1/repo/status.go index f4c0ebd38c..09597dc4e8 100644 --- a/routers/api/v1/repo/status.go +++ b/routers/api/v1/repo/status.go @@ -253,7 +253,7 @@ func GetCombinedCommitStatusByRef(ctx *context.APIContext) { repo := ctx.Repo.Repository - statuses, count, err := models.GetLatestCommitStatus(repo.ID, sha, utils.GetListOptions(ctx)) + statuses, count, err := models.GetLatestCommitStatus(ctx, repo.ID, sha, utils.GetListOptions(ctx)) if err != nil { ctx.Error(http.StatusInternalServerError, "GetLatestCommitStatus", fmt.Errorf("GetLatestCommitStatus[%s, %s]: %v", repo.FullName(), sha, err)) return diff --git a/routers/api/v1/repo/teams.go b/routers/api/v1/repo/teams.go index 1e3ea326d3..47c69d722b 100644 --- a/routers/api/v1/repo/teams.go +++ b/routers/api/v1/repo/teams.go @@ -12,7 +12,6 @@ import ( "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/convert" - api "code.gitea.io/gitea/modules/structs" ) // ListTeams list a repository's teams @@ -42,20 +41,16 @@ func ListTeams(ctx *context.APIContext) { return } - teams, err := organization.GetRepoTeams(ctx.Repo.Repository) + teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository) if err != nil { ctx.InternalServerError(err) return } - apiTeams := make([]*api.Team, len(teams)) - for i := range teams { - if err := teams[i].GetUnits(); err != nil { - ctx.Error(http.StatusInternalServerError, "GetUnits", err) - return - } - - apiTeams[i] = convert.ToTeam(teams[i]) + apiTeams, err := convert.ToTeams(teams, false) + if err != nil { + ctx.InternalServerError(err) + return } ctx.JSON(http.StatusOK, apiTeams) @@ -103,11 +98,11 @@ func IsTeam(ctx *context.APIContext) { } if models.HasRepository(team, ctx.Repo.Repository.ID) { - if err := team.GetUnits(); err != nil { - ctx.Error(http.StatusInternalServerError, "GetUnits", err) + apiTeam, err := convert.ToTeam(team) + if err != nil { + ctx.InternalServerError(err) return } - apiTeam := convert.ToTeam(team) ctx.JSON(http.StatusOK, apiTeam) return } @@ -221,7 +216,7 @@ func changeRepoTeam(ctx *context.APIContext, add bool) { } func getTeamByParam(ctx *context.APIContext) *organization.Team { - team, err := organization.GetTeam(ctx.Repo.Owner.ID, ctx.Params(":team")) + team, err := organization.GetTeam(ctx, ctx.Repo.Owner.ID, ctx.Params(":team")) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusNotFound, "TeamNotExit", err) diff --git a/routers/api/v1/repo/transfer.go b/routers/api/v1/repo/transfer.go index 241c578e60..067a4ebe19 100644 --- a/routers/api/v1/repo/transfer.go +++ b/routers/api/v1/repo/transfer.go @@ -57,7 +57,7 @@ func Transfer(ctx *context.APIContext) { opts := web.GetForm(ctx).(*api.TransferRepoOption) - newOwner, err := user_model.GetUserByName(opts.NewOwner) + newOwner, err := user_model.GetUserByName(ctx, opts.NewOwner) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusNotFound, "", "The new owner does not exist or cannot be found") @@ -84,7 +84,7 @@ func Transfer(ctx *context.APIContext) { org := convert.ToOrganization(organization.OrgFromUser(newOwner)) for _, tID := range *opts.TeamIDs { - team, err := organization.GetTeamByID(tID) + team, err := organization.GetTeamByID(ctx, tID) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "team", fmt.Errorf("team %d not found", tID)) return diff --git a/routers/api/v1/user/app.go b/routers/api/v1/user/app.go index 165b8f005e..0d2e8401cc 100644 --- a/routers/api/v1/user/app.go +++ b/routers/api/v1/user/app.go @@ -213,7 +213,7 @@ func CreateOauth2Application(ctx *context.APIContext) { data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions) - app, err := auth.CreateOAuth2Application(auth.CreateOAuth2ApplicationOptions{ + app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{ Name: data.Name, UserID: ctx.Doer.ID, RedirectURIs: data.RedirectURIs, @@ -320,7 +320,7 @@ func GetOauth2Application(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" appID := ctx.ParamsInt64(":id") - app, err := auth.GetOAuth2ApplicationByID(appID) + app, err := auth.GetOAuth2ApplicationByID(ctx, appID) if err != nil { if auth.IsErrOauthClientIDInvalid(err) || auth.IsErrOAuthApplicationNotFound(err) { ctx.NotFound() diff --git a/routers/api/v1/user/helper.go b/routers/api/v1/user/helper.go index fab3ce2ae5..ae7fa5248e 100644 --- a/routers/api/v1/user/helper.go +++ b/routers/api/v1/user/helper.go @@ -14,7 +14,7 @@ import ( // GetUserByParamsName get user by name func GetUserByParamsName(ctx *context.APIContext, name string) *user_model.User { username := ctx.Params(name) - user, err := user_model.GetUserByName(username) + user, err := user_model.GetUserByName(ctx, username) if err != nil { if user_model.IsErrUserNotExist(err) { if redirectUserID, err2 := user_model.LookupUserRedirect(username); err2 == nil { diff --git a/routers/api/v1/user/repo.go b/routers/api/v1/user/repo.go index 0231c8ccbc..709e3a6c54 100644 --- a/routers/api/v1/user/repo.go +++ b/routers/api/v1/user/repo.go @@ -7,8 +7,9 @@ package user import ( "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" + 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" @@ -20,7 +21,7 @@ import ( func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { opts := utils.GetListOptions(ctx) - repos, count, err := models.GetUserRepositories(&models.SearchRepoOptions{ + repos, count, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{ Actor: u, Private: private, ListOptions: opts, @@ -38,7 +39,7 @@ func listUserRepos(ctx *context.APIContext, u *user_model.User, private bool) { apiRepos := make([]*api.Repository, 0, len(repos)) for i := range repos { - access, err := models.AccessLevel(ctx.Doer, repos[i]) + access, err := access_model.AccessLevel(ctx.Doer, repos[i]) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) return @@ -102,7 +103,7 @@ func ListMyRepos(ctx *context.APIContext) { // "200": // "$ref": "#/responses/RepositoryList" - opts := &models.SearchRepoOptions{ + opts := &repo_model.SearchRepoOptions{ ListOptions: utils.GetListOptions(ctx), Actor: ctx.Doer, OwnerID: ctx.Doer.ID, @@ -111,7 +112,7 @@ func ListMyRepos(ctx *context.APIContext) { } var err error - repos, count, err := models.SearchRepository(opts) + repos, count, err := repo_model.SearchRepository(opts) if err != nil { ctx.Error(http.StatusInternalServerError, "SearchRepository", err) return @@ -123,7 +124,7 @@ func ListMyRepos(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "GetOwner", err) return } - accessMode, err := models.AccessLevel(ctx.Doer, repo) + accessMode, err := access_model.AccessLevel(ctx.Doer, repo) if err != nil { ctx.Error(http.StatusInternalServerError, "AccessLevel", err) } diff --git a/routers/api/v1/user/settings.go b/routers/api/v1/user/settings.go index dc7e7f1160..f00bf8c268 100644 --- a/routers/api/v1/user/settings.go +++ b/routers/api/v1/user/settings.go @@ -74,7 +74,7 @@ func UpdateUserSettings(ctx *context.APIContext) { ctx.Doer.KeepActivityPrivate = *form.HideActivity } - if err := user_model.UpdateUser(ctx.Doer, false); err != nil { + if err := user_model.UpdateUser(ctx, ctx.Doer, false); err != nil { ctx.InternalServerError(err) return } diff --git a/routers/api/v1/user/star.go b/routers/api/v1/user/star.go index cdbc35471b..9cb9ec79b8 100644 --- a/routers/api/v1/user/star.go +++ b/routers/api/v1/user/star.go @@ -8,8 +8,8 @@ package user import ( "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -28,7 +28,7 @@ func getStarredRepos(user *user_model.User, private bool, listOptions db.ListOpt repos := make([]*api.Repository, len(starredRepos)) for i, starred := range starredRepos { - access, err := models.AccessLevel(user, starred) + access, err := access_model.AccessLevel(user, starred) if err != nil { return nil, err } @@ -124,7 +124,7 @@ func IsStarring(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if repo_model.IsStaring(ctx.Doer.ID, ctx.Repo.Repository.ID) { + if repo_model.IsStaring(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID) { ctx.Status(http.StatusNoContent) } else { ctx.NotFound() diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 018f75762f..2a3cb15c0f 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -98,7 +98,7 @@ func GetInfo(ctx *context.APIContext) { // "404": // "$ref": "#/responses/notFound" - if !user_model.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) { + if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { // fake ErrUserNotExist error message to not leak information about existence ctx.NotFound("GetUserByName", user_model.ErrUserNotExist{Name: ctx.Params(":username")}) return diff --git a/routers/api/v1/user/watch.go b/routers/api/v1/user/watch.go index e7c6837cb8..83f23db15c 100644 --- a/routers/api/v1/user/watch.go +++ b/routers/api/v1/user/watch.go @@ -7,8 +7,8 @@ package user import ( "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" @@ -26,7 +26,7 @@ func getWatchedRepos(user *user_model.User, private bool, listOptions db.ListOpt repos := make([]*api.Repository, len(watchedRepos)) for i, watched := range watchedRepos { - access, err := models.AccessLevel(user, watched) + access, err := access_model.AccessLevel(user, watched) if err != nil { return nil, 0, err } @@ -156,7 +156,7 @@ func Watch(ctx *context.APIContext) { // "200": // "$ref": "#/responses/WatchInfo" - err := repo_model.WatchRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true) + err := repo_model.WatchRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, true) if err != nil { ctx.Error(http.StatusInternalServerError, "WatchRepo", err) return @@ -191,7 +191,7 @@ func Unwatch(ctx *context.APIContext) { // "204": // "$ref": "#/responses/empty" - err := repo_model.WatchRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, false) + err := repo_model.WatchRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, false) if err != nil { ctx.Error(http.StatusInternalServerError, "UnwatchRepo", err) return diff --git a/routers/common/repo.go b/routers/common/repo.go index d037e151f9..b3cd749115 100644 --- a/routers/common/repo.go +++ b/routers/common/repo.go @@ -88,10 +88,14 @@ func ServeData(ctx *context.Context, name string, size int64, reader io.Reader) } if (st.IsImage() || st.IsPDF()) && (setting.UI.SVG.Enabled || !st.IsSvgImage()) { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) - if st.IsSvgImage() { + if st.IsSvgImage() || st.IsPDF() { ctx.Resp.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; sandbox") ctx.Resp.Header().Set("X-Content-Type-Options", "nosniff") - ctx.Resp.Header().Set("Content-Type", typesniffer.SvgMimeType) + if st.IsSvgImage() { + ctx.Resp.Header().Set("Content-Type", typesniffer.SvgMimeType) + } else { + ctx.Resp.Header().Set("Content-Type", typesniffer.ApplicationOctetStream) + } } } else { ctx.Resp.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, name)) diff --git a/routers/init.go b/routers/init.go index 759945ce25..6036499362 100644 --- a/routers/init.go +++ b/routers/init.go @@ -10,7 +10,6 @@ import ( "reflect" "runtime" "strconv" - "strings" "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" @@ -31,6 +30,7 @@ import ( "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/svg" "code.gitea.io/gitea/modules/translation" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" packages_router "code.gitea.io/gitea/routers/api/packages" apiv1 "code.gitea.io/gitea/routers/api/v1" @@ -111,7 +111,7 @@ func GlobalInitInstalled(ctx context.Context) { log.Info("Custom path: %s", setting.CustomPath) log.Info("Log path: %s", setting.LogRootPath) log.Info("Configuration file: %s", setting.CustomConf) - log.Info("Run Mode: %s", strings.Title(setting.RunMode)) + log.Info("Run Mode: %s", util.ToTitleCase(setting.RunMode)) // Setup i18n translation.InitLocales() diff --git a/routers/install/install.go b/routers/install/install.go index 41b11aef33..bf95cae1c6 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -456,6 +456,8 @@ func SubmitInstall(ctx *context.Context) { cfg.Section("log").Key("ROOT_PATH").SetValue(form.LogRootPath) cfg.Section("log").Key("ROUTER").SetValue("console") + cfg.Section("repository.pull-request").Key("DEFAULT_MERGE_STYLE").SetValue("merge") + cfg.Section("repository.signing").Key("DEFAULT_TRUST_MODEL").SetValue("committer") cfg.Section("security").Key("INSTALL_LOCK").SetValue("true") @@ -521,7 +523,7 @@ func SubmitInstall(ctx *context.Context) { return } log.Info("Admin account already exist") - u, _ = user_model.GetUserByName(u.Name) + u, _ = user_model.GetUserByName(ctx, u.Name) } days := 86400 * setting.LogInRememberDays diff --git a/routers/private/hook_post_receive.go b/routers/private/hook_post_receive.go index 5e315ede47..eb2bbc1e5f 100644 --- a/routers/private/hook_post_receive.go +++ b/routers/private/hook_post_receive.go @@ -106,7 +106,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { repo.IsPrivate = opts.GitPushOptions.Bool(private.GitPushOptionRepoPrivate, repo.IsPrivate) repo.IsTemplate = opts.GitPushOptions.Bool(private.GitPushOptionRepoTemplate, repo.IsTemplate) - if err := repo_model.UpdateRepositoryCols(repo, "is_private", "is_template"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, repo, "is_private", "is_template"); err != nil { log.Error("Failed to Update: %s/%s Error: %v", ownerName, repoName, err) ctx.JSON(http.StatusInternalServerError, private.HookPostReceiveResult{ Err: fmt.Sprintf("Failed to Update: %s/%s Error: %v", ownerName, repoName, err), @@ -141,7 +141,7 @@ func HookPostReceive(ctx *gitea_context.PrivateContext) { continue } - pr, err := models.GetPullRequestByIndex(repo.ID, pullIndex) + pr, err := models.GetPullRequestByIndex(ctx, repo.ID, pullIndex) if err != nil && !models.IsErrPullRequestNotExist(err) { log.Error("Failed to get PR by index %v Error: %v", pullIndex, err) ctx.JSON(http.StatusInternalServerError, private.Response{ diff --git a/routers/private/hook_pre_receive.go b/routers/private/hook_pre_receive.go index d2203a1f99..1f005d35bf 100644 --- a/routers/private/hook_pre_receive.go +++ b/routers/private/hook_pre_receive.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" perm_model "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" gitea_context "code.gitea.io/gitea/modules/context" @@ -30,7 +31,7 @@ type preReceiveContext struct { // loadedPusher indicates that where the following information are loaded loadedPusher bool user *user_model.User // it's the org user if a DeployKey is used - userPerm models.Permission + userPerm access_model.Permission deployKeyAccessMode perm_model.AccessMode canCreatePullRequest bool @@ -55,7 +56,7 @@ func (ctx *preReceiveContext) CanWriteCode() bool { if !ctx.loadPusherAndPermission() { return false } - ctx.canWriteCode = ctx.userPerm.CanWriteToBranch(ctx.user, ctx.branchName) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite + ctx.canWriteCode = models.CanMaintainerWriteToBranch(ctx.userPerm, ctx.branchName, ctx.user) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite ctx.checkedCanWriteCode = true } return ctx.canWriteCode @@ -154,7 +155,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN return } - protectBranch, err := models.GetProtectedBranchBy(repo.ID, branchName) + protectBranch, err := models.GetProtectedBranchBy(ctx, repo.ID, branchName) if err != nil { log.Error("Unable to get protected branch: %s in %-v Error: %v", branchName, repo, err) ctx.JSON(http.StatusInternalServerError, private.Response{ @@ -472,7 +473,7 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool { } ctx.user = user - userPerm, err := models.GetUserRepoPermission(ctx, ctx.Repo.Repository, user) + userPerm, err := access_model.GetUserRepoPermission(ctx, ctx.Repo.Repository, user) if err != nil { log.Error("Unable to get Repo permission of repo %s/%s of User %s", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err) ctx.JSON(http.StatusInternalServerError, private.Response{ diff --git a/routers/private/hook_proc_receive.go b/routers/private/hook_proc_receive.go index e427a55c56..81dbc1fd18 100644 --- a/routers/private/hook_proc_receive.go +++ b/routers/private/hook_proc_receive.go @@ -23,7 +23,7 @@ func HookProcReceive(ctx *gitea_context.PrivateContext) { return } - results := agit.ProcRecive(ctx, opts) + results := agit.ProcReceive(ctx, opts) if ctx.Written() { return } diff --git a/routers/private/key.go b/routers/private/key.go index 3366b764e6..9977492c63 100644 --- a/routers/private/key.go +++ b/routers/private/key.go @@ -25,7 +25,7 @@ func UpdatePublicKeyInRepo(ctx *context.PrivateContext) { return } - deployKey, err := asymkey_model.GetDeployKeyByRepo(keyID, repoID) + deployKey, err := asymkey_model.GetDeployKeyByRepo(ctx, keyID, repoID) if err != nil { if asymkey_model.IsErrDeployKeyNotExist(err) { ctx.PlainText(http.StatusOK, "success") @@ -52,7 +52,7 @@ func UpdatePublicKeyInRepo(ctx *context.PrivateContext) { func AuthorizedPublicKeyByContent(ctx *context.PrivateContext) { content := ctx.FormString("content") - publicKey, err := asymkey_model.SearchPublicKeyByContent(content) + publicKey, err := asymkey_model.SearchPublicKeyByContent(ctx, content) if err != nil { ctx.JSON(http.StatusInternalServerError, private.Response{ Err: err.Error(), diff --git a/routers/private/mail.go b/routers/private/mail.go index 853b58b09d..966a838168 100644 --- a/routers/private/mail.go +++ b/routers/private/mail.go @@ -44,7 +44,7 @@ func SendEmail(ctx *context.PrivateContext) { var emails []string if len(mail.To) > 0 { for _, uname := range mail.To { - user, err := user_model.GetUserByName(uname) + user, err := user_model.GetUserByName(ctx, uname) if err != nil { err := fmt.Sprintf("Failed to get user information: %v", err) log.Error(err) diff --git a/routers/private/serv.go b/routers/private/serv.go index 6ef0079a2b..803d51e9d9 100644 --- a/routers/private/serv.go +++ b/routers/private/serv.go @@ -10,9 +10,9 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/models" asymkey_model "code.gitea.io/gitea/models/asymkey" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -109,7 +109,7 @@ func ServCommand(ctx *context.PrivateContext) { results.RepoName = repoName[:len(repoName)-5] } - owner, err := user_model.GetUserByName(results.OwnerName) + owner, err := user_model.GetUserByName(ctx, results.OwnerName) if err != nil { if user_model.IsErrUserNotExist(err) { // User is fetching/cloning a non-existent repository @@ -230,7 +230,7 @@ func ServCommand(ctx *context.PrivateContext) { var user *user_model.User if key.Type == asymkey_model.KeyTypeDeploy { var err error - deployKey, err = asymkey_model.GetDeployKeyByRepo(key.ID, repo.ID) + deployKey, err = asymkey_model.GetDeployKeyByRepo(ctx, key.ID, repo.ID) if err != nil { if asymkey_model.IsErrDeployKeyNotExist(err) { ctx.JSON(http.StatusNotFound, private.ErrServCommand{ @@ -320,7 +320,7 @@ func ServCommand(ctx *context.PrivateContext) { mode = perm.AccessModeRead } - perm, err := models.GetUserRepoPermission(ctx, repo, user) + perm, err := access_model.GetUserRepoPermission(ctx, repo, user) if err != nil { log.Error("Unable to get permissions for %-v with key %d in %-v Error: %v", user, key.ID, repo, err) ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{ @@ -345,7 +345,7 @@ func ServCommand(ctx *context.PrivateContext) { // We already know we aren't using a deploy key if !repoExist { - owner, err := user_model.GetUserByName(ownerName) + owner, err := user_model.GetUserByName(ctx, ownerName) if err != nil { ctx.JSON(http.StatusInternalServerError, private.ErrServCommand{ Results: results, diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index d4093f2049..78347e67c4 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -26,6 +26,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/updatechecker" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/cron" "code.gitea.io/gitea/services/forms" @@ -245,7 +246,7 @@ func Config(ctx *context.Context) { ctx.Data["OfflineMode"] = setting.OfflineMode ctx.Data["DisableRouterLog"] = setting.DisableRouterLog ctx.Data["RunUser"] = setting.RunUser - ctx.Data["RunMode"] = strings.Title(setting.RunMode) + ctx.Data["RunMode"] = util.ToTitleCase(setting.RunMode) if version, err := git.LocalVersion(); err == nil { ctx.Data["GitVersion"] = version.Original() } diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 1d72a88aa1..7ea8a52809 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -112,7 +112,7 @@ func NewAuthSource(ctx *context.Context) { ctx.Data["SSPIDefaultLanguage"] = "" // only the first as default - ctx.Data["oauth2_provider"] = oauth2providers[0].Name + ctx.Data["oauth2_provider"] = oauth2providers[0].Name() ctx.HTML(http.StatusOK, tplAuthNew) } diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go index 1483d0959d..bf71cb5595 100644 --- a/routers/web/admin/hooks.go +++ b/routers/web/admin/hooks.go @@ -35,7 +35,7 @@ func DefaultOrSystemWebhooks(ctx *context.Context) { sys["Title"] = ctx.Tr("admin.systemhooks") sys["Description"] = ctx.Tr("admin.systemhooks.desc") - sys["Webhooks"], err = webhook.GetSystemWebhooks(util.OptionalBoolNone) + sys["Webhooks"], err = webhook.GetSystemWebhooks(ctx, util.OptionalBoolNone) sys["BaseLink"] = setting.AppSubURL + "/admin/hooks" sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks" if err != nil { @@ -45,7 +45,7 @@ func DefaultOrSystemWebhooks(ctx *context.Context) { def["Title"] = ctx.Tr("admin.defaulthooks") def["Description"] = ctx.Tr("admin.defaulthooks.desc") - def["Webhooks"], err = webhook.GetDefaultWebhooks() + def["Webhooks"], err = webhook.GetDefaultWebhooks(ctx) def["BaseLink"] = setting.AppSubURL + "/admin/hooks" def["BaseLinkNew"] = setting.AppSubURL + "/admin/default-hooks" if err != nil { diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go index fb7be12c35..809d1de74b 100644 --- a/routers/web/admin/repos.go +++ b/routers/web/admin/repos.go @@ -121,7 +121,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) { return } - ctxUser, err := user_model.GetUserByName(dirSplit[0]) + ctxUser, err := user_model.GetUserByName(ctx, dirSplit[0]) if err != nil { if user_model.IsErrUserNotExist(err) { log.Debug("User does not exist: %s", dirSplit[0]) @@ -135,7 +135,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) { repoName := dirSplit[1] // check not a repo - has, err := repo_model.IsRepositoryExist(ctxUser, repoName) + has, err := repo_model.IsRepositoryExist(ctx, ctxUser, repoName) if err != nil { ctx.ServerError("IsRepositoryExist", err) return diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 7841ac569f..c37ecfd71e 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -389,7 +389,7 @@ func EditUserPost(ctx *context.Context) { u.ProhibitLogin = form.ProhibitLogin } - if err := user_model.UpdateUser(u, emailChanged); err != nil { + if err := user_model.UpdateUser(ctx, u, emailChanged); err != nil { if user_model.IsErrEmailAlreadyUsed(err) { ctx.Data["Err_Email"] = true ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form) diff --git a/routers/web/admin/users_test.go b/routers/web/admin/users_test.go index 9de548685c..e63367ccf2 100644 --- a/routers/web/admin/users_test.go +++ b/routers/web/admin/users_test.go @@ -47,7 +47,7 @@ func TestNewUserPost_MustChangePassword(t *testing.T) { assert.NotEmpty(t, ctx.Flash.SuccessMsg) - u, err := user_model.GetUserByName(username) + u, err := user_model.GetUserByName(ctx, username) assert.NoError(t, err) assert.Equal(t, username, u.Name) @@ -84,7 +84,7 @@ func TestNewUserPost_MustChangePasswordFalse(t *testing.T) { assert.NotEmpty(t, ctx.Flash.SuccessMsg) - u, err := user_model.GetUserByName(username) + u, err := user_model.GetUserByName(ctx, username) assert.NoError(t, err) assert.Equal(t, username, u.Name) @@ -151,7 +151,7 @@ func TestNewUserPost_VisibilityDefaultPublic(t *testing.T) { assert.NotEmpty(t, ctx.Flash.SuccessMsg) - u, err := user_model.GetUserByName(username) + u, err := user_model.GetUserByName(ctx, username) assert.NoError(t, err) assert.Equal(t, username, u.Name) @@ -190,7 +190,7 @@ func TestNewUserPost_VisibilityPrivate(t *testing.T) { assert.NotEmpty(t, ctx.Flash.SuccessMsg) - u, err := user_model.GetUserByName(username) + u, err := user_model.GetUserByName(ctx, username) assert.NoError(t, err) assert.Equal(t, username, u.Name) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index be936d2230..ea5c7232a8 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -64,7 +64,7 @@ func AutoSignIn(ctx *context.Context) (bool, error) { } }() - u, err := user_model.GetUserByName(uname) + u, err := user_model.GetUserByName(ctx, uname) if err != nil { if !user_model.IsErrUserNotExist(err) { return false, fmt.Errorf("GetUserByName: %v", err) @@ -632,8 +632,10 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth. ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()) ctx.HTML(http.StatusOK, TplActivate) - if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } return } @@ -653,14 +655,16 @@ func Activate(ctx *context.Context) { } // Resend confirmation email. if setting.Service.RegisterEmailConfirm { - if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) { + if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) { ctx.Data["ResendLimited"] = true } else { ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()) mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer) - if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } } } else { @@ -789,7 +793,7 @@ func ActivateEmail(ctx *context.Context) { if u, err := user_model.GetUserByID(email.UID); err != nil { log.Warn("GetUserByID: %d", email.UID) - } else { + } else if setting.CacheService.Enabled { // Allow user to validate more emails _ = ctx.Cache.Delete("MailResendLimit_" + u.LowerName) } diff --git a/routers/web/auth/linkaccount.go b/routers/web/auth/linkaccount.go index c3e96f077a..a2d76e9c5a 100644 --- a/routers/web/auth/linkaccount.go +++ b/routers/web/auth/linkaccount.go @@ -70,7 +70,7 @@ func LinkAccount(ctx *context.Context) { ctx.Data["user_exists"] = true } } else if len(uname) != 0 { - u, err := user_model.GetUserByName(uname) + u, err := user_model.GetUserByName(ctx, uname) if err != nil && !user_model.IsErrUserNotExist(err) { ctx.ServerError("UserSignIn", err) return diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 4c3e3c3ace..f646615968 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -5,6 +5,7 @@ package auth import ( + stdContext "context" "encoding/base64" "errors" "fmt" @@ -135,9 +136,9 @@ type AccessTokenResponse struct { IDToken string `json:"id_token,omitempty"` } -func newAccessTokenResponse(grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) { +func newAccessTokenResponse(ctx stdContext.Context, grant *auth.OAuth2Grant, serverKey, clientKey oauth2.JWTSigningKey) (*AccessTokenResponse, *AccessTokenError) { if setting.OAuth2.InvalidateRefreshTokens { - if err := grant.IncreaseCounter(); err != nil { + if err := grant.IncreaseCounter(ctx); err != nil { return nil, &AccessTokenError{ ErrorCode: AccessTokenErrorCodeInvalidGrant, ErrorDescription: "cannot increase the grant counter", @@ -182,7 +183,7 @@ func newAccessTokenResponse(grant *auth.OAuth2Grant, serverKey, clientKey oauth2 // generate OpenID Connect id_token signedIDToken := "" if grant.ScopeContains("openid") { - app, err := auth.GetOAuth2ApplicationByID(grant.ApplicationID) + app, err := auth.GetOAuth2ApplicationByID(ctx, grant.ApplicationID) if err != nil { return nil, &AccessTokenError{ ErrorCode: AccessTokenErrorCodeInvalidRequest, @@ -333,9 +334,9 @@ func IntrospectOAuth(ctx *context.Context) { token, err := oauth2.ParseToken(form.Token, oauth2.DefaultSigningKey) if err == nil { if token.Valid() == nil { - grant, err := auth.GetOAuth2GrantByID(token.GrantID) + grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID) if err == nil && grant != nil { - app, err := auth.GetOAuth2ApplicationByID(grant.ApplicationID) + app, err := auth.GetOAuth2ApplicationByID(ctx, grant.ApplicationID) if err == nil && app != nil { response.Active = true response.Scope = grant.Scope @@ -364,7 +365,7 @@ func AuthorizeOAuth(ctx *context.Context) { return } - app, err := auth.GetOAuth2ApplicationByClientID(form.ClientID) + app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID) if err != nil { if auth.IsErrOauthClientIDInvalid(err) { handleAuthorizeError(ctx, AuthorizeError{ @@ -438,7 +439,7 @@ func AuthorizeOAuth(ctx *context.Context) { return } - grant, err := app.GetGrantByUserID(ctx.Doer.ID) + grant, err := app.GetGrantByUserID(ctx, ctx.Doer.ID) if err != nil { handleServerError(ctx, form.State, form.RedirectURI) return @@ -446,7 +447,7 @@ func AuthorizeOAuth(ctx *context.Context) { // Redirect if user already granted access if grant != nil { - code, err := grant.GenerateNewAuthorizationCode(form.RedirectURI, form.CodeChallenge, form.CodeChallengeMethod) + code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, form.CodeChallenge, form.CodeChallengeMethod) if err != nil { handleServerError(ctx, form.State, form.RedirectURI) return @@ -458,7 +459,7 @@ func AuthorizeOAuth(ctx *context.Context) { } // Update nonce to reflect the new session if len(form.Nonce) > 0 { - err := grant.SetNonce(form.Nonce) + err := grant.SetNonce(ctx, form.Nonce) if err != nil { log.Error("Unable to update nonce: %v", err) } @@ -510,12 +511,12 @@ func GrantApplicationOAuth(ctx *context.Context) { ctx.Error(http.StatusBadRequest) return } - app, err := auth.GetOAuth2ApplicationByClientID(form.ClientID) + app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID) if err != nil { ctx.ServerError("GetOAuth2ApplicationByClientID", err) return } - grant, err := app.CreateGrant(ctx.Doer.ID, form.Scope) + grant, err := app.CreateGrant(ctx, ctx.Doer.ID, form.Scope) if err != nil { handleAuthorizeError(ctx, AuthorizeError{ State: form.State, @@ -525,7 +526,7 @@ func GrantApplicationOAuth(ctx *context.Context) { return } if len(form.Nonce) > 0 { - err := grant.SetNonce(form.Nonce) + err := grant.SetNonce(ctx, form.Nonce) if err != nil { log.Error("Unable to update nonce: %v", err) } @@ -535,7 +536,7 @@ func GrantApplicationOAuth(ctx *context.Context) { codeChallenge, _ = ctx.Session.Get("CodeChallenge").(string) codeChallengeMethod, _ = ctx.Session.Get("CodeChallengeMethod").(string) - code, err := grant.GenerateNewAuthorizationCode(form.RedirectURI, codeChallenge, codeChallengeMethod) + code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, codeChallenge, codeChallengeMethod) if err != nil { handleServerError(ctx, form.State, form.RedirectURI) return @@ -648,7 +649,7 @@ func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, server return } // get grant before increasing counter - grant, err := auth.GetOAuth2GrantByID(token.GrantID) + grant, err := auth.GetOAuth2GrantByID(ctx, token.GrantID) if err != nil || grant == nil { handleAccessTokenError(ctx, AccessTokenError{ ErrorCode: AccessTokenErrorCodeInvalidGrant, @@ -666,7 +667,7 @@ func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, server log.Warn("A client tried to use a refresh token for grant_id = %d was used twice!", grant.ID) return } - accessToken, tokenErr := newAccessTokenResponse(grant, serverKey, clientKey) + accessToken, tokenErr := newAccessTokenResponse(ctx, grant, serverKey, clientKey) if tokenErr != nil { handleAccessTokenError(ctx, *tokenErr) return @@ -675,7 +676,7 @@ func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, server } func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, serverKey, clientKey oauth2.JWTSigningKey) { - app, err := auth.GetOAuth2ApplicationByClientID(form.ClientID) + app, err := auth.GetOAuth2ApplicationByClientID(ctx, form.ClientID) if err != nil { handleAccessTokenError(ctx, AccessTokenError{ ErrorCode: AccessTokenErrorCodeInvalidClient, @@ -697,7 +698,7 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s }) return } - authorizationCode, err := auth.GetOAuth2AuthorizationByCode(form.Code) + authorizationCode, err := auth.GetOAuth2AuthorizationByCode(ctx, form.Code) if err != nil || authorizationCode == nil { handleAccessTokenError(ctx, AccessTokenError{ ErrorCode: AccessTokenErrorCodeUnauthorizedClient, @@ -722,13 +723,13 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s return } // remove token from database to deny duplicate usage - if err := authorizationCode.Invalidate(); err != nil { + if err := authorizationCode.Invalidate(ctx); err != nil { handleAccessTokenError(ctx, AccessTokenError{ ErrorCode: AccessTokenErrorCodeInvalidRequest, ErrorDescription: "cannot proceed your request", }) } - resp, tokenErr := newAccessTokenResponse(authorizationCode.Grant, serverKey, clientKey) + resp, tokenErr := newAccessTokenResponse(ctx, authorizationCode.Grant, serverKey, clientKey) if tokenErr != nil { handleAccessTokenError(ctx, *tokenErr) return @@ -846,7 +847,17 @@ func SignInOAuthCallback(ctx *context.Context) { } if u == nil { - if !setting.Service.AllowOnlyInternalRegistration && setting.OAuth2Client.EnableAutoRegistration { + if ctx.Doer != nil { + // attach user to already logged in user + err = externalaccount.LinkAccountToUser(ctx.Doer, gothUser) + if err != nil { + ctx.ServerError("UserLinkAccount", err) + return + } + + ctx.Redirect(setting.AppSubURL + "/user/settings/security") + return + } else if !setting.Service.AllowOnlyInternalRegistration && setting.OAuth2Client.EnableAutoRegistration { // create new user with details from oauth2 provider var missingFields []string if gothUser.UserID == "" { diff --git a/routers/web/auth/oauth_test.go b/routers/web/auth/oauth_test.go index 669d7431fc..5a09a95105 100644 --- a/routers/web/auth/oauth_test.go +++ b/routers/web/auth/oauth_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/services/auth/source/oauth2" @@ -21,7 +22,7 @@ func createAndParseToken(t *testing.T, grant *auth.OAuth2Grant) *oauth2.OIDCToke assert.NoError(t, err) assert.NotNil(t, signingKey) - response, terr := newAccessTokenResponse(grant, signingKey, signingKey) + response, terr := newAccessTokenResponse(db.DefaultContext, grant, signingKey, signingKey) assert.Nil(t, terr) assert.NotNil(t, response) @@ -43,7 +44,7 @@ func createAndParseToken(t *testing.T, grant *auth.OAuth2Grant) *oauth2.OIDCToke func TestNewAccessTokenResponse_OIDCToken(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) - grants, err := auth.GetOAuth2GrantsByUserID(3) + grants, err := auth.GetOAuth2GrantsByUserID(db.DefaultContext, 3) assert.NoError(t, err) assert.Len(t, grants, 1) @@ -59,7 +60,7 @@ func TestNewAccessTokenResponse_OIDCToken(t *testing.T) { assert.False(t, oidcToken.EmailVerified) user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) - grants, err = auth.GetOAuth2GrantsByUserID(user.ID) + grants, err = auth.GetOAuth2GrantsByUserID(db.DefaultContext, user.ID) assert.NoError(t, err) assert.Len(t, grants, 1) diff --git a/routers/web/auth/openid.go b/routers/web/auth/openid.go index 3012d8c5a5..32ae91da47 100644 --- a/routers/web/auth/openid.go +++ b/routers/web/auth/openid.go @@ -217,7 +217,7 @@ func signInOpenIDVerify(ctx *context.Context) { } if u == nil && nickname != "" { - u, _ = user_model.GetUserByName(nickname) + u, _ = user_model.GetUserByName(ctx, nickname) if err != nil { if !user_model.IsErrUserNotExist(err) { ctx.RenderWithErr(err.Error(), tplSignInOpenID, &forms.SignInOpenIDForm{ @@ -307,7 +307,7 @@ func ConnectOpenIDPost(ctx *context.Context) { // add OpenID for the user userOID := &user_model.UserOpenID{UID: u.ID, URI: oid} - if err = user_model.AddUserOpenID(userOID); err != nil { + if err = user_model.AddUserOpenID(ctx, userOID); err != nil { if user_model.IsErrOpenIDAlreadyUsed(err) { ctx.RenderWithErr(ctx.Tr("form.openid_been_used", oid), tplConnectOID, &form) return @@ -434,7 +434,7 @@ func RegisterOpenIDPost(ctx *context.Context) { // add OpenID for the user userOID := &user_model.UserOpenID{UID: u.ID, URI: oid} - if err = user_model.AddUserOpenID(userOID); err != nil { + if err = user_model.AddUserOpenID(ctx, userOID); err != nil { if user_model.IsErrOpenIDAlreadyUsed(err) { ctx.RenderWithErr(ctx.Tr("form.openid_been_used", oid), tplSignUpOID, &form) return diff --git a/routers/web/auth/password.go b/routers/web/auth/password.go index d7bf67cffb..06ccd2e76f 100644 --- a/routers/web/auth/password.go +++ b/routers/web/auth/password.go @@ -79,7 +79,7 @@ func ForgotPasswdPost(ctx *context.Context) { return } - if ctx.Cache.IsExist("MailResendLimit_" + u.LowerName) { + if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+u.LowerName) { ctx.Data["ResendLimited"] = true ctx.HTML(http.StatusOK, tplForgotPassword) return @@ -87,8 +87,10 @@ func ForgotPasswdPost(ctx *context.Context) { mailer.SendResetPasswordMail(u) - if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err = ctx.Cache.Put("MailResendLimit_"+u.LowerName, u.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language()) diff --git a/routers/web/base.go b/routers/web/base.go index 938abaef81..5f817c77ce 100644 --- a/routers/web/base.go +++ b/routers/web/base.go @@ -62,7 +62,7 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor w, req, u.String(), - http.StatusPermanentRedirect, + http.StatusTemporaryRedirect, ) }) } diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go index 41ca27782f..3fba2be37d 100644 --- a/routers/web/explore/code.go +++ b/routers/web/explore/code.go @@ -55,7 +55,7 @@ func Code(ctx *context.Context) { // guest user or non-admin user if ctx.Doer == nil || !isAdmin { - repoIDs, err = models.FindUserAccessibleRepoIDs(ctx.Doer) + repoIDs, err = repo_model.FindUserAccessibleRepoIDs(ctx.Doer) if err != nil { ctx.ServerError("SearchResults", err) return @@ -79,7 +79,7 @@ func Code(ctx *context.Context) { rightRepoMap := make(map[int64]*repo_model.Repository, len(repoMaps)) repoIDs = make([]int64, 0, len(repoMaps)) for id, repo := range repoMaps { - if models.CheckRepoUnitUser(repo, ctx.Doer, unit.TypeCode) { + if models.CheckRepoUnitUser(ctx, repo, ctx.Doer, unit.TypeCode) { rightRepoMap[id] = repo repoIDs = append(repoIDs, id) } diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index 3e8aa2bb0f..f64642bc95 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -7,7 +7,6 @@ package explore import ( "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" @@ -81,7 +80,7 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { language := ctx.FormTrim("language") ctx.Data["Language"] = language - repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: page, PageSize: opts.PageSize, diff --git a/routers/web/healthcheck/check.go b/routers/web/healthcheck/check.go index 481f05c0da..57707b6121 100644 --- a/routers/web/healthcheck/check.go +++ b/routers/web/healthcheck/check.go @@ -126,7 +126,7 @@ func checkCache(checks checks) status { } st := componentStatus{} - if err := cache.Ping(); err != nil { + if err := cache.GetCache().Ping(); err != nil { st.Status = fail st.Time = getCheckTime() log.Error("cache ping failed with error: %v", err) diff --git a/routers/web/org/home.go b/routers/web/org/home.go index 24a0f13b54..d565a0c242 100644 --- a/routers/web/org/home.go +++ b/routers/web/org/home.go @@ -8,7 +8,6 @@ import ( "net/http" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -105,7 +104,7 @@ func Home(ctx *context.Context) { count int64 err error ) - repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, diff --git a/routers/web/org/members.go b/routers/web/org/members.go index add8e724bd..374c893575 100644 --- a/routers/web/org/members.go +++ b/routers/web/org/members.go @@ -63,7 +63,7 @@ func Members(ctx *context.Context) { ctx.Data["Page"] = pager ctx.Data["Members"] = members ctx.Data["MembersIsPublicMember"] = membersIsPublic - ctx.Data["MembersIsUserOrgOwner"] = models.IsUserOrgOwner(members, org.ID) + ctx.Data["MembersIsUserOrgOwner"] = organization.IsUserOrgOwner(members, org.ID) ctx.Data["MembersTwoFaStatus"] = members.GetTwoFaStatus() ctx.HTML(http.StatusOK, tplMembers) diff --git a/routers/web/org/org_labels.go b/routers/web/org/org_labels.go index d79ffc597c..bfa9f162c3 100644 --- a/routers/web/org/org_labels.go +++ b/routers/web/org/org_labels.go @@ -17,7 +17,7 @@ import ( // RetrieveLabels find all the labels of an organization func RetrieveLabels(ctx *context.Context) { - labels, err := models.GetLabelsByOrgID(ctx.Org.Organization.ID, ctx.FormString("sort"), db.ListOptions{}) + labels, err := models.GetLabelsByOrgID(ctx, ctx.Org.Organization.ID, ctx.FormString("sort"), db.ListOptions{}) if err != nil { ctx.ServerError("RetrieveLabels.GetLabels", err) return @@ -59,7 +59,7 @@ func NewLabel(ctx *context.Context) { // UpdateLabel update a label's name and color func UpdateLabel(ctx *context.Context) { form := web.GetForm(ctx).(*forms.CreateLabelForm) - l, err := models.GetLabelInOrgByID(ctx.Org.Organization.ID, form.ID) + l, err := models.GetLabelInOrgByID(ctx, ctx.Org.Organization.ID, form.ID) if err != nil { switch { case models.IsErrOrgLabelNotExist(err): diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 5cd245ef09..c22a124e74 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -24,6 +24,7 @@ import ( user_setting "code.gitea.io/gitea/routers/web/user/setting" "code.gitea.io/gitea/services/forms" "code.gitea.io/gitea/services/org" + repo_service "code.gitea.io/gitea/services/repository" user_service "code.gitea.io/gitea/services/user" ) @@ -66,7 +67,7 @@ func SettingsPost(ctx *context.Context) { // Check if organization name has been changed. if org.LowerName != strings.ToLower(form.Name) { - isExist, err := user_model.IsUserExist(org.ID, form.Name) + isExist, err := user_model.IsUserExist(ctx, org.ID, form.Name) if err != nil { ctx.ServerError("IsUserExist", err) return @@ -110,14 +111,14 @@ func SettingsPost(ctx *context.Context) { visibilityChanged := form.Visibility != org.Visibility org.Visibility = form.Visibility - if err := user_model.UpdateUser(org.AsUser(), false); err != nil { + if err := user_model.UpdateUser(ctx, org.AsUser(), false); err != nil { ctx.ServerError("UpdateUser", err) return } // update forks visibility if visibilityChanged { - repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{ + repos, _, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{ Actor: org.AsUser(), Private: true, ListOptions: db.ListOptions{Page: 1, PageSize: org.NumRepos}, }) if err != nil { @@ -126,7 +127,7 @@ func SettingsPost(ctx *context.Context) { } for _, repo := range repos { repo.OwnerName = org.Name - if err := models.UpdateRepository(repo, true); err != nil { + if err := repo_service.UpdateRepository(repo, true); err != nil { ctx.ServerError("UpdateRepository", err) return } @@ -207,7 +208,7 @@ func Webhooks(ctx *context.Context) { ctx.Data["BaseLinkNew"] = ctx.Org.OrgLink + "/settings/hooks" ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc") - ws, err := webhook.ListWebhooksByOpts(&webhook.ListWebhookOptions{OrgID: ctx.Org.Organization.ID}) + ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OrgID: ctx.Org.Organization.ID}) if err != nil { ctx.ServerError("GetWebhooksByOrgId", err) return diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 31bfaea92f..284fb096f3 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -23,7 +23,6 @@ import ( "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/utils" "code.gitea.io/gitea/services/forms" @@ -123,7 +122,7 @@ func TeamsAction(ctx *context.Context) { } uname := utils.RemoveUsernameParameterSuffix(strings.ToLower(ctx.FormString("uname"))) var u *user_model.User - u, err = user_model.GetUserByName(uname) + u, err = user_model.GetUserByName(ctx, uname) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Flash.Error(ctx.Tr("form.user_not_exist")) @@ -357,17 +356,14 @@ func SearchTeam(ctx *context.Context) { return } - apiTeams := make([]*api.Team, len(teams)) - for i := range teams { - if err := teams[i].GetUnits(); err != nil { - log.Error("Team GetUnits failed: %v", err) - ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ - "ok": false, - "error": "SearchTeam failed to get units", - }) - return - } - apiTeams[i] = convert.ToTeam(teams[i]) + apiTeams, err := convert.ToTeams(teams, false) + if err != nil { + log.Error("convert ToTeams failed: %v", err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "ok": false, + "error": "SearchTeam failed to get units", + }) + return } ctx.SetTotalCountHeader(maxResults) diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go index c930311f70..190dc6c2c7 100644 --- a/routers/web/repo/attachment.go +++ b/routers/web/repo/attachment.go @@ -8,7 +8,7 @@ import ( "fmt" "net/http" - "code.gitea.io/gitea/models" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/httpcache" @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/routers/common" "code.gitea.io/gitea/services/attachment" + repo_service "code.gitea.io/gitea/services/repository" ) // UploadIssueAttachment response for Issue/PR attachments @@ -63,7 +64,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) { // DeleteAttachment response for deleting issue's attachment func DeleteAttachment(ctx *context.Context) { file := ctx.FormString("file") - attach, err := repo_model.GetAttachmentByUUID(file) + attach, err := repo_model.GetAttachmentByUUID(ctx, file) if err != nil { ctx.Error(http.StatusBadRequest, err.Error()) return @@ -84,7 +85,7 @@ func DeleteAttachment(ctx *context.Context) { // GetAttachment serve attachements func GetAttachment(ctx *context.Context) { - attach, err := repo_model.GetAttachmentByUUID(ctx.Params(":uuid")) + attach, err := repo_model.GetAttachmentByUUID(ctx, ctx.Params(":uuid")) if err != nil { if repo_model.IsErrAttachmentNotExist(err) { ctx.Error(http.StatusNotFound) @@ -94,7 +95,7 @@ func GetAttachment(ctx *context.Context) { return } - repository, unitType, err := models.LinkedRepository(attach) + repository, unitType, err := repo_service.LinkedRepository(attach) if err != nil { ctx.ServerError("LinkedRepository", err) return @@ -106,7 +107,7 @@ func GetAttachment(ctx *context.Context) { return } } else { // If we have the repository we check access - perm, err := models.GetUserRepoPermission(ctx, repository, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer) if err != nil { ctx.Error(http.StatusInternalServerError, "GetUserRepoPermission", err.Error()) return diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index 7f68fd3dd1..1636a6c293 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -335,7 +335,7 @@ func Diff(ctx *context.Context) { ctx.Data["Commit"] = commit ctx.Data["Diff"] = diff - statuses, _, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, commitID, db.ListOptions{}) + statuses, _, err := models.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptions{}) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 31914c43ab..d3653f04e9 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -18,6 +18,7 @@ import ( "strings" "code.gitea.io/gitea/models" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -253,7 +254,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { } else if len(headInfos) == 2 { headInfosSplit := strings.Split(headInfos[0], "/") if len(headInfosSplit) == 1 { - ci.HeadUser, err = user_model.GetUserByName(headInfos[0]) + ci.HeadUser, err = user_model.GetUserByName(ctx, headInfos[0]) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.NotFound("GetUserByName", nil) @@ -412,7 +413,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // Now we need to assert that the ctx.Doer has permission to read // the baseRepo's code and pulls // (NOT headRepo's) - permBase, err := models.GetUserRepoPermission(ctx, baseRepo, ctx.Doer) + permBase, err := access_model.GetUserRepoPermission(ctx, baseRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return nil @@ -431,7 +432,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { // If we're not merging from the same repo: if !isSameRepo { // Assert ctx.Doer has permission to read headRepo's codes - permHead, err := models.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer) + permHead, err := access_model.GetUserRepoPermission(ctx, ci.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return nil @@ -456,7 +457,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { if rootRepo != nil && rootRepo.ID != ci.HeadRepo.ID && rootRepo.ID != baseRepo.ID { - canRead := models.CheckRepoUnitUser(rootRepo, ctx.Doer, unit.TypeCode) + canRead := models.CheckRepoUnitUser(ctx, rootRepo, ctx.Doer, unit.TypeCode) if canRead { ctx.Data["RootRepo"] = rootRepo if !fileOnly { @@ -481,7 +482,7 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo { ownForkRepo.ID != ci.HeadRepo.ID && ownForkRepo.ID != baseRepo.ID && (rootRepo == nil || ownForkRepo.ID != rootRepo.ID) { - canRead := models.CheckRepoUnitUser(ownForkRepo, ctx.Doer, unit.TypeCode) + canRead := models.CheckRepoUnitUser(ctx, ownForkRepo, ctx.Doer, unit.TypeCode) if canRead { ctx.Data["OwnForkRepo"] = ownForkRepo if !fileOnly { diff --git a/routers/web/repo/find.go b/routers/web/repo/find.go new file mode 100644 index 0000000000..7117c00076 --- /dev/null +++ b/routers/web/repo/find.go @@ -0,0 +1,24 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo + +import ( + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" +) + +const ( + tplFindFiles base.TplName = "repo/find/files" +) + +// FindFiles render the page to find repository files +func FindFiles(ctx *context.Context) { + path := ctx.Params("*") + ctx.Data["TreeLink"] = ctx.Repo.RepoLink + "/src/" + path + ctx.Data["DataLink"] = ctx.Repo.RepoLink + "/tree-list/" + path + ctx.HTML(http.StatusOK, tplFindFiles) +} diff --git a/routers/web/repo/http.go b/routers/web/repo/http.go index a52d9b76c2..6a85bca16b 100644 --- a/routers/web/repo/http.go +++ b/routers/web/repo/http.go @@ -19,9 +19,9 @@ import ( "sync" "time" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/auth" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/context" @@ -182,7 +182,7 @@ func httpBase(ctx *context.Context) (h *serviceHandler) { } if repoExist { - p, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer) + p, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 7ddeb05f71..4a732ba454 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -23,6 +23,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" project_model "code.gitea.io/gitea/models/project" pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" @@ -48,6 +49,7 @@ import ( "code.gitea.io/gitea/services/forms" issue_service "code.gitea.io/gitea/services/issue" pull_service "code.gitea.io/gitea/services/pull" + repo_service "code.gitea.io/gitea/services/repository" ) const ( @@ -254,7 +256,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti } issueList := models.IssueList(issues) - approvalCounts, err := issueList.GetApprovalCounts() + approvalCounts, err := issueList.GetApprovalCounts(ctx) if err != nil { ctx.ServerError("ApprovalCounts", err) return @@ -282,7 +284,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti ctx.Data["CommitStatuses"] = commitStatuses // Get assignees. - ctx.Data["Assignees"], err = models.GetRepoAssignees(repo) + ctx.Data["Assignees"], err = repo_model.GetRepoAssignees(ctx, repo) if err != nil { ctx.ServerError("GetAssignees", err) return @@ -293,14 +295,14 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti return } - labels, err := models.GetLabelsByRepoID(repo.ID, "", db.ListOptions{}) + labels, err := models.GetLabelsByRepoID(ctx, repo.ID, "", db.ListOptions{}) if err != nil { ctx.ServerError("GetLabelsByRepoID", err) return } if repo.Owner.IsOrganization() { - orgLabels, err := models.GetLabelsByOrgID(repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) + orgLabels, err := models.GetLabelsByOrgID(ctx, repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) if err != nil { ctx.ServerError("GetLabelsByOrgID", err) return @@ -342,7 +344,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti } if ctx.Repo.CanWriteIssuesOrPulls(ctx.Params(":type") == "pulls") { - projects, _, err := project_model.GetProjects(project_model.SearchOptions{ + projects, _, err := project_model.GetProjects(ctx, project_model.SearchOptions{ RepoID: repo.ID, Type: project_model.TypeRepository, IsClosed: util.OptionalBoolOf(isShowClosed), @@ -440,7 +442,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R return } - ctx.Data["Assignees"], err = models.GetRepoAssignees(repo) + ctx.Data["Assignees"], err = repo_model.GetRepoAssignees(ctx, repo) if err != nil { ctx.ServerError("GetAssignees", err) return @@ -452,7 +454,7 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { var err error - ctx.Data["OpenProjects"], _, err = project_model.GetProjects(project_model.SearchOptions{ + ctx.Data["OpenProjects"], _, err = project_model.GetProjects(ctx, project_model.SearchOptions{ RepoID: repo.ID, Page: -1, IsClosed: util.OptionalBoolFalse, @@ -463,7 +465,7 @@ func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { return } - ctx.Data["ClosedProjects"], _, err = project_model.GetProjects(project_model.SearchOptions{ + ctx.Data["ClosedProjects"], _, err = project_model.GetProjects(ctx, project_model.SearchOptions{ RepoID: repo.ID, Page: -1, IsClosed: util.OptionalBoolTrue, @@ -521,13 +523,13 @@ func RetrieveRepoReviewers(ctx *context.Context, repo *repo_model.Repository, is posterID = 0 } - reviewers, err = models.GetReviewers(repo, ctx.Doer.ID, posterID) + reviewers, err = repo_model.GetReviewers(ctx, repo, ctx.Doer.ID, posterID) if err != nil { ctx.ServerError("GetReviewers", err) return } - teamReviewers, err = models.GetReviewerTeams(repo) + teamReviewers, err = repo_service.GetReviewerTeams(repo) if err != nil { ctx.ServerError("GetReviewerTeams", err) return @@ -672,14 +674,14 @@ func RetrieveRepoMetas(ctx *context.Context, repo *repo_model.Repository, isPull return nil } - labels, err := models.GetLabelsByRepoID(repo.ID, "", db.ListOptions{}) + labels, err := models.GetLabelsByRepoID(ctx, repo.ID, "", db.ListOptions{}) if err != nil { ctx.ServerError("GetLabelsByRepoID", err) return nil } ctx.Data["Labels"] = labels if repo.Owner.IsOrganization() { - orgLabels, err := models.GetLabelsByOrgID(repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) + orgLabels, err := models.GetLabelsByOrgID(ctx, repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) if err != nil { return nil } @@ -760,10 +762,10 @@ func setTemplateIfExists(ctx *context.Context, ctxDataKey string, possibleDirs, ctx.Data[issueTemplateTitleKey] = meta.Title ctx.Data[ctxDataKey] = templateBody labelIDs := make([]string, 0, len(meta.Labels)) - if repoLabels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, "", db.ListOptions{}); err == nil { + if repoLabels, err := models.GetLabelsByRepoID(ctx, ctx.Repo.Repository.ID, "", db.ListOptions{}); err == nil { ctx.Data["Labels"] = repoLabels if ctx.Repo.Owner.IsOrganization() { - if orgLabels, err := models.GetLabelsByOrgID(ctx.Repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}); err == nil { + if orgLabels, err := models.GetLabelsByOrgID(ctx, ctx.Repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}); err == nil { ctx.Data["OrgLabels"] = orgLabels repoLabels = append(repoLabels, orgLabels...) } @@ -817,7 +819,7 @@ func NewIssue(ctx *context.Context) { projectID := ctx.FormInt64("project") if projectID > 0 { - project, err := project_model.GetProjectByID(projectID) + project, err := project_model.GetProjectByID(ctx, projectID) if err != nil { log.Error("GetProjectByID: %d: %v", projectID, err) } else if project.RepoID != ctx.Repo.Repository.ID { @@ -929,7 +931,7 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull } if form.ProjectID > 0 { - p, err := project_model.GetProjectByID(form.ProjectID) + p, err := project_model.GetProjectByID(ctx, form.ProjectID) if err != nil { ctx.ServerError("GetProjectByID", err) return nil, nil, 0, 0 @@ -959,7 +961,7 @@ func ValidateRepoMetas(ctx *context.Context, form forms.CreateIssueForm, isPull return nil, nil, 0, 0 } - valid, err := models.CanBeAssigned(assignee, repo, isPull) + valid, err := access_model.CanBeAssigned(ctx, assignee, repo, isPull) if err != nil { ctx.ServerError("CanBeAssigned", err) return nil, nil, 0, 0 @@ -1051,7 +1053,7 @@ func NewIssuePost(ctx *context.Context) { // roleDescriptor returns the Role Descriptor for a comment in/with the given repo, poster and issue func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *user_model.User, issue *models.Issue) (models.RoleDescriptor, error) { - perm, err := models.GetUserRepoPermission(ctx, repo, poster) + perm, err := access_model.GetUserRepoPermission(ctx, repo, poster) if err != nil { return models.RoleDescriptorNone, err } @@ -1067,7 +1069,7 @@ func roleDescriptor(ctx stdCtx.Context, repo *repo_model.Repository, poster *use } else { // Otherwise check if poster is the real repo admin. - ok, err := models.IsUserRealRepoAdmin(repo, poster) + ok, err := access_model.IsUserRealRepoAdmin(repo, poster) if err != nil { return models.RoleDescriptorNone, err } @@ -1236,7 +1238,7 @@ func ViewIssue(ctx *context.Context) { for i := range issue.Labels { labelIDMark[issue.Labels[i].ID] = true } - labels, err := models.GetLabelsByRepoID(repo.ID, "", db.ListOptions{}) + labels, err := models.GetLabelsByRepoID(ctx, repo.ID, "", db.ListOptions{}) if err != nil { ctx.ServerError("GetLabelsByRepoID", err) return @@ -1244,7 +1246,7 @@ func ViewIssue(ctx *context.Context) { ctx.Data["Labels"] = labels if repo.Owner.IsOrganization() { - orgLabels, err := models.GetLabelsByOrgID(repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) + orgLabels, err := models.GetLabelsByOrgID(ctx, repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) if err != nil { ctx.ServerError("GetLabelsByOrgID", err) return @@ -1276,7 +1278,7 @@ func ViewIssue(ctx *context.Context) { if issue.IsPull { canChooseReviewer := ctx.Repo.CanWrite(unit.TypePullRequests) if !canChooseReviewer && ctx.Doer != nil && ctx.IsSigned { - canChooseReviewer, err = models.IsOfficialReviewer(issue, ctx.Doer) + canChooseReviewer, err = models.IsOfficialReviewer(ctx, issue, ctx.Doer) if err != nil { ctx.ServerError("IsOfficialReviewer", err) return @@ -1311,7 +1313,7 @@ func ViewIssue(ctx *context.Context) { if !ctx.Data["IsStopwatchRunning"].(bool) { var exists bool var sw *models.Stopwatch - if exists, sw, err = models.HasUserStopwatch(ctx.Doer.ID); err != nil { + if exists, sw, err = models.HasUserStopwatch(ctx, ctx.Doer.ID); err != nil { ctx.ServerError("HasUserStopwatch", err) return } @@ -1526,7 +1528,7 @@ func ViewIssue(ctx *context.Context) { if err := pull.LoadHeadRepoCtx(ctx); err != nil { log.Error("LoadHeadRepo: %v", err) } else if pull.HeadRepo != nil { - perm, err := models.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, pull.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -1548,7 +1550,7 @@ func ViewIssue(ctx *context.Context) { if err := pull.LoadBaseRepoCtx(ctx); err != nil { log.Error("LoadBaseRepo: %v", err) } - perm, err := models.GetUserRepoPermission(ctx, pull.BaseRepo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, pull.BaseRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -1687,12 +1689,12 @@ func ViewIssue(ctx *context.Context) { } // Get Dependencies - ctx.Data["BlockedByDependencies"], err = issue.BlockedByDependencies() + ctx.Data["BlockedByDependencies"], err = issue.BlockedByDependencies(ctx) if err != nil { ctx.ServerError("BlockedByDependencies", err) return } - ctx.Data["BlockingDependencies"], err = issue.BlockingDependencies() + ctx.Data["BlockingDependencies"], err = issue.BlockingDependencies(ctx) if err != nil { ctx.ServerError("BlockingDependencies", err) return @@ -1766,7 +1768,7 @@ func getActionIssues(ctx *context.Context) []*models.Issue { } issueIDs = append(issueIDs, issueID) } - issues, err := models.GetIssuesByIDs(issueIDs) + issues, err := models.GetIssuesByIDs(ctx, issueIDs) if err != nil { ctx.ServerError("GetIssuesByIDs", err) return nil @@ -1798,6 +1800,21 @@ func GetIssueInfo(ctx *context.Context) { } return } + + if issue.IsPull { + // Need to check if Pulls are enabled and we can read Pulls + if !ctx.Repo.Repository.CanEnablePulls() || !ctx.Repo.CanRead(unit.TypePullRequests) { + ctx.Error(http.StatusNotFound) + return + } + } else { + // Need to check if Issues are enabled and we can read Issues + if !ctx.Repo.CanRead(unit.TypeIssues) { + ctx.Error(http.StatusNotFound) + return + } + } + ctx.JSON(http.StatusOK, convert.ToAPIIssue(issue)) } @@ -1872,7 +1889,7 @@ func UpdateIssueContent(ctx *context.Context) { // when update the request doesn't intend to update attachments (eg: change checkbox state), ignore attachment updates if !ctx.FormBool("ignore_attachments") { - if err := updateAttachments(issue, ctx.FormStrings("files[]")); err != nil { + if err := updateAttachments(ctx, issue, ctx.FormStrings("files[]")); err != nil { ctx.ServerError("UpdateAttachments", err) return } @@ -1978,7 +1995,7 @@ func UpdateIssueAssignee(ctx *context.Context) { return } - valid, err := models.CanBeAssigned(assignee, issue.Repo, issue.IsPull) + valid, err := access_model.CanBeAssigned(ctx, assignee, issue.Repo, issue.IsPull) if err != nil { ctx.ServerError("canBeAssigned", err) return @@ -2046,7 +2063,7 @@ func UpdatePullReviewRequest(ctx *context.Context) { return } - team, err := organization.GetTeamByID(-reviewID) + team, err := organization.GetTeamByID(ctx, -reviewID) if err != nil { ctx.ServerError("GetTeamByID", err) return @@ -2144,7 +2161,7 @@ func SearchIssues(ctx *context.Context) { } // find repos user can access (for issue search) - opts := &models.SearchRepoOptions{ + opts := &repo_model.SearchRepoOptions{ Private: false, AllPublic: true, TopicOnly: false, @@ -2159,7 +2176,7 @@ func SearchIssues(ctx *context.Context) { opts.AllLimited = true } if ctx.FormString("owner") != "" { - owner, err := user_model.GetUserByName(ctx.FormString("owner")) + owner, err := user_model.GetUserByName(ctx, ctx.FormString("owner")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Error(http.StatusBadRequest, "Owner not found", err.Error()) @@ -2178,7 +2195,7 @@ func SearchIssues(ctx *context.Context) { ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team") return } - team, err := organization.GetTeam(opts.OwnerID, ctx.FormString("team")) + team, err := organization.GetTeam(ctx, opts.OwnerID, ctx.FormString("team")) if err != nil { if organization.IsErrTeamNotExist(err) { ctx.Error(http.StatusBadRequest, "Team not found", err.Error()) @@ -2190,8 +2207,8 @@ func SearchIssues(ctx *context.Context) { opts.TeamID = team.ID } - repoCond := models.SearchRepositoryCondition(opts) - repoIDs, _, err := models.SearchRepositoryIDs(opts) + repoCond := repo_model.SearchRepositoryCondition(opts) + repoIDs, _, err := repo_model.SearchRepositoryIDs(opts) if err != nil { ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err.Error()) return @@ -2306,7 +2323,7 @@ func getUserIDForFilter(ctx *context.Context, queryName string) int64 { return 0 } - user, err := user_model.GetUserByName(userName) + user, err := user_model.GetUserByName(ctx, userName) if user_model.IsErrUserNotExist(err) { ctx.NotFound("", err) return 0 @@ -2630,7 +2647,7 @@ func NewComment(ctx *context.Context) { // UpdateCommentContent change comment of issue's content func UpdateCommentContent(ctx *context.Context) { - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) return @@ -2671,7 +2688,7 @@ func UpdateCommentContent(ctx *context.Context) { // when the update request doesn't intend to update attachments (eg: change checkbox state), ignore attachment updates if !ctx.FormBool("ignore_attachments") { - if err := updateAttachments(comment, ctx.FormStrings("files[]")); err != nil { + if err := updateAttachments(ctx, comment, ctx.FormStrings("files[]")); err != nil { ctx.ServerError("UpdateAttachments", err) return } @@ -2696,7 +2713,7 @@ func UpdateCommentContent(ctx *context.Context) { // DeleteComment delete comment of issue func DeleteComment(ctx *context.Context) { - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) return @@ -2822,7 +2839,7 @@ func ChangeIssueReaction(ctx *context.Context) { // ChangeCommentReaction create a reaction for comment func ChangeCommentReaction(ctx *context.Context) { form := web.GetForm(ctx).(*forms.ReactionForm) - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) return @@ -2941,7 +2958,7 @@ func filterXRefComments(ctx *context.Context, issue *models.Issue) error { if err != nil { return err } - perm, err := models.GetUserRepoPermission(ctx, c.RefRepo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, c.RefRepo, ctx.Doer) if err != nil { return err } @@ -2967,7 +2984,7 @@ func GetIssueAttachments(ctx *context.Context) { // GetCommentAttachments returns attachments for the comment func GetCommentAttachments(ctx *context.Context) { - comment, err := models.GetCommentByID(ctx.ParamsInt64(":id")) + comment, err := models.GetCommentByID(ctx, ctx.ParamsInt64(":id")) if err != nil { ctx.NotFoundOrServerError("GetCommentByID", models.IsErrCommentNotExist, err) return @@ -2985,7 +3002,7 @@ func GetCommentAttachments(ctx *context.Context) { ctx.JSON(http.StatusOK, attachments) } -func updateAttachments(item interface{}, files []string) error { +func updateAttachments(ctx *context.Context, item interface{}, files []string) error { var attachments []*repo_model.Attachment switch content := item.(type) { case *models.Issue: @@ -3019,9 +3036,9 @@ func updateAttachments(item interface{}, files []string) error { } switch content := item.(type) { case *models.Issue: - content.Attachments, err = repo_model.GetAttachmentsByIssueID(content.ID) + content.Attachments, err = repo_model.GetAttachmentsByIssueID(ctx, content.ID) case *models.Comment: - content.Attachments, err = repo_model.GetAttachmentsByCommentID(content.ID) + content.Attachments, err = repo_model.GetAttachmentsByCommentID(ctx, content.ID) default: return fmt.Errorf("unknown Type: %T", content) } diff --git a/routers/web/repo/issue_content_history.go b/routers/web/repo/issue_content_history.go index 11cc8a2a6f..407832dffe 100644 --- a/routers/web/repo/issue_content_history.go +++ b/routers/web/repo/issue_content_history.go @@ -130,7 +130,7 @@ func GetContentHistoryDetail(ctx *context.Context) { var comment *models.Comment if history.CommentID != 0 { var err error - if comment, err = models.GetCommentByID(history.CommentID); err != nil { + if comment, err = models.GetCommentByID(ctx, history.CommentID); err != nil { log.Error("can not get comment for issue content history %v. err=%v", historyID, err) return } @@ -190,7 +190,7 @@ func SoftDeleteContentHistory(ctx *context.Context) { var history *issuesModel.ContentHistory var err error if commentID != 0 { - if comment, err = models.GetCommentByID(commentID); err != nil { + if comment, err = models.GetCommentByID(ctx, commentID); err != nil { log.Error("can not get comment for issue content history %v. err=%v", historyID, err) return } diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go index 887bbc115f..2e72d659be 100644 --- a/routers/web/repo/issue_label.go +++ b/routers/web/repo/issue_label.go @@ -56,7 +56,7 @@ func InitializeLabels(ctx *context.Context) { // RetrieveLabels find all the labels of a repository and organization func RetrieveLabels(ctx *context.Context) { - labels, err := models.GetLabelsByRepoID(ctx.Repo.Repository.ID, ctx.FormString("sort"), db.ListOptions{}) + labels, err := models.GetLabelsByRepoID(ctx, ctx.Repo.Repository.ID, ctx.FormString("sort"), db.ListOptions{}) if err != nil { ctx.ServerError("RetrieveLabels.GetLabels", err) return @@ -69,7 +69,7 @@ func RetrieveLabels(ctx *context.Context) { ctx.Data["Labels"] = labels if ctx.Repo.Owner.IsOrganization() { - orgLabels, err := models.GetLabelsByOrgID(ctx.Repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) + orgLabels, err := models.GetLabelsByOrgID(ctx, ctx.Repo.Owner.ID, ctx.FormString("sort"), db.ListOptions{}) if err != nil { ctx.ServerError("GetLabelsByOrgID", err) return @@ -127,7 +127,7 @@ func NewLabel(ctx *context.Context) { // UpdateLabel update a label's name and color func UpdateLabel(ctx *context.Context) { form := web.GetForm(ctx).(*forms.CreateLabelForm) - l, err := models.GetLabelInRepoByID(ctx.Repo.Repository.ID, form.ID) + l, err := models.GetLabelInRepoByID(ctx, ctx.Repo.Repository.ID, form.ID) if err != nil { switch { case models.IsErrRepoLabelNotExist(err): @@ -177,7 +177,7 @@ func UpdateIssueLabel(ctx *context.Context) { } } case "attach", "detach", "toggle": - label, err := models.GetLabelByID(ctx.FormInt64("id")) + label, err := models.GetLabelByID(ctx, ctx.FormInt64("id")) if err != nil { if models.IsErrRepoLabelNotExist(err) { ctx.Error(http.StatusNotFound, "GetLabelByID") @@ -191,7 +191,7 @@ func UpdateIssueLabel(ctx *context.Context) { // detach if any issues already have label, otherwise attach action = "attach" for _, issue := range issues { - if models.HasIssueLabel(issue.ID, label.ID) { + if models.HasIssueLabel(ctx, issue.ID, label.ID) { action = "detach" break } diff --git a/routers/web/repo/issue_stopwatch.go b/routers/web/repo/issue_stopwatch.go index 83e4ecedbf..4e1f6af039 100644 --- a/routers/web/repo/issue_stopwatch.go +++ b/routers/web/repo/issue_stopwatch.go @@ -87,7 +87,7 @@ func GetActiveStopwatch(ctx *context.Context) { return } - _, sw, err := models.HasUserStopwatch(ctx.Doer.ID) + _, sw, err := models.HasUserStopwatch(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("HasUserStopwatch", err) return diff --git a/routers/web/repo/projects.go b/routers/web/repo/projects.go index a6f843d848..c1805944db 100644 --- a/routers/web/repo/projects.go +++ b/routers/web/repo/projects.go @@ -70,7 +70,7 @@ func Projects(ctx *context.Context) { total = repo.NumClosedProjects } - projects, count, err := project_model.GetProjects(project_model.SearchOptions{ + projects, count, err := project_model.GetProjects(ctx, project_model.SearchOptions{ RepoID: repo.ID, Page: page, IsClosed: util.OptionalBoolOf(isShowClosed), @@ -182,7 +182,7 @@ func ChangeProjectStatus(ctx *context.Context) { // DeleteProject delete a project func DeleteProject(ctx *context.Context) { - p, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -213,7 +213,7 @@ func EditProject(ctx *context.Context) { ctx.Data["PageIsEditProjects"] = true ctx.Data["CanWriteProjects"] = ctx.Repo.Permission.CanWrite(unit.TypeProjects) - p, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -245,7 +245,7 @@ func EditProjectPost(ctx *context.Context) { return } - p, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + p, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -261,7 +261,7 @@ func EditProjectPost(ctx *context.Context) { p.Title = form.Title p.Description = form.Content - if err = project_model.UpdateProject(p); err != nil { + if err = project_model.UpdateProject(ctx, p); err != nil { ctx.ServerError("UpdateProjects", err) return } @@ -272,7 +272,7 @@ func EditProjectPost(ctx *context.Context) { // ViewProject renders the project board for a project func ViewProject(ctx *context.Context) { - project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -286,7 +286,7 @@ func ViewProject(ctx *context.Context) { return } - boards, err := project_model.GetBoards(project.ID) + boards, err := project_model.GetBoards(ctx, project.ID) if err != nil { ctx.ServerError("GetProjectBoards", err) return @@ -385,7 +385,7 @@ func DeleteProjectBoard(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -395,7 +395,7 @@ func DeleteProjectBoard(ctx *context.Context) { return } - pb, err := project_model.GetBoard(ctx.ParamsInt64(":boardID")) + pb, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) if err != nil { ctx.ServerError("GetProjectBoard", err) return @@ -434,7 +434,7 @@ func AddBoardToProjectPost(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -474,7 +474,7 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*project_model.Pr return nil, nil } - project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("", nil) @@ -484,7 +484,7 @@ func checkProjectBoardChangePermissions(ctx *context.Context) (*project_model.Pr return nil, nil } - board, err := project_model.GetBoard(ctx.ParamsInt64(":boardID")) + board, err := project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) if err != nil { ctx.ServerError("GetProjectBoard", err) return nil, nil @@ -523,7 +523,7 @@ func EditProjectBoard(ctx *context.Context) { board.Sorting = form.Sorting } - if err := project_model.UpdateBoard(board); err != nil { + if err := project_model.UpdateBoard(ctx, board); err != nil { ctx.ServerError("UpdateProjectBoard", err) return } @@ -566,7 +566,7 @@ func MoveIssues(ctx *context.Context) { return } - project, err := project_model.GetProjectByID(ctx.ParamsInt64(":id")) + project, err := project_model.GetProjectByID(ctx, ctx.ParamsInt64(":id")) if err != nil { if project_model.IsErrProjectNotExist(err) { ctx.NotFound("ProjectNotExist", nil) @@ -589,7 +589,7 @@ func MoveIssues(ctx *context.Context) { Title: ctx.Tr("repo.projects.type.uncategorized"), } } else { - board, err = project_model.GetBoard(ctx.ParamsInt64(":boardID")) + board, err = project_model.GetBoard(ctx, ctx.ParamsInt64(":boardID")) if err != nil { if project_model.IsErrProjectBoardNotExist(err) { ctx.NotFound("ProjectBoardNotExist", nil) @@ -622,7 +622,7 @@ func MoveIssues(ctx *context.Context) { issueIDs = append(issueIDs, issue.IssueID) sortedIssueIDs[issue.Sorting] = issue.IssueID } - movedIssues, err := models.GetIssuesByIDs(issueIDs) + movedIssues, err := models.GetIssuesByIDs(ctx, issueIDs) if err != nil { if models.IsErrIssueNotExist(err) { ctx.NotFound("IssueNotExisting", nil) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 27b61309a5..8df4ccc607 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -70,7 +71,7 @@ func getRepository(ctx *context.Context, repoID int64) *repo_model.Repository { return nil } - perm, err := models.GetUserRepoPermission(ctx, repo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, repo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return nil @@ -376,7 +377,7 @@ func PrepareMergedViewPullInfo(ctx *context.Context, issue *models.Issue) *git.C if len(compareInfo.Commits) != 0 { sha := compareInfo.Commits[0].ID.String() - commitStatuses, _, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, sha, db.ListOptions{}) + commitStatuses, _, err := models.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, sha, db.ListOptions{}) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -437,7 +438,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare ctx.ServerError(fmt.Sprintf("GetRefCommitID(%s)", pull.GetGitRefName()), err) return nil } - commitStatuses, _, err := models.GetLatestCommitStatus(repo.ID, sha, db.ListOptions{}) + commitStatuses, _, err := models.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{}) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -527,7 +528,7 @@ func PrepareViewPullInfo(ctx *context.Context, issue *models.Issue) *git.Compare return nil } - commitStatuses, _, err := models.GetLatestCommitStatus(repo.ID, sha, db.ListOptions{}) + commitStatuses, _, err := models.GetLatestCommitStatus(ctx, repo.ID, sha, db.ListOptions{}) if err != nil { ctx.ServerError("GetLatestCommitStatus", err) return nil @@ -757,7 +758,7 @@ func ViewPullFiles(ctx *context.Context) { setCompareContext(ctx, baseCommit, commit, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name) ctx.Data["RequireTribute"] = true - if ctx.Data["Assignees"], err = models.GetRepoAssignees(ctx.Repo.Repository); err != nil { + if ctx.Data["Assignees"], err = repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository); err != nil { ctx.ServerError("GetAssignees", err) return } @@ -766,7 +767,7 @@ func ViewPullFiles(ctx *context.Context) { return } - currentReview, err := models.GetCurrentReview(ctx.Doer, issue) + currentReview, err := models.GetCurrentReview(ctx, ctx.Doer, issue) if err != nil && !models.IsErrReviewNotExist(err) { ctx.ServerError("GetCurrentReview", err) return @@ -1247,7 +1248,7 @@ func CleanUpPullRequest(ctx *context.Context) { return } - perm, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -1353,7 +1354,7 @@ func DownloadPullPatch(ctx *context.Context) { // DownloadPullDiffOrPatch render a pull's raw diff or patch func DownloadPullDiffOrPatch(ctx *context.Context, patch bool) { - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) @@ -1446,7 +1447,7 @@ func UpdatePullRequestTarget(ctx *context.Context) { func SetAllowEdits(ctx *context.Context) { form := web.GetForm(ctx).(*forms.UpdateAllowEditsForm) - pr, err := models.GetPullRequestByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + pr, err := models.GetPullRequestByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if models.IsErrPullRequestNotExist(err) { ctx.NotFound("GetPullRequestByIndex", err) diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index 98272ed48d..e051290200 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -31,7 +31,7 @@ func RenderNewCodeCommentForm(ctx *context.Context) { if !issue.IsPull { return } - currentReview, err := models.GetCurrentReview(ctx.Doer, issue) + currentReview, err := models.GetCurrentReview(ctx, ctx.Doer, issue) if err != nil && !models.IsErrReviewNotExist(err) { ctx.ServerError("GetCurrentReview", err) return @@ -107,7 +107,7 @@ func UpdateResolveConversation(ctx *context.Context) { action := ctx.FormString("action") commentID := ctx.FormInt64("comment_id") - comment, err := models.GetCommentByID(commentID) + comment, err := models.GetCommentByID(ctx, commentID) if err != nil { ctx.ServerError("GetIssueByID", err) return diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go index 5f894ae501..fba3ef7a06 100644 --- a/routers/web/repo/release.go +++ b/routers/web/repo/release.go @@ -126,7 +126,7 @@ func releasesOrTags(ctx *context.Context, isTagList bool) { return } - if err = models.GetReleaseAttachments(releases...); err != nil { + if err = models.GetReleaseAttachments(ctx, releases...); err != nil { ctx.ServerError("GetReleaseAttachments", err) return } @@ -202,7 +202,7 @@ func SingleRelease(ctx *context.Context) { return } - err = models.GetReleaseAttachments(release) + err = models.GetReleaseAttachments(ctx, release) if err != nil { ctx.ServerError("GetReleaseAttachments", err) return @@ -279,7 +279,9 @@ func NewRelease(ctx *context.Context) { } ctx.Data["tag_name"] = rel.TagName - ctx.Data["tag_target"] = rel.Target + if rel.Target != "" { + ctx.Data["tag_target"] = rel.Target + } ctx.Data["title"] = rel.Title ctx.Data["content"] = rel.Note ctx.Data["attachments"] = rel.Attachments diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 199651b2f1..c2c79e4a0d 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -152,7 +152,7 @@ func Create(ctx *context.Context) { templateID := ctx.FormInt64("template_id") if templateID > 0 { templateRepo, err := repo_model.GetRepositoryByID(templateID) - if err == nil && models.CheckRepoUnitUser(templateRepo, ctxUser, unit.TypeCode) { + if err == nil && models.CheckRepoUnitUser(ctx, templateRepo, ctxUser, unit.TypeCode) { ctx.Data["repo_template"] = templateID ctx.Data["repo_template_name"] = templateRepo.Name } @@ -223,7 +223,7 @@ func CreatePost(ctx *context.Context) { var repo *repo_model.Repository var err error if form.RepoTemplate > 0 { - opts := models.GenerateRepoOptions{ + opts := repo_module.GenerateRepoOptions{ Name: form.RepoName, Description: form.Description, Private: form.Private, @@ -285,9 +285,9 @@ func Action(ctx *context.Context) { var err error switch ctx.Params(":action") { case "watch": - err = repo_model.WatchRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true) + err = repo_model.WatchRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, true) case "unwatch": - err = repo_model.WatchRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, false) + err = repo_model.WatchRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID, false) case "star": err = repo_model.StarRepo(ctx.Doer.ID, ctx.Repo.Repository.ID, true) case "unstar": @@ -304,7 +304,7 @@ func Action(ctx *context.Context) { ctx.Repo.Repository.Description = ctx.FormString("desc") ctx.Repo.Repository.Website = ctx.FormString("site") - err = models.UpdateRepository(ctx.Repo.Repository, false) + err = repo_service.UpdateRepository(ctx.Repo.Repository, false) } if err != nil { @@ -369,7 +369,7 @@ func RedirectDownload(ctx *context.Context) { } if len(releases) == 1 { release := releases[0] - att, err := repo_model.GetAttachmentByReleaseIDFileName(release.ID, fileName) + att, err := repo_model.GetAttachmentByReleaseIDFileName(ctx, release.ID, fileName) if err != nil { ctx.Error(http.StatusNotFound) return @@ -509,7 +509,7 @@ func InitiateDownload(ctx *context.Context) { // SearchRepo repositories via options func SearchRepo(ctx *context.Context) { - opts := &models.SearchRepoOptions{ + opts := &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ Page: ctx.FormInt("page"), PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), @@ -581,7 +581,7 @@ func SearchRepo(ctx *context.Context) { } var err error - repos, count, err := models.SearchRepository(opts) + repos, count, err := repo_model.SearchRepository(opts) if err != nil { ctx.JSON(http.StatusInternalServerError, api.SearchError{ OK: false, diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go index ccb603833c..1a7a41ae91 100644 --- a/routers/web/repo/setting.go +++ b/routers/web/repo/setting.go @@ -65,21 +65,23 @@ func Settings(ctx *context.Context) { ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval + ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath()) ctx.Data["SigningKeyAvailable"] = len(signing) > 0 ctx.Data["SigningSettings"] = setting.Repository.Signing ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + if ctx.Doer.IsAdmin { if setting.Indexer.RepoIndexerEnabled { - status, err := repo_model.GetIndexerStatus(ctx.Repo.Repository, repo_model.RepoIndexerTypeCode) + status, err := repo_model.GetIndexerStatus(ctx, ctx.Repo.Repository, repo_model.RepoIndexerTypeCode) if err != nil { ctx.ServerError("repo.indexer_status", err) return } ctx.Data["CodeIndexerStatus"] = status } - status, err := repo_model.GetIndexerStatus(ctx.Repo.Repository, repo_model.RepoIndexerTypeStats) + status, err := repo_model.GetIndexerStatus(ctx, ctx.Repo.Repository, repo_model.RepoIndexerTypeStats) if err != nil { ctx.ServerError("repo.indexer_status", err) return @@ -102,6 +104,17 @@ func SettingsPost(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsOptions"] = true + ctx.Data["ForcePrivate"] = setting.Repository.ForcePrivate + ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled + ctx.Data["DisableNewPushMirrors"] = setting.Mirror.DisableNewPush + ctx.Data["DefaultMirrorInterval"] = setting.Mirror.DefaultInterval + ctx.Data["MinimumMirrorInterval"] = setting.Mirror.MinInterval + + signing, _ := asymkey_service.SigningKey(ctx, ctx.Repo.Repository.RepoPath()) + ctx.Data["SigningKeyAvailable"] = len(signing) > 0 + ctx.Data["SigningSettings"] = setting.Repository.Signing + ctx.Data["CodeIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled + repo := ctx.Repo.Repository switch ctx.FormString("action") { @@ -168,7 +181,7 @@ func SettingsPost(ctx *context.Context) { } repo.IsPrivate = form.Private - if err := models.UpdateRepository(repo, visibilityChanged); err != nil { + if err := repo_service.UpdateRepository(repo, visibilityChanged); err != nil { ctx.ServerError("UpdateRepository", err) return } @@ -191,15 +204,15 @@ func SettingsPost(ctx *context.Context) { if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) { ctx.Data["Err_Interval"] = true ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form) - } else { - ctx.Repo.Mirror.EnablePrune = form.EnablePrune - ctx.Repo.Mirror.Interval = interval - ctx.Repo.Mirror.ScheduleNextUpdate() - if err := repo_model.UpdateMirror(ctx.Repo.Mirror); err != nil { - ctx.Data["Err_Interval"] = true - ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form) - return - } + return + } + + ctx.Repo.Mirror.EnablePrune = form.EnablePrune + ctx.Repo.Mirror.Interval = interval + ctx.Repo.Mirror.ScheduleNextUpdate() + if err := repo_model.UpdateMirror(ctx, ctx.Repo.Mirror); err != nil { + ctx.ServerError("UpdateMirror", err) + return } u, _ := git.GetRemoteAddress(ctx, ctx.Repo.Repository.RepoPath(), ctx.Repo.Mirror.GetRemoteName()) @@ -241,7 +254,7 @@ func SettingsPost(ctx *context.Context) { ctx.Repo.Mirror.LFS = form.LFS ctx.Repo.Mirror.LFSEndpoint = form.LFSEndpoint - if err := repo_model.UpdateMirror(ctx.Repo.Mirror); err != nil { + if err := repo_model.UpdateMirror(ctx, ctx.Repo.Mirror); err != nil { ctx.ServerError("UpdateMirror", err) return } @@ -491,7 +504,7 @@ func SettingsPost(ctx *context.Context) { return } if repoChanged { - if err := models.UpdateRepository(repo, false); err != nil { + if err := repo_service.UpdateRepository(repo, false); err != nil { ctx.ServerError("UpdateRepository", err) return } @@ -510,7 +523,7 @@ func SettingsPost(ctx *context.Context) { } if changed { - if err := models.UpdateRepository(repo, false); err != nil { + if err := repo_service.UpdateRepository(repo, false); err != nil { ctx.ServerError("UpdateRepository", err) return } @@ -530,7 +543,7 @@ func SettingsPost(ctx *context.Context) { repo.IsFsckEnabled = form.EnableHealthCheck } - if err := models.UpdateRepository(repo, false); err != nil { + if err := repo_service.UpdateRepository(repo, false); err != nil { ctx.ServerError("UpdateRepository", err) return } @@ -642,7 +655,7 @@ func SettingsPost(ctx *context.Context) { return } - newOwner, err := user_model.GetUserByName(ctx.FormString("new_owner_name")) + newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name")) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) @@ -833,14 +846,14 @@ func Collaboration(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("repo.settings") ctx.Data["PageIsSettingsCollaboration"] = true - users, err := models.GetCollaborators(ctx.Repo.Repository.ID, db.ListOptions{}) + users, err := repo_model.GetCollaborators(ctx, ctx.Repo.Repository.ID, db.ListOptions{}) if err != nil { ctx.ServerError("GetCollaborators", err) return } ctx.Data["Collaborators"] = users - teams, err := organization.GetRepoTeams(ctx.Repo.Repository) + teams, err := organization.GetRepoTeams(ctx, ctx.Repo.Repository) if err != nil { ctx.ServerError("GetRepoTeams", err) return @@ -863,7 +876,7 @@ func CollaborationPost(ctx *context.Context) { return } - u, err := user_model.GetUserByName(name) + u, err := user_model.GetUserByName(ctx, name) if err != nil { if user_model.IsErrUserNotExist(err) { ctx.Flash.Error(ctx.Tr("form.user_not_exist")) @@ -887,7 +900,7 @@ func CollaborationPost(ctx *context.Context) { return } - if got, err := models.IsCollaborator(ctx.Repo.Repository.ID, u.ID); err == nil && got { + if got, err := repo_model.IsCollaborator(ctx, ctx.Repo.Repository.ID, u.ID); err == nil && got { ctx.Flash.Error(ctx.Tr("repo.settings.add_collaborator_duplicate")) ctx.Redirect(ctx.Repo.RepoLink + "/settings/collaboration") return @@ -908,7 +921,7 @@ func CollaborationPost(ctx *context.Context) { // ChangeCollaborationAccessMode response for changing access of a collaboration func ChangeCollaborationAccessMode(ctx *context.Context) { - if err := models.ChangeCollaborationAccessMode( + if err := repo_model.ChangeCollaborationAccessMode( ctx.Repo.Repository, ctx.FormInt64("uid"), perm.AccessMode(ctx.FormInt("mode"))); err != nil { @@ -983,7 +996,7 @@ func DeleteTeam(ctx *context.Context) { return } - team, err := organization.GetTeamByID(ctx.FormInt64("id")) + team, err := organization.GetTeamByID(ctx, ctx.FormInt64("id")) if err != nil { ctx.ServerError("GetTeamByID", err) return @@ -1215,6 +1228,7 @@ func selectPushMirrorByForm(form *forms.RepoSettingForm, repo *repo_model.Reposi for _, m := range pushMirrors { if m.ID == id { + m.Repo = repo return m, nil } } diff --git a/routers/web/repo/setting_protected_branch.go b/routers/web/repo/setting_protected_branch.go index 1f6e2316e7..6c2f3ce01d 100644 --- a/routers/web/repo/setting_protected_branch.go +++ b/routers/web/repo/setting_protected_branch.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" @@ -110,7 +111,7 @@ func SettingsProtectedBranch(c *context.Context) { c.Data["Title"] = c.Tr("repo.settings.protected_branch") + " - " + branch c.Data["PageIsSettingsBranches"] = true - protectBranch, err := models.GetProtectedBranchBy(c.Repo.Repository.ID, branch) + protectBranch, err := models.GetProtectedBranchBy(c, c.Repo.Repository.ID, branch) if err != nil { if !git.IsErrBranchNotExist(err) { c.ServerError("GetProtectBranchOfRepoByName", err) @@ -125,7 +126,7 @@ func SettingsProtectedBranch(c *context.Context) { } } - users, err := models.GetRepoReaders(c.Repo.Repository) + users, err := access_model.GetRepoReaders(c.Repo.Repository) if err != nil { c.ServerError("Repo.Repository.GetReaders", err) return @@ -183,7 +184,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) { return } - protectBranch, err := models.GetProtectedBranchBy(ctx.Repo.Repository.ID, branch) + protectBranch, err := models.GetProtectedBranchBy(ctx, ctx.Repo.Repository.ID, branch) if err != nil { if !git.IsErrBranchNotExist(err) { ctx.ServerError("GetProtectBranchOfRepoByName", err) diff --git a/routers/web/repo/settings_test.go b/routers/web/repo/settings_test.go index 36d02de273..946220b4fc 100644 --- a/routers/web/repo/settings_test.go +++ b/routers/web/repo/settings_test.go @@ -130,7 +130,7 @@ func TestCollaborationPost(t *testing.T) { assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) - exists, err := models.IsCollaborator(re.ID, 4) + exists, err := repo_model.IsCollaborator(ctx, re.ID, 4) assert.NoError(t, err) assert.True(t, exists) } @@ -188,7 +188,7 @@ func TestCollaborationPost_AddCollaboratorTwice(t *testing.T) { assert.EqualValues(t, http.StatusSeeOther, ctx.Resp.Status()) - exists, err := models.IsCollaborator(re.ID, 4) + exists, err := repo_model.IsCollaborator(ctx, re.ID, 4) assert.NoError(t, err) assert.True(t, exists) diff --git a/routers/web/repo/tag.go b/routers/web/repo/tag.go index 7da1e36c81..3c47a0604f 100644 --- a/routers/web/repo/tag.go +++ b/routers/web/repo/tag.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" @@ -143,7 +144,7 @@ func setTagsContext(ctx *context.Context) error { } ctx.Data["ProtectedTags"] = protectedTags - users, err := models.GetRepoReaders(ctx.Repo.Repository) + users, err := access_model.GetRepoReaders(ctx.Repo.Repository) if err != nil { ctx.ServerError("Repo.Repository.GetReaders", err) return err diff --git a/routers/web/repo/treelist.go b/routers/web/repo/treelist.go new file mode 100644 index 0000000000..35ac0d507f --- /dev/null +++ b/routers/web/repo/treelist.go @@ -0,0 +1,55 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repo + +import ( + "net/http" + + "code.gitea.io/gitea/modules/base" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/git" + + "github.com/go-enry/go-enry/v2" +) + +// TreeList get all files' entries of a repository +func TreeList(ctx *context.Context) { + tree, err := ctx.Repo.Commit.SubTree("/") + if err != nil { + ctx.ServerError("Repo.Commit.SubTree", err) + return + } + + entries, err := tree.ListEntriesRecursive() + if err != nil { + ctx.ServerError("ListEntriesRecursive", err) + return + } + entries.CustomSort(base.NaturalSortLess) + + files := make([]string, 0, len(entries)) + for _, entry := range entries { + if !isExcludedEntry(entry) { + files = append(files, entry.Name()) + } + } + ctx.JSON(http.StatusOK, files) +} + +func isExcludedEntry(entry *git.TreeEntry) bool { + if entry.IsDir() { + return true + } + + if entry.IsSubModule() { + return true + } + + if enry.IsVendor(entry.Name()) { + return true + } + + return false +} diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index 86fc36fad7..48565cb62b 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -34,6 +34,7 @@ import ( "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/typesniffer" @@ -508,6 +509,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["ReadmeExist"] = readmeExist markupType := markup.Type(blob.Name()) + // If the markup is detected by custom markup renderer it should not be reset later on + // to not pass it down to the render context. + detected := false + if markupType == "" { + detected = true + markupType = markup.DetectRendererType(blob.Name(), bytes.NewReader(buf)) + } if markupType != "" { ctx.Data["HasSourceRenderedToggle"] = true } @@ -516,8 +524,12 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st ctx.Data["IsMarkup"] = true ctx.Data["MarkupType"] = markupType var result strings.Builder + if !detected { + markupType = "" + } err := markup.Render(&markup.RenderContext{ Ctx: ctx, + Type: markupType, Filename: blob.Name(), URLPrefix: path.Dir(treeLink), Metas: ctx.Repo.Repository.ComposeDocumentMetas(), @@ -684,7 +696,7 @@ func checkHomeCodeViewable(ctx *context.Context) { if ctx.IsSigned { // Set repo notification-status read if unread - if err := models.SetRepoReadBy(ctx.Repo.Repository.ID, ctx.Doer.ID); err != nil { + if err := models.SetRepoReadBy(ctx, ctx.Repo.Repository.ID, ctx.Doer.ID); err != nil { ctx.ServerError("ReadBy", err) return } @@ -839,7 +851,7 @@ func renderDirectoryFiles(ctx *context.Context, timeout time.Duration) git.Entri ctx.Data["LatestCommitUser"] = user_model.ValidateCommitWithEmail(latestCommit) } - statuses, _, err := models.GetLatestCommitStatus(ctx.Repo.Repository.ID, ctx.Repo.Commit.ID.String(), db.ListOptions{}) + statuses, _, err := models.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, ctx.Repo.Commit.ID.String(), db.ListOptions{}) if err != nil { log.Error("GetLatestCommitStatus: %v", err) } @@ -901,11 +913,11 @@ func renderCode(ctx *context.Context) { // it's possible for a repository to be non-empty by that flag but still 500 // because there are no branches - only tags -or the default branch is non-extant as it has been 0-pushed. ctx.Repo.Repository.IsEmpty = false - if err = repo_model.UpdateRepositoryCols(ctx.Repo.Repository, "is_empty"); err != nil { + if err = repo_model.UpdateRepositoryCols(ctx, ctx.Repo.Repository, "is_empty"); err != nil { ctx.ServerError("UpdateRepositoryCols", err) return } - if err = models.UpdateRepoSize(ctx, ctx.Repo.Repository); err != nil { + if err = repo_module.UpdateRepoSize(ctx, ctx.Repo.Repository); err != nil { ctx.ServerError("UpdateRepoSize", err) return } diff --git a/routers/web/repo/webhook.go b/routers/web/repo/webhook.go index d2e2461189..a9b14ee21f 100644 --- a/routers/web/repo/webhook.go +++ b/routers/web/repo/webhook.go @@ -44,7 +44,7 @@ func Webhooks(ctx *context.Context) { ctx.Data["BaseLinkNew"] = ctx.Repo.RepoLink + "/settings/hooks" ctx.Data["Description"] = ctx.Tr("repo.settings.hooks_desc", "https://docs.gitea.io/en-us/webhooks/") - ws, err := webhook.ListWebhooksByOpts(&webhook.ListWebhookOptions{RepoID: ctx.Repo.Repository.ID}) + ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{RepoID: ctx.Repo.Repository.ID}) if err != nil { ctx.ServerError("GetWebhooksByRepoID", err) return diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go index 77f60a1dfa..f4aabbf480 100644 --- a/routers/web/repo/wiki.go +++ b/routers/web/repo/wiki.go @@ -280,6 +280,8 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) { ctx.Data["footerPresent"] = false } + ctx.Data["toc"] = rctx.TableOfContents + // get commit count - wiki revisions commitsCount, _ := wikiRepo.FileCommitsCount("master", pageFilename) ctx.Data["CommitCount"] = commitsCount diff --git a/routers/web/user/avatar.go b/routers/web/user/avatar.go index c8bca9dc2c..53a603fab0 100644 --- a/routers/web/user/avatar.go +++ b/routers/web/user/avatar.go @@ -30,7 +30,7 @@ func AvatarByUserName(ctx *context.Context) { var user *user_model.User if strings.ToLower(userName) != "ghost" { var err error - if user, err = user_model.GetUserByName(userName); err != nil { + if user, err = user_model.GetUserByName(ctx, userName); err != nil { ctx.ServerError("Invalid user: "+userName, err) return } diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 2e7b382de6..9b4fc652f1 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -78,6 +78,7 @@ func Dashboard(ctx *context.Context) { ctx.Data["PageIsNews"] = true cnt, _ := organization.GetOrganizationCount(ctx, ctxUser) ctx.Data["UserOrgsCount"] = cnt + ctx.Data["MirrorsEnabled"] = setting.Mirror.Enabled var uid int64 if ctxUser != nil { @@ -165,12 +166,13 @@ func Milestones(ctx *context.Context) { return } - repoOpts := models.SearchRepoOptions{ + repoOpts := repo_model.SearchRepoOptions{ Actor: ctxUser, OwnerID: ctxUser.ID, Private: true, - AllPublic: false, // Include also all public repositories of users and public organisations - AllLimited: false, // Include also all public repositories of limited organisations + AllPublic: false, // Include also all public repositories of users and public organisations + AllLimited: false, // Include also all public repositories of limited organisations + Archived: util.OptionalBoolFalse, HasMilestones: util.OptionalBoolTrue, // Just needs display repos has milestones } @@ -179,7 +181,7 @@ func Milestones(ctx *context.Context) { } var ( - userRepoCond = models.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit + userRepoCond = repo_model.SearchRepositoryCondition(&repoOpts) // all repo condition user could visit repoCond = userRepoCond repoIDs []int64 @@ -232,7 +234,7 @@ func Milestones(ctx *context.Context) { return } - showRepos, _, err := models.SearchRepositoryByCondition(&repoOpts, userRepoCond, false) + showRepos, _, err := repo_model.SearchRepositoryByCondition(&repoOpts, userRepoCond, false) if err != nil { ctx.ServerError("SearchRepositoryByCondition", err) return @@ -435,7 +437,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { // As team: // - Team org's owns the repository. // - Team has read permission to repository. - repoOpts := &models.SearchRepoOptions{ + repoOpts := &repo_model.SearchRepoOptions{ Actor: ctx.Doer, OwnerID: ctx.Doer.ID, Private: true, @@ -443,12 +445,13 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { AllLimited: false, } - if ctxUser.IsOrganization() && ctx.Org.Team != nil { - repoOpts.TeamID = ctx.Org.Team.ID + if team != nil { + repoOpts.TeamID = team.ID } switch filterMode { case models.FilterModeAll: + case models.FilterModeYourRepositories: case models.FilterModeAssign: opts.AssigneeID = ctx.Doer.ID case models.FilterModeCreate: @@ -457,13 +460,6 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { opts.MentionedID = ctx.Doer.ID case models.FilterModeReviewRequested: opts.ReviewRequestedID = ctx.Doer.ID - case models.FilterModeYourRepositories: - if ctxUser.IsOrganization() && ctx.Org.Team != nil { - // Fixes a issue whereby the user's ID would be used - // to check if it's in the team(which possible isn't the case). - opts.User = nil - } - opts.RepoCond = models.SearchRepositoryCondition(repoOpts) } // keyword holds the search term entered into the search field. @@ -563,7 +559,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { } // a RepositoryList - showRepos := models.RepositoryListOfMap(showReposMap) + showRepos := repo_model.RepositoryListOfMap(showReposMap) sort.Sort(showRepos) // maps pull request IDs to their CommitStatus. Will be posted to ctx.Data. @@ -595,13 +591,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { Org: org, Team: team, } - if filterMode == models.FilterModeYourRepositories { - statsOpts.RepoCond = models.SearchRepositoryCondition(repoOpts) - } - // Detect when we only should search by team. - if opts.User == nil { - statsOpts.UserID = 0 - } + issueStats, err = models.GetUserIssueStats(statsOpts) if err != nil { ctx.ServerError("GetUserIssueStats Shown", err) @@ -620,6 +610,12 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { shownIssues = int(issueStats.ClosedCount) ctx.Data["TotalIssueCount"] = shownIssues } + if len(repoIDs) != 0 { + shownIssues = 0 + for _, repoID := range repoIDs { + shownIssues += int(issueCountByRepo[repoID]) + } + } ctx.Data["IsShowClosed"] = isShowClosed @@ -627,7 +623,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { ctx.Data["Issues"] = issues - approvalCounts, err := models.IssueList(issues).GetApprovalCounts() + approvalCounts, err := models.IssueList(issues).GetApprovalCounts(ctx) if err != nil { ctx.ServerError("ApprovalCounts", err) return diff --git a/routers/web/user/home_test.go b/routers/web/user/home_test.go index bf78e00ada..9ad0711dc0 100644 --- a/routers/web/user/home_test.go +++ b/routers/web/user/home_test.go @@ -8,7 +8,7 @@ import ( "net/http" "testing" - "code.gitea.io/gitea/models" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/test" @@ -26,7 +26,7 @@ func TestArchivedIssues(t *testing.T) { ctx.Req.Form.Set("state", "open") // Assume: User 30 has access to two Repos with Issues, one of the Repos being archived. - repos, _, _ := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctx.Doer}) + repos, _, _ := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{Actor: ctx.Doer}) assert.Len(t, repos, 2) IsArchived := make(map[int64]bool) NumIssues := make(map[int64]int) diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 05421cf555..9e658bcb14 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -5,6 +5,7 @@ package user import ( + goctx "context" "errors" "fmt" "net/http" @@ -14,6 +15,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" ) @@ -34,9 +36,11 @@ func GetNotificationCount(c *context.Context) { } c.Data["NotificationUnreadCount"] = func() int64 { - count, err := models.GetNotificationCount(c.Doer, models.NotificationStatusUnread) + count, err := models.GetNotificationCount(c, c.Doer, models.NotificationStatusUnread) if err != nil { - c.ServerError("GetNotificationCount", err) + if err != goctx.Canceled { + log.Error("Unable to GetNotificationCount for user:%-v: %v", c.Doer, err) + } return -1 } @@ -79,7 +83,7 @@ func getNotifications(c *context.Context) { status = models.NotificationStatusUnread } - total, err := models.GetNotificationCount(c.Doer, status) + total, err := models.GetNotificationCount(c, c.Doer, status) if err != nil { c.ServerError("ErrGetNotificationCount", err) return @@ -93,7 +97,7 @@ func getNotifications(c *context.Context) { } statuses := []models.NotificationStatus{status, models.NotificationStatusPinned} - notifications, err := models.NotificationsForUser(c.Doer, statuses, page, perPage) + notifications, err := models.NotificationsForUser(c, c.Doer, statuses, page, perPage) if err != nil { c.ServerError("ErrNotificationsForUser", err) return @@ -195,5 +199,5 @@ func NotificationPurgePost(c *context.Context) { // NewAvailable returns the notification counts func NewAvailable(ctx *context.Context) { - ctx.JSON(http.StatusOK, structs.NotificationCount{New: models.CountUnread(ctx.Doer)}) + ctx.JSON(http.StatusOK, structs.NotificationCount{New: models.CountUnread(ctx, ctx.Doer.ID)}) } diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 1c33998db9..b2b550cb73 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -7,11 +7,11 @@ package user import ( "net/http" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" container_model "code.gitea.io/gitea/models/packages/container" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" @@ -67,7 +67,7 @@ func ListPackages(ctx *context.Context) { continue } - permission, err := models.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer) + permission, err := access_model.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -177,7 +177,7 @@ func ViewPackageVersion(ctx *context.Context) { hasRepositoryAccess := false if pd.Repository != nil { - permission, err := models.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer) + permission, err := access_model.GetUserRepoPermission(ctx, pd.Repository, ctx.Doer) if err != nil { ctx.ServerError("GetUserRepoPermission", err) return @@ -287,7 +287,7 @@ func PackageSettings(ctx *context.Context) { ctx.Data["ContextUser"] = ctx.ContextUser ctx.Data["PackageDescriptor"] = pd - repos, _, _ := models.GetUserRepositories(&models.SearchRepoOptions{ + repos, _, _ := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{ Actor: pd.Owner, Private: true, }) diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 85870eddf5..44501fc245 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -42,7 +42,7 @@ func Profile(ctx *context.Context) { } // check view permissions - if !user_model.IsUserVisibleToViewer(ctx.ContextUser, ctx.Doer) { + if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name)) return } @@ -195,7 +195,7 @@ func Profile(ctx *context.Context) { } case "stars": ctx.Data["PageIsProfileStarList"] = true - repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, @@ -217,7 +217,7 @@ func Profile(ctx *context.Context) { total = int(count) case "projects": - ctx.Data["OpenProjects"], _, err = project_model.GetProjects(project_model.SearchOptions{ + ctx.Data["OpenProjects"], _, err = project_model.GetProjects(ctx, project_model.SearchOptions{ Page: -1, IsClosed: util.OptionalBoolFalse, Type: project_model.TypeIndividual, @@ -227,7 +227,7 @@ func Profile(ctx *context.Context) { return } case "watching": - repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, @@ -249,7 +249,7 @@ func Profile(ctx *context.Context) { total = int(count) default: - repos, count, err = models.SearchRepository(&models.SearchRepoOptions{ + repos, count, err = repo_model.SearchRepository(&repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: setting.UI.User.RepoPagingNum, Page: page, diff --git a/routers/web/user/setting/account.go b/routers/web/user/setting/account.go index b2476dff94..3e96cc7c85 100644 --- a/routers/web/user/setting/account.go +++ b/routers/web/user/setting/account.go @@ -105,7 +105,7 @@ func EmailPost(ctx *context.Context) { // Send activation Email if ctx.FormString("_method") == "SENDACTIVATION" { var address string - if ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) { + if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) { log.Error("Send activation: activation still pending") ctx.Redirect(setting.AppSubURL + "/user/settings/account") return @@ -141,8 +141,10 @@ func EmailPost(ctx *context.Context) { } address = email.Email - if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()))) ctx.Redirect(setting.AppSubURL + "/user/settings/account") @@ -181,7 +183,7 @@ func EmailPost(ctx *context.Context) { Email: form.Email, IsActivated: !setting.Service.RegisterEmailConfirm, } - if err := user_model.AddEmailAddress(email); err != nil { + if err := user_model.AddEmailAddress(ctx, email); err != nil { if user_model.IsErrEmailAlreadyUsed(err) { loadAccountData(ctx) @@ -201,8 +203,10 @@ func EmailPost(ctx *context.Context) { // Send confirmation email if setting.Service.RegisterEmailConfirm { mailer.SendActivateEmailMail(ctx.Doer, email) - if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { - log.Error("Set cache(MailResendLimit) fail: %v", err) + if setting.CacheService.Enabled { + if err := ctx.Cache.Put("MailResendLimit_"+ctx.Doer.LowerName, ctx.Doer.LowerName, 180); err != nil { + log.Error("Set cache(MailResendLimit) fail: %v", err) + } } ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language()))) } else { @@ -273,7 +277,7 @@ func loadAccountData(ctx *context.Context) { user_model.EmailAddress CanBePrimary bool } - pendingActivation := ctx.Cache.IsExist("MailResendLimit_" + ctx.Doer.LowerName) + pendingActivation := setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) emails := make([]*UserEmail, len(emlist)) for i, em := range emlist { var email UserEmail diff --git a/routers/web/user/setting/adopt.go b/routers/web/user/setting/adopt.go index ce2377a997..c7139f8bb1 100644 --- a/routers/web/user/setting/adopt.go +++ b/routers/web/user/setting/adopt.go @@ -32,7 +32,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) { root := user_model.UserPath(ctxUser.LowerName) // check not a repo - has, err := repo_model.IsRepositoryExist(ctxUser, dir) + has, err := repo_model.IsRepositoryExist(ctx, ctxUser, dir) if err != nil { ctx.ServerError("IsRepositoryExist", err) return diff --git a/routers/web/user/setting/applications.go b/routers/web/user/setting/applications.go index b0f599fc45..4ffec47801 100644 --- a/routers/web/user/setting/applications.go +++ b/routers/web/user/setting/applications.go @@ -93,12 +93,12 @@ func loadApplicationsData(ctx *context.Context) { ctx.Data["Tokens"] = tokens ctx.Data["EnableOAuth2"] = setting.OAuth2.Enable if setting.OAuth2.Enable { - ctx.Data["Applications"], err = auth.GetOAuth2ApplicationsByUserID(ctx.Doer.ID) + ctx.Data["Applications"], err = auth.GetOAuth2ApplicationsByUserID(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetOAuth2ApplicationsByUserID", err) return } - ctx.Data["Grants"], err = auth.GetOAuth2GrantsByUserID(ctx.Doer.ID) + ctx.Data["Grants"], err = auth.GetOAuth2GrantsByUserID(ctx, ctx.Doer.ID) if err != nil { ctx.ServerError("GetOAuth2GrantsByUserID", err) return diff --git a/routers/web/user/setting/oauth2.go b/routers/web/user/setting/oauth2.go index 76c50852a0..db76a12f18 100644 --- a/routers/web/user/setting/oauth2.go +++ b/routers/web/user/setting/oauth2.go @@ -34,7 +34,7 @@ func OAuthApplicationsPost(ctx *context.Context) { return } // TODO validate redirect URI - app, err := auth.CreateOAuth2Application(auth.CreateOAuth2ApplicationOptions{ + app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{ Name: form.Name, RedirectURIs: []string{form.RedirectURI}, UserID: ctx.Doer.ID, @@ -85,7 +85,7 @@ func OAuthApplicationsRegenerateSecret(ctx *context.Context) { ctx.Data["Title"] = ctx.Tr("settings") ctx.Data["PageIsSettingsApplications"] = true - app, err := auth.GetOAuth2ApplicationByID(ctx.ParamsInt64("id")) + app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id")) if err != nil { if auth.IsErrOAuthApplicationNotFound(err) { ctx.NotFound("Application not found", err) @@ -110,7 +110,7 @@ func OAuthApplicationsRegenerateSecret(ctx *context.Context) { // OAuth2ApplicationShow displays the given application func OAuth2ApplicationShow(ctx *context.Context) { - app, err := auth.GetOAuth2ApplicationByID(ctx.ParamsInt64("id")) + app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id")) if err != nil { if auth.IsErrOAuthApplicationNotFound(err) { ctx.NotFound("Application not found", err) @@ -147,7 +147,7 @@ func RevokeOAuth2Grant(ctx *context.Context) { ctx.ServerError("RevokeOAuth2Grant", fmt.Errorf("user id or grant id is zero")) return } - if err := auth.RevokeOAuth2Grant(ctx.FormInt64("id"), ctx.Doer.ID); err != nil { + if err := auth.RevokeOAuth2Grant(ctx, ctx.FormInt64("id"), ctx.Doer.ID); err != nil { ctx.ServerError("RevokeOAuth2Grant", err) return } diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 0123b9b523..972271269f 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -15,7 +15,6 @@ import ( "path/filepath" "strings" - "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" @@ -180,7 +179,7 @@ func UpdateAvatarSetting(ctx *context.Context, form *forms.AvatarForm, ctxUser * } else if ctxUser.UseCustomAvatar && ctxUser.Avatar == "" { // No avatar is uploaded but setting has been changed to enable, // generate a random one when needed. - if err := user_model.GenerateRandomAvatar(ctxUser); err != nil { + if err := user_model.GenerateRandomAvatar(ctx, ctxUser); err != nil { log.Error("GenerateRandomAvatar[%d]: %v", ctxUser.ID, err) } } @@ -304,7 +303,7 @@ func Repos(ctx *context.Context) { return } - userRepos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{ + userRepos, _, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{ Actor: ctxUser, Private: true, ListOptions: db.ListOptions{ @@ -329,7 +328,7 @@ func Repos(ctx *context.Context) { ctx.Data["Dirs"] = repoNames ctx.Data["ReposMap"] = repos } else { - repos, count64, err := models.GetUserRepositories(&models.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts}) + repos, count64, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{Actor: ctxUser, Private: true, ListOptions: opts}) if err != nil { ctx.ServerError("GetUserRepositories", err) return diff --git a/routers/web/user/setting/security/openid.go b/routers/web/user/setting/security/openid.go index 2ecc9b0533..a378c8bf64 100644 --- a/routers/web/user/setting/security/openid.go +++ b/routers/web/user/setting/security/openid.go @@ -90,7 +90,7 @@ func settingsOpenIDVerify(ctx *context.Context) { log.Trace("Verified ID: " + id) oid := &user_model.UserOpenID{UID: ctx.Doer.ID, URI: id} - if err = user_model.AddUserOpenID(oid); err != nil { + if err = user_model.AddUserOpenID(ctx, oid); err != nil { if user_model.IsErrOpenIDAlreadyUsed(err) { ctx.RenderWithErr(ctx.Tr("form.openid_been_used", id), tplSettingsSecurity, &forms.AddOpenIDForm{Openid: id}) return diff --git a/routers/web/user/setting/security/security.go b/routers/web/user/setting/security/security.go index a87012c480..747bf64a17 100644 --- a/routers/web/user/setting/security/security.go +++ b/routers/web/user/setting/security/security.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/auth/source/oauth2" ) const ( @@ -109,6 +110,14 @@ func loadSecurityData(ctx *context.Context) { } ctx.Data["AccountLinks"] = sources + orderedOAuth2Names, oauth2Providers, err := oauth2.GetActiveOAuth2Providers() + if err != nil { + ctx.ServerError("GetActiveOAuth2Providers", err) + return + } + ctx.Data["OrderedOAuth2Names"] = orderedOAuth2Names + ctx.Data["OAuth2Providers"] = oauth2Providers + openid, err := user_model.GetUserOpenIDs(ctx.Doer.ID) if err != nil { ctx.ServerError("GetUserOpenIDs", err) diff --git a/routers/web/web.go b/routers/web/web.go index 97ea1e9035..bf4c4662af 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -344,10 +344,6 @@ func RegisterRoutes(m *web.Route) { }, openIDSignInEnabled) m.Get("/sign_up", auth.SignUp) m.Post("/sign_up", bindIgnErr(forms.RegisterForm{}), auth.SignUpPost) - m.Group("/oauth2", func() { - m.Get("/{provider}", auth.SignInOAuth) - m.Get("/{provider}/callback", auth.SignInOAuthCallback) - }) 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) @@ -452,6 +448,10 @@ func RegisterRoutes(m *web.Route) { m.Get("/task/{task}", reqSignIn, user.TaskStatus) m.Get("/stopwatches", reqSignIn, user.GetStopwatches) m.Get("/search", ignExploreSignIn, user.Search) + m.Group("/oauth2", func() { + m.Get("/{provider}", auth.SignInOAuth) + m.Get("/{provider}/callback", auth.SignInOAuthCallback) + }) }) // ***** END: User ***** @@ -831,10 +831,21 @@ func RegisterRoutes(m *web.Route) { m.Group("/milestone", func() { m.Get("/{id}", repo.MilestoneIssuesAndPulls) }, reqRepoIssuesOrPullsReader, context.RepoRef()) + m.Get("/find/*", repo.FindFiles) + m.Group("/tree-list", func() { + m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.TreeList) + m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.TreeList) + m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.TreeList) + }) 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) + m.Group("/{type:issues|pulls}", func() { + m.Group("/{index}", func() { + m.Get("/info", repo.GetIssueInfo) + }) + }) }, context.RepoAssignment, context.UnitTypes()) // Grouping for those endpoints that do require authentication @@ -851,7 +862,6 @@ func RegisterRoutes(m *web.Route) { // So they can apply their own enable/disable logic on routers. m.Group("/{type:issues|pulls}", func() { m.Group("/{index}", func() { - m.Get("/info", repo.GetIssueInfo) m.Post("/title", repo.UpdateIssueTitle) m.Post("/content", repo.UpdateIssueContent) m.Post("/deadline", bindIgnErr(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline) diff --git a/routers/web/webfinger.go b/routers/web/webfinger.go index 27d0351b81..8402967867 100644 --- a/routers/web/webfinger.go +++ b/routers/web/webfinger.go @@ -59,7 +59,7 @@ func WebfingerQuery(ctx *context.Context) { return } - u, err = user_model.GetUserByNameCtx(ctx, parts[0]) + u, err = user_model.GetUserByName(ctx, parts[0]) case "mailto": u, err = user_model.GetUserByEmailContext(ctx, resource.Opaque) if u != nil && u.KeepEmailPrivate { @@ -79,7 +79,7 @@ func WebfingerQuery(ctx *context.Context) { return } - if !user_model.IsUserVisibleToViewer(u, ctx.Doer) { + if !user_model.IsUserVisibleToViewer(ctx, u, ctx.Doer) { ctx.Error(http.StatusNotFound) return } diff --git a/services/agit/agit.go b/services/agit/agit.go index 2889236181..cc520dbc76 100644 --- a/services/agit/agit.go +++ b/services/agit/agit.go @@ -20,8 +20,8 @@ import ( pull_service "code.gitea.io/gitea/services/pull" ) -// ProcRecive handle proc receive work -func ProcRecive(ctx *context.PrivateContext, opts *private.HookOptions) []private.HookProcReceiveRefResult { +// ProcReceive handle proc receive work +func ProcReceive(ctx *context.PrivateContext, opts *private.HookOptions) []private.HookProcReceiveRefResult { // TODO: Add more options? var ( topicBranch string diff --git a/services/asymkey/sign.go b/services/asymkey/sign.go index 6b17c017fc..2431146f97 100644 --- a/services/asymkey/sign.go +++ b/services/asymkey/sign.go @@ -310,7 +310,7 @@ Loop: return false, "", nil, &ErrWontSign{twofa} } case approved: - protectedBranch, err := models.GetProtectedBranchBy(repo.ID, pr.BaseBranch) + protectedBranch, err := models.GetProtectedBranchBy(ctx, repo.ID, pr.BaseBranch) if err != nil { return false, "", nil, err } diff --git a/services/asymkey/ssh_key.go b/services/asymkey/ssh_key.go index 1f6b93eb24..143c807a10 100644 --- a/services/asymkey/ssh_key.go +++ b/services/asymkey/ssh_key.go @@ -42,7 +42,7 @@ func DeletePublicKey(doer *user_model.User, id int64) (err error) { committer.Close() if key.Type == asymkey_model.KeyTypePrincipal { - return asymkey_model.RewriteAllPrincipalKeys() + return asymkey_model.RewriteAllPrincipalKeys(db.DefaultContext) } return asymkey_model.RewriteAllPublicKeys() diff --git a/services/attachment/attachment_test.go b/services/attachment/attachment_test.go index ffce5943e5..889151d8f3 100644 --- a/services/attachment/attachment_test.go +++ b/services/attachment/attachment_test.go @@ -9,6 +9,7 @@ import ( "path/filepath" "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" @@ -39,7 +40,7 @@ func TestUploadAttachment(t *testing.T) { }, f) assert.NoError(t, err) - attachment, err := repo_model.GetAttachmentByUUID(attach.UUID) + attachment, err := repo_model.GetAttachmentByUUID(db.DefaultContext, attach.UUID) assert.NoError(t, err) assert.EqualValues(t, user.ID, attachment.UploaderID) assert.Equal(t, int64(0), attachment.DownloadCount) diff --git a/services/auth/httpsign.go b/services/auth/httpsign.go new file mode 100644 index 0000000000..67053d2b77 --- /dev/null +++ b/services/auth/httpsign.go @@ -0,0 +1,217 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package auth + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "net/http" + "strings" + + asymkey_model "code.gitea.io/gitea/models/asymkey" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + + "github.com/go-fed/httpsig" + "golang.org/x/crypto/ssh" +) + +// Ensure the struct implements the interface. +var ( + _ Method = &HTTPSign{} + _ Named = &HTTPSign{} +) + +// HTTPSign implements the Auth interface and authenticates requests (API requests +// only) by looking for http signature data in the "Signature" header. +// more information can be found on https://github.com/go-fed/httpsig +type HTTPSign struct{} + +// Name represents the name of auth method +func (h *HTTPSign) Name() string { + return "httpsign" +} + +// 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 { + sigHead := req.Header.Get("Signature") + if len(sigHead) == 0 { + return nil + } + + var ( + publicKey *asymkey_model.PublicKey + err error + ) + + if len(req.Header.Get("X-Ssh-Certificate")) != 0 { + // Handle Signature signed by SSH certificates + if len(setting.SSH.TrustedUserCAKeys) == 0 { + return 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 + } + } else { + // Handle Signature signed by Public Key + publicKey, err = VerifyPubKey(req) + 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 + } + } + + u, err := user_model.GetUserByID(publicKey.OwnerID) + if err != nil { + log.Error("GetUserByID: %v", err) + return nil + } + + store.GetData()["IsApiToken"] = true + + log.Trace("HTTP Sign: Logged in user %-v", u) + + return u +} + +func VerifyPubKey(r *http.Request) (*asymkey_model.PublicKey, error) { + verifier, err := httpsig.NewVerifier(r) + if err != nil { + return nil, fmt.Errorf("httpsig.NewVerifier failed: %s", err) + } + + keyID := verifier.KeyId() + + publicKeys, err := asymkey_model.SearchPublicKey(0, keyID) + if err != nil { + return nil, err + } + + if len(publicKeys) == 0 { + return nil, fmt.Errorf("no public key found for keyid %s", keyID) + } + + sshPublicKey, _, _, _, err := ssh.ParseAuthorizedKey([]byte(publicKeys[0].Content)) + if err != nil { + return nil, err + } + + if err := doVerify(verifier, []ssh.PublicKey{sshPublicKey}); err != nil { + return nil, err + } + + return publicKeys[0], nil +} + +// VerifyCert verifies the validity of the ssh certificate and returns the publickey of the signer +// We verify that the certificate is signed with the correct CA +// We verify that the http request is signed with the private key (of the public key mentioned in the certificate) +func VerifyCert(r *http.Request) (*asymkey_model.PublicKey, error) { + // Get our certificate from the header + bcert, err := base64.RawStdEncoding.DecodeString(r.Header.Get("x-ssh-certificate")) + if err != nil { + return nil, err + } + + pk, err := ssh.ParsePublicKey(bcert) + if err != nil { + return nil, err + } + + // Check if it's really a ssh certificate + cert, ok := pk.(*ssh.Certificate) + if !ok { + return nil, fmt.Errorf("no certificate found") + } + + c := &ssh.CertChecker{ + IsUserAuthority: func(auth ssh.PublicKey) bool { + marshaled := auth.Marshal() + + for _, k := range setting.SSH.TrustedUserCAKeysParsed { + if bytes.Equal(marshaled, k.Marshal()) { + return true + } + } + + return false + }, + } + + // check the CA of the cert + if !c.IsUserAuthority(cert.SignatureKey) { + return nil, fmt.Errorf("CA check failed") + } + + // Create a verifier + verifier, err := httpsig.NewVerifier(r) + if err != nil { + return nil, fmt.Errorf("httpsig.NewVerifier failed: %s", err) + } + + // now verify that this request was signed with the private key that matches the certificate public key + if err := doVerify(verifier, []ssh.PublicKey{cert.Key}); err != nil { + return nil, err + } + + // Now for each of the certificate valid principals + for _, principal := range cert.ValidPrincipals { + // Look in the db for the public key + publicKey, err := asymkey_model.SearchPublicKeyByContentExact(r.Context(), principal) + if asymkey_model.IsErrKeyNotExist(err) { + // No public key matches this principal - try the next principal + continue + } else if err != nil { + // this error will be a db error therefore we can't solve this and we should abort + log.Error("SearchPublicKeyByContentExact: %v", err) + return nil, err + } + + // Validate the cert for this principal + if err := c.CheckCert(principal, cert); err != nil { + // however, because principal is a member of ValidPrincipals - if this fails then the certificate itself is invalid + return nil, err + } + + // OK we have a public key for a principal matching a valid certificate whose key has signed this request. + return publicKey, nil + } + + // No public key matching a principal in the certificate is registered in gitea + return nil, fmt.Errorf("no valid principal found") +} + +// doVerify iterates across the provided public keys attempting the verify the current request against each key in turn +func doVerify(verifier httpsig.Verifier, sshPublicKeys []ssh.PublicKey) error { + for _, publicKey := range sshPublicKeys { + cryptoPubkey := publicKey.(ssh.CryptoPublicKey).CryptoPublicKey() + + var algos []httpsig.Algorithm + + switch { + case strings.HasPrefix(publicKey.Type(), "ssh-ed25519"): + algos = []httpsig.Algorithm{httpsig.ED25519} + case strings.HasPrefix(publicKey.Type(), "ssh-rsa"): + algos = []httpsig.Algorithm{httpsig.RSA_SHA1, httpsig.RSA_SHA256, httpsig.RSA_SHA512} + } + for _, algo := range algos { + if err := verifier.Verify(cryptoPubkey, algo); err == nil { + return nil + } + } + } + + return errors.New("verification failed") +} diff --git a/services/auth/oauth2.go b/services/auth/oauth2.go index 42c91fac37..68638a0806 100644 --- a/services/auth/oauth2.go +++ b/services/auth/oauth2.go @@ -38,7 +38,7 @@ func CheckOAuthAccessToken(accessToken string) int64 { return 0 } var grant *auth.OAuth2Grant - if grant, err = auth.GetOAuth2GrantByID(token.GrantID); err != nil || grant == nil { + if grant, err = auth.GetOAuth2GrantByID(db.DefaultContext, token.GrantID); err != nil || grant == nil { return 0 } if token.Type != oauth2.TypeAccessToken { diff --git a/services/auth/reverseproxy.go b/services/auth/reverseproxy.go index 299d7abd34..05d6af78f1 100644 --- a/services/auth/reverseproxy.go +++ b/services/auth/reverseproxy.go @@ -63,7 +63,7 @@ func (r *ReverseProxy) Verify(req *http.Request, w http.ResponseWriter, store Da } log.Trace("ReverseProxy Authorization: Found username: %s", username) - user, err := user_model.GetUserByName(username) + user, err := user_model.GetUserByName(req.Context(), username) if err != nil { if !user_model.IsErrUserNotExist(err) || !r.isAutoRegisterAllowed() { log.Error("GetUserByName: %v", err) diff --git a/services/auth/source/ldap/source_authenticate.go b/services/auth/source/ldap/source_authenticate.go index d8d11f18e1..785cb8ed31 100644 --- a/services/auth/source/ldap/source_authenticate.go +++ b/services/auth/source/ldap/source_authenticate.go @@ -34,11 +34,11 @@ func (source *Source) Authenticate(user *user_model.User, userName, password str isAttributeSSHPublicKeySet := len(strings.TrimSpace(source.AttributeSSHPublicKey)) > 0 // Update User admin flag if exist - if isExist, err := user_model.IsUserExist(0, sr.Username); err != nil { + if isExist, err := user_model.IsUserExist(db.DefaultContext, 0, sr.Username); err != nil { return nil, err } else if isExist { if user == nil { - user, err = user_model.GetUserByName(sr.Username) + user, err = user_model.GetUserByName(db.DefaultContext, sr.Username) if err != nil { return nil, err } diff --git a/services/auth/source/ldap/source_sync.go b/services/auth/source/ldap/source_sync.go index a245f4c6ff..eb5ee8463f 100644 --- a/services/auth/source/ldap/source_sync.go +++ b/services/auth/source/ldap/source_sync.go @@ -118,7 +118,6 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { } err = user_model.CreateUser(usr, overwriteDefault) - if err != nil { log.Error("SyncExternalUsers[%s]: Error creating user %s: %v", source.authSource.Name, su.Username, err) } @@ -161,7 +160,7 @@ func (source *Source) Sync(ctx context.Context, updateExisting bool) error { } usr.IsActive = true - err = user_model.UpdateUser(usr, emailChanged, "full_name", "email", "is_admin", "is_restricted", "is_active") + err = user_model.UpdateUser(ctx, usr, emailChanged, "full_name", "email", "is_admin", "is_restricted", "is_active") if err != nil { log.Error("SyncExternalUsers[%s]: Error updating user %s: %v", source.authSource.Name, usr.Name, err) } diff --git a/services/auth/sspi_windows.go b/services/auth/sspi_windows.go index 9bc4041a74..7c9529a76b 100644 --- a/services/auth/sspi_windows.go +++ b/services/auth/sspi_windows.go @@ -127,7 +127,7 @@ func (s *SSPI) Verify(req *http.Request, w http.ResponseWriter, store DataStore, } log.Info("Authenticated as %s\n", username) - user, err := user_model.GetUserByName(username) + user, err := user_model.GetUserByName(req.Context(), username) if err != nil { if !user_model.IsErrUserNotExist(err) { log.Error("GetUserByName: %v", err) diff --git a/services/automerge/automerge.go b/services/automerge/automerge.go index 85af2659c6..3c7346ab58 100644 --- a/services/automerge/automerge.go +++ b/services/automerge/automerge.go @@ -13,6 +13,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" @@ -144,7 +145,7 @@ func getPullRequestsByHeadSHA(ctx context.Context, sha string, repo *repo_model. continue } - p, err := models.GetPullRequestByIndexCtx(ctx, repo.ID, prIndex) + p, err := models.GetPullRequestByIndex(ctx, repo.ID, prIndex) if err != nil { // If there is no pull request for this branch, we don't try to merge it. if models.IsErrPullRequestNotExist(err) { @@ -224,7 +225,7 @@ func handlePull(pullID int64, sha string) { return } - perm, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, doer) + perm, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer) if err != nil { log.Error("GetUserRepoPermission: %v", err) return diff --git a/services/comments/comments.go b/services/comments/comments.go index c1b3ab73c9..b80fddf93f 100644 --- a/services/comments/comments.go +++ b/services/comments/comments.go @@ -48,7 +48,7 @@ func UpdateComment(c *models.Comment, doer *user_model.User, oldContent string) return err } if !hasContentHistory { - if err = issues.SaveIssueContentHistory(db.GetEngine(db.DefaultContext), c.PosterID, c.IssueID, c.ID, + if err = issues.SaveIssueContentHistory(db.DefaultContext, c.PosterID, c.IssueID, c.ID, c.CreatedUnix, oldContent, true); err != nil { return err } @@ -60,7 +60,7 @@ func UpdateComment(c *models.Comment, doer *user_model.User, oldContent string) } if needsContentHistory { - err := issues.SaveIssueContentHistory(db.GetEngine(db.DefaultContext), doer.ID, c.IssueID, c.ID, timeutil.TimeStampNow(), c.Content, false) + err := issues.SaveIssueContentHistory(db.DefaultContext, doer.ID, c.IssueID, c.ID, timeutil.TimeStampNow(), c.Content, false) if err != nil { return err } diff --git a/services/context/user.go b/services/context/user.go index c5efd43782..1c92d24d4a 100644 --- a/services/context/user.go +++ b/services/context/user.go @@ -44,7 +44,7 @@ func userAssignment(ctx *context.Context, errCb func(int, string, interface{})) ctx.ContextUser = ctx.Doer } else { var err error - ctx.ContextUser, err = user_model.GetUserByName(username) + ctx.ContextUser, err = user_model.GetUserByName(ctx, username) if err != nil { if user_model.IsErrUserNotExist(err) { if redirectUserID, err := user_model.LookupUserRedirect(username); err == nil { diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 6f3fcb42c3..39fda34ea2 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -155,7 +155,9 @@ func registerCleanupPackages() { } func initBasicTasks() { - registerUpdateMirrorTask() + if setting.Mirror.Enabled { + registerUpdateMirrorTask() + } registerRepoHealthCheck() registerCheckRepoStats() registerArchiveCleanup() diff --git a/services/cron/tasks_extended.go b/services/cron/tasks_extended.go index 2d1bf53234..41bd5c4420 100644 --- a/services/cron/tasks_extended.go +++ b/services/cron/tasks_extended.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/admin" asymkey_model "code.gitea.io/gitea/models/asymkey" + "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/updatechecker" @@ -26,7 +27,7 @@ func registerDeleteInactiveUsers() { RunAtStart: false, Schedule: "@annually", }, - OlderThan: 0 * time.Second, + OlderThan: time.Minute * time.Duration(setting.Service.ActiveCodeLives), }, func(ctx context.Context, _ *user_model.User, config Config) error { olderThanConfig := config.(*OlderThanConfig) return user_service.DeleteInactiveUsers(ctx, olderThanConfig.OlderThan) @@ -79,7 +80,7 @@ func registerRewriteAllPrincipalKeys() { RunAtStart: false, Schedule: "@every 72h", }, func(_ context.Context, _ *user_model.User, _ Config) error { - return asymkey_model.RewriteAllPrincipalKeys() + return asymkey_model.RewriteAllPrincipalKeys(db.DefaultContext) }) } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 18cbac751c..2bcb91f8c3 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -623,7 +623,7 @@ func (f *CodeCommentForm) Validate(req *http.Request, errs binding.Errors) bindi // SubmitReviewForm for submitting a finished code review type SubmitReviewForm struct { Content string - Type string `binding:"Required;In(approve,comment,reject)"` + Type string CommitID string Files []string } @@ -634,7 +634,7 @@ func (f *SubmitReviewForm) Validate(req *http.Request, errs binding.Errors) bind return middleware.Validate(errs, ctx.Data, f, ctx.Locale) } -// ReviewType will return the corresponding reviewtype for type +// ReviewType will return the corresponding ReviewType for type func (f SubmitReviewForm) ReviewType() models.ReviewType { switch f.Type { case "approve": @@ -643,6 +643,8 @@ func (f SubmitReviewForm) ReviewType() models.ReviewType { return models.ReviewTypeComment case "reject": return models.ReviewTypeReject + case "": + return models.ReviewTypeComment // default to comment when doing quick-submit (Ctrl+Enter) on the review form default: return models.ReviewTypeUnknown } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 92ff92a6c0..d611ff513e 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -1220,7 +1220,7 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio oid := strings.TrimPrefix(line[1:], lfs.MetaFileOidPrefix) if len(oid) == 64 { m := &models.LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}} - count, err := db.Count(m) + count, err := db.CountByBean(db.DefaultContext, m) if err == nil && count > 0 { curFile.IsBin = true diff --git a/services/issue/assignee.go b/services/issue/assignee.go index e6169b9c7e..8cad03351c 100644 --- a/services/issue/assignee.go +++ b/services/issue/assignee.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -20,9 +21,10 @@ import ( // DeleteNotPassedAssignee deletes all assignees who aren't passed via the "assignees" array func DeleteNotPassedAssignee(issue *models.Issue, doer *user_model.User, assignees []*user_model.User) (err error) { var found bool + oriAssignes := make([]*user_model.User, len(issue.Assignees)) + _ = copy(oriAssignes, issue.Assignees) - for _, assignee := range issue.Assignees { - + for _, assignee := range oriAssignes { found = false for _, alreadyAssignee := range assignees { if assignee.ID == alreadyAssignee.ID { @@ -80,7 +82,7 @@ func ReviewRequest(issue *models.Issue, doer, reviewer *user_model.User, isAdd b } // IsValidReviewRequest Check permission for ReviewRequest -func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, isAdd bool, issue *models.Issue, permDoer *models.Permission) error { +func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, isAdd bool, issue *models.Issue, permDoer *access_model.Permission) error { if reviewer.IsOrganization() { return models.ErrNotValidReviewRequest{ Reason: "Organization can't be added as reviewer", @@ -96,20 +98,20 @@ func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, } } - permReviewer, err := models.GetUserRepoPermission(ctx, issue.Repo, reviewer) + permReviewer, err := access_model.GetUserRepoPermission(ctx, issue.Repo, reviewer) if err != nil { return err } if permDoer == nil { - permDoer = new(models.Permission) - *permDoer, err = models.GetUserRepoPermission(ctx, issue.Repo, doer) + permDoer = new(access_model.Permission) + *permDoer, err = access_model.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } } - lastreview, err := models.GetReviewByIssueIDAndUserID(issue.ID, reviewer.ID) + lastreview, err := models.GetReviewByIssueIDAndUserID(ctx, issue.ID, reviewer.ID) if err != nil && !models.IsErrReviewNotExist(err) { return err } @@ -131,7 +133,7 @@ func IsValidReviewRequest(ctx context.Context, reviewer, doer *user_model.User, pemResult = permDoer.CanAccessAny(perm.AccessModeWrite, unit.TypePullRequests) if !pemResult { - pemResult, err = models.IsOfficialReviewer(issue, doer) + pemResult, err = models.IsOfficialReviewer(ctx, issue, doer) if err != nil { return err } @@ -179,7 +181,7 @@ func IsValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, } } - permission, err := models.GetUserRepoPermission(ctx, issue.Repo, doer) + permission, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { log.Error("Unable to GetUserRepoPermission for %-v in %-v#%d", doer, issue.Repo, issue.Index) return err @@ -200,7 +202,7 @@ func IsValidTeamReviewRequest(ctx context.Context, reviewer *organization.Team, doerCanWrite := permission.CanAccessAny(perm.AccessModeWrite, unit.TypePullRequests) if !doerCanWrite { - official, err := models.IsOfficialReviewer(issue, doer) + official, err := models.IsOfficialReviewer(ctx, issue, doer) if err != nil { log.Error("Unable to Check if IsOfficialReviewer for %-v in %-v#%d", doer, issue.Repo, issue.Index) return err diff --git a/services/issue/assignee_test.go b/services/issue/assignee_test.go index d3d7ad74f8..ff4d7029eb 100644 --- a/services/issue/assignee_test.go +++ b/services/issue/assignee_test.go @@ -8,6 +8,7 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -20,21 +21,23 @@ func TestDeleteNotPassedAssignee(t *testing.T) { // Fake issue with assignees issue, err := models.GetIssueWithAttrsByID(1) 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 assert.NoError(t, err) // Check if he got removed - isAssigned, err := models.IsUserAssignedToIssue(issue, user1) + isAssigned, err := models.IsUserAssignedToIssue(db.DefaultContext, issue, user1) assert.NoError(t, err) assert.True(t, isAssigned) // Clean everyone err = DeleteNotPassedAssignee(issue, user1, []*user_model.User{}) assert.NoError(t, err) + assert.EqualValues(t, 0, len(issue.Assignees)) // Check they're gone - assignees, err := models.GetAssigneesByIssue(issue) - assert.NoError(t, err) - assert.Empty(t, assignees) + assert.NoError(t, issue.LoadAssignees(db.DefaultContext)) + assert.EqualValues(t, 0, len(issue.Assignees)) + assert.Empty(t, issue.Assignee) } diff --git a/services/issue/commit.go b/services/issue/commit.go index b5d97e12a8..5140eebed1 100644 --- a/services/issue/commit.go +++ b/services/issue/commit.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/references" @@ -131,7 +132,7 @@ func UpdateIssuesCommit(doer *user_model.User, repo *repo_model.Repository, comm continue } - perm, err := models.GetUserRepoPermission(db.DefaultContext, refRepo, doer) + perm, err := access_model.GetUserRepoPermission(db.DefaultContext, refRepo, doer) if err != nil { return err } diff --git a/services/issue/issue.go b/services/issue/issue.go index 6bc3959979..78a486727a 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -9,6 +9,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" @@ -99,7 +100,7 @@ func UpdateAssignees(issue *models.Issue, oneAssignee string, multipleAssignees // Loop through all assignees to add them for _, assigneeName := range multipleAssignees { - assignee, err := user_model.GetUserByName(assigneeName) + assignee, err := user_model.GetUserByName(db.DefaultContext, assigneeName) if err != nil { return err } @@ -163,7 +164,7 @@ func AddAssigneeIfNotAssigned(issue *models.Issue, doer *user_model.User, assign } // Check if the user is already assigned - isAssigned, err := models.IsUserAssignedToIssue(issue, assignee) + isAssigned, err := models.IsUserAssignedToIssue(db.DefaultContext, issue, assignee) if err != nil { return err } @@ -172,7 +173,7 @@ func AddAssigneeIfNotAssigned(issue *models.Issue, doer *user_model.User, assign return nil } - valid, err := models.CanBeAssigned(assignee, issue.Repo, issue.IsPull) + valid, err := access_model.CanBeAssigned(db.DefaultContext, assignee, issue.Repo, issue.IsPull) if err != nil { return err } diff --git a/services/issue/label.go b/services/issue/label.go index 62ccc0ad65..289466f604 100644 --- a/services/issue/label.go +++ b/services/issue/label.go @@ -7,6 +7,7 @@ package issue import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/notification" ) @@ -54,7 +55,7 @@ func RemoveLabel(issue *models.Issue, doer *user_model.User, label *models.Label return err } - perm, err := models.GetUserRepoPermission(ctx, issue.Repo, doer) + perm, err := access_model.GetUserRepoPermission(ctx, issue.Repo, doer) if err != nil { return err } @@ -79,7 +80,7 @@ func RemoveLabel(issue *models.Issue, doer *user_model.User, label *models.Label // ReplaceLabels removes all current labels and add new labels to the issue. func ReplaceLabels(issue *models.Issue, doer *user_model.User, labels []*models.Label) error { - old, err := models.GetLabelsByIssueID(issue.ID) + old, err := models.GetLabelsByIssueID(db.DefaultContext, issue.ID) if err != nil { return err } diff --git a/services/lfs/server.go b/services/lfs/server.go index c095bbfab4..f5c57a7dab 100644 --- a/services/lfs/server.go +++ b/services/lfs/server.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -488,7 +489,7 @@ func authenticate(ctx *context.Context, repository *repo_model.Repository, autho } // ctx.IsSigned is unnecessary here, this will be checked in perm.CanAccess - perm, err := models.GetUserRepoPermission(ctx, repository, ctx.Doer) + perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer) if err != nil { log.Error("Unable to GetUserRepoPermission for user %-v in repo %-v Error: %v", ctx.Doer, repository) return false diff --git a/services/mailer/mail_issue.go b/services/mailer/mail_issue.go index c24edf50c9..d479dd0d44 100644 --- a/services/mailer/mail_issue.go +++ b/services/mailer/mail_issue.go @@ -71,7 +71,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo unfiltered = append(unfiltered, ids...) // =========== Issue watchers =========== - ids, err = models.GetIssueWatchersIDs(ctx.Issue.ID, true) + ids, err = models.GetIssueWatchersIDs(ctx, ctx.Issue.ID, true) if err != nil { return fmt.Errorf("GetIssueWatchersIDs(%d): %v", ctx.Issue.ID, err) } @@ -98,7 +98,7 @@ func mailIssueCommentToParticipants(ctx *mailCommentContext, mentions []*user_mo } // Avoid mailing explicit unwatched - ids, err = models.GetIssueWatchersIDs(ctx.Issue.ID, false) + ids, err = models.GetIssueWatchersIDs(ctx, ctx.Issue.ID, false) if err != nil { return fmt.Errorf("GetIssueWatchersIDs(%d): %v", ctx.Issue.ID, err) } @@ -145,7 +145,7 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi visited[user.ID] = true // test if this user is allowed to see the issue/pull - if !models.CheckRepoUnitUser(ctx.Issue.Repo, user, checkUnit) { + if !models.CheckRepoUnitUser(ctx, ctx.Issue.Repo, user, checkUnit) { continue } diff --git a/services/mailer/mailer.go b/services/mailer/mailer.go index 3ca9b50fc6..f4bc2ddc63 100644 --- a/services/mailer/mailer.go +++ b/services/mailer/mailer.go @@ -281,6 +281,7 @@ func (s *sendmailSender) Send(from string, to []string, msg io.WriterTo) error { if err != nil { return err } + process.SetSysProcAttribute(cmd) if err = cmd.Start(); err != nil { _ = pipe.Close() diff --git a/services/migrations/codebase_test.go b/services/migrations/codebase_test.go index cb70a2bf75..03b5946d71 100644 --- a/services/migrations/codebase_test.go +++ b/services/migrations/codebase_test.go @@ -6,7 +6,6 @@ package migrations import ( "context" - "fmt" "net/url" "os" "testing" @@ -40,7 +39,7 @@ func TestCodebaseDownloadRepo(t *testing.T) { AuthPassword: apiPassword, }) if err != nil { - t.Fatal(fmt.Sprintf("Error creating Codebase downloader: %v", err)) + t.Fatalf("Error creating Codebase downloader: %v", err) } repo, err := downloader.GetRepoInfo() assert.NoError(t, err) diff --git a/services/migrations/error.go b/services/migrations/error.go index 3b3f975012..d26fa8112c 100644 --- a/services/migrations/error.go +++ b/services/migrations/error.go @@ -8,7 +8,7 @@ package migrations import ( "errors" - "github.com/google/go-github/v39/github" + "github.com/google/go-github/v45/github" ) // ErrRepoNotCreated returns the error that repository not created diff --git a/services/migrations/gitea_downloader.go b/services/migrations/gitea_downloader.go index 3c02e112ca..4ad55894ee 100644 --- a/services/migrations/gitea_downloader.go +++ b/services/migrations/gitea_downloader.go @@ -639,6 +639,11 @@ func (g *GiteaDownloader) GetReviews(reviewable base.Reviewable) ([]*base.Review } for _, pr := range prl { + if pr.Reviewer == nil { + // Presumably this is a team review which we cannot migrate at present but we have to skip this review as otherwise the review will be mapped on to an incorrect user. + // TODO: handle team reviews + continue + } rcl, _, err := g.client.ListPullReviewComments(g.repoOwner, g.repoName, reviewable.GetForeignIndex(), pr.ID) if err != nil { @@ -664,7 +669,7 @@ func (g *GiteaDownloader) GetReviews(reviewable base.Reviewable) ([]*base.Review }) } - allReviews = append(allReviews, &base.Review{ + review := &base.Review{ ID: pr.ID, IssueIndex: reviewable.GetLocalIndex(), ReviewerID: pr.Reviewer.ID, @@ -675,7 +680,9 @@ func (g *GiteaDownloader) GetReviews(reviewable base.Reviewable) ([]*base.Review CreatedAt: pr.Submitted, State: string(pr.State), Comments: reviewComments, - }) + } + + allReviews = append(allReviews, review) } if len(prl) < g.maxPerPage { diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 34dd59d7fc..408704adef 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -93,7 +93,7 @@ func (g *GiteaLocalUploader) MaxBatchInsertSize(tp string) int { // CreateRepo creates a repository func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.MigrateOptions) error { - owner, err := user_model.GetUserByName(g.repoOwner) + owner, err := user_model.GetUserByName(g.ctx, g.repoOwner) if err != nil { return err } @@ -696,6 +696,8 @@ func convertReviewState(state string) models.ReviewType { return models.ReviewTypeReject case base.ReviewStateCommented: return models.ReviewTypeComment + case base.ReviewStateRequestReview: + return models.ReviewTypeRequest default: return models.ReviewTypePending } @@ -826,7 +828,7 @@ func (g *GiteaLocalUploader) Finish() error { } g.repo.Status = repo_model.RepositoryReady - return repo_model.UpdateRepositoryCols(g.repo, "status") + return repo_model.UpdateRepositoryCols(g.ctx, g.repo, "status") } func (g *GiteaLocalUploader) remapUser(source user_model.ExternalUserMigrated, target user_model.ExternalUserRemappable) error { diff --git a/services/migrations/gitea_uploader_test.go b/services/migrations/gitea_uploader_test.go index f57c8e2333..bd7c6e0657 100644 --- a/services/migrations/gitea_uploader_test.go +++ b/services/migrations/gitea_uploader_test.go @@ -40,7 +40,8 @@ func TestGiteaUploadRepo(t *testing.T) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}).(*user_model.User) var ( - downloader = NewGithubDownloaderV3(context.Background(), "https://github.com", "", "", "", "go-xorm", "builder") + ctx = context.Background() + downloader = NewGithubDownloaderV3(ctx, "https://github.com", "", "", "", "go-xorm", "builder") repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05") uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName) ) @@ -80,7 +81,7 @@ func TestGiteaUploadRepo(t *testing.T) { assert.NoError(t, err) assert.Empty(t, milestones) - labels, err := models.GetLabelsByRepoID(repo.ID, "", db.ListOptions{}) + labels, err := models.GetLabelsByRepoID(ctx, repo.ID, "", db.ListOptions{}) assert.NoError(t, err) assert.Len(t, labels, 12) diff --git a/services/migrations/github.go b/services/migrations/github.go index faf0cf0794..5f5b430fa9 100644 --- a/services/migrations/github.go +++ b/services/migrations/github.go @@ -21,7 +21,7 @@ import ( "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/util" - "github.com/google/go-github/v39/github" + "github.com/google/go-github/v45/github" "golang.org/x/oauth2" ) @@ -778,6 +778,7 @@ func (g *GithubDownloaderV3) GetReviews(reviewable base.Reviewable) ([]*base.Rev opt := &github.ListOptions{ PerPage: g.maxPerPage, } + // Get approve/request change reviews for { g.waitAndPickClient() reviews, resp, err := g.getClient().PullRequests.ListReviews(g.ctx, g.repoOwner, g.repoName, int(reviewable.GetForeignIndex()), opt) @@ -817,5 +818,28 @@ func (g *GithubDownloaderV3) GetReviews(reviewable base.Reviewable) ([]*base.Rev } opt.Page = resp.NextPage } + // Get requested reviews + for { + g.waitAndPickClient() + reviewers, resp, err := g.getClient().PullRequests.ListReviewers(g.ctx, g.repoOwner, g.repoName, int(reviewable.GetForeignIndex()), opt) + if err != nil { + return nil, fmt.Errorf("error while listing repos: %v", err) + } + g.setRate(&resp.Rate) + for _, user := range reviewers.Users { + r := &base.Review{ + ReviewerID: user.GetID(), + ReviewerName: user.GetLogin(), + State: base.ReviewStateRequestReview, + IssueIndex: reviewable.GetLocalIndex(), + } + allReviews = append(allReviews, r) + } + // TODO: Handle Team requests + if resp.NextPage == 0 { + break + } + opt.Page = resp.NextPage + } return allReviews, nil } diff --git a/services/migrations/gitlab_test.go b/services/migrations/gitlab_test.go index e63d674186..829964b384 100644 --- a/services/migrations/gitlab_test.go +++ b/services/migrations/gitlab_test.go @@ -34,7 +34,7 @@ func TestGitlabDownloadRepo(t *testing.T) { downloader, err := NewGitlabDownloader(context.Background(), "https://gitlab.com", "gitea/test_repo", "", "", gitlabPersonalAccessToken) if err != nil { - t.Fatal(fmt.Sprintf("NewGitlabDownloader is nil: %v", err)) + t.Fatalf("NewGitlabDownloader is nil: %v", err) } repo, err := downloader.GetRepoInfo() assert.NoError(t, err) diff --git a/services/migrations/onedev_test.go b/services/migrations/onedev_test.go index 0cf1ab852c..6a17eb334b 100644 --- a/services/migrations/onedev_test.go +++ b/services/migrations/onedev_test.go @@ -6,7 +6,6 @@ package migrations import ( "context" - "fmt" "net/http" "net/url" "testing" @@ -26,7 +25,7 @@ func TestOneDevDownloadRepo(t *testing.T) { u, _ := url.Parse("https://code.onedev.io") downloader := NewOneDevDownloader(context.Background(), u, "", "", "go-gitea-test_repo") if err != nil { - t.Fatal(fmt.Sprintf("NewOneDevDownloader is nil: %v", err)) + t.Fatalf("NewOneDevDownloader is nil: %v", err) } repo, err := downloader.GetRepoInfo() assert.NoError(t, err) diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index ecd031b387..caa81f0fe9 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -10,8 +10,8 @@ import ( "strings" "time" - "code.gitea.io/gitea/models" admin_model "code.gitea.io/gitea/models/admin" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/modules/cache" "code.gitea.io/gitea/modules/git" @@ -31,7 +31,7 @@ const gitShortEmptySha = "0000000" // UpdateAddress writes new address to Git repository and database func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error { remoteName := m.GetRemoteName() - repoPath := m.Repo.RepoPath() + repoPath := m.GetRepository().RepoPath() // Remove old remote _, _, err := git.NewCommand(ctx, "remote", "rm", remoteName).RunStdString(&git.RunOpts{Dir: repoPath}) if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") { @@ -71,7 +71,7 @@ func UpdateAddress(ctx context.Context, m *repo_model.Mirror, addr string) error } m.Repo.OriginalURL = addr - return repo_model.UpdateRepositoryCols(m.Repo, "original_url") + return repo_model.UpdateRepositoryCols(ctx, m.Repo, "original_url") } // mirrorSyncResult contains information of a updated reference. @@ -300,7 +300,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo gitRepo.Close() log.Trace("SyncMirrors [repo: %-v]: updating size of repository", m.Repo) - if err := models.UpdateRepoSize(ctx, m.Repo); err != nil { + if err := repo_module.UpdateRepoSize(ctx, m.Repo); err != nil { log.Error("SyncMirrors [repo: %-v]: failed to update size for mirror repository: %v", m.Repo, err) } @@ -395,11 +395,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Error("PANIC whilst SyncMirrors[repo_id: %d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2)) }() - m, err := repo_model.GetMirrorByRepoID(repoID) + m, err := repo_model.GetMirrorByRepoID(ctx, repoID) if err != nil { log.Error("SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v", repoID, err) return false } + _ = m.GetRepository() // force load repository of mirror ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing Mirror %s/%s", m.Repo.OwnerName, m.Repo.Name)) defer finished() @@ -415,7 +416,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool { log.Trace("SyncMirrors [repo: %-v]: Scheduling next update", m.Repo) m.ScheduleNextUpdate() - if err = repo_model.UpdateMirror(m); err != nil { + if err = repo_model.UpdateMirror(ctx, m); err != nil { log.Error("SyncMirrors [repo: %-v]: failed to UpdateMirror with next update date: %v", m.Repo, err) return false } @@ -574,7 +575,7 @@ func checkAndUpdateEmptyRepository(m *repo_model.Mirror, gitRepo *git.Repository } m.Repo.IsEmpty = false // Update the is empty and default_branch columns - if err := repo_model.UpdateRepositoryCols(m.Repo, "default_branch", "is_empty"); err != nil { + if err := repo_model.UpdateRepositoryCols(db.DefaultContext, m.Repo, "default_branch", "is_empty"); err != nil { log.Error("Failed to update default branch of repository %-v. Error: %v", m.Repo, err) desc := fmt.Sprintf("Failed to uupdate default branch of repository '%s': %v", m.Repo.RepoPath(), err) if err = admin_model.CreateRepositoryNotice(desc); err != nil { diff --git a/services/mirror/mirror_push.go b/services/mirror/mirror_push.go index 5c0c14c627..138ebb737b 100644 --- a/services/mirror/mirror_push.go +++ b/services/mirror/mirror_push.go @@ -66,6 +66,7 @@ func AddPushMirrorRemote(ctx context.Context, m *repo_model.PushMirror, addr str // RemovePushMirrorRemote removes the push mirror remote. func RemovePushMirrorRemote(ctx context.Context, m *repo_model.PushMirror) error { cmd := git.NewCommand(ctx, "remote", "rm", m.RemoteName) + _ = m.GetRepository() if _, _, err := cmd.RunStdString(&git.RunOpts{Dir: m.Repo.RepoPath()}); err != nil { return err @@ -99,6 +100,8 @@ func SyncPushMirror(ctx context.Context, mirrorID int64) bool { return false } + _ = m.GetRepository() + m.LastError = "" ctx, _, finished := process.GetManager().AddContext(ctx, fmt.Sprintf("Syncing PushMirror %s/%s to %s", m.Repo.OwnerName, m.Repo.Name, m.RemoteName)) diff --git a/services/org/org.go b/services/org/org.go index d7b3019e74..b24b7e34c4 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -26,7 +26,7 @@ func DeleteOrganization(org *organization.Organization) error { defer commiter.Close() // Check ownership of repository. - count, err := repo_model.GetRepositoryCount(ctx, org.ID) + count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: org.ID}) if err != nil { return fmt.Errorf("GetRepositoryCount: %v", err) } else if count > 0 { diff --git a/services/pull/check.go b/services/pull/check.go index 6852940b22..94e7ca7161 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -60,7 +61,7 @@ func AddToTaskQueue(pr *models.PullRequest) { } // CheckPullMergable check if the pull mergable based on all conditions (branch protection, merge options, ...) -func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *models.Permission, pr *models.PullRequest, manuallMerge, force bool) error { +func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *models.PullRequest, manuallMerge, force bool) error { return db.WithTx(func(ctx context.Context) error { if pr.HasMerged { return ErrHasMerged @@ -98,7 +99,7 @@ func CheckPullMergable(stdCtx context.Context, doer *user_model.User, perm *mode if err := CheckPullBranchProtections(ctx, pr, false); err != nil { if models.IsErrDisallowedToMerge(err) { if force { - if isRepoAdmin, err2 := models.IsUserRepoAdminCtx(ctx, pr.BaseRepo, doer); err2 != nil { + if isRepoAdmin, err2 := access_model.IsUserRepoAdmin(ctx, pr.BaseRepo, doer); err2 != nil { return err2 } else if !isRepoAdmin { return err diff --git a/services/pull/commit_status.go b/services/pull/commit_status.go index ec4cc2aa07..539b3c8520 100644 --- a/services/pull/commit_status.go +++ b/services/pull/commit_status.go @@ -132,7 +132,7 @@ func GetPullRequestCommitStatusState(ctx context.Context, pr *models.PullRequest return "", errors.Wrap(err, "LoadBaseRepo") } - commitStatuses, _, err := models.GetLatestCommitStatusCtx(ctx, pr.BaseRepo.ID, sha, db.ListOptions{}) + commitStatuses, _, err := models.GetLatestCommitStatus(ctx, pr.BaseRepo.ID, sha, db.ListOptions{}) if err != nil { return "", errors.Wrap(err, "GetLatestCommitStatus") } diff --git a/services/pull/edits.go b/services/pull/edits.go index 68515ec141..11932d9ab8 100644 --- a/services/pull/edits.go +++ b/services/pull/edits.go @@ -10,6 +10,7 @@ import ( "errors" "code.gitea.io/gitea/models" + access_model "code.gitea.io/gitea/models/perm/access" unit_model "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" ) @@ -26,7 +27,7 @@ func SetAllowEdits(ctx context.Context, doer *user_model.User, pr *models.PullRe return err } - permission, err := models.GetUserRepoPermission(ctx, pr.HeadRepo, doer) + permission, err := access_model.GetUserRepoPermission(ctx, pr.HeadRepo, doer) if err != nil { return err } diff --git a/services/pull/merge.go b/services/pull/merge.go index 0af3cc1613..fcced65cdf 100644 --- a/services/pull/merge.go +++ b/services/pull/merge.go @@ -19,6 +19,7 @@ import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" + access_model "code.gitea.io/gitea/models/perm/access" pull_model "code.gitea.io/gitea/models/pull" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" @@ -751,7 +752,7 @@ func getDiffTree(ctx context.Context, repoPath, baseBranch, headBranch string) ( } // IsUserAllowedToMerge check if user is allowed to merge PR with given permissions and branch protections -func IsUserAllowedToMerge(ctx context.Context, pr *models.PullRequest, p models.Permission, user *user_model.User) (bool, error) { +func IsUserAllowedToMerge(ctx context.Context, pr *models.PullRequest, p access_model.Permission, user *user_model.User) (bool, error) { if user == nil { return false, nil } diff --git a/services/pull/pull.go b/services/pull/pull.go index b94b6769a4..efac3f019e 100644 --- a/services/pull/pull.go +++ b/services/pull/pull.go @@ -290,7 +290,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, if err != nil { log.Error("GetDiverging: %v", err) } else { - err = pr.UpdateCommitDivergence(divergence.Ahead, divergence.Behind) + err = pr.UpdateCommitDivergence(ctx, divergence.Ahead, divergence.Behind) if err != nil { log.Error("UpdateCommitDivergence: %v", err) } @@ -336,7 +336,7 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string, log.Error("GetDiverging: %v", err) } } else { - err = pr.UpdateCommitDivergence(divergence.Ahead, divergence.Behind) + err = pr.UpdateCommitDivergence(ctx, divergence.Ahead, divergence.Behind) if err != nil { log.Error("UpdateCommitDivergence: %v", err) } @@ -793,7 +793,7 @@ func getAllCommitStatus(gitRepo *git.Repository, pr *models.PullRequest) (status return nil, nil, shaErr } - statuses, _, err = models.GetLatestCommitStatus(pr.BaseRepo.ID, sha, db.ListOptions{}) + statuses, _, err = models.GetLatestCommitStatus(db.DefaultContext, pr.BaseRepo.ID, sha, db.ListOptions{}) lastStatus = models.CalcCommitStatus(statuses) return statuses, lastStatus, err } diff --git a/services/pull/review.go b/services/pull/review.go index 940fe4470d..eac7279f9b 100644 --- a/services/pull/review.go +++ b/services/pull/review.go @@ -71,13 +71,13 @@ func CreateCodeComment(ctx context.Context, doer *user_model.User, gitRepo *git. return comment, nil } - review, err := models.GetCurrentReview(doer, issue) + review, err := models.GetCurrentReview(ctx, doer, issue) if err != nil { if !models.IsErrReviewNotExist(err) { return nil, err } - if review, err = models.CreateReview(models.CreateReviewOptions{ + if review, err = models.CreateReview(ctx, models.CreateReviewOptions{ Type: models.ReviewTypePending, Reviewer: doer, Issue: issue, @@ -135,7 +135,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo head := pr.GetGitRefName() if line > 0 { if reviewID != 0 { - first, err := models.FindComments(&models.FindCommentsOptions{ + first, err := models.FindComments(ctx, &models.FindCommentsOptions{ ReviewID: reviewID, Line: line, TreePath: treePath, @@ -152,7 +152,7 @@ func createCodeComment(ctx context.Context, doer *user_model.User, repo *repo_mo } else if err != nil && !models.IsErrCommentNotExist(err) { return nil, fmt.Errorf("Find first comment for %d line %d path %s. Error: %v", reviewID, line, treePath, err) } else { - review, err := models.GetReviewByID(reviewID) + review, err := models.GetReviewByID(ctx, reviewID) if err == nil && len(review.CommitID) > 0 { head = review.CommitID } else if err != nil && !models.IsErrReviewNotExist(err) { @@ -272,7 +272,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos // DismissReview dismissing stale review by repo admin func DismissReview(ctx context.Context, reviewID int64, message string, doer *user_model.User, isDismiss bool) (comment *models.Comment, err error) { - review, err := models.GetReviewByID(reviewID) + review, err := models.GetReviewByID(ctx, reviewID) if err != nil { return } diff --git a/services/pull/update.go b/services/pull/update.go index 3c5c1c048c..0ab8ffcd7d 100644 --- a/services/pull/update.go +++ b/services/pull/update.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -83,7 +84,7 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *models.PullRequest, user * if user == nil { return false, false, nil } - headRepoPerm, err := models.GetUserRepoPermission(ctx, pull.HeadRepo, user) + headRepoPerm, err := access_model.GetUserRepoPermission(ctx, pull.HeadRepo, user) if err != nil { return false, false, err } @@ -115,7 +116,7 @@ func IsUserAllowedToUpdate(ctx context.Context, pull *models.PullRequest, user * return false, false, nil } - baseRepoPerm, err := models.GetUserRepoPermission(ctx, pull.BaseRepo, user) + baseRepoPerm, err := access_model.GetUserRepoPermission(ctx, pull.BaseRepo, user) if err != nil { return false, false, err } diff --git a/services/release/release.go b/services/release/release.go index 0372e3a690..b2cbceb12d 100644 --- a/services/release/release.go +++ b/services/release/release.go @@ -112,10 +112,10 @@ func createTag(gitRepo *git.Repository, rel *models.Release, msg string) (bool, // CreateRelease creates a new release of repository. func CreateRelease(gitRepo *git.Repository, rel *models.Release, attachmentUUIDs []string, msg string) error { - isExist, err := models.IsReleaseExist(rel.RepoID, rel.TagName) + has, err := models.IsReleaseExist(gitRepo.Ctx, rel.RepoID, rel.TagName) if err != nil { return err - } else if isExist { + } else if has { return models.ErrReleaseAlreadyExist{ TagName: rel.TagName, } @@ -126,7 +126,7 @@ func CreateRelease(gitRepo *git.Repository, rel *models.Release, attachmentUUIDs } rel.LowerTagName = strings.ToLower(rel.TagName) - if err = models.InsertRelease(rel); err != nil { + if err = db.Insert(gitRepo.Ctx, rel); err != nil { return err } @@ -143,10 +143,10 @@ func CreateRelease(gitRepo *git.Repository, rel *models.Release, attachmentUUIDs // CreateNewTag creates a new repository tag func CreateNewTag(ctx context.Context, doer *user_model.User, repo *repo_model.Repository, commit, tagName, msg string) error { - isExist, err := models.IsReleaseExist(repo.ID, tagName) + has, err := models.IsReleaseExist(ctx, repo.ID, tagName) if err != nil { return err - } else if isExist { + } else if has { return models.ErrTagAlreadyExists{ TagName: tagName, } @@ -174,11 +174,7 @@ func CreateNewTag(ctx context.Context, doer *user_model.User, repo *repo_model.R return err } - if err = models.InsertRelease(rel); err != nil { - return err - } - - return err + return db.Insert(ctx, rel) } // UpdateRelease updates information, attachments of a release and will create tag if it's not a draft and tag not exist. @@ -286,12 +282,12 @@ func UpdateRelease(doer *user_model.User, gitRepo *git.Repository, rel *models.R // DeleteReleaseByID deletes a release and corresponding Git tag by given ID. func DeleteReleaseByID(ctx context.Context, id int64, doer *user_model.User, delTag bool) error { - rel, err := models.GetReleaseByID(id) + rel, err := models.GetReleaseByID(ctx, id) if err != nil { return fmt.Errorf("GetReleaseByID: %v", err) } - repo, err := repo_model.GetRepositoryByID(rel.RepoID) + repo, err := repo_model.GetRepositoryByIDCtx(ctx, rel.RepoID) if err != nil { return fmt.Errorf("GetRepositoryByID: %v", err) } diff --git a/services/release/release_test.go b/services/release/release_test.go index 19d985491f..0f5b74f70d 100644 --- a/services/release/release_test.go +++ b/services/release/release_test.go @@ -11,6 +11,7 @@ import ( "time" "code.gitea.io/gitea/models" + "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" @@ -161,7 +162,7 @@ func TestRelease_Update(t *testing.T) { time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Note = "Changed note" assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) - release, err = models.GetReleaseByID(release.ID) + release, err = models.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -185,7 +186,7 @@ func TestRelease_Update(t *testing.T) { time.Sleep(2 * time.Second) // sleep 2 seconds to ensure a different timestamp release.Title = "Changed title" assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) - release, err = models.GetReleaseByID(release.ID) + release, err = models.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Less(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -210,7 +211,7 @@ func TestRelease_Update(t *testing.T) { release.Title = "Changed title" release.Note = "Changed note" assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) - release, err = models.GetReleaseByID(release.ID) + release, err = models.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Equal(t, int64(releaseCreatedUnix), int64(release.CreatedUnix)) @@ -235,7 +236,7 @@ func TestRelease_Update(t *testing.T) { tagName := release.TagName assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, nil, nil)) - release, err = models.GetReleaseByID(release.ID) + release, err = models.GetReleaseByID(db.DefaultContext, release.ID) assert.NoError(t, err) assert.Equal(t, tagName, release.TagName) @@ -248,7 +249,7 @@ func TestRelease_Update(t *testing.T) { assert.NoError(t, err) assert.NoError(t, UpdateRelease(user, gitRepo, release, []string{attach.UUID}, nil, nil)) - assert.NoError(t, models.GetReleaseAttachments(release)) + assert.NoError(t, models.GetReleaseAttachments(db.DefaultContext, release)) assert.Len(t, release.Attachments, 1) assert.EqualValues(t, attach.UUID, release.Attachments[0].UUID) assert.EqualValues(t, release.ID, release.Attachments[0].ReleaseID) @@ -259,7 +260,7 @@ func TestRelease_Update(t *testing.T) { attach.UUID: "test2.txt", })) release.Attachments = nil - assert.NoError(t, models.GetReleaseAttachments(release)) + assert.NoError(t, models.GetReleaseAttachments(db.DefaultContext, release)) assert.Len(t, release.Attachments, 1) assert.EqualValues(t, attach.UUID, release.Attachments[0].UUID) assert.EqualValues(t, release.ID, release.Attachments[0].ReleaseID) @@ -268,7 +269,7 @@ func TestRelease_Update(t *testing.T) { // delete the attachment assert.NoError(t, UpdateRelease(user, gitRepo, release, nil, []string{attach.UUID}, nil)) release.Attachments = nil - assert.NoError(t, models.GetReleaseAttachments(release)) + assert.NoError(t, models.GetReleaseAttachments(db.DefaultContext, release)) assert.Empty(t, release.Attachments) } diff --git a/services/repository/adopt.go b/services/repository/adopt.go index b287d94f9d..48f049cd28 100644 --- a/services/repository/adopt.go +++ b/services/repository/adopt.go @@ -73,7 +73,7 @@ func AdoptRepository(doer, u *user_model.User, opts models.CreateRepoOptions) (* if err := adoptRepository(ctx, repoPath, doer, repo, opts); err != nil { return fmt.Errorf("createDelegateHooks: %v", err) } - if err := models.CheckDaemonExportOK(ctx, repo); err != nil { + if err := repo_module.CheckDaemonExportOK(ctx, repo); err != nil { return fmt.Errorf("checkDaemonExportOK: %v", err) } @@ -182,7 +182,7 @@ func adoptRepository(ctx context.Context, repoPath string, u *user_model.User, r } } - if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil { + if err = repo_module.UpdateRepository(ctx, repo, false); err != nil { return fmt.Errorf("updateRepository: %v", err) } @@ -208,7 +208,7 @@ func DeleteUnadoptedRepository(doer, u *user_model.User, repoName string) error } } - if exist, err := repo_model.IsRepositoryExist(u, repoName); err != nil { + if exist, err := repo_model.IsRepositoryExist(db.DefaultContext, u, repoName); err != nil { return err } else if exist { return repo_model.ErrRepoAlreadyExist{ @@ -238,7 +238,7 @@ func checkUnadoptedRepositories(userName string, repoNamesToCheck []string, unad if len(repoNamesToCheck) == 0 { return nil } - ctxUser, err := user_model.GetUserByName(userName) + ctxUser, err := user_model.GetUserByName(db.DefaultContext, userName) if err != nil { if user_model.IsErrUserNotExist(err) { log.Debug("Missing user: %s", userName) @@ -246,7 +246,7 @@ func checkUnadoptedRepositories(userName string, repoNamesToCheck []string, unad } return err } - repos, _, err := models.GetUserRepositories(&models.SearchRepoOptions{ + repos, _, err := repo_model.GetUserRepositories(&repo_model.SearchRepoOptions{ Actor: ctxUser, Private: true, ListOptions: db.ListOptions{ diff --git a/services/repository/avatar.go b/services/repository/avatar.go index f51a312e17..dcf04c7e54 100644 --- a/services/repository/avatar.go +++ b/services/repository/avatar.go @@ -44,7 +44,7 @@ func UploadAvatar(repo *repo_model.Repository, data []byte) error { // Users can upload the same image to other repo - prefix it with ID // Then repo will be removed - only it avatar file will be removed repo.Avatar = newAvatar - if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "avatar"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, repo, "avatar"); err != nil { return fmt.Errorf("UploadAvatar: Update repository avatar: %v", err) } @@ -83,7 +83,7 @@ func DeleteAvatar(repo *repo_model.Repository) error { defer committer.Close() repo.Avatar = "" - if err := repo_model.UpdateRepositoryColsCtx(ctx, repo, "avatar"); err != nil { + if err := repo_model.UpdateRepositoryCols(ctx, repo, "avatar"); err != nil { return fmt.Errorf("DeleteAvatar: Update repository avatar: %v", err) } @@ -117,5 +117,5 @@ func generateAvatar(ctx context.Context, templateRepo, generateRepo *repo_model. return err } - return repo_model.UpdateRepositoryColsCtx(ctx, generateRepo, "avatar") + return repo_model.UpdateRepositoryCols(ctx, generateRepo, "avatar") } diff --git a/services/repository/check.go b/services/repository/check.go index 6fb86d0dc3..17bdf2fac1 100644 --- a/services/repository/check.go +++ b/services/repository/check.go @@ -17,6 +17,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" + repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/util" "xorm.io/builder" @@ -89,7 +90,7 @@ func GitGcRepos(ctx context.Context, timeout time.Duration, args ...string) erro } // Now update the size of the repository - if err := models.UpdateRepoSize(ctx, repo); err != nil { + 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 = admin_model.CreateRepositoryNotice(desc); err != nil { diff --git a/services/repository/files/patch.go b/services/repository/files/patch.go index 240cb4fe2c..73464f31f3 100644 --- a/services/repository/files/patch.go +++ b/services/repository/files/patch.go @@ -66,7 +66,7 @@ func (opts *ApplyDiffPatchOptions) Validate(ctx context.Context, repo *repo_mode return err } } else { - protectedBranch, err := models.GetProtectedBranchBy(repo.ID, opts.OldBranch) + protectedBranch, err := models.GetProtectedBranchBy(ctx, repo.ID, opts.OldBranch) if err != nil { return err } diff --git a/services/repository/files/update.go b/services/repository/files/update.go index 2cb40aac47..a093ee5da7 100644 --- a/services/repository/files/update.go +++ b/services/repository/files/update.go @@ -462,7 +462,7 @@ func CreateOrUpdateRepoFile(ctx context.Context, repo *repo_model.Repository, do // VerifyBranchProtection verify the branch protection for modifying the given treePath on the given branch func VerifyBranchProtection(ctx context.Context, repo *repo_model.Repository, doer *user_model.User, branchName, treePath string) error { - protectedBranch, err := models.GetProtectedBranchBy(repo.ID, branchName) + protectedBranch, err := models.GetProtectedBranchBy(ctx, repo.ID, branchName) if err != nil { return err } diff --git a/services/repository/fork.go b/services/repository/fork.go index a2ef75bbd0..f4888cba1d 100644 --- a/services/repository/fork.go +++ b/services/repository/fork.go @@ -96,7 +96,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork return err } - if err = models.IncrementRepoForkNum(txCtx, opts.BaseRepo.ID); err != nil { + if err = repo_model.IncrementRepoForkNum(txCtx, opts.BaseRepo.ID); err != nil { return err } @@ -116,7 +116,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork return fmt.Errorf("git clone: %v", err) } - if err := models.CheckDaemonExportOK(txCtx, repo); err != nil { + if err := repo_module.CheckDaemonExportOK(txCtx, repo); err != nil { return fmt.Errorf("checkDaemonExportOK: %v", err) } @@ -139,7 +139,7 @@ func ForkRepository(ctx context.Context, doer, owner *user_model.User, opts Fork } // even if below operations failed, it could be ignored. And they will be retried - if err := models.UpdateRepoSize(ctx, repo); err != nil { + if err := repo_module.UpdateRepoSize(ctx, repo); err != nil { log.Error("Failed to update size for repository: %v", err) } if err := repo_model.CopyLanguageStat(opts.BaseRepo, repo); err != nil { @@ -173,7 +173,7 @@ func ConvertForkToNormalRepository(repo *repo_model.Repository) error { return nil } - if err := models.DecrementRepoForkNum(ctx, repo.ForkID); err != nil { + if err := repo_model.DecrementRepoForkNum(ctx, repo.ForkID); err != nil { log.Error("Unable to decrement repo fork num for old root repo %d of repository %-v whilst converting from fork. Error: %v", repo.ForkID, repo, err) return err } @@ -181,7 +181,7 @@ func ConvertForkToNormalRepository(repo *repo_model.Repository) error { repo.IsFork = false repo.ForkID = 0 - if err := models.UpdateRepositoryCtx(ctx, repo, false); err != nil { + if err := repo_module.UpdateRepository(ctx, repo, false); err != nil { log.Error("Unable to update repository %-v whilst converting from fork. Error: %v", repo, err) return err } diff --git a/services/repository/hooks.go b/services/repository/hooks.go index 67931ffcb6..45a031f38e 100644 --- a/services/repository/hooks.go +++ b/services/repository/hooks.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" @@ -84,3 +85,29 @@ func GenerateGitHooks(ctx context.Context, templateRepo, generateRepo *repo_mode } return nil } + +// GenerateWebhooks generates webhooks from a template repository +func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { + templateWebhooks, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{RepoID: templateRepo.ID}) + if err != nil { + return err + } + + ws := make([]*webhook.Webhook, 0, len(templateWebhooks)) + for _, templateWebhook := range templateWebhooks { + ws = append(ws, &webhook.Webhook{ + RepoID: generateRepo.ID, + URL: templateWebhook.URL, + HTTPMethod: templateWebhook.HTTPMethod, + ContentType: templateWebhook.ContentType, + Secret: templateWebhook.Secret, + HookEvent: templateWebhook.HookEvent, + IsActive: templateWebhook.IsActive, + Type: templateWebhook.Type, + OrgID: templateWebhook.OrgID, + Events: templateWebhook.Events, + Meta: templateWebhook.Meta, + }) + } + return webhook.CreateWebhooks(ctx, ws) +} diff --git a/services/repository/push.go b/services/repository/push.go index 4eb52c18c2..b6741c5ab4 100644 --- a/services/repository/push.go +++ b/services/repository/push.go @@ -95,7 +95,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } defer gitRepo.Close() - if err = models.UpdateRepoSize(ctx, repo); err != nil { + if err = repo_module.UpdateRepoSize(ctx, repo); err != nil { log.Error("Failed to update size for repository: %v", err) } @@ -181,7 +181,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } } // Update the is empty and default_branch columns - if err := repo_model.UpdateRepositoryCols(repo, "default_branch", "is_empty"); err != nil { + if err := repo_model.UpdateRepositoryCols(db.DefaultContext, repo, "default_branch", "is_empty"); err != nil { return fmt.Errorf("UpdateRepositoryCols: %v", err) } } @@ -269,7 +269,7 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error { } // Even if user delete a branch on a repository which he didn't watch, he will be watch that. - if err = repo_model.WatchIfAuto(opts.PusherID, repo.ID, true); err != nil { + if err = repo_model.WatchIfAuto(db.DefaultContext, opts.PusherID, repo.ID, true); err != nil { log.Warn("Fail to perform auto watch on user %v for repo %v: %v", opts.PusherID, repo.ID, err) } } else { @@ -399,7 +399,7 @@ func pushUpdateAddTags(ctx context.Context, repo *repo_model.Repository, gitRepo } if len(newReleases) > 0 { - if err = models.InsertReleasesContext(ctx, newReleases); err != nil { + if err = db.Insert(ctx, newReleases); err != nil { return fmt.Errorf("Insert: %v", err) } } diff --git a/services/repository/repository.go b/services/repository/repository.go index 6799ca586e..6848eda101 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/organization" packages_model "code.gitea.io/gitea/models/packages" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/notification" @@ -85,3 +86,42 @@ func Init() error { admin_model.RemoveAllWithNotice(db.DefaultContext, "Clean up temporary repositories", repo_module.LocalCopyPath()) return initPushQueue() } + +// UpdateRepository updates a repository +func UpdateRepository(repo *repo_model.Repository, visibilityChanged bool) (err error) { + ctx, committer, err := db.TxContext() + if err != nil { + return err + } + defer committer.Close() + + if err = repo_module.UpdateRepository(ctx, repo, visibilityChanged); err != nil { + return fmt.Errorf("updateRepository: %v", err) + } + + return committer.Commit() +} + +// LinkedRepository returns the linked repo if any +func LinkedRepository(a *repo_model.Attachment) (*repo_model.Repository, unit.Type, error) { + if a.IssueID != 0 { + iss, err := models.GetIssueByID(a.IssueID) + if err != nil { + return nil, unit.TypeIssues, err + } + repo, err := repo_model.GetRepositoryByID(iss.RepoID) + unitType := unit.TypeIssues + if iss.IsPull { + unitType = unit.TypePullRequests + } + return repo, unitType, err + } else if a.ReleaseID != 0 { + rel, err := models.GetReleaseByID(db.DefaultContext, a.ReleaseID) + if err != nil { + return nil, unit.TypeReleases, err + } + repo, err := repo_model.GetRepositoryByID(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 new file mode 100644 index 0000000000..e0ffcac3cc --- /dev/null +++ b/services/repository/repository_test.go @@ -0,0 +1,43 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repository + +import ( + "testing" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestLinkedRepository(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + testCases := []struct { + name string + attachID int64 + expectedRepo *repo_model.Repository + expectedUnitType unit.Type + }{ + {"LinkedIssue", 1, &repo_model.Repository{ID: 1}, unit.TypeIssues}, + {"LinkedComment", 3, &repo_model.Repository{ID: 1}, unit.TypePullRequests}, + {"LinkedRelease", 9, &repo_model.Repository{ID: 1}, unit.TypeReleases}, + {"Notlinked", 10, nil, -1}, + } + for _, tc := range testCases { + 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) + assert.NoError(t, err) + if tc.expectedRepo != nil { + assert.Equal(t, tc.expectedRepo.ID, repo.ID) + } + assert.Equal(t, tc.expectedUnitType, unitType) + }) + } +} diff --git a/services/repository/review.go b/services/repository/review.go new file mode 100644 index 0000000000..9e8012978e --- /dev/null +++ b/services/repository/review.go @@ -0,0 +1,24 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repository + +import ( + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" + "code.gitea.io/gitea/models/perm" + repo_model "code.gitea.io/gitea/models/repo" +) + +// GetReviewerTeams get all teams can be requested to review +func GetReviewerTeams(repo *repo_model.Repository) ([]*organization.Team, error) { + if err := repo.GetOwner(db.DefaultContext); err != nil { + return nil, err + } + if !repo.Owner.IsOrganization() { + return nil, nil + } + + return organization.GetTeamsWithAccessToRepo(db.DefaultContext, repo.OwnerID, repo.ID, perm.AccessModeRead) +} diff --git a/services/repository/review_test.go b/services/repository/review_test.go new file mode 100644 index 0000000000..640657d1dd --- /dev/null +++ b/services/repository/review_test.go @@ -0,0 +1,28 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package repository + +import ( + "testing" + + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unittest" + + "github.com/stretchr/testify/assert" +) + +func TestRepoGetReviewerTeams(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository) + teams, err := GetReviewerTeams(repo2) + assert.NoError(t, err) + assert.Empty(t, teams) + + repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) + teams, err = GetReviewerTeams(repo3) + assert.NoError(t, err) + assert.Len(t, teams, 2) +} diff --git a/services/repository/template.go b/services/repository/template.go index 28fa1523a5..6a1bfaff5b 100644 --- a/services/repository/template.go +++ b/services/repository/template.go @@ -16,8 +16,27 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" ) +// GenerateIssueLabels generates issue labels from a template repository +func GenerateIssueLabels(ctx context.Context, templateRepo, generateRepo *repo_model.Repository) error { + templateLabels, err := models.GetLabelsByRepoID(ctx, templateRepo.ID, "", db.ListOptions{}) + if err != nil { + return err + } + + newLabels := make([]*models.Label, 0, len(templateLabels)) + for _, templateLabel := range templateLabels { + newLabels = append(newLabels, &models.Label{ + RepoID: generateRepo.ID, + Name: templateLabel.Name, + Description: templateLabel.Description, + Color: templateLabel.Color, + }) + } + return db.Insert(ctx, newLabels) +} + // GenerateRepository generates a repository from a template -func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.Repository, opts models.GenerateRepoOptions) (_ *repo_model.Repository, err error) { +func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.Repository, opts repo_module.GenerateRepoOptions) (_ *repo_model.Repository, err error) { if !doer.IsAdmin && !owner.CanCreateRepo() { return nil, repo_model.ErrReachLimitOfRepo{ Limit: owner.MaxRepoCreation, @@ -54,7 +73,7 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R // Webhooks if opts.Webhooks { - if err = models.GenerateWebhooks(ctx, templateRepo, generateRepo); err != nil { + if err = GenerateWebhooks(ctx, templateRepo, generateRepo); err != nil { return err } } @@ -68,7 +87,7 @@ func GenerateRepository(doer, owner *user_model.User, templateRepo *repo_model.R // Issue Labels if opts.IssueLabels { - if err = models.GenerateIssueLabels(ctx, templateRepo, generateRepo); err != nil { + if err = GenerateIssueLabels(ctx, templateRepo, generateRepo); err != nil { return err } } diff --git a/services/repository/transfer.go b/services/repository/transfer.go index 3feeb68f22..ae15383240 100644 --- a/services/repository/transfer.go +++ b/services/repository/transfer.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/log" @@ -105,7 +106,7 @@ func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.R } // In case the new owner would not have sufficient access to the repo, give access rights for read - hasAccess, err := models.HasAccess(newOwner.ID, repo) + hasAccess, err := access_model.HasAccess(db.DefaultContext, newOwner.ID, repo) if err != nil { return err } @@ -113,7 +114,7 @@ func StartRepositoryTransfer(doer, newOwner *user_model.User, repo *repo_model.R if err := models.AddCollaborator(repo, newOwner); err != nil { return err } - if err := models.ChangeCollaborationAccessMode(repo, newOwner.ID, perm.AccessModeRead); err != nil { + if err := repo_model.ChangeCollaborationAccessMode(repo, newOwner.ID, perm.AccessModeRead); err != nil { return err } } diff --git a/services/repository/transfer_test.go b/services/repository/transfer_test.go index 1081c76c7e..8be8c5353d 100644 --- a/services/repository/transfer_test.go +++ b/services/repository/transfer_test.go @@ -9,7 +9,9 @@ import ( "testing" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" + access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" @@ -65,13 +67,13 @@ func TestStartRepositoryTransferSetPermission(t *testing.T) { repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}).(*repo_model.Repository) repo.Owner = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) - hasAccess, err := models.HasAccess(recipient.ID, repo) + hasAccess, err := access_model.HasAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) assert.False(t, hasAccess) assert.NoError(t, StartRepositoryTransfer(doer, recipient, repo, nil)) - hasAccess, err = models.HasAccess(recipient.ID, repo) + hasAccess, err = access_model.HasAccess(db.DefaultContext, recipient.ID, repo) assert.NoError(t, err) assert.True(t, hasAccess) diff --git a/services/user/user.go b/services/user/user.go index d41fc42493..4db4d7ca17 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -44,7 +44,7 @@ func DeleteUser(u *user_model.User) error { // cannot perform delete operation. // Check ownership of repository. - count, err := repo_model.GetRepositoryCount(ctx, u.ID) + count, err := repo_model.CountRepositories(ctx, repo_model.CountRepositoryOptions{OwnerID: u.ID}) if err != nil { return fmt.Errorf("GetRepositoryCount: %v", err) } else if count > 0 { @@ -78,7 +78,7 @@ func DeleteUser(u *user_model.User) error { if err = asymkey_model.RewriteAllPublicKeys(); err != nil { return err } - if err = asymkey_model.RewriteAllPrincipalKeys(); err != nil { + if err = asymkey_model.RewriteAllPrincipalKeys(db.DefaultContext); err != nil { return err } diff --git a/services/webhook/general.go b/services/webhook/general.go index 5080cf98dc..e8006fabae 100644 --- a/services/webhook/general.go +++ b/services/webhook/general.go @@ -141,7 +141,7 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm func getReleasePayloadInfo(p *api.ReleasePayload, linkFormatter linkFormatter, withSender bool) (text string, color int) { repoLink := linkFormatter(p.Repository.HTMLURL, p.Repository.FullName) - refLink := linkFormatter(p.Repository.HTMLURL+"/src/"+util.PathEscapeSegments(p.Release.TagName), p.Release.TagName) + refLink := linkFormatter(p.Repository.HTMLURL+"/releases/tag/"+util.PathEscapeSegments(p.Release.TagName), p.Release.TagName) switch p.Action { case api.HookReleasePublished: diff --git a/services/webhook/matrix_test.go b/services/webhook/matrix_test.go index 3cc7c7518f..34196aedf0 100644 --- a/services/webhook/matrix_test.go +++ b/services/webhook/matrix_test.go @@ -165,8 +165,8 @@ func TestMatrixPayload(t *testing.T) { require.NotNil(t, pl) require.IsType(t, &MatrixPayloadUnsafe{}, pl) - assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Release created: [v1.0](http://localhost:3000/test/repo/src/v1.0) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body) - assert.Equal(t, `[test/repo] Release created: v1.0 by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody) + assert.Equal(t, "[[test/repo](http://localhost:3000/test/repo)] Release created: [v1.0](http://localhost:3000/test/repo/releases/tag/v1.0) by [user1](https://try.gitea.io/user1)", pl.(*MatrixPayloadUnsafe).Body) + assert.Equal(t, `[test/repo] Release created: v1.0 by user1`, pl.(*MatrixPayloadUnsafe).FormattedBody) }) } diff --git a/services/webhook/slack_test.go b/services/webhook/slack_test.go index 1fa7777328..8278afb69a 100644 --- a/services/webhook/slack_test.go +++ b/services/webhook/slack_test.go @@ -154,7 +154,7 @@ func TestSlackPayload(t *testing.T) { require.NotNil(t, pl) require.IsType(t, &SlackPayload{}, pl) - assert.Equal(t, "[] Release created: by ", pl.(*SlackPayload).Text) + assert.Equal(t, "[] Release created: by ", pl.(*SlackPayload).Text) }) } diff --git a/services/webhook/telegram_test.go b/services/webhook/telegram_test.go index 6a3682847c..2f83090166 100644 --- a/services/webhook/telegram_test.go +++ b/services/webhook/telegram_test.go @@ -154,7 +154,7 @@ func TestTelegramPayload(t *testing.T) { require.NotNil(t, pl) require.IsType(t, &TelegramPayload{}, pl) - assert.Equal(t, `[test/repo] Release created: v1.0 by user1`, pl.(*TelegramPayload).Message) + assert.Equal(t, `[test/repo] Release created: v1.0 by user1`, pl.(*TelegramPayload).Message) }) } diff --git a/services/webhook/webhook.go b/services/webhook/webhook.go index b15b8173f5..68cfe147aa 100644 --- a/services/webhook/webhook.go +++ b/services/webhook/webhook.go @@ -5,10 +5,12 @@ package webhook import ( + "context" "fmt" "strconv" "strings" + "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" webhook_model "code.gitea.io/gitea/models/webhook" "code.gitea.io/gitea/modules/git" @@ -218,15 +220,15 @@ func prepareWebhook(w *webhook_model.Webhook, repo *repo_model.Repository, event // PrepareWebhooks adds new webhooks to task queue for given payload. func PrepareWebhooks(repo *repo_model.Repository, event webhook_model.HookEventType, p api.Payloader) error { - if err := prepareWebhooks(repo, event, p); err != nil { + if err := prepareWebhooks(db.DefaultContext, repo, event, p); err != nil { return err } return addToTask(repo.ID) } -func prepareWebhooks(repo *repo_model.Repository, event webhook_model.HookEventType, p api.Payloader) error { - ws, err := webhook_model.ListWebhooksByOpts(&webhook_model.ListWebhookOptions{ +func prepareWebhooks(ctx context.Context, repo *repo_model.Repository, event webhook_model.HookEventType, p api.Payloader) error { + ws, err := webhook_model.ListWebhooksByOpts(ctx, &webhook_model.ListWebhookOptions{ RepoID: repo.ID, IsActive: util.OptionalBoolTrue, }) @@ -237,7 +239,7 @@ func prepareWebhooks(repo *repo_model.Repository, event webhook_model.HookEventT // check if repo belongs to org and append additional webhooks if repo.MustOwner().IsOrganization() { // get hooks for org - orgHooks, err := webhook_model.ListWebhooksByOpts(&webhook_model.ListWebhookOptions{ + orgHooks, err := webhook_model.ListWebhooksByOpts(ctx, &webhook_model.ListWebhookOptions{ OrgID: repo.OwnerID, IsActive: util.OptionalBoolTrue, }) @@ -248,7 +250,7 @@ func prepareWebhooks(repo *repo_model.Repository, event webhook_model.HookEventT } // Add any admin-defined system webhooks - systemHooks, err := webhook_model.GetSystemWebhooks(util.OptionalBoolTrue) + systemHooks, err := webhook_model.GetSystemWebhooks(ctx, util.OptionalBoolTrue) if err != nil { return fmt.Errorf("GetSystemWebhooks: %v", err) } diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl index b4a703e413..f1b4da35eb 100644 --- a/templates/admin/auth/list.tmpl +++ b/templates/admin/auth/list.tmpl @@ -6,7 +6,7 @@

{{.i18n.Tr "admin.auths.auth_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})

diff --git a/templates/admin/base/search.tmpl b/templates/admin/base/search.tmpl index 98fd3f4a07..4ec62c162c 100644 --- a/templates/admin/base/search.tmpl +++ b/templates/admin/base/search.tmpl @@ -18,6 +18,6 @@
- +
diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index 277c777a89..92444efbd8 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -25,7 +25,7 @@
- +
diff --git a/templates/admin/org/list.tmpl b/templates/admin/org/list.tmpl index 0782ef64e9..1cfd3e79e1 100644 --- a/templates/admin/org/list.tmpl +++ b/templates/admin/org/list.tmpl @@ -6,7 +6,7 @@

{{.i18n.Tr "admin.orgs.org_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})

diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index df89d8bed2..6b19c09a1e 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -24,7 +24,7 @@ - +
diff --git a/templates/admin/process.tmpl b/templates/admin/process.tmpl index c44300dbb7..51bf1d48f9 100644 --- a/templates/admin/process.tmpl +++ b/templates/admin/process.tmpl @@ -1,7 +1,7 @@

{{.i18n.Tr "admin.monitor.process"}}

diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index da05bfab96..96f04b8fe4 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -6,7 +6,7 @@

{{.i18n.Tr "admin.repos.repo_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})

diff --git a/templates/admin/repo/search.tmpl b/templates/admin/repo/search.tmpl index 8b1deb9134..e51d50936b 100644 --- a/templates/admin/repo/search.tmpl +++ b/templates/admin/repo/search.tmpl @@ -24,6 +24,6 @@
- +
diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl index 345f59401a..cd04891d7e 100644 --- a/templates/admin/repo/unadopted.tmpl +++ b/templates/admin/repo/unadopted.tmpl @@ -6,7 +6,7 @@

{{.i18n.Tr "admin.repos.unadopted"}}

@@ -14,7 +14,7 @@
- +
diff --git a/templates/admin/stacktrace.tmpl b/templates/admin/stacktrace.tmpl index 68dfbe066d..5c3993e234 100644 --- a/templates/admin/stacktrace.tmpl +++ b/templates/admin/stacktrace.tmpl @@ -6,7 +6,7 @@

{{.i18n.Tr "admin.monitor.stacktrace"}}: {{.i18n.Tr "admin.monitor.goroutines" .GoroutineCount}}

diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl index 755e4436f8..963a440e29 100644 --- a/templates/admin/user/list.tmpl +++ b/templates/admin/user/list.tmpl @@ -6,7 +6,7 @@

{{.i18n.Tr "admin.users.user_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})

@@ -56,7 +56,7 @@
- +
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index f3dcfe8429..e75531746a 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -4,13 +4,13 @@ {{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}} {{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}} - + - - - + + + - + {{if .GoGetImport}} @@ -19,12 +19,10 @@ {{end}} - + - {{template "base/head_script" .}} - {{if .PageIsUserProfile}} - - - - + + + + {{if .Owner.Description}} {{end}} {{else if .Repository}} {{if .Issue}} - - + + {{if .Issue.Content}} - + {{end}} {{else}} - - + + {{if .Repository.Description}} - + {{end}} {{end}} - + {{if .Repository.AvatarLink}} - + {{else}} - + {{end}} {{else}} - - - + + + {{end}} - + {{if .IsSigned }} {{ if ne .SignedUser.Theme "gitea" }} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 5ce1d0b888..37a579142c 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -1,7 +1,7 @@
diff --git a/templates/explore/repo_search.tmpl b/templates/explore/repo_search.tmpl index bc4572dfcd..3d45305df3 100644 --- a/templates/explore/repo_search.tmpl +++ b/templates/explore/repo_search.tmpl @@ -27,7 +27,7 @@
- +
diff --git a/templates/explore/search.tmpl b/templates/explore/search.tmpl index 245cc9f345..2c1687f60e 100644 --- a/templates/explore/search.tmpl +++ b/templates/explore/search.tmpl @@ -19,7 +19,7 @@
- +
diff --git a/templates/org/home.tmpl b/templates/org/home.tmpl index 1fe0b035e6..a49029d4d5 100644 --- a/templates/org/home.tmpl +++ b/templates/org/home.tmpl @@ -78,7 +78,7 @@
{{if .IsOrganizationOwner}} {{end}} {{end}} diff --git a/templates/org/team/sidebar.tmpl b/templates/org/team/sidebar.tmpl index 8adee3cc7a..d597d1349f 100644 --- a/templates/org/team/sidebar.tmpl +++ b/templates/org/team/sidebar.tmpl @@ -12,7 +12,7 @@
{{$.CsrfTokenHtml}} - +
{{end}}
diff --git a/templates/org/team/teams.tmpl b/templates/org/team/teams.tmpl index 9165a62bca..49407ef194 100644 --- a/templates/org/team/teams.tmpl +++ b/templates/org/team/teams.tmpl @@ -25,7 +25,7 @@ {{else if $.IsOrganizationOwner}}
{{$.CsrfTokenHtml}} - +
{{end}}
diff --git a/templates/package/shared/list.tmpl b/templates/package/shared/list.tmpl index 9e6bf5ce9e..ce2b57e4a0 100644 --- a/templates/package/shared/list.tmpl +++ b/templates/package/shared/list.tmpl @@ -17,7 +17,7 @@ - +
diff --git a/templates/package/shared/versionlist.tmpl b/templates/package/shared/versionlist.tmpl index e2aa19cc8c..59f7cd1647 100644 --- a/templates/package/shared/versionlist.tmpl +++ b/templates/package/shared/versionlist.tmpl @@ -10,7 +10,7 @@ {{end}} - +
diff --git a/templates/repo/commit_page.tmpl b/templates/repo/commit_page.tmpl index f43050ad0e..1e62968363 100644 --- a/templates/repo/commit_page.tmpl +++ b/templates/repo/commit_page.tmpl @@ -17,16 +17,16 @@ {{$class = (printf "%s%s" $class " isWarning")}} {{end}} {{end}} -
-
+
+

{{RenderCommitMessage $.Context .Commit.Message $.RepoLink $.Repository.ComposeMetas}}{{template "repo/commit_statuses" dict "Status" .CommitStatus "Statuses" .CommitStatuses "root" $}}

{{if not $.PageIsWiki}}
- + {{.i18n.Tr "repo.diff.browse_source"}} {{if and ($.Permission.CanWrite $.UnitTypeCode) (not $.Repository.IsArchived) (not .IsDeleted)}}{{- /* */ -}} -