Compare commits

..

No commits in common. "f20bf2fe3b17d998940d5277db75c16b41d2a12c" and "d647e74502fdf734c89b3e6592a9ad88c3005971" have entirely different histories.

57 changed files with 510 additions and 1440 deletions

View File

@ -32,7 +32,6 @@ steps:
pull: always
commands:
- make deps-backend
- make deps-tools
volumes:
- name: deps
path: /go
@ -169,112 +168,7 @@ steps:
---
kind: pipeline
type: docker
name: testing-pgsql
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- push
- tag
- pull_request
paths:
exclude:
- docs/**
volumes:
- name: deps
temp: {}
services:
- name: pgsql
pull: default
image: postgres:15
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
- name: ldap
image: gitea/test-openldap:latest
pull: always
- name: minio
image: minio/minio:RELEASE.2021-03-12T00-00-47Z
pull: always
commands:
- minio server /data
environment:
MINIO_ACCESS_KEY: 123456
MINIO_SECRET_KEY: 12345678
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: golang:1.20
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-pgsql
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-pgsql-migration test-pgsql
environment:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
TEST_TAGS: gogit
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
name: testing-mysql
name: testing-amd64
platform:
os: linux
@ -304,12 +198,40 @@ services:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: test
- name: mysql8
image: mysql:8
pull: always
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
- name: mssql
image: mcr.microsoft.com/mssql/server:latest
pull: always
environment:
ACCEPT_EULA: Y
MSSQL_PID: Standard
SA_PASSWORD: MwantsaSecurePassword1
- name: ldap
image: gitea/test-openldap:latest
pull: always
- name: elasticsearch
image: elasticsearch:7.5.0
pull: always
environment:
discovery.type: single-node
- name: minio
image: minio/minio:RELEASE.2021-03-12T00-00-47Z
pull: always
commands:
- minio server /data
environment:
MINIO_ACCESS_KEY: 123456
MINIO_SECRET_KEY: 12345678
- name: smtpimap
image: tabascoterrier/docker-imap-devel:latest
pull: always
@ -335,6 +257,12 @@ steps:
- name: deps
path: /go
- name: tag-pre-condition
image: drone/git
pull: always
commands:
- git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
- name: prepare-test-env
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
pull: always
@ -350,7 +278,7 @@ steps:
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
TAGS: bindata sqlite sqlite_unlock_notify
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
@ -363,7 +291,7 @@ steps:
- make unit-test-coverage test-check
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
TAGS: bindata sqlite sqlite_unlock_notify
RACE_ENABLED: true
GITHUB_READ_TOKEN:
from_secret: github_read_token
@ -379,7 +307,7 @@ steps:
- make unit-test-coverage test-check
environment:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
TAGS: bindata gogit sqlite sqlite_unlock_notify
RACE_ENABLED: true
GITHUB_READ_TOKEN:
from_secret: github_read_token
@ -397,6 +325,7 @@ steps:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
TEST_INDEXER_CODE_ES_URL: "http://elastic:changeme@elasticsearch:9200"
depends_on: [build]
@ -404,6 +333,38 @@ steps:
- name: deps
path: /go
- name: test-mysql8
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-mysql8-migration test-mysql8
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
- name: test-mssql
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- make test-mssql-migration test-mssql
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
RACE_ENABLED: true
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
- name: generate-coverage
image: golang:1.20
commands:
@ -437,186 +398,7 @@ steps:
---
kind: pipeline
type: docker
name: testing-mysql8
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- push
- tag
- pull_request
paths:
exclude:
- docs/**
volumes:
- name: deps
temp: {}
services:
- name: mysql8
image: mysql:8
pull: always
environment:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: testgitea
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: golang:1.20
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-mysql8
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-mysql8-migration test-mysql8
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
name: testing-mssql
platform:
os: linux
arch: amd64
depends_on:
- compliance
trigger:
event:
- push
- tag
- pull_request
paths:
exclude:
- docs/**
volumes:
- name: deps
temp: {}
services:
- name: mssql
image: mcr.microsoft.com/mssql/server:latest
pull: always
environment:
ACCEPT_EULA: Y
MSSQL_PID: Standard
SA_PASSWORD: MwantsaSecurePassword1
steps:
- name: fetch-tags
image: docker:git
pull: always
commands:
- git config --global --add safe.directory /drone/src
- git fetch --tags --force
when:
event:
exclude:
- pull_request
- name: deps-backend
image: golang:1.20
pull: always
commands:
- make deps-backend
volumes:
- name: deps
path: /go
- name: prepare-test-env
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
pull: always
commands:
- ./build/test-env-prepare.sh
- name: build
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- ./build/test-env-check.sh
- make backend
environment:
GOPROXY: https://goproxy.io # proxy.golang.org is blocked in China, this proxy is not
GOSUMDB: sum.golang.org
TAGS: bindata
depends_on: [deps-backend, prepare-test-env]
volumes:
- name: deps
path: /go
- name: test-mssql
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- make test-mssql-migration test-mssql
environment:
GOPROXY: https://goproxy.io
TAGS: bindata
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
name: testing-sqlite
name: testing-arm64
platform:
os: linux
@ -638,6 +420,18 @@ volumes:
- name: deps
temp: {}
services:
- name: pgsql
pull: default
image: postgres:10
environment:
POSTGRES_DB: test
POSTGRES_PASSWORD: postgres
- name: ldap
pull: default
image: gitea/test-openldap:latest
steps:
- name: fetch-tags
image: docker:git
@ -696,6 +490,23 @@ steps:
- name: deps
path: /go
- name: test-pgsql
image: gitea/test_env:linux-arm64 # https://gitea.com/gitea/test-env
user: gitea
commands:
- timeout -s ABRT 50m make test-pgsql-migration test-pgsql
environment:
GOPROXY: https://goproxy.io
TAGS: bindata gogit
RACE_ENABLED: true
TEST_TAGS: gogit
TEST_LDAP: 1
USE_REPO_TEST_DIR: 1
depends_on: [build]
volumes:
- name: deps
path: /go
---
kind: pipeline
type: docker
@ -719,6 +530,15 @@ volumes:
- name: deps
temp: {}
services:
- name: pgsql
pull: default
image: postgres:10
environment:
POSTGRES_DB: testgitea-e2e
POSTGRES_PASSWORD: postgres
POSTGRES_INITDB_ARGS: --encoding=UTF8 --lc-collate='en_US.UTF-8' --lc-ctype='en_US.UTF-8'
steps:
- name: deps-frontend
image: node:18
@ -748,12 +568,14 @@ steps:
- curl -sLO https://go.dev/dl/go1.20.linux-amd64.tar.gz && tar -C /usr/local -xzf go1.20.linux-amd64.tar.gz
- groupadd --gid 1001 gitea && useradd -m --gid 1001 --uid 1001 gitea
- apt-get -qq update && apt-get -qqy install build-essential
- export TEST_PGSQL_SCHEMA=''
- ./build/test-env-prepare.sh
- su gitea bash -c "export PATH=$PATH:/usr/local/go/bin && timeout -s ABRT 40m make test-e2e-sqlite"
- su gitea bash -c "export PATH=$PATH:/usr/local/go/bin && timeout -s ABRT 40m make test-e2e-pgsql"
environment:
GOPROXY: https://goproxy.io
GOSUMDB: sum.golang.org
USE_REPO_TEST_DIR: 1
TEST_PGSQL_DBNAME: 'testgitea-e2e'
DEBIAN_FRONTEND: noninteractive
depends_on: [build-frontend, deps-backend]
volumes:
@ -887,11 +709,8 @@ trigger:
- docs/**
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
volumes:
- name: deps
@ -1023,11 +842,8 @@ trigger:
- tag
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-arm64
- testing-amd64
volumes:
- name: deps
@ -1178,11 +994,8 @@ platform:
arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1251,11 +1064,8 @@ platform:
arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1319,11 +1129,8 @@ platform:
arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1385,11 +1192,8 @@ platform:
arch: amd64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1488,11 +1292,8 @@ platform:
arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1561,11 +1362,8 @@ platform:
arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1629,11 +1427,8 @@ platform:
arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1698,11 +1493,8 @@ platform:
arch: arm64
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
trigger:
ref:
@ -1815,6 +1607,7 @@ platform:
steps:
- name: manifest-rootless
pull: always
image: plugins/manifest
pull: always
settings:
@ -1878,11 +1671,8 @@ trigger:
- failure
depends_on:
- testing-mysql
- testing-mysql8
- testing-mssql
- testing-pgsql
- testing-sqlite
- testing-amd64
- testing-arm64
- release-version
- release-latest
- docker-linux-amd64-release

View File

@ -190,7 +190,6 @@ help:
@echo " - deps install dependencies"
@echo " - deps-frontend install frontend dependencies"
@echo " - deps-backend install backend dependencies"
@echo " - deps-tools install tool dependencies"
@echo " - lint lint everything"
@echo " - lint-frontend lint frontend files"
@echo " - lint-backend lint backend files"
@ -822,7 +821,7 @@ docs:
cd docs; make trans-copy clean build-offline;
.PHONY: deps
deps: deps-frontend deps-backend deps-tools
deps: deps-frontend deps-backend
.PHONY: deps-frontend
deps-frontend: node_modules
@ -830,9 +829,6 @@ deps-frontend: node_modules
.PHONY: deps-backend
deps-backend:
$(GO) mod download
.PHONY: deps-tools
deps-tools:
$(GO) install $(AIR_PACKAGE)
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
$(GO) install $(ERRCHECK_PACKAGE)

View File

@ -7,7 +7,6 @@ package cmd
import (
"errors"
"fmt"
"net/url"
"os"
"strings"
"text/tabwriter"
@ -470,19 +469,11 @@ func runAddOauth(c *cli.Context) error {
return err
}
config := parseOAuth2Config(c)
if config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
return fmt.Errorf("invalid Auto Discovery URL: %s (this must be a valid URL starting with http:// or https://)", config.OpenIDConnectAutoDiscoveryURL)
}
}
return auth_model.CreateSource(&auth_model.Source{
Type: auth_model.OAuth2,
Name: c.String("name"),
IsActive: true,
Cfg: config,
Cfg: parseOAuth2Config(c),
})
}

View File

@ -576,22 +576,6 @@ ROUTER = console
;; The routing level will default to that of the system but individual router level can be set in
;; [log.<mode>.router] LEVEL
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Print request id which parsed from request headers in access log, when access log is enabled.
;; * E.g:
;; * In request Header: X-Request-ID: test-id-123
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "test-id-123"
;;
;; If you configure more than one in the .ini file, it will match in the order of configuration,
;; and the first match will be finally printed in the log.
;; * E.g:
;; * In reuqest Header: X-Trace-ID: trace-id-1q2w3e4r
;; * Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID, X-Trace-ID, X-Req-ID
;; * Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "trace-id-1q2w3e4r"
;;
;; REQUEST_ID_HEADERS =
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;

View File

@ -881,13 +881,7 @@ Default templates for project boards:
- `Identity`: the SignedUserName or `"-"` if not logged in.
- `Start`: the start time of the request.
- `ResponseWriter`: the responseWriter from the request.
- `RequestID`: the value matching REQUEST_ID_HEADERSdefault: `-`, if not matched.
- You must be very careful to ensure that this template does not throw errors or panics as this template runs outside of the panic/recovery script.
- `REQUEST_ID_HEADERS`: **\<empty\>**: You can configure multiple values that are splited by comma here. It will match in the order of configuration, and the first match will be finally printed in the access log.
- e.g.
- In the Request Header: X-Request-ID: **test-id-123**
- Configuration in app.ini: REQUEST_ID_HEADERS = X-Request-ID
- Print in log: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "**test-id-123**" ...
### Log subsections (`log.name`, `log.name.*`)

View File

@ -262,22 +262,7 @@ test01.xls: application/vnd.ms-excel; charset=binary
- `ROOT_PATH`: 日志文件根目录。
- `MODE`: 日志记录模式,默认是为 `console`。如果要写到多个通道,用逗号分隔
- `LEVEL`: 日志级别,默认为 `Trace`
- `DISABLE_ROUTER_LOG`: 关闭日志中的路由日志。
- `ENABLE_ACCESS_LOG`: 是否开启 Access Log, 默认为 false。
- `ACCESS_LOG_TEMPLATE`: `access.log` 输出内容的模板,默认模板:**`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`**
模板支持以下参数:
- `Ctx`: 请求上下文。
- `Identity`: 登录用户名,默认: “`-`”。
- `Start`: 请求开始时间。
- `ResponseWriter`:
- `RequestID`: 从请求头中解析得到的与 `REQUEST_ID_HEADERS` 匹配的值,默认: “`-`”。
- 一定要谨慎配置该模板否则可能会引起panic.
- `REQUEST_ID_HEADERS`: 从 Request Header 中匹配指定 Key并将匹配到的值输出到 `access.log` 中(需要在 `ACCESS_LOG_TEMPLATE` 中指定输出位置)。如果在该参数中配置多个 Key 请用逗号分割,程序将按照配置的顺序进行匹配。
- 示例:
- 请求头: X-Request-ID: **test-id-123**
- 配置文件: REQUEST_ID_HEADERS = X-Request-ID
- 日志输出: 127.0.0.1:58384 - - [14/Feb/2023:16:33:51 +0800] "**test-id-123**" ...
- `LEVEL`: 日志级别,默认为`Trace`
## Cron (`cron`)

View File

@ -60,7 +60,6 @@ Gitea supports the following scopes for tokens:
| &nbsp;&nbsp;&nbsp; **write:public_key** | Grant read/write access to public keys |
| &nbsp;&nbsp;&nbsp; **read:public_key** | Grant read-only access to public keys |
| **admin:org_hook** | Grants full access to organizational-level hooks |
| **admin:user_hook** | Grants full access to user-level hooks |
| **notification** | Grants full access to notifications |
| **user** | Grants full access to user profile info |
| &nbsp;&nbsp;&nbsp; **read:user** | Grants read access to user's profile |

View File

@ -32,8 +32,6 @@ const (
AccessTokenScopeAdminOrgHook AccessTokenScope = "admin:org_hook"
AccessTokenScopeAdminUserHook AccessTokenScope = "admin:user_hook"
AccessTokenScopeNotification AccessTokenScope = "notification"
AccessTokenScopeUser AccessTokenScope = "user"
@ -66,7 +64,7 @@ type AccessTokenScopeBitmap uint64
const (
// AccessTokenScopeAllBits is the bitmap of all access token scopes, except `sudo`.
AccessTokenScopeAllBits AccessTokenScopeBitmap = AccessTokenScopeRepoBits |
AccessTokenScopeAdminOrgBits | AccessTokenScopeAdminPublicKeyBits | AccessTokenScopeAdminOrgHookBits | AccessTokenScopeAdminUserHookBits |
AccessTokenScopeAdminOrgBits | AccessTokenScopeAdminPublicKeyBits | AccessTokenScopeAdminOrgHookBits |
AccessTokenScopeNotificationBits | AccessTokenScopeUserBits | AccessTokenScopeDeleteRepoBits |
AccessTokenScopePackageBits | AccessTokenScopeAdminGPGKeyBits | AccessTokenScopeAdminApplicationBits
@ -88,8 +86,6 @@ const (
AccessTokenScopeAdminOrgHookBits AccessTokenScopeBitmap = 1 << iota
AccessTokenScopeAdminUserHookBits AccessTokenScopeBitmap = 1 << iota
AccessTokenScopeNotificationBits AccessTokenScopeBitmap = 1 << iota
AccessTokenScopeUserBits AccessTokenScopeBitmap = 1<<iota | AccessTokenScopeReadUserBits | AccessTokenScopeUserEmailBits | AccessTokenScopeUserFollowBits
@ -127,7 +123,6 @@ var allAccessTokenScopes = []AccessTokenScope{
AccessTokenScopeAdminPublicKey, AccessTokenScopeWritePublicKey, AccessTokenScopeReadPublicKey,
AccessTokenScopeAdminRepoHook, AccessTokenScopeWriteRepoHook, AccessTokenScopeReadRepoHook,
AccessTokenScopeAdminOrgHook,
AccessTokenScopeAdminUserHook,
AccessTokenScopeNotification,
AccessTokenScopeUser, AccessTokenScopeReadUser, AccessTokenScopeUserEmail, AccessTokenScopeUserFollow,
AccessTokenScopeDeleteRepo,
@ -152,7 +147,6 @@ var allAccessTokenScopeBits = map[AccessTokenScope]AccessTokenScopeBitmap{
AccessTokenScopeWriteRepoHook: AccessTokenScopeWriteRepoHookBits,
AccessTokenScopeReadRepoHook: AccessTokenScopeReadRepoHookBits,
AccessTokenScopeAdminOrgHook: AccessTokenScopeAdminOrgHookBits,
AccessTokenScopeAdminUserHook: AccessTokenScopeAdminUserHookBits,
AccessTokenScopeNotification: AccessTokenScopeNotificationBits,
AccessTokenScopeUser: AccessTokenScopeUserBits,
AccessTokenScopeReadUser: AccessTokenScopeReadUserBits,
@ -269,7 +263,7 @@ func (bitmap AccessTokenScopeBitmap) ToScope() AccessTokenScope {
scope := AccessTokenScope(strings.Join(scopes, ","))
scope = AccessTokenScope(strings.ReplaceAll(
string(scope),
"repo,admin:org,admin:public_key,admin:org_hook,admin:user_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application",
"repo,admin:org,admin:public_key,admin:org_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application",
"all",
))
return scope

View File

@ -40,8 +40,8 @@ func TestAccessTokenScope_Normalize(t *testing.T) {
{"admin:gpg_key,write:gpg_key,user", "user,admin:gpg_key", nil},
{"admin:application,write:application,user", "user,admin:application", nil},
{"all", "all", nil},
{"repo,admin:org,admin:public_key,admin:repo_hook,admin:org_hook,admin:user_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application", "all", nil},
{"repo,admin:org,admin:public_key,admin:repo_hook,admin:org_hook,admin:user_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application,sudo", "all,sudo", nil},
{"repo,admin:org,admin:public_key,admin:repo_hook,admin:org_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application", "all", nil},
{"repo,admin:org,admin:public_key,admin:repo_hook,admin:org_hook,notification,user,delete_repo,package,admin:gpg_key,admin:application,sudo", "all,sudo", nil},
}
for _, test := range tests {

View File

@ -16,7 +16,7 @@
-
id: 3
owner_id: 3
org_id: 3
repo_id: 3
url: www.example.com/url3
content_type: 1 # json

View File

@ -467,8 +467,6 @@ var migrations = []Migration{
// v244 -> v245
NewMigration("Add NeedApproval to actions tables", v1_20.AddNeedApprovalToActionRun),
// v245 -> v246
NewMigration("Rename Webhook org_id to owner_id", v1_20.RenameWebhookOrgToOwner),
}
// GetCurrentDBVersion returns the current db version

View File

@ -1,74 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package v1_20 //nolint
import (
"context"
"fmt"
"code.gitea.io/gitea/models/migrations/base"
"code.gitea.io/gitea/modules/setting"
"xorm.io/xorm"
)
func RenameWebhookOrgToOwner(x *xorm.Engine) error {
type Webhook struct {
OrgID int64 `xorm:"INDEX"`
}
// This migration maybe rerun so that we should check if it has been run
ownerExist, err := x.Dialect().IsColumnExist(x.DB(), context.Background(), "webhook", "owner_id")
if err != nil {
return err
}
if ownerExist {
orgExist, err := x.Dialect().IsColumnExist(x.DB(), context.Background(), "webhook", "org_id")
if err != nil {
return err
}
if !orgExist {
return nil
}
}
sess := x.NewSession()
defer sess.Close()
if err := sess.Begin(); err != nil {
return err
}
if err := sess.Sync2(new(Webhook)); err != nil {
return err
}
if ownerExist {
if err := base.DropTableColumns(sess, "webhook", "owner_id"); err != nil {
return err
}
}
switch {
case setting.Database.Type.IsMySQL():
inferredTable, err := x.TableInfo(new(Webhook))
if err != nil {
return err
}
sqlType := x.Dialect().SQLType(inferredTable.GetColumn("org_id"))
if _, err := sess.Exec(fmt.Sprintf("ALTER TABLE `webhook` CHANGE org_id owner_id %s", sqlType)); err != nil {
return err
}
case setting.Database.Type.IsMSSQL():
if _, err := sess.Exec("sp_rename 'webhook.org_id', 'owner_id', 'COLUMN'"); err != nil {
return err
}
default:
if _, err := sess.Exec("ALTER TABLE `webhook` RENAME COLUMN org_id TO owner_id"); err != nil {
return err
}
}
return sess.Commit()
}

View File

@ -239,32 +239,6 @@ func (org *Organization) CustomAvatarRelativePath() string {
return org.Avatar
}
// UnitPermission returns unit permission
func (org *Organization) UnitPermission(ctx context.Context, doer *user_model.User, unitType unit.Type) perm.AccessMode {
if doer != nil {
teams, err := GetUserOrgTeams(ctx, org.ID, doer.ID)
if err != nil {
log.Error("GetUserOrgTeams: %v", err)
return perm.AccessModeNone
}
if err := teams.LoadUnits(ctx); err != nil {
log.Error("LoadUnits: %v", err)
return perm.AccessModeNone
}
if len(teams) > 0 {
return teams.UnitMaxAccess(unitType)
}
}
if org.Visibility.IsPublic() {
return perm.AccessModeRead
}
return perm.AccessModeNone
}
// CreateOrganization creates record of a new organization.
func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
if !owner.CanCreateOrganization() {

View File

@ -393,11 +393,6 @@ func (u *User) IsOrganization() bool {
return u.Type == UserTypeOrganization
}
// IsIndividual returns true if user is actually a individual user.
func (u *User) IsIndividual() bool {
return u.Type == UserTypeIndividual
}
// DisplayName returns full name if it's not empty,
// returns username otherwise.
func (u *User) DisplayName() string {

View File

@ -122,7 +122,7 @@ func IsValidHookContentType(name string) bool {
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64 `xorm:"INDEX"` // An ID of 0 indicates either a default or system webhook
OwnerID int64 `xorm:"INDEX"`
OrgID int64 `xorm:"INDEX"`
IsSystemWebhook bool
URL string `xorm:"url TEXT"`
HTTPMethod string `xorm:"http_method"`
@ -412,11 +412,11 @@ func GetWebhookByRepoID(repoID, id int64) (*Webhook, error) {
})
}
// GetWebhookByOwnerID returns webhook of a user or organization by given ID.
func GetWebhookByOwnerID(ownerID, id int64) (*Webhook, error) {
// GetWebhookByOrgID returns webhook of organization by given ID.
func GetWebhookByOrgID(orgID, id int64) (*Webhook, error) {
return getWebhook(&Webhook{
ID: id,
OwnerID: ownerID,
OrgID: orgID,
})
}
@ -424,7 +424,7 @@ func GetWebhookByOwnerID(ownerID, id int64) (*Webhook, error) {
type ListWebhookOptions struct {
db.ListOptions
RepoID int64
OwnerID int64
OrgID int64
IsActive util.OptionalBool
}
@ -433,8 +433,8 @@ func (opts *ListWebhookOptions) toCond() builder.Cond {
if opts.RepoID != 0 {
cond = cond.And(builder.Eq{"webhook.repo_id": opts.RepoID})
}
if opts.OwnerID != 0 {
cond = cond.And(builder.Eq{"webhook.owner_id": opts.OwnerID})
if opts.OrgID != 0 {
cond = cond.And(builder.Eq{"webhook.org_id": opts.OrgID})
}
if !opts.IsActive.IsNone() {
cond = cond.And(builder.Eq{"webhook.is_active": opts.IsActive.IsTrue()})
@ -503,10 +503,10 @@ func DeleteWebhookByRepoID(repoID, id int64) error {
})
}
// DeleteWebhookByOwnerID deletes webhook of a user or organization by given ID.
func DeleteWebhookByOwnerID(ownerID, id int64) error {
// DeleteWebhookByOrgID deletes webhook of organization by given ID.
func DeleteWebhookByOrgID(orgID, id int64) error {
return deleteWebhook(&Webhook{
ID: id,
OwnerID: ownerID,
OrgID: orgID,
})
}

View File

@ -15,7 +15,7 @@ import (
func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) {
webhooks := make([]*Webhook, 0, 5)
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, false).
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, false).
Find(&webhooks)
}
@ -23,7 +23,7 @@ func GetDefaultWebhooks(ctx context.Context) ([]*Webhook, error) {
func GetSystemOrDefaultWebhook(ctx context.Context, id int64) (*Webhook, error) {
webhook := &Webhook{ID: id}
has, err := db.GetEngine(ctx).
Where("repo_id=? AND owner_id=?", 0, 0).
Where("repo_id=? AND org_id=?", 0, 0).
Get(webhook)
if err != nil {
return nil, err
@ -38,11 +38,11 @@ func GetSystemWebhooks(ctx context.Context, isActive util.OptionalBool) ([]*Webh
webhooks := make([]*Webhook, 0, 5)
if isActive.IsNone() {
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND owner_id=? AND is_system_webhook=?", 0, 0, true).
Where("repo_id=? AND org_id=? AND is_system_webhook=?", 0, 0, true).
Find(&webhooks)
}
return webhooks, db.GetEngine(ctx).
Where("repo_id=? AND owner_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
Where("repo_id=? AND org_id=? AND is_system_webhook=? AND is_active = ?", 0, 0, true, isActive.IsTrue()).
Find(&webhooks)
}
@ -50,7 +50,7 @@ func GetSystemWebhooks(ctx context.Context, isActive util.OptionalBool) ([]*Webh
func DeleteDefaultSystemWebhook(ctx context.Context, id int64) error {
return db.WithTx(ctx, func(ctx context.Context) error {
count, err := db.GetEngine(ctx).
Where("repo_id=? AND owner_id=?", 0, 0).
Where("repo_id=? AND org_id=?", 0, 0).
Delete(&Webhook{ID: id})
if err != nil {
return err

View File

@ -109,13 +109,13 @@ func TestGetWebhookByRepoID(t *testing.T) {
assert.True(t, IsErrWebhookNotExist(err))
}
func TestGetWebhookByOwnerID(t *testing.T) {
func TestGetWebhookByOrgID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
hook, err := GetWebhookByOwnerID(3, 3)
hook, err := GetWebhookByOrgID(3, 3)
assert.NoError(t, err)
assert.Equal(t, int64(3), hook.ID)
_, err = GetWebhookByOwnerID(unittest.NonexistentID, unittest.NonexistentID)
_, err = GetWebhookByOrgID(unittest.NonexistentID, unittest.NonexistentID)
assert.Error(t, err)
assert.True(t, IsErrWebhookNotExist(err))
}
@ -140,9 +140,9 @@ func TestGetWebhooksByRepoID(t *testing.T) {
}
}
func TestGetActiveWebhooksByOwnerID(t *testing.T) {
func TestGetActiveWebhooksByOrgID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3, IsActive: util.OptionalBoolTrue})
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OrgID: 3, IsActive: util.OptionalBoolTrue})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)
@ -150,9 +150,9 @@ func TestGetActiveWebhooksByOwnerID(t *testing.T) {
}
}
func TestGetWebhooksByOwnerID(t *testing.T) {
func TestGetWebhooksByOrgID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OwnerID: 3})
hooks, err := ListWebhooksByOpts(db.DefaultContext, &ListWebhookOptions{OrgID: 3})
assert.NoError(t, err)
if assert.Len(t, hooks, 1) {
assert.Equal(t, int64(3), hooks[0].ID)
@ -181,13 +181,13 @@ func TestDeleteWebhookByRepoID(t *testing.T) {
assert.True(t, IsErrWebhookNotExist(err))
}
func TestDeleteWebhookByOwnerID(t *testing.T) {
func TestDeleteWebhookByOrgID(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 3, OwnerID: 3})
assert.NoError(t, DeleteWebhookByOwnerID(3, 3))
unittest.AssertNotExistsBean(t, &Webhook{ID: 3, OwnerID: 3})
unittest.AssertExistsAndLoadBean(t, &Webhook{ID: 3, OrgID: 3})
assert.NoError(t, DeleteWebhookByOrgID(3, 3))
unittest.AssertNotExistsBean(t, &Webhook{ID: 3, OrgID: 3})
err := DeleteWebhookByOwnerID(unittest.NonexistentID, unittest.NonexistentID)
err := DeleteWebhookByOrgID(unittest.NonexistentID, unittest.NonexistentID)
assert.Error(t, err)
assert.True(t, IsErrWebhookNotExist(err))
}

View File

@ -6,9 +6,7 @@ package context
import (
"bytes"
"context"
"fmt"
"net/http"
"strings"
"text/template"
"time"
@ -22,39 +20,13 @@ type routerLoggerOptions struct {
Start *time.Time
ResponseWriter http.ResponseWriter
Ctx map[string]interface{}
RequestID *string
}
var signedUserNameStringPointerKey interface{} = "signedUserNameStringPointerKey"
const keyOfRequestIDInTemplate = ".RequestID"
// According to:
// TraceId: A valid trace identifier is a 16-byte array with at least one non-zero byte
// MD5 output is 16 or 32 bytes: md5-bytes is 16, md5-hex is 32
// SHA1: similar, SHA1-bytes is 20, SHA1-hex is 40.
// UUID is 128-bit, 32 hex chars, 36 ASCII chars with 4 dashes
// So, we accept a Request ID with a maximum character length of 40
const maxRequestIDByteLength = 40
func parseRequestIDFromRequestHeader(req *http.Request) string {
requestID := "-"
for _, key := range setting.Log.RequestIDHeaders {
if req.Header.Get(key) != "" {
requestID = req.Header.Get(key)
break
}
}
if len(requestID) > maxRequestIDByteLength {
requestID = fmt.Sprintf("%s...", requestID[:maxRequestIDByteLength])
}
return requestID
}
// AccessLogger returns a middleware to log access logger
func AccessLogger() func(http.Handler) http.Handler {
logger := log.GetLogger("access")
needRequestID := len(setting.Log.RequestIDHeaders) > 0 && strings.Contains(setting.Log.AccessLogTemplate, keyOfRequestIDInTemplate)
logTemplate, _ := template.New("log").Parse(setting.Log.AccessLogTemplate)
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
@ -62,11 +34,6 @@ func AccessLogger() func(http.Handler) http.Handler {
identity := "-"
r := req.WithContext(context.WithValue(req.Context(), signedUserNameStringPointerKey, &identity))
var requestID string
if needRequestID {
requestID = parseRequestIDFromRequestHeader(req)
}
next.ServeHTTP(w, r)
rw := w.(ResponseWriter)
@ -80,7 +47,6 @@ func AccessLogger() func(http.Handler) http.Handler {
"RemoteAddr": req.RemoteAddr,
"Req": req,
},
RequestID: &requestID,
})
if err != nil {
log.Error("Could not set up chi access logger: %v", err.Error())

View File

@ -11,6 +11,7 @@ import (
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
)
@ -30,34 +31,29 @@ type Organization struct {
}
func (org *Organization) CanWriteUnit(ctx *Context, unitType unit.Type) bool {
return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeWrite
if ctx.Doer == nil {
return false
}
return org.UnitPermission(ctx, ctx.Doer.ID, unitType) >= perm.AccessModeWrite
}
func (org *Organization) CanReadUnit(ctx *Context, unitType unit.Type) bool {
return org.Organization.UnitPermission(ctx, ctx.Doer, unitType) >= perm.AccessModeRead
}
func GetOrganizationByParams(ctx *Context) {
orgName := ctx.Params(":org")
var err error
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
func (org *Organization) UnitPermission(ctx *Context, doerID int64, unitType unit.Type) perm.AccessMode {
if doerID > 0 {
teams, err := organization.GetUserOrgTeams(ctx, org.Organization.ID, doerID)
if err != nil {
if organization.IsErrOrgNotExist(err) {
redirectUserID, err := user_model.LookupUserRedirect(orgName)
if err == nil {
RedirectToUser(ctx, orgName, redirectUserID)
} else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
ctx.ServerError("LookupUserRedirect", err)
log.Error("GetUserOrgTeams: %v", err)
return perm.AccessModeNone
}
} else {
ctx.ServerError("GetUserByName", err)
if len(teams) > 0 {
return teams.UnitMaxAccess(unitType)
}
return
}
if org.Organization.Visibility == structs.VisibleTypePublic {
return perm.AccessModeRead
}
return perm.AccessModeNone
}
// HandleOrgAssignment handles organization assignment
@ -81,26 +77,25 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
requireTeamAdmin = args[3]
}
orgName := ctx.Params(":org")
var err error
if ctx.ContextUser == nil {
// if Organization is not defined, get it from params
if ctx.Org.Organization == nil {
GetOrganizationByParams(ctx)
if ctx.Written() {
return
}
}
} else if ctx.ContextUser.IsOrganization() {
if ctx.Org == nil {
ctx.Org = &Organization{}
}
ctx.Org.Organization = (*organization.Organization)(ctx.ContextUser)
ctx.Org.Organization, err = organization.GetOrgByName(ctx, orgName)
if err != nil {
if organization.IsErrOrgNotExist(err) {
redirectUserID, err := user_model.LookupUserRedirect(orgName)
if err == nil {
RedirectToUser(ctx, orgName, redirectUserID)
} else if user_model.IsErrUserRedirectNotExist(err) {
ctx.NotFound("GetUserByName", err)
} else {
// ContextUser is an individual User
ctx.ServerError("LookupUserRedirect", err)
}
} else {
ctx.ServerError("GetUserByName", err)
}
return
}
org := ctx.Org.Organization
// Handle Visibility
@ -161,7 +156,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
}
ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner
ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["IsPublicMember"] = func(uid int64) bool {
@ -237,10 +231,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) {
return
}
}
ctx.Data["CanReadProjects"] = ctx.Org.CanReadUnit(ctx, unit.TypeProjects)
ctx.Data["CanReadPackages"] = ctx.Org.CanReadUnit(ctx, unit.TypePackages)
ctx.Data["CanReadCode"] = ctx.Org.CanReadUnit(ctx, unit.TypeCode)
}
// OrgAssignment returns a middleware to handle organization assignment

View File

@ -38,7 +38,6 @@ var Log struct {
EnableAccessLog bool
AccessLogTemplate string
BufferLength int64
RequestIDHeaders []string
}
// GetLogDescriptions returns a race safe set of descriptions
@ -154,7 +153,6 @@ func loadLogFrom(rootCfg ConfigProvider) {
Log.AccessLogTemplate = sec.Key("ACCESS_LOG_TEMPLATE").MustString(
`{{.Ctx.RemoteAddr}} - {{.Identity}} {{.Start.Format "[02/Jan/2006:15:04:05 -0700]" }} "{{.Ctx.Req.Method}} {{.Ctx.Req.URL.RequestURI}} {{.Ctx.Req.Proto}}" {{.ResponseWriter.Status}} {{.ResponseWriter.Size}} "{{.Ctx.Req.Referer}}\" \"{{.Ctx.Req.UserAgent}}"`,
)
Log.RequestIDHeaders = sec.Key("REQUEST_ID_HEADERS").Strings(",")
// the `MustString` updates the default value, and `log.ACCESS` is used by `generateNamedLogger("access")` later
_ = rootCfg.Section("log").Key("ACCESS").MustString("file")

View File

@ -821,8 +821,6 @@ remove_account_link = Remove Linked Account
remove_account_link_desc = Removing a linked account will revoke its access to your Gitea account. Continue?
remove_account_link_success = The linked account has been removed.
hooks.desc = Add webhooks which will be triggered for <strong>all repositories</strong> owned by this user.
orgs_none = You are not a member of any organizations.
repos_none = You do not own any repositories
@ -2290,8 +2288,6 @@ release.edit_subheader = Releases organize project versions.
release.tag_name = Tag name
release.target = Target
release.tag_helper = Choose an existing tag or create a new tag.
release.tag_helper_new = New tag. This tag will be created from the target.
release.tag_helper_existing = Existing tag.
release.title = Title
release.content = Content
release.prerelease_desc = Mark as Pre-Release
@ -2812,8 +2808,6 @@ auths.still_in_used = The authentication source is still in use. Convert or dele
auths.deletion_success = The authentication source has been deleted.
auths.login_source_exist = The authentication source '%s' already exists.
auths.login_source_of_type_exist = An authentication source of this type already exists.
auths.unable_to_initialize_openid = Unable to initialize OpenID Connect Provider: %s
auths.invalid_openIdConnectAutoDiscoveryURL = Invalid Auto Discovery URL (this must be a valid URL starting with http:// or https://)
config.server_config = Server Configuration
config.app_name = Site Title

View File

@ -334,7 +334,7 @@ non_local_account=Yerel olmayan kullanıcılar parolalarını Gitea web arayüz
verify=Doğrula
scratch_code=Çizgi kodu
use_scratch_code=Bir çizgi kodu kullanınız
twofa_scratch_used=Geçici kodunuzu kullandınız. İki aşamalı ayarlar sayfasına yönlendirildiniz, burada aygıt kaydınızı kaldırabilir veya yeni bir geçici kod oluşturabilirsiniz.
twofa_scratch_used=Çizgi kodunuzu kullandınız. İki aşamalı ayarlar sayfasına yönlendirildiniz, burada cihaz kaydınızı kaldırabilir veya yeni bir çizgi kodu oluşturabilirsiniz.
twofa_passcode_incorrect=Şifreniz yanlış. Aygıtınızı yanlış yerleştirdiyseniz, oturum açmak için çizgi kodunuzu kullanın.
twofa_scratch_token_incorrect=Çizgi kodunuz doğru değildir.
login_userpass=Oturum Aç
@ -736,12 +736,12 @@ unbind=Bağlantıyı Kaldır
unbind_success=Sosyal hesabın bağlantısı Gitea hesabınızdan kaldırılmıştır.
manage_access_token=Erişim Jetonlarını Yönet
generate_new_token=Yeni Erişim Anahtarı Üret
generate_new_token=Yeni Jeton Üret
tokens_desc=Bu jetonlar Gitea API'sini kullanarak hesabınıza erişim sağlar.
new_token_desc=Jeton kullanan uygulamalar hesabınıza tam erişime sahiptir.
token_name=Jeton İsmi
generate_token=Erişim Anahtarı Üret
generate_token_success=Yeni bir erişim anahtarı oluşturuldu. Tekrar gösterilmeyeceği için şimdi kopyalayın.
generate_token=Jeton Üret
generate_token_success=Yeni bir jeton oluşturuldu. Tekrar gösterilmeyeceği için şimdi kopyalayın.
generate_token_name_duplicate=<strong>%s</strong> zaten bir uygulama adı olarak kullanılmış. Lütfen yeni bir tane kullanın.
delete_token=Sil
access_token_deletion=Erişim Jetonunu Sil
@ -784,12 +784,12 @@ twofa_desc=İki faktörlü kimlik doğrulama, hesabınızın güvenliğini artı
twofa_is_enrolled=Hesabınız şu anda iki faktörlü kimlik doğrulaması içinde <strong>kaydedilmiş</strong>.
twofa_not_enrolled=Hesabınız şu anda iki faktörlü kimlik doğrulaması içinde kaydedilmemiş.
twofa_disable=İki Aşamalı Doğrulamayı Devre Dışı Bırak
twofa_scratch_token_regenerate=Geçici Kodu Yeniden Üret
twofa_scratch_token_regenerated=Geçici kodunuz artık %s. Güvenilir bir yerde saklayın.
twofa_scratch_token_regenerate=Kazıma Belirtecini Yenile
twofa_scratch_token_regenerated=Kazıma belirteciniz şimdi %s. Güvenli bir yerde saklayın.
twofa_enroll=İki Faktörlü Kimlik Doğrulamaya Kaydolun
twofa_disable_note=Gerekirse iki faktörlü kimlik doğrulamayı devre dışı bırakabilirsiniz.
twofa_disable_desc=İki faktörlü kimlik doğrulamayı devre dışı bırakmak hesabınızı daha az güvenli hale getirir. Devam edilsin mi?
regenerate_scratch_token_desc=Geçici kodunuzu kaybettiyseniz veya oturum açmak için kullandıysanız, buradan sıfırlayabilirsiniz.
regenerate_scratch_token_desc=Karalama belirtecinizi yanlış yerleştirdiyseniz veya oturum açmak için kullandıysanız, buradan sıfırlayabilirsiniz.
twofa_disabled=İki faktörlü kimlik doğrulama devre dışı bırakıldı.
scan_this_image=Kim doğrulama uygulamanızla bu görüntüyü tarayın:
or_enter_secret=Veya gizli şeyi girin: %s

View File

@ -54,7 +54,7 @@ mirror=鏡像
new_repo=新增儲存庫
new_migrate=遷移外部儲存庫
new_mirror=新鏡像
new_fork=新增儲存庫 Fork
new_fork=新增儲存庫 fork
new_org=新增組織
new_project=新增專案
new_project_column=新增欄位
@ -476,8 +476,6 @@ url_error=`'%s' 是無效的 URL。`
include_error=` 必須包含子字串「%s」。
glob_pattern_error=` glob 比對模式無效:%s.`
regex_pattern_error=` 正規表示式模式無效:%s.`
username_error=`只能包含英文字母數字 ('0-9'、'a-z'、'A-Z')、破折號 ('-')、底線 ('_')、句點 ('.'),不能以非英文字母數字開頭或結尾,也不允許連續的非英文字母數字。`
invalid_group_team_map_error=` 對應無效: %s`
unknown_error=未知錯誤:
captcha_incorrect=驗證碼不正確。
password_not_match=密碼錯誤。
@ -523,11 +521,11 @@ must_use_public_key=您提供的金鑰是私有金鑰,請勿上傳您的私有
unable_verify_ssh_key=無法驗證 SSH 密鑰
auth_failed=授權認證失敗:%v
still_own_repo=您的帳戶擁有一個以上的儲存庫,請先刪除或轉移它們。
still_has_org=您的帳戶是一個或多個組織的成員,請先離開它們。
still_own_packages=您的帳戶擁有一個以上的套件,請先刪除它們。
org_still_own_repo=此組織仍然擁有一個以上的儲存庫,請先刪除或轉移它們。
org_still_own_packages=此組織仍然擁有一個以上的套件,請先刪除它們。
still_own_repo=此帳戶仍然擁有一個或多個儲存庫,您必須先刪除或轉移它們。
still_has_org=此帳戶仍是一個或多個組織的成員,您必須先離開它們。
still_own_packages=您的帳戶擁有一個或多個套件,請先刪除他們。
org_still_own_repo=該組織仍然是某些儲存庫的擁有者,您必須先轉移或刪除它們才能執行刪除組織!
org_still_own_packages=此組織擁有一個或多個套件,請先刪除他們。
target_branch_not_exist=目標分支不存在
@ -1134,7 +1132,6 @@ editor.commit_directly_to_this_branch=直接提交到 <strong class="branch-name
editor.create_new_branch=為此提交建立<strong>新分支</strong>並提出合併請求。
editor.create_new_branch_np=為本次提交建立<strong>新分支</strong>。
editor.propose_file_change=提出檔案變更
editor.new_branch_name=命名此提交的新分支
editor.new_branch_name_desc=新的分支名稱...
editor.cancel=取消
editor.filename_cannot_be_empty=檔案名稱不能為空。
@ -1220,8 +1217,8 @@ projects.template.desc=範本
projects.template.desc_helper=選擇專案範本以開始
projects.type.uncategorized=未分類
projects.column.edit=編輯欄位
projects.column.edit_title=名稱
projects.column.new_title=名稱
projects.column.edit_title=組織名稱
projects.column.new_title=組織名稱
projects.column.new_submit=建立欄位
projects.column.new=新增欄位
projects.column.set_default=設為預設
@ -1241,7 +1238,7 @@ issues.filter_assignees=篩選負責人
issues.filter_milestones=篩選里程碑
issues.filter_projects=篩選專案
issues.filter_labels=篩選標籤
issues.filter_reviewers=篩選審
issues.filter_reviewers=篩選審
issues.new=新增問題
issues.new.title_empty=標題不可為空
issues.new.labels=標籤
@ -1658,7 +1655,6 @@ pulls.merge_instruction_hint=`您也可以查看<a class="show-instruction">命
pulls.merge_instruction_step1_desc=在您的儲存庫中切換到新分支並測試變更。
pulls.merge_instruction_step2_desc=合併變更並更新到 Gitea。
pulls.clear_merge_message=清除合併訊息
pulls.clear_merge_message_hint=清除合併訊息將僅移除提交訊息內容,留下產生的 git 結尾如「Co-Authored-By …」。
pulls.auto_merge_button_when_succeed=(當通過檢查後)
pulls.auto_merge_when_succeed=通過所有檢查後自動合併
@ -2623,7 +2619,7 @@ users.still_own_repo=這個使用者還擁有一個或更多的儲存庫。請
users.still_has_org=此使用者是組織的成員。請先將他從組織中移除。
users.purge=清除使用者
users.purge_help=強制刪除使用者和他擁有的所有儲存庫、組織、套件,所有留言也會被刪除。
users.still_own_packages=此使用者仍然擁有一個以上的套件,請先刪除這些套件。
users.still_own_packages=此使用者擁有一個或多個套件,請先刪除這些套件。
users.deletion_success=使用者帳戶已被刪除。
users.reset_2fa=重設兩步驟驗證
users.list_status_filter.menu_text=篩選
@ -2653,7 +2649,7 @@ emails.change_email_header=更新電子信箱屬性
emails.change_email_text=您確定要更新這個電子信箱?
orgs.org_manage_panel=組織管理
orgs.name=名稱
orgs.name=組織名稱
orgs.teams=團隊數
orgs.members=成員數
orgs.new_orga=新增組織
@ -2662,7 +2658,7 @@ repos.repo_manage_panel=儲存庫管理
repos.unadopted=未接管的儲存庫
repos.unadopted.no_more=找不到其他未接管的儲存庫
repos.owner=擁有者
repos.name=名稱
repos.name=儲存庫名稱
repos.private=私有
repos.watches=關注數
repos.stars=星號數
@ -2694,8 +2690,8 @@ systemhooks.update_webhook=更新系統 Webhook
auths.auth_manage_panel=認證來源管理
auths.new=新增認證來源
auths.name=名稱
auths.type=類型
auths.name=認證名稱
auths.type=認證類型
auths.enabled=已啟用
auths.syncenabled=啟用使用者同步
auths.updated=最後更新時間
@ -2766,7 +2762,6 @@ auths.oauth2_required_claim_value_helper=填寫此名稱以限制 Claim 中有
auths.oauth2_group_claim_name=Claim 名稱提供群組名稱給此來源。(選用)
auths.oauth2_admin_group=管理員使用者的群組 Claim 值。(選用 - 需要上面的 Claim 名稱)
auths.oauth2_restricted_group=受限制使用者的群組 Claim 值。(選用 - 需要上面的 Claim 名稱)
auths.oauth2_map_group_to_team=將已 Claim 的群組對應到組織團隊。(選用 - 需要上述 Claim 名稱)
auths.oauth2_map_group_to_team_removal=如果使用者不屬於相對應的群組,將使用者從已同步的團隊移除。
auths.enable_auto_register=允許授權用戶自動註冊
auths.sspi_auto_create_users=自動建立使用者
@ -2848,7 +2843,7 @@ config.lfs_http_auth_expiry=LFS HTTP 驗證有效時間
config.db_config=資料庫組態
config.db_type=資料庫類型
config.db_host=主機地址
config.db_name=名稱
config.db_name=資料庫名稱
config.db_user=使用者名稱
config.db_schema=結構描述
config.db_ssl_mode=SSL
@ -2951,7 +2946,7 @@ config.get_setting_failed=讀取設定值 %s 失敗
config.set_setting_failed=寫入設定值 %s 失敗
monitor.cron=Cron 任務
monitor.name=名稱
monitor.name=任務名稱
monitor.schedule=任務安排
monitor.next=下次執行時間
monitor.previous=上次執行時間
@ -3036,7 +3031,7 @@ notices.deselect_all=取消所有選取
notices.inverse_selection=反向選取
notices.delete_selected=刪除選取項
notices.delete_all=刪除所有提示
notices.type=類型
notices.type=提示類型
notices.type_1=儲存庫
notices.type_2=任務
notices.desc=描述
@ -3201,7 +3196,7 @@ generic.documentation=關於通用 registry 的詳情請參閱<a target="_blank"
helm.registry=透過下列命令設定此註冊中心:
helm.install=執行下列命令安裝此套件:
helm.documentation=關於 Helm registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/helm/">說明文件</a>。
maven.registry=在您專案的 <code>pom.xml</code> 檔設定此註冊中心:
maven.registry=在您的 <code>pom.xml</code> 檔設定此註冊中心:
maven.install=若要使用此套件,請在您 <code>pom.xml</code> 檔的 <code>dependencies</code> 段落加入下列內容:
maven.install2=透過下列命令執行:
maven.download=透過下列命令下載相依性:
@ -3210,7 +3205,7 @@ nuget.registry=透過下列命令設定此註冊中心:
nuget.install=執行下列命令以使用 NuGet 安裝此套件:
nuget.documentation=關於 NuGet registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/nuget/">說明文件</a>。
nuget.dependency.framework=目標框架
npm.registry=在您專案的 <code>.npmrc</code> 檔設定此註冊中心:
npm.registry=在您的 <code>.npmrc</code> 檔設定此註冊中心:
npm.install=執行下列命令以使用 npm 安裝此套件:
npm.install2=或將它加到 package.json 檔:
npm.documentation=關於 npm registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/npm/">說明文件</a>。
@ -3246,7 +3241,6 @@ settings.delete.success=已刪除該套件。
settings.delete.error=刪除套件失敗。
owner.settings.cargo.title=Cargo Registry 索引
owner.settings.cargo.initialize=初始化索引
owner.settings.cargo.initialize.description=使用 Cargo Registry 時需要一個特別的 Git 儲存庫作為索引。您可以在此使用必要的設定建立和重建它。
owner.settings.cargo.initialize.error=初始化 Cargo 索引失敗: %v
owner.settings.cargo.initialize.success=成功建立了 Cargo 索引。
owner.settings.cargo.rebuild=重建索引
@ -3258,7 +3252,6 @@ owner.settings.cleanuprules.add=加入清理規則
owner.settings.cleanuprules.edit=編輯清理規則
owner.settings.cleanuprules.none=沒有可用的清理規則。閱讀文件以了解更多。
owner.settings.cleanuprules.preview=清理規則預覽
owner.settings.cleanuprules.preview.overview=已排定要移除 %d 個套件。
owner.settings.cleanuprules.preview.none=清理規則不符合任何套件。
owner.settings.cleanuprules.enabled=已啟用
owner.settings.cleanuprules.pattern_full_match=將比對規則套用到完整的套件名稱
@ -3282,9 +3275,8 @@ secrets=Secret
description=Secret 會被傳給特定的 Action其他情況無法讀取。
none=還沒有 Secret。
value=
name=名稱
name=組織名稱
creation=加入 Secret
creation.name_placeholder=不區分大小寫,只能包含英文字母、數字、底線 ('_'),不能以 GITEA_ 或 GITHUB_ 開頭。
creation.value_placeholder=輸入任何內容,頭尾的空白都會被忽略。
creation.success=已加入 Secret「%s」。
creation.failed=加入 Secret 失敗。
@ -3313,8 +3305,8 @@ runners.new=建立 Runner
runners.new_notice=如何啟動 Runner
runners.status=狀態
runners.id=ID
runners.name=名稱
runners.owner_type=類型
runners.name=組織名稱
runners.owner_type=認證類型
runners.description=組織描述
runners.labels=標籤
runners.last_online=最後上線時間

View File

@ -105,7 +105,10 @@ func CreateHook(ctx *context.APIContext) {
// "$ref": "#/responses/Hook"
form := web.GetForm(ctx).(*api.CreateHookOption)
// TODO in body params
if !utils.CheckCreateHookOption(ctx, form) {
return
}
utils.AddSystemHook(ctx, form)
}

View File

@ -835,13 +835,6 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Get("/stopwatches", reqToken(auth_model.AccessTokenScopeRepo), repo.GetStopwatches)
m.Get("/subscriptions", reqToken(auth_model.AccessTokenScopeRepo), user.GetMyWatchedRepos)
m.Get("/teams", reqToken(auth_model.AccessTokenScopeRepo), org.ListUserTeams)
m.Group("/hooks", func() {
m.Combo("").Get(user.ListHooks).
Post(bind(api.CreateHookOption{}), user.CreateHook)
m.Combo("/{id}").Get(user.GetHook).
Patch(bind(api.EditHookOption{}), user.EditHook).
Delete(user.DeleteHook)
}, reqToken(auth_model.AccessTokenScopeAdminUserHook), reqWebhooksEnabled())
}, reqToken(""))
// Repositories

View File

@ -6,6 +6,7 @@ package org
import (
"net/http"
webhook_model "code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
@ -38,10 +39,34 @@ func ListHooks(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/HookList"
utils.ListOwnerHooks(
ctx,
ctx.ContextUser,
)
opts := &webhook_model.ListWebhookOptions{
ListOptions: utils.GetListOptions(ctx),
OrgID: ctx.Org.Organization.ID,
}
count, err := webhook_model.CountWebhooksByOpts(opts)
if err != nil {
ctx.InternalServerError(err)
return
}
orgHooks, err := webhook_model.ListWebhooksByOpts(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
hooks := make([]*api.Hook, len(orgHooks))
for i, hook := range orgHooks {
hooks[i], err = webhook_service.ToHook(ctx.Org.Organization.AsUser().HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
}
}
ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, hooks)
}
// GetHook get an organization's hook by id
@ -67,12 +92,14 @@ func GetHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"
hook, err := utils.GetOwnerHook(ctx, ctx.ContextUser.ID, ctx.ParamsInt64("id"))
org := ctx.Org.Organization
hookID := ctx.ParamsInt64(":id")
hook, err := utils.GetOrgHook(ctx, org.ID, hookID)
if err != nil {
return
}
apiHook, err := webhook_service.ToHook(ctx.ContextUser.HomeLink(), hook)
apiHook, err := webhook_service.ToHook(org.AsUser().HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
@ -104,14 +131,15 @@ func CreateHook(ctx *context.APIContext) {
// "201":
// "$ref": "#/responses/Hook"
utils.AddOwnerHook(
ctx,
ctx.ContextUser,
web.GetForm(ctx).(*api.CreateHookOption),
)
form := web.GetForm(ctx).(*api.CreateHookOption)
// TODO in body params
if !utils.CheckCreateHookOption(ctx, form) {
return
}
utils.AddOrgHook(ctx, form)
}
// EditHook modify a hook of an organization
// EditHook modify a hook of a repository
func EditHook(ctx *context.APIContext) {
// swagger:operation PATCH /orgs/{org}/hooks/{id} organization orgEditHook
// ---
@ -140,12 +168,11 @@ func EditHook(ctx *context.APIContext) {
// "200":
// "$ref": "#/responses/Hook"
utils.EditOwnerHook(
ctx,
ctx.ContextUser,
web.GetForm(ctx).(*api.EditHookOption),
ctx.ParamsInt64("id"),
)
form := web.GetForm(ctx).(*api.EditHookOption)
// TODO in body params
hookID := ctx.ParamsInt64(":id")
utils.EditOrgHook(ctx, form, hookID)
}
// DeleteHook delete a hook of an organization
@ -171,9 +198,15 @@ func DeleteHook(ctx *context.APIContext) {
// "204":
// "$ref": "#/responses/empty"
utils.DeleteOwnerHook(
ctx,
ctx.ContextUser,
ctx.ParamsInt64("id"),
)
org := ctx.Org.Organization
hookID := ctx.ParamsInt64(":id")
if err := webhook_model.DeleteWebhookByOrgID(org.ID, hookID); err != nil {
if webhook_model.IsErrWebhookNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOrgID", err)
}
return
}
ctx.Status(http.StatusNoContent)
}

View File

@ -223,8 +223,12 @@ func CreateHook(ctx *context.APIContext) {
// responses:
// "201":
// "$ref": "#/responses/Hook"
form := web.GetForm(ctx).(*api.CreateHookOption)
utils.AddRepoHook(ctx, web.GetForm(ctx).(*api.CreateHookOption))
if !utils.CheckCreateHookOption(ctx, form) {
return
}
utils.AddRepoHook(ctx, form)
}
// EditHook modify a hook of a repository

View File

@ -1,154 +0,0 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"net/http"
"code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/web"
"code.gitea.io/gitea/routers/api/v1/utils"
webhook_service "code.gitea.io/gitea/services/webhook"
)
// ListHooks list the authenticated user's webhooks
func ListHooks(ctx *context.APIContext) {
// swagger:operation GET /user/hooks user userListHooks
// ---
// summary: List the authenticated user's webhooks
// produces:
// - application/json
// parameters:
// - name: page
// in: query
// description: page number of results to return (1-based)
// type: integer
// - name: limit
// in: query
// description: page size of results
// type: integer
// responses:
// "200":
// "$ref": "#/responses/HookList"
utils.ListOwnerHooks(
ctx,
ctx.Doer,
)
}
// GetHook get the authenticated user's hook by id
func GetHook(ctx *context.APIContext) {
// swagger:operation GET /user/hooks/{id} user userGetHook
// ---
// summary: Get a hook
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: id of the hook to get
// type: integer
// format: int64
// required: true
// responses:
// "200":
// "$ref": "#/responses/Hook"
hook, err := utils.GetOwnerHook(ctx, ctx.Doer.ID, ctx.ParamsInt64("id"))
if err != nil {
return
}
apiHook, err := webhook_service.ToHook(ctx.Doer.HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
}
ctx.JSON(http.StatusOK, apiHook)
}
// CreateHook create a hook for the authenticated user
func CreateHook(ctx *context.APIContext) {
// swagger:operation POST /user/hooks user userCreateHook
// ---
// summary: Create a hook
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: body
// in: body
// required: true
// schema:
// "$ref": "#/definitions/CreateHookOption"
// responses:
// "201":
// "$ref": "#/responses/Hook"
utils.AddOwnerHook(
ctx,
ctx.Doer,
web.GetForm(ctx).(*api.CreateHookOption),
)
}
// EditHook modify a hook of the authenticated user
func EditHook(ctx *context.APIContext) {
// swagger:operation PATCH /user/hooks/{id} user userEditHook
// ---
// summary: Update a hook
// consumes:
// - application/json
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: id of the hook to update
// type: integer
// format: int64
// required: true
// - name: body
// in: body
// schema:
// "$ref": "#/definitions/EditHookOption"
// responses:
// "200":
// "$ref": "#/responses/Hook"
utils.EditOwnerHook(
ctx,
ctx.Doer,
web.GetForm(ctx).(*api.EditHookOption),
ctx.ParamsInt64("id"),
)
}
// DeleteHook delete a hook of the authenticated user
func DeleteHook(ctx *context.APIContext) {
// swagger:operation DELETE /user/hooks/{id} user userDeleteHook
// ---
// summary: Delete a hook
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: id of the hook to delete
// type: integer
// format: int64
// required: true
// responses:
// "204":
// "$ref": "#/responses/empty"
utils.DeleteOwnerHook(
ctx,
ctx.Doer,
ctx.ParamsInt64("id"),
)
}

View File

@ -8,7 +8,6 @@ import (
"net/http"
"strings"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/json"
@ -19,46 +18,15 @@ import (
webhook_service "code.gitea.io/gitea/services/webhook"
)
// ListOwnerHooks lists the webhooks of the provided owner
func ListOwnerHooks(ctx *context.APIContext, owner *user_model.User) {
opts := &webhook.ListWebhookOptions{
ListOptions: GetListOptions(ctx),
OwnerID: owner.ID,
}
count, err := webhook.CountWebhooksByOpts(opts)
if err != nil {
ctx.InternalServerError(err)
return
}
hooks, err := webhook.ListWebhooksByOpts(ctx, opts)
if err != nil {
ctx.InternalServerError(err)
return
}
apiHooks := make([]*api.Hook, len(hooks))
for i, hook := range hooks {
apiHooks[i], err = webhook_service.ToHook(owner.HomeLink(), hook)
if err != nil {
ctx.InternalServerError(err)
return
}
}
ctx.SetTotalCountHeader(count)
ctx.JSON(http.StatusOK, apiHooks)
}
// GetOwnerHook gets an user or organization webhook. Errors are written to ctx.
func GetOwnerHook(ctx *context.APIContext, ownerID, hookID int64) (*webhook.Webhook, error) {
w, err := webhook.GetWebhookByOwnerID(ownerID, hookID)
// GetOrgHook get an organization's webhook. If there is an error, write to
// `ctx` accordingly and return the error
func GetOrgHook(ctx *context.APIContext, orgID, hookID int64) (*webhook.Webhook, error) {
w, err := webhook.GetWebhookByOrgID(orgID, hookID)
if err != nil {
if webhook.IsErrWebhookNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "GetWebhookByOwnerID", err)
ctx.Error(http.StatusInternalServerError, "GetWebhookByOrgID", err)
}
return nil, err
}
@ -80,9 +48,9 @@ func GetRepoHook(ctx *context.APIContext, repoID, hookID int64) (*webhook.Webhoo
return w, nil
}
// checkCreateHookOption check if a CreateHookOption form is valid. If invalid,
// CheckCreateHookOption check if a CreateHookOption form is valid. If invalid,
// write the appropriate error to `ctx`. Return whether the form is valid
func checkCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption) bool {
func CheckCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption) bool {
if !webhook_service.IsValidHookTaskType(form.Type) {
ctx.Error(http.StatusUnprocessableEntity, "", fmt.Sprintf("Invalid hook type: %s", form.Type))
return false
@ -113,13 +81,14 @@ func AddSystemHook(ctx *context.APIContext, form *api.CreateHookOption) {
}
}
// AddOwnerHook adds a hook to an user or organization
func AddOwnerHook(ctx *context.APIContext, owner *user_model.User, form *api.CreateHookOption) {
hook, ok := addHook(ctx, form, owner.ID, 0)
// AddOrgHook add a hook to an organization. Writes to `ctx` accordingly
func AddOrgHook(ctx *context.APIContext, form *api.CreateHookOption) {
org := ctx.Org.Organization
hook, ok := addHook(ctx, form, org.ID, 0)
if !ok {
return
}
apiHook, ok := toAPIHook(ctx, owner.HomeLink(), hook)
apiHook, ok := toAPIHook(ctx, org.AsUser().HomeLink(), hook)
if !ok {
return
}
@ -159,18 +128,14 @@ func pullHook(events []string, event string) bool {
return util.SliceContainsString(events, event, true) || util.SliceContainsString(events, string(webhook_module.HookEventPullRequest), true)
}
// addHook add the hook specified by `form`, `ownerID` and `repoID`. If there is
// addHook add the hook specified by `form`, `orgID` and `repoID`. If there is
// an error, write to `ctx` accordingly. Return (webhook, ok)
func addHook(ctx *context.APIContext, form *api.CreateHookOption, ownerID, repoID int64) (*webhook.Webhook, bool) {
if !checkCreateHookOption(ctx, form) {
return nil, false
}
func addHook(ctx *context.APIContext, form *api.CreateHookOption, orgID, repoID int64) (*webhook.Webhook, bool) {
if len(form.Events) == 0 {
form.Events = []string{"push"}
}
w := &webhook.Webhook{
OwnerID: ownerID,
OrgID: orgID,
RepoID: repoID,
URL: form.Config["url"],
ContentType: webhook.ToHookContentType(form.Config["content_type"]),
@ -269,20 +234,21 @@ func EditSystemHook(ctx *context.APIContext, form *api.EditHookOption, hookID in
ctx.JSON(http.StatusOK, h)
}
// EditOwnerHook updates a webhook of an user or organization
func EditOwnerHook(ctx *context.APIContext, owner *user_model.User, form *api.EditHookOption, hookID int64) {
hook, err := GetOwnerHook(ctx, owner.ID, hookID)
// EditOrgHook edit webhook `w` according to `form`. Writes to `ctx` accordingly
func EditOrgHook(ctx *context.APIContext, form *api.EditHookOption, hookID int64) {
org := ctx.Org.Organization
hook, err := GetOrgHook(ctx, org.ID, hookID)
if err != nil {
return
}
if !editHook(ctx, form, hook) {
return
}
updated, err := GetOwnerHook(ctx, owner.ID, hookID)
updated, err := GetOrgHook(ctx, org.ID, hookID)
if err != nil {
return
}
apiHook, ok := toAPIHook(ctx, owner.HomeLink(), updated)
apiHook, ok := toAPIHook(ctx, org.AsUser().HomeLink(), updated)
if !ok {
return
}
@ -396,16 +362,3 @@ func editHook(ctx *context.APIContext, form *api.EditHookOption, w *webhook.Webh
}
return true
}
// DeleteOwnerHook deletes the hook owned by the owner.
func DeleteOwnerHook(ctx *context.APIContext, owner *user_model.User, hookID int64) {
if err := webhook.DeleteWebhookByOwnerID(owner.ID, hookID); err != nil {
if webhook.IsErrWebhookNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "DeleteWebhookByOwnerID", err)
}
return
}
ctx.Status(http.StatusNoContent)
}

View File

@ -271,15 +271,6 @@ func NewAuthSourcePost(ctx *context.Context) {
}
case auth.OAuth2:
config = parseOAuth2Config(form)
oauth2Config := config.(*oauth2.Source)
if oauth2Config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
ctx.Data["Err_DiscoveryURL"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthNew, form)
return
}
}
case auth.SSPI:
var err error
config, err = parseSSPIConfig(ctx, form)
@ -314,10 +305,6 @@ func NewAuthSourcePost(ctx *context.Context) {
if auth.IsErrSourceAlreadyExist(err) {
ctx.Data["Err_Name"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.login_source_exist", err.(auth.ErrSourceAlreadyExist).Name), tplAuthNew, form)
} else if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Data["Err_DiscoveryURL"] = true
unwrapped := err.(oauth2.ErrOpenIDConnectInitialize).Unwrap()
ctx.RenderWithErr(ctx.Tr("admin.auths.unable_to_initialize_openid", unwrapped), tplAuthNew, form)
} else {
ctx.ServerError("auth.CreateSource", err)
}
@ -402,15 +389,6 @@ func EditAuthSourcePost(ctx *context.Context) {
}
case auth.OAuth2:
config = parseOAuth2Config(form)
oauth2Config := config.(*oauth2.Source)
if oauth2Config.Provider == "openidConnect" {
discoveryURL, err := url.Parse(oauth2Config.OpenIDConnectAutoDiscoveryURL)
if err != nil || (discoveryURL.Scheme != "http" && discoveryURL.Scheme != "https") {
ctx.Data["Err_DiscoveryURL"] = true
ctx.RenderWithErr(ctx.Tr("admin.auths.invalid_openIdConnectAutoDiscoveryURL"), tplAuthEdit, form)
return
}
}
case auth.SSPI:
config, err = parseSSPIConfig(ctx, form)
if err != nil {
@ -430,7 +408,6 @@ func EditAuthSourcePost(ctx *context.Context) {
if err := auth.UpdateSource(source); err != nil {
if oauth2.IsErrOpenIDConnectInitialize(err) {
ctx.Flash.Error(err.Error(), true)
ctx.Data["Err_DiscoveryURL"] = true
ctx.HTML(http.StatusOK, tplAuthEdit)
} else {
ctx.ServerError("UpdateSource", err)

View File

@ -156,7 +156,6 @@ func Home(ctx *context.Context) {
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "language", "Language")
ctx.Data["Page"] = pager
ctx.Data["ContextUser"] = ctx.ContextUser
ctx.HTML(http.StatusOK, tplOrgHome)
}

View File

@ -123,7 +123,6 @@ func NewProject(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.projects.new")
ctx.Data["BoardTypes"] = project_model.GetBoardConfig()
ctx.Data["CanWriteProjects"] = canWriteProjects(ctx)
ctx.Data["PageIsViewProjects"] = true
ctx.Data["HomeLink"] = ctx.ContextUser.HomeLink()
shared_user.RenderUserHeader(ctx)
ctx.HTML(http.StatusOK, tplProjectsNew)

View File

@ -218,9 +218,9 @@ func Webhooks(ctx *context.Context) {
ctx.Data["BaseLinkNew"] = ctx.Org.OrgLink + "/settings/hooks"
ctx.Data["Description"] = ctx.Tr("org.settings.hooks_desc")
ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OwnerID: ctx.Org.Organization.ID})
ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OrgID: ctx.Org.Organization.ID})
if err != nil {
ctx.ServerError("ListWebhooksByOpts", err)
ctx.ServerError("GetWebhooksByOrgId", err)
return
}
@ -230,8 +230,8 @@ func Webhooks(ctx *context.Context) {
// DeleteWebhook response for delete webhook
func DeleteWebhook(ctx *context.Context) {
if err := webhook.DeleteWebhookByOwnerID(ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteWebhookByOwnerID: " + err.Error())
if err := webhook.DeleteWebhookByOrgID(ctx.Org.Organization.ID, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteWebhookByOrgID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
}

View File

@ -33,7 +33,6 @@ const (
tplHooks base.TplName = "repo/settings/webhook/base"
tplHookNew base.TplName = "repo/settings/webhook/new"
tplOrgHookNew base.TplName = "org/settings/hook_new"
tplUserHookNew base.TplName = "user/settings/hook_new"
tplAdminHookNew base.TplName = "admin/hook_new"
)
@ -55,8 +54,8 @@ func Webhooks(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplHooks)
}
type ownerRepoCtx struct {
OwnerID int64
type orgRepoCtx struct {
OrgID int64
RepoID int64
IsAdmin bool
IsSystemWebhook bool
@ -65,10 +64,10 @@ type ownerRepoCtx struct {
NewTemplate base.TplName
}
// getOwnerRepoCtx determines whether this is a repo, owner, or admin (both default and system) context.
func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) {
if is, ok := ctx.Data["IsRepositoryWebhook"]; ok && is.(bool) {
return &ownerRepoCtx{
// getOrgRepoCtx determines whether this is a repo, organization, or admin (both default and system) context.
func getOrgRepoCtx(ctx *context.Context) (*orgRepoCtx, error) {
if len(ctx.Repo.RepoLink) > 0 {
return &orgRepoCtx{
RepoID: ctx.Repo.Repository.ID,
Link: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
LinkNew: path.Join(ctx.Repo.RepoLink, "settings/hooks"),
@ -76,35 +75,37 @@ func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) {
}, nil
}
if is, ok := ctx.Data["IsOrganizationWebhook"]; ok && is.(bool) {
return &ownerRepoCtx{
OwnerID: ctx.ContextUser.ID,
if len(ctx.Org.OrgLink) > 0 {
return &orgRepoCtx{
OrgID: ctx.Org.Organization.ID,
Link: path.Join(ctx.Org.OrgLink, "settings/hooks"),
LinkNew: path.Join(ctx.Org.OrgLink, "settings/hooks"),
NewTemplate: tplOrgHookNew,
}, nil
}
if is, ok := ctx.Data["IsUserWebhook"]; ok && is.(bool) {
return &ownerRepoCtx{
OwnerID: ctx.Doer.ID,
Link: path.Join(setting.AppSubURL, "/user/settings/hooks"),
LinkNew: path.Join(setting.AppSubURL, "/user/settings/hooks"),
NewTemplate: tplUserHookNew,
if ctx.Doer.IsAdmin {
// Are we looking at default webhooks?
if ctx.Params(":configType") == "default-hooks" {
return &orgRepoCtx{
IsAdmin: true,
Link: path.Join(setting.AppSubURL, "/admin/hooks"),
LinkNew: path.Join(setting.AppSubURL, "/admin/default-hooks"),
NewTemplate: tplAdminHookNew,
}, nil
}
if ctx.Doer.IsAdmin {
return &ownerRepoCtx{
// Must be system webhooks instead
return &orgRepoCtx{
IsAdmin: true,
IsSystemWebhook: ctx.Params(":configType") == "system-hooks",
IsSystemWebhook: true,
Link: path.Join(setting.AppSubURL, "/admin/hooks"),
LinkNew: path.Join(setting.AppSubURL, "/admin/system-hooks"),
NewTemplate: tplAdminHookNew,
}, nil
}
return nil, errors.New("unable to set OwnerRepo context")
return nil, errors.New("unable to set OrgRepo context")
}
func checkHookType(ctx *context.Context) string {
@ -121,9 +122,9 @@ func WebhooksNew(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.settings.add_webhook")
ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}}
orCtx, err := getOwnerRepoCtx(ctx)
orCtx, err := getOrgRepoCtx(ctx)
if err != nil {
ctx.ServerError("getOwnerRepoCtx", err)
ctx.ServerError("getOrgRepoCtx", err)
return
}
@ -204,9 +205,9 @@ func createWebhook(ctx *context.Context, params webhookParams) {
ctx.Data["Webhook"] = webhook.Webhook{HookEvent: &webhook_module.HookEvent{}}
ctx.Data["HookType"] = params.Type
orCtx, err := getOwnerRepoCtx(ctx)
orCtx, err := getOrgRepoCtx(ctx)
if err != nil {
ctx.ServerError("getOwnerRepoCtx", err)
ctx.ServerError("getOrgRepoCtx", err)
return
}
ctx.Data["BaseLink"] = orCtx.LinkNew
@ -235,7 +236,7 @@ func createWebhook(ctx *context.Context, params webhookParams) {
IsActive: params.WebhookForm.Active,
Type: params.Type,
Meta: string(meta),
OwnerID: orCtx.OwnerID,
OrgID: orCtx.OrgID,
IsSystemWebhook: orCtx.IsSystemWebhook,
}
err = w.SetHeaderAuthorization(params.WebhookForm.AuthorizationHeader)
@ -576,19 +577,19 @@ func packagistHookParams(ctx *context.Context) webhookParams {
}
}
func checkWebhook(ctx *context.Context) (*ownerRepoCtx, *webhook.Webhook) {
orCtx, err := getOwnerRepoCtx(ctx)
func checkWebhook(ctx *context.Context) (*orgRepoCtx, *webhook.Webhook) {
orCtx, err := getOrgRepoCtx(ctx)
if err != nil {
ctx.ServerError("getOwnerRepoCtx", err)
ctx.ServerError("getOrgRepoCtx", err)
return nil, nil
}
ctx.Data["BaseLink"] = orCtx.Link
var w *webhook.Webhook
if orCtx.RepoID > 0 {
w, err = webhook.GetWebhookByRepoID(orCtx.RepoID, ctx.ParamsInt64(":id"))
} else if orCtx.OwnerID > 0 {
w, err = webhook.GetWebhookByOwnerID(orCtx.OwnerID, ctx.ParamsInt64(":id"))
w, err = webhook.GetWebhookByRepoID(ctx.Repo.Repository.ID, ctx.ParamsInt64(":id"))
} else if orCtx.OrgID > 0 {
w, err = webhook.GetWebhookByOrgID(ctx.Org.Organization.ID, ctx.ParamsInt64(":id"))
} else if orCtx.IsAdmin {
w, err = webhook.GetSystemOrDefaultWebhook(ctx, ctx.ParamsInt64(":id"))
}

View File

@ -9,8 +9,6 @@ import (
)
func RenderUserHeader(ctx *context.Context) {
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["ContextUser"] = ctx.ContextUser
}

View File

@ -24,7 +24,6 @@ func CodeSearch(ctx *context.Context) {
return
}
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
ctx.Data["Title"] = ctx.Tr("explore.code")

View File

@ -304,7 +304,6 @@ func Profile(ctx *context.Context) {
pager.AddParam(ctx, "date", "Date")
}
ctx.Data["Page"] = pager
ctx.Data["IsProjectEnabled"] = true
ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled

View File

@ -1,48 +0,0 @@
// Copyright 2023 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package setting
import (
"net/http"
"code.gitea.io/gitea/models/webhook"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting"
)
const (
tplSettingsHooks base.TplName = "user/settings/hooks"
)
// Webhooks render webhook list page
func Webhooks(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("settings")
ctx.Data["PageIsSettingsHooks"] = true
ctx.Data["BaseLink"] = setting.AppSubURL + "/user/settings/hooks"
ctx.Data["BaseLinkNew"] = setting.AppSubURL + "/user/settings/hooks"
ctx.Data["Description"] = ctx.Tr("settings.hooks.desc")
ws, err := webhook.ListWebhooksByOpts(ctx, &webhook.ListWebhookOptions{OwnerID: ctx.Doer.ID})
if err != nil {
ctx.ServerError("ListWebhooksByOpts", err)
return
}
ctx.Data["Webhooks"] = ws
ctx.HTML(http.StatusOK, tplSettingsHooks)
}
// DeleteWebhook response for delete webhook
func DeleteWebhook(ctx *context.Context) {
if err := webhook.DeleteWebhookByOwnerID(ctx.Doer.ID, ctx.FormInt64("id")); err != nil {
ctx.Flash.Error("DeleteWebhookByOwnerID: " + err.Error())
} else {
ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success"))
}
ctx.JSON(http.StatusOK, map[string]interface{}{
"redirect": setting.AppSubURL + "/user/settings/hooks",
})
}

View File

@ -315,35 +315,6 @@ func RegisterRoutes(m *web.Route) {
}
}
addWebhookAddRoutes := func() {
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
}
addWebhookEditRoutes := func() {
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
}
// FIXME: not all routes need go through same middleware.
// Especially some AJAX requests, we can reduce middleware number to improve performance.
// Routers.
@ -511,19 +482,6 @@ func RegisterRoutes(m *web.Route) {
m.Get("/organization", user_setting.Organization)
m.Get("/repos", user_setting.Repos)
m.Post("/repos/unadopted", user_setting.AdoptOrDeleteRepository)
m.Group("/hooks", func() {
m.Get("", user_setting.Webhooks)
m.Post("/delete", user_setting.DeleteWebhook)
addWebhookAddRoutes()
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
addWebhookEditRoutes()
}, webhooksEnabled, func(ctx *context.Context) {
ctx.Data["IsUserWebhook"] = true
})
}, reqSignIn, func(ctx *context.Context) {
ctx.Data["PageIsUserSettings"] = true
ctx.Data["AllThemes"] = setting.UI.Themes
@ -617,11 +575,32 @@ func RegisterRoutes(m *web.Route) {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
addWebhookEditRoutes()
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
}, webhooksEnabled)
m.Group("/{configType:default-hooks|system-hooks}", func() {
addWebhookAddRoutes()
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
})
m.Group("/auths", func() {
@ -711,21 +690,6 @@ func RegisterRoutes(m *web.Route) {
}
}
reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
return func(ctx *context.Context) {
if ctx.ContextUser == nil {
ctx.NotFound(unitType.String(), nil)
return
}
if ctx.ContextUser.IsOrganization() {
if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
ctx.NotFound(unitType.String(), nil)
return
}
}
}
}
// ***** START: Organization *****
m.Group("/org", func() {
m.Group("/{org}", func() {
@ -795,15 +759,32 @@ func RegisterRoutes(m *web.Route) {
m.Group("/hooks", func() {
m.Get("", org.Webhooks)
m.Post("/delete", org.DeleteWebhook)
addWebhookAddRoutes()
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
addWebhookEditRoutes()
}, webhooksEnabled, func(ctx *context.Context) {
ctx.Data["IsOrganizationWebhook"] = true
})
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
}, webhooksEnabled)
m.Group("/labels", func() {
m.Get("", org.RetrieveLabels, org.Labels)
@ -888,10 +869,8 @@ func RegisterRoutes(m *web.Route) {
}
m.Group("/projects", func() {
m.Group("", func() {
m.Get("", org.Projects)
m.Get("/{id}", org.ViewProject)
}, reqUnitAccess(unit.TypeProjects, perm.AccessModeRead))
m.Group("", func() { //nolint:dupl
m.Get("/new", org.NewProject)
m.Post("/new", web.Bind(forms.CreateProjectForm{}), org.NewProjectPost)
@ -911,18 +890,25 @@ func RegisterRoutes(m *web.Route) {
m.Post("/move", org.MoveIssues)
})
})
}, reqSignIn, reqUnitAccess(unit.TypeProjects, perm.AccessModeWrite), func(ctx *context.Context) {
if ctx.ContextUser.IsIndividual() && ctx.ContextUser.ID != ctx.Doer.ID {
}, reqSignIn, func(ctx *context.Context) {
if ctx.ContextUser == nil {
ctx.NotFound("NewProject", nil)
return
}
if ctx.ContextUser.IsOrganization() {
if !ctx.Org.CanWriteUnit(ctx, unit.TypeProjects) {
ctx.NotFound("NewProject", nil)
return
}
} else if ctx.ContextUser.ID != ctx.Doer.ID {
ctx.NotFound("NewProject", nil)
return
}
})
}, repo.MustEnableProjects)
m.Group("", func() {
m.Get("/code", user.CodeSearch)
}, reqUnitAccess(unit.TypeCode, perm.AccessModeRead))
}, context_service.UserAssignmentWeb(), context.OrgAssignment())
}, context_service.UserAssignmentWeb())
// ***** Release Attachment Download without Signin
m.Get("/{username}/{reponame}/releases/download/{vTag}/{fileName}", ignSignIn, context.RepoAssignment, repo.MustBeNotEmpty, repo.RedirectDownload)
@ -976,16 +962,35 @@ func RegisterRoutes(m *web.Route) {
m.Group("/hooks", func() {
m.Get("", repo.Webhooks)
m.Post("/delete", repo.DeleteWebhook)
addWebhookAddRoutes()
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
m.Post("/gogs/new", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksNewPost)
m.Post("/slack/new", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksNewPost)
m.Post("/discord/new", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksNewPost)
m.Post("/dingtalk/new", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksNewPost)
m.Post("/telegram/new", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksNewPost)
m.Post("/matrix/new", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksNewPost)
m.Post("/msteams/new", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksNewPost)
m.Post("/feishu/new", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksNewPost)
m.Post("/wechatwork/new", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksNewPost)
m.Post("/packagist/new", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksNewPost)
m.Group("/{id}", func() {
m.Get("", repo.WebHooksEdit)
m.Post("/test", repo.TestWebhook)
m.Post("/replay/{uuid}", repo.ReplayWebhook)
})
addWebhookEditRoutes()
}, webhooksEnabled, func(ctx *context.Context) {
ctx.Data["IsRepositoryWebhook"] = true
})
m.Post("/gitea/{id}", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksEditPost)
m.Post("/gogs/{id}", web.Bind(forms.NewGogshookForm{}), repo.GogsHooksEditPost)
m.Post("/slack/{id}", web.Bind(forms.NewSlackHookForm{}), repo.SlackHooksEditPost)
m.Post("/discord/{id}", web.Bind(forms.NewDiscordHookForm{}), repo.DiscordHooksEditPost)
m.Post("/dingtalk/{id}", web.Bind(forms.NewDingtalkHookForm{}), repo.DingtalkHooksEditPost)
m.Post("/telegram/{id}", web.Bind(forms.NewTelegramHookForm{}), repo.TelegramHooksEditPost)
m.Post("/matrix/{id}", web.Bind(forms.NewMatrixHookForm{}), repo.MatrixHooksEditPost)
m.Post("/msteams/{id}", web.Bind(forms.NewMSTeamsHookForm{}), repo.MSTeamsHooksEditPost)
m.Post("/feishu/{id}", web.Bind(forms.NewFeishuHookForm{}), repo.FeishuHooksEditPost)
m.Post("/wechatwork/{id}", web.Bind(forms.NewWechatWorkHookForm{}), repo.WechatworkHooksEditPost)
m.Post("/packagist/{id}", web.Bind(forms.NewPackagistHookForm{}), repo.PackagistHooksEditPost)
}, webhooksEnabled)
m.Group("/keys", func() {
m.Combo("").Get(repo.DeployKeys).

View File

@ -36,10 +36,6 @@ func (err ErrOpenIDConnectInitialize) Error() string {
return fmt.Sprintf("Failed to initialize OpenID Connect Provider with name '%s' with url '%s': %v", err.ProviderName, err.OpenIDConnectAutoDiscoveryURL, err.Cause)
}
func (err ErrOpenIDConnectInitialize) Unwrap() error {
return err.Cause
}
// wrapOpenIDConnectInitializeError is used to wrap the error but this cannot be done in modules/auth/oauth2
// inside oauth2: import cycle not allowed models -> modules/auth/oauth2 -> models
func wrapOpenIDConnectInitializeError(err error, providerName string, source *Source) error {

View File

@ -8,6 +8,7 @@ import (
"net/http"
"strings"
org_model "code.gitea.io/gitea/models/organization"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/context"
)
@ -56,6 +57,14 @@ func userAssignment(ctx *context.Context, errCb func(int, string, interface{}))
} else {
errCb(http.StatusInternalServerError, "GetUserByName", err)
}
} else {
if ctx.ContextUser.IsOrganization() {
if ctx.Org == nil {
ctx.Org = &context.Organization{}
}
ctx.Org.Organization = (*org_model.Organization)(ctx.ContextUser)
ctx.Data["Org"] = ctx.Org.Organization
}
}
}
}

View File

@ -101,7 +101,7 @@ func GenerateWebhooks(ctx context.Context, templateRepo, generateRepo *repo_mode
HookEvent: templateWebhook.HookEvent,
IsActive: templateWebhook.IsActive,
Type: templateWebhook.Type,
OwnerID: templateWebhook.OwnerID,
OrgID: templateWebhook.OrgID,
Events: templateWebhook.Events,
Meta: templateWebhook.Meta,
})

View File

@ -229,16 +229,16 @@ func PrepareWebhooks(ctx context.Context, source EventSource, event webhook_modu
owner = source.Repository.MustOwner(ctx)
}
// append additional webhooks of a user or organization
if owner != nil {
ownerHooks, err := webhook_model.ListWebhooksByOpts(ctx, &webhook_model.ListWebhookOptions{
OwnerID: owner.ID,
// check if owner is an org and append additional webhooks
if owner != nil && owner.IsOrganization() {
orgHooks, err := webhook_model.ListWebhooksByOpts(ctx, &webhook_model.ListWebhookOptions{
OrgID: owner.ID,
IsActive: util.OptionalBoolTrue,
})
if err != nil {
return fmt.Errorf("ListWebhooksByOpts: %w", err)
}
ws = append(ws, ownerHooks...)
ws = append(ws, orgHooks...)
}
// Add any admin-defined system webhooks

View File

@ -24,7 +24,7 @@
<label for="oauth2_icon_url">{{.locale.Tr "admin.auths.oauth2_icon_url"}}</label>
<input id="oauth2_icon_url" name="oauth2_icon_url" value="{{.oauth2_icon_url}}">
</div>
<div class="open_id_connect_auto_discovery_url required field{{if .Err_DiscoveryURL}} error{{end}}">
<div class="open_id_connect_auto_discovery_url required field">
<label for="open_id_connect_auto_discovery_url">{{.locale.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label>
<input id="open_id_connect_auto_discovery_url" name="open_id_connect_auto_discovery_url" value="{{.open_id_connect_auto_discovery_url}}">
</div>

View File

@ -3,18 +3,16 @@
<a class="{{if .PageIsViewRepositories}}active {{end}}item" href="{{$.Org.HomeLink}}">
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
</a>
{{if and .IsProjectEnabled .CanReadProjects}}
<a class="{{if .PageIsViewProjects}}active {{end}}item" href="{{$.Org.HomeLink}}/-/projects">
{{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}}
</a>
{{end}}
{{if and .IsPackageEnabled .CanReadPackages}}
{{if .IsPackageEnabled}}
<a class="item" href="{{$.Org.HomeLink}}/-/packages">
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
</a>
{{end}}
{{if and .IsRepoIndexerEnabled .CanReadCode}}
<a class="item" href="{{$.Org.HomeLink}}/-/code">
{{if .IsRepoIndexerEnabled}}
<a class="{{if $.PageIsOrgCode}}active {{end}}item" href="{{$.Org.HomeLink}}/-/code">
{{svg "octicon-code"}}&nbsp;{{$.locale.Tr "org.code"}}
</a>
{{end}}

View File

@ -20,8 +20,6 @@
<b>{{.tag_name}}</b><span class="at">@</span><strong>{{.tag_target}}</strong>
{{else}}
<input id="tag-name" name="tag_name" value="{{.tag_name}}" placeholder="{{.locale.Tr "repo.release.tag_name"}}" autofocus required maxlength="255">
<input id="tag-name-editor" type="hidden" data-existing-tags={{Json .Tags}} data-tag-helper={{.locale.Tr "repo.release.tag_helper"}} data-tag-helper-new={{.locale.Tr "repo.release.tag_helper_new"}} data-tag-helper-existing={{.locale.Tr "repo.release.tag_helper_existing"}} />
<div id="tag-target-selector" class="gt-dib">
<span class="at">@</span>
<div class="ui selection dropdown">
<input type="hidden" name="tag_target" value="{{.tag_target}}"/>
@ -37,10 +35,7 @@
{{end}}
</div>
</div>
</div>
<div>
<span id="tag-helper" class="help gt-mt-2">{{.locale.Tr "repo.release.tag_helper"}}</span>
</div>
<span class="help">{{.locale.Tr "repo.release.tag_helper"}}</span>
{{end}}
</div>
</div>

View File

@ -40,7 +40,7 @@
<span class="ui label">N/A</span>
{{end}}
</a>
{{if or $.Permission.IsAdmin $.IsOrganizationOwner $.PageIsAdmin $.PageIsUserSettings}}
{{if or $.Permission.IsAdmin $.IsOrganizationOwner $.PageIsAdmin}}
<div class="right menu">
<form class="item" action="{{$.Link}}/replay/{{.UUID}}" method="post">
{{$.CsrfTokenHtml}}

View File

@ -13014,152 +13014,6 @@
}
}
},
"/user/hooks": {
"get": {
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "List the authenticated user's webhooks",
"operationId": "userListHooks",
"parameters": [
{
"type": "integer",
"description": "page number of results to return (1-based)",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "page size of results",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"$ref": "#/responses/HookList"
}
}
},
"post": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Create a hook",
"operationId": "userCreateHook",
"parameters": [
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/CreateHookOption"
}
}
],
"responses": {
"201": {
"$ref": "#/responses/Hook"
}
}
}
},
"/user/hooks/{id}": {
"get": {
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Get a hook",
"operationId": "userGetHook",
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "id of the hook to get",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"$ref": "#/responses/Hook"
}
}
},
"delete": {
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Delete a hook",
"operationId": "userDeleteHook",
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "id of the hook to delete",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"204": {
"$ref": "#/responses/empty"
}
}
},
"patch": {
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"user"
],
"summary": "Update a hook",
"operationId": "userEditHook",
"parameters": [
{
"type": "integer",
"format": "int64",
"description": "id of the hook to update",
"name": "id",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"schema": {
"$ref": "#/definitions/EditHookOption"
}
}
],
"responses": {
"200": {
"$ref": "#/responses/Hook"
}
}
}
},
"/user/keys": {
"get": {
"produces": [

View File

@ -22,17 +22,15 @@
<a class="item" href="{{.ContextUser.HomeLink}}">
{{svg "octicon-repo"}} {{.locale.Tr "user.repositories"}}
</a>
{{if and .IsProjectEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadProjects))}}
<a href="{{.ContextUser.HomeLink}}/-/projects" class="{{if .PageIsViewProjects}}active {{end}}item">
{{svg "octicon-project-symlink"}} {{.locale.Tr "user.projects"}}
</a>
{{end}}
{{if and .IsPackageEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadPackages))}}
{{if (not .UnitPackagesGlobalDisabled)}}
<a href="{{.ContextUser.HomeLink}}/-/packages" class="{{if .IsPackagesPage}}active {{end}}item">
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
</a>
{{end}}
{{if and .IsRepoIndexerEnabled (or .ContextUser.IsIndividual (and .ContextUser.IsOrganization .CanReadCode))}}
{{if .IsRepoIndexerEnabled}}
<a href="{{.ContextUser.HomeLink}}/-/code" class="{{if .IsCodePage}}active {{end}}item">
{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
</a>

View File

@ -138,12 +138,6 @@
<label>admin:org_hook</label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input class="enable-system" type="checkbox" name="scope" value="admin:user_hook">
<label>admin:user_hook</label>
</div>
</div>
<div class="field">
<div class="ui checkbox">
<input class="enable-system" type="checkbox" name="scope" value="notification">

View File

@ -1,53 +0,0 @@
{{template "base/head" .}}
<div class="page-content user settings new webhook">
{{template "user/settings/navbar" .}}
<div class="ui container">
<div class="twelve wide column content">
{{template "base/alert" .}}
<h4 class="ui top attached header">
{{if .PageIsSettingsHooksNew}}{{.locale.Tr "repo.settings.add_webhook"}}{{else}}{{.locale.Tr "repo.settings.update_webhook"}}{{end}}
<div class="ui right">
{{if eq .HookType "gitea"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gitea.svg">
{{else if eq .HookType "gogs"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/gogs.ico">
{{else if eq .HookType "slack"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/slack.png">
{{else if eq .HookType "discord"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/discord.png">
{{else if eq .HookType "dingtalk"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/dingtalk.ico">
{{else if eq .HookType "telegram"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/telegram.png">
{{else if eq .HookType "msteams"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/msteams.png">
{{else if eq .HookType "feishu"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/feishu.png">
{{else if eq .HookType "matrix"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/matrix.svg">
{{else if eq .HookType "wechatwork"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/wechatwork.png">
{{else if eq .HookType "packagist"}}
<img width="26" height="26" src="{{AssetUrlPrefix}}/img/packagist.png">
{{end}}
</div>
</h4>
<div class="ui attached segment">
{{template "repo/settings/webhook/gitea" .}}
{{template "repo/settings/webhook/gogs" .}}
{{template "repo/settings/webhook/slack" .}}
{{template "repo/settings/webhook/discord" .}}
{{template "repo/settings/webhook/dingtalk" .}}
{{template "repo/settings/webhook/telegram" .}}
{{template "repo/settings/webhook/msteams" .}}
{{template "repo/settings/webhook/feishu" .}}
{{template "repo/settings/webhook/matrix" .}}
{{template "repo/settings/webhook/wechatwork" .}}
{{template "repo/settings/webhook/packagist" .}}
</div>
{{template "repo/settings/webhook/history" .}}
</div>
</div>
</div>
{{template "base/footer" .}}

View File

@ -1,8 +0,0 @@
{{template "base/head" .}}
<div class="page-content user settings webhooks">
{{template "user/settings/navbar" .}}
<div class="ui container">
{{template "repo/settings/webhook/list" .}}
</div>
</div>
{{template "base/footer" .}}

View File

@ -26,11 +26,6 @@
{{.locale.Tr "packages.title"}}
</a>
{{end}}
{{if not DisableWebhooks}}
<a class="{{if .PageIsSettingsHooks}}active {{end}}item" href="{{AppSubUrl}}/user/settings/hooks">
{{.locale.Tr "repo.settings.hooks"}}
</a>
{{end}}
<a class="{{if .PageIsSettingsOrganization}}active {{end}}item" href="{{AppSubUrl}}/user/settings/organization">
{{.locale.Tr "settings.organization"}}
</a>

View File

@ -55,6 +55,28 @@ LFS_START_SERVER = true
LFS_JWT_SECRET = Tv_MjmZuHqpIY6GFl12ebgkRAMt4RlWt0v4EHKSXO0w
SSH_TRUSTED_USER_CA_KEYS = ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCb4DC1dMFnJ6pXWo7GMxTchtzmJHYzfN6sZ9FAPFR4ijMLfGki+olvOMO5Fql1/yGnGfbELQa1S6y4shSvj/5K+zUFScmEXYf3Gcr87RqilLkyk16RS+cHNB1u87xTHbETaa3nyCJeGQRpd4IQ4NKob745mwDZ7jQBH8AZEng50Oh8y8fi8skBBBzaYp1ilgvzG740L7uex6fHV62myq0SXeCa+oJUjq326FU8y+Vsa32H8A3e7tOgXZPdt2TVNltx2S9H2WO8RMi7LfaSwARNfy1zu+bfR50r6ef8Yx5YKCMz4wWb1SHU1GS800mjOjlInLQORYRNMlSwR1+vLlVDciOqFapDSbj+YOVOawR0R1aqlSKpZkt33DuOBPx9qe6CVnIi7Z+Px/KqM+OLCzlLY/RS+LbxQpDWcfTVRiP+S5qRTcE3M3UioN/e0BE/1+MpX90IGpvVkA63ILYbKEa4bM3ASL7ChTCr6xN5XT+GpVJveFKK1cfNx9ExHI4rzYE=
[lfs]
MINIO_BASE_PATH = lfs/
[attachment]
MINIO_BASE_PATH = attachments/
[avatars]
MINIO_BASE_PATH = avatars/
[repo-avatars]
MINIO_BASE_PATH = repo-avatars/
[storage]
STORAGE_TYPE = minio
SERVE_DIRECT = false
MINIO_ENDPOINT = minio:9000
MINIO_ACCESS_KEY_ID = 123456
MINIO_SECRET_ACCESS_KEY = 12345678
MINIO_BUCKET = gitea
MINIO_LOCATION = us-east-1
MINIO_USE_SSL = false
[mailer]
ENABLED = true
MAILER_TYPE = dummy
@ -100,9 +122,6 @@ INSTALL_LOCK = true
SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
[lfs]
PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-mysql/data/lfs
[packages]
ENABLED = true

View File

@ -105,26 +105,7 @@ SECRET_KEY = 9pCviYTWSb
INTERNAL_TOKEN = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0OTU1NTE2MTh9.hhSVGOANkaKk3vfCd2jDOIww4pUk0xtg9JRde5UogyQ
[lfs]
MINIO_BASE_PATH = lfs/
[attachment]
MINIO_BASE_PATH = attachments/
[avatars]
MINIO_BASE_PATH = avatars/
[repo-avatars]
MINIO_BASE_PATH = repo-avatars/
[storage]
STORAGE_TYPE = minio
SERVE_DIRECT = false
MINIO_ENDPOINT = minio:9000
MINIO_ACCESS_KEY_ID = 123456
MINIO_SECRET_ACCESS_KEY = 12345678
MINIO_BUCKET = gitea
MINIO_LOCATION = us-east-1
MINIO_USE_SSL = false
PATH = tests/{{TEST_TYPE}}/gitea-{{TEST_TYPE}}-pgsql/data/lfs
[packages]
ENABLED = true

View File

@ -3,7 +3,7 @@ import {attachTribute} from './tribute.js';
import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js';
import {initEasyMDEImagePaste} from './comp/ImagePaste.js';
import {createCommentEasyMDE} from './comp/EasyMDE.js';
import {hideElem, showElem} from '../utils/dom.js';
import {hideElem} from '../utils/dom.js';
export function initRepoRelease() {
$(document).on('click', '.remove-rel-attach', function() {
@ -14,43 +14,8 @@ export function initRepoRelease() {
});
}
export function initRepoReleaseNew() {
const $repoReleaseNew = $('.repository.new.release');
if (!$repoReleaseNew.length) return;
initTagNameEditor();
initRepoReleaseEditor();
}
function initTagNameEditor() {
const el = document.getElementById('tag-name-editor');
if (!el) return;
const existingTags = JSON.parse(el.getAttribute('data-existing-tags'));
if (!Array.isArray(existingTags)) return;
const defaultTagHelperText = el.getAttribute('data-tag-helper');
const newTagHelperText = el.getAttribute('data-tag-helper-new');
const existingTagHelperText = el.getAttribute('data-tag-helper-existing');
document.getElementById('tag-name').addEventListener('keyup', (e) => {
const value = e.target.value;
if (existingTags.includes(value)) {
// If the tag already exists, hide the target branch selector.
hideElem('#tag-target-selector');
document.getElementById('tag-helper').innerText = existingTagHelperText;
} else {
showElem('#tag-target-selector');
if (value) {
document.getElementById('tag-helper').innerText = newTagHelperText;
} else {
document.getElementById('tag-helper').innerText = defaultTagHelperText;
}
}
});
}
function initRepoReleaseEditor() {
export function initRepoReleaseEditor() {
const $editor = $('.repository.new.release .content-editor');
if ($editor.length === 0) {
return;

View File

@ -76,7 +76,7 @@ import {
import {initViewedCheckboxListenerFor} from './features/pull-view-file.js';
import {initOrgTeamSearchRepoBox, initOrgTeamSettings} from './features/org-team.js';
import {initUserAuthWebAuthn, initUserAuthWebAuthnRegister} from './features/user-auth-webauthn.js';
import {initRepoRelease, initRepoReleaseNew} from './features/repo-release.js';
import {initRepoRelease, initRepoReleaseEditor} from './features/repo-release.js';
import {initRepoEditor} from './features/repo-editor.js';
import {initCompSearchUserBox} from './features/comp/SearchUserBox.js';
import {initInstall} from './features/install.js';
@ -179,7 +179,7 @@ $(document).ready(() => {
initRepoPullRequestAllowMaintainerEdit();
initRepoPullRequestReview();
initRepoRelease();
initRepoReleaseNew();
initRepoReleaseEditor();
initRepoSettingGitHook();
initRepoSettingSearchTeamBox();
initRepoSettingsCollaboration();