Merge remote-tracking branch 'upstream/main'
This commit is contained in:
commit
721b734049
380 changed files with 4696 additions and 4229 deletions
7
Makefile
7
Makefile
|
@ -17,7 +17,6 @@ else
|
|||
DIST := dist
|
||||
DIST_DIRS := $(DIST)/binaries $(DIST)/release
|
||||
IMPORT := code.gitea.io/gitea
|
||||
export GO111MODULE=on
|
||||
|
||||
GO ?= go
|
||||
SHASUM ?= shasum -a 256
|
||||
|
@ -363,7 +362,7 @@ test\#%:
|
|||
coverage:
|
||||
grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' coverage.out > coverage-bodged.out
|
||||
grep '^\(mode: .*\)\|\(.*:[0-9]\+\.[0-9]\+,[0-9]\+\.[0-9]\+ [0-9]\+ [0-9]\+\)$$' integration.coverage.out > integration.coverage-bodged.out
|
||||
GO111MODULE=on $(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all || (echo "gocovmerge failed"; echo "integration.coverage.out"; cat integration.coverage.out; echo "coverage.out"; cat coverage.out; exit 1)
|
||||
$(GO) run build/gocovmerge.go integration.coverage-bodged.out coverage-bodged.out > coverage.all || (echo "gocovmerge failed"; echo "integration.coverage.out"; cat integration.coverage.out; echo "coverage.out"; cat coverage.out; exit 1)
|
||||
|
||||
.PHONY: unit-test-coverage
|
||||
unit-test-coverage:
|
||||
|
@ -754,11 +753,11 @@ update-translations:
|
|||
|
||||
.PHONY: generate-license
|
||||
generate-license:
|
||||
GO111MODULE=on $(GO) run build/generate-licenses.go
|
||||
$(GO) run build/generate-licenses.go
|
||||
|
||||
.PHONY: generate-gitignore
|
||||
generate-gitignore:
|
||||
GO111MODULE=on $(GO) run build/generate-gitignores.go
|
||||
$(GO) run build/generate-gitignores.go
|
||||
|
||||
.PHONY: generate-images
|
||||
generate-images: | node_modules
|
||||
|
|
12
SECURITY.md
12
SECURITY.md
|
@ -11,12 +11,12 @@ Please **DO NOT** file a public issue, instead send your report privately to `se
|
|||
|
||||
Due to the sensitive nature of security information, you can use below GPG public key encrypt your mail body.
|
||||
|
||||
The PGP key is valid until June 24, 2024.
|
||||
Key ID: 6FCD2D5B
|
||||
Key Type: RSA
|
||||
Expires: 6/24/2024
|
||||
Key Size: 4096/4096
|
||||
Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
|
||||
The PGP key is valid until June 24, 2024.
|
||||
Key ID: 6FCD2D5B
|
||||
Key Type: RSA
|
||||
Expires: 6/24/2024
|
||||
Key Size: 4096/4096
|
||||
Fingerprint: 3DE0 3D1E 144A 7F06 9359 99DC AAFD 2381 6FCD 2D5B
|
||||
UserID: Gitea Security <security@gitea.io>
|
||||
|
||||
```
|
||||
|
|
|
@ -34,6 +34,10 @@ var (
|
|||
Name: "not-active",
|
||||
Usage: "Deactivate the authentication source.",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "active",
|
||||
Usage: "Activate the authentication source.",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "security-protocol",
|
||||
Usage: "Security protocol name.",
|
||||
|
@ -117,6 +121,10 @@ var (
|
|||
Name: "synchronize-users",
|
||||
Usage: "Enable user synchronization.",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "disable-synchronize-users",
|
||||
Usage: "Disable user synchronization.",
|
||||
},
|
||||
cli.UintFlag{
|
||||
Name: "page-size",
|
||||
Usage: "Search page size.",
|
||||
|
@ -183,9 +191,15 @@ func parseAuthSource(c *cli.Context, authSource *auth.Source) {
|
|||
if c.IsSet("not-active") {
|
||||
authSource.IsActive = !c.Bool("not-active")
|
||||
}
|
||||
if c.IsSet("active") {
|
||||
authSource.IsActive = c.Bool("active")
|
||||
}
|
||||
if c.IsSet("synchronize-users") {
|
||||
authSource.IsSyncEnabled = c.Bool("synchronize-users")
|
||||
}
|
||||
if c.IsSet("disable-synchronize-users") {
|
||||
authSource.IsSyncEnabled = !c.Bool("disable-synchronize-users")
|
||||
}
|
||||
}
|
||||
|
||||
// parseLdapConfig assigns values on config according to command line flags.
|
||||
|
|
|
@ -858,6 +858,36 @@ func TestUpdateLdapBindDn(t *testing.T) {
|
|||
},
|
||||
errMsg: "Invalid authentication type. expected: LDAP (via BindDN), actual: OAuth2",
|
||||
},
|
||||
// case 24
|
||||
{
|
||||
args: []string{
|
||||
"ldap-test",
|
||||
"--id", "24",
|
||||
"--name", "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
|
||||
"--active",
|
||||
"--disable-synchronize-users",
|
||||
},
|
||||
id: 24,
|
||||
existingAuthSource: &auth.Source{
|
||||
Type: auth.LDAP,
|
||||
IsActive: false,
|
||||
IsSyncEnabled: true,
|
||||
Cfg: &ldap.Source{
|
||||
Name: "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.LDAP,
|
||||
Name: "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
|
||||
IsActive: true,
|
||||
IsSyncEnabled: false,
|
||||
Cfg: &ldap.Source{
|
||||
Name: "ldap (via Bind DN) flip 'active' and 'user sync' attributes",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
|
@ -1221,6 +1251,33 @@ func TestUpdateLdapSimpleAuth(t *testing.T) {
|
|||
},
|
||||
errMsg: "Invalid authentication type. expected: LDAP (simple auth), actual: PAM",
|
||||
},
|
||||
// case 20
|
||||
{
|
||||
args: []string{
|
||||
"ldap-test",
|
||||
"--id", "20",
|
||||
"--name", "ldap (simple auth) flip 'active' attribute",
|
||||
"--active",
|
||||
},
|
||||
id: 20,
|
||||
existingAuthSource: &auth.Source{
|
||||
Type: auth.DLDAP,
|
||||
IsActive: false,
|
||||
Cfg: &ldap.Source{
|
||||
Name: "ldap (simple auth) flip 'active' attribute",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
authSource: &auth.Source{
|
||||
Type: auth.DLDAP,
|
||||
Name: "ldap (simple auth) flip 'active' attribute",
|
||||
IsActive: true,
|
||||
Cfg: &ldap.Source{
|
||||
Name: "ldap (simple auth) flip 'active' attribute",
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
base "code.gitea.io/gitea/modules/migration"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -83,6 +84,11 @@ func runDumpRepository(ctx *cli.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// migrations.GiteaLocalUploader depends on git module
|
||||
if err := git.InitSimple(context.Background()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Info("AppPath: %s", setting.AppPath)
|
||||
log.Info("AppWorkPath: %s", setting.AppWorkPath)
|
||||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
|
@ -128,7 +134,9 @@ func runDumpRepository(ctx *cli.Context) error {
|
|||
} else {
|
||||
units := strings.Split(ctx.String("units"), ",")
|
||||
for _, unit := range units {
|
||||
switch strings.ToLower(unit) {
|
||||
switch strings.ToLower(strings.TrimSpace(unit)) {
|
||||
case "":
|
||||
continue
|
||||
case "wiki":
|
||||
opts.Wiki = true
|
||||
case "issues":
|
||||
|
@ -145,6 +153,8 @@ func runDumpRepository(ctx *cli.Context) error {
|
|||
opts.Comments = true
|
||||
case "pull_requests":
|
||||
opts.PullRequests = true
|
||||
default:
|
||||
return errors.New("invalid unit: " + unit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ package cmd
|
|||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/private"
|
||||
|
@ -37,10 +38,10 @@ var CmdRestoreRepository = cli.Command{
|
|||
Value: "",
|
||||
Usage: "Restore destination repository name",
|
||||
},
|
||||
cli.StringSliceFlag{
|
||||
cli.StringFlag{
|
||||
Name: "units",
|
||||
Value: nil,
|
||||
Usage: `Which items will be restored, one or more units should be repeated with this flag.
|
||||
Value: "",
|
||||
Usage: `Which items will be restored, one or more units should be separated as comma.
|
||||
wiki, issues, labels, releases, release_assets, milestones, pull_requests, comments are allowed. Empty means all units.`,
|
||||
},
|
||||
cli.BoolFlag{
|
||||
|
@ -55,13 +56,16 @@ func runRestoreRepository(c *cli.Context) error {
|
|||
defer cancel()
|
||||
|
||||
setting.LoadFromExisting()
|
||||
|
||||
var units []string
|
||||
if s := c.String("units"); s != "" {
|
||||
units = strings.Split(s, ",")
|
||||
}
|
||||
statusCode, errStr := private.RestoreRepo(
|
||||
ctx,
|
||||
c.String("repo_dir"),
|
||||
c.String("owner_name"),
|
||||
c.String("repo_name"),
|
||||
c.StringSlice("units"),
|
||||
units,
|
||||
c.Bool("validation"),
|
||||
)
|
||||
if statusCode == http.StatusOK {
|
||||
|
|
|
@ -475,20 +475,6 @@ ENABLE = true
|
|||
;; Maximum length of oauth2 token/cookie stored on server
|
||||
;MAX_TOKEN_LENGTH = 32767
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[U2F]
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;
|
||||
;; NOTE: THE DEFAULT VALUES HERE WILL NEED TO BE CHANGED
|
||||
;; Two Factor authentication with security keys
|
||||
;; https://developers.yubico.com/U2F/App_ID.html
|
||||
;;
|
||||
;; DEPRECATED - this only applies to previously registered security keys using the U2F standard
|
||||
APP_ID = ; e.g. http://localhost:3000/
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
[log]
|
||||
|
@ -1245,7 +1231,7 @@ PATH =
|
|||
;; Define allowed algorithms and their minimum key length (use -1 to disable a type)
|
||||
;ED25519 = 256
|
||||
;ECDSA = 256
|
||||
;RSA = 2048
|
||||
;RSA = 2047 ; we allow 2047 here because an otherwise valid 2048 bit RSA key can be reported as having 2047 bit length
|
||||
;DSA = -1 ; set to 1024 to switch on
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
@ -1690,7 +1676,7 @@ PATH =
|
|||
;ENABLED = true
|
||||
;;
|
||||
;; Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
|
||||
;ALLOWED_TYPES = .docx,.gif,.gz,.jpeg,.jpg,.mp4,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip
|
||||
;ALLOWED_TYPES = .csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip
|
||||
;;
|
||||
;; Max size of each file. Defaults to 4MB
|
||||
;MAX_SIZE = 4
|
||||
|
@ -2127,7 +2113,7 @@ PATH =
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; The first locale will be used as the default if user browser's language doesn't match any locale in the list.
|
||||
;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN
|
||||
;LANGS = en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN
|
||||
;NAMES = English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,Français,Nederlands,Latviešu,Русский,Українська,日本語,Español,Português do Brasil,Português de Portugal,Polski,Български,Italiano,Suomi,Türkçe,Čeština,Српски,Svenska,한국어,Ελληνικά,فارسی,Magyar nyelv,Bahasa Indonesia,മലയാളം
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
@ -621,7 +621,7 @@ Define allowed algorithms and their minimum key length (use -1 to disable a type
|
|||
|
||||
- `ED25519`: **256**
|
||||
- `ECDSA`: **256**
|
||||
- `RSA`: **2048**
|
||||
- `RSA`: **2047**: We set 2047 here because an otherwise valid 2048 RSA key can be reported as 2047 length.
|
||||
- `DSA`: **-1**: DSA is now disabled by default. Set to **1024** to re-enable but ensure you may need to reconfigure your SSHD provider
|
||||
|
||||
## Webhook (`webhook`)
|
||||
|
@ -742,7 +742,7 @@ Default templates for project boards:
|
|||
## Issue and pull request attachments (`attachment`)
|
||||
|
||||
- `ENABLED`: **true**: Whether issue and pull request attachments are enabled.
|
||||
- `ALLOWED_TYPES`: **.docx,.gif,.gz,.jpeg,.jpg,mp4,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
|
||||
- `ALLOWED_TYPES`: **.csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip**: Comma-separated list of allowed file extensions (`.zip`), mime types (`text/plain`) or wildcard type (`image/*`, `audio/*`, `video/*`). Empty value or `*/*` allows all types.
|
||||
- `MAX_SIZE`: **4**: Maximum size (MB).
|
||||
- `MAX_FILES`: **5**: Maximum number of attachments that can be uploaded at once.
|
||||
- `STORAGE_TYPE`: **local**: Storage type for attachments, `local` for local disk or `minio` for s3 compatible object storage service, default is `local` or other name defined with `[storage.xxx]`
|
||||
|
@ -999,13 +999,10 @@ Default templates for project boards:
|
|||
|
||||
## i18n (`i18n`)
|
||||
|
||||
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sr-SP,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**:
|
||||
- `LANGS`: **en-US,zh-CN,zh-HK,zh-TW,de-DE,fr-FR,nl-NL,lv-LV,ru-RU,uk-UA,ja-JP,es-ES,pt-BR,pt-PT,pl-PL,bg-BG,it-IT,fi-FI,tr-TR,cs-CZ,sv-SE,ko-KR,el-GR,fa-IR,hu-HU,id-ID,ml-IN**:
|
||||
List of locales shown in language selector. The first locale will be used as the default if user browser's language doesn't match any locale in the list.
|
||||
- `NAMES`: **English,简体中文,繁體中文(香港),繁體中文(台灣),Deutsch,Français,Nederlands,Latviešu,Русский,Українська,日本語,Español,Português do Brasil,Português de Portugal,Polski,Български,Italiano,Suomi,Türkçe,Čeština,Српски,Svenska,한국어,Ελληνικά,فارسی,Magyar nyelv,Bahasa Indonesia,മലയാളം**: Visible names corresponding to the locales
|
||||
|
||||
## U2F (`U2F`) **DEPRECATED**
|
||||
- `APP_ID`: **`ROOT_URL`**: Declares the facet of the application which is used for authentication of previously registered U2F keys. Requires HTTPS.
|
||||
|
||||
## Markup (`markup`)
|
||||
|
||||
- `MERMAID_MAX_SOURCE_CHARACTERS`: **5000**: Set the maximum size of a Mermaid source. (Set to -1 to disable)
|
||||
|
|
|
@ -335,8 +335,8 @@ The list of themes a user can choose from can be configured with the `THEMES` va
|
|||
|
||||
To make a custom theme available to all users:
|
||||
|
||||
1. Add a CSS file to `$GITEA_PUBLIC/public/css/theme-<theme-name>.css`.
|
||||
The value of `$GITEA_PUBLIC` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath".
|
||||
1. Add a CSS file to `$GITEA_CUSTOM/public/css/theme-<theme-name>.css`.
|
||||
The value of `$GITEA_CUSTOM` of your instance can be queried by calling `gitea help` and looking up the value of "CustomPath".
|
||||
2. Add `<theme-name>` to the comma-separated list of setting `THEMES` in `app.ini`
|
||||
|
||||
Community themes are listed in [gitea/awesome-gitea#themes](https://gitea.com/gitea/awesome-gitea#themes).
|
||||
|
|
|
@ -50,7 +50,7 @@ menu:
|
|||
| 有寫入權限的儲存庫 Token | ✓ | ✘ | ✓ | ✓ | ✓ | ✘ | ✓ |
|
||||
| 內建 Container Registry | [✘](https://github.com/go-gitea/gitea/issues/2316) | ✘ | ✘ | ✓ | ✓ | ✘ | ✘ |
|
||||
| 對外部 Git 鏡像 | ✓ | ✓ | ✘ | ✘ | ✓ | ✓ | ✓ |
|
||||
| FIDO U2F (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| FIDO (2FA) | ✓ | ✘ | ✓ | ✓ | ✓ | ✓ | ✘ |
|
||||
| 內建 CI/CD | ✘ | ✘ | ✓ | ✓ | ✓ | ✘ | ✘ |
|
||||
| 子群組: 群組中的群組 | ✘ | ✘ | ✘ | ✓ | ✓ | ✘ | ✓ |
|
||||
|
||||
|
|
6
go.mod
6
go.mod
|
@ -66,7 +66,7 @@ require (
|
|||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/mattn/go-sqlite3 v1.14.12
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.18
|
||||
github.com/microcosm-cc/bluemonday v1.0.19
|
||||
github.com/minio/minio-go/v7 v7.0.26
|
||||
github.com/msteinert/pam v1.0.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
|
@ -94,9 +94,9 @@ require (
|
|||
go.jolheiser.com/hcaptcha v0.0.4
|
||||
go.jolheiser.com/pwn v0.0.3
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/tools v0.1.10
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
|
|
13
go.sum
13
go.sum
|
@ -1154,8 +1154,8 @@ github.com/mholt/acmez v1.0.2 h1:C8wsEBIUVi6e0DYoxqCcFuXtwc4AWXL/jgcDjF7mjVo=
|
|||
github.com/mholt/acmez v1.0.2/go.mod h1:8qnn8QA/Ewx8E3ZSsmscqsIjhhpxuy9vqdgbX2ceceM=
|
||||
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
|
||||
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
|
||||
github.com/microcosm-cc/bluemonday v1.0.18 h1:6HcxvXDAi3ARt3slx6nTesbvorIc3QeTzBNRvWktHBo=
|
||||
github.com/microcosm-cc/bluemonday v1.0.18/go.mod h1:Z0r70sCuXHig8YpBzCc5eGHAap2K7e/u082ZUpDRRqM=
|
||||
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
|
||||
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
|
@ -1793,14 +1793,13 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
|
|||
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210813160813-60bc85c4be6d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898 h1:K7wO6V1IrczY9QOQ2WkVpw4JQSwCd52UsxVEirZUfiw=
|
||||
golang.org/x/net v0.0.0-20220630215102-69896b714898/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
@ -1947,8 +1946,8 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
|
||||
|
|
|
@ -16,7 +16,7 @@ import (
|
|||
"code.gitea.io/gitea/models/organization"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/services/auth"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -275,8 +275,7 @@ func TestLDAPUserSigninFailed(t *testing.T) {
|
|||
addAuthSourceLDAP(t, "")
|
||||
|
||||
u := otherLDAPUsers[0]
|
||||
|
||||
testLoginFailed(t, u.UserName, u.Password, i18n.Tr("en", "form.username_password_incorrect"))
|
||||
testLoginFailed(t, u.UserName, u.Password, translation.NewLocale("en-US").Tr("form.username_password_incorrect"))
|
||||
}
|
||||
|
||||
func TestLDAPUserSSHKeySync(t *testing.T) {
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"net/url"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -37,7 +37,7 @@ func TestUndoDeleteBranch(t *testing.T) {
|
|||
htmlDoc, name := branchAction(t, ".undo-button")
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
||||
i18n.Tr("en", "repo.branch.restore_success", name),
|
||||
translation.NewLocale("en-US").Tr("repo.branch.restore_success", name),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ func deleteBranch(t *testing.T) {
|
|||
htmlDoc, name := branchAction(t, ".delete-branch-button")
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.positive.message").Text(),
|
||||
i18n.Tr("en", "repo.branch.deletion_success", name),
|
||||
translation.NewLocale("en-US").Tr("repo.branch.deletion_success", name),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,12 +5,17 @@
|
|||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/services/migrations"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -40,3 +45,54 @@ func TestMigrateLocalPath(t *testing.T) {
|
|||
|
||||
setting.ImportLocalPaths = old
|
||||
}
|
||||
|
||||
func TestMigrateGiteaForm(t *testing.T) {
|
||||
onGiteaRun(t, func(t *testing.T, u *url.URL) {
|
||||
AllowLocalNetworks := setting.Migrations.AllowLocalNetworks
|
||||
setting.Migrations.AllowLocalNetworks = true
|
||||
AppVer := setting.AppVer
|
||||
// Gitea SDK (go-sdk) need to parse the AppVer from server response, so we must set it to a valid version string.
|
||||
setting.AppVer = "1.16.0"
|
||||
defer func() {
|
||||
setting.Migrations.AllowLocalNetworks = AllowLocalNetworks
|
||||
setting.AppVer = AppVer
|
||||
migrations.Init()
|
||||
}()
|
||||
assert.NoError(t, migrations.Init())
|
||||
|
||||
ownerName := "user2"
|
||||
repoName := "repo1"
|
||||
repoOwner := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: ownerName}).(*user_model.User)
|
||||
session := loginUser(t, ownerName)
|
||||
token := getTokenForLoggedInUser(t, session)
|
||||
|
||||
// Step 0: verify the repo is available
|
||||
req := NewRequestf(t, "GET", fmt.Sprintf("/%s/%s", ownerName, repoName))
|
||||
_ = session.MakeRequest(t, req, http.StatusOK)
|
||||
// Step 1: get the Gitea migration form
|
||||
req = NewRequestf(t, "GET", "/repo/migrate/?service_type=%d", structs.GiteaService)
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
// Step 2: load the form
|
||||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
link, exists := htmlDoc.doc.Find(`form.ui.form[action^="/repo/migrate"]`).Attr("action")
|
||||
assert.True(t, exists, "The template has changed")
|
||||
// Step 4: submit the migration to only migrate issues
|
||||
migratedRepoName := "otherrepo"
|
||||
req = NewRequestWithValues(t, "POST", link, map[string]string{
|
||||
"_csrf": htmlDoc.GetCSRF(),
|
||||
"service": fmt.Sprintf("%d", structs.GiteaService),
|
||||
"clone_addr": fmt.Sprintf("%s%s/%s", u, ownerName, repoName),
|
||||
"auth_token": token,
|
||||
"issues": "on",
|
||||
"repo_name": migratedRepoName,
|
||||
"description": "",
|
||||
"uid": fmt.Sprintf("%d", repoOwner.ID),
|
||||
})
|
||||
resp = session.MakeRequest(t, req, http.StatusSeeOther)
|
||||
// Step 5: a redirection displays the migrated repository
|
||||
loc := resp.Header().Get("Location")
|
||||
assert.EqualValues(t, fmt.Sprintf("/%s/%s", ownerName, migratedRepoName), loc)
|
||||
// Step 6: check the repo was created
|
||||
unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{Name: migratedRepoName})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/git"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/services/pull"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
files_service "code.gitea.io/gitea/services/repository/files"
|
||||
|
@ -204,7 +204,7 @@ func TestCantMergeWorkInProgress(t *testing.T) {
|
|||
text := strings.TrimSpace(htmlDoc.doc.Find(".merge-section > .item").Last().Text())
|
||||
assert.NotEmpty(t, text, "Can't find WIP text")
|
||||
|
||||
assert.Contains(t, text, i18n.Tr("en", "repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
|
||||
assert.Contains(t, text, translation.NewLocale("en-US").Tr("repo.pulls.cannot_merge_work_in_progress"), "Unable to find WIP text")
|
||||
assert.Contains(t, text, "[wip]", "Unable to find WIP text")
|
||||
})
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
"code.gitea.io/gitea/models/unittest"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/PuerkitoBio/goquery"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -86,7 +86,7 @@ func TestCreateRelease(t *testing.T) {
|
|||
session := loginUser(t, "user2")
|
||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, false)
|
||||
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.stable"), 4)
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.stable"), 4)
|
||||
}
|
||||
|
||||
func TestCreateReleasePreRelease(t *testing.T) {
|
||||
|
@ -95,7 +95,7 @@ func TestCreateReleasePreRelease(t *testing.T) {
|
|||
session := loginUser(t, "user2")
|
||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", true, false)
|
||||
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.prerelease"), 4)
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.prerelease"), 4)
|
||||
}
|
||||
|
||||
func TestCreateReleaseDraft(t *testing.T) {
|
||||
|
@ -104,7 +104,7 @@ func TestCreateReleaseDraft(t *testing.T) {
|
|||
session := loginUser(t, "user2")
|
||||
createNewRelease(t, session, "/user2/repo1", "v0.0.1", "v0.0.1", false, true)
|
||||
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", i18n.Tr("en", "repo.release.draft"), 4)
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.1", translation.NewLocale("en-US").Tr("repo.release.draft"), 4)
|
||||
}
|
||||
|
||||
func TestCreateReleasePaging(t *testing.T) {
|
||||
|
@ -124,11 +124,11 @@ func TestCreateReleasePaging(t *testing.T) {
|
|||
}
|
||||
createNewRelease(t, session, "/user2/repo1", "v0.0.12", "v0.0.12", false, true)
|
||||
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", i18n.Tr("en", "repo.release.draft"), 10)
|
||||
checkLatestReleaseAndCount(t, session, "/user2/repo1", "v0.0.12", translation.NewLocale("en-US").Tr("repo.release.draft"), 10)
|
||||
|
||||
// Check that user4 does not see draft and still see 10 latest releases
|
||||
session2 := loginUser(t, "user4")
|
||||
checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", i18n.Tr("en", "repo.release.stable"), 10)
|
||||
checkLatestReleaseAndCount(t, session2, "/user2/repo1", "v0.0.11", translation.NewLocale("en-US").Tr("repo.release.stable"), 10)
|
||||
}
|
||||
|
||||
func TestViewReleaseListNoLogin(t *testing.T) {
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -52,37 +52,37 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "feature/test1",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature/test1"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test1"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.require_error"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.require_error"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "feature=test1",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature=test1"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature=test1"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: strings.Repeat("b", 101),
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.max_size_error", "100"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("form.NewBranchName") + translation.NewLocale("en-US").Tr("form.max_size_error", "100"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "master",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.branch_already_exists", "master"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_already_exists", "master"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "master/test",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.branch_name_conflict", "master/test", "master"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.branch_name_conflict", "master/test", "master"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "commit/acd1d892867872cb47f3993468605b8aa59aa2e0",
|
||||
|
@ -93,21 +93,21 @@ func testCreateBranches(t *testing.T, giteaURL *url.URL) {
|
|||
OldRefSubURL: "commit/65f1bf27bc3bf70f64657658635e66094edbcb4d",
|
||||
NewBranch: "feature/test3",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature/test3"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test3"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "branch/master",
|
||||
NewBranch: "v1.0.0",
|
||||
CreateRelease: "v1.0.0",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.tag_collision", "v1.0.0"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.tag_collision", "v1.0.0"),
|
||||
},
|
||||
{
|
||||
OldRefSubURL: "tag/v1.0.0",
|
||||
NewBranch: "feature/test4",
|
||||
CreateRelease: "v1.0.1",
|
||||
ExpectedStatus: http.StatusSeeOther,
|
||||
FlashMessage: i18n.Tr("en", "repo.branch.create_success", "feature/test4"),
|
||||
FlashMessage: translation.NewLocale("en-US").Tr("repo.branch.create_success", "feature/test4"),
|
||||
},
|
||||
}
|
||||
for _, test := range tests {
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -47,10 +47,10 @@ func TestSignin(t *testing.T) {
|
|||
password string
|
||||
message string
|
||||
}{
|
||||
{username: "wrongUsername", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")},
|
||||
{username: "wrongUsername", password: "password", message: i18n.Tr("en", "form.username_password_incorrect")},
|
||||
{username: "user15", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")},
|
||||
{username: "user1@example.com", password: "wrongPassword", message: i18n.Tr("en", "form.username_password_incorrect")},
|
||||
{username: "wrongUsername", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
||||
{username: "wrongUsername", password: "password", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
||||
{username: "user15", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
||||
{username: "user1@example.com", password: "wrongPassword", message: translation.NewLocale("en-US").Tr("form.username_password_incorrect")},
|
||||
}
|
||||
|
||||
for _, s := range samples {
|
||||
|
|
|
@ -13,7 +13,7 @@ import (
|
|||
"code.gitea.io/gitea/models/unittest"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -68,9 +68,9 @@ func TestSignupEmail(t *testing.T) {
|
|||
wantStatus int
|
||||
wantMsg string
|
||||
}{
|
||||
{"exampleUser@example.com\r\n", http.StatusOK, i18n.Tr("en", "form.email_invalid")},
|
||||
{"exampleUser@example.com\r", http.StatusOK, i18n.Tr("en", "form.email_invalid")},
|
||||
{"exampleUser@example.com\n", http.StatusOK, i18n.Tr("en", "form.email_invalid")},
|
||||
{"exampleUser@example.com\r\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
|
||||
{"exampleUser@example.com\r", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
|
||||
{"exampleUser@example.com\n", http.StatusOK, translation.NewLocale("en-US").Tr("form.email_invalid")},
|
||||
{"exampleUser@example.com", http.StatusSeeOther, ""},
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
user_model "code.gitea.io/gitea/models/user"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/test"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -67,7 +67,7 @@ func TestRenameInvalidUsername(t *testing.T) {
|
|||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||
i18n.Tr("en", "form.alpha_dash_dot_error"),
|
||||
translation.NewLocale("en-US").Tr("form.alpha_dash_dot_error"),
|
||||
)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &user_model.User{Name: invalidUsername})
|
||||
|
@ -131,7 +131,7 @@ func TestRenameReservedUsername(t *testing.T) {
|
|||
htmlDoc := NewHTMLParser(t, resp.Body)
|
||||
assert.Contains(t,
|
||||
htmlDoc.doc.Find(".ui.negative.message").Text(),
|
||||
i18n.Tr("en", "user.form.name_reserved", reservedUsername),
|
||||
translation.NewLocale("en-US").Tr("user.form.name_reserved", reservedUsername),
|
||||
)
|
||||
|
||||
unittest.AssertNotExistsBean(t, &user_model.User{Name: reservedUsername})
|
||||
|
|
|
@ -92,12 +92,12 @@ func init() {
|
|||
|
||||
// TableIndices implements xorm's TableIndices interface
|
||||
func (a *Action) TableIndices() []*schemas.Index {
|
||||
repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType)
|
||||
repoIndex.AddColumn("repo_id", "user_id", "is_deleted")
|
||||
|
||||
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
|
||||
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
|
||||
|
||||
repoIndex := schemas.NewIndex("r_c_u_d", schemas.IndexType)
|
||||
repoIndex.AddColumn("repo_id", "created_unix", "user_id", "is_deleted")
|
||||
|
||||
return []*schemas.Index{actUserIndex, repoIndex}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,17 @@ func ChangeProjectAssign(issue *Issue, doer *user_model.User, newProjectID int64
|
|||
func addUpdateIssueProject(ctx context.Context, issue *Issue, doer *user_model.User, newProjectID int64) error {
|
||||
oldProjectID := issue.projectID(ctx)
|
||||
|
||||
// Only check if we add a new project and not remove it.
|
||||
if newProjectID > 0 {
|
||||
newProject, err := project_model.GetProjectByID(ctx, newProjectID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if newProject.RepoID != issue.RepoID {
|
||||
return fmt.Errorf("issue's repository is not the same as project's repository")
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := db.GetEngine(ctx).Where("project_issue.issue_id=?", issue.ID).Delete(&project_model.ProjectIssue{}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -124,6 +124,11 @@ func NewMilestone(m *Milestone) (err error) {
|
|||
return committer.Commit()
|
||||
}
|
||||
|
||||
// HasMilestoneByRepoID returns if the milestone exists in the repository.
|
||||
func HasMilestoneByRepoID(ctx context.Context, repoID, id int64) (bool, error) {
|
||||
return db.GetEngine(ctx).ID(id).Where("repo_id=?", repoID).Exist(new(Milestone))
|
||||
}
|
||||
|
||||
// GetMilestoneByRepoID returns the milestone in a repository.
|
||||
func GetMilestoneByRepoID(ctx context.Context, repoID, id int64) (*Milestone, error) {
|
||||
m := new(Milestone)
|
||||
|
@ -356,7 +361,7 @@ func (opts GetMilestonesOption) toCond() builder.Cond {
|
|||
}
|
||||
|
||||
if len(opts.Name) != 0 {
|
||||
cond = cond.And(builder.Like{"name", opts.Name})
|
||||
cond = cond.And(builder.Like{"UPPER(name)", strings.ToUpper(opts.Name)})
|
||||
}
|
||||
|
||||
return cond
|
||||
|
|
|
@ -56,6 +56,9 @@ type Version struct {
|
|||
Version int64
|
||||
}
|
||||
|
||||
// Use noopMigration when there is a migration that has been no-oped
|
||||
var noopMigration = func(_ *xorm.Engine) error { return nil }
|
||||
|
||||
// This is a sequence of migrations. Add new migrations to the bottom of the list.
|
||||
// If you want to "retire" a migration, remove it from the top of the list and
|
||||
// update minDBVersion accordingly
|
||||
|
@ -351,7 +354,7 @@ var migrations = []Migration{
|
|||
// v198 -> v199
|
||||
NewMigration("Add issue content history table", addTableIssueContentHistory),
|
||||
// v199 -> v200
|
||||
NewMigration("No-op (remote version is using AppState now)", addRemoteVersionTableNoop),
|
||||
NewMigration("No-op (remote version is using AppState now)", noopMigration),
|
||||
// v200 -> v201
|
||||
NewMigration("Add table app_state", addTableAppState),
|
||||
// v201 -> v202
|
||||
|
@ -388,9 +391,11 @@ var migrations = []Migration{
|
|||
// v215 -> v216
|
||||
NewMigration("allow to view files in PRs", addReviewViewedFiles),
|
||||
// v216 -> v217
|
||||
NewMigration("Improve Action table indices", improveActionTableIndices),
|
||||
NewMigration("No-op (Improve Action table indices v1)", noopMigration),
|
||||
// v217 -> v218
|
||||
NewMigration("Alter hook_task table TEXT fields to LONGTEXT", alterHookTaskTextFieldsToLongText),
|
||||
// v218 -> v219
|
||||
NewMigration("Improve Action table indices v2", improveActionTableIndices),
|
||||
}
|
||||
|
||||
// GetCurrentDBVersion returns the current db version
|
||||
|
|
|
@ -4,11 +4,4 @@
|
|||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
func addRemoteVersionTableNoop(x *xorm.Engine) error {
|
||||
// we used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now.
|
||||
return nil
|
||||
}
|
||||
// We used to use a table `remote_version` to store information for updater, now we use `AppState`, so this migration task is a no-op now.
|
||||
|
|
|
@ -4,43 +4,5 @@
|
|||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type improveActionTableIndicesAction struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 // Receiver user id.
|
||||
OpType int
|
||||
ActUserID int64 // Action user id.
|
||||
RepoID int64
|
||||
CommentID int64 `xorm:"INDEX"`
|
||||
IsDeleted bool `xorm:"NOT NULL DEFAULT false"`
|
||||
RefName string
|
||||
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Content string `xorm:"TEXT"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||||
}
|
||||
|
||||
// TableName sets the name of this table
|
||||
func (a *improveActionTableIndicesAction) TableName() string {
|
||||
return "action"
|
||||
}
|
||||
|
||||
// TableIndices implements xorm's TableIndices interface
|
||||
func (a *improveActionTableIndicesAction) TableIndices() []*schemas.Index {
|
||||
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
|
||||
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
|
||||
|
||||
repoIndex := schemas.NewIndex("r_c_u_d", schemas.IndexType)
|
||||
repoIndex.AddColumn("repo_id", "created_unix", "user_id", "is_deleted")
|
||||
|
||||
return []*schemas.Index{actUserIndex, repoIndex}
|
||||
}
|
||||
|
||||
func improveActionTableIndices(x *xorm.Engine) error {
|
||||
return x.Sync2(&improveActionTableIndicesAction{})
|
||||
}
|
||||
// This migration added non-ideal indices to the action table which on larger datasets slowed things down
|
||||
// it has been superceded by v218.go
|
||||
|
|
46
models/migrations/v218.go
Normal file
46
models/migrations/v218.go
Normal file
|
@ -0,0 +1,46 @@
|
|||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package migrations
|
||||
|
||||
import (
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
|
||||
"xorm.io/xorm"
|
||||
"xorm.io/xorm/schemas"
|
||||
)
|
||||
|
||||
type improveActionTableIndicesAction struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
UserID int64 // Receiver user id.
|
||||
OpType int
|
||||
ActUserID int64 // Action user id.
|
||||
RepoID int64
|
||||
CommentID int64 `xorm:"INDEX"`
|
||||
IsDeleted bool `xorm:"NOT NULL DEFAULT false"`
|
||||
RefName string
|
||||
IsPrivate bool `xorm:"NOT NULL DEFAULT false"`
|
||||
Content string `xorm:"TEXT"`
|
||||
CreatedUnix timeutil.TimeStamp `xorm:"created"`
|
||||
}
|
||||
|
||||
// TableName sets the name of this table
|
||||
func (*improveActionTableIndicesAction) TableName() string {
|
||||
return "action"
|
||||
}
|
||||
|
||||
// TableIndices implements xorm's TableIndices interface
|
||||
func (*improveActionTableIndicesAction) TableIndices() []*schemas.Index {
|
||||
repoIndex := schemas.NewIndex("r_u_d", schemas.IndexType)
|
||||
repoIndex.AddColumn("repo_id", "user_id", "is_deleted")
|
||||
|
||||
actUserIndex := schemas.NewIndex("au_r_c_u_d", schemas.IndexType)
|
||||
actUserIndex.AddColumn("act_user_id", "repo_id", "created_unix", "user_id", "is_deleted")
|
||||
|
||||
return []*schemas.Index{actUserIndex, repoIndex}
|
||||
}
|
||||
|
||||
func improveActionTableIndices(x *xorm.Engine) error {
|
||||
return x.Sync2(&improveActionTableIndicesAction{})
|
||||
}
|
|
@ -316,37 +316,45 @@ func (u *User) GenerateEmailActivateCode(email string) string {
|
|||
}
|
||||
|
||||
// GetUserFollowers returns range of user's followers.
|
||||
func GetUserFollowers(u *User, listOptions db.ListOptions) ([]*User, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
|
||||
sess := db.GetEngine(ctx).
|
||||
Select("`user`.*").
|
||||
Join("LEFT", "follow", "`user`.id=follow.user_id").
|
||||
Where("follow.follow_id=?", u.ID).
|
||||
Join("LEFT", "follow", "`user`.id=follow.user_id")
|
||||
And(isUserVisibleToViewerCond(viewer))
|
||||
|
||||
if listOptions.Page != 0 {
|
||||
sess = db.SetSessionPagination(sess, &listOptions)
|
||||
|
||||
users := make([]*User, 0, listOptions.PageSize)
|
||||
return users, sess.Find(&users)
|
||||
count, err := sess.FindAndCount(&users)
|
||||
return users, count, err
|
||||
}
|
||||
|
||||
users := make([]*User, 0, 8)
|
||||
return users, sess.Find(&users)
|
||||
count, err := sess.FindAndCount(&users)
|
||||
return users, count, err
|
||||
}
|
||||
|
||||
// GetUserFollowing returns range of user's following.
|
||||
func GetUserFollowing(u *User, listOptions db.ListOptions) ([]*User, error) {
|
||||
func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) {
|
||||
sess := db.GetEngine(db.DefaultContext).
|
||||
Select("`user`.*").
|
||||
Join("LEFT", "follow", "`user`.id=follow.follow_id").
|
||||
Where("follow.user_id=?", u.ID).
|
||||
Join("LEFT", "follow", "`user`.id=follow.follow_id")
|
||||
And(isUserVisibleToViewerCond(viewer))
|
||||
|
||||
if listOptions.Page != 0 {
|
||||
sess = db.SetSessionPagination(sess, &listOptions)
|
||||
|
||||
users := make([]*User, 0, listOptions.PageSize)
|
||||
return users, sess.Find(&users)
|
||||
count, err := sess.FindAndCount(&users)
|
||||
return users, count, err
|
||||
}
|
||||
|
||||
users := make([]*User, 0, 8)
|
||||
return users, sess.Find(&users)
|
||||
count, err := sess.FindAndCount(&users)
|
||||
return users, count, err
|
||||
}
|
||||
|
||||
// NewGitSig generates and returns the signature of given user.
|
||||
|
@ -485,6 +493,9 @@ func (u *User) GitName() string {
|
|||
|
||||
// ShortName ellipses username to length
|
||||
func (u *User) ShortName(length int) string {
|
||||
if setting.UI.DefaultShowFullName && len(u.FullName) > 0 {
|
||||
return base.EllipsisString(u.FullName, length)
|
||||
}
|
||||
return base.EllipsisString(u.Name, length)
|
||||
}
|
||||
|
||||
|
@ -1219,6 +1230,39 @@ func GetAdminUser() (*User, error) {
|
|||
return &admin, nil
|
||||
}
|
||||
|
||||
func isUserVisibleToViewerCond(viewer *User) builder.Cond {
|
||||
if viewer != nil && viewer.IsAdmin {
|
||||
return builder.NewCond()
|
||||
}
|
||||
|
||||
if viewer == nil || viewer.IsRestricted {
|
||||
return builder.Eq{
|
||||
"`user`.visibility": structs.VisibleTypePublic,
|
||||
}
|
||||
}
|
||||
|
||||
return builder.Neq{
|
||||
"`user`.visibility": structs.VisibleTypePrivate,
|
||||
}.Or(
|
||||
builder.In("`user`.id",
|
||||
builder.
|
||||
Select("`follow`.user_id").
|
||||
From("follow").
|
||||
Where(builder.Eq{"`follow`.follow_id": viewer.ID})),
|
||||
builder.In("`user`.id",
|
||||
builder.
|
||||
Select("`team_user`.uid").
|
||||
From("team_user").
|
||||
Join("INNER", "`team_user` AS t2", "`team_user`.id = `t2`.id").
|
||||
Where(builder.Eq{"`t2`.uid": viewer.ID})),
|
||||
builder.In("`user`.id",
|
||||
builder.
|
||||
Select("`team_user`.uid").
|
||||
From("team_user").
|
||||
Join("INNER", "`team_user` AS t2", "`team_user`.org_id = `t2`.org_id").
|
||||
Where(builder.Eq{"`t2`.uid": viewer.ID})))
|
||||
}
|
||||
|
||||
// IsUserVisibleToViewer check if viewer is able to see user profile
|
||||
func IsUserVisibleToViewer(ctx context.Context, u, viewer *User) bool {
|
||||
if viewer != nil && viewer.IsAdmin {
|
||||
|
|
|
@ -794,7 +794,7 @@ func Contexter() func(next http.Handler) http.Handler {
|
|||
ctx.Data["UnitPullsGlobalDisabled"] = unit.TypePullRequests.UnitGlobalDisabled()
|
||||
ctx.Data["UnitProjectsGlobalDisabled"] = unit.TypeProjects.UnitGlobalDisabled()
|
||||
|
||||
ctx.Data["i18n"] = locale
|
||||
ctx.Data["locale"] = locale
|
||||
ctx.Data["AllLangs"] = translation.AllLangs()
|
||||
|
||||
next.ServeHTTP(ctx.Resp, ctx.Req)
|
||||
|
|
|
@ -58,6 +58,29 @@ func checkUserEmail(ctx context.Context, logger log.Logger, _ bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// From time to time Gitea makes changes to the reserved usernames and which symbols
|
||||
// are allowed for various reasons. This check helps with detecting users that, according
|
||||
// to our reserved names, don't have a valid username.
|
||||
func checkUserName(ctx context.Context, logger log.Logger, _ bool) error {
|
||||
var invalidUserCount int64
|
||||
if err := iterateUserAccounts(ctx, func(u *user.User) error {
|
||||
if err := user.IsUsableUsername(u.Name); err != nil {
|
||||
invalidUserCount++
|
||||
logger.Warn("User[id=%d] does not have a valid username: %v", u.ID, err)
|
||||
}
|
||||
return nil
|
||||
}); err != nil {
|
||||
return fmt.Errorf("iterateUserAccounts: %v", err)
|
||||
}
|
||||
|
||||
if invalidUserCount == 0 {
|
||||
logger.Info("All users have a valid username.")
|
||||
} else {
|
||||
logger.Warn("%d user(s) have a non-valid username.", invalidUserCount)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
Register(&Check{
|
||||
Title: "Check if users has an valid email address",
|
||||
|
@ -66,4 +89,11 @@ func init() {
|
|||
Run: checkUserEmail,
|
||||
Priority: 9,
|
||||
})
|
||||
Register(&Check{
|
||||
Title: "Check if users have a valid username",
|
||||
Name: "check-user-names",
|
||||
IsDefault: false,
|
||||
Run: checkUserName,
|
||||
Priority: 9,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -284,7 +284,7 @@ func (b *ElasticSearchIndexer) Index(ctx context.Context, repo *repo_model.Repos
|
|||
reqs := make([]elastic.BulkableRequest, 0)
|
||||
if len(changes.Updates) > 0 {
|
||||
// Now because of some insanity with git cat-file not immediately failing if not run in a valid git directory we need to run git rev-parse first!
|
||||
if err := git.EnsureValidGitRepository(git.DefaultContext, repo.RepoPath()); err != nil {
|
||||
if err := git.EnsureValidGitRepository(ctx, repo.RepoPath()); err != nil {
|
||||
log.Error("Unable to open git repo: %s for %-v: %v", repo.RepoPath(), repo, err)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -841,9 +841,10 @@ func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) {
|
|||
|
||||
// Repos with external issue trackers might still need to reference local PRs
|
||||
// We need to concern with the first one that shows up in the text, whichever it is
|
||||
if hasExtTrackFormat && !isNumericStyle {
|
||||
if hasExtTrackFormat && !isNumericStyle && refNumeric != nil {
|
||||
// If numeric (PR) was found, and it was BEFORE the non-numeric pattern, use that
|
||||
if foundNumeric && refNumeric.RefLocation.Start < ref.RefLocation.Start {
|
||||
// Allow a free-pass when non-numeric pattern wasn't found.
|
||||
if found && (ref == nil || refNumeric.RefLocation.Start < ref.RefLocation.Start) {
|
||||
found = foundNumeric
|
||||
ref = refNumeric
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import (
|
|||
"net/url"
|
||||
|
||||
"code.gitea.io/gitea/modules/markup"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/yuin/goldmark/ast"
|
||||
)
|
||||
|
@ -18,7 +18,7 @@ func createTOCNode(toc []markup.Header, lang string) ast.Node {
|
|||
details := NewDetails()
|
||||
summary := NewSummary()
|
||||
|
||||
summary.AppendChild(summary, ast.NewString([]byte(i18n.Tr(lang, "toc"))))
|
||||
summary.AppendChild(summary, ast.NewString([]byte(translation.NewLocale(lang).Tr("toc"))))
|
||||
details.AppendChild(details, summary)
|
||||
ul := ast.NewList('-')
|
||||
details.AppendChild(details, ul)
|
||||
|
|
|
@ -19,52 +19,52 @@ func (n NullDownloader) SetContext(_ context.Context) {}
|
|||
|
||||
// GetRepoInfo returns a repository information
|
||||
func (n NullDownloader) GetRepoInfo() (*Repository, error) {
|
||||
return nil, &ErrNotSupported{Entity: "RepoInfo"}
|
||||
return nil, ErrNotSupported{Entity: "RepoInfo"}
|
||||
}
|
||||
|
||||
// GetTopics return repository topics
|
||||
func (n NullDownloader) GetTopics() ([]string, error) {
|
||||
return nil, &ErrNotSupported{Entity: "Topics"}
|
||||
return nil, ErrNotSupported{Entity: "Topics"}
|
||||
}
|
||||
|
||||
// GetMilestones returns milestones
|
||||
func (n NullDownloader) GetMilestones() ([]*Milestone, error) {
|
||||
return nil, &ErrNotSupported{Entity: "Milestones"}
|
||||
return nil, ErrNotSupported{Entity: "Milestones"}
|
||||
}
|
||||
|
||||
// GetReleases returns releases
|
||||
func (n NullDownloader) GetReleases() ([]*Release, error) {
|
||||
return nil, &ErrNotSupported{Entity: "Releases"}
|
||||
return nil, ErrNotSupported{Entity: "Releases"}
|
||||
}
|
||||
|
||||
// GetLabels returns labels
|
||||
func (n NullDownloader) GetLabels() ([]*Label, error) {
|
||||
return nil, &ErrNotSupported{Entity: "Labels"}
|
||||
return nil, ErrNotSupported{Entity: "Labels"}
|
||||
}
|
||||
|
||||
// GetIssues returns issues according start and limit
|
||||
func (n NullDownloader) GetIssues(page, perPage int) ([]*Issue, bool, error) {
|
||||
return nil, false, &ErrNotSupported{Entity: "Issues"}
|
||||
return nil, false, ErrNotSupported{Entity: "Issues"}
|
||||
}
|
||||
|
||||
// GetComments returns comments of an issue or PR
|
||||
func (n NullDownloader) GetComments(commentable Commentable) ([]*Comment, bool, error) {
|
||||
return nil, false, &ErrNotSupported{Entity: "Comments"}
|
||||
return nil, false, ErrNotSupported{Entity: "Comments"}
|
||||
}
|
||||
|
||||
// GetAllComments returns paginated comments
|
||||
func (n NullDownloader) GetAllComments(page, perPage int) ([]*Comment, bool, error) {
|
||||
return nil, false, &ErrNotSupported{Entity: "AllComments"}
|
||||
return nil, false, ErrNotSupported{Entity: "AllComments"}
|
||||
}
|
||||
|
||||
// GetPullRequests returns pull requests according page and perPage
|
||||
func (n NullDownloader) GetPullRequests(page, perPage int) ([]*PullRequest, bool, error) {
|
||||
return nil, false, &ErrNotSupported{Entity: "PullRequests"}
|
||||
return nil, false, ErrNotSupported{Entity: "PullRequests"}
|
||||
}
|
||||
|
||||
// GetReviews returns pull requests review
|
||||
func (n NullDownloader) GetReviews(reviewable Reviewable) ([]*Review, error) {
|
||||
return nil, &ErrNotSupported{Entity: "Reviews"}
|
||||
return nil, ErrNotSupported{Entity: "Reviews"}
|
||||
}
|
||||
|
||||
// FormatCloneURL add authentication into remote URLs
|
||||
|
|
|
@ -27,7 +27,7 @@ func newAttachmentService() {
|
|||
|
||||
Attachment.Storage = getStorage("attachments", storageType, sec)
|
||||
|
||||
Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".docx,.gif,.gz,.jpeg,.jpg,.mp4,.log,.pdf,.png,.pptx,.txt,.xlsx,.zip")
|
||||
Attachment.AllowedTypes = sec.Key("ALLOWED_TYPES").MustString(".csv,.docx,.fodg,.fodp,.fods,.fodt,.gif,.gz,.jpeg,.jpg,.log,.md,.mov,.mp4,.odf,.odg,.odp,.ods,.odt,.pdf,.png,.pptx,.svg,.tgz,.txt,.webm,.xls,.xlsx,.zip")
|
||||
Attachment.MaxSize = sec.Key("MAX_SIZE").MustInt64(4)
|
||||
Attachment.MaxFiles = sec.Key("MAX_FILES").MustInt(5)
|
||||
Attachment.Enabled = sec.Key("ENABLED").MustBool(true)
|
||||
|
|
|
@ -26,7 +26,6 @@ var defaultI18nLangNames = []string{
|
|||
"fi-FI", "Suomi",
|
||||
"tr-TR", "Türkçe",
|
||||
"cs-CZ", "Čeština",
|
||||
"sr-SP", "Српски",
|
||||
"sv-SE", "Svenska",
|
||||
"ko-KR", "한국어",
|
||||
"el-GR", "Ελληνικά",
|
||||
|
|
|
@ -170,7 +170,7 @@ var (
|
|||
ServerMACs: []string{"hmac-sha2-256-etm@openssh.com", "hmac-sha2-256", "hmac-sha1"},
|
||||
KeygenPath: "ssh-keygen",
|
||||
MinimumKeySizeCheck: true,
|
||||
MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2048},
|
||||
MinimumKeySizes: map[string]int{"ed25519": 256, "ed25519-sk": 256, "ecdsa": 256, "ecdsa-sk": 256, "rsa": 2047},
|
||||
ServerHostKeys: []string{"ssh/gitea.rsa", "ssh/gogs.rsa"},
|
||||
AuthorizedKeysCommandTemplate: "{{.AppPath}} --config={{.CustomConf}} serv key-{{.Key.ID}}",
|
||||
PerWriteTimeout: PerWriteTimeout,
|
||||
|
@ -402,11 +402,6 @@ var (
|
|||
MaxTokenLength: math.MaxInt16,
|
||||
}
|
||||
|
||||
// FIXME: DEPRECATED to be removed in v1.18.0
|
||||
U2F = struct {
|
||||
AppID string
|
||||
}{}
|
||||
|
||||
// Metrics settings
|
||||
Metrics = struct {
|
||||
Enabled bool
|
||||
|
@ -1103,16 +1098,6 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
|||
for _, emoji := range UI.CustomEmojis {
|
||||
UI.CustomEmojisMap[emoji] = ":" + emoji + ":"
|
||||
}
|
||||
|
||||
// FIXME: DEPRECATED to be removed in v1.18.0
|
||||
U2F.AppID = strings.TrimSuffix(AppURL, "/")
|
||||
if Cfg.Section("U2F").HasKey("APP_ID") {
|
||||
log.Error("Deprecated setting `[U2F]` `APP_ID` present. This fallback will be removed in v1.18.0")
|
||||
U2F.AppID = Cfg.Section("U2F").Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/"))
|
||||
} else if Cfg.Section("u2f").HasKey("APP_ID") {
|
||||
log.Error("Deprecated setting `[u2]` `APP_ID` present. This fallback will be removed in v1.18.0")
|
||||
U2F.AppID = Cfg.Section("u2f").Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/"))
|
||||
}
|
||||
}
|
||||
|
||||
func parseAuthorizedPrincipalsAllow(values []string) ([]string, bool) {
|
||||
|
|
|
@ -105,7 +105,6 @@ func NewFuncMap() []template.FuncMap {
|
|||
"Str2html": Str2html,
|
||||
"TimeSince": timeutil.TimeSince,
|
||||
"TimeSinceUnix": timeutil.TimeSinceUnix,
|
||||
"RawTimeSince": timeutil.RawTimeSince,
|
||||
"FileSize": base.FileSize,
|
||||
"PrettyNumber": base.PrettyNumber,
|
||||
"JsPrettyNumber": JsPrettyNumber,
|
||||
|
@ -484,7 +483,6 @@ func NewTextFuncMap() []texttmpl.FuncMap {
|
|||
},
|
||||
"TimeSince": timeutil.TimeSince,
|
||||
"TimeSinceUnix": timeutil.TimeSinceUnix,
|
||||
"RawTimeSince": timeutil.RawTimeSince,
|
||||
"DateFmtLong": func(t time.Time) string {
|
||||
return t.Format(time.RFC1123Z)
|
||||
},
|
||||
|
|
|
@ -12,7 +12,7 @@ import (
|
|||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
)
|
||||
|
||||
// Seconds-based time units
|
||||
|
@ -29,146 +29,146 @@ func round(s float64) int64 {
|
|||
return int64(math.Round(s))
|
||||
}
|
||||
|
||||
func computeTimeDiffFloor(diff int64, lang string) (int64, string) {
|
||||
var diffStr string
|
||||
func computeTimeDiffFloor(diff int64, lang translation.Locale) (int64, string) {
|
||||
diffStr := ""
|
||||
switch {
|
||||
case diff <= 0:
|
||||
diff = 0
|
||||
diffStr = i18n.Tr(lang, "tool.now")
|
||||
diffStr = lang.Tr("tool.now")
|
||||
case diff < 2:
|
||||
diff = 0
|
||||
diffStr = i18n.Tr(lang, "tool.1s")
|
||||
diffStr = lang.Tr("tool.1s")
|
||||
case diff < 1*Minute:
|
||||
diffStr = i18n.Tr(lang, "tool.seconds", diff)
|
||||
diffStr = lang.Tr("tool.seconds", diff)
|
||||
diff = 0
|
||||
|
||||
case diff < 2*Minute:
|
||||
diff -= 1 * Minute
|
||||
diffStr = i18n.Tr(lang, "tool.1m")
|
||||
diffStr = lang.Tr("tool.1m")
|
||||
case diff < 1*Hour:
|
||||
diffStr = i18n.Tr(lang, "tool.minutes", diff/Minute)
|
||||
diffStr = lang.Tr("tool.minutes", diff/Minute)
|
||||
diff -= diff / Minute * Minute
|
||||
|
||||
case diff < 2*Hour:
|
||||
diff -= 1 * Hour
|
||||
diffStr = i18n.Tr(lang, "tool.1h")
|
||||
diffStr = lang.Tr("tool.1h")
|
||||
case diff < 1*Day:
|
||||
diffStr = i18n.Tr(lang, "tool.hours", diff/Hour)
|
||||
diffStr = lang.Tr("tool.hours", diff/Hour)
|
||||
diff -= diff / Hour * Hour
|
||||
|
||||
case diff < 2*Day:
|
||||
diff -= 1 * Day
|
||||
diffStr = i18n.Tr(lang, "tool.1d")
|
||||
diffStr = lang.Tr("tool.1d")
|
||||
case diff < 1*Week:
|
||||
diffStr = i18n.Tr(lang, "tool.days", diff/Day)
|
||||
diffStr = lang.Tr("tool.days", diff/Day)
|
||||
diff -= diff / Day * Day
|
||||
|
||||
case diff < 2*Week:
|
||||
diff -= 1 * Week
|
||||
diffStr = i18n.Tr(lang, "tool.1w")
|
||||
diffStr = lang.Tr("tool.1w")
|
||||
case diff < 1*Month:
|
||||
diffStr = i18n.Tr(lang, "tool.weeks", diff/Week)
|
||||
diffStr = lang.Tr("tool.weeks", diff/Week)
|
||||
diff -= diff / Week * Week
|
||||
|
||||
case diff < 2*Month:
|
||||
diff -= 1 * Month
|
||||
diffStr = i18n.Tr(lang, "tool.1mon")
|
||||
diffStr = lang.Tr("tool.1mon")
|
||||
case diff < 1*Year:
|
||||
diffStr = i18n.Tr(lang, "tool.months", diff/Month)
|
||||
diffStr = lang.Tr("tool.months", diff/Month)
|
||||
diff -= diff / Month * Month
|
||||
|
||||
case diff < 2*Year:
|
||||
diff -= 1 * Year
|
||||
diffStr = i18n.Tr(lang, "tool.1y")
|
||||
diffStr = lang.Tr("tool.1y")
|
||||
default:
|
||||
diffStr = i18n.Tr(lang, "tool.years", diff/Year)
|
||||
diffStr = lang.Tr("tool.years", diff/Year)
|
||||
diff -= (diff / Year) * Year
|
||||
}
|
||||
return diff, diffStr
|
||||
}
|
||||
|
||||
func computeTimeDiff(diff int64, lang string) (int64, string) {
|
||||
var diffStr string
|
||||
func computeTimeDiff(diff int64, lang translation.Locale) (int64, string) {
|
||||
diffStr := ""
|
||||
switch {
|
||||
case diff <= 0:
|
||||
diff = 0
|
||||
diffStr = i18n.Tr(lang, "tool.now")
|
||||
diffStr = lang.Tr("tool.now")
|
||||
case diff < 2:
|
||||
diff = 0
|
||||
diffStr = i18n.Tr(lang, "tool.1s")
|
||||
diffStr = lang.Tr("tool.1s")
|
||||
case diff < 1*Minute:
|
||||
diffStr = i18n.Tr(lang, "tool.seconds", diff)
|
||||
diffStr = lang.Tr("tool.seconds", diff)
|
||||
diff = 0
|
||||
|
||||
case diff < Minute+Minute/2:
|
||||
diff -= 1 * Minute
|
||||
diffStr = i18n.Tr(lang, "tool.1m")
|
||||
diffStr = lang.Tr("tool.1m")
|
||||
case diff < 1*Hour:
|
||||
minutes := round(float64(diff) / Minute)
|
||||
if minutes > 1 {
|
||||
diffStr = i18n.Tr(lang, "tool.minutes", minutes)
|
||||
diffStr = lang.Tr("tool.minutes", minutes)
|
||||
} else {
|
||||
diffStr = i18n.Tr(lang, "tool.1m")
|
||||
diffStr = lang.Tr("tool.1m")
|
||||
}
|
||||
diff -= diff / Minute * Minute
|
||||
|
||||
case diff < Hour+Hour/2:
|
||||
diff -= 1 * Hour
|
||||
diffStr = i18n.Tr(lang, "tool.1h")
|
||||
diffStr = lang.Tr("tool.1h")
|
||||
case diff < 1*Day:
|
||||
hours := round(float64(diff) / Hour)
|
||||
if hours > 1 {
|
||||
diffStr = i18n.Tr(lang, "tool.hours", hours)
|
||||
diffStr = lang.Tr("tool.hours", hours)
|
||||
} else {
|
||||
diffStr = i18n.Tr(lang, "tool.1h")
|
||||
diffStr = lang.Tr("tool.1h")
|
||||
}
|
||||
diff -= diff / Hour * Hour
|
||||
|
||||
case diff < Day+Day/2:
|
||||
diff -= 1 * Day
|
||||
diffStr = i18n.Tr(lang, "tool.1d")
|
||||
diffStr = lang.Tr("tool.1d")
|
||||
case diff < 1*Week:
|
||||
days := round(float64(diff) / Day)
|
||||
if days > 1 {
|
||||
diffStr = i18n.Tr(lang, "tool.days", days)
|
||||
diffStr = lang.Tr("tool.days", days)
|
||||
} else {
|
||||
diffStr = i18n.Tr(lang, "tool.1d")
|
||||
diffStr = lang.Tr("tool.1d")
|
||||
}
|
||||
diff -= diff / Day * Day
|
||||
|
||||
case diff < Week+Week/2:
|
||||
diff -= 1 * Week
|
||||
diffStr = i18n.Tr(lang, "tool.1w")
|
||||
diffStr = lang.Tr("tool.1w")
|
||||
case diff < 1*Month:
|
||||
weeks := round(float64(diff) / Week)
|
||||
if weeks > 1 {
|
||||
diffStr = i18n.Tr(lang, "tool.weeks", weeks)
|
||||
diffStr = lang.Tr("tool.weeks", weeks)
|
||||
} else {
|
||||
diffStr = i18n.Tr(lang, "tool.1w")
|
||||
diffStr = lang.Tr("tool.1w")
|
||||
}
|
||||
diff -= diff / Week * Week
|
||||
|
||||
case diff < 1*Month+Month/2:
|
||||
diff -= 1 * Month
|
||||
diffStr = i18n.Tr(lang, "tool.1mon")
|
||||
diffStr = lang.Tr("tool.1mon")
|
||||
case diff < 1*Year:
|
||||
months := round(float64(diff) / Month)
|
||||
if months > 1 {
|
||||
diffStr = i18n.Tr(lang, "tool.months", months)
|
||||
diffStr = lang.Tr("tool.months", months)
|
||||
} else {
|
||||
diffStr = i18n.Tr(lang, "tool.1mon")
|
||||
diffStr = lang.Tr("tool.1mon")
|
||||
}
|
||||
diff -= diff / Month * Month
|
||||
|
||||
case diff < Year+Year/2:
|
||||
diff -= 1 * Year
|
||||
diffStr = i18n.Tr(lang, "tool.1y")
|
||||
diffStr = lang.Tr("tool.1y")
|
||||
default:
|
||||
years := round(float64(diff) / Year)
|
||||
if years > 1 {
|
||||
diffStr = i18n.Tr(lang, "tool.years", years)
|
||||
diffStr = lang.Tr("tool.years", years)
|
||||
} else {
|
||||
diffStr = i18n.Tr(lang, "tool.1y")
|
||||
diffStr = lang.Tr("tool.1y")
|
||||
}
|
||||
diff -= (diff / Year) * Year
|
||||
}
|
||||
|
@ -177,24 +177,24 @@ func computeTimeDiff(diff int64, lang string) (int64, string) {
|
|||
|
||||
// MinutesToFriendly returns a user friendly string with number of minutes
|
||||
// converted to hours and minutes.
|
||||
func MinutesToFriendly(minutes int, lang string) string {
|
||||
func MinutesToFriendly(minutes int, lang translation.Locale) string {
|
||||
duration := time.Duration(minutes) * time.Minute
|
||||
return TimeSincePro(time.Now().Add(-duration), lang)
|
||||
}
|
||||
|
||||
// TimeSincePro calculates the time interval and generate full user-friendly string.
|
||||
func TimeSincePro(then time.Time, lang string) string {
|
||||
func TimeSincePro(then time.Time, lang translation.Locale) string {
|
||||
return timeSincePro(then, time.Now(), lang)
|
||||
}
|
||||
|
||||
func timeSincePro(then, now time.Time, lang string) string {
|
||||
func timeSincePro(then, now time.Time, lang translation.Locale) string {
|
||||
diff := now.Unix() - then.Unix()
|
||||
|
||||
if then.After(now) {
|
||||
return i18n.Tr(lang, "tool.future")
|
||||
return lang.Tr("tool.future")
|
||||
}
|
||||
if diff == 0 {
|
||||
return i18n.Tr(lang, "tool.now")
|
||||
return lang.Tr("tool.now")
|
||||
}
|
||||
|
||||
var timeStr, diffStr string
|
||||
|
@ -209,11 +209,11 @@ func timeSincePro(then, now time.Time, lang string) string {
|
|||
return strings.TrimPrefix(timeStr, ", ")
|
||||
}
|
||||
|
||||
func timeSince(then, now time.Time, lang string) string {
|
||||
func timeSince(then, now time.Time, lang translation.Locale) string {
|
||||
return timeSinceUnix(then.Unix(), now.Unix(), lang)
|
||||
}
|
||||
|
||||
func timeSinceUnix(then, now int64, lang string) string {
|
||||
func timeSinceUnix(then, now int64, lang translation.Locale) string {
|
||||
lbl := "tool.ago"
|
||||
diff := now - then
|
||||
if then > now {
|
||||
|
@ -221,36 +221,31 @@ func timeSinceUnix(then, now int64, lang string) string {
|
|||
diff = then - now
|
||||
}
|
||||
if diff <= 0 {
|
||||
return i18n.Tr(lang, "tool.now")
|
||||
return lang.Tr("tool.now")
|
||||
}
|
||||
|
||||
_, diffStr := computeTimeDiff(diff, lang)
|
||||
return i18n.Tr(lang, lbl, diffStr)
|
||||
}
|
||||
|
||||
// RawTimeSince retrieves i18n key of time since t
|
||||
func RawTimeSince(t time.Time, lang string) string {
|
||||
return timeSince(t, time.Now(), lang)
|
||||
return lang.Tr(lbl, diffStr)
|
||||
}
|
||||
|
||||
// TimeSince calculates the time interval and generate user-friendly string.
|
||||
func TimeSince(then time.Time, lang string) template.HTML {
|
||||
func TimeSince(then time.Time, lang translation.Locale) template.HTML {
|
||||
return htmlTimeSince(then, time.Now(), lang)
|
||||
}
|
||||
|
||||
func htmlTimeSince(then, now time.Time, lang string) template.HTML {
|
||||
func htmlTimeSince(then, now time.Time, lang translation.Locale) template.HTML {
|
||||
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`,
|
||||
then.In(setting.DefaultUILocation).Format(GetTimeFormat(lang)),
|
||||
then.In(setting.DefaultUILocation).Format(GetTimeFormat(lang.Language())),
|
||||
timeSince(then, now, lang)))
|
||||
}
|
||||
|
||||
// TimeSinceUnix calculates the time interval and generate user-friendly string.
|
||||
func TimeSinceUnix(then TimeStamp, lang string) template.HTML {
|
||||
func TimeSinceUnix(then TimeStamp, lang translation.Locale) template.HTML {
|
||||
return htmlTimeSinceUnix(then, TimeStamp(time.Now().Unix()), lang)
|
||||
}
|
||||
|
||||
func htmlTimeSinceUnix(then, now TimeStamp, lang string) template.HTML {
|
||||
func htmlTimeSinceUnix(then, now TimeStamp, lang translation.Locale) template.HTML {
|
||||
return template.HTML(fmt.Sprintf(`<span class="time-since" title="%s">%s</span>`,
|
||||
then.FormatInLocation(GetTimeFormat(lang), setting.DefaultUILocation),
|
||||
then.FormatInLocation(GetTimeFormat(lang.Language()), setting.DefaultUILocation),
|
||||
timeSinceUnix(int64(then), int64(now), lang)))
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
@ -42,16 +41,16 @@ func TestMain(m *testing.M) {
|
|||
}
|
||||
|
||||
func TestTimeSince(t *testing.T) {
|
||||
assert.Equal(t, "now", timeSince(BaseDate, BaseDate, "en"))
|
||||
assert.Equal(t, "now", timeSince(BaseDate, BaseDate, translation.NewLocale("en-US")))
|
||||
|
||||
// test that each diff in `diffs` yields the expected string
|
||||
test := func(expected string, diffs ...time.Duration) {
|
||||
t.Run(expected, func(t *testing.T) {
|
||||
for _, diff := range diffs {
|
||||
actual := timeSince(BaseDate, BaseDate.Add(diff), "en")
|
||||
assert.Equal(t, i18n.Tr("en", "tool.ago", expected), actual)
|
||||
actual = timeSince(BaseDate.Add(diff), BaseDate, "en")
|
||||
assert.Equal(t, i18n.Tr("en", "tool.from_now", expected), actual)
|
||||
actual := timeSince(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US"))
|
||||
assert.Equal(t, translation.NewLocale("en-US").Tr("tool.ago", expected), actual)
|
||||
actual = timeSince(BaseDate.Add(diff), BaseDate, translation.NewLocale("en-US"))
|
||||
assert.Equal(t, translation.NewLocale("en-US").Tr("tool.from_now", expected), actual)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -82,13 +81,13 @@ func TestTimeSince(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTimeSincePro(t *testing.T) {
|
||||
assert.Equal(t, "now", timeSincePro(BaseDate, BaseDate, "en"))
|
||||
assert.Equal(t, "now", timeSincePro(BaseDate, BaseDate, translation.NewLocale("en-US")))
|
||||
|
||||
// test that a difference of `diff` yields the expected string
|
||||
test := func(expected string, diff time.Duration) {
|
||||
actual := timeSincePro(BaseDate, BaseDate.Add(diff), "en")
|
||||
actual := timeSincePro(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US"))
|
||||
assert.Equal(t, expected, actual)
|
||||
assert.Equal(t, "future", timeSincePro(BaseDate.Add(diff), BaseDate, "en"))
|
||||
assert.Equal(t, "future", timeSincePro(BaseDate.Add(diff), BaseDate, translation.NewLocale("en-US")))
|
||||
}
|
||||
test("1 second", time.Second)
|
||||
test("2 seconds", 2*time.Second)
|
||||
|
@ -119,7 +118,7 @@ func TestHtmlTimeSince(t *testing.T) {
|
|||
setting.DefaultUILocation = time.UTC
|
||||
// test that `diff` yields a result containing `expected`
|
||||
test := func(expected string, diff time.Duration) {
|
||||
actual := htmlTimeSince(BaseDate, BaseDate.Add(diff), "en")
|
||||
actual := htmlTimeSince(BaseDate, BaseDate.Add(diff), translation.NewLocale("en-US"))
|
||||
assert.Contains(t, actual, `title="Sat Jan 1 00:00:00 UTC 2000"`)
|
||||
assert.Contains(t, actual, expected)
|
||||
}
|
||||
|
@ -138,7 +137,7 @@ func TestComputeTimeDiff(t *testing.T) {
|
|||
test := func(base int64, str string, offsets ...int64) {
|
||||
for _, offset := range offsets {
|
||||
t.Run(fmt.Sprintf("%s:%d", str, offset), func(t *testing.T) {
|
||||
diff, diffStr := computeTimeDiff(base+offset, "en")
|
||||
diff, diffStr := computeTimeDiff(base+offset, translation.NewLocale("en-US"))
|
||||
assert.Equal(t, offset, diff)
|
||||
assert.Equal(t, str, diffStr)
|
||||
})
|
||||
|
@ -171,7 +170,7 @@ func TestComputeTimeDiff(t *testing.T) {
|
|||
func TestMinutesToFriendly(t *testing.T) {
|
||||
// test that a number of minutes yields the expected string
|
||||
test := func(expected string, minutes int) {
|
||||
actual := MinutesToFriendly(minutes, "en")
|
||||
actual := MinutesToFriendly(minutes, translation.NewLocale("en-US"))
|
||||
assert.Equal(t, expected, actual)
|
||||
}
|
||||
test("1 minute", 1)
|
||||
|
|
|
@ -7,10 +7,13 @@ package i18n
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
@ -18,123 +21,278 @@ import (
|
|||
var (
|
||||
ErrLocaleAlreadyExist = errors.New("lang already exists")
|
||||
|
||||
DefaultLocales = NewLocaleStore()
|
||||
DefaultLocales = NewLocaleStore(true)
|
||||
)
|
||||
|
||||
type locale struct {
|
||||
// This mutex will be set if we have live-reload enabled (e.g. dev mode)
|
||||
reloadMu *sync.RWMutex
|
||||
|
||||
store *LocaleStore
|
||||
langName string
|
||||
langDesc string
|
||||
messages *ini.File
|
||||
|
||||
idxToMsgMap map[int]string // the map idx is generated by store's trKeyToIdxMap
|
||||
|
||||
sourceFileName string
|
||||
sourceFileInfo os.FileInfo
|
||||
lastReloadCheckTime time.Time
|
||||
}
|
||||
|
||||
type LocaleStore struct {
|
||||
// at the moment, all these fields are readonly after initialization
|
||||
langNames []string
|
||||
langDescs []string
|
||||
localeMap map[string]*locale
|
||||
// This mutex will be set if we have live-reload enabled (e.g. dev mode)
|
||||
reloadMu *sync.RWMutex
|
||||
|
||||
langNames []string
|
||||
langDescs []string
|
||||
localeMap map[string]*locale
|
||||
|
||||
// this needs to be locked when live-reloading
|
||||
trKeyToIdxMap map[string]int
|
||||
|
||||
defaultLang string
|
||||
}
|
||||
|
||||
func NewLocaleStore() *LocaleStore {
|
||||
return &LocaleStore{localeMap: make(map[string]*locale)}
|
||||
func NewLocaleStore(isProd bool) *LocaleStore {
|
||||
store := &LocaleStore{localeMap: make(map[string]*locale), trKeyToIdxMap: make(map[string]int)}
|
||||
if !isProd {
|
||||
store.reloadMu = &sync.RWMutex{}
|
||||
}
|
||||
return store
|
||||
}
|
||||
|
||||
// AddLocaleByIni adds locale by ini into the store
|
||||
func (ls *LocaleStore) AddLocaleByIni(langName, langDesc string, localeFile interface{}, otherLocaleFiles ...interface{}) error {
|
||||
if _, ok := ls.localeMap[langName]; ok {
|
||||
// if source is a string, then the file is loaded. In dev mode, this file will be checked for live-reloading
|
||||
// if source is a []byte, then the content is used
|
||||
// Note: this is not concurrent safe
|
||||
func (store *LocaleStore) AddLocaleByIni(langName, langDesc string, source interface{}) error {
|
||||
if _, ok := store.localeMap[langName]; ok {
|
||||
return ErrLocaleAlreadyExist
|
||||
}
|
||||
|
||||
l := &locale{store: store, langName: langName}
|
||||
if store.reloadMu != nil {
|
||||
l.reloadMu = &sync.RWMutex{}
|
||||
l.reloadMu.Lock() // Arguably this is not necessary as AddLocaleByIni isn't concurrent safe - but for consistency we do this
|
||||
defer l.reloadMu.Unlock()
|
||||
}
|
||||
|
||||
if fileName, ok := source.(string); ok {
|
||||
l.sourceFileName = fileName
|
||||
l.sourceFileInfo, _ = os.Stat(fileName) // live-reload only works for regular files. the error can be ignored
|
||||
}
|
||||
|
||||
var err error
|
||||
l.idxToMsgMap, err = store.readIniToIdxToMsgMap(source)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
store.langNames = append(store.langNames, langName)
|
||||
store.langDescs = append(store.langDescs, langDesc)
|
||||
|
||||
store.localeMap[l.langName] = l
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// readIniToIdxToMsgMap will read a provided ini and creates an idxToMsgMap
|
||||
func (store *LocaleStore) readIniToIdxToMsgMap(source interface{}) (map[int]string, error) {
|
||||
iniFile, err := ini.LoadSources(ini.LoadOptions{
|
||||
IgnoreInlineComment: true,
|
||||
UnescapeValueCommentSymbols: true,
|
||||
}, localeFile, otherLocaleFiles...)
|
||||
if err == nil {
|
||||
iniFile.BlockMode = false
|
||||
lc := &locale{store: ls, langName: langName, langDesc: langDesc, messages: iniFile}
|
||||
ls.langNames = append(ls.langNames, lc.langName)
|
||||
ls.langDescs = append(ls.langDescs, lc.langDesc)
|
||||
ls.localeMap[lc.langName] = lc
|
||||
}, source)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to load ini: %w", err)
|
||||
}
|
||||
return err
|
||||
iniFile.BlockMode = false
|
||||
|
||||
idxToMsgMap := make(map[int]string)
|
||||
|
||||
if store.reloadMu != nil {
|
||||
store.reloadMu.Lock()
|
||||
defer store.reloadMu.Unlock()
|
||||
}
|
||||
|
||||
for _, section := range iniFile.Sections() {
|
||||
for _, key := range section.Keys() {
|
||||
|
||||
var trKey string
|
||||
if section.Name() == "" || section.Name() == "DEFAULT" {
|
||||
trKey = key.Name()
|
||||
} else {
|
||||
trKey = section.Name() + "." + key.Name()
|
||||
}
|
||||
|
||||
// Instead of storing the key strings in multiple different maps we compute a idx which will act as numeric code for key
|
||||
// This reduces the size of the locale idxToMsgMaps
|
||||
idx, ok := store.trKeyToIdxMap[trKey]
|
||||
if !ok {
|
||||
idx = len(store.trKeyToIdxMap)
|
||||
store.trKeyToIdxMap[trKey] = idx
|
||||
}
|
||||
idxToMsgMap[idx] = key.Value()
|
||||
}
|
||||
}
|
||||
iniFile = nil
|
||||
return idxToMsgMap, nil
|
||||
}
|
||||
|
||||
func (ls *LocaleStore) HasLang(langName string) bool {
|
||||
_, ok := ls.localeMap[langName]
|
||||
func (store *LocaleStore) idxForTrKey(trKey string) (int, bool) {
|
||||
if store.reloadMu != nil {
|
||||
store.reloadMu.RLock()
|
||||
defer store.reloadMu.RUnlock()
|
||||
}
|
||||
idx, ok := store.trKeyToIdxMap[trKey]
|
||||
return idx, ok
|
||||
}
|
||||
|
||||
// HasLang reports if a language is available in the store
|
||||
func (store *LocaleStore) HasLang(langName string) bool {
|
||||
_, ok := store.localeMap[langName]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (ls *LocaleStore) ListLangNameDesc() (names, desc []string) {
|
||||
return ls.langNames, ls.langDescs
|
||||
// ListLangNameDesc reports if a language available in the store
|
||||
func (store *LocaleStore) ListLangNameDesc() (names, desc []string) {
|
||||
return store.langNames, store.langDescs
|
||||
}
|
||||
|
||||
// SetDefaultLang sets default language as a fallback
|
||||
func (ls *LocaleStore) SetDefaultLang(lang string) {
|
||||
ls.defaultLang = lang
|
||||
func (store *LocaleStore) SetDefaultLang(lang string) {
|
||||
store.defaultLang = lang
|
||||
}
|
||||
|
||||
// Tr translates content to target language. fall back to default language.
|
||||
func (ls *LocaleStore) Tr(lang, trKey string, trArgs ...interface{}) string {
|
||||
l, ok := ls.localeMap[lang]
|
||||
func (store *LocaleStore) Tr(lang, trKey string, trArgs ...interface{}) string {
|
||||
l, ok := store.localeMap[lang]
|
||||
if !ok {
|
||||
l, ok = ls.localeMap[ls.defaultLang]
|
||||
l, ok = store.localeMap[store.defaultLang]
|
||||
}
|
||||
|
||||
if ok {
|
||||
return l.Tr(trKey, trArgs...)
|
||||
}
|
||||
return trKey
|
||||
}
|
||||
|
||||
// Tr translates content to locale language. fall back to default language.
|
||||
func (l *locale) Tr(trKey string, trArgs ...interface{}) string {
|
||||
var section string
|
||||
|
||||
idx := strings.IndexByte(trKey, '.')
|
||||
if idx > 0 {
|
||||
section = trKey[:idx]
|
||||
trKey = trKey[idx+1:]
|
||||
// reloadIfNeeded will check if the locale needs to be reloaded
|
||||
// this function will assume that the l.reloadMu has been RLocked if it already exists
|
||||
func (l *locale) reloadIfNeeded() {
|
||||
if l.reloadMu == nil {
|
||||
return
|
||||
}
|
||||
|
||||
trMsg := trKey
|
||||
if trIni, err := l.messages.Section(section).GetKey(trKey); err == nil {
|
||||
trMsg = trIni.Value()
|
||||
} else if l.store.defaultLang != "" && l.langName != l.store.defaultLang {
|
||||
// try to fall back to default
|
||||
if defaultLocale, ok := l.store.localeMap[l.store.defaultLang]; ok {
|
||||
if trIni, err = defaultLocale.messages.Section(section).GetKey(trKey); err == nil {
|
||||
trMsg = trIni.Value()
|
||||
}
|
||||
}
|
||||
now := time.Now()
|
||||
if now.Sub(l.lastReloadCheckTime) < time.Second || l.sourceFileInfo == nil || l.sourceFileName == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if len(trArgs) > 0 {
|
||||
fmtArgs := make([]interface{}, 0, len(trArgs))
|
||||
for _, arg := range trArgs {
|
||||
val := reflect.ValueOf(arg)
|
||||
if val.Kind() == reflect.Slice {
|
||||
// before, it can accept Tr(lang, key, a, [b, c], d, [e, f]) as Sprintf(msg, a, b, c, d, e, f), it's an unstable behavior
|
||||
// now, we restrict the strange behavior and only support:
|
||||
// 1. Tr(lang, key, [slice-items]) as Sprintf(msg, items...)
|
||||
// 2. Tr(lang, key, args...) as Sprintf(msg, args...)
|
||||
if len(trArgs) == 1 {
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
fmtArgs = append(fmtArgs, val.Index(i).Interface())
|
||||
}
|
||||
} else {
|
||||
log.Error("the args for i18n shouldn't contain uncertain slices, key=%q, args=%v", trKey, trArgs)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
fmtArgs = append(fmtArgs, arg)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf(trMsg, fmtArgs...)
|
||||
l.reloadMu.RUnlock()
|
||||
l.reloadMu.Lock() // (NOTE: a pre-emption can occur between these two locks so we need to recheck)
|
||||
defer l.reloadMu.RLock()
|
||||
defer l.reloadMu.Unlock()
|
||||
|
||||
if now.Sub(l.lastReloadCheckTime) < time.Second || l.sourceFileInfo == nil || l.sourceFileName == "" {
|
||||
return
|
||||
}
|
||||
return trMsg
|
||||
|
||||
l.lastReloadCheckTime = now
|
||||
sourceFileInfo, err := os.Stat(l.sourceFileName)
|
||||
if err != nil || sourceFileInfo.ModTime().Equal(l.sourceFileInfo.ModTime()) {
|
||||
return
|
||||
}
|
||||
|
||||
idxToMsgMap, err := l.store.readIniToIdxToMsgMap(l.sourceFileName)
|
||||
if err == nil {
|
||||
l.idxToMsgMap = idxToMsgMap
|
||||
} else {
|
||||
log.Error("Unable to live-reload the locale file %q, err: %v", l.sourceFileName, err)
|
||||
}
|
||||
|
||||
// We will set the sourceFileInfo to this file to prevent repeated attempts to re-load this broken file
|
||||
l.sourceFileInfo = sourceFileInfo
|
||||
}
|
||||
|
||||
func ResetDefaultLocales() {
|
||||
DefaultLocales = NewLocaleStore()
|
||||
// Tr translates content to locale language. fall back to default language.
|
||||
func (l *locale) Tr(trKey string, trArgs ...interface{}) string {
|
||||
if l.reloadMu != nil {
|
||||
l.reloadMu.RLock()
|
||||
defer l.reloadMu.RUnlock()
|
||||
l.reloadIfNeeded()
|
||||
}
|
||||
|
||||
msg, _ := l.tryTr(trKey, trArgs...)
|
||||
return msg
|
||||
}
|
||||
|
||||
func (l *locale) tryTr(trKey string, trArgs ...interface{}) (msg string, found bool) {
|
||||
trMsg := trKey
|
||||
|
||||
// convert the provided trKey to a common idx from the store
|
||||
idx, ok := l.store.idxForTrKey(trKey)
|
||||
|
||||
if ok {
|
||||
if msg, found = l.idxToMsgMap[idx]; found {
|
||||
trMsg = msg // use the translation that we have found
|
||||
} else if l.langName != l.store.defaultLang {
|
||||
// No translation available in our current language... fallback to the default language
|
||||
|
||||
// Attempt to get the default language from the locale store
|
||||
if def, ok := l.store.localeMap[l.store.defaultLang]; ok {
|
||||
|
||||
if def.reloadMu != nil {
|
||||
def.reloadMu.RLock()
|
||||
def.reloadIfNeeded()
|
||||
}
|
||||
if msg, found = def.idxToMsgMap[idx]; found {
|
||||
trMsg = msg // use the translation that we have found
|
||||
}
|
||||
if def.reloadMu != nil {
|
||||
def.reloadMu.RUnlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !found && !setting.IsProd {
|
||||
log.Error("missing i18n translation key: %q", trKey)
|
||||
}
|
||||
|
||||
if len(trArgs) == 0 {
|
||||
return trMsg, found
|
||||
}
|
||||
|
||||
fmtArgs := make([]interface{}, 0, len(trArgs))
|
||||
for _, arg := range trArgs {
|
||||
val := reflect.ValueOf(arg)
|
||||
if val.Kind() == reflect.Slice {
|
||||
// Previously, we would accept Tr(lang, key, a, [b, c], d, [e, f]) as Sprintf(msg, a, b, c, d, e, f)
|
||||
// but this is an unstable behavior.
|
||||
//
|
||||
// So we restrict the accepted arguments to either:
|
||||
//
|
||||
// 1. Tr(lang, key, [slice-items]) as Sprintf(msg, items...)
|
||||
// 2. Tr(lang, key, args...) as Sprintf(msg, args...)
|
||||
if len(trArgs) == 1 {
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
fmtArgs = append(fmtArgs, val.Index(i).Interface())
|
||||
}
|
||||
} else {
|
||||
log.Error("the args for i18n shouldn't contain uncertain slices, key=%q, args=%v", trKey, trArgs)
|
||||
break
|
||||
}
|
||||
} else {
|
||||
fmtArgs = append(fmtArgs, arg)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Sprintf(trMsg, fmtArgs...), found
|
||||
}
|
||||
|
||||
// ResetDefaultLocales resets the current default locales
|
||||
// NOTE: this is not synchronized
|
||||
func ResetDefaultLocales(isProd bool) {
|
||||
DefaultLocales = NewLocaleStore(isProd)
|
||||
}
|
||||
|
||||
// Tr use default locales to translate content to target language.
|
||||
|
|
|
@ -27,30 +27,36 @@ fmt = %[2]s %[1]s
|
|||
sub = Changed Sub String
|
||||
`)
|
||||
|
||||
ls := NewLocaleStore()
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1))
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2))
|
||||
ls.SetDefaultLang("lang1")
|
||||
for _, isProd := range []bool{true, false} {
|
||||
ls := NewLocaleStore(isProd)
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang1", "Lang1", testData1))
|
||||
assert.NoError(t, ls.AddLocaleByIni("lang2", "Lang2", testData2))
|
||||
ls.SetDefaultLang("lang1")
|
||||
|
||||
result := ls.Tr("lang1", "fmt", "a", "b")
|
||||
assert.Equal(t, "a b", result)
|
||||
result := ls.Tr("lang1", "fmt", "a", "b")
|
||||
assert.Equal(t, "a b", result)
|
||||
|
||||
result = ls.Tr("lang2", "fmt", "a", "b")
|
||||
assert.Equal(t, "b a", result)
|
||||
result = ls.Tr("lang2", "fmt", "a", "b")
|
||||
assert.Equal(t, "b a", result)
|
||||
|
||||
result = ls.Tr("lang1", "section.sub")
|
||||
assert.Equal(t, "Sub String", result)
|
||||
result = ls.Tr("lang1", "section.sub")
|
||||
assert.Equal(t, "Sub String", result)
|
||||
|
||||
result = ls.Tr("lang2", "section.sub")
|
||||
assert.Equal(t, "Changed Sub String", result)
|
||||
result = ls.Tr("lang2", "section.sub")
|
||||
assert.Equal(t, "Changed Sub String", result)
|
||||
|
||||
result = ls.Tr("", ".dot.name")
|
||||
assert.Equal(t, "Dot Name", result)
|
||||
result = ls.Tr("", ".dot.name")
|
||||
assert.Equal(t, "Dot Name", result)
|
||||
|
||||
result = ls.Tr("lang2", "section.mixed")
|
||||
assert.Equal(t, `test value; <span style="color: red; background: none;">more text</span>`, result)
|
||||
result = ls.Tr("lang2", "section.mixed")
|
||||
assert.Equal(t, `test value; <span style="color: red; background: none;">more text</span>`, result)
|
||||
|
||||
langs, descs := ls.ListLangNameDesc()
|
||||
assert.Equal(t, []string{"lang1", "lang2"}, langs)
|
||||
assert.Equal(t, []string{"Lang1", "Lang2"}, descs)
|
||||
langs, descs := ls.ListLangNameDesc()
|
||||
assert.Equal(t, []string{"lang1", "lang2"}, langs)
|
||||
assert.Equal(t, []string{"Lang1", "Lang2"}, descs)
|
||||
|
||||
result, found := ls.localeMap["lang1"].tryTr("no-such")
|
||||
assert.Equal(t, "no-such", result)
|
||||
assert.False(t, found)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package translation
|
||||
|
||||
import (
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
|
@ -12,6 +13,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/options"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
@ -40,31 +42,35 @@ func AllLangs() []*LangType {
|
|||
return allLangs
|
||||
}
|
||||
|
||||
// TryTr tries to do the translation, if no translation, it returns (format, false)
|
||||
func TryTr(lang, format string, args ...interface{}) (string, bool) {
|
||||
s := i18n.Tr(lang, format, args...)
|
||||
// now the i18n library is not good enough and we can only use this hacky method to detect whether the transaction exists
|
||||
idx := strings.IndexByte(format, '.')
|
||||
defaultText := format
|
||||
if idx > 0 {
|
||||
defaultText = format[idx+1:]
|
||||
}
|
||||
return s, s != defaultText
|
||||
}
|
||||
|
||||
// InitLocales loads the locales
|
||||
func InitLocales() {
|
||||
i18n.ResetDefaultLocales()
|
||||
i18n.ResetDefaultLocales(setting.IsProd)
|
||||
localeNames, err := options.Dir("locale")
|
||||
if err != nil {
|
||||
log.Fatal("Failed to list locale files: %v", err)
|
||||
}
|
||||
|
||||
localFiles := make(map[string][]byte, len(localeNames))
|
||||
localFiles := make(map[string]interface{}, len(localeNames))
|
||||
for _, name := range localeNames {
|
||||
localFiles[name], err = options.Locale(name)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load %s locale file. %v", name, err)
|
||||
if options.IsDynamic() {
|
||||
// Try to check if CustomPath has the file, otherwise fallback to StaticRootPath
|
||||
value := path.Join(setting.CustomPath, "options/locale", name)
|
||||
|
||||
isFile, err := util.IsFile(value)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load %s locale file. %v", name, err)
|
||||
}
|
||||
|
||||
if isFile {
|
||||
localFiles[name] = value
|
||||
} else {
|
||||
localFiles[name] = path.Join(setting.StaticRootPath, "options/locale", name)
|
||||
}
|
||||
} else {
|
||||
localFiles[name], err = options.Locale(name)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to load %s locale file. %v", name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,6 +82,7 @@ func InitLocales() {
|
|||
matcher = language.NewMatcher(supportedTags)
|
||||
for i := range setting.Names {
|
||||
key := "locale_" + setting.Langs[i] + ".ini"
|
||||
|
||||
if err = i18n.DefaultLocales.AddLocaleByIni(setting.Langs[i], setting.Names[i], localFiles[key]); err != nil {
|
||||
log.Error("Failed to set messages to %s: %v", setting.Langs[i], err)
|
||||
}
|
||||
|
@ -132,16 +139,7 @@ func (l *locale) Language() string {
|
|||
|
||||
// Tr translates content to target language.
|
||||
func (l *locale) Tr(format string, args ...interface{}) string {
|
||||
if setting.IsProd {
|
||||
return i18n.Tr(l.Lang, format, args...)
|
||||
}
|
||||
|
||||
// in development, we should show an error if a translation key is missing
|
||||
s, ok := TryTr(l.Lang, format, args...)
|
||||
if !ok {
|
||||
log.Error("missing i18n translation key: %q", format)
|
||||
}
|
||||
return s
|
||||
return i18n.Tr(l.Lang, format, args...)
|
||||
}
|
||||
|
||||
// Language specific rules for translating plural texts
|
||||
|
|
|
@ -46,7 +46,6 @@ webauthn_error_unable_to_process=Server nemohl zpracovat váš požadavek.
|
|||
webauthn_error_duplicated=Zabezpečovací klíč není pro tento požadavek povolen. Prosím ujistěte se, zda klíč není již registrován.
|
||||
webauthn_error_empty=Musíte nastavit název tohoto klíče.
|
||||
webauthn_error_timeout=Požadavek vypršel dříve, než se podařilo přečíst váš klíč. Znovu načtěte tuto stránku a akci opakujte.
|
||||
webauthn_u2f_deprecated=Klíč: „%s“ autentifikuje pomocí zastaralého procesu U2F. Měli byste znovu zaregistrovat tento klíč a zrušit starou registraci.
|
||||
webauthn_reload=Znovu načíst
|
||||
|
||||
repository=Repozitář
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=Der Server konnte deine Anfrage nicht bearbeite
|
|||
webauthn_error_duplicated=Für diese Anfrage ist der Sicherheitsschlüssel nicht erlaubt. Bitte stell sicher, dass er nicht bereits registriert ist.
|
||||
webauthn_error_empty=Du musst einen Namen für diesen Schlüssel festlegen.
|
||||
webauthn_error_timeout=Das Zeitlimit wurde erreicht, bevor dein Schlüssel gelesen werden konnte. Bitte lade die Seite erneut.
|
||||
webauthn_u2f_deprecated=Der Schlüssel: '%s' authentifiziert sich über den veralteten U2F-Prozess. Bitte registriere den Schlüssel neu und lösche die alte Registrierung.
|
||||
webauthn_reload=Neu laden
|
||||
|
||||
repository=Repository
|
||||
|
@ -1516,7 +1515,7 @@ pulls.tab_conversation=Diskussion
|
|||
pulls.tab_commits=Commits
|
||||
pulls.tab_files=Geänderte Dateien
|
||||
pulls.reopen_to_merge=Bitte diesen Pull-Request wieder öffnen, um zu mergen.
|
||||
pulls.cant_reopen_deleted_branch=Dieser Pull-Request kann nicht wieder geöffnet werden, da die Branche bereits gelöscht wurde.
|
||||
pulls.cant_reopen_deleted_branch=Dieser Pull-Request kann nicht wieder geöffnet werden, da die Branch bereits gelöscht wurde.
|
||||
pulls.merged=Zusammengeführt
|
||||
pulls.merged_as=Der Pull Request wurde als <a rel="nofollow" class="ui sha" href="%[1]s"><code>%[2]s</code></a> gemergt.
|
||||
pulls.manually_merged=Manuell gemergt
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=Ο διακομιστής δεν μπόρεσε
|
|||
webauthn_error_duplicated=Το κλειδί ασφαλείας δεν επιτρέπεται για αυτό το αίτημα. Βεβαιωθείτε ότι το κλειδί δεν έχει ήδη καταχωρηθεί.
|
||||
webauthn_error_empty=Πρέπει να ορίσετε ένα όνομα για αυτό το κλειδί.
|
||||
webauthn_error_timeout=Το χρονικό όριο έφτασε πριν το κλειδί να διαβαστεί. Παρακαλώ ανανεώστε τη σελίδα και προσπαθήστε ξανά.
|
||||
webauthn_u2f_deprecated=Το κλειδί: '%s' πιστοποιεί χρησιμοποιώντας το παρωχημένο πρωτόκολλο U2F. Θα πρέπει να καταχωρήσετε ξανά αυτό το κλειδί και να καταργήσετε την παλιά εγγραφή.
|
||||
webauthn_reload=Ανανέωση
|
||||
|
||||
repository=Αποθετήριο
|
||||
|
@ -1276,7 +1275,7 @@ issues.filter_sort=Ταξινόμηση
|
|||
issues.filter_sort.latest=Νεότερα
|
||||
issues.filter_sort.oldest=Παλαιότερα
|
||||
issues.filter_sort.recentupdate=Ενημερώθηκαν πρόσφατα
|
||||
issues.filter_sort.leastupdate=Λιγότερο πρόσφατα ανανεωμένο
|
||||
issues.filter_sort.leastupdate=Ενημερώθηκαν παλαιότερα
|
||||
issues.filter_sort.mostcomment=Περισσότερο σχολιασμένα
|
||||
issues.filter_sort.leastcomment=Λιγότερο σχολιασμένα
|
||||
issues.filter_sort.nearduedate=Πλησιέστερη παράδοση
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process = The server could not process your request.
|
|||
webauthn_error_duplicated = The security key is not permitted for this request. Please make sure that the key is not already registered.
|
||||
webauthn_error_empty = You must set a name for this key.
|
||||
webauthn_error_timeout = Timeout reached before your key could be read. Please reload this page and retry.
|
||||
webauthn_u2f_deprecated = The key: '%s' authenticates using the deprecated U2F process. You should re-register this key and remove the old registration.
|
||||
webauthn_reload = Reload
|
||||
|
||||
repository = Repository
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=El servidor no pudo procesar su solicitud.
|
|||
webauthn_error_duplicated=La clave de seguridad no está permitida para esta solicitud. Por favor, asegúrese de que la clave no está ya registrada.
|
||||
webauthn_error_empty=Debe establecer un nombre para esta clave.
|
||||
webauthn_error_timeout=Tiempo de espera máximo alcanzado antes de que su clave pudiese ser leída. Por favor, cargue la página y vuelva a intentarlo.
|
||||
webauthn_u2f_deprecated=La clave: '%s' se autentifica usando el proceso U2F obsoleto. Debe volver a registrar esta clave y eliminar el registro antiguo.
|
||||
webauthn_reload=Recargar
|
||||
|
||||
repository=Repositorio
|
||||
|
@ -1610,6 +1609,8 @@ pulls.auto_merge_canceled_schedule=Fusión automaticá estaba cancellada para es
|
|||
pulls.auto_merge_newly_scheduled_comment=`programó este Pull Request para fusionar automática cuando todas las comprobaciones tengan éxito %[1]s`
|
||||
pulls.auto_merge_canceled_schedule_comment=`canceló la fusión automática de este Pull Request %[1]s`
|
||||
|
||||
pulls.delete.title=¿Borrar este pull request?
|
||||
pulls.delete.text=¿Realmente quieres eliminar esta pull request? (Esto eliminará permanentemente todo el contenido. Considera cerrarlo si simplemente deseas archivarlo)
|
||||
|
||||
milestones.new=Nuevo hito
|
||||
milestones.closed=Cerrada %s
|
||||
|
|
|
@ -46,7 +46,6 @@ webauthn_error_unable_to_process=Netþjónninn gat ekki ráðið við beiðni þ
|
|||
webauthn_error_duplicated=Öryggislykillinn er ekki leyfður fyrir þessa beiðni. Gakktu úr skugga um að lykillinn sé ekki þegar skráður.
|
||||
webauthn_error_empty=Þú verður að setja nafn fyrir þennan lykil.
|
||||
webauthn_error_timeout=Tímamörk náð áður en hægt var að lesa lykilinn þinn. Vinsamlegast endurhlaðið þessa síðu og reyndu aftur.
|
||||
webauthn_u2f_deprecated=Lykillinn: „%s“ auðkennir með því að nota úrelta U2F aðferð. Þú ættir að endurskrá þennan lykil og fjarlægja gömlu skráninguna.
|
||||
webauthn_reload=Endurhlaða
|
||||
|
||||
repository=Hugbúnaðarsafn
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=サーバーがリクエストを処理でき
|
|||
webauthn_error_duplicated=このリクエストに対しては、許可されていないセキュリティキーです。 キーが未登録であることを確認してください。
|
||||
webauthn_error_empty=このキーに名前を設定する必要があります。
|
||||
webauthn_error_timeout=キーを読み取る前にタイムアウトになりました。 このページをリロードしてもう一度やり直してください。
|
||||
webauthn_u2f_deprecated=キー: '%s' は非推奨のU2Fプロセスを使用して認証しています。このキーを再登録して古い登録を削除したほうが良いでしょう。
|
||||
webauthn_reload=リロード
|
||||
|
||||
repository=リポジトリ
|
||||
|
@ -1610,6 +1609,8 @@ pulls.auto_merge_canceled_schedule=このプルリクエストの自動マージ
|
|||
pulls.auto_merge_newly_scheduled_comment=`が、すべてのチェックが成功すると自動マージを行うよう、このプルリクエストをスケジュール %[1]s`
|
||||
pulls.auto_merge_canceled_schedule_comment=`が、すべてのチェックが成功したときのプルリクエストの自動マージをキャンセル %[1]s`
|
||||
|
||||
pulls.delete.title=このプルリクエストを削除しますか?
|
||||
pulls.delete.text=本当にこのプルリクエストを削除しますか? (これはすべてのコンテンツを完全に削除します。 保存しておきたい場合は、代わりにクローズすることを検討してください)
|
||||
|
||||
milestones.new=新しいマイルストーン
|
||||
milestones.closed=%s にクローズ
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=Serveris nevar apstrādāt Jūsu pieprasījumu.
|
|||
webauthn_error_duplicated=Drošības atslēga nav atļauta šim pieprasījumam. Pārliecinieties, ka šī atslēga jau nav reģistrēta.
|
||||
webauthn_error_empty=Norādiet atslēgas nosaukumu.
|
||||
webauthn_error_timeout=Iestājusies noildze, mēģinot, nolasīt atslēgu. Pārlādējiet lapu un mēģiniet vēlreiz.
|
||||
webauthn_u2f_deprecated=Atslēga '%s' izmanto novecojušu U2F procesu. Noņemiet iepriekšējo reģistrāciju un veiciet reģistrācijas procesu no jauna.
|
||||
webauthn_reload=Pārlādēt
|
||||
|
||||
repository=Repozitorijs
|
||||
|
|
|
@ -46,7 +46,6 @@ webauthn_error_unable_to_process=Serwer nie mógł obsłużyć Twojego żądania
|
|||
webauthn_error_duplicated=Klucz bezpieczeństwa nie jest dozwolony dla tego żądania. Upewnij się, że klucz nie jest już zarejestrowany.
|
||||
webauthn_error_empty=Musisz ustawić nazwę dla tego klucza.
|
||||
webauthn_error_timeout=Osiągnięto limit czasu zanim Twój klucz może zostać odczytany. Odśwież stronę i spróbuj ponownie.
|
||||
webauthn_u2f_deprecated=Klucz '%s' uwierzytelnia przy użyciu przestarzałego procesu U2F. Powinieneś ponownie zarejestrować ten klucz i usunąć starą rejestrację.
|
||||
webauthn_reload=Odśwież
|
||||
|
||||
repository=Repozytorium
|
||||
|
|
|
@ -2,6 +2,7 @@ home=Inicio
|
|||
dashboard=Painel
|
||||
explore=Explorar
|
||||
help=Ajuda
|
||||
logo=Logotipo
|
||||
sign_in=Acessar
|
||||
sign_in_with=Acessar com
|
||||
sign_out=Sair
|
||||
|
@ -46,7 +47,6 @@ webauthn_error_unable_to_process=O servidor não pôde processar sua solicitaç
|
|||
webauthn_error_duplicated=A chave de segurança não é permitida para esta solicitação. Por favor, certifique-se que a chave já não está registrada.
|
||||
webauthn_error_empty=Você deve definir um nome para esta chave.
|
||||
webauthn_error_timeout=Tempo limite atingido antes de sua chave poder ser lida. Por favor, recarregue esta página e tente novamente.
|
||||
webauthn_u2f_deprecated=A chave: '%s' autentica utilizando o processo U2F descontinuado. Você deve registrar novamente esta chave e remover o registro antigo.
|
||||
webauthn_reload=Recarregar
|
||||
|
||||
repository=Repositório
|
||||
|
@ -442,6 +442,7 @@ size_error=`deve ser do tamanho %s.`
|
|||
min_size_error=` deve conter pelo menos %s caracteres.`
|
||||
max_size_error=` deve conter no máximo %s caracteres.`
|
||||
email_error=` não é um endereço de e-mail válido.`
|
||||
url_error=`'%s' não é uma URL válida.`
|
||||
include_error=` deve conter '%s'.`
|
||||
glob_pattern_error=` padrão glob é inválido: %s.`
|
||||
regex_pattern_error=` o regex é inválido: %s.`
|
||||
|
@ -715,6 +716,9 @@ generate_token_success=Seu novo token foi gerado. Copie-o agora, pois ele não s
|
|||
generate_token_name_duplicate=<strong>%s</strong> já foi usado como um nome de aplicativo. Por favor, use outro.
|
||||
delete_token=Excluir
|
||||
access_token_deletion=Excluir token de acesso
|
||||
access_token_deletion_cancel_action=Cancelar
|
||||
access_token_deletion_confirm_action=Excluir
|
||||
access_token_deletion_desc=A exclusão de um token revoga o acesso à sua conta para aplicativos que o usam. Continuar?
|
||||
delete_token_success=O token foi excluído. Os aplicativos que o utilizam já não têm acesso à sua conta.
|
||||
|
||||
manage_oauth2_applications=Gerenciar aplicativos OAuth2
|
||||
|
@ -1487,6 +1491,7 @@ pulls.new=Novo pull request
|
|||
pulls.view=Ver Pull Request
|
||||
pulls.compare_changes=Novo pull request
|
||||
pulls.allow_edits_from_maintainers=Permitir edições de mantenedores
|
||||
pulls.allow_edits_from_maintainers_err=Falha na atualização
|
||||
pulls.compare_changes_desc=Selecione o branch de destino (push) e o branch de origem (pull) para o merge.
|
||||
pulls.has_viewed_file=Visto
|
||||
pulls.has_changed_since_last_review=Alterado desde a última revisão
|
||||
|
@ -1590,6 +1595,7 @@ pulls.merge_instruction_hint=`Você também pode ver as <a class="show-instructi
|
|||
pulls.merge_instruction_step1_desc=No repositório do seu projeto, crie um novo branch e teste as alterações.
|
||||
pulls.merge_instruction_step2_desc=Faça merge das alterações e atualize no Gitea.
|
||||
|
||||
pulls.auto_merge_button_when_succeed=(Quando a verificação for bem-sucedida)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=O servidor não conseguiu processar o seu pedid
|
|||
webauthn_error_duplicated=A chave de segurança não é permitida neste pedido. Certifique-se de que a chave não está já registada.
|
||||
webauthn_error_empty=Você tem que definir um nome para esta chave.
|
||||
webauthn_error_timeout=O tempo limite foi atingido antes que a sua chave pudesse ser lida. Recarregue esta página e tente novamente.
|
||||
webauthn_u2f_deprecated=A chave: '%s' autentica usando o processo U2F, mas este foi descontinuado. Você deveria registar novamente esta chave e remover o registo antigo.
|
||||
webauthn_reload=Recarregar
|
||||
|
||||
repository=Repositório
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=服务器无法处理您的请求。
|
|||
webauthn_error_duplicated=此安全密钥未被许可用于这个请求。请确保该密钥尚未注册。
|
||||
webauthn_error_empty=您必须为此密钥设置一个名称。
|
||||
webauthn_error_timeout=未能在允许的时限内读取密钥。请重新加载此页面并重试。
|
||||
webauthn_u2f_deprecated=密钥 '%s' 使用的是已经废弃的 U2F 进行身份验证。您应该重新注册此密钥并删除旧的注册。
|
||||
webauthn_reload=重新加载
|
||||
|
||||
repository=仓库
|
||||
|
|
|
@ -47,7 +47,6 @@ webauthn_error_unable_to_process=伺服器無法執行您的請求。
|
|||
webauthn_error_duplicated=此請求不允許使用這個安全金鑰。請確保該金鑰尚未註冊。
|
||||
webauthn_error_empty=您必須命名此金鑰。
|
||||
webauthn_error_timeout=在成功讀取金鑰之前已逾時,請重新載入此頁面並重試。
|
||||
webauthn_u2f_deprecated=「%s」金鑰使用已廢棄的 U2F 流程進行驗證。您應該重新註冊此金鑰並將先前註冊的移除。
|
||||
webauthn_reload=重新載入
|
||||
|
||||
repository=儲存庫
|
||||
|
|
30
package-lock.json
generated
30
package-lock.json
generated
|
@ -22,7 +22,7 @@
|
|||
"less": "4.1.2",
|
||||
"less-loader": "11.0.0",
|
||||
"license-checker-webpack-plugin": "0.2.1",
|
||||
"mermaid": "9.1.1",
|
||||
"mermaid": "9.1.2",
|
||||
"mini-css-extract-plugin": "2.6.0",
|
||||
"monaco-editor": "0.33.0",
|
||||
"monaco-editor-webpack-plugin": "7.0.1",
|
||||
|
@ -3833,9 +3833,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.6.tgz",
|
||||
"integrity": "sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg=="
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.8.tgz",
|
||||
"integrity": "sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw=="
|
||||
},
|
||||
"node_modules/domutils": {
|
||||
"version": "2.8.0",
|
||||
|
@ -7741,15 +7741,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/mermaid": {
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.1.tgz",
|
||||
"integrity": "sha512-2RVD+WkzZ4VDyO9gQvQAuQ/ux2gLigJtKDTlbwjYqOR/NwsVzTSfGm/kx648/qWJsg6Sv04tE9BWCO8s6a+pFA==",
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.2.tgz",
|
||||
"integrity": "sha512-RVf3hBKqiMfyORHboCaEjOAK1TomLO50hYRPvlTrZCXlCniM5pRpe8UlkHBjjpaLtioZnbdYv/vEVj7iKnwkJQ==",
|
||||
"dependencies": {
|
||||
"@braintree/sanitize-url": "^6.0.0",
|
||||
"d3": "^7.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"dompurify": "2.3.6",
|
||||
"dompurify": "2.3.8",
|
||||
"graphlib": "^2.1.8",
|
||||
"khroma": "^2.0.0",
|
||||
"moment-mini": "^2.24.0",
|
||||
|
@ -13815,9 +13815,9 @@
|
|||
}
|
||||
},
|
||||
"dompurify": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.6.tgz",
|
||||
"integrity": "sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg=="
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.8.tgz",
|
||||
"integrity": "sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw=="
|
||||
},
|
||||
"domutils": {
|
||||
"version": "2.8.0",
|
||||
|
@ -16860,15 +16860,15 @@
|
|||
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
|
||||
},
|
||||
"mermaid": {
|
||||
"version": "9.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.1.tgz",
|
||||
"integrity": "sha512-2RVD+WkzZ4VDyO9gQvQAuQ/ux2gLigJtKDTlbwjYqOR/NwsVzTSfGm/kx648/qWJsg6Sv04tE9BWCO8s6a+pFA==",
|
||||
"version": "9.1.2",
|
||||
"resolved": "https://registry.npmjs.org/mermaid/-/mermaid-9.1.2.tgz",
|
||||
"integrity": "sha512-RVf3hBKqiMfyORHboCaEjOAK1TomLO50hYRPvlTrZCXlCniM5pRpe8UlkHBjjpaLtioZnbdYv/vEVj7iKnwkJQ==",
|
||||
"requires": {
|
||||
"@braintree/sanitize-url": "^6.0.0",
|
||||
"d3": "^7.0.0",
|
||||
"dagre": "^0.8.5",
|
||||
"dagre-d3": "^0.6.4",
|
||||
"dompurify": "2.3.6",
|
||||
"dompurify": "2.3.8",
|
||||
"graphlib": "^2.1.8",
|
||||
"khroma": "^2.0.0",
|
||||
"moment-mini": "^2.24.0",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"less": "4.1.2",
|
||||
"less-loader": "11.0.0",
|
||||
"license-checker-webpack-plugin": "0.2.1",
|
||||
"mermaid": "9.1.1",
|
||||
"mermaid": "9.1.2",
|
||||
"mini-css-extract-plugin": "2.6.0",
|
||||
"monaco-editor": "0.33.0",
|
||||
"monaco-editor-webpack-plugin": "7.0.1",
|
||||
|
|
|
@ -886,7 +886,7 @@ func dismissReview(ctx *context.APIContext, msg string, isDismiss bool) {
|
|||
return
|
||||
}
|
||||
|
||||
_, err := pull_service.DismissReview(ctx, review.ID, msg, ctx.Doer, isDismiss)
|
||||
_, err := pull_service.DismissReview(ctx, review.ID, ctx.Repo.Repository.ID, msg, ctx.Doer, isDismiss)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "pull_service.DismissReview", err)
|
||||
return
|
||||
|
|
|
@ -24,13 +24,13 @@ func responseAPIUsers(ctx *context.APIContext, users []*user_model.User) {
|
|||
}
|
||||
|
||||
func listUserFollowers(ctx *context.APIContext, u *user_model.User) {
|
||||
users, err := user_model.GetUserFollowers(u, utils.GetListOptions(ctx))
|
||||
users, count, err := user_model.GetUserFollowers(ctx, u, ctx.Doer, utils.GetListOptions(ctx))
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserFollowers", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(int64(u.NumFollowers))
|
||||
ctx.SetTotalCountHeader(count)
|
||||
responseAPIUsers(ctx, users)
|
||||
}
|
||||
|
||||
|
@ -86,13 +86,13 @@ func ListFollowers(ctx *context.APIContext) {
|
|||
}
|
||||
|
||||
func listUserFollowing(ctx *context.APIContext, u *user_model.User) {
|
||||
users, err := user_model.GetUserFollowing(u, utils.GetListOptions(ctx))
|
||||
users, count, err := user_model.GetUserFollowing(ctx, u, ctx.Doer, utils.GetListOptions(ctx))
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetUserFollowing", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.SetTotalCountHeader(int64(u.NumFollowing))
|
||||
ctx.SetTotalCountHeader(count)
|
||||
responseAPIUsers(ctx, users)
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ func Init(next http.Handler) http.Handler {
|
|||
Render: rnd,
|
||||
Session: session.GetSession(req),
|
||||
Data: map[string]interface{}{
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Title": locale.Tr("install.install"),
|
||||
"PageIsInstall": true,
|
||||
"DbTypeNames": dbTypeNames,
|
||||
|
|
|
@ -57,7 +57,7 @@ func installRecovery() func(next http.Handler) http.Handler {
|
|||
store := dataStore{
|
||||
"Language": lc.Language(),
|
||||
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
|
||||
"i18n": lc,
|
||||
"locale": lc,
|
||||
"SignedUserID": int64(0),
|
||||
"SignedUserName": "",
|
||||
}
|
||||
|
|
|
@ -477,7 +477,7 @@ func (ctx *preReceiveContext) loadPusherAndPermission() bool {
|
|||
|
||||
userPerm, err := access_model.GetUserRepoPermission(ctx, ctx.Repo.Repository, user)
|
||||
if err != nil {
|
||||
log.Error("Unable to get Repo permission of repo %s/%s of User %s", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err)
|
||||
log.Error("Unable to get Repo permission of repo %s/%s of User %s: %v", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get Repo permission of repo %s/%s of User %s: %v", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err),
|
||||
})
|
||||
|
|
|
@ -25,6 +25,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/queue"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/updatechecker"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
|
@ -85,7 +86,7 @@ var sysStatus struct {
|
|||
}
|
||||
|
||||
func updateSystemStatus() {
|
||||
sysStatus.Uptime = timeutil.TimeSincePro(setting.AppStartTime, "en")
|
||||
sysStatus.Uptime = timeutil.TimeSincePro(setting.AppStartTime, translation.NewLocale("en-US"))
|
||||
|
||||
m := new(runtime.MemStats)
|
||||
runtime.ReadMemStats(m)
|
||||
|
|
|
@ -266,7 +266,7 @@ func SignInPost(ctx *context.Context) {
|
|||
}
|
||||
|
||||
if hasTOTPtwofa {
|
||||
// User will need to use U2F, save data
|
||||
// User will need to use WebAuthn, save data
|
||||
if err := ctx.Session.Set("totpEnrolled", u.ID); err != nil {
|
||||
ctx.ServerError("UserSignIn: Unable to set WebAuthn Enrolled in session", err)
|
||||
return
|
||||
|
@ -278,7 +278,7 @@ func SignInPost(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// If we have U2F redirect there first
|
||||
// If we have WebAuthn redirect there first
|
||||
if hasWebAuthnTwofa {
|
||||
ctx.Redirect(setting.AppSubURL + "/user/webauthn")
|
||||
return
|
||||
|
@ -317,7 +317,6 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe
|
|||
_ = ctx.Session.Delete("openid_determined_username")
|
||||
_ = ctx.Session.Delete("twofaUid")
|
||||
_ = ctx.Session.Delete("twofaRemember")
|
||||
_ = ctx.Session.Delete("u2fChallenge")
|
||||
_ = ctx.Session.Delete("linkAccount")
|
||||
if err := ctx.Session.Set("uid", u.ID); err != nil {
|
||||
log.Error("Error setting uid %d in session: %v", u.ID, err)
|
||||
|
@ -629,7 +628,7 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
|
|||
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
ctx.Data["Email"] = u.Email
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
|
||||
ctx.HTML(http.StatusOK, TplActivate)
|
||||
|
||||
if setting.CacheService.Enabled {
|
||||
|
@ -658,7 +657,7 @@ func Activate(ctx *context.Context) {
|
|||
if setting.CacheService.Enabled && ctx.Cache.IsExist("MailResendLimit_"+ctx.Doer.LowerName) {
|
||||
ctx.Data["ResendLimited"] = true
|
||||
} else {
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
|
||||
mailer.SendActivateAccountMail(ctx.Locale, ctx.Doer)
|
||||
|
||||
if setting.CacheService.Enabled {
|
||||
|
|
|
@ -63,7 +63,7 @@ func ForgotPasswdPost(ctx *context.Context) {
|
|||
u, err := user_model.GetUserByEmail(email)
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale)
|
||||
ctx.Data["IsResetSent"] = true
|
||||
ctx.HTML(http.StatusOK, tplForgotPassword)
|
||||
return
|
||||
|
@ -93,7 +93,7 @@ func ForgotPasswdPost(ctx *context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale)
|
||||
ctx.Data["IsResetSent"] = true
|
||||
ctx.HTML(http.StatusOK, tplForgotPassword)
|
||||
}
|
||||
|
|
|
@ -67,10 +67,7 @@ func WebAuthnLoginAssertion(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
// FIXME: DEPRECATED appid is deprecated and is planned to be removed in v1.18.0
|
||||
assertion, sessionData, err := wa.WebAuthn.BeginLogin((*wa.User)(user), webauthn.WithAssertionExtensions(protocol.AuthenticationExtensions{
|
||||
"appid": setting.U2F.AppID,
|
||||
}))
|
||||
assertion, sessionData, err := wa.WebAuthn.BeginLogin((*wa.User)(user))
|
||||
if err != nil {
|
||||
ctx.ServerError("webauthn.BeginLogin", err)
|
||||
return
|
||||
|
@ -159,12 +156,5 @@ func WebAuthnLoginAssertionPost(ctx *context.Context) {
|
|||
}
|
||||
_ = ctx.Session.Delete("twofaUid")
|
||||
|
||||
// Finally check if the appid extension was used:
|
||||
if value, ok := parsedResponse.ClientExtensionResults["appid"]; ok {
|
||||
if appid, ok := value.(bool); ok && appid {
|
||||
ctx.Flash.Error(ctx.Tr("webauthn_u2f_deprecated", dbCred.Name))
|
||||
}
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, map[string]string{"redirect": redirect})
|
||||
}
|
||||
|
|
|
@ -139,7 +139,7 @@ func Recovery() func(next http.Handler) http.Handler {
|
|||
store := dataStore{
|
||||
"Language": lc.Language(),
|
||||
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
|
||||
"i18n": lc,
|
||||
"locale": lc,
|
||||
}
|
||||
|
||||
user := context.GetContextUser(req)
|
||||
|
|
|
@ -21,8 +21,8 @@ func TemplatePreview(ctx *context.Context) {
|
|||
ctx.Data["AppVer"] = setting.AppVer
|
||||
ctx.Data["AppUrl"] = setting.AppURL
|
||||
ctx.Data["Code"] = "2014031910370000009fff6782aadb2162b4a997acb69d4400888e0b9274657374"
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale.Language())
|
||||
ctx.Data["ActiveCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)
|
||||
ctx.Data["ResetPwdCodeLives"] = timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, ctx.Locale)
|
||||
ctx.Data["CurDbValue"] = ""
|
||||
|
||||
ctx.HTML(http.StatusOK, base.TplName(ctx.Params("*")))
|
||||
|
|
|
@ -255,7 +255,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
|
|||
commitCnt++
|
||||
|
||||
// User avatar image
|
||||
commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Locale.Language())
|
||||
commitSince := timeutil.TimeSinceUnix(timeutil.TimeStamp(commit.Author.When.Unix()), ctx.Locale)
|
||||
|
||||
var avatar string
|
||||
if commit.User != nil {
|
||||
|
|
|
@ -803,7 +803,8 @@ func NewIssue(ctx *context.Context) {
|
|||
body := ctx.FormString("body")
|
||||
ctx.Data["BodyQuery"] = body
|
||||
|
||||
ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects)
|
||||
isProjectsEnabled := ctx.Repo.CanRead(unit.TypeProjects)
|
||||
ctx.Data["IsProjectsEnabled"] = isProjectsEnabled
|
||||
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
|
||||
upload.AddUploadContext(ctx, "comment")
|
||||
|
||||
|
@ -819,7 +820,7 @@ func NewIssue(ctx *context.Context) {
|
|||
}
|
||||
|
||||
projectID := ctx.FormInt64("project")
|
||||
if projectID > 0 {
|
||||
if projectID > 0 && isProjectsEnabled {
|
||||
project, err := project_model.GetProjectByID(ctx, projectID)
|
||||
if err != nil {
|
||||
log.Error("GetProjectByID: %d: %v", projectID, err)
|
||||
|
@ -1043,6 +1044,11 @@ func NewIssuePost(ctx *context.Context) {
|
|||
}
|
||||
|
||||
if projectID > 0 {
|
||||
if !ctx.Repo.CanRead(unit.TypeProjects) {
|
||||
// User must also be able to see the project.
|
||||
ctx.Error(http.StatusBadRequest, "user hasn't permissions to read projects")
|
||||
return
|
||||
}
|
||||
if err := issues_model.ChangeProjectAssign(issue, ctx.Doer, projectID); err != nil {
|
||||
ctx.ServerError("ChangeProjectAssign", err)
|
||||
return
|
||||
|
@ -1783,6 +1789,10 @@ func getActionIssues(ctx *context.Context) []*issues_model.Issue {
|
|||
issueUnitEnabled := ctx.Repo.CanRead(unit.TypeIssues)
|
||||
prUnitEnabled := ctx.Repo.CanRead(unit.TypePullRequests)
|
||||
for _, issue := range issues {
|
||||
if issue.RepoID != ctx.Repo.Repository.ID {
|
||||
ctx.NotFound("some issue's RepoID is incorrect", errors.New("some issue's RepoID is incorrect"))
|
||||
return nil
|
||||
}
|
||||
if issue.IsPull && !prUnitEnabled || !issue.IsPull && !issueUnitEnabled {
|
||||
ctx.NotFound("IssueOrPullRequestUnitNotAllowed", nil)
|
||||
return nil
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
|
||||
"github.com/sergi/go-diff/diffmatchpatch"
|
||||
)
|
||||
|
@ -29,14 +28,13 @@ func GetContentHistoryOverview(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
lang := ctx.Locale.Language()
|
||||
editedHistoryCountMap, _ := issues_model.QueryIssueContentHistoryEditedCountMap(ctx, issue.ID)
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"i18n": map[string]interface{}{
|
||||
"textEdited": i18n.Tr(lang, "repo.issues.content_history.edited"),
|
||||
"textDeleteFromHistory": i18n.Tr(lang, "repo.issues.content_history.delete_from_history"),
|
||||
"textDeleteFromHistoryConfirm": i18n.Tr(lang, "repo.issues.content_history.delete_from_history_confirm"),
|
||||
"textOptions": i18n.Tr(lang, "repo.issues.content_history.options"),
|
||||
"textEdited": ctx.Tr("repo.issues.content_history.edited"),
|
||||
"textDeleteFromHistory": ctx.Tr("repo.issues.content_history.delete_from_history"),
|
||||
"textDeleteFromHistoryConfirm": ctx.Tr("repo.issues.content_history.delete_from_history_confirm"),
|
||||
"textOptions": ctx.Tr("repo.issues.content_history.options"),
|
||||
},
|
||||
"editedHistoryCountMap": editedHistoryCountMap,
|
||||
})
|
||||
|
@ -55,7 +53,6 @@ func GetContentHistoryList(ctx *context.Context) {
|
|||
// render history list to HTML for frontend dropdown items: (name, value)
|
||||
// name is HTML of "avatar + userName + userAction + timeSince"
|
||||
// value is historyId
|
||||
lang := ctx.Locale.Language()
|
||||
var results []map[string]interface{}
|
||||
for _, item := range items {
|
||||
var actionText string
|
||||
|
@ -67,7 +64,7 @@ func GetContentHistoryList(ctx *context.Context) {
|
|||
} else {
|
||||
actionText = ctx.Locale.Tr("repo.issues.content_history.edited")
|
||||
}
|
||||
timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, lang)
|
||||
timeSinceText := timeutil.TimeSinceUnix(item.EditedUnix, ctx.Locale)
|
||||
|
||||
username := item.UserName
|
||||
if setting.UI.DefaultShowFullName && strings.TrimSpace(item.UserFullName) != "" {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -633,10 +634,17 @@ func MoveIssues(ctx *context.Context) {
|
|||
}
|
||||
|
||||
if len(movedIssues) != len(form.Issues) {
|
||||
ctx.ServerError("IssuesNotFound", err)
|
||||
ctx.ServerError("some issues do not exist", errors.New("some issues do not exist"))
|
||||
return
|
||||
}
|
||||
|
||||
for _, issue := range movedIssues {
|
||||
if issue.RepoID != project.RepoID {
|
||||
ctx.ServerError("Some issue's repoID is not equal to project's repoID", errors.New("Some issue's repoID is not equal to project's repoID"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = project_model.MoveIssuesOnProjectBoard(board, sortedIssueIDs); err != nil {
|
||||
ctx.ServerError("MoveIssuesOnProjectBoard", err)
|
||||
return
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package repo
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
|
@ -118,6 +119,11 @@ func UpdateResolveConversation(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
if comment.Issue.RepoID != ctx.Repo.Repository.ID {
|
||||
ctx.NotFound("comment's repoID is incorrect", errors.New("comment's repoID is incorrect"))
|
||||
return
|
||||
}
|
||||
|
||||
var permResult bool
|
||||
if permResult, err = issues_model.CanMarkConversation(comment.Issue, ctx.Doer); err != nil {
|
||||
ctx.ServerError("CanMarkConversation", err)
|
||||
|
@ -236,7 +242,7 @@ func SubmitReview(ctx *context.Context) {
|
|||
// DismissReview dismissing stale review by repo admin
|
||||
func DismissReview(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.DismissReviewForm)
|
||||
comm, err := pull_service.DismissReview(ctx, form.ReviewID, form.Message, ctx.Doer, true)
|
||||
comm, err := pull_service.DismissReview(ctx, form.ReviewID, ctx.Repo.Repository.ID, form.Message, ctx.Doer, true)
|
||||
if err != nil {
|
||||
ctx.ServerError("pull_service.DismissReview", err)
|
||||
return
|
||||
|
|
|
@ -163,7 +163,7 @@ func Profile(ctx *context.Context) {
|
|||
|
||||
switch tab {
|
||||
case "followers":
|
||||
items, err := user_model.GetUserFollowers(ctx.ContextUser, db.ListOptions{
|
||||
items, count, err := user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Page: page,
|
||||
})
|
||||
|
@ -173,9 +173,9 @@ func Profile(ctx *context.Context) {
|
|||
}
|
||||
ctx.Data["Cards"] = items
|
||||
|
||||
total = ctx.ContextUser.NumFollowers
|
||||
total = int(count)
|
||||
case "following":
|
||||
items, err := user_model.GetUserFollowing(ctx.ContextUser, db.ListOptions{
|
||||
items, count, err := user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{
|
||||
PageSize: setting.UI.User.RepoPagingNum,
|
||||
Page: page,
|
||||
})
|
||||
|
@ -185,7 +185,7 @@ func Profile(ctx *context.Context) {
|
|||
}
|
||||
ctx.Data["Cards"] = items
|
||||
|
||||
total = ctx.ContextUser.NumFollowing
|
||||
total = int(count)
|
||||
case "activity":
|
||||
ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
|
||||
RequestedUser: ctx.ContextUser,
|
||||
|
|
|
@ -34,6 +34,7 @@ func Account(ctx *context.Context) {
|
|||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsAccount"] = true
|
||||
ctx.Data["Email"] = ctx.Doer.Email
|
||||
ctx.Data["EnableNotifyMail"] = setting.Service.EnableNotifyMail
|
||||
|
||||
loadAccountData(ctx)
|
||||
|
||||
|
@ -146,7 +147,7 @@ func EmailPost(ctx *context.Context) {
|
|||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
}
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", address, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/account")
|
||||
return
|
||||
}
|
||||
|
@ -208,7 +209,7 @@ func EmailPost(ctx *context.Context) {
|
|||
log.Error("Set cache(MailResendLimit) fail: %v", err)
|
||||
}
|
||||
}
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale.Language())))
|
||||
ctx.Flash.Info(ctx.Tr("settings.add_email_confirmation_sent", email.Email, timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, ctx.Locale)))
|
||||
} else {
|
||||
ctx.Flash.Success(ctx.Tr("settings.add_email_success"))
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
"code.gitea.io/gitea/modules/typesniffer"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
|
@ -136,7 +136,7 @@ func ProfilePost(ctx *context.Context) {
|
|||
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
|
||||
|
||||
log.Trace("User settings updated: %s", ctx.Doer.Name)
|
||||
ctx.Flash.Success(i18n.Tr(ctx.Doer.Language, "settings.update_profile_success"))
|
||||
ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).Tr("settings.update_profile_success"))
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings")
|
||||
}
|
||||
|
||||
|
@ -425,7 +425,7 @@ func UpdateUserLang(ctx *context.Context) {
|
|||
middleware.SetLocaleCookie(ctx.Resp, ctx.Doer.Language, 0)
|
||||
|
||||
log.Trace("User settings updated: %s", ctx.Doer.Name)
|
||||
ctx.Flash.Success(i18n.Tr(ctx.Doer.Language, "settings.update_language_success"))
|
||||
ctx.Flash.Success(translation.NewLocale(ctx.Doer.Language).Tr("settings.update_language_success"))
|
||||
ctx.Redirect(setting.AppSubURL + "/user/settings/appearance")
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,6 @@ const (
|
|||
func Security(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsSecurity"] = true
|
||||
ctx.Data["RequireU2F"] = true
|
||||
|
||||
if ctx.FormString("openid.return_to") != "" {
|
||||
settingsOpenIDVerify(ctx)
|
||||
|
|
|
@ -901,7 +901,7 @@ func RegisterRoutes(m *web.Route) {
|
|||
|
||||
m.Post("/labels", reqRepoIssuesOrPullsWriter, repo.UpdateIssueLabel)
|
||||
m.Post("/milestone", reqRepoIssuesOrPullsWriter, repo.UpdateIssueMilestone)
|
||||
m.Post("/projects", reqRepoIssuesOrPullsWriter, repo.UpdateIssueProject)
|
||||
m.Post("/projects", reqRepoIssuesOrPullsWriter, reqRepoProjectsReader, repo.UpdateIssueProject)
|
||||
m.Post("/assignee", reqRepoIssuesOrPullsWriter, repo.UpdateIssueAssignee)
|
||||
m.Post("/request_review", reqRepoIssuesOrPullsReader, repo.UpdatePullReviewRequest)
|
||||
m.Post("/dismiss_review", reqRepoAdmin, bindIgnErr(forms.DismissReviewForm{}), repo.DismissReview)
|
||||
|
|
|
@ -199,7 +199,7 @@ func checkRestricted(l *ldap.Conn, ls *Source, userDN string) bool {
|
|||
// List all group memberships of a user
|
||||
func (source *Source) listLdapGroupMemberships(l *ldap.Conn, uid string) []string {
|
||||
var ldapGroups []string
|
||||
groupFilter := fmt.Sprintf("(%s=%s)", source.GroupMemberUID, uid)
|
||||
groupFilter := fmt.Sprintf("(%s=%s)", source.GroupMemberUID, ldap.EscapeFilter(uid))
|
||||
result, err := l.Search(ldap.NewSearchRequest(
|
||||
source.GroupDN,
|
||||
ldap.ScopeWholeSubtree,
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"code.gitea.io/gitea/modules/graceful"
|
||||
"code.gitea.io/gitea/modules/process"
|
||||
"code.gitea.io/gitea/modules/sync"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
|
||||
"github.com/gogs/cron"
|
||||
)
|
||||
|
@ -63,7 +64,7 @@ type TaskTableRow struct {
|
|||
task *Task
|
||||
}
|
||||
|
||||
func (t *TaskTableRow) FormatLastMessage(locale string) string {
|
||||
func (t *TaskTableRow) FormatLastMessage(locale translation.Locale) string {
|
||||
if t.Status == "finished" {
|
||||
return t.task.GetConfig().FormatMessage(locale, t.Name, t.Status, t.LastDoer)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ package cron
|
|||
import (
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/modules/translation/i18n"
|
||||
"code.gitea.io/gitea/modules/translation"
|
||||
)
|
||||
|
||||
// Config represents a basic configuration interface that cron task
|
||||
|
@ -15,7 +15,7 @@ type Config interface {
|
|||
IsEnabled() bool
|
||||
DoRunAtStart() bool
|
||||
GetSchedule() string
|
||||
FormatMessage(locale, name, status, doer string, args ...interface{}) string
|
||||
FormatMessage(locale translation.Locale, name, status, doer string, args ...interface{}) string
|
||||
DoNoticeOnSuccess() bool
|
||||
}
|
||||
|
||||
|
@ -69,9 +69,9 @@ func (b *BaseConfig) DoNoticeOnSuccess() bool {
|
|||
|
||||
// FormatMessage returns a message for the task
|
||||
// Please note the `status` string will be concatenated with `admin.dashboard.cron.` and `admin.dashboard.task.` to provide locale messages. Similarly `name` will be composed with `admin.dashboard.` to provide the locale name for the task.
|
||||
func (b *BaseConfig) FormatMessage(locale, name, status, doer string, args ...interface{}) string {
|
||||
func (b *BaseConfig) FormatMessage(locale translation.Locale, name, status, doer string, args ...interface{}) string {
|
||||
realArgs := make([]interface{}, 0, len(args)+2)
|
||||
realArgs = append(realArgs, i18n.Tr(locale, "admin.dashboard."+name))
|
||||
realArgs = append(realArgs, locale.Tr("admin.dashboard."+name))
|
||||
if doer == "" {
|
||||
realArgs = append(realArgs, "(Cron)")
|
||||
} else {
|
||||
|
@ -81,7 +81,7 @@ func (b *BaseConfig) FormatMessage(locale, name, status, doer string, args ...in
|
|||
realArgs = append(realArgs, args...)
|
||||
}
|
||||
if doer == "" {
|
||||
return i18n.Tr(locale, "admin.dashboard.cron."+status, realArgs...)
|
||||
return locale.Tr("admin.dashboard.cron."+status, realArgs...)
|
||||
}
|
||||
return i18n.Tr(locale, "admin.dashboard.task."+status, realArgs...)
|
||||
return locale.Tr("admin.dashboard.task."+status, realArgs...)
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
|
|||
doerName = doer.Name
|
||||
}
|
||||
|
||||
ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage("en-US", t.Name, "process", doerName))
|
||||
ctx, _, finished := pm.AddContext(baseCtx, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "process", doerName))
|
||||
defer finished()
|
||||
|
||||
if err := t.fun(ctx, doer, config); err != nil {
|
||||
|
@ -114,7 +114,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
|
|||
t.LastDoer = doerName
|
||||
t.lock.Unlock()
|
||||
|
||||
if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage("en-US", t.Name, "cancelled", doerName, message)); err != nil {
|
||||
if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "cancelled", doerName, message)); err != nil {
|
||||
log.Error("CreateNotice: %v", err)
|
||||
}
|
||||
return
|
||||
|
@ -127,7 +127,7 @@ func (t *Task) RunWithUser(doer *user_model.User, config Config) {
|
|||
t.lock.Unlock()
|
||||
|
||||
if config.DoNoticeOnSuccess() {
|
||||
if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage("en-US", t.Name, "finished", doerName)); err != nil {
|
||||
if err := admin_model.CreateNotice(ctx, admin_model.NoticeTask, config.FormatMessage(translation.NewLocale("en-US"), t.Name, "finished", doerName)); err != nil {
|
||||
log.Error("CreateNotice: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -148,7 +148,7 @@ func RegisterTask(name string, config Config, fun func(context.Context, *user_mo
|
|||
log.Debug("Registering task: %s", name)
|
||||
|
||||
i18nKey := "admin.dashboard." + name
|
||||
if _, ok := translation.TryTr("en-US", i18nKey); !ok {
|
||||
if value := translation.NewLocale("en-US").Tr(i18nKey); value == i18nKey {
|
||||
return fmt.Errorf("translation is missing for task %q, please add translation for %q", name, i18nKey)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,17 @@ import (
|
|||
)
|
||||
|
||||
func changeMilestoneAssign(ctx context.Context, doer *user_model.User, issue *issues_model.Issue, oldMilestoneID int64) error {
|
||||
// Only check if milestone exists if we don't remove it.
|
||||
if issue.MilestoneID > 0 {
|
||||
has, err := issues_model.HasMilestoneByRepoID(ctx, issue.RepoID, issue.MilestoneID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("HasMilestoneByRepoID: %v", err)
|
||||
}
|
||||
if !has {
|
||||
return fmt.Errorf("HasMilestoneByRepoID: issue doesn't exist")
|
||||
}
|
||||
}
|
||||
|
||||
if err := issues_model.UpdateIssueCols(ctx, issue, "milestone_id"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -75,12 +75,12 @@ func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, s
|
|||
locale := translation.NewLocale(language)
|
||||
data := map[string]interface{}{
|
||||
"DisplayName": u.DisplayName(),
|
||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, language),
|
||||
"ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, language),
|
||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale),
|
||||
"ResetPwdCodeLives": timeutil.MinutesToFriendly(setting.Service.ResetPwdCodeLives, locale),
|
||||
"Code": code,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
@ -126,12 +126,12 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
|
|||
locale := translation.NewLocale(u.Language)
|
||||
data := map[string]interface{}{
|
||||
"DisplayName": u.DisplayName(),
|
||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale.Language()),
|
||||
"ActiveCodeLives": timeutil.MinutesToFriendly(setting.Service.ActiveCodeLives, locale),
|
||||
"Code": u.GenerateEmailActivateCode(email.Email),
|
||||
"Email": email.Email,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ func SendRegisterNotifyMail(u *user_model.User) {
|
|||
"Username": u.Name,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
@ -196,7 +196,7 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
|
|||
"Link": repo.HTMLURL(),
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
|
|||
"ReviewComments": reviewComments,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ func mailNewRelease(ctx context.Context, lang string, tos []string, rel *models.
|
|||
"Subject": subject,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
|
|||
"Language": locale.Language(),
|
||||
"Destination": destination,
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"locale": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
|
|
@ -590,7 +590,7 @@ func updateOptionsUnits(opts *base.MigrateOptions, units []string) error {
|
|||
opts.ReleaseAssets = true
|
||||
} else {
|
||||
for _, unit := range units {
|
||||
switch strings.ToLower(unit) {
|
||||
switch strings.ToLower(strings.TrimSpace(unit)) {
|
||||
case "":
|
||||
continue
|
||||
case "wiki":
|
||||
|
|
|
@ -271,7 +271,7 @@ func SubmitReview(ctx context.Context, doer *user_model.User, gitRepo *git.Repos
|
|||
}
|
||||
|
||||
// DismissReview dismissing stale review by repo admin
|
||||
func DismissReview(ctx context.Context, reviewID int64, message string, doer *user_model.User, isDismiss bool) (comment *issues_model.Comment, err error) {
|
||||
func DismissReview(ctx context.Context, reviewID, repoID int64, message string, doer *user_model.User, isDismiss bool) (comment *issues_model.Comment, err error) {
|
||||
review, err := issues_model.GetReviewByID(ctx, reviewID)
|
||||
if err != nil {
|
||||
return
|
||||
|
@ -281,6 +281,16 @@ func DismissReview(ctx context.Context, reviewID int64, message string, doer *us
|
|||
return nil, fmt.Errorf("not need to dismiss this review because it's type is not Approve or change request")
|
||||
}
|
||||
|
||||
// load data for notify
|
||||
if err = review.LoadAttributes(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check if the review's repoID is the one we're currently expecting.
|
||||
if review.Issue.RepoID != repoID {
|
||||
return nil, fmt.Errorf("reviews's repository is not the same as the one we expect")
|
||||
}
|
||||
|
||||
if err = issues_model.DismissReview(review, isDismiss); err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -289,10 +299,6 @@ func DismissReview(ctx context.Context, reviewID int64, message string, doer *us
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// load data for notify
|
||||
if err = review.LoadAttributes(ctx); err != nil {
|
||||
return
|
||||
}
|
||||
if err = review.Issue.LoadPullRequest(); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.auths.edit"}}
|
||||
{{.locale.Tr "admin.auths.edit"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<form class="ui form" action="{{.Link}}" method="post">
|
||||
|
@ -12,12 +12,12 @@
|
|||
{{.CsrfTokenHtml}}
|
||||
<input type="hidden" name="id" value="{{.Source.ID}}">
|
||||
<div class="inline field">
|
||||
<label>{{$.i18n.Tr "admin.auths.auth_type"}}</label>
|
||||
<label>{{$.locale.Tr "admin.auths.auth_type"}}</label>
|
||||
<input type="hidden" id="auth_type" name="type" value="{{.Source.Type.Int}}">
|
||||
<span>{{.Source.TypeName}}</span>
|
||||
</div>
|
||||
<div class="required inline field {{if .Err_Name}}error{{end}}">
|
||||
<label for="name">{{.i18n.Tr "admin.auths.auth_name"}}</label>
|
||||
<label for="name">{{.locale.Tr "admin.auths.auth_name"}}</label>
|
||||
<input id="name" name="name" value="{{.Source.Name}}" autofocus required>
|
||||
</div>
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
|||
{{if or .Source.IsLDAP .Source.IsDLDAP}}
|
||||
{{ $cfg:=.Source.Cfg }}
|
||||
<div class="inline required field {{if .Err_SecurityProtocol}}error{{end}}">
|
||||
<label>{{.i18n.Tr "admin.auths.security_protocol"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.security_protocol"}}</label>
|
||||
<div class="ui selection security-protocol dropdown">
|
||||
<input type="hidden" id="security_protocol" name="security_protocol" value="{{$cfg.SecurityProtocol.Int}}">
|
||||
<div class="text">{{$cfg.SecurityProtocolName}}</div>
|
||||
|
@ -38,74 +38,74 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="host">{{.i18n.Tr "admin.auths.host"}}</label>
|
||||
<label for="host">{{.locale.Tr "admin.auths.host"}}</label>
|
||||
<input id="host" name="host" value="{{$cfg.Host}}" placeholder="e.g. mydomain.com" required>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="port">{{.i18n.Tr "admin.auths.port"}}</label>
|
||||
<label for="port">{{.locale.Tr "admin.auths.port"}}</label>
|
||||
<input id="port" name="port" value="{{$cfg.Port}}" placeholder="e.g. 636" required>
|
||||
</div>
|
||||
<div class="has-tls inline field {{if not .HasTLS}}hide{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<input name="skip_verify" type="checkbox" {{if .Source.SkipVerify}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
{{if .Source.IsLDAP}}
|
||||
<div class="field">
|
||||
<label for="bind_dn">{{.i18n.Tr "admin.auths.bind_dn"}}</label>
|
||||
<label for="bind_dn">{{.locale.Tr "admin.auths.bind_dn"}}</label>
|
||||
<input id="bind_dn" name="bind_dn" value="{{$cfg.BindDN}}" placeholder="e.g. cn=Search,dc=mydomain,dc=com">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="bind_password">{{.i18n.Tr "admin.auths.bind_password"}}</label>
|
||||
<label for="bind_password">{{.locale.Tr "admin.auths.bind_password"}}</label>
|
||||
<input id="bind_password" name="bind_password" type="password" value="{{$cfg.BindPassword}}">
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="{{if .Source.IsLDAP}}required{{end}} field">
|
||||
<label for="user_base">{{.i18n.Tr "admin.auths.user_base"}}</label>
|
||||
<label for="user_base">{{.locale.Tr "admin.auths.user_base"}}</label>
|
||||
<input id="user_base" name="user_base" value="{{$cfg.UserBase}}" placeholder="e.g. ou=Users,dc=mydomain,dc=com" {{if .Source.IsLDAP}}required{{end}}>
|
||||
</div>
|
||||
{{if .Source.IsDLDAP}}
|
||||
<div class="required field">
|
||||
<label for="user_dn">{{.i18n.Tr "admin.auths.user_dn"}}</label>
|
||||
<label for="user_dn">{{.locale.Tr "admin.auths.user_dn"}}</label>
|
||||
<input id="user_dn" name="user_dn" value="{{$cfg.UserDN}}" placeholder="e.g. uid=%s,ou=Users,dc=mydomain,dc=com" required>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="required field">
|
||||
<label for="filter">{{.i18n.Tr "admin.auths.filter"}}</label>
|
||||
<label for="filter">{{.locale.Tr "admin.auths.filter"}}</label>
|
||||
<input id="filter" name="filter" value="{{$cfg.Filter}}" placeholder="e.g. (&(objectClass=posixAccount)(uid=%s))" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="admin_filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
|
||||
<label for="admin_filter">{{.locale.Tr "admin.auths.admin_filter"}}</label>
|
||||
<input id="admin_filter" name="admin_filter" value="{{$cfg.AdminFilter}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="restricted_filter">{{.i18n.Tr "admin.auths.restricted_filter"}}</label>
|
||||
<label for="restricted_filter">{{.locale.Tr "admin.auths.restricted_filter"}}</label>
|
||||
<input id="restricted_filter" name="restricted_filter" value="{{$cfg.RestrictedFilter}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.restricted_filter_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.restricted_filter_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
||||
<input id="attribute_username" name="attribute_username" value="{{$cfg.AttributeUsername}}" placeholder="{{.i18n.Tr "admin.auths.attribute_username_placeholder"}}">
|
||||
<label for="attribute_username">{{.locale.Tr "admin.auths.attribute_username"}}</label>
|
||||
<input id="attribute_username" name="attribute_username" value="{{$cfg.AttributeUsername}}" placeholder="{{.locale.Tr "admin.auths.attribute_username_placeholder"}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
|
||||
<label for="attribute_name">{{.locale.Tr "admin.auths.attribute_name"}}</label>
|
||||
<input id="attribute_name" name="attribute_name" value="{{$cfg.AttributeName}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_surname">{{.i18n.Tr "admin.auths.attribute_surname"}}</label>
|
||||
<label for="attribute_surname">{{.locale.Tr "admin.auths.attribute_surname"}}</label>
|
||||
<input id="attribute_surname" name="attribute_surname" value="{{$cfg.AttributeSurname}}">
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label>
|
||||
<label for="attribute_mail">{{.locale.Tr "admin.auths.attribute_mail"}}</label>
|
||||
<input id="attribute_mail" name="attribute_mail" value="{{$cfg.AttributeMail}}" placeholder="e.g. mail" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_ssh_public_key">{{.i18n.Tr "admin.auths.attribute_ssh_public_key"}}</label>
|
||||
<label for="attribute_ssh_public_key">{{.locale.Tr "admin.auths.attribute_ssh_public_key"}}</label>
|
||||
<input id="attribute_ssh_public_key" name="attribute_ssh_public_key" value="{{$cfg.AttributeSSHPublicKey}}" placeholder="e.g. SshPublicKey">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_avatar">{{.i18n.Tr "admin.auths.attribute_avatar"}}</label>
|
||||
<label for="attribute_avatar">{{.locale.Tr "admin.auths.attribute_avatar"}}</label>
|
||||
<input id="attribute_avatar" name="attribute_avatar" value="{{$cfg.AttributeAvatar}}" placeholder="e.g. jpegPhoto">
|
||||
</div>
|
||||
|
||||
|
@ -113,33 +113,33 @@
|
|||
<!-- ldap group begin -->
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.enable_ldap_groups"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.enable_ldap_groups"}}</strong></label>
|
||||
<input type="checkbox" name="groups_enabled" class="js-ldap-group-toggle" {{if $cfg.GroupsEnabled}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ldap-group-options" class="ui segment secondary" {{if not $cfg.GroupsEnabled}}hidden{{end}}>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.group_search_base"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.group_search_base"}}</label>
|
||||
<input name="group_dn" value="{{$cfg.GroupDN}}" placeholder="e.g. ou=group,dc=mydomain,dc=com">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.group_attribute_list_users"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.group_attribute_list_users"}}</label>
|
||||
<input name="group_member_uid" value="{{$cfg.GroupMemberUID}}" placeholder="e.g. memberUid">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.user_attribute_in_group"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.user_attribute_in_group"}}</label>
|
||||
<input name="user_uid" value="{{$cfg.UserUID}}" placeholder="e.g. uid">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.verify_group_membership"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.verify_group_membership"}}</label>
|
||||
<input name="group_filter" value="{{$cfg.GroupFilter}}" placeholder="e.g. (|(cn=gitea_users)(cn=admins))">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.map_group_to_team"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.map_group_to_team"}}</label>
|
||||
<input name="group_team_map" value="{{$cfg.GroupTeamMap}}" placeholder='e.g. {"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}'>
|
||||
</div>
|
||||
<div class="ui checkbox">
|
||||
<label>{{.i18n.Tr "admin.auths.map_group_to_team_removal"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.map_group_to_team_removal"}}</label>
|
||||
<input name="group_team_map_removal" type="checkbox" {{if $cfg.GroupTeamMapRemoval}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -148,31 +148,31 @@
|
|||
{{if .Source.IsLDAP}}
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label for="use_paged_search"><strong>{{.i18n.Tr "admin.auths.use_paged_search"}}</strong></label>
|
||||
<label for="use_paged_search"><strong>{{.locale.Tr "admin.auths.use_paged_search"}}</strong></label>
|
||||
<input id="use_paged_search" name="use_paged_search" type="checkbox" {{if $cfg.UsePagedSearch}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field required search-page-size{{if not $cfg.UsePagedSearch}} hide{{end}}">
|
||||
<label for="search_page_size">{{.i18n.Tr "admin.auths.search_page_size"}}</label>
|
||||
<label for="search_page_size">{{.locale.Tr "admin.auths.search_page_size"}}</label>
|
||||
<input id="search_page_size" name="search_page_size" value="{{if $cfg.UsePagedSearch}}{{$cfg.SearchPageSize}}{{end}}">
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.attributes_in_bind"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.attributes_in_bind"}}</strong></label>
|
||||
<input name="attributes_in_bind" type="checkbox" {{if $cfg.AttributesInBind}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if $cfg.SkipLocalTwoFA}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label for="allow_deactivate_all"><strong>{{.i18n.Tr "admin.auths.allow_deactivate_all"}}</strong></label>
|
||||
<label for="allow_deactivate_all"><strong>{{.locale.Tr "admin.auths.allow_deactivate_all"}}</strong></label>
|
||||
<input id="allow_deactivate_all" name="allow_deactivate_all" type="checkbox" {{if $cfg.AllowDeactivateAll}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -182,7 +182,7 @@
|
|||
{{if .Source.IsSMTP}}
|
||||
{{ $cfg:=.Source.Cfg }}
|
||||
<div class="inline required field">
|
||||
<label>{{.i18n.Tr "admin.auths.smtp_auth"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.smtp_auth"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="smtp_auth" name="smtp_auth" value="{{$cfg.Auth}}" required>
|
||||
<div class="text">{{$cfg.Auth}}</div>
|
||||
|
@ -195,47 +195,47 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="smtp_host">{{.i18n.Tr "admin.auths.smtphost"}}</label>
|
||||
<label for="smtp_host">{{.locale.Tr "admin.auths.smtphost"}}</label>
|
||||
<input id="smtp_host" name="smtp_host" value="{{$cfg.Host}}" required>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="smtp_port">{{.i18n.Tr "admin.auths.smtpport"}}</label>
|
||||
<label for="smtp_port">{{.locale.Tr "admin.auths.smtpport"}}</label>
|
||||
<input id="smtp_port" name="smtp_port" value="{{$cfg.Port}}" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="force_smtps"><strong>{{.i18n.Tr "admin.auths.force_smtps"}}</strong></label>
|
||||
<label for="force_smtps"><strong>{{.locale.Tr "admin.auths.force_smtps"}}</strong></label>
|
||||
<input id="force_smtps" name="force_smtps" type="checkbox" {{if $cfg.ForceSMTPS}}checked{{end}}>
|
||||
</div>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.force_smtps_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.force_smtps_helper"}}</p>
|
||||
</div>
|
||||
<div class="has-tls inline field {{if not .HasTLS}}hide{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<input name="skip_verify" type="checkbox" {{if .Source.SkipVerify}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="helo_hostname">{{.i18n.Tr "admin.auths.helo_hostname"}}</label>
|
||||
<label for="helo_hostname">{{.locale.Tr "admin.auths.helo_hostname"}}</label>
|
||||
<input id="helo_hostname" name="helo_hostname" value="{{$cfg.HeloHostname}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.helo_hostname_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.helo_hostname_helper"}}</p>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label for="disable_helo"><strong>{{.i18n.Tr "admin.auths.disable_helo"}}</strong></label>
|
||||
<label for="disable_helo"><strong>{{.locale.Tr "admin.auths.disable_helo"}}</strong></label>
|
||||
<input id="disable_helo" name="disable_helo" type="checkbox" {{if $cfg.DisableHelo}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="allowed_domains">{{.i18n.Tr "admin.auths.allowed_domains"}}</label>
|
||||
<label for="allowed_domains">{{.locale.Tr "admin.auths.allowed_domains"}}</label>
|
||||
<input id="allowed_domains" name="allowed_domains" value="{{$cfg.AllowedDomains}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.allowed_domains_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.allowed_domains_helper"}}</p>
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if $cfg.SkipLocalTwoFA}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
@ -244,18 +244,18 @@
|
|||
{{if .Source.IsPAM}}
|
||||
{{ $cfg:=.Source.Cfg }}
|
||||
<div class="required field">
|
||||
<label for="pam_service_name">{{.i18n.Tr "admin.auths.pam_service_name"}}</label>
|
||||
<label for="pam_service_name">{{.locale.Tr "admin.auths.pam_service_name"}}</label>
|
||||
<input id="pam_service_name" name="pam_service_name" value="{{$cfg.ServiceName}}" required>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="pam_email_domain">{{.i18n.Tr "admin.auths.pam_email_domain"}}</label>
|
||||
<label for="pam_email_domain">{{.locale.Tr "admin.auths.pam_email_domain"}}</label>
|
||||
<input id="pam_email_domain" name="pam_email_domain" value="{{$cfg.EmailDomain}}">
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if $cfg.SkipLocalTwoFA}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
|
@ -264,7 +264,7 @@
|
|||
{{if .Source.IsOAuth2}}
|
||||
{{ $cfg:=.Source.Cfg }}
|
||||
<div class="inline required field">
|
||||
<label>{{.i18n.Tr "admin.auths.oauth2_provider"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.oauth2_provider"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="oauth2_provider" name="oauth2_provider" value="{{$cfg.Provider}}" required>
|
||||
<div class="text">{{.CurrentOAuth2Provider.DisplayName}}</div>
|
||||
|
@ -277,52 +277,52 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="oauth2_key">{{.i18n.Tr "admin.auths.oauth2_clientID"}}</label>
|
||||
<label for="oauth2_key">{{.locale.Tr "admin.auths.oauth2_clientID"}}</label>
|
||||
<input id="oauth2_key" name="oauth2_key" value="{{$cfg.ClientID}}" required>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="oauth2_secret">{{.i18n.Tr "admin.auths.oauth2_clientSecret"}}</label>
|
||||
<label for="oauth2_secret">{{.locale.Tr "admin.auths.oauth2_clientSecret"}}</label>
|
||||
<input id="oauth2_secret" name="oauth2_secret" value="{{$cfg.ClientSecret}}" required>
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<label for="oauth2_icon_url">{{.i18n.Tr "admin.auths.oauth2_icon_url"}}</label>
|
||||
<label for="oauth2_icon_url">{{.locale.Tr "admin.auths.oauth2_icon_url"}}</label>
|
||||
<input id="oauth2_icon_url" name="oauth2_icon_url" value="{{$cfg.IconURL}}">
|
||||
</div>
|
||||
<div class="open_id_connect_auto_discovery_url required field">
|
||||
<label for="open_id_connect_auto_discovery_url">{{.i18n.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label>
|
||||
<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="{{$cfg.OpenIDConnectAutoDiscoveryURL}}">
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if $cfg.SkipLocalTwoFA}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.oauth2_use_custom_url"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.oauth2_use_custom_url"}}</strong></label>
|
||||
<input id="oauth2_use_custom_url" name="oauth2_use_custom_url" type="checkbox" {{if $cfg.CustomURLMapping}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_auth_url required field">
|
||||
<label for="oauth2_auth_url">{{.i18n.Tr "admin.auths.oauth2_authURL"}}</label>
|
||||
<label for="oauth2_auth_url">{{.locale.Tr "admin.auths.oauth2_authURL"}}</label>
|
||||
<input id="oauth2_auth_url" name="oauth2_auth_url" value="{{if $cfg.CustomURLMapping}}{{$cfg.CustomURLMapping.AuthURL}}{{end}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_token_url required field">
|
||||
<label for="oauth2_token_url">{{.i18n.Tr "admin.auths.oauth2_tokenURL"}}</label>
|
||||
<label for="oauth2_token_url">{{.locale.Tr "admin.auths.oauth2_tokenURL"}}</label>
|
||||
<input id="oauth2_token_url" name="oauth2_token_url" value="{{if $cfg.CustomURLMapping}}{{$cfg.CustomURLMapping.TokenURL}}{{end}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_profile_url required field">
|
||||
<label for="oauth2_profile_url">{{.i18n.Tr "admin.auths.oauth2_profileURL"}}</label>
|
||||
<label for="oauth2_profile_url">{{.locale.Tr "admin.auths.oauth2_profileURL"}}</label>
|
||||
<input id="oauth2_profile_url" name="oauth2_profile_url" value="{{if $cfg.CustomURLMapping}}{{$cfg.CustomURLMapping.ProfileURL}}{{end}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_email_url required field">
|
||||
<label for="oauth2_email_url">{{.i18n.Tr "admin.auths.oauth2_emailURL"}}</label>
|
||||
<label for="oauth2_email_url">{{.locale.Tr "admin.auths.oauth2_emailURL"}}</label>
|
||||
<input id="oauth2_email_url" name="oauth2_email_url" value="{{if $cfg.CustomURLMapping}}{{$cfg.CustomURLMapping.EmailURL}}{{end}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_tenant required field">
|
||||
<label for="oauth2_tenant">{{.i18n.Tr "admin.auths.oauth2_tenant"}}</label>
|
||||
<label for="oauth2_tenant">{{.locale.Tr "admin.auths.oauth2_tenant"}}</label>
|
||||
<input id="oauth2_tenant" name="oauth2_tenant" value="{{if $cfg.CustomURLMapping}}{{$cfg.CustomURLMapping.Tenant}}{{end}}">
|
||||
</div>
|
||||
|
||||
|
@ -336,29 +336,29 @@
|
|||
{{end}}{{end}}
|
||||
|
||||
<div class="field">
|
||||
<label for="oauth2_scopes">{{.i18n.Tr "admin.auths.oauth2_scopes"}}</label>
|
||||
<label for="oauth2_scopes">{{.locale.Tr "admin.auths.oauth2_scopes"}}</label>
|
||||
<input id="oauth2_scopes" name="oauth2_scopes" value="{{if $cfg.Scopes}}{{Join $cfg.Scopes "," }}{{end}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_required_claim_name">{{.i18n.Tr "admin.auths.oauth2_required_claim_name"}}</label>
|
||||
<label for="oauth2_required_claim_name">{{.locale.Tr "admin.auths.oauth2_required_claim_name"}}</label>
|
||||
<input id="oauth2_required_claim_name" name="oauth2_required_claim_name" values="{{$cfg.RequiredClaimName}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.oauth2_required_claim_name_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_required_claim_value">{{.i18n.Tr "admin.auths.oauth2_required_claim_value"}}</label>
|
||||
<label for="oauth2_required_claim_value">{{.locale.Tr "admin.auths.oauth2_required_claim_value"}}</label>
|
||||
<input id="oauth2_required_claim_value" name="oauth2_required_claim_value" values="{{$cfg.RequiredClaimValue}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.oauth2_required_claim_value_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_group_claim_name">{{.i18n.Tr "admin.auths.oauth2_group_claim_name"}}</label>
|
||||
<label for="oauth2_group_claim_name">{{.locale.Tr "admin.auths.oauth2_group_claim_name"}}</label>
|
||||
<input id="oauth2_group_claim_name" name="oauth2_group_claim_name" value="{{$cfg.GroupClaimName}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_admin_group">{{.i18n.Tr "admin.auths.oauth2_admin_group"}}</label>
|
||||
<label for="oauth2_admin_group">{{.locale.Tr "admin.auths.oauth2_admin_group"}}</label>
|
||||
<input id="oauth2_admin_group" name="oauth2_admin_group" value="{{$cfg.AdminGroup}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_restricted_group">{{.i18n.Tr "admin.auths.oauth2_restricted_group"}}</label>
|
||||
<label for="oauth2_restricted_group">{{.locale.Tr "admin.auths.oauth2_restricted_group"}}</label>
|
||||
<input id="oauth2_restricted_group" name="oauth2_restricted_group" value="{{$cfg.RestrictedGroup}}">
|
||||
</div>
|
||||
{{end}}
|
||||
|
@ -368,32 +368,32 @@
|
|||
{{ $cfg:=.Source.Cfg }}
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="sspi_auto_create_users"><strong>{{.i18n.Tr "admin.auths.sspi_auto_create_users"}}</strong></label>
|
||||
<label for="sspi_auto_create_users"><strong>{{.locale.Tr "admin.auths.sspi_auto_create_users"}}</strong></label>
|
||||
<input id="sspi_auto_create_users" name="sspi_auto_create_users" class="sspi-auto-create-users" type="checkbox" {{if $cfg.AutoCreateUsers}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_auto_create_users_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_auto_create_users_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="sspi_auto_activate_users"><strong>{{.i18n.Tr "admin.auths.sspi_auto_activate_users"}}</strong></label>
|
||||
<label for="sspi_auto_activate_users"><strong>{{.locale.Tr "admin.auths.sspi_auto_activate_users"}}</strong></label>
|
||||
<input id="sspi_auto_activate_users" name="sspi_auto_activate_users" class="sspi-auto-activate-users" type="checkbox" {{if $cfg.AutoActivateUsers}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_auto_activate_users_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="sspi_strip_domain_names"><strong>{{.i18n.Tr "admin.auths.sspi_strip_domain_names"}}</strong></label>
|
||||
<label for="sspi_strip_domain_names"><strong>{{.locale.Tr "admin.auths.sspi_strip_domain_names"}}</strong></label>
|
||||
<input id="sspi_strip_domain_names" name="sspi_strip_domain_names" class="sspi-strip-domain-names" type="checkbox" {{if $cfg.StripDomainNames}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_strip_domain_names_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="sspi_separator_replacement">{{.i18n.Tr "admin.auths.sspi_separator_replacement"}}</label>
|
||||
<label for="sspi_separator_replacement">{{.locale.Tr "admin.auths.sspi_separator_replacement"}}</label>
|
||||
<input id="sspi_separator_replacement" name="sspi_separator_replacement" value="{{$cfg.SeparatorReplacement}}" required>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_separator_replacement_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_separator_replacement_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="sspi_default_language">{{.i18n.Tr "admin.auths.sspi_default_language"}}</label>
|
||||
<label for="sspi_default_language">{{.locale.Tr "admin.auths.sspi_default_language"}}</label>
|
||||
<div class="ui language selection dropdown" id="sspi_default_language">
|
||||
<input name="sspi_default_language" type="hidden" value="{{$cfg.DefaultLanguage}}">
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
|
@ -405,27 +405,27 @@
|
|||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_default_language_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_default_language_helper"}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
{{if .Source.IsLDAP}}
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.syncenabled"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.syncenabled"}}</strong></label>
|
||||
<input name="is_sync_enabled" type="checkbox" {{if .Source.IsSyncEnabled}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.activated"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.activated"}}</strong></label>
|
||||
<input name="is_active" type="checkbox" {{if .Source.IsActive}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button class="ui green button">{{.i18n.Tr "admin.auths.update"}}</button>
|
||||
<div class="ui red button delete-button" data-url="{{$.Link}}/delete" data-id="{{.Source.ID}}">{{.i18n.Tr "admin.auths.delete"}}</div>
|
||||
<button class="ui green button">{{.locale.Tr "admin.auths.update"}}</button>
|
||||
<div class="ui red button delete-button" data-url="{{$.Link}}/delete" data-id="{{.Source.ID}}">{{.locale.Tr "admin.auths.delete"}}</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -435,10 +435,10 @@
|
|||
<div class="ui small basic delete modal">
|
||||
<div class="ui icon header">
|
||||
{{svg "octicon-trash"}}
|
||||
{{.i18n.Tr "admin.auths.delete_auth_title"}}
|
||||
{{.locale.Tr "admin.auths.delete_auth_title"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.i18n.Tr "admin.auths.delete_auth_desc"}}</p>
|
||||
<p>{{.locale.Tr "admin.auths.delete_auth_desc"}}</p>
|
||||
</div>
|
||||
{{template "base/delete_modal_actions" .}}
|
||||
</div>
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.auths.auth_manage_panel"}} ({{.i18n.Tr "admin.total" .Total}})
|
||||
{{.locale.Tr "admin.auths.auth_manage_panel"}} ({{.locale.Tr "admin.total" .Total}})
|
||||
<div class="ui right">
|
||||
<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/auths/new">{{.i18n.Tr "admin.auths.new"}}</a>
|
||||
<a class="ui primary tiny button" href="{{AppSubUrl}}/admin/auths/new">{{.locale.Tr "admin.auths.new"}}</a>
|
||||
</div>
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
|
@ -14,12 +14,12 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>{{.i18n.Tr "admin.auths.name"}}</th>
|
||||
<th>{{.i18n.Tr "admin.auths.type"}}</th>
|
||||
<th>{{.i18n.Tr "admin.auths.enabled"}}</th>
|
||||
<th>{{.i18n.Tr "admin.auths.updated"}}</th>
|
||||
<th>{{.i18n.Tr "admin.users.created"}}</th>
|
||||
<th>{{.i18n.Tr "admin.users.edit"}}</th>
|
||||
<th>{{.locale.Tr "admin.auths.name"}}</th>
|
||||
<th>{{.locale.Tr "admin.auths.type"}}</th>
|
||||
<th>{{.locale.Tr "admin.auths.enabled"}}</th>
|
||||
<th>{{.locale.Tr "admin.auths.updated"}}</th>
|
||||
<th>{{.locale.Tr "admin.users.created"}}</th>
|
||||
<th>{{.locale.Tr "admin.users.edit"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.auths.new"}}
|
||||
{{.locale.Tr "admin.auths.new"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<form class="ui form" action="{{.Link}}" method="post">
|
||||
|
@ -12,7 +12,7 @@
|
|||
{{.CsrfTokenHtml}}
|
||||
<!-- Types and name -->
|
||||
<div class="inline required field {{if .Err_Type}}error{{end}}">
|
||||
<label>{{.i18n.Tr "admin.auths.auth_type"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.auth_type"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="auth_type" name="type" value="{{.type}}">
|
||||
<div class="text">{{.CurrentTypeName}}</div>
|
||||
|
@ -25,7 +25,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required inline field {{if .Err_Name}}error{{end}}">
|
||||
<label for="name">{{.i18n.Tr "admin.auths.auth_name"}}</label>
|
||||
<label for="name">{{.locale.Tr "admin.auths.auth_name"}}</label>
|
||||
<input id="name" name="name" value="{{.name}}" autofocus required>
|
||||
</div>
|
||||
|
||||
|
@ -37,16 +37,16 @@
|
|||
|
||||
<!-- PAM -->
|
||||
<div class="pam required field {{if not (eq .type 4)}}hide{{end}}">
|
||||
<label for="pam_service_name">{{.i18n.Tr "admin.auths.pam_service_name"}}</label>
|
||||
<label for="pam_service_name">{{.locale.Tr "admin.auths.pam_service_name"}}</label>
|
||||
<input id="pam_service_name" name="pam_service_name" value="{{.pam_service_name}}" />
|
||||
<label for="pam_email_domain">{{.i18n.Tr "admin.auths.pam_email_domain"}}</label>
|
||||
<label for="pam_email_domain">{{.locale.Tr "admin.auths.pam_email_domain"}}</label>
|
||||
<input id="pam_email_domain" name="pam_email_domain" value="{{.pam_email_domain}}">
|
||||
</div>
|
||||
<div class="pam optional field {{if not (eq .type 4)}}hide{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if .skip_local_two_fa}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -58,67 +58,67 @@
|
|||
|
||||
<div class="ldap field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.attributes_in_bind"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.attributes_in_bind"}}</strong></label>
|
||||
<input name="attributes_in_bind" type="checkbox" {{if .attributes_in_bind}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ldap inline field {{if not (eq .type 2)}}hide{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.syncenabled"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.syncenabled"}}</strong></label>
|
||||
<input name="is_sync_enabled" type="checkbox" {{if .is_sync_enabled}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.activated"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.activated"}}</strong></label>
|
||||
<input name="is_active" type="checkbox" {{if .is_active}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<button class="ui green button">{{.i18n.Tr "admin.auths.new"}}</button>
|
||||
<button class="ui green button">{{.locale.Tr "admin.auths.new"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.auths.tips"}}
|
||||
{{.locale.Tr "admin.auths.tips"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<h5>GMail Settings:</h5>
|
||||
<p>Host: smtp.gmail.com, Port: 587, Enable TLS Encryption: true</p>
|
||||
|
||||
<h5>{{.i18n.Tr "admin.auths.tips.oauth2.general"}}:</h5>
|
||||
<p>{{.i18n.Tr "admin.auths.tips.oauth2.general.tip"}}</p>
|
||||
<h5>{{.locale.Tr "admin.auths.tips.oauth2.general"}}:</h5>
|
||||
<p>{{.locale.Tr "admin.auths.tips.oauth2.general.tip"}}</p>
|
||||
|
||||
<h5 class="ui top attached header">{{.i18n.Tr "admin.auths.tip.oauth2_provider"}}</h5>
|
||||
<h5 class="ui top attached header">{{.locale.Tr "admin.auths.tip.oauth2_provider"}}</h5>
|
||||
<div class="ui attached segment">
|
||||
<li>Bitbucket</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.bitbucket"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.bitbucket"}}</span>
|
||||
<li>Dropbox</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.dropbox"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.dropbox"}}</span>
|
||||
<li>Facebook</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.facebook"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.facebook"}}</span>
|
||||
<li>GitHub</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.github"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.github"}}</span>
|
||||
<li>GitLab</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.gitlab"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.gitlab"}}</span>
|
||||
<li>Google</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.google_plus"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.google_plus"}}</span>
|
||||
<li>OpenID Connect</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.openid_connect"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.openid_connect"}}</span>
|
||||
<li>Twitter</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.twitter"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.twitter"}}</span>
|
||||
<li>Discord</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.discord"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.discord"}}</span>
|
||||
<li>Gitea</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.gitea"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.gitea"}}</span>
|
||||
<li>Nextcloud</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.nextcloud"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.nextcloud"}}</span>
|
||||
<li>Yandex</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.yandex"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.yandex"}}</span>
|
||||
<li>Mastodon</li>
|
||||
<span>{{.i18n.Tr "admin.auths.tip.mastodon"}}</span>
|
||||
<span>{{.locale.Tr "admin.auths.tip.mastodon"}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="ldap dldap field {{if not (or (eq .type 2) (eq .type 5))}}hide{{end}}">
|
||||
<div class="inline required field {{if .Err_SecurityProtocol}}error{{end}}">
|
||||
<label>{{.i18n.Tr "admin.auths.security_protocol"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.security_protocol"}}</label>
|
||||
<div class="ui selection security-protocol dropdown">
|
||||
<input type="hidden" id="security_protocol" name="security_protocol" value="{{.security_protocol}}">
|
||||
<div class="text">{{.CurrentSecurityProtocol}}</div>
|
||||
|
@ -13,103 +13,103 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="host">{{.i18n.Tr "admin.auths.host"}}</label>
|
||||
<label for="host">{{.locale.Tr "admin.auths.host"}}</label>
|
||||
<input id="host" name="host" value="{{.host}}" placeholder="e.g. mydomain.com">
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="port">{{.i18n.Tr "admin.auths.port"}}</label>
|
||||
<label for="port">{{.locale.Tr "admin.auths.port"}}</label>
|
||||
<input id="port" name="port" value="{{.port}}" placeholder="e.g. 636">
|
||||
</div>
|
||||
<div class="has-tls inline field {{if not .HasTLS}}hide{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<input name="skip_verify" type="checkbox" {{if .skip_verify}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ldap field {{if not (eq .type 2)}}hide{{end}}">
|
||||
<label for="bind_dn">{{.i18n.Tr "admin.auths.bind_dn"}}</label>
|
||||
<label for="bind_dn">{{.locale.Tr "admin.auths.bind_dn"}}</label>
|
||||
<input id="bind_dn" name="bind_dn" value="{{.bind_dn}}" placeholder="e.g. cn=Search,dc=mydomain,dc=com">
|
||||
</div>
|
||||
<div class="ldap field {{if not (eq .type 2)}}hide{{end}}">
|
||||
<label for="bind_password">{{.i18n.Tr "admin.auths.bind_password"}}</label>
|
||||
<label for="bind_password">{{.locale.Tr "admin.auths.bind_password"}}</label>
|
||||
<input id="bind_password" name="bind_password" type="password" autocomplete="off" value="{{.bind_password}}">
|
||||
</div>
|
||||
<div class="binddnrequired {{if (eq .type 2)}}required{{end}} field">
|
||||
<label for="user_base">{{.i18n.Tr "admin.auths.user_base"}}</label>
|
||||
<label for="user_base">{{.locale.Tr "admin.auths.user_base"}}</label>
|
||||
<input id="user_base" name="user_base" value="{{.user_base}}" placeholder="e.g. ou=Users,dc=mydomain,dc=com">
|
||||
</div>
|
||||
<div class="dldap required field {{if not (eq .type 5)}}hide{{end}}">
|
||||
<label for="user_dn">{{.i18n.Tr "admin.auths.user_dn"}}</label>
|
||||
<label for="user_dn">{{.locale.Tr "admin.auths.user_dn"}}</label>
|
||||
<input id="user_dn" name="user_dn" value="{{.user_dn}}" placeholder="e.g. uid=%s,ou=Users,dc=mydomain,dc=com">
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="filter">{{.i18n.Tr "admin.auths.filter"}}</label>
|
||||
<label for="filter">{{.locale.Tr "admin.auths.filter"}}</label>
|
||||
<input id="filter" name="filter" value="{{.filter}}" placeholder="e.g. (&(objectClass=posixAccount)(uid=%s))">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="admin_filter">{{.i18n.Tr "admin.auths.admin_filter"}}</label>
|
||||
<label for="admin_filter">{{.locale.Tr "admin.auths.admin_filter"}}</label>
|
||||
<input id="admin_filter" name="admin_filter" value="{{.admin_filter}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="restricted_filter">{{.i18n.Tr "admin.auths.restricted_filter"}}</label>
|
||||
<label for="restricted_filter">{{.locale.Tr "admin.auths.restricted_filter"}}</label>
|
||||
<input id="restricted_filter" name="admin_filter" value="{{.restricted_filter}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.restricted_filter_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.restricted_filter_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_username">{{.i18n.Tr "admin.auths.attribute_username"}}</label>
|
||||
<input id="attribute_username" name="attribute_username" value="{{.attribute_username}}" placeholder="{{.i18n.Tr "admin.auths.attribute_username_placeholder"}}">
|
||||
<label for="attribute_username">{{.locale.Tr "admin.auths.attribute_username"}}</label>
|
||||
<input id="attribute_username" name="attribute_username" value="{{.attribute_username}}" placeholder="{{.locale.Tr "admin.auths.attribute_username_placeholder"}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_name">{{.i18n.Tr "admin.auths.attribute_name"}}</label>
|
||||
<label for="attribute_name">{{.locale.Tr "admin.auths.attribute_name"}}</label>
|
||||
<input id="attribute_name" name="attribute_name" value="{{.attribute_name}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_surname">{{.i18n.Tr "admin.auths.attribute_surname"}}</label>
|
||||
<label for="attribute_surname">{{.locale.Tr "admin.auths.attribute_surname"}}</label>
|
||||
<input id="attribute_surname" name="attribute_surname" value="{{.attribute_surname}}">
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="attribute_mail">{{.i18n.Tr "admin.auths.attribute_mail"}}</label>
|
||||
<label for="attribute_mail">{{.locale.Tr "admin.auths.attribute_mail"}}</label>
|
||||
<input id="attribute_mail" name="attribute_mail" value="{{.attribute_mail}}" placeholder="e.g. mail">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_ssh_public_key">{{.i18n.Tr "admin.auths.attribute_ssh_public_key"}}</label>
|
||||
<label for="attribute_ssh_public_key">{{.locale.Tr "admin.auths.attribute_ssh_public_key"}}</label>
|
||||
<input id="attribute_ssh_public_key" name="attribute_ssh_public_key" value="{{.attribute_ssh_public_key}}" placeholder="e.g. SshPublicKey">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="attribute_avatar">{{.i18n.Tr "admin.auths.attribute_avatar"}}</label>
|
||||
<label for="attribute_avatar">{{.locale.Tr "admin.auths.attribute_avatar"}}</label>
|
||||
<input id="attribute_avatar" name="attribute_avatar" value="{{.attribute_avatar}}" placeholder="e.g. jpegPhoto">
|
||||
</div>
|
||||
|
||||
<!-- ldap group begin -->
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.enable_ldap_groups"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.enable_ldap_groups"}}</strong></label>
|
||||
<input type="checkbox" name="groups_enabled" class="js-ldap-group-toggle" {{if .groups_enabled}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div id="ldap-group-options" class="ui segment secondary">
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.group_search_base"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.group_search_base"}}</label>
|
||||
<input name="group_dn" value="{{.group_dn}}" placeholder="e.g. ou=group,dc=mydomain,dc=com">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.group_attribute_list_users"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.group_attribute_list_users"}}</label>
|
||||
<input name="group_member_uid" value="{{.group_member_uid}}" placeholder="e.g. memberUid">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.user_attribute_in_group"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.user_attribute_in_group"}}</label>
|
||||
<input name="user_uid" value="{{.user_uid}}" placeholder="e.g. uid">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.verify_group_membership"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.verify_group_membership"}}</label>
|
||||
<input name="group_filter" value="{{.group_filter}}" placeholder="e.g. (|(cn=gitea_users)(cn=admins))">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{.i18n.Tr "admin.auths.map_group_to_team"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.map_group_to_team"}}</label>
|
||||
<input name="group_team_map" value="{{.group_team_map}}" placeholder='e.g. {"cn=my-group,cn=groups,dc=example,dc=org": {"MyGiteaOrganization": ["MyGiteaTeam1", "MyGiteaTeam2"]}}'>
|
||||
</div>
|
||||
<div class="ui checkbox">
|
||||
<label>{{.i18n.Tr "admin.auths.map_group_to_team_removal"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.map_group_to_team_removal"}}</label>
|
||||
<input name="group_team_map_removal" type="checkbox" {{if .group_team_map_removal}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -117,24 +117,24 @@
|
|||
|
||||
<div class="ldap inline field {{if not (eq .type 2)}}hide{{end}}">
|
||||
<div class="ui checkbox">
|
||||
<label for="use_paged_search"><strong>{{.i18n.Tr "admin.auths.use_paged_search"}}</strong></label>
|
||||
<label for="use_paged_search"><strong>{{.locale.Tr "admin.auths.use_paged_search"}}</strong></label>
|
||||
<input id="use_paged_search" name="use_paged_search" class="use-paged-search" type="checkbox" {{if .use_paged_search}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ldap field search-page-size required {{if or (not (eq .type 2)) (not .use_paged_search)}}hide{{end}}">
|
||||
<label for="search_page_size">{{.i18n.Tr "admin.auths.search_page_size"}}</label>
|
||||
<label for="search_page_size">{{.locale.Tr "admin.auths.search_page_size"}}</label>
|
||||
<input id="search_page_size" name="search_page_size" value="{{.search_page_size}}">
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if .skip_local_two_fa}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label for="allow_deactivate_all"><strong>{{.i18n.Tr "admin.auths.allow_deactivate_all"}}</strong></label>
|
||||
<label for="allow_deactivate_all"><strong>{{.locale.Tr "admin.auths.allow_deactivate_all"}}</strong></label>
|
||||
<input id="allow_deactivate_all" name="allow_deactivate_all" type="checkbox" {{if .allow_deactivate_all}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="oauth2 field {{if not (eq .type 6)}}hide{{end}}">
|
||||
<div class="inline required field">
|
||||
<label>{{.i18n.Tr "admin.auths.oauth2_provider"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.oauth2_provider"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="oauth2_provider" name="oauth2_provider" value="{{.oauth2_provider}}">
|
||||
<div class="text">{{.oauth2_provider}}</div>
|
||||
|
@ -13,53 +13,53 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="oauth2_key">{{.i18n.Tr "admin.auths.oauth2_clientID"}}</label>
|
||||
<label for="oauth2_key">{{.locale.Tr "admin.auths.oauth2_clientID"}}</label>
|
||||
<input id="oauth2_key" name="oauth2_key" value="{{.oauth2_key}}">
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="oauth2_secret">{{.i18n.Tr "admin.auths.oauth2_clientSecret"}}</label>
|
||||
<label for="oauth2_secret">{{.locale.Tr "admin.auths.oauth2_clientSecret"}}</label>
|
||||
<input id="oauth2_secret" name="oauth2_secret" value="{{.oauth2_secret}}">
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<label for="oauth2_icon_url">{{.i18n.Tr "admin.auths.oauth2_icon_url"}}</label>
|
||||
<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">
|
||||
<label for="open_id_connect_auto_discovery_url">{{.i18n.Tr "admin.auths.openIdConnectAutoDiscoveryURL"}}</label>
|
||||
<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>
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if .skip_local_two_fa}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="oauth2_use_custom_url inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.oauth2_use_custom_url"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.oauth2_use_custom_url"}}</strong></label>
|
||||
<input id="oauth2_use_custom_url" name="oauth2_use_custom_url" type="checkbox">
|
||||
</div>
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_auth_url required field">
|
||||
<label for="oauth2_auth_url">{{.i18n.Tr "admin.auths.oauth2_authURL"}}</label>
|
||||
<label for="oauth2_auth_url">{{.locale.Tr "admin.auths.oauth2_authURL"}}</label>
|
||||
<input id="oauth2_auth_url" name="oauth2_auth_url" value="{{.oauth2_auth_url}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_token_url required field">
|
||||
<label for="oauth2_token_url">{{.i18n.Tr "admin.auths.oauth2_tokenURL"}}</label>
|
||||
<label for="oauth2_token_url">{{.locale.Tr "admin.auths.oauth2_tokenURL"}}</label>
|
||||
<input id="oauth2_token_url" name="oauth2_token_url" value="{{.oauth2_token_url}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_profile_url required field">
|
||||
<label for="oauth2_profile_url">{{.i18n.Tr "admin.auths.oauth2_profileURL"}}</label>
|
||||
<label for="oauth2_profile_url">{{.locale.Tr "admin.auths.oauth2_profileURL"}}</label>
|
||||
<input id="oauth2_profile_url" name="oauth2_profile_url" value="{{.oauth2_profile_url}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_email_url required field">
|
||||
<label for="oauth2_email_url">{{.i18n.Tr "admin.auths.oauth2_emailURL"}}</label>
|
||||
<label for="oauth2_email_url">{{.locale.Tr "admin.auths.oauth2_emailURL"}}</label>
|
||||
<input id="oauth2_email_url" name="oauth2_email_url" value="{{.oauth2_email_url}}">
|
||||
</div>
|
||||
<div class="oauth2_use_custom_url_field oauth2_tenant required field">
|
||||
<label for="oauth2_tenant">{{.i18n.Tr "admin.auths.oauth2_tenant"}}</label>
|
||||
<label for="oauth2_tenant">{{.locale.Tr "admin.auths.oauth2_tenant"}}</label>
|
||||
<input id="oauth2_tenant" name="oauth2_tenant" value="{{.oauth2_tenant}}">
|
||||
</div>
|
||||
|
||||
|
@ -73,29 +73,29 @@
|
|||
{{end}}{{end}}
|
||||
|
||||
<div class="field">
|
||||
<label for="oauth2_scopes">{{.i18n.Tr "admin.auths.oauth2_scopes"}}</label>
|
||||
<label for="oauth2_scopes">{{.locale.Tr "admin.auths.oauth2_scopes"}}</label>
|
||||
<input id="oauth2_scopes" name="oauth2_scopes" values="{{.oauth2_scopes}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_required_claim_name">{{.i18n.Tr "admin.auths.oauth2_required_claim_name"}}</label>
|
||||
<label for="oauth2_required_claim_name">{{.locale.Tr "admin.auths.oauth2_required_claim_name"}}</label>
|
||||
<input id="oauth2_required_claim_name" name="oauth2_required_claim_name" values="{{.oauth2_required_claim_name}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.oauth2_required_claim_name_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.oauth2_required_claim_name_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_required_claim_value">{{.i18n.Tr "admin.auths.oauth2_required_claim_value"}}</label>
|
||||
<label for="oauth2_required_claim_value">{{.locale.Tr "admin.auths.oauth2_required_claim_value"}}</label>
|
||||
<input id="oauth2_required_claim_value" name="oauth2_required_claim_value" values="{{.oauth2_required_claim_value}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.oauth2_required_claim_value_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.oauth2_required_claim_value_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_group_claim_name">{{.i18n.Tr "admin.auths.oauth2_group_claim_name"}}</label>
|
||||
<label for="oauth2_group_claim_name">{{.locale.Tr "admin.auths.oauth2_group_claim_name"}}</label>
|
||||
<input id="oauth2_group_claim_name" name="oauth2_group_claim_name" value="{{.oauth2_group_claim_name}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_admin_group">{{.i18n.Tr "admin.auths.oauth2_admin_group"}}</label>
|
||||
<label for="oauth2_admin_group">{{.locale.Tr "admin.auths.oauth2_admin_group"}}</label>
|
||||
<input id="oauth2_admin_group" name="oauth2_admin_group" value="{{.oauth2_group_claim_name}}">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="oauth2_restricted_group">{{.i18n.Tr "admin.auths.oauth2_restricted_group"}}</label>
|
||||
<label for="oauth2_restricted_group">{{.locale.Tr "admin.auths.oauth2_restricted_group"}}</label>
|
||||
<input id="oauth2_restricted_group" name="oauth2_restricted_group" value="{{.oauth2_group_claim_name}}">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="smtp field {{if not (eq .type 3)}}hide{{end}}">
|
||||
<div class="inline required field">
|
||||
<label>{{.i18n.Tr "admin.auths.smtp_auth"}}</label>
|
||||
<label>{{.locale.Tr "admin.auths.smtp_auth"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="smtp_auth" name="smtp_auth" value="{{.smtp_auth}}">
|
||||
<div class="text">{{.smtp_auth}}</div>
|
||||
|
@ -13,47 +13,47 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="smtp_host">{{.i18n.Tr "admin.auths.smtphost"}}</label>
|
||||
<label for="smtp_host">{{.locale.Tr "admin.auths.smtphost"}}</label>
|
||||
<input id="smtp_host" name="smtp_host" value="{{.smtp_host}}">
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="smtp_port">{{.i18n.Tr "admin.auths.smtpport"}}</label>
|
||||
<label for="smtp_port">{{.locale.Tr "admin.auths.smtpport"}}</label>
|
||||
<input id="smtp_port" name="smtp_port" value="{{.smtp_port}}">
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label for="force_smtps"><strong>{{.i18n.Tr "admin.auths.force_smtps"}}</strong></label>
|
||||
<label for="force_smtps"><strong>{{.locale.Tr "admin.auths.force_smtps"}}</strong></label>
|
||||
<input id="force_smtps" name="force_smtps" type="checkbox" {{if .force_smtps}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.force_smtps_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.force_smtps_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label><strong>{{.i18n.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<label><strong>{{.locale.Tr "admin.auths.skip_tls_verify"}}</strong></label>
|
||||
<input name="skip_verify" type="checkbox" {{if .skip_verify}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="helo_hostname">{{.i18n.Tr "admin.auths.helo_hostname"}}</label>
|
||||
<label for="helo_hostname">{{.locale.Tr "admin.auths.helo_hostname"}}</label>
|
||||
<input id="helo_hostname" name="helo_hostname" value="{{.helo_hostname}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.helo_hostname_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.helo_hostname_helper"}}</p>
|
||||
</div>
|
||||
<div class="inline field">
|
||||
<div class="ui checkbox">
|
||||
<label for="disable_helo"><strong>{{.i18n.Tr "admin.auths.disable_helo"}}</strong></label>
|
||||
<label for="disable_helo"><strong>{{.locale.Tr "admin.auths.disable_helo"}}</strong></label>
|
||||
<input id="disable_helo" name="disable_helo" type="checkbox" {{if .disable_helo}}checked{{end}}>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="allowed_domains">{{.i18n.Tr "admin.auths.allowed_domains"}}</label>
|
||||
<label for="allowed_domains">{{.locale.Tr "admin.auths.allowed_domains"}}</label>
|
||||
<input id="allowed_domains" name="allowed_domains" value="{{.allowed_domains}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.allowed_domains_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.allowed_domains_helper"}}</p>
|
||||
</div>
|
||||
<div class="optional field">
|
||||
<div class="ui checkbox">
|
||||
<label for="skip_local_two_fa"><strong>{{.i18n.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<label for="skip_local_two_fa"><strong>{{.locale.Tr "admin.auths.skip_local_two_fa"}}</strong></label>
|
||||
<input id="skip_local_two_fa" name="skip_local_two_fa" type="checkbox" {{if .skip_local_two_fa}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.skip_local_two_fa_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,32 +1,32 @@
|
|||
<div class="sspi field {{if not (eq .type 7)}}hide{{end}}">
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="sspi_auto_create_users"><strong>{{.i18n.Tr "admin.auths.sspi_auto_create_users"}}</strong></label>
|
||||
<label for="sspi_auto_create_users"><strong>{{.locale.Tr "admin.auths.sspi_auto_create_users"}}</strong></label>
|
||||
<input id="sspi_auto_create_users" name="sspi_auto_create_users" class="sspi-auto-create-users" type="checkbox" {{if .SSPIAutoCreateUsers}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_auto_create_users_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_auto_create_users_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="sspi_auto_activate_users"><strong>{{.i18n.Tr "admin.auths.sspi_auto_activate_users"}}</strong></label>
|
||||
<label for="sspi_auto_activate_users"><strong>{{.locale.Tr "admin.auths.sspi_auto_activate_users"}}</strong></label>
|
||||
<input id="sspi_auto_activate_users" name="sspi_auto_activate_users" class="sspi-auto-activate-users" type="checkbox" {{if .SSPIAutoActivateUsers}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_auto_activate_users_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_auto_activate_users_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="ui checkbox">
|
||||
<label for="sspi_strip_domain_names"><strong>{{.i18n.Tr "admin.auths.sspi_strip_domain_names"}}</strong></label>
|
||||
<label for="sspi_strip_domain_names"><strong>{{.locale.Tr "admin.auths.sspi_strip_domain_names"}}</strong></label>
|
||||
<input id="sspi_strip_domain_names" name="sspi_strip_domain_names" class="sspi-strip-domain-names" type="checkbox" {{if .SSPIStripDomainNames}}checked{{end}}>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_strip_domain_names_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_strip_domain_names_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="required field">
|
||||
<label for="sspi_separator_replacement">{{.i18n.Tr "admin.auths.sspi_separator_replacement"}}</label>
|
||||
<label for="sspi_separator_replacement">{{.locale.Tr "admin.auths.sspi_separator_replacement"}}</label>
|
||||
<input id="sspi_separator_replacement" name="sspi_separator_replacement" value="{{.SSPISeparatorReplacement}}">
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_separator_replacement_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_separator_replacement_helper"}}</p>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="sspi_default_language">{{.i18n.Tr "admin.auths.sspi_default_language"}}</label>
|
||||
<label for="sspi_default_language">{{.locale.Tr "admin.auths.sspi_default_language"}}</label>
|
||||
<div class="ui language selection dropdown" id="sspi_default_language">
|
||||
<input name="sspi_default_language" type="hidden" value="{{.SSPIDefaultLanguage}}">
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
|
@ -38,6 +38,6 @@
|
|||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help">{{.i18n.Tr "admin.auths.sspi_default_language_helper"}}</p>
|
||||
<p class="help">{{.locale.Tr "admin.auths.sspi_default_language_helper"}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,22 +2,22 @@
|
|||
<!-- Sort -->
|
||||
<div class="ui dropdown type jump item">
|
||||
<span class="text">
|
||||
{{.i18n.Tr "repo.issues.filter_sort"}}
|
||||
{{.locale.Tr "repo.issues.filter_sort"}}
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
</span>
|
||||
<div class="menu">
|
||||
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||
<a class="{{if or (eq .SortType "oldest") (not .SortType)}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.oldest"}}</a>
|
||||
<a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.latest"}}</a>
|
||||
<a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
|
||||
<a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}">{{.locale.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}}</a>
|
||||
<a class="{{if eq .SortType "recentupdate"}}active{{end}} item" href="{{$.Link}}?sort=recentupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.recentupdate"}}</a>
|
||||
<a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}">{{.locale.Tr "repo.issues.filter_sort.leastupdate"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form class="ui form ignore-dirty" style="max-width: 90%;">
|
||||
<div class="ui fluid action input">
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
|
||||
<button class="ui primary button">{{.i18n.Tr "explore.search"}}</button>
|
||||
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}..." autofocus>
|
||||
<button class="ui primary button">{{.locale.Tr "explore.search"}}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -4,50 +4,50 @@
|
|||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.server_config"}}
|
||||
{{.locale.Tr "admin.config.server_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.app_name"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.app_name"}}</dt>
|
||||
<dd>{{AppName}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.app_ver"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.app_ver"}}</dt>
|
||||
<dd>{{AppVer}}{{AppBuiltWith}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.custom_conf"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.custom_conf"}}</dt>
|
||||
<dd>{{.CustomConf}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.app_url"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.app_url"}}</dt>
|
||||
<dd>{{.AppUrl}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.domain"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.domain"}}</dt>
|
||||
<dd>{{.Domain}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.offline_mode"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.offline_mode"}}</dt>
|
||||
<dd>{{if .OfflineMode}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.disable_router_log"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.disable_router_log"}}</dt>
|
||||
<dd>{{if .DisableRouterLog}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<dt>{{.i18n.Tr "admin.config.run_user"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.run_user"}}</dt>
|
||||
<dd>{{.RunUser}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.run_mode"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.run_mode"}}</dt>
|
||||
<dd>{{.RunMode}}</dd>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<dt>{{.i18n.Tr "admin.config.git_version"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.git_version"}}</dt>
|
||||
<dd>{{.GitVersion}}</dd>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<dt>{{.i18n.Tr "admin.config.repo_root_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.repo_root_path"}}</dt>
|
||||
<dd>{{.RepoRootPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.static_file_root_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.static_file_root_path"}}</dt>
|
||||
<dd>{{.StaticRootPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.custom_file_root_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.custom_file_root_path"}}</dt>
|
||||
<dd>{{.CustomRootPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.log_file_root_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.log_file_root_path"}}</dt>
|
||||
<dd>{{.LogRootPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.script_type"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.script_type"}}</dt>
|
||||
<dd>{{.ScriptType}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.reverse_auth_user"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.reverse_auth_user"}}</dt>
|
||||
<dd>{{.ReverseProxyAuthUser}}</dd>
|
||||
|
||||
{{if .EnvVars }}
|
||||
|
@ -62,33 +62,33 @@
|
|||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.ssh_config"}}
|
||||
{{.locale.Tr "admin.config.ssh_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_enabled"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_enabled"}}</dt>
|
||||
<dd>{{if not .SSH.Disabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{if not .SSH.Disabled}}
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_start_builtin_server"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_start_builtin_server"}}</dt>
|
||||
<dd>{{if .SSH.StartBuiltinServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_domain"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_domain"}}</dt>
|
||||
<dd>{{.SSH.Domain}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_port"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_port"}}</dt>
|
||||
<dd>{{.SSH.Port}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_listen_port"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_listen_port"}}</dt>
|
||||
<dd>{{.SSH.ListenPort}}</dd>
|
||||
|
||||
{{if not .SSH.StartBuiltinServer}}
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_root_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_root_path"}}</dt>
|
||||
<dd>{{.SSH.RootPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_key_test_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_key_test_path"}}</dt>
|
||||
<dd>{{.SSH.KeyTestPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_keygen_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_keygen_path"}}</dt>
|
||||
<dd>{{.SSH.KeygenPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_minimum_key_size_check"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_minimum_key_size_check"}}</dt>
|
||||
<dd>{{if .SSH.MinimumKeySizeCheck}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{if .SSH.MinimumKeySizeCheck}}
|
||||
<dt>{{.i18n.Tr "admin.config.ssh_minimum_key_sizes"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.ssh_minimum_key_sizes"}}</dt>
|
||||
<dd>{{.SSH.MinimumKeySizes}}</dd>
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
@ -97,304 +97,304 @@
|
|||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.lfs_config"}}
|
||||
{{.locale.Tr "admin.config.lfs_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.lfs_enabled"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.lfs_enabled"}}</dt>
|
||||
<dd>{{if .LFS.StartServer}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{if .LFS.StartServer}}
|
||||
<dt>{{.i18n.Tr "admin.config.lfs_content_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.lfs_content_path"}}</dt>
|
||||
<dd>{{.LFS.Path}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.lfs_http_auth_expiry"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.lfs_http_auth_expiry"}}</dt>
|
||||
<dd>{{.LFS.HTTPAuthExpiry}}</dd>
|
||||
{{end}}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.db_config"}}
|
||||
{{.locale.Tr "admin.config.db_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.db_type"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_type"}}</dt>
|
||||
<dd>{{.DbCfg.Type}}</dd>
|
||||
{{if not (eq .DbCfg.Type "sqlite3")}}
|
||||
<dt>{{.i18n.Tr "admin.config.db_host"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_host"}}</dt>
|
||||
<dd>{{if .DbCfg.Host}}{{.DbCfg.Host}}{{else}}-{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.db_name"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_name"}}</dt>
|
||||
<dd>{{if .DbCfg.Name}}{{.DbCfg.Name}}{{else}}-{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.db_user"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_user"}}</dt>
|
||||
<dd>{{if .DbCfg.User}}{{.DbCfg.User}}{{else}}-{{end}}</dd>
|
||||
{{end}}
|
||||
{{if eq .DbCfg.Type "postgres"}}
|
||||
<dt>{{.i18n.Tr "admin.config.db_schema"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_schema"}}</dt>
|
||||
<dd>{{if .DbCfg.Schema}}{{.DbCfg.Schema}}{{else}}-{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.db_ssl_mode"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_ssl_mode"}}</dt>
|
||||
<dd>{{if .DbCfg.SSLMode}}{{.DbCfg.SSLMode}}{{else}}-{{end}}</dd>
|
||||
{{end}}
|
||||
{{if eq .DbCfg.Type "sqlite3"}}
|
||||
<dt>{{.i18n.Tr "admin.config.db_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.db_path"}}</dt>
|
||||
<dd>{{if .DbCfg.Path}}{{.DbCfg.Path}}{{else}}-{{end}}</dd>
|
||||
{{end}}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.service_config"}}
|
||||
{{.locale.Tr "admin.config.service_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.register_email_confirm"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.register_email_confirm"}}</dt>
|
||||
<dd>{{if .Service.RegisterEmailConfirm}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.disable_register"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.disable_register"}}</dt>
|
||||
<dd>{{if .Service.DisableRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.allow_only_internal_registration"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.allow_only_internal_registration"}}</dt>
|
||||
<dd>{{if .Service.AllowOnlyInternalRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.allow_only_external_registration"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.allow_only_external_registration"}}</dt>
|
||||
<dd>{{if .Service.AllowOnlyExternalRegistration}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.show_registration_button"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.show_registration_button"}}</dt>
|
||||
<dd>{{if .Service.ShowRegistrationButton}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.enable_openid_signup"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.enable_openid_signup"}}</dt>
|
||||
<dd>{{if .Service.EnableOpenIDSignUp}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.enable_openid_signin"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.enable_openid_signin"}}</dt>
|
||||
<dd>{{if .Service.EnableOpenIDSignIn}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.require_sign_in_view"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.require_sign_in_view"}}</dt>
|
||||
<dd>{{if .Service.RequireSignInView}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.mail_notify"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mail_notify"}}</dt>
|
||||
<dd>{{if .Service.EnableNotifyMail}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.disable_key_size_check"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.disable_key_size_check"}}</dt>
|
||||
<dd>{{if .SSH.MinimumKeySizeCheck}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.enable_captcha"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.enable_captcha"}}</dt>
|
||||
<dd>{{if .Service.EnableCaptcha}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.default_keep_email_private"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.default_keep_email_private"}}</dt>
|
||||
<dd>{{if .Service.DefaultKeepEmailPrivate}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.default_allow_create_organization"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.default_allow_create_organization"}}</dt>
|
||||
<dd>{{if .Service.DefaultAllowCreateOrganization}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.enable_timetracking"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.enable_timetracking"}}</dt>
|
||||
<dd>{{if .Service.EnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{if .Service.EnableTimetracking}}
|
||||
<dt>{{.i18n.Tr "admin.config.default_enable_timetracking"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.default_enable_timetracking"}}</dt>
|
||||
<dd>{{if .Service.DefaultEnableTimetracking}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.default_allow_only_contributors_to_track_time"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.default_allow_only_contributors_to_track_time"}}</dt>
|
||||
<dd>{{if .Service.DefaultAllowOnlyContributorsToTrackTime}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{end}}
|
||||
<dt>{{.i18n.Tr "admin.config.default_visibility_organization"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.default_visibility_organization"}}</dt>
|
||||
<dd>{{.Service.DefaultOrgVisibility}}</dd>
|
||||
|
||||
<dt>{{.i18n.Tr "admin.config.no_reply_address"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.no_reply_address"}}</dt>
|
||||
<dd>{{if .Service.NoReplyAddress}}{{.Service.NoReplyAddress}}{{else}}-{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.default_enable_dependencies"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.default_enable_dependencies"}}</dt>
|
||||
<dd>{{if .Service.DefaultEnableDependencies}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<div class="ui divider"></div>
|
||||
<dt>{{.i18n.Tr "admin.config.active_code_lives"}}</dt>
|
||||
<dd>{{.Service.ActiveCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.reset_password_code_lives"}}</dt>
|
||||
<dd>{{.Service.ResetPwdCodeLives}} {{.i18n.Tr "tool.raw_minutes"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.active_code_lives"}}</dt>
|
||||
<dd>{{.Service.ActiveCodeLives}} {{.locale.Tr "tool.raw_minutes"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.reset_password_code_lives"}}</dt>
|
||||
<dd>{{.Service.ResetPwdCodeLives}} {{.locale.Tr "tool.raw_minutes"}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.webhook_config"}}
|
||||
{{.locale.Tr "admin.config.webhook_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.queue_length"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.queue_length"}}</dt>
|
||||
<dd>{{.Webhook.QueueLength}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.deliver_timeout"}}</dt>
|
||||
<dd>{{.Webhook.DeliverTimeout}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.skip_tls_verify"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.deliver_timeout"}}</dt>
|
||||
<dd>{{.Webhook.DeliverTimeout}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.skip_tls_verify"}}</dt>
|
||||
<dd>{{if .Webhook.SkipTLSVerify}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.mailer_config"}}
|
||||
{{.locale.Tr "admin.config.mailer_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_enabled"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_enabled"}}</dt>
|
||||
<dd>{{if .MailerEnabled}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{if .MailerEnabled}}
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_name"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_name"}}</dt>
|
||||
<dd>{{.Mailer.Name}}</dd>
|
||||
{{if eq .Mailer.MailerType "smtp"}}
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_disable_helo"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_disable_helo"}}</dt>
|
||||
<dd>{{if .DisableHelo}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_host"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_host"}}</dt>
|
||||
<dd>{{.Mailer.Host}}</dd>
|
||||
{{else if eq .Mailer.MailerType "sendmail"}}
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_use_sendmail"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_use_sendmail"}}</dt>
|
||||
<dd>{{svg "octicon-check"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_sendmail_path"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_sendmail_path"}}</dt>
|
||||
<dd>{{.Mailer.SendmailPath}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_sendmail_args"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_sendmail_args"}}</dt>
|
||||
<dd>{{.Mailer.SendmailArgs}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_sendmail_timeout"}}</dt>
|
||||
<dd>{{.Mailer.SendmailTimeout}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_sendmail_timeout"}}</dt>
|
||||
<dd>{{.Mailer.SendmailTimeout}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
{{end}}
|
||||
<dt>{{.i18n.Tr "admin.config.mailer_user"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.mailer_user"}}</dt>
|
||||
<dd>{{if .Mailer.User}}{{.Mailer.User}}{{else}}(empty){{end}}</dd><br>
|
||||
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/admin/config/test_mail" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="inline field ui left">
|
||||
<div class="ui input">
|
||||
<input type="email" name="email" placeholder="{{.i18n.Tr "admin.config.test_email_placeholder"}}" size="29" required>
|
||||
<input type="email" name="email" placeholder="{{.locale.Tr "admin.config.test_email_placeholder"}}" size="29" required>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui green button" id="test-mail-btn">{{.i18n.Tr "admin.config.send_test_mail"}}</button>
|
||||
<button class="ui green button" id="test-mail-btn">{{.locale.Tr "admin.config.send_test_mail"}}</button>
|
||||
</form>
|
||||
{{end}}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.cache_config"}}
|
||||
{{.locale.Tr "admin.config.cache_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.cache_adapter"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.cache_adapter"}}</dt>
|
||||
<dd>{{.CacheAdapter}}</dd>
|
||||
{{if eq .CacheAdapter "memory"}}
|
||||
<dt>{{.i18n.Tr "admin.config.cache_interval"}}</dt>
|
||||
<dd>{{.CacheInterval}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.cache_interval"}}</dt>
|
||||
<dd>{{.CacheInterval}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
{{end}}
|
||||
{{if .CacheConn}}
|
||||
<dt>{{.i18n.Tr "admin.config.cache_conn"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.cache_conn"}}</dt>
|
||||
<dd><code>{{.CacheConn}}</code></dd>
|
||||
<dt>{{.i18n.Tr "admin.config.cache_item_ttl"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.cache_item_ttl"}}</dt>
|
||||
<dd><code>{{.CacheItemTTL}}</code></dd>
|
||||
{{end}}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.session_config"}}
|
||||
{{.locale.Tr "admin.config.session_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.session_provider"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.session_provider"}}</dt>
|
||||
<dd>{{.SessionConfig.Provider}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.provider_config"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.provider_config"}}</dt>
|
||||
<dd><code>{{if .SessionConfig.ProviderConfig}}{{.SessionConfig.ProviderConfig}}{{else}}-{{end}}</code></dd>
|
||||
<dt>{{.i18n.Tr "admin.config.cookie_name"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.cookie_name"}}</dt>
|
||||
<dd>{{.SessionConfig.CookieName}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.gc_interval_time"}}</dt>
|
||||
<dd>{{.SessionConfig.Gclifetime}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.session_life_time"}}</dt>
|
||||
<dd>{{.SessionConfig.Maxlifetime}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.https_only"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.gc_interval_time"}}</dt>
|
||||
<dd>{{.SessionConfig.Gclifetime}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.session_life_time"}}</dt>
|
||||
<dd>{{.SessionConfig.Maxlifetime}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.https_only"}}</dt>
|
||||
<dd>{{if .SessionConfig.Secure}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.picture_config"}}
|
||||
{{.locale.Tr "admin.config.picture_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.disable_gravatar"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.disable_gravatar"}}</dt>
|
||||
<dd>{{if .DisableGravatar}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<div class="ui divider"></div>
|
||||
<dt>{{.i18n.Tr "admin.config.enable_federated_avatar"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.enable_federated_avatar"}}</dt>
|
||||
<dd>{{if .EnableFederatedAvatar}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.git_config"}}
|
||||
{{.locale.Tr "admin.config.git_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
<dt>{{.i18n.Tr "admin.config.git_disable_diff_highlight"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.git_disable_diff_highlight"}}</dt>
|
||||
<dd>{{if .Git.DisableDiffHighlight}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_max_diff_lines"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.git_max_diff_lines"}}</dt>
|
||||
<dd>{{.Git.MaxGitDiffLines}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_max_diff_line_characters"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.git_max_diff_line_characters"}}</dt>
|
||||
<dd>{{.Git.MaxGitDiffLineCharacters}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_max_diff_files"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.git_max_diff_files"}}</dt>
|
||||
<dd>{{.Git.MaxGitDiffFiles}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_gc_args"}}</dt>
|
||||
<dt>{{.locale.Tr "admin.config.git_gc_args"}}</dt>
|
||||
<dd><code>{{.Git.GCArgs}}</code></dd>
|
||||
<div class="ui divider"></div>
|
||||
<dt>{{.i18n.Tr "admin.config.git_migrate_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Migrate}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_mirror_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Mirror}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_clone_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Clone}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_pull_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Pull}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.i18n.Tr "admin.config.git_gc_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.GC}} {{.i18n.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.git_migrate_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Migrate}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.git_mirror_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Mirror}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.git_clone_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Clone}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.git_pull_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.Pull}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
<dt>{{.locale.Tr "admin.config.git_gc_timeout"}}</dt>
|
||||
<dd>{{.Git.Timeout.GC}} {{.locale.Tr "tool.raw_seconds"}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.config.log_config"}}
|
||||
{{.locale.Tr "admin.config.log_config"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<dl class="dl-horizontal admin-dl-horizontal">
|
||||
{{range .Loggers.default.SubLogDescriptions}}
|
||||
<dt>{{$.i18n.Tr "admin.config.log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_mode"}}</dt>
|
||||
<dd>{{.Name}} ({{.Provider}})</dd>
|
||||
<dt>{{$.i18n.Tr "admin.config.log_config"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_config"}}</dt>
|
||||
<dd><pre>{{.Config | JsonPrettyPrint}}</pre></dd>
|
||||
{{end}}
|
||||
<div class="ui divider"></div>
|
||||
<dt>{{$.i18n.Tr "admin.config.router_log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.router_log_mode"}}</dt>
|
||||
{{if .DisableRouterLog}}
|
||||
<dd>{{$.i18n.Tr "admin.config.disabled_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.disabled_logger"}}</dd>
|
||||
{{else}}
|
||||
{{if .Loggers.router.SubLogDescriptions}}
|
||||
<dd>{{$.i18n.Tr "admin.config.own_named_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.own_named_logger"}}</dd>
|
||||
{{range .Loggers.router.SubLogDescriptions}}
|
||||
<dt>{{$.i18n.Tr "admin.config.log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_mode"}}</dt>
|
||||
<dd>{{.Name}} ({{.Provider}})</dd>
|
||||
<dt>{{$.i18n.Tr "admin.config.log_config"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_config"}}</dt>
|
||||
<dd><pre>{{.Config | JsonPrettyPrint}}</pre></dd>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<dd>{{$.i18n.Tr "admin.config.routes_to_default_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.routes_to_default_logger"}}</dd>
|
||||
{{end}}
|
||||
{{end}}
|
||||
<div class="ui divider"></div>
|
||||
<dt>{{$.i18n.Tr "admin.config.access_log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.access_log_mode"}}</dt>
|
||||
{{if .EnableAccessLog}}
|
||||
{{if .Loggers.access.SubLogDescriptions}}
|
||||
<dd>{{$.i18n.Tr "admin.config.own_named_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.own_named_logger"}}</dd>
|
||||
{{range .Loggers.access.SubLogDescriptions}}
|
||||
<dt>{{$.i18n.Tr "admin.config.log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_mode"}}</dt>
|
||||
<dd>{{.Name}} ({{.Provider}})</dd>
|
||||
<dt>{{$.i18n.Tr "admin.config.log_config"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_config"}}</dt>
|
||||
<dd><pre>{{.Config | JsonPrettyPrint}}</pre></dd>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<dd>{{$.i18n.Tr "admin.config.routes_to_default_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.routes_to_default_logger"}}</dd>
|
||||
{{end}}
|
||||
<dt>{{$.i18n.Tr "admin.config.access_log_template"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.access_log_template"}}</dt>
|
||||
<dd><code>{{$.AccessLogTemplate}}</code></dd>
|
||||
{{else}}
|
||||
<dd>{{$.i18n.Tr "admin.config.disabled_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.disabled_logger"}}</dd>
|
||||
{{end}}
|
||||
<div class="ui divider"></div>
|
||||
<dt>{{$.i18n.Tr "admin.config.xorm_log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.xorm_log_mode"}}</dt>
|
||||
{{if .EnableXORMLog}}
|
||||
{{if .Loggers.xorm.SubLogDescriptions}}
|
||||
<dd>{{$.i18n.Tr "admin.config.own_named_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.own_named_logger"}}</dd>
|
||||
{{range .Loggers.xorm.SubLogDescriptions}}
|
||||
<dt>{{$.i18n.Tr "admin.config.log_mode"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_mode"}}</dt>
|
||||
<dd>{{.Name}} ({{.Provider}})</dd>
|
||||
<dt>{{$.i18n.Tr "admin.config.log_config"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.log_config"}}</dt>
|
||||
<dd><pre>{{.Config | JsonPrettyPrint}}</pre></dd>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<dd>{{$.i18n.Tr "admin.config.routes_to_default_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.routes_to_default_logger"}}</dd>
|
||||
{{end}}
|
||||
<dt>{{$.i18n.Tr "admin.config.xorm_log_sql"}}</dt>
|
||||
<dt>{{$.locale.Tr "admin.config.xorm_log_sql"}}</dt>
|
||||
<dd>{{if $.LogSQL}}{{svg "octicon-check"}}{{else}}{{svg "octicon-x"}}{{end}}</dd>
|
||||
{{else}}
|
||||
<dd>{{$.i18n.Tr "admin.config.disabled_logger"}}</dd>
|
||||
<dd>{{$.locale.Tr "admin.config.disabled_logger"}}</dd>
|
||||
{{end}}
|
||||
</dl>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<h4 class="ui top attached header">
|
||||
{{.i18n.Tr "admin.monitor.cron"}}
|
||||
{{.locale.Tr "admin.monitor.cron"}}
|
||||
</h4>
|
||||
<div class="ui attached table segment">
|
||||
<form method="post" action="{{AppSubUrl}}/admin">
|
||||
|
@ -7,24 +7,24 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{{.i18n.Tr "admin.monitor.name"}}</th>
|
||||
<th>{{.i18n.Tr "admin.monitor.schedule"}}</th>
|
||||
<th>{{.i18n.Tr "admin.monitor.next"}}</th>
|
||||
<th>{{.i18n.Tr "admin.monitor.previous"}}</th>
|
||||
<th>{{.i18n.Tr "admin.monitor.execute_times"}}</th>
|
||||
<th>{{.i18n.Tr "admin.monitor.last_execution_result"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.name"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.schedule"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.next"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.previous"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.execute_times"}}</th>
|
||||
<th>{{.locale.Tr "admin.monitor.last_execution_result"}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .Entries}}
|
||||
<tr>
|
||||
<td><button type="submit" class="ui green button" name="op" value="{{.Name}}" title="{{$.i18n.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
|
||||
<td>{{$.i18n.Tr (printf "admin.dashboard.%s" .Name)}}</td>
|
||||
<td><button type="submit" class="ui green button" name="op" value="{{.Name}}" title="{{$.locale.Tr "admin.dashboard.operation_run"}}">{{svg "octicon-triangle-right"}}</button></td>
|
||||
<td>{{$.locale.Tr (printf "admin.dashboard.%s" .Name)}}</td>
|
||||
<td>{{.Spec}}</td>
|
||||
<td>{{DateFmtLong .Next}}</td>
|
||||
<td>{{if gt .Prev.Year 1 }}{{DateFmtLong .Prev}}{{else}}N/A{{end}}</td>
|
||||
<td>{{.ExecTimes}}</td>
|
||||
<td {{if ne .Status ""}}class="tooltip" data-content="{{.FormatLastMessage $.i18n.Language}}"{{end}} >{{if eq .Status "" }}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}}</td>
|
||||
<td {{if ne .Status ""}}class="tooltip" data-content="{{.FormatLastMessage $.locale}}"{{end}} >{{if eq .Status "" }}—{{else if eq .Status "finished"}}{{svg "octicon-check" 16}}{{else}}{{svg "octicon-x" 16}}{{end}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue