mirror of
https://github.com/go-gitea/gitea.git
synced 2025-04-08 17:05:45 +02:00
merge main
This commit is contained in:
commit
c14f7a75d6
@ -17,6 +17,7 @@ insert_final_newline = false
|
||||
|
||||
[templates/swagger/v1_json.tmpl]
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
|
||||
[templates/user/auth/oidc_wellknown.tmpl]
|
||||
indent_style = space
|
||||
|
@ -336,7 +336,7 @@ module.exports = {
|
||||
'@typescript-eslint/no-unsafe-unary-minus': [2],
|
||||
'@typescript-eslint/no-unused-expressions': [0],
|
||||
'@typescript-eslint/no-unused-vars': [2, {vars: 'all', args: 'all', caughtErrors: 'all', ignoreRestSiblings: false, argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_'}],
|
||||
'@typescript-eslint/no-use-before-define': [0],
|
||||
'@typescript-eslint/no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true, typedefs: false, enums: false, ignoreTypeReferences: true}],
|
||||
'@typescript-eslint/no-useless-constructor': [0],
|
||||
'@typescript-eslint/no-useless-empty-export': [0],
|
||||
'@typescript-eslint/no-wrapper-object-types': [2],
|
||||
@ -693,7 +693,7 @@ module.exports = {
|
||||
'no-unused-labels': [2],
|
||||
'no-unused-private-class-members': [2],
|
||||
'no-unused-vars': [0], // handled by @typescript-eslint/no-unused-vars
|
||||
'no-use-before-define': [2, {functions: false, classes: true, variables: true, allowNamedExports: true}],
|
||||
'no-use-before-define': [0], // handled by @typescript-eslint/no-use-before-define
|
||||
'no-use-extend-native/no-use-extend-native': [2],
|
||||
'no-useless-backreference': [2],
|
||||
'no-useless-call': [2],
|
||||
|
10
.github/labeler.yml
vendored
10
.github/labeler.yml
vendored
@ -41,7 +41,7 @@ modifies/internal:
|
||||
- ".dockerignore"
|
||||
- "docker/**"
|
||||
- ".editorconfig"
|
||||
- ".eslintrc.yaml"
|
||||
- ".eslintrc.cjs"
|
||||
- ".golangci.yml"
|
||||
- ".gitpod.yml"
|
||||
- ".markdownlint.yaml"
|
||||
@ -49,7 +49,7 @@ modifies/internal:
|
||||
- "stylelint.config.js"
|
||||
- ".yamllint.yaml"
|
||||
- ".github/**"
|
||||
- ".gitea/"
|
||||
- ".gitea/**"
|
||||
- ".devcontainer/**"
|
||||
- "build.go"
|
||||
- "build/**"
|
||||
@ -73,9 +73,9 @@ modifies/go:
|
||||
modifies/frontend:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- "**/*.js"
|
||||
- "**/*.ts"
|
||||
- "**/*.vue"
|
||||
- "*.js"
|
||||
- "*.ts"
|
||||
- "web_src/**"
|
||||
|
||||
docs-update-needed:
|
||||
- changed-files:
|
||||
|
9
.github/workflows/files-changed.yml
vendored
9
.github/workflows/files-changed.yml
vendored
@ -51,14 +51,16 @@ jobs:
|
||||
- "options/locale/locale_en-US.ini"
|
||||
|
||||
frontend:
|
||||
- "**/*.js"
|
||||
- "*.js"
|
||||
- "*.ts"
|
||||
- "web_src/**"
|
||||
- "tools/*.js"
|
||||
- "tools/*.ts"
|
||||
- "assets/emoji.json"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
- "Makefile"
|
||||
- ".eslintrc.yaml"
|
||||
- "stylelint.config.js"
|
||||
- ".eslintrc.cjs"
|
||||
- ".npmrc"
|
||||
|
||||
docs:
|
||||
@ -85,6 +87,7 @@ jobs:
|
||||
|
||||
swagger:
|
||||
- "templates/swagger/v1_json.tmpl"
|
||||
- "templates/swagger/v1_input.json"
|
||||
- "Makefile"
|
||||
- "package.json"
|
||||
- "package-lock.json"
|
||||
|
4
.github/workflows/release-tag-version.yml
vendored
4
.github/workflows/release-tag-version.yml
vendored
@ -88,9 +88,9 @@ jobs:
|
||||
# 1.2
|
||||
# 1.2.3
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{version}}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
@ -126,9 +126,9 @@ jobs:
|
||||
# 1.2
|
||||
# 1.2.3
|
||||
tags: |
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{version}}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
|
21
Makefile
21
Makefile
@ -165,10 +165,8 @@ ifdef DEPS_PLAYWRIGHT
|
||||
endif
|
||||
|
||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape}}/api/v1"|g
|
||||
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape}}/api/v1"|"basePath": "/api/v1"|g
|
||||
SWAGGER_SPEC_INPUT := templates/swagger/v1_input.json
|
||||
SWAGGER_EXCLUDE := code.gitea.io/sdk
|
||||
SWAGGER_NEWLINE_COMMAND := -e '$$a\'
|
||||
|
||||
TEST_MYSQL_HOST ?= mysql:3306
|
||||
TEST_MYSQL_DBNAME ?= testgitea
|
||||
@ -271,10 +269,8 @@ endif
|
||||
.PHONY: generate-swagger
|
||||
generate-swagger: $(SWAGGER_SPEC) ## generate the swagger spec from code comments
|
||||
|
||||
$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA)
|
||||
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
|
||||
$(SWAGGER_SPEC): $(GO_SOURCES_NO_BINDATA) $(SWAGGER_SPEC_INPUT)
|
||||
$(GO) run $(SWAGGER_PACKAGE) generate spec --exclude "$(SWAGGER_EXCLUDE)" --input "$(SWAGGER_SPEC_INPUT)" --output './$(SWAGGER_SPEC)'
|
||||
|
||||
.PHONY: swagger-check
|
||||
swagger-check: generate-swagger
|
||||
@ -287,9 +283,11 @@ swagger-check: generate-swagger
|
||||
|
||||
.PHONY: swagger-validate
|
||||
swagger-validate: ## check if the swagger spec is valid
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
|
||||
@# swagger "validate" requires that the "basePath" must start with a slash, but we are using Golang template "{{...}}"
|
||||
@$(SED_INPLACE) -E -e 's|"basePath":( *)"(.*)"|"basePath":\1"/\2"|g' './$(SWAGGER_SPEC)' # add a prefix slash to basePath
|
||||
@# FIXME: there are some warnings
|
||||
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
@$(SED_INPLACE) -E -e 's|"basePath":( *)"/(.*)"|"basePath":\1"\2"|g' './$(SWAGGER_SPEC)' # remove the prefix slash from basePath
|
||||
|
||||
.PHONY: checks
|
||||
checks: checks-frontend checks-backend ## run various consistency checks
|
||||
@ -380,6 +378,7 @@ lint-go-gopls: ## lint go files with gopls
|
||||
|
||||
.PHONY: lint-editorconfig
|
||||
lint-editorconfig:
|
||||
@echo "Running editorconfig check..."
|
||||
@$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) $(EDITORCONFIG_FILES)
|
||||
|
||||
.PHONY: lint-actions
|
||||
@ -471,7 +470,9 @@ tidy-check: tidy
|
||||
go-licenses: $(GO_LICENSE_FILE) ## regenerate go licenses
|
||||
|
||||
$(GO_LICENSE_FILE): go.mod go.sum
|
||||
-$(GO) run $(GO_LICENSES_PACKAGE) save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null
|
||||
@rm -rf $(GO_LICENSE_FILE)
|
||||
$(GO) install $(GO_LICENSES_PACKAGE)
|
||||
-GOOS=linux CGO_ENABLED=1 go-licenses save . --force --save_path=$(GO_LICENSE_TMP_DIR) 2>/dev/null
|
||||
$(GO) run build/generate-go-licenses.go $(GO_LICENSE_TMP_DIR) $(GO_LICENSE_FILE)
|
||||
@rm -rf $(GO_LICENSE_TMP_DIR)
|
||||
|
||||
|
@ -54,10 +54,6 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||
altTLSALPNPort = p
|
||||
}
|
||||
|
||||
// FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https"
|
||||
// Ideally it should migrate to AppDataPath write to "AppDataPath/https"
|
||||
certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
||||
magic := certmagic.NewDefault()
|
||||
// Try to use private CA root if provided, otherwise defaults to system's trust
|
||||
var certPool *x509.CertPool
|
||||
if setting.AcmeCARoot != "" {
|
||||
@ -67,7 +63,13 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||
log.Warn("Failed to parse CA Root certificate, using default CA trust: %v", err)
|
||||
}
|
||||
}
|
||||
myACME := certmagic.NewACMEIssuer(magic, certmagic.ACMEIssuer{
|
||||
// FIXME: this path is not right, it uses "AppWorkPath" incorrectly, and writes the data into "AppWorkPath/https"
|
||||
// Ideally it should migrate to AppDataPath write to "AppDataPath/https"
|
||||
// And one more thing, no idea why we should set the global default variables here
|
||||
// But it seems that the current ACME code needs these global variables to make renew work.
|
||||
// Otherwise, "renew" will use incorrect storage path
|
||||
certmagic.Default.Storage = &certmagic.FileStorage{Path: setting.AcmeLiveDirectory}
|
||||
certmagic.DefaultACME = certmagic.ACMEIssuer{
|
||||
CA: setting.AcmeURL,
|
||||
TrustedRoots: certPool,
|
||||
Email: setting.AcmeEmail,
|
||||
@ -77,8 +79,10 @@ func runACME(listenAddr string, m http.Handler) error {
|
||||
ListenHost: setting.HTTPAddr,
|
||||
AltTLSALPNPort: altTLSALPNPort,
|
||||
AltHTTPPort: altHTTPPort,
|
||||
})
|
||||
}
|
||||
|
||||
magic := certmagic.NewDefault()
|
||||
myACME := certmagic.NewACMEIssuer(magic, certmagic.DefaultACME)
|
||||
magic.Issuers = []certmagic.Issuer{myACME}
|
||||
|
||||
// this obtains certificates or renews them if necessary
|
||||
|
10
go.mod
10
go.mod
@ -8,7 +8,7 @@ go 1.24
|
||||
godebug x509negativeserial=1
|
||||
|
||||
require (
|
||||
code.gitea.io/actions-proto-go v0.4.0
|
||||
code.gitea.io/actions-proto-go v0.4.1
|
||||
code.gitea.io/gitea-vet v0.2.3
|
||||
code.gitea.io/sdk/gitea v0.20.0
|
||||
codeberg.org/gusted/mcaptcha v0.0.0-20220723083913-4f3072e1d570
|
||||
@ -24,7 +24,7 @@ require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.17.0
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358
|
||||
github.com/ProtonMail/go-crypto v1.1.5
|
||||
github.com/ProtonMail/go-crypto v1.1.6
|
||||
github.com/PuerkitoBio/goquery v1.10.2
|
||||
github.com/SaveTheRbtz/zstd-seekable-format-go/pkg v0.7.3
|
||||
github.com/alecthomas/chroma/v2 v2.15.0
|
||||
@ -117,10 +117,10 @@ require (
|
||||
github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
gitlab.com/gitlab-org/api/client-go v0.123.0
|
||||
golang.org/x/crypto v0.33.0
|
||||
golang.org/x/crypto v0.35.0
|
||||
golang.org/x/image v0.24.0
|
||||
golang.org/x/net v0.35.0
|
||||
golang.org/x/oauth2 v0.26.0
|
||||
golang.org/x/oauth2 v0.27.0
|
||||
golang.org/x/sync v0.11.0
|
||||
golang.org/x/sys v0.30.0
|
||||
golang.org/x/text v0.22.0
|
||||
@ -318,7 +318,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
||||
|
||||
replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0
|
||||
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.261.3
|
||||
replace github.com/nektos/act => gitea.com/gitea/act v0.261.4
|
||||
|
||||
// TODO: the only difference is in `PutObject`: the fork doesn't use `NewVerifyingReader(r, sha256.New(), oid, expectedSize)`, need to figure out why
|
||||
replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0
|
||||
|
19
go.sum
19
go.sum
@ -1,7 +1,7 @@
|
||||
cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I=
|
||||
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||
code.gitea.io/actions-proto-go v0.4.0 h1:OsPBPhodXuQnsspG1sQ4eRE1PeoZyofd7+i73zCwnsU=
|
||||
code.gitea.io/actions-proto-go v0.4.0/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
||||
code.gitea.io/actions-proto-go v0.4.1 h1:l0EYhjsgpUe/1VABo2eK7zcoNX2W44WOnb0MSLrKfls=
|
||||
code.gitea.io/actions-proto-go v0.4.1/go.mod h1:mn7Wkqz6JbnTOHQpot3yDeHx+O5C9EGhMEE+htvHBas=
|
||||
code.gitea.io/gitea-vet v0.2.3 h1:gdFmm6WOTM65rE8FUBTRzeQZYzXePKSSB1+r574hWwI=
|
||||
code.gitea.io/gitea-vet v0.2.3/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE=
|
||||
code.gitea.io/sdk/gitea v0.20.0 h1:Zm/QDwwZK1awoM4AxdjeAQbxolzx2rIP8dDfmKu+KoU=
|
||||
@ -16,8 +16,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg=
|
||||
git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs=
|
||||
gitea.com/gitea/act v0.261.3 h1:BhiYpGJQKGq0XMYYICCYAN4KnsEWHyLbA6dxhZwFcV4=
|
||||
gitea.com/gitea/act v0.261.3/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
|
||||
gitea.com/gitea/act v0.261.4 h1:Tf9eLlvsYFtKcpuxlMvf9yT3g4Hshb2Beqw6C1STuH8=
|
||||
gitea.com/gitea/act v0.261.4/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok=
|
||||
gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40=
|
||||
gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits=
|
||||
gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso=
|
||||
@ -71,8 +71,8 @@ github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSC
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
|
||||
github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v1.1.6 h1:ZcV+Ropw6Qn0AX9brlQLAUXfqLBc7Bl+f/DmNxpLfdw=
|
||||
github.com/ProtonMail/go-crypto v1.1.6/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/PuerkitoBio/goquery v1.10.2 h1:7fh2BdHcG6VFZsK7toXBT/Bh1z5Wmy8Q9MV9HqT2AM8=
|
||||
github.com/PuerkitoBio/goquery v1.10.2/go.mod h1:0guWGjcLu9AYC7C1GHnpysHy056u9aEkUHwhdnePMCU=
|
||||
github.com/RoaringBitmap/roaring v0.4.23/go.mod h1:D0gp8kJQgE1A4LQ5wFLggQEyvDi06Mq5mKs52e1TwOo=
|
||||
@ -831,8 +831,9 @@ golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliY
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
||||
golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
|
||||
golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
|
||||
golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
|
||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||
@ -868,8 +869,8 @@ golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/oauth2 v0.26.0 h1:afQXWNNaeC4nvZ0Ed9XvCCzXM6UHJG7iCg0W4fPqSBE=
|
||||
golang.org/x/oauth2 v0.26.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
|
||||
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
@ -454,6 +454,24 @@ func ActivityReadable(user, doer *user_model.User) bool {
|
||||
doer != nil && (doer.IsAdmin || user.ID == doer.ID)
|
||||
}
|
||||
|
||||
func FeedDateCond(opts GetFeedsOptions) builder.Cond {
|
||||
cond := builder.NewCond()
|
||||
if opts.Date == "" {
|
||||
return cond
|
||||
}
|
||||
|
||||
dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
|
||||
if err != nil {
|
||||
log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
|
||||
} else {
|
||||
dateHigh := dateLow.Add(86399000000000) // 23h59m59s
|
||||
|
||||
cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()})
|
||||
cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()})
|
||||
}
|
||||
return cond
|
||||
}
|
||||
|
||||
func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.Cond, error) {
|
||||
cond := builder.NewCond()
|
||||
|
||||
@ -534,17 +552,7 @@ func ActivityQueryCondition(ctx context.Context, opts GetFeedsOptions) (builder.
|
||||
cond = cond.And(builder.Eq{"is_deleted": false})
|
||||
}
|
||||
|
||||
if opts.Date != "" {
|
||||
dateLow, err := time.ParseInLocation("2006-01-02", opts.Date, setting.DefaultUILocation)
|
||||
if err != nil {
|
||||
log.Warn("Unable to parse %s, filter not applied: %v", opts.Date, err)
|
||||
} else {
|
||||
dateHigh := dateLow.Add(86399000000000) // 23h59m59s
|
||||
|
||||
cond = cond.And(builder.Gte{"`action`.created_unix": dateLow.Unix()})
|
||||
cond = cond.And(builder.Lte{"`action`.created_unix": dateHigh.Unix()})
|
||||
}
|
||||
}
|
||||
cond = cond.And(FeedDateCond(opts))
|
||||
|
||||
return cond, nil
|
||||
}
|
||||
|
@ -208,9 +208,31 @@ func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, int64, err
|
||||
return nil, 0, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
|
||||
}
|
||||
|
||||
cond, err := ActivityQueryCondition(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
var err error
|
||||
var cond builder.Cond
|
||||
// if the actor is the requested user or is an administrator, we can skip the ActivityQueryCondition
|
||||
if opts.Actor != nil && opts.RequestedUser != nil && (opts.Actor.IsAdmin || opts.Actor.ID == opts.RequestedUser.ID) {
|
||||
cond = builder.Eq{
|
||||
"user_id": opts.RequestedUser.ID,
|
||||
}.And(
|
||||
FeedDateCond(opts),
|
||||
)
|
||||
|
||||
if !opts.IncludeDeleted {
|
||||
cond = cond.And(builder.Eq{"is_deleted": false})
|
||||
}
|
||||
|
||||
if !opts.IncludePrivate {
|
||||
cond = cond.And(builder.Eq{"is_private": false})
|
||||
}
|
||||
if opts.OnlyPerformedBy {
|
||||
cond = cond.And(builder.Eq{"act_user_id": opts.RequestedUser.ID})
|
||||
}
|
||||
} else {
|
||||
cond, err = ActivityQueryCondition(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
}
|
||||
|
||||
actions := make([]*Action, 0, opts.PageSize)
|
||||
|
@ -44,7 +44,7 @@ func init() {
|
||||
// TranslatableMessage represents JSON struct that can be translated with a Locale
|
||||
type TranslatableMessage struct {
|
||||
Format string
|
||||
Args []any `json:"omitempty"`
|
||||
Args []any `json:",omitempty"`
|
||||
}
|
||||
|
||||
// LoadRepo loads repository of the task
|
||||
|
@ -5,6 +5,7 @@ package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
@ -14,7 +15,7 @@ import (
|
||||
type AccessTokenScopeCategory int
|
||||
|
||||
const (
|
||||
AccessTokenScopeCategoryActivityPub = iota
|
||||
AccessTokenScopeCategoryActivityPub AccessTokenScopeCategory = iota
|
||||
AccessTokenScopeCategoryAdmin
|
||||
AccessTokenScopeCategoryMisc // WARN: this is now just a placeholder, don't remove it which will change the following values
|
||||
AccessTokenScopeCategoryNotification
|
||||
@ -193,6 +194,14 @@ var accessTokenScopes = map[AccessTokenScopeLevel]map[AccessTokenScopeCategory]A
|
||||
},
|
||||
}
|
||||
|
||||
func GetAccessTokenCategories() (res []string) {
|
||||
for _, cat := range accessTokenScopes[Read] {
|
||||
res = append(res, strings.TrimPrefix(string(cat), "read:"))
|
||||
}
|
||||
slices.Sort(res)
|
||||
return res
|
||||
}
|
||||
|
||||
// GetRequiredScopes gets the specific scopes for a given level and categories
|
||||
func GetRequiredScopes(level AccessTokenScopeLevel, scopeCategories ...AccessTokenScopeCategory) []AccessTokenScope {
|
||||
scopes := make([]AccessTokenScope, 0, len(scopeCategories))
|
||||
@ -270,6 +279,9 @@ func (s AccessTokenScope) parse() (accessTokenScopeBitmap, error) {
|
||||
|
||||
// StringSlice returns the AccessTokenScope as a []string
|
||||
func (s AccessTokenScope) StringSlice() []string {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
return strings.Split(string(s), ",")
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ type scopeTestNormalize struct {
|
||||
}
|
||||
|
||||
func TestAccessTokenScope_Normalize(t *testing.T) {
|
||||
assert.Equal(t, []string{"activitypub", "admin", "issue", "misc", "notification", "organization", "package", "repository", "user"}, GetAccessTokenCategories())
|
||||
tests := []scopeTestNormalize{
|
||||
{"", "", nil},
|
||||
{"write:misc,write:notification,read:package,write:notification,public-only", "public-only,write:misc,write:notification,read:package", nil},
|
||||
@ -25,7 +26,7 @@ func TestAccessTokenScope_Normalize(t *testing.T) {
|
||||
{"write:activitypub,write:admin,write:misc,write:notification,write:organization,write:package,write:issue,write:repository,write:user,public-only", "public-only,all", nil},
|
||||
}
|
||||
|
||||
for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} {
|
||||
for _, scope := range GetAccessTokenCategories() {
|
||||
tests = append(tests,
|
||||
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("read:%s", scope)), AccessTokenScope(fmt.Sprintf("read:%s", scope)), nil},
|
||||
scopeTestNormalize{AccessTokenScope(fmt.Sprintf("write:%s", scope)), AccessTokenScope(fmt.Sprintf("write:%s", scope)), nil},
|
||||
@ -59,7 +60,7 @@ func TestAccessTokenScope_HasScope(t *testing.T) {
|
||||
{"public-only", "read:issue", false, nil},
|
||||
}
|
||||
|
||||
for _, scope := range []string{"activitypub", "admin", "misc", "notification", "organization", "package", "issue", "repository", "user"} {
|
||||
for _, scope := range GetAccessTokenCategories() {
|
||||
tests = append(tests,
|
||||
scopeTestHasScope{
|
||||
AccessTokenScope(fmt.Sprintf("read:%s", scope)),
|
||||
|
@ -28,11 +28,16 @@ type PullRequestsOptions struct {
|
||||
Labels []int64
|
||||
MilestoneID int64
|
||||
PosterID int64
|
||||
BaseBranch string
|
||||
}
|
||||
|
||||
func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) *xorm.Session {
|
||||
sess := db.GetEngine(ctx).Where("pull_request.base_repo_id=?", baseRepoID)
|
||||
|
||||
if opts.BaseBranch != "" {
|
||||
sess.And("pull_request.base_branch=?", opts.BaseBranch)
|
||||
}
|
||||
|
||||
sess.Join("INNER", "issue", "pull_request.issue_id = issue.id")
|
||||
switch opts.State {
|
||||
case "closed", "open":
|
||||
@ -56,7 +61,7 @@ func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullR
|
||||
}
|
||||
|
||||
// GetUnmergedPullRequestsByHeadInfo returns all pull requests that are open and has not been merged
|
||||
func GetUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch string) ([]*PullRequest, error) {
|
||||
func GetUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch string) (PullRequestList, error) {
|
||||
prs := make([]*PullRequest, 0, 2)
|
||||
sess := db.GetEngine(ctx).
|
||||
Join("INNER", "issue", "issue.id = pull_request.issue_id").
|
||||
@ -111,7 +116,7 @@ func HasUnmergedPullRequestsByHeadInfo(ctx context.Context, repoID int64, branch
|
||||
|
||||
// GetUnmergedPullRequestsByBaseInfo returns all pull requests that are open and has not been merged
|
||||
// by given base information (repo and branch).
|
||||
func GetUnmergedPullRequestsByBaseInfo(ctx context.Context, repoID int64, branch string) ([]*PullRequest, error) {
|
||||
func GetUnmergedPullRequestsByBaseInfo(ctx context.Context, repoID int64, branch string) (PullRequestList, error) {
|
||||
prs := make([]*PullRequest, 0, 2)
|
||||
return prs, db.GetEngine(ctx).
|
||||
Where("base_repo_id=? AND base_branch=? AND has_merged=? AND issue.is_closed=?",
|
||||
|
@ -16,11 +16,11 @@ import (
|
||||
func TestPullRequestList_LoadAttributes(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
prs := []*issues_model.PullRequest{
|
||||
prs := issues_model.PullRequestList{
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}),
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}),
|
||||
}
|
||||
assert.NoError(t, issues_model.PullRequestList(prs).LoadAttributes(db.DefaultContext))
|
||||
assert.NoError(t, prs.LoadAttributes(db.DefaultContext))
|
||||
for _, pr := range prs {
|
||||
assert.NotNil(t, pr.Issue)
|
||||
assert.Equal(t, pr.IssueID, pr.Issue.ID)
|
||||
@ -32,11 +32,11 @@ func TestPullRequestList_LoadAttributes(t *testing.T) {
|
||||
func TestPullRequestList_LoadReviewCommentsCounts(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
prs := []*issues_model.PullRequest{
|
||||
prs := issues_model.PullRequestList{
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}),
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}),
|
||||
}
|
||||
reviewComments, err := issues_model.PullRequestList(prs).LoadReviewCommentsCounts(db.DefaultContext)
|
||||
reviewComments, err := prs.LoadReviewCommentsCounts(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, reviewComments, 2)
|
||||
for _, pr := range prs {
|
||||
@ -47,11 +47,11 @@ func TestPullRequestList_LoadReviewCommentsCounts(t *testing.T) {
|
||||
func TestPullRequestList_LoadReviews(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
prs := []*issues_model.PullRequest{
|
||||
prs := issues_model.PullRequestList{
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 1}),
|
||||
unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 2}),
|
||||
}
|
||||
reviewList, err := issues_model.PullRequestList(prs).LoadReviews(db.DefaultContext)
|
||||
reviewList, err := prs.LoadReviews(db.DefaultContext)
|
||||
assert.NoError(t, err)
|
||||
// 1, 7, 8, 9, 10, 22
|
||||
assert.Len(t, reviewList, 6)
|
||||
|
@ -124,6 +124,7 @@ func GetUserOrgsList(ctx context.Context, user *user_model.User) ([]*MinimalOrg,
|
||||
if err := db.GetEngine(ctx).Select(columnsStr).
|
||||
Table("user").
|
||||
Where(builder.In("`user`.`id`", queryUserOrgIDs(user.ID, true))).
|
||||
OrderBy("`user`.lower_name ASC").
|
||||
Find(&orgs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -110,9 +110,12 @@ func GetPackageDescriptor(ctx context.Context, pv *PackageVersion) (*PackageDesc
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
repository, err := repo_model.GetRepositoryByID(ctx, p.RepoID)
|
||||
if err != nil && !repo_model.IsErrRepoNotExist(err) {
|
||||
return nil, err
|
||||
var repository *repo_model.Repository
|
||||
if p.RepoID > 0 {
|
||||
repository, err = repo_model.GetRepositoryByID(ctx, p.RepoID)
|
||||
if err != nil && !repo_model.IsErrRepoNotExist(err) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
creator, err := user_model.GetUserByID(ctx, pv.CreatorID)
|
||||
if err != nil {
|
||||
|
@ -646,13 +646,15 @@ func (repo *Repository) DescriptionHTML(ctx context.Context) template.HTML {
|
||||
type CloneLink struct {
|
||||
SSH string
|
||||
HTTPS string
|
||||
Tea string
|
||||
}
|
||||
|
||||
// ComposeHTTPSCloneURL returns HTTPS clone URL based on given owner and repository name.
|
||||
// ComposeHTTPSCloneURL returns HTTPS clone URL based on the given owner and repository name.
|
||||
func ComposeHTTPSCloneURL(ctx context.Context, owner, repo string) string {
|
||||
return fmt.Sprintf("%s%s/%s.git", httplib.GuessCurrentAppURL(ctx), url.PathEscape(owner), url.PathEscape(repo))
|
||||
}
|
||||
|
||||
// ComposeSSHCloneURL returns SSH clone URL based on the given owner and repository name.
|
||||
func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) string {
|
||||
sshUser := setting.SSH.User
|
||||
sshDomain := setting.SSH.Domain
|
||||
@ -686,11 +688,17 @@ func ComposeSSHCloneURL(doer *user_model.User, ownerName, repoName string) strin
|
||||
return fmt.Sprintf("%s@%s:%s/%s.git", sshUser, sshHost, url.PathEscape(ownerName), url.PathEscape(repoName))
|
||||
}
|
||||
|
||||
// ComposeTeaCloneCommand returns Tea CLI clone command based on the given owner and repository name.
|
||||
func ComposeTeaCloneCommand(ctx context.Context, owner, repo string) string {
|
||||
return fmt.Sprintf("tea clone %s/%s", url.PathEscape(owner), url.PathEscape(repo))
|
||||
}
|
||||
|
||||
func (repo *Repository) cloneLink(ctx context.Context, doer *user_model.User, repoPathName string) *CloneLink {
|
||||
cl := new(CloneLink)
|
||||
cl.SSH = ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName)
|
||||
cl.HTTPS = ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName)
|
||||
return cl
|
||||
return &CloneLink{
|
||||
SSH: ComposeSSHCloneURL(doer, repo.OwnerName, repoPathName),
|
||||
HTTPS: ComposeHTTPSCloneURL(ctx, repo.OwnerName, repoPathName),
|
||||
Tea: ComposeTeaCloneCommand(ctx, repo.OwnerName, repoPathName),
|
||||
}
|
||||
}
|
||||
|
||||
// CloneLink returns clone URLs of repository.
|
||||
|
@ -5,6 +5,7 @@ package repo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
@ -149,9 +150,9 @@ func GetRepoAssignees(ctx context.Context, repo *Repository) (_ []*user_model.Us
|
||||
// If isShowFullName is set to true, also include full name prefix search
|
||||
func GetIssuePostersWithSearch(ctx context.Context, repo *Repository, isPull bool, search string, isShowFullName bool) ([]*user_model.User, error) {
|
||||
users := make([]*user_model.User, 0, 30)
|
||||
var prefixCond builder.Cond = builder.Like{"name", search + "%"}
|
||||
var prefixCond builder.Cond = builder.Like{"lower_name", strings.ToLower(search) + "%"}
|
||||
if isShowFullName {
|
||||
prefixCond = prefixCond.Or(builder.Like{"full_name", "%" + search + "%"})
|
||||
prefixCond = prefixCond.Or(db.BuildCaseInsensitiveLike("full_name", "%"+search+"%"))
|
||||
}
|
||||
|
||||
cond := builder.In("`user`.id",
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestRepoAssignees(t *testing.T) {
|
||||
@ -38,3 +39,19 @@ func TestRepoAssignees(t *testing.T) {
|
||||
assert.NotContains(t, []int64{users[0].ID, users[1].ID, users[2].ID}, 15)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetIssuePostersWithSearch(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2})
|
||||
|
||||
users, err := repo_model.GetIssuePostersWithSearch(db.DefaultContext, repo2, false, "USER", false /* full name */)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, users, 1)
|
||||
assert.Equal(t, "user2", users[0].Name)
|
||||
|
||||
users, err = repo_model.GetIssuePostersWithSearch(db.DefaultContext, repo2, false, "TW%O", true /* full name */)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, users, 1)
|
||||
assert.Equal(t, "user2", users[0].Name)
|
||||
}
|
||||
|
@ -62,6 +62,10 @@ func TestSanitizer(t *testing.T) {
|
||||
`<a href="javascript:alert('xss')">bad</a>`, `bad`,
|
||||
`<a href="vbscript:no">bad</a>`, `bad`,
|
||||
`<a href="data:1234">bad</a>`, `bad`,
|
||||
|
||||
// Some classes and attributes are used by the frontend framework and will execute JS code, so make sure they are removed
|
||||
`<div class="link-action" data-attr-class="foo" data-url="xxx">txt</div>`, `<div data-attr-class="foo">txt</div>`,
|
||||
`<div class="form-fetch-action" data-markdown-generated-content="bar" data-global-init="a" data-global-click="b">txt</div>`, `<div data-markdown-generated-content="bar">txt</div>`,
|
||||
}
|
||||
|
||||
for i := 0; i < len(testCases); i += 2 {
|
||||
|
@ -169,20 +169,24 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
||||
HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0")
|
||||
HTTPPort = sec.Key("HTTP_PORT").MustString("3000")
|
||||
|
||||
// DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version
|
||||
// if these are removed, the warning will not be shown
|
||||
if sec.HasKey("ENABLE_ACME") {
|
||||
EnableAcme = sec.Key("ENABLE_ACME").MustBool(false)
|
||||
} else {
|
||||
deprecatedSetting(rootCfg, "server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME", "v1.19.0")
|
||||
EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
|
||||
}
|
||||
|
||||
Protocol = HTTP
|
||||
protocolCfg := sec.Key("PROTOCOL").String()
|
||||
if protocolCfg != "https" && EnableAcme {
|
||||
log.Fatal("ACME could only be used with HTTPS protocol")
|
||||
}
|
||||
|
||||
switch protocolCfg {
|
||||
case "https":
|
||||
Protocol = HTTPS
|
||||
|
||||
// DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version
|
||||
// if these are removed, the warning will not be shown
|
||||
if sec.HasKey("ENABLE_ACME") {
|
||||
EnableAcme = sec.Key("ENABLE_ACME").MustBool(false)
|
||||
} else {
|
||||
deprecatedSetting(rootCfg, "server", "ENABLE_LETSENCRYPT", "server", "ENABLE_ACME", "v1.19.0")
|
||||
EnableAcme = sec.Key("ENABLE_LETSENCRYPT").MustBool(false)
|
||||
}
|
||||
if EnableAcme {
|
||||
AcmeURL = sec.Key("ACME_URL").MustString("")
|
||||
AcmeCARoot = sec.Key("ACME_CA_ROOT").MustString("")
|
||||
@ -210,6 +214,9 @@ func loadServerFrom(rootCfg ConfigProvider) {
|
||||
deprecatedSetting(rootCfg, "server", "LETSENCRYPT_EMAIL", "server", "ACME_EMAIL", "v1.19.0")
|
||||
AcmeEmail = sec.Key("LETSENCRYPT_EMAIL").MustString("")
|
||||
}
|
||||
if AcmeEmail == "" {
|
||||
log.Fatal("ACME Email is not set (ACME_EMAIL).")
|
||||
}
|
||||
} else {
|
||||
CertFile = sec.Key("CERT_FILE").String()
|
||||
KeyFile = sec.Key("KEY_FILE").String()
|
||||
|
@ -911,7 +911,6 @@ delete_token_success=Token byl odstraněn. Aplikace, které jej používají ji
|
||||
repo_and_org_access=Repozitář a přístup organizace
|
||||
permissions_public_only=Pouze veřejnost
|
||||
permissions_access_all=Vše (veřejné, soukromé a omezené)
|
||||
select_permissions=Vyberte oprávnění
|
||||
permission_not_set=Není nastaveno
|
||||
permission_no_access=Bez přístupu
|
||||
permission_read=Přečtené
|
||||
@ -2580,7 +2579,6 @@ diff.commit=revize
|
||||
diff.git-notes=Poznámky
|
||||
diff.data_not_available=Rozdílový obsah není dostupný
|
||||
diff.options_button=Možnosti rozdílového porovnání
|
||||
diff.show_diff_stats=Zobrazit statistiky
|
||||
diff.download_patch=Stáhněte soubor záplaty
|
||||
diff.download_diff=Stáhněte rozdílový soubor
|
||||
diff.show_split_view=Rozdělené zobrazení
|
||||
|
@ -910,7 +910,6 @@ delete_token_success=Der Zugriffstoken wurde gelöscht. Anwendungen die diesen T
|
||||
repo_and_org_access=Repository- und Organisationszugriff
|
||||
permissions_public_only=Nur öffentlich
|
||||
permissions_access_all=Alle (öffentlich, privat und begrenzt)
|
||||
select_permissions=Berechtigungen auswählen
|
||||
permission_not_set=Nicht festgelegt
|
||||
permission_no_access=Kein Zugriff
|
||||
permission_read=Lesen
|
||||
@ -2569,7 +2568,6 @@ diff.commit=Commit
|
||||
diff.git-notes=Hinweise
|
||||
diff.data_not_available=Keine Diff-Daten verfügbar
|
||||
diff.options_button=Diff-Optionen
|
||||
diff.show_diff_stats=Statistiken anzeigen
|
||||
diff.download_patch=Patch-Datei herunterladen
|
||||
diff.download_diff=Vergleichs-Datei herunterladen
|
||||
diff.show_split_view=Geteilte Ansicht
|
||||
|
@ -810,7 +810,6 @@ delete_token_success=Το διακριτικό έχει διαγραφεί. Οι
|
||||
repo_and_org_access=Πρόσβαση στο Αποθετήριο και Οργανισμό
|
||||
permissions_public_only=Δημόσια μόνο
|
||||
permissions_access_all=Όλα (δημόσια, ιδιωτικά, και περιορισμένα)
|
||||
select_permissions=Επιλέξτε δικαιώματα
|
||||
permission_no_access=Καμία Πρόσβαση
|
||||
permission_read=Αναγνωσμένες
|
||||
permission_write=Ανάγνωση και Εγγραφή
|
||||
@ -2317,7 +2316,6 @@ diff.commit=υποβολή
|
||||
diff.git-notes=Σημειώσεις
|
||||
diff.data_not_available=Δεν Υπάρχει Διαθέσιμο Περιεχόμενο Diff
|
||||
diff.options_button=Επιλογές Diff
|
||||
diff.show_diff_stats=Εμφάνιση Στατιστικών
|
||||
diff.download_patch=Λήψη Αρχείου Patch
|
||||
diff.download_diff=Λήψη Αρχείου Diff
|
||||
diff.show_split_view=Διαιρεμένη Προβολή
|
||||
|
@ -917,7 +917,6 @@ delete_token_success = The token has been deleted. Applications using it no long
|
||||
repo_and_org_access = Repository and Organization Access
|
||||
permissions_public_only = Public only
|
||||
permissions_access_all = All (public, private, and limited)
|
||||
select_permissions = Select permissions
|
||||
permission_not_set = Not set
|
||||
permission_no_access = No Access
|
||||
permission_read = Read
|
||||
@ -1465,6 +1464,8 @@ issues.filter_milestones = Filter Milestone
|
||||
issues.filter_projects = Filter Project
|
||||
issues.filter_labels = Filter Label
|
||||
issues.filter_reviewers = Filter Reviewer
|
||||
issues.filter_no_results = No results
|
||||
issues.filter_no_results_placeholder = Try adjusting your search filters.
|
||||
issues.new = New Issue
|
||||
issues.new.title_empty = Title cannot be empty
|
||||
issues.new.labels = Labels
|
||||
@ -2593,7 +2594,6 @@ diff.commit = commit
|
||||
diff.git-notes = Notes
|
||||
diff.data_not_available = Diff Content Not Available
|
||||
diff.options_button = Diff Options
|
||||
diff.show_diff_stats = Show Stats
|
||||
diff.download_patch = Download Patch File
|
||||
diff.download_diff = Download Diff File
|
||||
diff.show_split_view = Split View
|
||||
|
@ -806,7 +806,6 @@ delete_token_success=El token ha sido eliminado. Las aplicaciones que lo usen ya
|
||||
repo_and_org_access=Acceso al Repositorio y a la Organización
|
||||
permissions_public_only=Sólo público
|
||||
permissions_access_all=Todo (público, privado y limitado)
|
||||
select_permissions=Seleccionar permisos
|
||||
permission_no_access=Sin acceso
|
||||
permission_read=Leídas
|
||||
permission_write=Lectura y Escritura
|
||||
@ -2298,7 +2297,6 @@ diff.commit=commit
|
||||
diff.git-notes=Notas
|
||||
diff.data_not_available=El contenido del Diff no está disponible
|
||||
diff.options_button=Opciones de diferencias
|
||||
diff.show_diff_stats=Mostrar estadísticas
|
||||
diff.download_patch=Descargar archivo de parche
|
||||
diff.download_diff=Descargar archivo de diferencias
|
||||
diff.show_split_view=Dividir vista
|
||||
|
@ -1777,7 +1777,6 @@ diff.commit=کامیت
|
||||
diff.git-notes=یادداشتها
|
||||
diff.data_not_available=محتوای تفاوت ها در دسترس نیست
|
||||
diff.options_button=تنظیمات (diff) تغییرات
|
||||
diff.show_diff_stats=نمایش وضعیت
|
||||
diff.download_patch=دانلود پرونده وصله
|
||||
diff.download_diff=دانلود فایل تغییرات diff
|
||||
diff.show_split_view=مشاهده تقسیم شده
|
||||
|
@ -917,7 +917,6 @@ delete_token_success=Ce jeton a été supprimé. Les applications l'utilisant n'
|
||||
repo_and_org_access=Accès aux Organisations et Dépôts
|
||||
permissions_public_only=Publique uniquement
|
||||
permissions_access_all=Tout (public, privé et limité)
|
||||
select_permissions=Sélectionner les autorisations
|
||||
permission_not_set=Non défini
|
||||
permission_no_access=Aucun accès
|
||||
permission_read=Lecture
|
||||
@ -1701,7 +1700,9 @@ issues.time_estimate_invalid=Le format du temps estimé est invalide
|
||||
issues.start_tracking_history=`a commencé son travail %s.`
|
||||
issues.tracker_auto_close=Le minuteur sera automatiquement arrêté quand le ticket sera fermé.
|
||||
issues.tracking_already_started=`Vous avez déjà un minuteur en cours sur <a href="%s">un autre ticket</a> !`
|
||||
issues.stop_tracking=Arrêter le minuteur
|
||||
issues.stop_tracking_history=a travaillé sur <b>%[1]s</b> %[2]s
|
||||
issues.cancel_tracking=Abandonner
|
||||
issues.cancel_tracking_history=`a abandonné son minuteur %s.`
|
||||
issues.del_time=Supprimer ce minuteur du journal
|
||||
issues.add_time_history=a pointé du temps de travail sur <b>%[1]s</b>, %[2]s
|
||||
@ -2590,7 +2591,6 @@ diff.commit=révision
|
||||
diff.git-notes=Notes
|
||||
diff.data_not_available=Contenu de la comparaison indisponible
|
||||
diff.options_button=Option de Diff
|
||||
diff.show_diff_stats=Voir les Statistiques
|
||||
diff.download_patch=Télécharger le Fichier Patch
|
||||
diff.download_diff=Télécharger le Fichier des Différences
|
||||
diff.show_split_view=Vue séparée
|
||||
|
@ -917,7 +917,6 @@ delete_token_success=Tá an comhartha scriosta. Níl rochtain ag iarratais a ús
|
||||
repo_and_org_access=Rochtain Stórála agus Eagraíochta
|
||||
permissions_public_only=Poiblí amháin
|
||||
permissions_access_all=Gach (poiblí, príobháideach agus teoranta)
|
||||
select_permissions=Roghnaigh ceadanna
|
||||
permission_not_set=Níl leagtha
|
||||
permission_no_access=Gan rochtain
|
||||
permission_read=Léigh
|
||||
@ -1464,6 +1463,8 @@ issues.filter_milestones=Cloch Mhíle Scagaire
|
||||
issues.filter_projects=Tionscadal Scagaire
|
||||
issues.filter_labels=Lipéad Scagaire
|
||||
issues.filter_reviewers=Athbhreithneoir Scagaire
|
||||
issues.filter_no_results=Gan torthaí
|
||||
issues.filter_no_results_placeholder=Bain triail as do scagairí cuardaigh a choigeartú.
|
||||
issues.new=Eagrán Nua
|
||||
issues.new.title_empty=Ní féidir leis an teideal a bheith folamh
|
||||
issues.new.labels=Lipéid
|
||||
@ -1701,7 +1702,9 @@ issues.time_estimate_invalid=Tá formáid meastachán ama neamhbhailí
|
||||
issues.start_tracking_history=thosaigh ag obair %s
|
||||
issues.tracker_auto_close=Stopfar ama go huathoibríoch nuair a dhúnfar an tsaincheist seo
|
||||
issues.tracking_already_started=`Tá tús curtha agat cheana féin ag rianú ama ar <a href="%s">eagrán eile</a>!`
|
||||
issues.stop_tracking=Stad uaineadóir
|
||||
issues.stop_tracking_history=d'oibrigh do <b>%[1]s</b> %[2]s
|
||||
issues.cancel_tracking=Caith amach
|
||||
issues.cancel_tracking_history=`rianú ama curtha ar ceal %s`
|
||||
issues.del_time=Scrios an log ama seo
|
||||
issues.add_time_history=cuireadh am caite <b>%[1]s</b> %[2]s leis
|
||||
@ -2590,7 +2593,6 @@ diff.commit=tiomantas
|
||||
diff.git-notes=Nótaí
|
||||
diff.data_not_available=Níl Ábhar Difríochtaí Ar Fáil
|
||||
diff.options_button=Roghanna Diff
|
||||
diff.show_diff_stats=Taispeáin Staitisticí
|
||||
diff.download_patch=Íoslódáil an comhad paiste
|
||||
diff.download_diff=Íoslódáil Comhad Diff
|
||||
diff.show_split_view=Amharc Scoilt
|
||||
|
@ -1098,7 +1098,6 @@ diff.parent=szülő
|
||||
diff.commit=commit
|
||||
diff.git-notes=Megjegyzések
|
||||
diff.data_not_available=A különbségek nem megjeleníthetőek
|
||||
diff.show_diff_stats=Statisztikák mutatása
|
||||
diff.show_split_view=Osztott nézet
|
||||
diff.show_unified_view=Egyesített nézet
|
||||
diff.stats_desc=<strong>%d fájl</strong> változott, egészen pontosan <strong>%d új sor hozzáadva</strong> és <strong>%d régi sor törölve</strong>
|
||||
|
@ -1929,7 +1929,6 @@ diff.commit=commit
|
||||
diff.git-notes=Note
|
||||
diff.data_not_available=Dati Diff non disponibili
|
||||
diff.options_button=Opzioni Diff
|
||||
diff.show_diff_stats=Mostra statistiche
|
||||
diff.download_patch=Scarica il file Patch
|
||||
diff.download_diff=Scarica il file Diff
|
||||
diff.show_split_view=Visualizzazione separata
|
||||
|
@ -385,6 +385,12 @@ show_only_public=公開のみ表示
|
||||
|
||||
issues.in_your_repos=あなたのリポジトリ
|
||||
|
||||
guide_title=アクティビティはありません
|
||||
guide_desc=現在フォロー中のリポジトリやユーザーがないため、表示するコンテンツがありません。 以下のリンクから、興味のあるリポジトリやユーザーを探すことができます。
|
||||
explore_repos=リポジトリを探す
|
||||
explore_users=ユーザーを探す
|
||||
empty_org=組織はまだありません。
|
||||
empty_repo=リポジトリはまだありません。
|
||||
|
||||
[explore]
|
||||
repos=リポジトリ
|
||||
@ -911,7 +917,6 @@ delete_token_success=トークンを削除しました。 削除したトーク
|
||||
repo_and_org_access=リポジトリと組織へのアクセス
|
||||
permissions_public_only=公開のみ
|
||||
permissions_access_all=すべて (公開、プライベート、限定)
|
||||
select_permissions=許可の選択
|
||||
permission_not_set=設定なし
|
||||
permission_no_access=アクセス不可
|
||||
permission_read=読み取り
|
||||
@ -1348,6 +1353,8 @@ editor.new_branch_name_desc=新しいブランチ名…
|
||||
editor.cancel=キャンセル
|
||||
editor.filename_cannot_be_empty=ファイル名は空にできません。
|
||||
editor.filename_is_invalid=`ファイル名が不正です: "%s"`
|
||||
editor.commit_email=コミット メールアドレス
|
||||
editor.invalid_commit_email=コミットに使うメールアドレスが正しくありません。
|
||||
editor.branch_does_not_exist=このリポジトリにブランチ "%s" は存在しません。
|
||||
editor.branch_already_exists=ブランチ "%s" は、このリポジトリに既に存在します。
|
||||
editor.directory_is_a_file=ディレクトリ名 "%s" はすでにリポジトリ内のファイルで使用されています。
|
||||
@ -1693,7 +1700,9 @@ issues.time_estimate_invalid=見積時間のフォーマットが不正です
|
||||
issues.start_tracking_history=が作業を開始 %s
|
||||
issues.tracker_auto_close=タイマーは、このイシューがクローズされると自動的に終了します
|
||||
issues.tracking_already_started=`<a href="%s">別のイシュー</a>で既にタイムトラッキングを開始しています!`
|
||||
issues.stop_tracking=タイマー終了
|
||||
issues.stop_tracking_history=が <b>%[1]s</b> の作業を終了 %[2]s
|
||||
issues.cancel_tracking=破棄
|
||||
issues.cancel_tracking_history=`がタイムトラッキングを中止 %s`
|
||||
issues.del_time=このタイムログを削除
|
||||
issues.add_time_history=が作業時間 <b>%[1]s</b> を追加 %[2]s
|
||||
@ -2329,6 +2338,8 @@ settings.event_fork=フォーク
|
||||
settings.event_fork_desc=リポジトリがフォークされたとき。
|
||||
settings.event_wiki=Wiki
|
||||
settings.event_wiki_desc=Wikiページが作成・名前変更・編集・削除されたとき。
|
||||
settings.event_statuses=ステータス
|
||||
settings.event_statuses_desc=APIによってコミットのステータスが更新されたとき。
|
||||
settings.event_release=リリース
|
||||
settings.event_release_desc=リポジトリでリリースが作成・更新・削除されたとき。
|
||||
settings.event_push=プッシュ
|
||||
@ -2580,7 +2591,6 @@ diff.commit=コミット
|
||||
diff.git-notes=Notes
|
||||
diff.data_not_available=差分はありません
|
||||
diff.options_button=差分オプション
|
||||
diff.show_diff_stats=統計情報を表示
|
||||
diff.download_patch=Patchファイルをダウンロード
|
||||
diff.download_diff=Diffファイルをダウンロード
|
||||
diff.show_split_view=分割表示
|
||||
@ -2876,6 +2886,14 @@ view_as_role=表示: %s
|
||||
view_as_public_hint=READMEを公開ユーザーとして見ています。
|
||||
view_as_member_hint=READMEをこの組織のメンバーとして見ています。
|
||||
|
||||
worktime=作業時間
|
||||
worktime.date_range_start=期間 (自)
|
||||
worktime.date_range_end=期間 (至)
|
||||
worktime.query=集計
|
||||
worktime.time=時間
|
||||
worktime.by_repositories=リポジトリ別
|
||||
worktime.by_milestones=マイルストーン別
|
||||
worktime.by_members=メンバー別
|
||||
|
||||
[admin]
|
||||
maintenance=メンテナンス
|
||||
|
@ -814,7 +814,6 @@ delete_token_success=Pilnvara tika izdzēsta. Lietojumprogrammām, kas izmantoja
|
||||
repo_and_org_access=Repozitorija un organizācijas piekļuve
|
||||
permissions_public_only=Tikai publiskie
|
||||
permissions_access_all=Visi (publiskie, privātie un ierobežotie)
|
||||
select_permissions=Norādiet tiesības
|
||||
permission_no_access=Nav piekļuves
|
||||
permission_read=Skatīšanās
|
||||
permission_write=Skatīšanās un raksīšanas
|
||||
@ -2317,7 +2316,6 @@ diff.commit=revīzija
|
||||
diff.git-notes=Piezīmes
|
||||
diff.data_not_available=Satura salīdzināšana nav pieejama
|
||||
diff.options_button=Salīdzināšanas iespējas
|
||||
diff.show_diff_stats=Rādīt statistiku
|
||||
diff.download_patch=Lejupielādēt ielāpa failu
|
||||
diff.download_diff=Lejupielādēt izmaiņu failu
|
||||
diff.show_split_view=Dalītais skats
|
||||
|
@ -1864,7 +1864,6 @@ diff.commit=commit
|
||||
diff.git-notes=Notities
|
||||
diff.data_not_available=Diff gegevens niet beschikbaar
|
||||
diff.options_button=Diff opties
|
||||
diff.show_diff_stats=Statistieken weergeven
|
||||
diff.download_patch=Download Patch-bestand
|
||||
diff.download_diff=Download Diff-bestand
|
||||
diff.show_split_view=Zij-aan-zij weergave
|
||||
|
@ -1728,7 +1728,6 @@ diff.commit=commit
|
||||
diff.git-notes=Notatki
|
||||
diff.data_not_available=Informacje nt. zmian nie są dostępne
|
||||
diff.options_button=Opcje porównania
|
||||
diff.show_diff_stats=Pokaż statystyki
|
||||
diff.download_patch=Ściągnij plik aktualizacji
|
||||
diff.download_diff=Ściągnij plik porównania
|
||||
diff.show_split_view=Widok podzielony
|
||||
|
@ -812,7 +812,6 @@ delete_token_success=O token foi excluído. Os aplicativos que o utilizam já n
|
||||
repo_and_org_access=Acesso ao Repositório e Organização
|
||||
permissions_public_only=Apenas público
|
||||
permissions_access_all=Todos (público, privado e limitado)
|
||||
select_permissions=Selecionar permissões
|
||||
permission_no_access=Sem acesso
|
||||
permission_read=Ler
|
||||
permission_write=Ler e escrever
|
||||
@ -2282,7 +2281,6 @@ diff.commit=commit
|
||||
diff.git-notes=Notas
|
||||
diff.data_not_available=Conteúdo de diff não disponível
|
||||
diff.options_button=Opções de diferenças
|
||||
diff.show_diff_stats=Mostrar estatísticas
|
||||
diff.download_patch=Baixar arquivo de patch
|
||||
diff.download_diff=Baixar arquivo de diferenças
|
||||
diff.show_split_view=Visão dividida
|
||||
|
@ -917,7 +917,6 @@ delete_token_success=O código foi eliminado. Aplicações que o usavam deixaram
|
||||
repo_and_org_access=Acesso aos repositórios e às organizações
|
||||
permissions_public_only=Apenas público
|
||||
permissions_access_all=Tudo (público, privado e limitado)
|
||||
select_permissions=Escolher permissões
|
||||
permission_not_set=Não definido
|
||||
permission_no_access=Sem acesso
|
||||
permission_read=Lidas
|
||||
@ -1464,6 +1463,8 @@ issues.filter_milestones=Filtrar etapa
|
||||
issues.filter_projects=Filtrar planeamento
|
||||
issues.filter_labels=Filtrar rótulo
|
||||
issues.filter_reviewers=Filtrar revisor
|
||||
issues.filter_no_results=Sem resultados
|
||||
issues.filter_no_results_placeholder=Tente ajustar os seus filtros de pesquisa.
|
||||
issues.new=Questão nova
|
||||
issues.new.title_empty=O título não pode estar vazio
|
||||
issues.new.labels=Rótulos
|
||||
@ -2592,7 +2593,6 @@ diff.commit=cometimento
|
||||
diff.git-notes=Notas
|
||||
diff.data_not_available=O conteúdo das diferenças não está disponível
|
||||
diff.options_button=Opções das diferenças
|
||||
diff.show_diff_stats=Mostrar estatísticas
|
||||
diff.download_patch=Descarregar ficheiro patch
|
||||
diff.download_diff=Descarregar ficheiro diff
|
||||
diff.show_split_view=Visualização em 2 colunas
|
||||
|
@ -807,7 +807,6 @@ delete_token_success=Токен удалён. Приложения, исполь
|
||||
repo_and_org_access=Доступ к репозиторию и организации
|
||||
permissions_public_only=Только публичные
|
||||
permissions_access_all=Все (публичные, приватные и ограниченные)
|
||||
select_permissions=Выбрать разрешения
|
||||
permission_no_access=Нет доступа
|
||||
permission_read=Прочитанные
|
||||
permission_write=Чтение и запись
|
||||
@ -2268,7 +2267,6 @@ diff.commit=Коммит
|
||||
diff.git-notes=Заметки
|
||||
diff.data_not_available=Разница недоступна
|
||||
diff.options_button=Опции Diff
|
||||
diff.show_diff_stats=Показать статистику
|
||||
diff.download_patch=Скачать Patch файл
|
||||
diff.download_diff=Скачать Diff файл
|
||||
diff.show_split_view=Разделённый вид
|
||||
|
@ -1739,7 +1739,6 @@ diff.commit=කැප
|
||||
diff.git-notes=සටහන්
|
||||
diff.data_not_available=Diff අන්තර්ගත ලබාගත නොහැක
|
||||
diff.options_button=විවිධ විකල්ප
|
||||
diff.show_diff_stats=සංඛ්යාන පෙන්වන්න
|
||||
diff.download_patch=පැච් ගොනුව බාගත
|
||||
diff.download_diff=බාගත Dff ගොනුව
|
||||
diff.show_split_view=භේදය දැක්ම
|
||||
|
@ -895,7 +895,6 @@ delete_token_success=Jeton silindi. Onu kullanan uygulamalar artık hesabınıza
|
||||
repo_and_org_access=Depo ve Organizasyon Erişimi
|
||||
permissions_public_only=Yalnızca herkese açık
|
||||
permissions_access_all=Tümü (herkese açık, özel ve sınırlı)
|
||||
select_permissions=İzinleri seçin
|
||||
permission_not_set=Ayarlanmadı
|
||||
permission_no_access=Erişim Yok
|
||||
permission_read=Okunmuş
|
||||
@ -2470,7 +2469,6 @@ diff.commit=işleme
|
||||
diff.git-notes=Notlar
|
||||
diff.data_not_available=Farklı İçerik Mevut Değil
|
||||
diff.options_button=Diff Seçenekleri
|
||||
diff.show_diff_stats=İstatistikleri Göster
|
||||
diff.download_patch=Yama Dosyasını İndir
|
||||
diff.download_diff=Diff Dosyasını İndir
|
||||
diff.show_split_view=Görünümü Böl
|
||||
|
@ -1789,7 +1789,6 @@ diff.commit=коміт
|
||||
diff.git-notes=Примітки
|
||||
diff.data_not_available=Різниця недоступна
|
||||
diff.options_button=Параметри порівняння
|
||||
diff.show_diff_stats=Показати статистику
|
||||
diff.download_patch=Завантажити патч
|
||||
diff.download_diff=Завантажити файл різниці
|
||||
diff.show_split_view=Розділений перегляд
|
||||
|
@ -910,7 +910,6 @@ delete_token_success=令牌已经被删除。使用该令牌的应用将不再
|
||||
repo_and_org_access=仓库和组织访问权限
|
||||
permissions_public_only=仅公开
|
||||
permissions_access_all=全部(公开、私有和受限)
|
||||
select_permissions=选择权限
|
||||
permission_not_set=未设置
|
||||
permission_no_access=无访问权限
|
||||
permission_read=可读
|
||||
@ -2569,7 +2568,6 @@ diff.commit=当前提交
|
||||
diff.git-notes=Notes
|
||||
diff.data_not_available=比较内容不可用
|
||||
diff.options_button=Diff 选项
|
||||
diff.show_diff_stats=显示统计
|
||||
diff.download_patch=下载 Patch 文件
|
||||
diff.download_diff=下载 Diff 文件
|
||||
diff.show_split_view=分列视图
|
||||
|
@ -907,7 +907,6 @@ delete_token_success=已刪除 Token。使用此 Token 的應用程式無法再
|
||||
repo_and_org_access=儲存庫和組織存取
|
||||
permissions_public_only=僅公開
|
||||
permissions_access_all=全部 (公開、私有與受限)
|
||||
select_permissions=選擇權限
|
||||
permission_not_set=尚未設定
|
||||
permission_no_access=沒有權限
|
||||
permission_read=讀取
|
||||
@ -2560,7 +2559,6 @@ diff.commit=當前提交
|
||||
diff.git-notes=備註
|
||||
diff.data_not_available=沒有內容比較可以使用
|
||||
diff.options_button=差異選項
|
||||
diff.show_diff_stats=顯示統計資料
|
||||
diff.download_patch=下載 Patch 檔
|
||||
diff.download_diff=下載差異檔
|
||||
diff.show_split_view=分割檢視
|
||||
|
@ -66,6 +66,7 @@ type PackageMetadataResponse struct {
|
||||
}
|
||||
|
||||
// PackageVersionMetadata contains package metadata
|
||||
// https://getcomposer.org/doc/05-repositories.md#package
|
||||
type PackageVersionMetadata struct {
|
||||
*composer_module.Metadata
|
||||
Name string `json:"name"`
|
||||
@ -73,6 +74,7 @@ type PackageVersionMetadata struct {
|
||||
Type string `json:"type"`
|
||||
Created time.Time `json:"time"`
|
||||
Dist Dist `json:"dist"`
|
||||
Source Source `json:"source"`
|
||||
}
|
||||
|
||||
// Dist contains package download information
|
||||
@ -82,6 +84,13 @@ type Dist struct {
|
||||
Checksum string `json:"shasum"`
|
||||
}
|
||||
|
||||
// Source contains package source information
|
||||
type Source struct {
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"`
|
||||
Reference string `json:"reference"`
|
||||
}
|
||||
|
||||
func createPackageMetadataResponse(registryURL string, pds []*packages_model.PackageDescriptor) *PackageMetadataResponse {
|
||||
versions := make([]*PackageVersionMetadata, 0, len(pds))
|
||||
|
||||
@ -94,7 +103,7 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
|
||||
}
|
||||
}
|
||||
|
||||
versions = append(versions, &PackageVersionMetadata{
|
||||
pkg := PackageVersionMetadata{
|
||||
Name: pd.Package.Name,
|
||||
Version: pd.Version.Version,
|
||||
Type: packageType,
|
||||
@ -105,7 +114,16 @@ func createPackageMetadataResponse(registryURL string, pds []*packages_model.Pac
|
||||
URL: fmt.Sprintf("%s/files/%s/%s/%s", registryURL, url.PathEscape(pd.Package.LowerName), url.PathEscape(pd.Version.LowerVersion), url.PathEscape(pd.Files[0].File.LowerName)),
|
||||
Checksum: pd.Files[0].Blob.HashSHA1,
|
||||
},
|
||||
})
|
||||
}
|
||||
if pd.Repository != nil {
|
||||
pkg.Source = Source{
|
||||
URL: pd.Repository.HTMLURL(),
|
||||
Type: "git",
|
||||
Reference: pd.Version.Version,
|
||||
}
|
||||
}
|
||||
|
||||
versions = append(versions, &pkg)
|
||||
}
|
||||
|
||||
return &PackageMetadataResponse{
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
maven_module "code.gitea.io/gitea/modules/packages/maven"
|
||||
)
|
||||
|
||||
// MetadataResponse https://maven.apache.org/ref/3.2.5/maven-repository-metadata/repository-metadata.html
|
||||
@ -22,7 +21,7 @@ type MetadataResponse struct {
|
||||
}
|
||||
|
||||
// pds is expected to be sorted ascending by CreatedUnix
|
||||
func createMetadataResponse(pds []*packages_model.PackageDescriptor) *MetadataResponse {
|
||||
func createMetadataResponse(pds []*packages_model.PackageDescriptor, groupID, artifactID string) *MetadataResponse {
|
||||
var release *packages_model.PackageDescriptor
|
||||
|
||||
versions := make([]string, 0, len(pds))
|
||||
@ -35,11 +34,9 @@ func createMetadataResponse(pds []*packages_model.PackageDescriptor) *MetadataRe
|
||||
|
||||
latest := pds[len(pds)-1]
|
||||
|
||||
metadata := latest.Metadata.(*maven_module.Metadata)
|
||||
|
||||
resp := &MetadataResponse{
|
||||
GroupID: metadata.GroupID,
|
||||
ArtifactID: metadata.ArtifactID,
|
||||
GroupID: groupID,
|
||||
ArtifactID: artifactID,
|
||||
Latest: latest.Version.Version,
|
||||
Version: versions,
|
||||
}
|
||||
|
@ -84,20 +84,19 @@ func handlePackageFile(ctx *context.Context, serveContent bool) {
|
||||
}
|
||||
|
||||
func serveMavenMetadata(ctx *context.Context, params parameters) {
|
||||
// /com/foo/project/maven-metadata.xml[.md5/.sha1/.sha256/.sha512]
|
||||
|
||||
pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageName())
|
||||
if errors.Is(err, util.ErrNotExist) {
|
||||
pvs, err = packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageNameLegacy())
|
||||
}
|
||||
// path pattern: /com/foo/project/maven-metadata.xml[.md5/.sha1/.sha256/.sha512]
|
||||
// in case there are legacy package names ("GroupID-ArtifactID") we need to check both, new packages always use ":" as separator("GroupID:ArtifactID")
|
||||
pvsLegacy, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageNameLegacy())
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
if len(pvs) == 0 {
|
||||
apiError(ctx, http.StatusNotFound, packages_model.ErrPackageNotExist)
|
||||
pvs, err := packages_model.GetVersionsByPackageName(ctx, ctx.Package.Owner.ID, packages_model.TypeMaven, params.toInternalPackageName())
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
pvs = append(pvsLegacy, pvs...)
|
||||
|
||||
pds, err := packages_model.GetPackageDescriptors(ctx, pvs)
|
||||
if err != nil {
|
||||
@ -110,7 +109,7 @@ func serveMavenMetadata(ctx *context.Context, params parameters) {
|
||||
return pds[i].Version.CreatedUnix < pds[j].Version.CreatedUnix
|
||||
})
|
||||
|
||||
xmlMetadata, err := xml.Marshal(createMetadataResponse(pds))
|
||||
xmlMetadata, err := xml.Marshal(createMetadataResponse(pds, params.GroupID, params.ArtifactID))
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
|
@ -7,8 +7,6 @@
|
||||
// This documentation describes the Gitea API.
|
||||
//
|
||||
// Schemes: https, http
|
||||
// BasePath: /api/v1
|
||||
// Version: {{AppVer | JSEscape}}
|
||||
// License: MIT http://opensource.org/licenses/MIT
|
||||
//
|
||||
// Consumes:
|
||||
|
@ -7,6 +7,7 @@ package repo
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/perm"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
@ -274,12 +275,13 @@ func GetRepoPermissions(ctx *context.APIContext) {
|
||||
// "403":
|
||||
// "$ref": "#/responses/forbidden"
|
||||
|
||||
if !ctx.Doer.IsAdmin && ctx.Doer.LoginName != ctx.PathParam("collaborator") && !ctx.IsUserRepoAdmin() {
|
||||
collaboratorUsername := ctx.PathParam("collaborator")
|
||||
if !ctx.Doer.IsAdmin && ctx.Doer.LowerName != strings.ToLower(collaboratorUsername) && !ctx.IsUserRepoAdmin() {
|
||||
ctx.APIError(http.StatusForbidden, "Only admins can query all permissions, repo admins can query all repo permissions, collaborators can query only their own")
|
||||
return
|
||||
}
|
||||
|
||||
collaborator, err := user_model.GetUserByName(ctx, ctx.PathParam("collaborator"))
|
||||
collaborator, err := user_model.GetUserByName(ctx, collaboratorUsername)
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.APIError(http.StatusNotFound, err)
|
||||
|
@ -59,6 +59,10 @@ func ListPullRequests(ctx *context.APIContext) {
|
||||
// description: Name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: base_branch
|
||||
// in: query
|
||||
// description: Filter by target base branch of the pull request
|
||||
// type: string
|
||||
// - name: state
|
||||
// in: query
|
||||
// description: State of pull request
|
||||
@ -132,6 +136,7 @@ func ListPullRequests(ctx *context.APIContext) {
|
||||
Labels: labelIDs,
|
||||
MilestoneID: ctx.FormInt64("milestone"),
|
||||
PosterID: posterID,
|
||||
BaseBranch: ctx.FormTrim("base_branch"),
|
||||
})
|
||||
if err != nil {
|
||||
ctx.APIErrorInternal(err)
|
||||
|
@ -52,13 +52,22 @@ func generateMockStepsLog(logCur actions.LogCursor) (stepsLog []*actions.ViewSte
|
||||
return stepsLog
|
||||
}
|
||||
|
||||
func MockActionsRunsJobs(ctx *context.Context) {
|
||||
req := web.GetForm(ctx).(*actions.ViewRequest)
|
||||
func MockActionsView(ctx *context.Context) {
|
||||
ctx.Data["RunID"] = ctx.PathParam("run")
|
||||
ctx.Data["JobID"] = ctx.PathParam("job")
|
||||
ctx.HTML(http.StatusOK, "devtest/repo-action-view")
|
||||
}
|
||||
|
||||
func MockActionsRunsJobs(ctx *context.Context) {
|
||||
runID := ctx.PathParamInt64("run")
|
||||
|
||||
req := web.GetForm(ctx).(*actions.ViewRequest)
|
||||
resp := &actions.ViewResponse{}
|
||||
resp.State.Run.TitleHTML = `mock run title <a href="/">link</a>`
|
||||
resp.State.Run.Status = actions_model.StatusRunning.String()
|
||||
resp.State.Run.CanCancel = true
|
||||
resp.State.Run.CanCancel = runID == 10
|
||||
resp.State.Run.CanApprove = runID == 20
|
||||
resp.State.Run.CanRerun = runID == 30
|
||||
resp.State.Run.CanDeleteArtifact = true
|
||||
resp.State.Run.WorkflowID = "workflow-id"
|
||||
resp.State.Run.WorkflowLink = "./workflow-link"
|
||||
@ -85,6 +94,29 @@ func MockActionsRunsJobs(ctx *context.Context) {
|
||||
Size: 1024 * 1024,
|
||||
Status: "completed",
|
||||
})
|
||||
|
||||
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
|
||||
ID: runID * 10,
|
||||
Name: "job 100",
|
||||
Status: actions_model.StatusRunning.String(),
|
||||
CanRerun: true,
|
||||
Duration: "1h",
|
||||
})
|
||||
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
|
||||
ID: runID*10 + 1,
|
||||
Name: "job 101",
|
||||
Status: actions_model.StatusWaiting.String(),
|
||||
CanRerun: false,
|
||||
Duration: "2h",
|
||||
})
|
||||
resp.State.Run.Jobs = append(resp.State.Run.Jobs, &actions.ViewJob{
|
||||
ID: runID*10 + 2,
|
||||
Name: "job 102",
|
||||
Status: actions_model.StatusFailure.String(),
|
||||
CanRerun: false,
|
||||
Duration: "3h",
|
||||
})
|
||||
|
||||
resp.State.CurrentJob.Steps = append(resp.State.CurrentJob.Steps, &actions.ViewJobStep{
|
||||
Summary: "step 0 (mock slow)",
|
||||
Duration: time.Hour.String(),
|
||||
|
@ -344,18 +344,30 @@ func Diff(ctx *context.Context) {
|
||||
ctx.Data["Reponame"] = repoName
|
||||
|
||||
var parentCommit *git.Commit
|
||||
var parentCommitID string
|
||||
if commit.ParentCount() > 0 {
|
||||
parentCommit, err = gitRepo.GetCommit(parents[0])
|
||||
if err != nil {
|
||||
ctx.NotFound(err)
|
||||
return
|
||||
}
|
||||
parentCommitID = parentCommit.ID.String()
|
||||
}
|
||||
setCompareContext(ctx, parentCommit, commit, userName, repoName)
|
||||
ctx.Data["Title"] = commit.Summary() + " · " + base.ShortSha(commitID)
|
||||
ctx.Data["Commit"] = commit
|
||||
ctx.Data["Diff"] = diff
|
||||
|
||||
if !fileOnly {
|
||||
diffTree, err := gitdiff.GetDiffTree(ctx, gitRepo, false, parentCommitID, commitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiffTree", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.PageData["DiffFiles"] = transformDiffTreeForUI(diffTree, nil)
|
||||
}
|
||||
|
||||
statuses, _, err := git_model.GetLatestCommitStatus(ctx, ctx.Repo.Repository.ID, commitID, db.ListOptionsAll)
|
||||
if err != nil {
|
||||
log.Error("GetLatestCommitStatus: %v", err)
|
||||
|
@ -633,6 +633,16 @@ func PrepareCompareDiff(
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
|
||||
|
||||
if !fileOnly {
|
||||
diffTree, err := gitdiff.GetDiffTree(ctx, ci.HeadGitRepo, false, beforeCommitID, headCommitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiffTree", err)
|
||||
return false
|
||||
}
|
||||
|
||||
ctx.PageData["DiffFiles"] = transformDiffTreeForUI(diffTree, nil)
|
||||
}
|
||||
|
||||
headCommit, err := ci.HeadGitRepo.GetCommit(headCommitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetCommit", err)
|
||||
|
@ -78,7 +78,7 @@ func httpBase(ctx *context.Context) *serviceHandler {
|
||||
strings.HasSuffix(ctx.Req.URL.Path, "git-upload-archive") {
|
||||
isPull = true
|
||||
} else {
|
||||
isPull = ctx.Req.Method == "GET"
|
||||
isPull = ctx.Req.Method == "HEAD" || ctx.Req.Method == "GET"
|
||||
}
|
||||
|
||||
var accessMode perm.AccessMode
|
||||
|
@ -761,6 +761,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
|
||||
|
||||
var methodWithError string
|
||||
var diff *gitdiff.Diff
|
||||
shouldGetUserSpecificDiff := false
|
||||
|
||||
// if we're not logged in or only a single commit (or commit range) is shown we
|
||||
// have to load only the diff and not get the viewed information
|
||||
@ -772,6 +773,7 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
|
||||
} else {
|
||||
diff, err = gitdiff.SyncAndGetUserSpecificDiff(ctx, ctx.Doer.ID, pull, gitRepo, diffOptions, files...)
|
||||
methodWithError = "SyncAndGetUserSpecificDiff"
|
||||
shouldGetUserSpecificDiff = true
|
||||
}
|
||||
if err != nil {
|
||||
ctx.ServerError(methodWithError, err)
|
||||
@ -816,6 +818,27 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi
|
||||
}
|
||||
}
|
||||
|
||||
if !fileOnly {
|
||||
// note: use mergeBase is set to false because we already have the merge base from the pull request info
|
||||
diffTree, err := gitdiff.GetDiffTree(ctx, gitRepo, false, pull.MergeBase, headCommitID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetDiffTree", err)
|
||||
return
|
||||
}
|
||||
|
||||
filesViewedState := make(map[string]pull_model.ViewedState)
|
||||
if shouldGetUserSpecificDiff {
|
||||
// This sort of sucks because we already fetch this when getting the diff
|
||||
review, err := pull_model.GetNewestReviewState(ctx, ctx.Doer.ID, issue.ID)
|
||||
if err == nil && review != nil && review.UpdatedFiles != nil {
|
||||
// If there wasn't an error and we have a review with updated files, use that
|
||||
filesViewedState = review.UpdatedFiles
|
||||
}
|
||||
}
|
||||
|
||||
ctx.PageData["DiffFiles"] = transformDiffTreeForUI(diffTree, filesViewedState)
|
||||
}
|
||||
|
||||
ctx.Data["Diff"] = diff
|
||||
ctx.Data["DiffNotAvailable"] = diff.NumFiles == 0
|
||||
|
||||
|
@ -7,9 +7,11 @@ import (
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
pull_model "code.gitea.io/gitea/models/pull"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
||||
"github.com/go-enry/go-enry/v2"
|
||||
@ -55,6 +57,36 @@ func isExcludedEntry(entry *git.TreeEntry) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type FileDiffFile struct {
|
||||
Name string
|
||||
NameHash string
|
||||
IsSubmodule bool
|
||||
IsViewed bool
|
||||
Status string
|
||||
}
|
||||
|
||||
// transformDiffTreeForUI transforms a DiffTree into a slice of FileDiffFile for UI rendering
|
||||
// it also takes a map of file names to their viewed state, which is used to mark files as viewed
|
||||
func transformDiffTreeForUI(diffTree *gitdiff.DiffTree, filesViewedState map[string]pull_model.ViewedState) []FileDiffFile {
|
||||
files := make([]FileDiffFile, 0, len(diffTree.Files))
|
||||
|
||||
for _, file := range diffTree.Files {
|
||||
nameHash := git.HashFilePathForWebUI(file.HeadPath)
|
||||
isSubmodule := file.HeadMode == git.EntryModeCommit
|
||||
isViewed := filesViewedState[file.HeadPath] == pull_model.Viewed
|
||||
|
||||
files = append(files, FileDiffFile{
|
||||
Name: file.HeadPath,
|
||||
NameHash: nameHash,
|
||||
IsSubmodule: isSubmodule,
|
||||
IsViewed: isViewed,
|
||||
Status: file.Status,
|
||||
})
|
||||
}
|
||||
|
||||
return files
|
||||
}
|
||||
|
||||
func Tree(ctx *context.Context) {
|
||||
recursive := ctx.FormBool("recursive")
|
||||
|
||||
|
@ -6,12 +6,14 @@ package setting
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/templates"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/context"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
@ -39,18 +41,29 @@ func ApplicationsPost(ctx *context.Context) {
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
ctx.Data["UserDisabledFeatures"] = user_model.DisabledFeaturesWithLoginType(ctx.Doer)
|
||||
|
||||
if ctx.HasError() {
|
||||
loadApplicationsData(ctx)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSettingsApplications)
|
||||
return
|
||||
_ = ctx.Req.ParseForm()
|
||||
var scopeNames []string
|
||||
for k, v := range ctx.Req.Form {
|
||||
if strings.HasPrefix(k, "scope-") {
|
||||
scopeNames = append(scopeNames, v...)
|
||||
}
|
||||
}
|
||||
|
||||
scope, err := form.GetScope()
|
||||
scope, err := auth_model.AccessTokenScope(strings.Join(scopeNames, ",")).Normalize()
|
||||
if err != nil {
|
||||
ctx.ServerError("GetScope", err)
|
||||
return
|
||||
}
|
||||
if scope == "" || scope == auth_model.AccessTokenScopePublicOnly {
|
||||
ctx.Flash.Error(ctx.Tr("settings.at_least_one_permission"), true)
|
||||
}
|
||||
|
||||
if ctx.HasError() {
|
||||
loadApplicationsData(ctx)
|
||||
ctx.HTML(http.StatusOK, tplSettingsApplications)
|
||||
return
|
||||
}
|
||||
|
||||
t := &auth_model.AccessToken{
|
||||
UID: ctx.Doer.ID,
|
||||
Name: form.Name,
|
||||
@ -99,7 +112,14 @@ func loadApplicationsData(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["Tokens"] = tokens
|
||||
ctx.Data["EnableOAuth2"] = setting.OAuth2.Enabled
|
||||
ctx.Data["IsAdmin"] = ctx.Doer.IsAdmin
|
||||
|
||||
// Handle specific ordered token categories for admin or non-admin users
|
||||
tokenCategoryNames := auth_model.GetAccessTokenCategories()
|
||||
if !ctx.Doer.IsAdmin {
|
||||
tokenCategoryNames = util.SliceRemoveAll(tokenCategoryNames, "admin")
|
||||
}
|
||||
ctx.Data["TokenCategories"] = tokenCategoryNames
|
||||
|
||||
if setting.OAuth2.Enabled {
|
||||
ctx.Data["Applications"], err = db.Find[auth_model.OAuth2Application](ctx, auth_model.FindOAuth2ApplicationsOptions{
|
||||
OwnerID: ctx.Doer.ID,
|
||||
|
@ -1640,6 +1640,7 @@ func registerRoutes(m *web.Router) {
|
||||
m.Any("", devtest.List)
|
||||
m.Any("/fetch-action-test", devtest.FetchActionTest)
|
||||
m.Any("/{sub}", devtest.Tmpl)
|
||||
m.Get("/repo-action-view/{run}/{job}", devtest.MockActionsView)
|
||||
m.Post("/actions-mock/runs/{run}/jobs/{job}", web.Bind(actions.ViewRequest{}), devtest.MockActionsRunsJobs)
|
||||
})
|
||||
}
|
||||
|
@ -291,6 +291,11 @@ func RepoRefForAPI(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
ctx := GetAPIContext(req)
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
ctx.APIErrorNotFound("repository is empty")
|
||||
return
|
||||
}
|
||||
|
||||
if ctx.Repo.GitRepo == nil {
|
||||
ctx.APIErrorInternal(fmt.Errorf("no open git repo"))
|
||||
return
|
||||
|
@ -213,13 +213,16 @@ func Contexter() func(next http.Handler) http.Handler {
|
||||
// Attention: this function changes ctx.Data and ctx.Flash
|
||||
// If HasError is called, then before Redirect, the error message should be stored by ctx.Flash.Error(ctx.GetErrMsg()) again.
|
||||
func (ctx *Context) HasError() bool {
|
||||
hasErr, ok := ctx.Data["HasError"]
|
||||
if !ok {
|
||||
hasErr, _ := ctx.Data["HasError"].(bool)
|
||||
hasErr = hasErr || ctx.Flash.ErrorMsg != ""
|
||||
if !hasErr {
|
||||
return false
|
||||
}
|
||||
ctx.Flash.ErrorMsg = ctx.GetErrMsg()
|
||||
if ctx.Flash.ErrorMsg == "" {
|
||||
ctx.Flash.ErrorMsg = ctx.GetErrMsg()
|
||||
}
|
||||
ctx.Data["Flash"] = ctx.Flash
|
||||
return hasErr.(bool)
|
||||
return hasErr
|
||||
}
|
||||
|
||||
// GetErrMsg returns error message in form validation.
|
||||
|
@ -7,9 +7,7 @@ package forms
|
||||
import (
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/web/middleware"
|
||||
@ -347,8 +345,7 @@ func (f *EditVariableForm) Validate(req *http.Request, errs binding.Errors) bind
|
||||
|
||||
// NewAccessTokenForm form for creating access token
|
||||
type NewAccessTokenForm struct {
|
||||
Name string `binding:"Required;MaxSize(255)" locale:"settings.token_name"`
|
||||
Scope []string
|
||||
Name string `binding:"Required;MaxSize(255)" locale:"settings.token_name"`
|
||||
}
|
||||
|
||||
// Validate validates the fields
|
||||
@ -357,12 +354,6 @@ func (f *NewAccessTokenForm) Validate(req *http.Request, errs binding.Errors) bi
|
||||
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
|
||||
}
|
||||
|
||||
func (f *NewAccessTokenForm) GetScope() (auth_model.AccessTokenScope, error) {
|
||||
scope := strings.Join(f.Scope, ",")
|
||||
s, err := auth_model.AccessTokenScope(scope).Normalize()
|
||||
return s, err
|
||||
}
|
||||
|
||||
// EditOAuth2ApplicationForm form for editing oauth2 applications
|
||||
type EditOAuth2ApplicationForm struct {
|
||||
Name string `binding:"Required;MaxSize(255)" form:"application_name"`
|
||||
|
@ -4,10 +4,8 @@
|
||||
package forms
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"github.com/gobwas/glob"
|
||||
@ -104,28 +102,3 @@ func TestRegisterForm_IsDomainAllowed_BlockedEmail(t *testing.T) {
|
||||
assert.Equal(t, v.valid, form.IsEmailDomainAllowed())
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAccessTokenForm_GetScope(t *testing.T) {
|
||||
tests := []struct {
|
||||
form NewAccessTokenForm
|
||||
scope auth_model.AccessTokenScope
|
||||
expectedErr error
|
||||
}{
|
||||
{
|
||||
form: NewAccessTokenForm{Name: "test", Scope: []string{"read:repository"}},
|
||||
scope: "read:repository",
|
||||
},
|
||||
{
|
||||
form: NewAccessTokenForm{Name: "test", Scope: []string{"read:repository", "write:user"}},
|
||||
scope: "read:repository,write:user",
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
scope, err := test.form.GetScope()
|
||||
assert.Equal(t, test.expectedErr, err)
|
||||
assert.Equal(t, test.scope, scope)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -44,16 +44,17 @@ func UnlinkFromRepository(ctx context.Context, pkg *packages_model.Package, doer
|
||||
}
|
||||
|
||||
repo, err := repo_model.GetRepositoryByID(ctx, pkg.RepoID)
|
||||
if err != nil {
|
||||
if err != nil && !repo_model.IsErrRepoNotExist(err) {
|
||||
return fmt.Errorf("error getting repository %d: %w", pkg.RepoID, err)
|
||||
}
|
||||
|
||||
perms, err := access_model.GetUserRepoPermission(ctx, repo, doer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting permissions for user %d on repository %d: %w", doer.ID, repo.ID, err)
|
||||
}
|
||||
if !perms.CanWrite(unit.TypePackages) {
|
||||
return util.ErrPermissionDenied
|
||||
if err == nil {
|
||||
perms, err := access_model.GetUserRepoPermission(ctx, repo, doer)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting permissions for user %d on repository %d: %w", doer.ID, repo.ID, err)
|
||||
}
|
||||
if !perms.CanWrite(unit.TypePackages) {
|
||||
return util.ErrPermissionDenied
|
||||
}
|
||||
}
|
||||
|
||||
user, err := user_model.GetUserByID(ctx, pkg.OwnerID)
|
||||
|
@ -407,11 +407,10 @@ func AddTestPullRequestTask(doer *user_model.User, repoID int64, branch string,
|
||||
}
|
||||
|
||||
if isSync {
|
||||
requests := issues_model.PullRequestList(prs)
|
||||
if err = requests.LoadAttributes(ctx); err != nil {
|
||||
if err = prs.LoadAttributes(ctx); err != nil {
|
||||
log.Error("PullRequestList.LoadAttributes: %v", err)
|
||||
}
|
||||
if invalidationErr := checkForInvalidation(ctx, requests, repoID, doer, branch); invalidationErr != nil {
|
||||
if invalidationErr := checkForInvalidation(ctx, prs, repoID, doer, branch); invalidationErr != nil {
|
||||
log.Error("checkForInvalidation: %v", invalidationErr)
|
||||
}
|
||||
if err == nil {
|
||||
@ -645,7 +644,7 @@ func retargetBranchPulls(ctx context.Context, doer *user_model.User, repoID int6
|
||||
return err
|
||||
}
|
||||
|
||||
if err := issues_model.PullRequestList(prs).LoadAttributes(ctx); err != nil {
|
||||
if err := prs.LoadAttributes(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -672,11 +671,11 @@ func AdjustPullsCausedByBranchDeleted(ctx context.Context, doer *user_model.User
|
||||
return err
|
||||
}
|
||||
|
||||
if err := issues_model.PullRequestList(prs).LoadAttributes(ctx); err != nil {
|
||||
if err := prs.LoadAttributes(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
issues_model.PullRequestList(prs).SetHeadRepo(repo)
|
||||
if err := issues_model.PullRequestList(prs).LoadRepositories(ctx); err != nil {
|
||||
prs.SetHeadRepo(repo)
|
||||
if err := prs.LoadRepositories(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -707,11 +706,11 @@ func AdjustPullsCausedByBranchDeleted(ctx context.Context, doer *user_model.User
|
||||
return err
|
||||
}
|
||||
|
||||
if err := issues_model.PullRequestList(prs).LoadAttributes(ctx); err != nil {
|
||||
if err := prs.LoadAttributes(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
issues_model.PullRequestList(prs).SetBaseRepo(repo)
|
||||
if err := issues_model.PullRequestList(prs).LoadRepositories(ctx); err != nil {
|
||||
prs.SetBaseRepo(repo)
|
||||
if err := prs.LoadRepositories(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -744,7 +743,7 @@ func CloseRepoBranchesPulls(ctx context.Context, doer *user_model.User, repo *re
|
||||
return err
|
||||
}
|
||||
|
||||
if err = issues_model.PullRequestList(prs).LoadAttributes(ctx); err != nil {
|
||||
if err = prs.LoadAttributes(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
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"
|
||||
@ -267,6 +268,11 @@ func DeleteRepositoryDirectly(ctx context.Context, doer *user_model.User, repoID
|
||||
return err
|
||||
}
|
||||
|
||||
// unlink packages linked to this repository
|
||||
if err = packages_model.UnlinkRepositoryFromAllPackages(ctx, repoID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = committer.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -11,7 +11,6 @@ import (
|
||||
"code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
"code.gitea.io/gitea/models/organization"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
system_model "code.gitea.io/gitea/models/system"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
@ -63,11 +62,7 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod
|
||||
notify_service.DeleteRepository(ctx, doer, repo)
|
||||
}
|
||||
|
||||
if err := DeleteRepositoryDirectly(ctx, doer, repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return packages_model.UnlinkRepositoryFromAllPackages(ctx, repo.ID)
|
||||
return DeleteRepositoryDirectly(ctx, doer, repo.ID)
|
||||
}
|
||||
|
||||
// PushCreateRepo creates a repository when a new repository is pushed to an appropriate namespace
|
||||
|
@ -18,6 +18,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
webhook_model "code.gitea.io/gitea/models/webhook"
|
||||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/hostmatcher"
|
||||
@ -92,10 +93,10 @@ func newDefaultRequest(ctx context.Context, w *webhook_model.Webhook, t *webhook
|
||||
}
|
||||
|
||||
body = []byte(t.PayloadContent)
|
||||
return req, body, addDefaultHeaders(req, []byte(w.Secret), t, body)
|
||||
return req, body, addDefaultHeaders(req, []byte(w.Secret), w, t, body)
|
||||
}
|
||||
|
||||
func addDefaultHeaders(req *http.Request, secret []byte, t *webhook_model.HookTask, payloadContent []byte) error {
|
||||
func addDefaultHeaders(req *http.Request, secret []byte, w *webhook_model.Webhook, t *webhook_model.HookTask, payloadContent []byte) error {
|
||||
var signatureSHA1 string
|
||||
var signatureSHA256 string
|
||||
if len(secret) > 0 {
|
||||
@ -112,10 +113,27 @@ func addDefaultHeaders(req *http.Request, secret []byte, t *webhook_model.HookTa
|
||||
|
||||
event := t.EventType.Event()
|
||||
eventType := string(t.EventType)
|
||||
targetType := "default"
|
||||
if w.IsSystemWebhook {
|
||||
targetType = "system"
|
||||
} else if w.RepoID != 0 {
|
||||
targetType = "repository"
|
||||
} else if w.OwnerID != 0 {
|
||||
owner, err := user_model.GetUserByID(req.Context(), w.OwnerID)
|
||||
if owner != nil && err == nil {
|
||||
if owner.IsOrganization() {
|
||||
targetType = "organization"
|
||||
} else {
|
||||
targetType = "user"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
req.Header.Add("X-Gitea-Delivery", t.UUID)
|
||||
req.Header.Add("X-Gitea-Event", event)
|
||||
req.Header.Add("X-Gitea-Event-Type", eventType)
|
||||
req.Header.Add("X-Gitea-Signature", signatureSHA256)
|
||||
req.Header.Add("X-Gitea-Hook-Installation-Target-Type", targetType)
|
||||
req.Header.Add("X-Gogs-Delivery", t.UUID)
|
||||
req.Header.Add("X-Gogs-Event", event)
|
||||
req.Header.Add("X-Gogs-Event-Type", eventType)
|
||||
@ -125,6 +143,7 @@ func addDefaultHeaders(req *http.Request, secret []byte, t *webhook_model.HookTa
|
||||
req.Header["X-GitHub-Delivery"] = []string{t.UUID}
|
||||
req.Header["X-GitHub-Event"] = []string{event}
|
||||
req.Header["X-GitHub-Event-Type"] = []string{eventType}
|
||||
req.Header["X-GitHub-Hook-Installation-Target-Type"] = []string{targetType}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ func newMatrixRequest(_ context.Context, w *webhook_model.Webhook, t *webhook_mo
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
return req, body, addDefaultHeaders(req, []byte(w.Secret), t, body) // likely useless, but has always been sent historially
|
||||
return req, body, addDefaultHeaders(req, []byte(w.Secret), w, t, body) // likely useless, but has always been sent historially
|
||||
}
|
||||
|
||||
const matrixPayloadSizeLimit = 1024 * 64
|
||||
|
@ -107,7 +107,7 @@ func newJSONRequest[T any](pc payloadConvertor[T], w *webhook_model.Webhook, t *
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
if withDefaultHeaders {
|
||||
return req, body, addDefaultHeaders(req, []byte(w.Secret), t, body)
|
||||
return req, body, addDefaultHeaders(req, []byte(w.Secret), w, t, body)
|
||||
}
|
||||
return req, body, nil
|
||||
}
|
||||
|
@ -9,30 +9,25 @@
|
||||
{{if .User.IsAdmin}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "admin.users.admin"}}</span>
|
||||
{{end}}
|
||||
{{if .User.IsTypeBot}}
|
||||
<span class="ui basic label">{{ctx.Locale.Tr "admin.users.bot"}}</span>
|
||||
{{end}}
|
||||
</div>
|
||||
<div class="flex-item-body">
|
||||
<b>{{ctx.Locale.Tr "admin.users.auth_source"}}:</b>
|
||||
{{if eq .LoginSource.ID 0}}
|
||||
{{ctx.Locale.Tr "admin.users.local"}}
|
||||
{{else}}
|
||||
{{.LoginSource.Name}}
|
||||
{{end}}
|
||||
{{Iif (eq .LoginSource.ID 0) (ctx.Locale.Tr "admin.users.local") .LoginSource.Name}}
|
||||
</div>
|
||||
<div class="flex-item-body">
|
||||
<b>{{ctx.Locale.Tr "admin.users.activated"}}:</b>
|
||||
{{if .User.IsActive}}
|
||||
{{svg "octicon-check"}}
|
||||
{{else}}
|
||||
{{svg "octicon-x"}}
|
||||
{{end}}
|
||||
{{svg (Iif .User.IsActive "octicon-check" "octicon-x")}}
|
||||
</div>
|
||||
<div class="flex-item-body">
|
||||
<b>{{ctx.Locale.Tr "admin.users.prohibit_login"}}:</b>
|
||||
{{svg (Iif .User.ProhibitLogin "octicon-check" "octicon-x")}}
|
||||
</div>
|
||||
<div class="flex-item-body">
|
||||
<b>{{ctx.Locale.Tr "admin.users.restricted"}}:</b>
|
||||
{{if .User.IsRestricted}}
|
||||
{{svg "octicon-check"}}
|
||||
{{else}}
|
||||
{{svg "octicon-x"}}
|
||||
{{end}}
|
||||
{{svg (Iif .User.IsRestricted "octicon-check" "octicon-x")}}
|
||||
</div>
|
||||
<div class="flex-item-body">
|
||||
<b>{{ctx.Locale.Tr "settings.visibility"}}:</b>
|
||||
@ -42,11 +37,7 @@
|
||||
</div>
|
||||
<div class="flex-item-body">
|
||||
<b>{{ctx.Locale.Tr "admin.users.2fa"}}:</b>
|
||||
{{if .TwoFactorEnabled}}
|
||||
<span class="text green">{{svg "octicon-check"}}</span>
|
||||
{{else}}
|
||||
{{svg "octicon-x"}}
|
||||
{{end}}
|
||||
{{svg (Iif .TwoFactorEnabled "octicon-check" "octicon-x")}}
|
||||
</div>
|
||||
{{if .User.Language}}
|
||||
<div class="flex-item-body">
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="flex-item">
|
||||
<div class="flex-item-main">
|
||||
<div class="flex-text-block">
|
||||
{{.Email}}
|
||||
<a href="mailto:{{.Email}}">{{.Email}}</a>
|
||||
{{if .IsPrimary}}
|
||||
<div class="ui primary label">{{ctx.Locale.Tr "settings.primary"}}</div>
|
||||
{{end}}
|
||||
|
@ -1,20 +1,20 @@
|
||||
{{if .Flash.ErrorMsg}}
|
||||
{{- if .Flash.ErrorMsg -}}
|
||||
<div class="ui negative message flash-message flash-error">
|
||||
<p>{{.Flash.ErrorMsg | SanitizeHTML}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .Flash.SuccessMsg}}
|
||||
{{- end -}}
|
||||
{{- if .Flash.SuccessMsg -}}
|
||||
<div class="ui positive message flash-message flash-success">
|
||||
<p>{{.Flash.SuccessMsg | SanitizeHTML}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .Flash.InfoMsg}}
|
||||
{{- end -}}
|
||||
{{- if .Flash.InfoMsg -}}
|
||||
<div class="ui info message flash-message flash-info">
|
||||
<p>{{.Flash.InfoMsg | SanitizeHTML}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .Flash.WarningMsg}}
|
||||
{{- end -}}
|
||||
{{- if .Flash.WarningMsg -}}
|
||||
<div class="ui warning message flash-message flash-warning">
|
||||
<p>{{.Flash.WarningMsg | SanitizeHTML}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{- end -}}
|
||||
|
@ -17,7 +17,7 @@
|
||||
{{if eq .Num -1}}
|
||||
<a class="disabled item">...</a>
|
||||
{{else}}
|
||||
<a class="{{if .IsCurrent}}active {{end}}item tw-content-center" {{if not .IsCurrent}}href="{{$paginationLink}}?page={{.Num}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>{{.Num}}</a>
|
||||
<a class="{{if .IsCurrent}}active {{end}}item" {{if not .IsCurrent}}href="{{$paginationLink}}?page={{.Num}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>{{.Num}}</a>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<a class="{{if not .HasNext}}disabled{{end}} item navigation" {{if .HasNext}}href="{{$paginationLink}}?page={{.Next}}{{if $paginationParams}}&{{$paginationParams}}{{end}}"{{end}}>
|
||||
|
@ -1,8 +1,13 @@
|
||||
{{template "base/head" .}}
|
||||
<div class="page-content">
|
||||
<div class="tw-flex tw-justify-center tw-items-center tw-gap-5">
|
||||
<a href="/devtest/repo-action-view/10/100">Run:CanCancel</a>
|
||||
<a href="/devtest/repo-action-view/20/200">Run:CanApprove</a>
|
||||
<a href="/devtest/repo-action-view/30/300">Run:CanRerun</a>
|
||||
</div>
|
||||
{{template "repo/actions/view_component" (dict
|
||||
"RunIndex" 1
|
||||
"JobIndex" 2
|
||||
"RunIndex" (or .RunID 10)
|
||||
"JobIndex" (or .JobID 100)
|
||||
"ActionsURL" (print AppSubUrl "/devtest/actions-mock")
|
||||
)}}
|
||||
</div>
|
||||
|
@ -14,6 +14,7 @@
|
||||
{{if $.CloneButtonShowSSH}}
|
||||
<button class="item repo-clone-ssh" data-link="{{$.CloneButtonOriginLink.SSH}}">SSH</button>
|
||||
{{end}}
|
||||
<button class="item repo-clone-tea" data-link="{{$.CloneButtonOriginLink.Tea}}">Tea CLI</button>
|
||||
</div>
|
||||
<div class="divider"></div>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{{$showFileTree := (and (not .DiffNotAvailable) (gt .Diff.NumFiles 1))}}
|
||||
<div>
|
||||
<div class="diff-detail-box diff-box">
|
||||
<div class="diff-detail-box">
|
||||
<div class="tw-flex tw-items-center tw-flex-wrap tw-gap-2 tw-ml-0.5">
|
||||
{{if $showFileTree}}
|
||||
<button class="diff-toggle-file-tree-button not-mobile btn interact-fg" data-show-text="{{ctx.Locale.Tr "repo.diff.show_file_tree"}}" data-hide-text="{{ctx.Locale.Tr "repo.diff.hide_file_tree"}}">
|
||||
@ -57,32 +57,6 @@
|
||||
<div>{{ctx.Locale.Tr "repo.pulls.showing_specified_commit_range" (ShortSha .BeforeCommitID) (ShortSha .AfterCommitID)}} - <a href="{{$.Issue.Link}}/files?style={{if $.IsSplitStyle}}split{{else}}unified{{end}}&whitespace={{$.WhitespaceBehavior}}&show-outdated={{$.ShowOutdatedComments}}">{{ctx.Locale.Tr "repo.pulls.show_all_commits"}}</a></div>
|
||||
</div>
|
||||
{{end}}
|
||||
<script id="diff-data-script" type="module">
|
||||
const diffDataFiles = [{{range $i, $file := .Diff.Files}}{Name:"{{$file.Name}}",NameHash:"{{$file.NameHash}}",Type:{{$file.Type}},IsBin:{{$file.IsBin}},IsSubmodule:{{$file.IsSubmodule}},Addition:{{$file.Addition}},Deletion:{{$file.Deletion}},IsViewed:{{$file.IsViewed}}},{{end}}];
|
||||
const diffData = {
|
||||
isIncomplete: {{.Diff.IsIncomplete}},
|
||||
tooManyFilesMessage: "{{ctx.Locale.Tr "repo.diff.too_many_files"}}",
|
||||
binaryFileMessage: "{{ctx.Locale.Tr "repo.diff.bin"}}",
|
||||
showMoreMessage: "{{ctx.Locale.Tr "repo.diff.show_more"}}",
|
||||
statisticsMessage: "{{ctx.Locale.Tr "repo.diff.stats_desc_file"}}",
|
||||
linkLoadMore: "?skip-to={{.Diff.End}}&file-only=true",
|
||||
};
|
||||
|
||||
// for first time loading, the diffFileInfo is a plain object
|
||||
// after the Vue component is mounted, the diffFileInfo is a reactive object
|
||||
// keep in mind that this script block would be executed many times when loading more files, by "loadMoreFiles"
|
||||
let diffFileInfo = window.config.pageData.diffFileInfo || {
|
||||
files:[],
|
||||
fileTreeIsVisible: false,
|
||||
fileListIsVisible: false,
|
||||
isLoadingNewData: false,
|
||||
selectedItem: '',
|
||||
};
|
||||
diffFileInfo = Object.assign(diffFileInfo, diffData);
|
||||
diffFileInfo.files.push(...diffDataFiles);
|
||||
window.config.pageData.diffFileInfo = diffFileInfo;
|
||||
</script>
|
||||
<div id="diff-file-list"></div>
|
||||
{{end}}
|
||||
<div id="diff-container">
|
||||
{{if $showFileTree}}
|
||||
@ -106,7 +80,7 @@
|
||||
{{$showFileViewToggle := or $isImage (and (not $file.IsIncomplete) $isCsv)}}
|
||||
{{$isExpandable := or (gt $file.Addition 0) (gt $file.Deletion 0) $file.IsBin}}
|
||||
{{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.Repository.IsArchived) $.IsShowingAllCommits}}
|
||||
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}} tw-mt-0" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if or ($file.ShouldBeHidden) (not $isExpandable)}}data-folded="true"{{end}}>
|
||||
<div class="diff-file-box file-content {{TabSizeClass $.Editorconfig $file.Name}} tw-mt-0" id="diff-{{$file.NameHash}}" data-old-filename="{{$file.OldName}}" data-new-filename="{{$file.Name}}" {{if or ($file.ShouldBeHidden) (not $isExpandable)}}data-folded="true"{{end}}>
|
||||
<h4 class="diff-file-header sticky-2nd-row ui top attached header">
|
||||
<div class="diff-file-name tw-flex tw-flex-1 tw-items-center tw-gap-1 tw-flex-wrap">
|
||||
<button class="fold-file btn interact-bg tw-p-1{{if not $isExpandable}} tw-invisible{{end}}">
|
||||
@ -235,7 +209,7 @@
|
||||
{{end}}
|
||||
|
||||
{{if .Diff.IsIncomplete}}
|
||||
<div class="diff-file-box diff-box file-content tw-mt-2" id="diff-incomplete">
|
||||
<div class="diff-file-box file-content tw-mt-2" id="diff-incomplete">
|
||||
<h4 class="ui top attached header tw-font-normal tw-flex tw-items-center tw-justify-between">
|
||||
{{ctx.Locale.Tr "repo.diff.too_many_files"}}
|
||||
<a class="ui basic tiny button" id="diff-show-more-files" data-href="?skip-to={{.Diff.End}}&file-only=true">{{ctx.Locale.Tr "repo.diff.show_more"}}</a>
|
||||
|
@ -1,7 +1,6 @@
|
||||
<div class="ui dropdown tiny basic button" data-tooltip-content="{{ctx.Locale.Tr "repo.diff.options_button"}}">
|
||||
{{svg "octicon-kebab-horizontal"}}
|
||||
<div class="menu">
|
||||
<a class="item" id="show-file-list-btn">{{ctx.Locale.Tr "repo.diff.show_diff_stats"}}</a>
|
||||
{{if .Issue.Index}}
|
||||
<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.patch" download="{{.Issue.Index}}.patch">{{ctx.Locale.Tr "repo.diff.download_patch"}}</a>
|
||||
<a class="item" href="{{$.RepoLink}}/pulls/{{.Issue.Index}}.diff" download="{{.Issue.Index}}.diff">{{ctx.Locale.Tr "repo.diff.download_diff"}}</a>
|
||||
|
@ -1,6 +1,4 @@
|
||||
{{if .Flash}}
|
||||
{{template "base/alert" .}}
|
||||
{{end}}
|
||||
<form class="issue-content ui comment form form-fetch-action" id="new-issue" action="{{.Link}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="issue-content-left">
|
||||
@ -9,7 +7,10 @@
|
||||
{{ctx.AvatarUtils.Avatar .SignedUser 40}}
|
||||
<div class="ui segment content tw-my-0">
|
||||
<div class="field">
|
||||
<input name="title" class="js-autofocus-end" id="issue_title" placeholder="{{ctx.Locale.Tr "repo.milestones.title"}}" value="{{if .TitleQuery}}{{.TitleQuery}}{{else if .IssueTemplateTitle}}{{.IssueTemplateTitle}}{{else}}{{.title}}{{end}}" required maxlength="255" autocomplete="off">
|
||||
<input name="title" data-global-init="initInputAutoFocusEnd" id="issue_title" required maxlength="255" autocomplete="off"
|
||||
placeholder="{{ctx.Locale.Tr "repo.milestones.title"}}"
|
||||
value="{{if .TitleQuery}}{{.TitleQuery}}{{else if .IssueTemplateTitle}}{{.IssueTemplateTitle}}{{else}}{{.title}}{{end}}"
|
||||
>
|
||||
{{if .PageIsComparePull}}
|
||||
<div class="title_wip_desc" data-wip-prefixes="{{JsonUtils.EncodeToString .PullRequestWorkInProgressPrefixes}}">{{ctx.Locale.Tr "repo.pulls.title_wip_desc" (index .PullRequestWorkInProgressPrefixes 0)}}</div>
|
||||
{{end}}
|
||||
|
@ -17,7 +17,7 @@
|
||||
{{ctx.Locale.PrettyNumber .OpenCount}} {{ctx.Locale.Tr "repo.issues.open_title"}}
|
||||
</a>
|
||||
<a class="{{if eq .State "closed"}}active {{end}}item flex-text-inline" href="{{if eq .State "closed"}}{{$allStatesLink}}{{else}}{{$closedLink}}{{end}}">
|
||||
{{svg "octicon-check"}}
|
||||
{{svg "octicon-issue-closed"}}
|
||||
{{ctx.Locale.PrettyNumber .ClosedCount}} {{ctx.Locale.Tr "repo.issues.closed_title"}}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -1,13 +1,18 @@
|
||||
{{if and .Issue.IsPull .IsIssuePoster (not .Issue.IsClosed) .Issue.PullRequest.HeadRepo}}
|
||||
{{if and (not (eq .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName)) .CanWriteToHeadRepo}}
|
||||
{{- $isHeadForkedRepo := and .Issue.PullRequest .Issue.PullRequest.HeadRepo (ne .Issue.PullRequest.HeadRepo.FullName .Issue.PullRequest.BaseRepo.FullName) -}}
|
||||
{{if $isHeadForkedRepo}}
|
||||
{{- $isPullPoster := and .Issue.IsPull .IsIssuePoster -}}
|
||||
{{- $isPullEditable := and .Issue.PullRequest (not .Issue.IsClosed) (not .Repository.IsArchived) -}}
|
||||
{{- $allowToChange := and $isPullPoster $isPullEditable -}}
|
||||
<div class="divider"></div>
|
||||
<div class="ui checkbox loading-icon-2px" id="allow-edits-from-maintainers"
|
||||
<div class="ui checkbox {{if not $allowToChange}}disabled{{end}} loading-icon-2px"
|
||||
{{if $allowToChange}}
|
||||
id="allow-edits-from-maintainers"
|
||||
data-url="{{.Issue.Link}}"
|
||||
data-tooltip-content="{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers_desc"}}"
|
||||
data-prompt-error="{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers_err"}}"
|
||||
{{end}}
|
||||
>
|
||||
<label><strong>{{ctx.Locale.Tr "repo.pulls.allow_edits_from_maintainers"}}</strong></label>
|
||||
<input type="checkbox" {{if .Issue.PullRequest.AllowMaintainerEdit}}checked{{end}}>
|
||||
<input type="checkbox" {{if .Issue.PullRequest.AllowMaintainerEdit}}checked{{end}} {{if not $allowToChange}}disabled{{end}}>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/assignee?issue_ids={{$pageMeta.Issue.ID}}"{{end}}
|
||||
>
|
||||
<input class="combo-value" name="assignee_ids" type="hidden" value="{{$data.SelectedAssigneeIDs}}">
|
||||
<div class="ui dropdown {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<div class="ui dropdown text-flex-grow {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<a class="text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.new.assignees"}}</strong> {{if $pageMeta.CanModifyIssueOrPull}}{{svg "octicon-gear"}}{{end}}
|
||||
</a>
|
||||
|
@ -4,7 +4,7 @@
|
||||
{{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/labels?issue_ids={{$pageMeta.Issue.ID}}"{{end}}
|
||||
>
|
||||
<input class="combo-value" name="label_ids" type="hidden" value="{{$data.SelectedLabelIDs}}">
|
||||
<div class="ui dropdown {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<div class="ui dropdown text-flex-grow {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<a class="text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.new.labels"}}</strong> {{if $pageMeta.CanModifyIssueOrPull}}{{svg "octicon-gear"}}{{end}}
|
||||
</a>
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/milestone?issue_ids={{$pageMeta.Issue.ID}}"{{end}}
|
||||
>
|
||||
<input class="combo-value" name="milestone_id" type="hidden" value="{{$data.SelectedMilestoneID}}">
|
||||
<div class="ui dropdown {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<div class="ui dropdown text-flex-grow {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<a class="text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.new.milestone"}}</strong> {{if $pageMeta.CanModifyIssueOrPull}}{{svg "octicon-gear"}}{{end}}
|
||||
</a>
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/projects?issue_ids={{$pageMeta.Issue.ID}}"{{end}}
|
||||
>
|
||||
<input class="combo-value" name="project_id" type="hidden" value="{{$data.SelectedProjectID}}">
|
||||
<div class="ui dropdown {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<div class="ui dropdown text-flex-grow {{if not $pageMeta.CanModifyIssueOrPull}}disabled{{end}}">
|
||||
<a class="text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.new.projects"}}</strong> {{if $pageMeta.CanModifyIssueOrPull}}{{svg "octicon-gear"}}{{end}}
|
||||
</a>
|
||||
|
@ -6,7 +6,7 @@
|
||||
{{if $pageMeta.Issue}}data-update-url="{{$pageMeta.RepoLink}}/issues/request_review?issue_ids={{$pageMeta.Issue.ID}}"{{end}}
|
||||
>
|
||||
<input type="hidden" class="combo-value" name="reviewer_ids">{{/* match CreateIssueForm */}}
|
||||
<div class="ui dropdown {{if or (not $hasCandidates) (not $data.CanChooseReviewer)}}disabled{{end}}">
|
||||
<div class="ui dropdown text-flex-grow {{if or (not $hasCandidates) (not $data.CanChooseReviewer)}}disabled{{end}}">
|
||||
<a class="text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.review.reviewers"}}</strong> {{if $data.CanChooseReviewer}}{{svg "octicon-gear"}}{{end}}
|
||||
</a>
|
||||
|
@ -2,10 +2,12 @@
|
||||
{{if and .CanUseTimetracker (not .Repository.IsArchived)}}
|
||||
<div class="divider"></div>
|
||||
<div>
|
||||
<div class="ui dropdown jump">
|
||||
<div class="ui dropdown text-flex-grow jump">
|
||||
<a class="text muted">
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.tracker"}}</strong> {{svg "octicon-gear"}}
|
||||
{{if $.IsStopwatchRunning}}{{svg "octicon-stopwatch"}}{{end}}
|
||||
<div>
|
||||
<strong>{{ctx.Locale.Tr "repo.issues.tracker"}}</strong> {{if $.IsStopwatchRunning}}{{svg "octicon-stopwatch"}}{{end}}
|
||||
</div>
|
||||
{{svg "octicon-gear"}}
|
||||
</a>
|
||||
<div class="menu">
|
||||
<a class="item issue-set-time-estimate show-modal" data-modal="#issue-time-set-estimate-modal">
|
||||
|
@ -3,7 +3,7 @@
|
||||
<a class="muted">{{svg "octicon-smiley"}}</a>
|
||||
<div class="menu">
|
||||
{{range $value := AllowedReactions}}
|
||||
<a class="item emoji comment-reaction-button" data-tooltip-content="{{$value}}" aria-label="{{$value}}" data-reaction-content="{{$value}}">{{ReactionToEmoji $value}}</a>
|
||||
<a class="item emoji" data-tooltip-content="{{$value}}" aria-label="{{$value}}" data-reaction-content="{{$value}}" data-global-click="onCommentReactionButtonClick">{{ReactionToEmoji $value}}</a>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -40,7 +40,7 @@
|
||||
{{if $diff}}
|
||||
{{$file := (index $diff.Files 0)}}
|
||||
<div id="code-preview-{{$comment.ID}}" class="ui table segment{{if $resolved}} tw-hidden{{end}}">
|
||||
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}">
|
||||
<div class="diff-file-box file-content {{TabSizeClass $.Editorconfig $file.Name}}">
|
||||
<div class="file-body file-code code-view code-diff code-diff-unified unicode-escaped">
|
||||
<table>
|
||||
<tbody>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<div class="bottom-reactions" data-action-url="{{$.ActionURL}}">
|
||||
{{range $key, $value := .Reactions}}
|
||||
{{$hasReacted := $value.HasUser ctx.RootData.SignedUserID}}
|
||||
<a role="button" class="ui label basic{{if $hasReacted}} primary{{end}}{{if not ctx.RootData.IsSigned}} disabled{{end}} comment-reaction-button"
|
||||
data-tooltip-content
|
||||
title="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}"
|
||||
<a role="button" class="ui label basic{{if $hasReacted}} primary{{end}}{{if not ctx.RootData.IsSigned}} disabled{{end}}"
|
||||
data-global-click="onCommentReactionButtonClick"
|
||||
data-tooltip-content title="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}"
|
||||
aria-label="{{$value.GetFirstUsers}}{{if gt ($value.GetMoreUserCount) 0}} {{ctx.Locale.Tr "repo.reactions_more" $value.GetMoreUserCount}}{{end}}"
|
||||
data-tooltip-placement="bottom-start"
|
||||
data-reaction-content="{{$key}}" data-has-reacted="{{$hasReacted}}">
|
||||
|
@ -153,6 +153,11 @@
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="tw-text-center tw-p-8">
|
||||
<h3 class="tw-my-4">{{ctx.Locale.Tr "repo.issues.filter_no_results"}}</h3>
|
||||
<p class="tw-text-placeholder-text">{{ctx.Locale.Tr "repo.issues.filter_no_results_placeholder"}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .IssueIndexerUnavailable}}
|
||||
<div class="ui error message">
|
||||
|
@ -11,7 +11,7 @@
|
||||
<div class="repository search">
|
||||
{{range $result := .SearchResults}}
|
||||
{{$repo := or $.Repo (index $.RepoMaps .RepoID)}}
|
||||
<div class="diff-file-box diff-box file-content non-diff-file-content repo-search-result">
|
||||
<div class="diff-file-box file-content non-diff-file-content repo-search-result">
|
||||
<h4 class="ui top attached header tw-font-normal tw-flex tw-flex-wrap">
|
||||
{{if not $.Repo}}
|
||||
<span class="file tw-flex-1">
|
||||
|
6
templates/swagger/v1_input.json
Normal file
6
templates/swagger/v1_input.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info": {
|
||||
"version": "{{AppVer | JSEscape}}"
|
||||
},
|
||||
"basePath": "{{AppSubUrl | JSEscape}}/api/v1"
|
||||
}
|
8
templates/swagger/v1_json.tmpl
generated
8
templates/swagger/v1_json.tmpl
generated
@ -12047,6 +12047,12 @@
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by target base branch of the pull request",
|
||||
"name": "base_branch",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"enum": [
|
||||
"open",
|
||||
@ -27580,4 +27586,4 @@
|
||||
"TOTPHeader": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@ -50,49 +50,41 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui bottom attached segment">
|
||||
<h5 class="ui top header">
|
||||
{{ctx.Locale.Tr "settings.generate_new_token"}}
|
||||
</h5>
|
||||
<form id="scoped-access-form" class="ui form ignore-dirty" action="{{.Link}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_Name}}error{{end}}">
|
||||
<label for="name">{{ctx.Locale.Tr "settings.token_name"}}</label>
|
||||
<input id="name" name="name" value="{{.name}}" autofocus required maxlength="255">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{ctx.Locale.Tr "settings.repo_and_org_access"}}</label>
|
||||
<label class="tw-cursor-pointer">
|
||||
<input class="enable-system tw-mt-1 tw-mr-1" type="radio" name="scope" value="{{$.AccessTokenScopePublicOnly}}">
|
||||
{{ctx.Locale.Tr "settings.permissions_public_only"}}
|
||||
</label>
|
||||
<label class="tw-cursor-pointer">
|
||||
<input class="enable-system tw-mt-1 tw-mr-1" type="radio" name="scope" value="" checked>
|
||||
{{ctx.Locale.Tr "settings.permissions_access_all"}}
|
||||
</label>
|
||||
</div>
|
||||
<details class="ui optional field">
|
||||
<summary class="tw-pb-4 tw-pl-1">
|
||||
{{ctx.Locale.Tr "settings.select_permissions"}}
|
||||
</summary>
|
||||
<p class="activity meta">
|
||||
<i>{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (`href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`|SafeHTML)}}</i>
|
||||
</p>
|
||||
<div id="scoped-access-token-selector"
|
||||
data-is-admin="{{if .IsAdmin}}true{{else}}false{{end}}"
|
||||
data-no-access-label="{{ctx.Locale.Tr "settings.permission_no_access"}}"
|
||||
data-read-label="{{ctx.Locale.Tr "settings.permission_read"}}"
|
||||
data-write-label="{{ctx.Locale.Tr "settings.permission_write"}}"
|
||||
data-locale-component-failed-to-load="{{ctx.Locale.Tr "graphs.component_failed_to_load"}}"
|
||||
>
|
||||
<details {{if or .name (not .Tokens)}}open{{end}}>
|
||||
<summary><h4 class="ui header tw-inline-block tw-my-2">{{ctx.Locale.Tr "settings.generate_new_token"}}</h4></summary>
|
||||
<form class="ui form ignore-dirty" action="{{.Link}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_Name}}error{{end}}">
|
||||
<label for="name">{{ctx.Locale.Tr "settings.token_name"}}</label>
|
||||
<input id="name" name="name" value="{{.name}}" required maxlength="255">
|
||||
</div>
|
||||
</details>
|
||||
<button id="scoped-access-submit" class="ui primary button">
|
||||
{{ctx.Locale.Tr "settings.generate_token"}}
|
||||
</button>
|
||||
</form>{{/* Fomantic ".ui.form .warning.message" is hidden by default, so put the warning message out of the form*/}}
|
||||
<div id="scoped-access-warning" class="ui warning message center tw-hidden">
|
||||
{{ctx.Locale.Tr "settings.at_least_one_permission"}}
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="tw-my-2">{{ctx.Locale.Tr "settings.repo_and_org_access"}}</div>
|
||||
<label class="gt-checkbox">
|
||||
<input type="radio" name="scope-public-only" value="{{$.AccessTokenScopePublicOnly}}"> {{ctx.Locale.Tr "settings.permissions_public_only"}}
|
||||
</label>
|
||||
<label class="gt-checkbox">
|
||||
<input type="radio" name="scope-public-only" value="" checked> {{ctx.Locale.Tr "settings.permissions_access_all"}}
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<div class="tw-my-2">{{ctx.Locale.Tr "settings.access_token_desc" (HTMLFormat `href="%s/api/swagger" target="_blank"` AppSubUrl) (`href="https://docs.gitea.com/development/oauth2-provider#scopes" target="_blank"`|SafeHTML)}}</div>
|
||||
<table class="ui table unstackable tw-my-2">
|
||||
{{range $category := .TokenCategories}}
|
||||
<tr>
|
||||
<td>{{$category}}</td>
|
||||
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="" checked> {{ctx.Locale.Tr "settings.permission_no_access"}}</label></td>
|
||||
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="read:{{$category}}"> {{ctx.Locale.Tr "settings.permission_read"}}</label></td>
|
||||
<td><label class="gt-checkbox"><input type="radio" name="scope-{{$category}}" value="write:{{$category}}"> {{ctx.Locale.Tr "settings.permission_write"}}</label></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</table>
|
||||
</div>
|
||||
<button class="ui primary button">
|
||||
{{ctx.Locale.Tr "settings.generate_token"}}
|
||||
</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
{{if .EnableOAuth2}}
|
||||
|
@ -48,33 +48,33 @@
|
||||
</div>
|
||||
|
||||
<div class="ui bottom attached segment">
|
||||
<h5 class="ui top header">
|
||||
{{ctx.Locale.Tr "settings.create_oauth2_application"}}
|
||||
</h5>
|
||||
<form class="ui form ignore-dirty" action="{{.Link}}/oauth2" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||
<label for="application-name">{{ctx.Locale.Tr "settings.oauth2_application_name"}}</label>
|
||||
<input id="application-name" name="application_name" value="{{.application_name}}" required maxlength="255">
|
||||
</div>
|
||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||
<label for="redirect-uris">{{ctx.Locale.Tr "settings.oauth2_redirect_uris"}}</label>
|
||||
<textarea name="redirect_uris" id="redirect-uris"></textarea>
|
||||
</div>
|
||||
<div class="field {{if .Err_ConfidentialClient}}error{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label>
|
||||
<input class="disable-setting" type="checkbox" name="confidential_client" data-target="#skip-secondary-authorization" checked>
|
||||
<details {{if .application_name}}open{{end}}>
|
||||
<summary><h4 class="ui header tw-inline-block tw-my-2">{{ctx.Locale.Tr "settings.create_oauth2_application"}}</h4></summary>
|
||||
<form class="ui form ignore-dirty" action="{{.Link}}/oauth2" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||
<label for="application-name">{{ctx.Locale.Tr "settings.oauth2_application_name"}}</label>
|
||||
<input id="application-name" name="application_name" value="{{.application_name}}" required maxlength="255">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if .Err_SkipSecondaryAuthorization}}error{{end}} disabled" id="skip-secondary-authorization">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "settings.oauth2_skip_secondary_authorization"}}</label>
|
||||
<input type="checkbox" name="skip_secondary_authorization">
|
||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||
<label for="redirect-uris">{{ctx.Locale.Tr "settings.oauth2_redirect_uris"}}</label>
|
||||
<textarea name="redirect_uris" id="redirect-uris"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui primary button">
|
||||
{{ctx.Locale.Tr "settings.create_oauth2_application_button"}}
|
||||
</button>
|
||||
</form>
|
||||
<div class="field {{if .Err_ConfidentialClient}}error{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label>
|
||||
<input class="disable-setting" type="checkbox" name="confidential_client" data-target="#skip-secondary-authorization" checked>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field {{if .Err_SkipSecondaryAuthorization}}error{{end}} disabled" id="skip-secondary-authorization">
|
||||
<div class="ui checkbox">
|
||||
<label>{{ctx.Locale.Tr "settings.oauth2_skip_secondary_authorization"}}</label>
|
||||
<input type="checkbox" name="skip_secondary_authorization">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui primary button">
|
||||
{{ctx.Locale.Tr "settings.create_oauth2_application_button"}}
|
||||
</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
|
@ -76,7 +76,7 @@ func TestAPIAdminOrgCreateNotAdmin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
nonAdminUsername := "user2"
|
||||
session := loginUser(t, nonAdminUsername)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
|
||||
org := api.CreateOrgOption{
|
||||
UserName: "user2_org",
|
||||
FullName: "User2's organization",
|
||||
|
@ -76,7 +76,7 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
||||
var newPublicKey api.PublicKey
|
||||
DecodeJSON(t, resp, &newPublicKey)
|
||||
|
||||
token = getUserToken(t, normalUsername)
|
||||
token = getUserToken(t, normalUsername, auth_model.AccessTokenScopeAll)
|
||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d", adminUsername, newPublicKey.ID).
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
@ -139,7 +139,7 @@ func TestAPIListUsersNotLoggedIn(t *testing.T) {
|
||||
func TestAPIListUsersNonAdmin(t *testing.T) {
|
||||
defer tests.PrepareTestEnv(t)()
|
||||
nonAdminUsername := "user2"
|
||||
token := getUserToken(t, nonAdminUsername)
|
||||
token := getUserToken(t, nonAdminUsername, auth_model.AccessTokenScopeAll)
|
||||
req := NewRequest(t, "GET", "/api/v1/admin/users").
|
||||
AddTokenAuth(token)
|
||||
MakeRequest(t, req, http.StatusForbidden)
|
||||
|
@ -33,6 +33,10 @@ type APITestContext struct {
|
||||
|
||||
func NewAPITestContext(t *testing.T, username, reponame string, scope ...auth.AccessTokenScope) APITestContext {
|
||||
session := loginUser(t, username)
|
||||
if len(scope) == 0 {
|
||||
// FIXME: legacy logic: no scope means all
|
||||
scope = []auth.AccessTokenScope{auth.AccessTokenScopeAll}
|
||||
}
|
||||
token := getTokenForLoggedInUser(t, session, scope...)
|
||||
return APITestContext{
|
||||
Session: session,
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
"code.gitea.io/gitea/models/packages"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
composer_module "code.gitea.io/gitea/modules/packages/composer"
|
||||
@ -217,5 +218,39 @@ func TestPackageComposer(t *testing.T) {
|
||||
assert.Equal(t, "4f5fa464c3cb808a1df191dbf6cb75363f8b7072", pkgs[0].Dist.Checksum)
|
||||
assert.Len(t, pkgs[0].Bin, 1)
|
||||
assert.Equal(t, packageBin, pkgs[0].Bin[0])
|
||||
|
||||
// Test package linked to repository
|
||||
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
userPkgs, err := packages.GetPackagesByType(db.DefaultContext, user.ID, packages.TypeComposer)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, userPkgs, 1)
|
||||
assert.EqualValues(t, 0, userPkgs[0].RepoID)
|
||||
|
||||
err = packages.SetRepositoryLink(db.DefaultContext, userPkgs[0].ID, repo1.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("%s/p2/%s/%s.json", url, vendorName, projectName)).
|
||||
AddBasicAuth(user.Name)
|
||||
resp = MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
result = composer.PackageMetadataResponse{}
|
||||
DecodeJSON(t, resp, &result)
|
||||
|
||||
assert.Contains(t, result.Packages, packageName)
|
||||
pkgs = result.Packages[packageName]
|
||||
assert.Len(t, pkgs, 1)
|
||||
assert.Equal(t, packageName, pkgs[0].Name)
|
||||
assert.Equal(t, packageVersion, pkgs[0].Version)
|
||||
assert.Equal(t, packageType, pkgs[0].Type)
|
||||
assert.Equal(t, packageDescription, pkgs[0].Description)
|
||||
assert.Len(t, pkgs[0].Authors, 1)
|
||||
assert.Equal(t, packageAuthor, pkgs[0].Authors[0].Name)
|
||||
assert.Equal(t, "zip", pkgs[0].Dist.Type)
|
||||
assert.Equal(t, "4f5fa464c3cb808a1df191dbf6cb75363f8b7072", pkgs[0].Dist.Checksum)
|
||||
assert.Len(t, pkgs[0].Bin, 1)
|
||||
assert.Equal(t, packageBin, pkgs[0].Bin[0])
|
||||
assert.Equal(t, repo1.HTMLURL(), pkgs[0].Source.URL)
|
||||
assert.Equal(t, "git", pkgs[0].Source.Type)
|
||||
assert.Equal(t, packageVersion, pkgs[0].Source.Reference)
|
||||
})
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user