aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony Wang2022-06-16 12:30:21 -0500
committerAnthony Wang2022-06-16 12:30:33 -0500
commit37b913476eaf374dded618a18ef16f7c34c93787 (patch)
tree1da98dec0816ec95e46a8a8016461314bf1adec1
parentd76159a2da54f5dfeed8c56f89285ce2408f3d60 (diff)
parentb35490c53d5b87e3e23d01869630ab029668e47f (diff)
Merge branch 'feature-activitypub' into feature-go-ap-inbox-outbox
-rw-r--r--cmd/doctor.go2
-rw-r--r--cmd/hook.go4
-rw-r--r--custom/conf/app.example.ini10
-rw-r--r--docs/content/doc/advanced/config-cheat-sheet.en-us.md11
-rw-r--r--docs/content/doc/advanced/config-cheat-sheet.zh-cn.md7
-rw-r--r--docs/content/doc/advanced/signing.en-us.md15
-rw-r--r--integrations/api_activitypub_person_test.go4
-rw-r--r--integrations/integration_test.go9
-rw-r--r--integrations/links_test.go12
-rw-r--r--integrations/migration-test/migration_test.go2
-rw-r--r--models/git/lfs.go5
-rw-r--r--models/issues/issue.go4
-rw-r--r--models/migrations/migrations_test.go6
-rw-r--r--models/org.go3
-rw-r--r--models/project/issue.go8
-rw-r--r--models/repo/repo_list.go69
-rw-r--r--models/unittest/testdb.go4
-rw-r--r--models/user/setting_keys.go4
-rw-r--r--modules/activitypub/client.go8
-rw-r--r--modules/activitypub/send.go6
-rw-r--r--modules/activitypub/user_settings.go22
-rw-r--r--modules/context/pagination.go1
-rw-r--r--modules/csv/csv.go2
-rw-r--r--modules/csv/csv_test.go2
-rw-r--r--modules/git/commit.go27
-rw-r--r--modules/git/git.go55
-rw-r--r--modules/git/repo_attribute.go60
-rw-r--r--modules/git/repo_compare.go8
-rw-r--r--modules/git/repo_language_stats_gogit.go31
-rw-r--r--modules/git/repo_language_stats_nogogit.go33
-rw-r--r--modules/git/repo_tree.go4
-rw-r--r--modules/markup/console/console.go8
-rw-r--r--modules/markup/csv/csv.go8
-rw-r--r--modules/markup/external/external.go12
-rw-r--r--modules/markup/html_test.go35
-rw-r--r--modules/markup/markdown/markdown.go9
-rw-r--r--modules/markup/markdown/markdown_test.go8
-rw-r--r--modules/markup/orgmode/orgmode.go9
-rw-r--r--modules/markup/renderer.go81
-rw-r--r--modules/repository/init.go22
-rw-r--r--modules/setting/federation.go5
-rw-r--r--modules/setting/markup.go37
-rw-r--r--options/locale/locale_lv-LV.ini220
-rw-r--r--options/locale/locale_zh-TW.ini258
-rw-r--r--routers/api/v1/activitypub/person.go6
-rw-r--r--routers/api/v1/activitypub/reqsignature.go4
-rw-r--r--routers/api/v1/api.go2
-rw-r--r--routers/web/explore/code.go144
-rw-r--r--routers/web/repo/compare.go4
-rw-r--r--routers/web/repo/render.go79
-rw-r--r--routers/web/repo/view.go36
-rw-r--r--routers/web/user/profile.go1
-rw-r--r--routers/web/web.go7
-rw-r--r--services/gitdiff/gitdiff.go33
-rw-r--r--services/mirror/mirror.go4
-rw-r--r--services/pull/merge.go27
-rw-r--r--services/repository/files/temp_repo.go49
-rw-r--r--templates/admin/repo/search.tmpl8
-rw-r--r--templates/explore/code.tmpl1
-rw-r--r--templates/explore/repo_list.tmpl2
-rw-r--r--templates/explore/repo_search.tmpl21
-rw-r--r--templates/explore/search.tmpl13
-rw-r--r--templates/repo/home.tmpl2
-rw-r--r--templates/swagger/v1_json.tmpl2
-rw-r--r--web_src/less/_base.less4
65 files changed, 1026 insertions, 573 deletions
diff --git a/cmd/doctor.go b/cmd/doctor.go
index 73dfeb1db..3f16c6e2a 100644
--- a/cmd/doctor.go
+++ b/cmd/doctor.go
@@ -203,7 +203,7 @@ func runDoctor(ctx *cli.Context) error {
// Now we can set up our own logger to return information about what the doctor is doing
if err := log.NewNamedLogger("doctorouter",
- 1000,
+ 0,
"console",
"console",
fmt.Sprintf(`{"level":"INFO","stacktracelevel":"NONE","colorize":%t,"flags":-1}`, colorize)); err != nil {
diff --git a/cmd/hook.go b/cmd/hook.go
index 8078763b1..73386038b 100644
--- a/cmd/hook.go
+++ b/cmd/hook.go
@@ -308,6 +308,8 @@ func runHookPostReceive(c *cli.Context) error {
ctx, cancel := installSignals()
defer cancel()
+ setup("hooks/post-receive.log", c.Bool("debug"))
+
// First of all run update-server-info no matter what
if _, _, err := git.NewCommand(ctx, "update-server-info").RunStdString(nil); err != nil {
return fmt.Errorf("Failed to call 'git update-server-info': %v", err)
@@ -318,8 +320,6 @@ func runHookPostReceive(c *cli.Context) error {
return nil
}
- setup("hooks/post-receive.log", c.Bool("debug"))
-
if len(os.Getenv("SSH_ORIGINAL_COMMAND")) == 0 {
if setting.OnlyAllowPushIfGiteaEnvironmentSet {
return fail(`Rejecting changes as Gitea environment not set.
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 2fb2c1a56..5b8d50537 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -2181,8 +2181,11 @@ PATH =
;RENDER_COMMAND = "asciidoc --out-file=- -"
;; Don't pass the file on STDIN, pass the filename as argument instead.
;IS_INPUT_FILE = false
-; Don't filter html tags and attributes if true
-;DISABLE_SANITIZER = false
+;; How the content will be rendered.
+;; * sanitized: Sanitize the content and render it inside current page, default to only allow a few HTML tags and attributes. Customized sanitizer rules can be defined in [markup.sanitizer.*] .
+;; * no-sanitizer: Disable the sanitizer and render the content inside current page. It's **insecure** and may lead to XSS attack if the content contains malicious code.
+;; * iframe: Render the content in a separate standalone page and embed it into current page by iframe. The iframe is in sandbox mode with same-origin disabled, and the JS code are safely isolated from parent page.
+;RENDER_CONTENT_MODE=sanitized
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2249,6 +2252,9 @@ PATH =
;; Enable/Disable user statistics for nodeinfo if federation is enabled
; SHARE_USER_STATISTICS = true
;;
+;; Maximum federation request and response size (MB)
+; MAX_SIZE = 4
+;;
;; HTTP signature algorithms
; ALGORITHMS = rsa-sha256, rsa-sha512
;;
diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
index 314ecf478..75c1c4014 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md
@@ -1026,13 +1026,16 @@ IS_INPUT_FILE = false
command. Multiple extensions needs a comma as splitter.
- RENDER\_COMMAND: External command to render all matching extensions.
- IS\_INPUT\_FILE: **false** Input is not a standard input but a file param followed `RENDER_COMMAND`.
-- DISABLE_SANITIZER: **false** Don't filter html tags and attributes if true. Don't change this to true except you know what that means.
+- RENDER_CONTENT_MODE: **sanitized** How the content will be rendered.
+ - sanitized: Sanitize the content and render it inside current page, default to only allow a few HTML tags and attributes. Customized sanitizer rules can be defined in `[markup.sanitizer.*]`.
+ - no-sanitizer: Disable the sanitizer and render the content inside current page. It's **insecure** and may lead to XSS attack if the content contains malicious code.
+ - iframe: Render the content in a separate standalone page and embed it into current page by iframe. The iframe is in sandbox mode with same-origin disabled, and the JS code are safely isolated from parent page.
Two special environment variables are passed to the render command:
- `GITEA_PREFIX_SRC`, which contains the current URL prefix in the `src` path tree. To be used as prefix for links.
- `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths.
-If `DISABLE_SANITIZER` is false, Gitea supports customizing the sanitization policy for rendered HTML. The example below will support KaTeX output from pandoc.
+If `RENDER_CONTENT_MODE` is `sanitized`, Gitea supports customizing the sanitization policy for rendered HTML. The example below will support KaTeX output from pandoc.
```ini
[markup.sanitizer.TeX]
@@ -1087,6 +1090,10 @@ Task queue configuration has been moved to `queue.task`. However, the below conf
- `ENABLED`: **true**: Enable/Disable federation capabilities
- `SHARE_USER_STATISTICS`: **true**: Enable/Disable user statistics for nodeinfo if federation is enabled
+- `MAX_SIZE`: **4**: Maximum federation request and response size (MB)
+
+ WARNING: Changing the settings below can break federation.
+
- `ALGORITHMS`: **rsa-sha256, rsa-sha512**: HTTP signature algorithms
- `DIGEST_ALGORITHM`: **SHA-256**: HTTP signature digest algorithm
- `GET_HEADERS`: **(request-target), Date**: GET headers for federation requests
diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
index cc6e950fb..ef1504bc9 100644
--- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
+++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md
@@ -318,14 +318,17 @@ IS_INPUT_FILE = false
- FILE_EXTENSIONS: 关联的文档的扩展名,多个扩展名用都好分隔。
- RENDER_COMMAND: 工具的命令行命令及参数。
- IS_INPUT_FILE: 输入方式是最后一个参数为文件路径还是从标准输入读取。
-- DISABLE_SANITIZER: **false** 如果为 true 则不过滤 HTML 标签和属性。除非你知道这意味着什么,否则不要设置为 true。
+- RENDER_CONTENT_MODE: **sanitized** 内容如何被渲染。
+ - sanitized: 对内容进行净化并渲染到当前页面中,仅有一部分 HTML 标签和属性是被允许的。
+ - no-sanitizer: 禁用净化器,把内容渲染到当前页面中。此模式是**不安全**的,如果内容中含有恶意代码,可能会导致 XSS 攻击。
+ - iframe: 把内容渲染在一个独立的页面中并使用 iframe 嵌入到当前页面中。使用的 iframe 工作在沙箱模式并禁用了同源请求,JS 代码被安全的从父页面中隔离出去。
以下两个环境变量将会被传递给渲染命令:
- `GITEA_PREFIX_SRC`:包含当前的`src`路径的URL前缀,可以被用于链接的前缀。
- `GITEA_PREFIX_RAW`:包含当前的`raw`路径的URL前缀,可以被用于图片的前缀。
-如果 `DISABLE_SANITIZER` 为 false,则 Gitea 支持自定义渲染 HTML 的净化策略。以下例子将用 pandoc 支持 KaTeX 输出。
+如果 `RENDER_CONTENT_MODE` 为 `sanitized`,则 Gitea 支持自定义渲染 HTML 的净化策略。以下例子将用 pandoc 支持 KaTeX 输出。
```ini
[markup.sanitizer.TeX]
diff --git a/docs/content/doc/advanced/signing.en-us.md b/docs/content/doc/advanced/signing.en-us.md
index aaaeb7103..8ae2f94e9 100644
--- a/docs/content/doc/advanced/signing.en-us.md
+++ b/docs/content/doc/advanced/signing.en-us.md
@@ -83,8 +83,7 @@ The first option to discuss is the `SIGNING_KEY`. There are three main
options:
- `none` - this prevents Gitea from signing any commits
-- `default` - Gitea will default to the key configured within
- `git config`
+- `default` - Gitea will default to the key configured within `git config`
- `KEYID` - Gitea will sign commits with the gpg key with the ID
`KEYID`. In this case you should provide a `SIGNING_NAME` and
`SIGNING_EMAIL` to be displayed for this key.
@@ -98,6 +97,12 @@ repositories, `SIGNING_KEY=default` could be used to provide different
signing keys on a per-repository basis. However, this is clearly not an
ideal UI and therefore subject to change.
+**Since 1.17**, Gitea runs git in its own home directory `[repository].ROOT` and uses its own config `{[repository].ROOT}/.gitconfig`.
+If you have your own customized git config for Gitea, you should set these configs in system git config (aka `/etc/gitconfig`)
+or the Gitea internal git config `{[repository].ROOT}/.gitconfig`.
+Related home files for git command (like `.gnupg`) should also be put in Gitea's git home directory `[repository].ROOT`.
+
+
### `INITIAL_COMMIT`
This option determines whether Gitea should sign the initial commit
@@ -118,7 +123,7 @@ The possible values are:
- `never`: Never sign
- `pubkey`: Only sign if the user has a public key
-- `twofa`: Only sign if the user logs in with two factor authentication
+- `twofa`: Only sign if the user logs in with two-factor authentication
- `parentsigned`: Only sign if the parent commit is signed.
- `always`: Always sign
@@ -132,7 +137,7 @@ editor or API CRUD actions. The possible values are:
- `never`: Never sign
- `pubkey`: Only sign if the user has a public key
-- `twofa`: Only sign if the user logs in with two factor authentication
+- `twofa`: Only sign if the user logs in with two-factor authentication
- `parentsigned`: Only sign if the parent commit is signed.
- `always`: Always sign
@@ -146,7 +151,7 @@ The possible options are:
- `never`: Never sign
- `pubkey`: Only sign if the user has a public key
-- `twofa`: Only sign if the user logs in with two factor authentication
+- `twofa`: Only sign if the user logs in with two-factor authentication
- `basesigned`: Only sign if the parent commit in the base repo is signed.
- `headsigned`: Only sign if the head commit in the head branch is signed.
- `commitssigned`: Only sign if all the commits in the head branch to the merge point are signed.
diff --git a/integrations/api_activitypub_person_test.go b/integrations/api_activitypub_person_test.go
index 70f1134fa..4898d5e01 100644
--- a/integrations/api_activitypub_person_test.go
+++ b/integrations/api_activitypub_person_test.go
@@ -38,7 +38,7 @@ func TestActivityPubPerson(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, ap.PersonType, person.Type)
- assert.Equal(t, username, person.Name.String())
+ assert.Equal(t, username, person.PreferredUsername.String())
keyID := person.GetID().String()
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), keyID)
assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/outbox$", username), person.Outbox.GetID().String())
@@ -64,7 +64,7 @@ func TestActivityPubMissingPerson(t *testing.T) {
req := NewRequestf(t, "GET", "/api/v1/activitypub/user/nonexistentuser")
resp := MakeRequest(t, req, http.StatusNotFound)
- assert.Contains(t, resp.Body.String(), "GetUserByName")
+ assert.Contains(t, resp.Body.String(), "user redirect does not exist")
})
}
diff --git a/integrations/integration_test.go b/integrations/integration_test.go
index ce21eb2ef..b0004927f 100644
--- a/integrations/integration_test.go
+++ b/integrations/integration_test.go
@@ -174,7 +174,12 @@ func initIntegrationTest() {
setting.LoadForTest()
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
_ = util.RemoveAll(repo_module.LocalCopyPath())
+
+ if err := git.InitOnceWithSync(context.Background()); err != nil {
+ log.Fatal("git.InitOnceWithSync: %v", err)
+ }
git.CheckLFSVersion()
+
setting.InitDBConfig()
if err := storage.Init(); err != nil {
fmt.Printf("Init storage failed: %v", err)
@@ -275,7 +280,7 @@ func prepareTestEnv(t testing.TB, skip ...int) func() {
assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background()))
+ assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@@ -576,7 +581,7 @@ func resetFixtures(t *testing.T) {
assert.NoError(t, unittest.LoadFixtures())
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background()))
+ assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
diff --git a/integrations/links_test.go b/integrations/links_test.go
index bc87ffad8..d0cf978f6 100644
--- a/integrations/links_test.go
+++ b/integrations/links_test.go
@@ -22,11 +22,11 @@ func TestLinksNoLogin(t *testing.T) {
links := []string{
"/explore/repos",
- "/explore/repos?q=test&tab=",
+ "/explore/repos?q=test",
"/explore/users",
- "/explore/users?q=test&tab=",
+ "/explore/users?q=test",
"/explore/organizations",
- "/explore/organizations?q=test&tab=",
+ "/explore/organizations?q=test",
"/",
"/user/sign_up",
"/user/login",
@@ -81,11 +81,11 @@ func TestNoLoginNotExist(t *testing.T) {
func testLinksAsUser(userName string, t *testing.T) {
links := []string{
"/explore/repos",
- "/explore/repos?q=test&tab=",
+ "/explore/repos?q=test",
"/explore/users",
- "/explore/users?q=test&tab=",
+ "/explore/users?q=test",
"/explore/organizations",
- "/explore/organizations?q=test&tab=",
+ "/explore/organizations?q=test",
"/",
"/user/forgot_password",
"/api/swagger",
diff --git a/integrations/migration-test/migration_test.go b/integrations/migration-test/migration_test.go
index 83c31d801..20a5c903a 100644
--- a/integrations/migration-test/migration_test.go
+++ b/integrations/migration-test/migration_test.go
@@ -62,7 +62,6 @@ func initMigrationTest(t *testing.T) func() {
assert.True(t, len(setting.RepoRootPath) != 0)
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background()))
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
@@ -83,6 +82,7 @@ func initMigrationTest(t *testing.T) func() {
}
}
+ assert.NoError(t, git.InitOnceWithSync(context.Background()))
git.CheckLFSVersion()
setting.InitDBConfig()
setting.NewLogServices(true)
diff --git a/models/git/lfs.go b/models/git/lfs.go
index 13b8b234f..ec963cf59 100644
--- a/models/git/lfs.go
+++ b/models/git/lfs.go
@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
@@ -213,7 +214,7 @@ func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) {
count, err := db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
return count > 0, err
}
- cond := repo_model.AccessibleRepositoryCondition(user)
+ cond := repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)
count, err := db.GetEngine(db.DefaultContext).Where(cond).Join("INNER", "repository", "`lfs_meta_object`.repository_id = `repository`.id").Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}})
return count > 0, err
}
@@ -244,7 +245,7 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6
newMetas := make([]*LFSMetaObject, 0, len(metas))
cond := builder.In(
"`lfs_meta_object`.repository_id",
- builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user)),
+ builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)),
)
err = sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas)
if err != nil {
diff --git a/models/issues/issue.go b/models/issues/issue.go
index 0f4af3e84..76a0ea7d0 100644
--- a/models/issues/issue.go
+++ b/models/issues/issue.go
@@ -1430,7 +1430,7 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organizati
cond = cond.And(
builder.Or(
repo_model.UserOwnedRepoCond(userID), // owned repos
- repo_model.UserCollaborationRepoCond(repoIDstr, userID), // collaboration repos
+ repo_model.UserAccessRepoCond(repoIDstr, userID), // user can access repo in a unit independent way
repo_model.UserAssignedRepoCond(repoIDstr, userID), // user has been assigned accessible public repos
repo_model.UserMentionedRepoCond(repoIDstr, userID), // user has been mentioned accessible public repos
repo_model.UserCreateIssueRepoCond(repoIDstr, userID, isPull), // user has created issue/pr accessible public repos
@@ -1499,7 +1499,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i
opts.setupSessionNoLimit(sess)
- accessCond := repo_model.AccessibleRepositoryCondition(user)
+ accessCond := repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)
if err := sess.Where(accessCond).
Distinct("issue.repo_id").
Table("issue").
diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go
index 0c8e74f73..46782f24a 100644
--- a/models/migrations/migrations_test.go
+++ b/models/migrations/migrations_test.go
@@ -66,6 +66,10 @@ func TestMain(m *testing.M) {
setting.SetCustomPathAndConf("", "", "")
setting.LoadForTest()
+ if err = git.InitOnceWithSync(context.Background()); err != nil {
+ fmt.Printf("Unable to InitOnceWithSync: %v\n", err)
+ os.Exit(1)
+ }
git.CheckLFSVersion()
setting.InitDBConfig()
setting.NewLogServices(true)
@@ -203,7 +207,7 @@ func prepareTestEnv(t *testing.T, skip int, syncModels ...interface{}) (*xorm.En
deferFn := PrintCurrentTest(t, ourSkip)
assert.NoError(t, os.RemoveAll(setting.RepoRootPath))
assert.NoError(t, unittest.CopyDir(path.Join(filepath.Dir(setting.AppPath), "integrations/gitea-repositories-meta"), setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background()))
+ assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
assert.NoError(t, err, "unable to read the new repo root: %v\n", err)
diff --git a/models/org.go b/models/org.go
index 009fe758b..849c9b985 100644
--- a/models/org.go
+++ b/models/org.go
@@ -14,6 +14,7 @@ import (
"code.gitea.io/gitea/models/organization"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
user_model "code.gitea.io/gitea/models/user"
"xorm.io/builder"
@@ -54,7 +55,7 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) {
Join("LEFT", builder.
Select("id as repo_id, owner_id as repo_owner_id").
From("repository").
- Where(repo_model.AccessibleRepositoryCondition(user)), "`repository`.repo_owner_id = `team`.org_id").
+ Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), "`repository`.repo_owner_id = `team`.org_id").
Where("`team_user`.uid = ?", user.ID).
GroupBy(groupByStr)
diff --git a/models/project/issue.go b/models/project/issue.go
index 04efc0e74..6e6a8c574 100644
--- a/models/project/issue.go
+++ b/models/project/issue.go
@@ -9,6 +9,7 @@ import (
"fmt"
"code.gitea.io/gitea/models/db"
+ "code.gitea.io/gitea/modules/log"
)
// ProjectIssue saves relation from issue to a project
@@ -41,6 +42,7 @@ func (p *Project) NumIssues() int {
Cols("issue_id").
Count()
if err != nil {
+ log.Error("NumIssues: %v", err)
return 0
}
return int(c)
@@ -54,6 +56,7 @@ func (p *Project) NumClosedIssues() int {
Cols("issue_id").
Count()
if err != nil {
+ log.Error("NumClosedIssues: %v", err)
return 0
}
return int(c)
@@ -63,8 +66,11 @@ func (p *Project) NumClosedIssues() int {
func (p *Project) NumOpenIssues() int {
c, err := db.GetEngine(db.DefaultContext).Table("project_issue").
Join("INNER", "issue", "project_issue.issue_id=issue.id").
- Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false).Count("issue.id")
+ Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false).
+ Cols("issue_id").
+ Count()
if err != nil {
+ log.Error("NumOpenIssues: %v", err)
return 0
}
return int(c)
diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go
index 1bec35d57..a70fc8efd 100644
--- a/models/repo/repo_list.go
+++ b/models/repo/repo_list.go
@@ -269,8 +269,8 @@ func UserMentionedRepoCond(id string, userID int64) builder.Cond {
)
}
-// UserCollaborationRepoCond returns user as collabrators repositories list
-func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond {
+// UserAccessRepoCond returns a condition for selecting all repositories a user has unit independent access to
+func UserAccessRepoCond(idStr string, userID int64) builder.Cond {
return builder.In(idStr, builder.Select("repo_id").
From("`access`").
Where(builder.And(
@@ -280,8 +280,18 @@ func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond {
)
}
-// userOrgTeamRepoCond selects repos that the given user has access to through team membership
-func userOrgTeamRepoCond(idStr string, userID int64) builder.Cond {
+// userCollaborationRepoCond returns a condition for selecting all repositories a user is collaborator in
+func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond {
+ return builder.In(idStr, builder.Select("repo_id").
+ From("`collaboration`").
+ Where(builder.And(
+ builder.Eq{"`collaboration`.user_id": userID},
+ )),
+ )
+}
+
+// UserOrgTeamRepoCond selects repos that the given user has access to through team membership
+func UserOrgTeamRepoCond(idStr string, userID int64) builder.Cond {
return builder.In(idStr, userOrgTeamRepoBuilder(userID))
}
@@ -297,7 +307,13 @@ func userOrgTeamRepoBuilder(userID int64) *builder.Builder {
func userOrgTeamUnitRepoBuilder(userID int64, unitType unit.Type) *builder.Builder {
return userOrgTeamRepoBuilder(userID).
Join("INNER", "team_unit", "`team_unit`.team_id = `team_repo`.team_id").
- Where(builder.Eq{"`team_unit`.`type`": unitType})
+ Where(builder.Eq{"`team_unit`.`type`": unitType}).
+ And(builder.Gt{"`team_unit`.`access_mode`": int(perm.AccessModeNone)})
+}
+
+// userOrgTeamUnitRepoCond returns a condition to select repo ids where user's teams can access the special unit.
+func userOrgTeamUnitRepoCond(idStr string, userID int64, unitType unit.Type) builder.Cond {
+ return builder.In(idStr, userOrgTeamUnitRepoBuilder(userID, unitType))
}
// UserOrgUnitRepoCond selects repos that the given user has access to through org and the special unit
@@ -350,7 +366,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
if opts.Private {
if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID {
// OK we're in the context of a User
- cond = cond.And(AccessibleRepositoryCondition(opts.Actor))
+ cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid))
}
} else {
// Not looking at private organisations and users
@@ -395,10 +411,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
builder.Neq{"owner_id": opts.OwnerID},
// 2. But we can see because of:
builder.Or(
- // A. We have access
- UserCollaborationRepoCond("`repository`.id", opts.OwnerID),
+ // A. We have unit independent access
+ UserAccessRepoCond("`repository`.id", opts.OwnerID),
// B. We are in a team for
- userOrgTeamRepoCond("`repository`.id", opts.OwnerID),
+ UserOrgTeamRepoCond("`repository`.id", opts.OwnerID),
// C. Public repositories in organizations that we are member of
userOrgPublicRepoCondPrivate(opts.OwnerID),
),
@@ -479,7 +495,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond {
}
if opts.Actor != nil && opts.Actor.IsRestricted {
- cond = cond.And(AccessibleRepositoryCondition(opts.Actor))
+ cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid))
}
if opts.Archived != util.OptionalBoolNone {
@@ -574,7 +590,7 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c
}
// AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible
-func AccessibleRepositoryCondition(user *user_model.User) builder.Cond {
+func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) builder.Cond {
cond := builder.NewCond()
if user == nil || !user.IsRestricted || user.ID <= 0 {
@@ -594,13 +610,24 @@ func AccessibleRepositoryCondition(user *user_model.User) builder.Cond {
}
if user != nil {
+ // 2. Be able to see all repositories that we have unit independent access to
+ // 3. Be able to see all repositories through team membership(s)
+ if unitType == unit.TypeInvalid {
+ // Regardless of UnitType
+ cond = cond.Or(
+ UserAccessRepoCond("`repository`.id", user.ID),
+ UserOrgTeamRepoCond("`repository`.id", user.ID),
+ )
+ } else {
+ // For a specific UnitType
+ cond = cond.Or(
+ UserCollaborationRepoCond("`repository`.id", user.ID),
+ userOrgTeamUnitRepoCond("`repository`.id", user.ID, unitType),
+ )
+ }
cond = cond.Or(
- // 2. Be able to see all repositories that we have access to
- UserCollaborationRepoCond("`repository`.id", user.ID),
- // 3. Repositories that we directly own
+ // 4. Repositories that we directly own
builder.Eq{"`repository`.owner_id": user.ID},
- // 4. Be able to see all repositories that we are in a team
- userOrgTeamRepoCond("`repository`.id", user.ID),
// 5. Be able to see all public repos in private organizations that we are an org_user of
userOrgPublicRepoCond(user.ID),
)
@@ -645,18 +672,18 @@ func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) {
// AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered.
func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder {
// NB: Please note this code needs to still work if user is nil
- return builder.Select("id").From("repository").Where(AccessibleRepositoryCondition(user))
+ return builder.Select("id").From("repository").Where(AccessibleRepositoryCondition(user, unit.TypeInvalid))
}
-// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id
-func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) {
+// FindUserCodeAccessibleRepoIDs finds all at Code level accessible repositories' ID by the user's id
+func FindUserCodeAccessibleRepoIDs(user *user_model.User) ([]int64, error) {
repoIDs := make([]int64, 0, 10)
if err := db.GetEngine(db.DefaultContext).
Table("repository").
Cols("id").
- Where(AccessibleRepositoryCondition(user)).
+ Where(AccessibleRepositoryCondition(user, unit.TypeCode)).
Find(&repoIDs); err != nil {
- return nil, fmt.Errorf("FindUserAccesibleRepoIDs: %v", err)
+ return nil, fmt.Errorf("FindUserCodeAccesibleRepoIDs: %v", err)
}
return repoIDs, nil
}
diff --git a/models/unittest/testdb.go b/models/unittest/testdb.go
index d1a449851..baea46dbc 100644
--- a/models/unittest/testdb.go
+++ b/models/unittest/testdb.go
@@ -117,9 +117,11 @@ func MainTest(m *testing.M, testOpts *TestOptions) {
if err = CopyDir(filepath.Join(testOpts.GiteaRootPath, "integrations", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
fatalTestError("util.CopyDir: %v\n", err)
}
+
if err = git.InitOnceWithSync(context.Background()); err != nil {
fatalTestError("git.Init: %v\n", err)
}
+ git.CheckLFSVersion()
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
if err != nil {
@@ -202,7 +204,7 @@ func PrepareTestEnv(t testing.TB) {
assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
assert.NoError(t, CopyDir(metaPath, setting.RepoRootPath))
- assert.NoError(t, git.InitOnceWithSync(context.Background()))
+ assert.NoError(t, git.InitOnceWithSync(context.Background())) // the gitconfig has been removed above, so sync the gitconfig again
ownerDirs, err := os.ReadDir(setting.RepoRootPath)
assert.NoError(t, err)
diff --git a/models/user/setting_keys.go b/models/user/setting_keys.go
index 109b5dd91..d48ac9305 100644
--- a/models/user/setting_keys.go
+++ b/models/user/setting_keys.go
@@ -9,4 +9,8 @@ const (
SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types"
// SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff
SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour"
+ // UserActivityPubPrivPem is user's private key
+ UserActivityPubPrivPem = "activitypub.priv_pem"
+ // UserActivityPubPubPem is user's public key
+ UserActivityPubPubPem = "activitypub.pub_pem"
)
diff --git a/modules/activitypub/client.go b/modules/activitypub/client.go
index b04706dd0..8c2854f71 100644
--- a/modules/activitypub/client.go
+++ b/modules/activitypub/client.go
@@ -27,6 +27,11 @@ const (
httpsigExpirationTime = 60
)
+// Gets the current time as an RFC 2616 formatted string
+func CurrentTime() string {
+ return strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT")
+}
+
func containsRequiredHTTPHeaders(method string, headers []string) error {
var hasRequestTarget, hasDate, hasDigest bool
for _, header := range headers {
@@ -98,8 +103,7 @@ func (c *Client) NewRequest(b []byte, to string) (req *http.Request, err error)
}
req.Header.Add("Content-Type", ActivityStreamsContentType)
req.Header.Add("Accept-Charset", "utf-8")
- req.Header.Add("Date", strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT"))
-
+ req.Header.Add("Date", CurrentTime())
signer, _, err := httpsig.NewSigner(c.algs, c.digestAlg, c.postHeaders, httpsig.Signature, httpsigExpirationTime)
if err != nil {
return
diff --git a/modules/activitypub/send.go b/modules/activitypub/send.go
index cf65660e2..e0266c488 100644
--- a/modules/activitypub/send.go
+++ b/modules/activitypub/send.go
@@ -9,8 +9,6 @@ import (
"io"
"net/http"
"net/url"
- "strings"
- "time"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/httplib"
@@ -25,7 +23,7 @@ func Fetch(iri *url.URL) (b []byte, err error) {
req := httplib.NewRequest(iri.String(), http.MethodGet)
req.Header("Accept", ActivityStreamsContentType)
req.Header("Accept-Charset", "utf-8")
- req.Header("Date", strings.ReplaceAll(time.Now().UTC().Format(time.RFC1123), "UTC", "GMT"))
+ req.Header("Date", CurrentTime())
resp, err := req.Response()
if err != nil {
return
@@ -36,7 +34,7 @@ func Fetch(iri *url.URL) (b []byte, err error) {
err = fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status)
return
}
- b, err = io.ReadAll(resp.Body)
+ b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize))
return
}
diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go
index 3289d45c5..2144e7b47 100644
--- a/modules/activitypub/user_settings.go
+++ b/modules/activitypub/user_settings.go
@@ -8,41 +8,37 @@ import (
user_model "code.gitea.io/gitea/models/user"
)
-const (
- userActivitypubPrivpem = "activitypub_privpem"
- userActivitypubPubpem = "activitypub_pubpem"
-)
-
-// GetKeyPair function
+// GetKeyPair function returns a user's private and public keys
func GetKeyPair(user *user_model.User) (pub, priv string, err error) {
var settings map[string]*user_model.Setting
- if settings, err = user_model.GetUserSettings(user.ID, []string{userActivitypubPrivpem, userActivitypubPubpem}); err != nil {
+ settings, err = user_model.GetUserSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem})
+ if err != nil {
return
} else if len(settings) == 0 {
if priv, pub, err = GenerateKeyPair(); err != nil {
return
}
- if err = user_model.SetUserSetting(user.ID, userActivitypubPrivpem, priv); err != nil {
+ if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, priv); err != nil {
return
}
- if err = user_model.SetUserSetting(user.ID, userActivitypubPubpem, pub); err != nil {
+ if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, pub); err != nil {
return
}
return
} else {
- priv = settings[userActivitypubPrivpem].SettingValue
- pub = settings[userActivitypubPubpem].SettingValue
+ priv = settings[user_model.UserActivityPubPrivPem].SettingValue
+ pub = settings[user_model.UserActivityPubPubPem].SettingValue
return
}
}
-// GetPublicKey function
+// GetPublicKey function returns a user's public key
func GetPublicKey(user *user_model.User) (pub string, err error) {
pub, _, err = GetKeyPair(user)
return
}
-// GetPrivateKey function
+// GetPrivateKey function returns a user's private key
func GetPrivateKey(user *user_model.User) (priv string, err error) {
_, priv, err = GetKeyPair(user)
return
diff --git a/modules/context/pagination.go b/modules/context/pagination.go
index c0079c295..617b472f0 100644
--- a/modules/context/pagination.go
+++ b/modules/context/pagination.go
@@ -52,7 +52,6 @@ func (p *Pagination) GetParams() template.URL {
func (p *Pagination) SetDefaultParams(ctx *Context) {
p.AddParam(ctx, "sort", "SortType")
p.AddParam(ctx, "q", "Keyword")
- p.AddParam(ctx, "tab", "TabName")
// do not add any more uncommon params here!
p.AddParam(ctx, "t", "queryType")
}
diff --git a/modules/csv/csv.go b/modules/csv/csv.go
index 0dd54271f..fe0c35096 100644
--- a/modules/csv/csv.go
+++ b/modules/csv/csv.go
@@ -54,7 +54,7 @@ func CreateReaderAndDetermineDelimiter(ctx *markup.RenderContext, rd io.Reader)
func determineDelimiter(ctx *markup.RenderContext, data []byte) rune {
extension := ".csv"
if ctx != nil {
- extension = strings.ToLower(filepath.Ext(ctx.Filename))
+ extension = strings.ToLower(filepath.Ext(ctx.RelativePath))
}
var delimiter rune
diff --git a/modules/csv/csv_test.go b/modules/csv/csv_test.go
index b1e928ae9..9d0848ae5 100644
--- a/modules/csv/csv_test.go
+++ b/modules/csv/csv_test.go
@@ -230,7 +230,7 @@ John Doe john@doe.com This,note,had,a,lot,of,commas,to,test,delimiters`,
}
for n, c := range cases {
- delimiter := determineDelimiter(&markup.RenderContext{Filename: c.filename}, []byte(decodeSlashes(t, c.csv)))
+ delimiter := determineDelimiter(&markup.RenderContext{RelativePath: c.filename}, []byte(decodeSlashes(t, c.csv)))
assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter)
}
}
diff --git a/modules/git/commit.go b/modules/git/commit.go
index 99fbbd0cf..82b5e0b25 100644
--- a/modules/git/commit.go
+++ b/modules/git/commit.go
@@ -206,26 +206,17 @@ func (c *Commit) HasPreviousCommit(commitHash SHA1) (bool, error) {
return false, nil
}
- if err := CheckGitVersionAtLeast("1.8"); err == nil {
- _, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
- if err == nil {
- return true, nil
+ _, _, err := NewCommand(c.repo.Ctx, "merge-base", "--is-ancestor", that, this).RunStdString(&RunOpts{Dir: c.repo.Path})
+ if err == nil {
+ return true, nil
+ }
+ var exitError *exec.ExitError
+ if errors.As(err, &exitError) {
+ if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
+ return false, nil
}
- var exitError *exec.ExitError
- if errors.As(err, &exitError) {
- if exitError.ProcessState.ExitCode() == 1 && len(exitError.Stderr) == 0 {
- return false, nil
- }
- }
- return false, err
- }
-
- result, _, err := NewCommand(c.repo.Ctx, "rev-list", "--ancestry-path", "-n1", that+".."+this, "--").RunStdString(&RunOpts{Dir: c.repo.Path})
- if err != nil {
- return false, err
}
-
- return len(strings.TrimSpace(result)) > 0, nil
+ return false, err
}
// CommitsBeforeLimit returns num commits before current revision
diff --git a/modules/git/git.go b/modules/git/git.go
index 0459f57dd..d789a576b 100644
--- a/modules/git/git.go
+++ b/modules/git/git.go
@@ -7,10 +7,10 @@ package git
import (
"context"
+ "errors"
"fmt"
"os"
"os/exec"
- "path/filepath"
"runtime"
"strings"
"sync"
@@ -22,20 +22,16 @@ import (
"github.com/hashicorp/go-version"
)
-var (
- // GitVersionRequired is the minimum Git version required
- // At the moment, all code for git 1.x are not changed, if some users want to test with old git client
- // or bypass the check, they still have a chance to edit this variable manually.
- // If everything works fine, the code for git 1.x could be removed in a separate PR before 1.17 frozen.
- GitVersionRequired = "2.0.0"
+// GitVersionRequired is the minimum Git version required
+const GitVersionRequired = "2.0.0"
+var (
// GitExecutable is the command name of git
// Could be updated to an absolute path while initialization
GitExecutable = "git"
- // DefaultContext is the default context to run git commands in
- // will be overwritten by InitXxx with HammerContext
- DefaultContext = context.Background()
+ // DefaultContext is the default context to run git commands in, must be initialized by git.InitXxx
+ DefaultContext context.Context
// SupportProcReceive version >= 2.29.0
SupportProcReceive bool
@@ -128,36 +124,43 @@ func VersionInfo() string {
return fmt.Sprintf(format, args...)
}
+func checkInit() error {
+ if setting.RepoRootPath == "" {
+ return errors.New("can not init Git's HomeDir (RepoRootPath is empty), the setting and git modules are not initialized correctly")
+ }
+ if DefaultContext != nil {
+ log.Warn("git module has been initialized already, duplicate init should be fixed")
+ }
+ return nil
+}
+
// HomeDir is the home dir for git to store the global config file used by Gitea internally
func HomeDir() string {
if setting.RepoRootPath == "" {
- // TODO: now, some unit test code call the git module directly without initialization, which is incorrect.
- // at the moment, we just use a temp HomeDir to prevent from conflicting with user's git config
- // in the future, the git module should be initialized first before use.
- tmpHomeDir := filepath.Join(os.TempDir(), "gitea-temp-home")
- log.Error("Git's HomeDir is empty (RepoRootPath is empty), the git module is not initialized correctly, using a temp HomeDir (%s) temporarily", tmpHomeDir)
- return tmpHomeDir
+ // strict check, make sure the git module is initialized correctly.
+ // attention: when the git module is called in gitea sub-command (serv/hook), the log module is not able to show messages to users.
+ // for example: if there is gitea git hook code calling git.NewCommand before git.InitXxx, the integration test won't show the real failure reasons.
+ log.Fatal("can not get Git's HomeDir (RepoRootPath is empty), the setting and git modules are not initialized correctly")
+ return ""
}
return setting.RepoRootPath
}
// InitSimple initializes git module with a very simple step, no config changes, no global command arguments.
// This method doesn't change anything to filesystem. At the moment, it is only used by "git serv" sub-command, no data-race
+// However, in integration test, the sub-command function may be called in the current process, so the InitSimple would be called multiple times, too
func InitSimple(ctx context.Context) error {
+ if err := checkInit(); err != nil {
+ return err
+ }
+
DefaultContext = ctx
if setting.Git.Timeout.Default > 0 {
defaultCommandExecutionTimeout = time.Duration(setting.Git.Timeout.Default) * time.Second
}
- if err := SetExecutablePath(setting.Git.Path); err != nil {
- return err
- }
-
- // force cleanup args
- globalCommandArgs = []string{}
-
- return nil
+ return SetExecutablePath(setting.Git.Path)
}
var initOnce sync.Once
@@ -166,6 +169,10 @@ var initOnce sync.Once
// This method will update the global variables ONLY ONCE (just like git.CheckLFSVersion -- which is not ideal too),
// otherwise there will be data-race problem at the moment.
func InitOnceWithSync(ctx context.Context) (err error) {
+ if err = checkInit(); err != nil {
+ return err
+ }
+
initOnce.Do(func() {
err = InitSimple(ctx)
if err != nil {
diff --git a/modules/git/repo_attribute.go b/modules/git/repo_attribute.go
index 38818788f..596a91e80 100644
--- a/modules/git/repo_attribute.go
+++ b/modules/git/repo_attribute.go
@@ -30,10 +30,10 @@ type CheckAttributeOpts struct {
func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[string]string, error) {
env := []string{}
- if len(opts.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
+ if len(opts.IndexFile) > 0 {
env = append(env, "GIT_INDEX_FILE="+opts.IndexFile)
}
- if len(opts.WorkTree) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
+ if len(opts.WorkTree) > 0 {
env = append(env, "GIT_WORK_TREE="+opts.WorkTree)
}
@@ -56,8 +56,7 @@ func (repo *Repository) CheckAttribute(opts CheckAttributeOpts) (map[string]map[
}
}
- // git check-attr --cached first appears in git 1.7.8
- if opts.CachedOnly && CheckGitVersionAtLeast("1.7.8") == nil {
+ if opts.CachedOnly {
cmdArgs = append(cmdArgs, "--cached")
}
@@ -125,12 +124,12 @@ type CheckAttributeReader struct {
func (c *CheckAttributeReader) Init(ctx context.Context) error {
cmdArgs := []string{"check-attr", "--stdin", "-z"}
- if len(c.IndexFile) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
+ if len(c.IndexFile) > 0 {
cmdArgs = append(cmdArgs, "--cached")
c.env = append(c.env, "GIT_INDEX_FILE="+c.IndexFile)
}
- if len(c.WorkTree) > 0 && CheckGitVersionAtLeast("1.7.8") == nil {
+ if len(c.WorkTree) > 0 {
c.env = append(c.env, "GIT_WORK_TREE="+c.WorkTree)
}
@@ -160,17 +159,10 @@ func (c *CheckAttributeReader) Init(ctx context.Context) error {
return err
}
- if CheckGitVersionAtLeast("1.8.5") == nil {
- lw := new(nulSeparatedAttributeWriter)
- lw.attributes = make(chan attributeTriple, 5)
- lw.closed = make(chan struct{})
- c.stdOut = lw
- } else {
- lw := new(lineSeparatedAttributeWriter)
- lw.attributes = make(chan attributeTriple, 5)
- lw.closed = make(chan struct{})
- c.stdOut = lw
- }
+ lw := new(nulSeparatedAttributeWriter)
+ lw.attributes = make(chan attributeTriple, 5)
+ lw.closed = make(chan struct{})
+ c.stdOut = lw
return nil
}
@@ -400,3 +392,37 @@ func (wr *lineSeparatedAttributeWriter) Close() error {
close(wr.closed)
return nil
}
+
+// Create a check attribute reader for the current repository and provided commit ID
+func (repo *Repository) CheckAttributeReader(commitID string) (*CheckAttributeReader, context.CancelFunc) {
+ indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)
+ if err != nil {
+ return nil, func() {}
+ }
+
+ checker := &CheckAttributeReader{
+ Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language"},
+ Repo: repo,
+ IndexFile: indexFilename,
+ WorkTree: worktree,
+ }
+ ctx, cancel := context.WithCancel(repo.Ctx)
+ if err := checker.Init(ctx); err != nil {
+ log.Error("Unable to open checker for %s. Error: %v", commitID, err)
+ } else {
+ go func() {
+ err := checker.Run()
+ if err != nil && err != ctx.Err() {
+ log.Error("Unable to open checker for %s. Error: %v", commitID, err)
+ }
+ cancel()
+ }()
+ }
+ deferable := func() {
+ _ = checker.Close()
+ cancel()
+ deleteTemporaryFile()
+ }
+
+ return checker, deferable
+}
diff --git a/modules/git/repo_compare.go b/modules/git/repo_compare.go
index 4b0cc8536..3c7af7300 100644
--- a/modules/git/repo_compare.go
+++ b/modules/git/repo_compare.go
@@ -255,13 +255,7 @@ func (repo *Repository) GetDiff(base, head string, w io.Writer) error {
// GetDiffBinary generates and returns patch data between given revisions, including binary diffs.
func (repo *Repository) GetDiffBinary(base, head string, w io.Writer) error {
- if CheckGitVersionAtLeast("1.7.7") == nil {
- return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram", base, head).Run(&RunOpts{
- Dir: repo.Path,
- Stdout: w,
- })
- }
- return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--patience", base, head).Run(&RunOpts{
+ return NewCommand(repo.Ctx, "diff", "-p", "--binary", "--histogram", base, head).Run(&RunOpts{
Dir: repo.Path,
Stdout: w,
})
diff --git a/modules/git/repo_language_stats_gogit.go b/modules/git/repo_language_stats_gogit.go
index 3c9f026b7..34b0dc45d 100644
--- a/modules/git/repo_language_stats_gogit.go
+++ b/modules/git/repo_language_stats_gogit.go
@@ -8,12 +8,10 @@ package git
import (
"bytes"
- "context"
"io"
"strings"
"code.gitea.io/gitea/modules/analyze"
- "code.gitea.io/gitea/modules/log"
"github.com/go-enry/go-enry/v2"
"github.com/go-git/go-git/v5"
@@ -43,33 +41,8 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
return nil, err
}
- var checker *CheckAttributeReader
-
- if CheckGitVersionAtLeast("1.7.8") == nil {
- indexFilename, workTree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)
- if err == nil {
- defer deleteTemporaryFile()
- checker = &CheckAttributeReader{
- Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language"},
- Repo: repo,
- IndexFile: indexFilename,
- WorkTree: workTree,
- }
- ctx, cancel := context.WithCancel(DefaultContext)
- if err := checker.Init(ctx); err != nil {
- log.Error("Unable to open checker for %s. Error: %v", commitID, err)
- } else {
- go func() {
- err = checker.Run()
- if err != nil {
- log.Error("Unable to open checker for %s. Error: %v", commitID, err)
- cancel()
- }
- }()
- }
- defer cancel()
- }
- }
+ checker, deferable := repo.CheckAttributeReader(commitID)
+ defer deferable()
sizes := make(map[string]int64)
err = tree.Files().ForEach(func(f *object.File) error {
diff --git a/modules/git/repo_language_stats_nogogit.go b/modules/git/repo_language_stats_nogogit.go
index 41b176f81..d237924f9 100644
--- a/modules/git/repo_language_stats_nogogit.go
+++ b/modules/git/repo_language_stats_nogogit.go
@@ -9,7 +9,6 @@ package git
import (
"bufio"
"bytes"
- "context"
"io"
"math"
"strings"
@@ -63,36 +62,8 @@ func (repo *Repository) GetLanguageStats(commitID string) (map[string]int64, err
return nil, err
}
- var checker *CheckAttributeReader
-
- if CheckGitVersionAtLeast("1.7.8") == nil {
- indexFilename, worktree, deleteTemporaryFile, err := repo.ReadTreeToTemporaryIndex(commitID)
- if err == nil {
- defer deleteTemporaryFile()
- checker = &CheckAttributeReader{
- Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language"},
- Repo: repo,
- IndexFile: indexFilename,
- WorkTree: worktree,
- }
- ctx, cancel := context.WithCancel(repo.Ctx)
- if err := checker.Init(ctx); err != nil {
- log.Error("Unable to open checker for %s. Error: %v", commitID, err)
- } else {
- go func() {
- err = checker.Run()
- if err != nil {
- log.Error("Unable to open checker for %s. Error: %v", commitID, err)
- cancel()
- }
- }()
- }
- defer func() {
- _ = checker.Close()
- cancel()
- }()
- }
- }
+ checker, deferable := repo.CheckAttributeReader(commitID)
+ defer deferable()
contentBuf := bytes.Buffer{}
var content []byte
diff --git a/modules/git/repo_tree.go b/modules/git/repo_tree.go
index 2e139dadd..2ea3f0187 100644
--- a/modules/git/repo_tree.go
+++ b/modules/git/repo_tree.go
@@ -45,11 +45,11 @@ func (repo *Repository) CommitTree(author, committer *Signature, tree *Tree, opt
_, _ = messageBytes.WriteString(opts.Message)
_, _ = messageBytes.WriteString("\n")
- if CheckGitVersionAtLeast("1.7.9") == nil && (opts.KeyID != "" || opts.AlwaysSign) {
+ if opts.KeyID != "" || opts.AlwaysSign {
cmd.AddArguments(fmt.Sprintf("-S%s", opts.KeyID))
}
- if CheckGitVersionAtLeast("2.0.0") == nil && opts.NoGPGSign {
+ if opts.NoGPGSign {
cmd.AddArguments("--no-gpg-sign")
}
diff --git a/modules/markup/console/console.go b/modules/markup/console/console.go
index b59594acb..597593eee 100644
--- a/modules/markup/console/console.go
+++ b/modules/markup/console/console.go
@@ -33,9 +33,6 @@ func (Renderer) Name() string {
return MarkupName
}
-// NeedPostProcess implements markup.Renderer
-func (Renderer) NeedPostProcess() bool { return false }
-
// Extensions implements markup.Renderer
func (Renderer) Extensions() []string {
return []string{".sh-session"}
@@ -48,11 +45,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
}
}
-// SanitizerDisabled disabled sanitize if return true
-func (Renderer) SanitizerDisabled() bool {
- return false
-}
-
// CanRender implements markup.RendererContentDetector
func (Renderer) CanRender(filename string, input io.Reader) bool {
buf, err := io.ReadAll(input)
diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go
index 17c3fe6f4..5095b8546 100644
--- a/modules/markup/csv/csv.go
+++ b/modules/markup/csv/csv.go
@@ -29,9 +29,6 @@ func (Renderer) Name() string {
return "csv"
}
-// NeedPostProcess implements markup.Renderer
-func (Renderer) NeedPostProcess() bool { return false }
-
// Extensions implements markup.Renderer
func (Renderer) Extensions() []string {
return []string{".csv", ".tsv"}
@@ -46,11 +43,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
}
}
-// SanitizerDisabled disabled sanitize if return true
-func (Renderer) SanitizerDisabled() bool {
- return false
-}
-
func writeField(w io.Writer, element, class, field string) error {
if _, err := io.WriteString(w, "<"); err != nil {
return err
diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go
index a587abcc3..23dd45ba0 100644
--- a/modules/markup/external/external.go
+++ b/modules/markup/external/external.go
@@ -34,6 +34,11 @@ type Renderer struct {
*setting.MarkupRenderer
}
+var (
+ _ markup.PostProcessRenderer = (*Renderer)(nil)
+ _ markup.ExternalRenderer = (*Renderer)(nil)
+)
+
// Name returns the external tool name
func (p *Renderer) Name() string {
return p.MarkupName
@@ -56,7 +61,12 @@ func (p *Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
// SanitizerDisabled disabled sanitize if return true
func (p *Renderer) SanitizerDisabled() bool {
- return p.DisableSanitizer
+ return p.RenderContentMode == setting.RenderContentModeNoSanitizer || p.RenderContentMode == setting.RenderContentModeIframe
+}
+
+// DisplayInIFrame represents whether render the content with an iframe
+func (p *Renderer) DisplayInIFrame() bool {
+ return p.RenderContentMode == setting.RenderContentModeIframe
}
func envMark(envName string) string {
diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go
index f6aabc627..a7cf81250 100644
--- a/modules/markup/html_test.go
+++ b/modules/markup/html_test.go
@@ -5,12 +5,14 @@
package markup_test
import (
+ "context"
"io"
"strings"
"testing"
"code.gitea.io/gitea/modules/emoji"
"code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/log"
. "code.gitea.io/gitea/modules/markup"
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
@@ -25,14 +27,21 @@ var localMetas = map[string]string{
"repoPath": "../../integrations/gitea-repositories-meta/user13/repo11.git/",
}
+func TestMain(m *testing.M) {
+ setting.LoadAllowEmpty()
+ if err := git.InitSimple(context.Background()); err != nil {
+ log.Fatal("git init failed, err: %v", err)
+ }
+}
+
func TestRender_Commits(t *testing.T) {
setting.AppURL = TestAppURL
test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{
- Ctx: git.DefaultContext,
- Filename: ".md",
- URLPrefix: TestRepoURL,
- Metas: localMetas,
+ Ctx: git.DefaultContext,
+ RelativePath: ".md",
+ URLPrefix: TestRepoURL,
+ Metas: localMetas,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
@@ -80,9 +89,9 @@ func TestRender_CrossReferences(t *testing.T) {
test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{
- Filename: "a.md",
- URLPrefix: setting.AppSubURL,
- Metas: localMetas,
+ RelativePath: "a.md",
+ URLPrefix: setting.AppSubURL,
+ Metas: localMetas,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
@@ -124,8 +133,8 @@ func TestRender_links(t *testing.T) {
test := func(input, expected string) {
buffer, err := RenderString(&RenderContext{
- Filename: "a.md",
- URLPrefix: TestRepoURL,
+ RelativePath: "a.md",
+ URLPrefix: TestRepoURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
@@ -223,8 +232,8 @@ func TestRender_email(t *testing.T) {
test := func(input, expected string) {
res, err := RenderString(&RenderContext{
- Filename: "a.md",
- URLPrefix: TestRepoURL,
+ RelativePath: "a.md",
+ URLPrefix: TestRepoURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res))
@@ -281,8 +290,8 @@ func TestRender_emoji(t *testing.T) {
test := func(input, expected string) {
expected = strings.ReplaceAll(expected, "&", "&amp;")
buffer, err := RenderString(&RenderContext{
- Filename: "a.md",
- URLPrefix: TestRepoURL,
+ RelativePath: "a.md",
+ URLPrefix: TestRepoURL,
}, input)
assert.NoError(t, err)
assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer))
diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go
index 7ebdfea6c..37e11e606 100644
--- a/modules/markup/markdown/markdown.go
+++ b/modules/markup/markdown/markdown.go
@@ -205,12 +205,14 @@ func init() {
// Renderer implements markup.Renderer
type Renderer struct{}
+var _ markup.PostProcessRenderer = (*Renderer)(nil)
+
// Name implements markup.Renderer
func (Renderer) Name() string {
return MarkupName
}
-// NeedPostProcess implements markup.Renderer
+// NeedPostProcess implements markup.PostProcessRenderer
func (Renderer) NeedPostProcess() bool { return true }
// Extensions implements markup.Renderer
@@ -223,11 +225,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
return []setting.MarkupSanitizerRule{}
}
-// SanitizerDisabled disabled sanitize if return true
-func (Renderer) SanitizerDisabled() bool {
- return false
-}
-
// Render implements markup.Renderer
func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
return render(ctx, input, output)
diff --git a/modules/markup/markdown/markdown_test.go b/modules/markup/markdown/markdown_test.go
index a069d402b..732fe1a6b 100644
--- a/modules/markup/markdown/markdown_test.go
+++ b/modules/markup/markdown/markdown_test.go
@@ -5,6 +5,7 @@
package markdown_test
import (
+ "context"
"strings"
"testing"
@@ -31,6 +32,13 @@ var localMetas = map[string]string{
"repoPath": "../../../integrations/gitea-repositories-meta/user13/repo11.git/",
}
+func TestMain(m *testing.M) {
+ setting.LoadAllowEmpty()
+ if err := git.InitSimple(context.Background()); err != nil {
+ log.Fatal("git init failed, err: %v", err)
+ }
+}
+
func TestRender_StandardLinks(t *testing.T) {
setting.AppURL = AppURL
setting.AppSubURL = AppSubURL
diff --git a/modules/markup/orgmode/orgmode.go b/modules/markup/orgmode/orgmode.go
index 2f394b992..8c9f3b3da 100644
--- a/modules/markup/orgmode/orgmode.go
+++ b/modules/markup/orgmode/orgmode.go
@@ -29,12 +29,14 @@ func init() {
// Renderer implements markup.Renderer for orgmode
type Renderer struct{}
+var _ markup.PostProcessRenderer = (*Renderer)(nil)
+
// Name implements markup.Renderer
func (Renderer) Name() string {
return "orgmode"
}
-// NeedPostProcess implements markup.Renderer
+// NeedPostProcess implements markup.PostProcessRenderer
func (Renderer) NeedPostProcess() bool { return true }
// Extensions implements markup.Renderer
@@ -47,11 +49,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule {
return []setting.MarkupSanitizerRule{}
}
-// SanitizerDisabled disabled sanitize if return true
-func (Renderer) SanitizerDisabled() bool {
- return false
-}
-
// Render renders orgmode rawbytes to HTML
func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error {
htmlWriter := org.NewHTMLWriter()
diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go
index 6e4ae4e08..e88fa3118 100644
--- a/modules/markup/renderer.go
+++ b/modules/markup/renderer.go
@@ -10,6 +10,7 @@ import (
"errors"
"fmt"
"io"
+ "net/url"
"path/filepath"
"strings"
"sync"
@@ -43,17 +44,18 @@ type Header struct {
// RenderContext represents a render context
type RenderContext struct {
- Ctx context.Context
- Filename string
- Type string
- IsWiki bool
- URLPrefix string
- Metas map[string]string
- DefaultLink string
- GitRepo *git.Repository
- ShaExistCache map[string]bool
- cancelFn func()
- TableOfContents []Header
+ Ctx context.Context
+ RelativePath string // relative path from tree root of the branch
+ Type string
+ IsWiki bool
+ URLPrefix string
+ Metas map[string]string
+ DefaultLink string
+ GitRepo *git.Repository
+ ShaExistCache map[string]bool
+ cancelFn func()
+ TableOfContents []Header
+ InStandalonePage bool // used by external render. the router "/org/repo/render/..." will output the rendered content in a standalone page
}
// Cancel runs any cleanup functions that have been registered for this Ctx
@@ -88,12 +90,24 @@ func (ctx *RenderContext) AddCancel(fn func()) {
type Renderer interface {
Name() string // markup format name
Extensions() []string
- NeedPostProcess() bool
SanitizerRules() []setting.MarkupSanitizerRule
- SanitizerDisabled() bool
Render(ctx *RenderContext, input io.Reader, output io.Writer) error
}
+// PostProcessRenderer defines an interface for renderers who need post process
+type PostProcessRenderer interface {
+ NeedPostProcess() bool
+}
+
+// PostProcessRenderer defines an interface for external renderers
+type ExternalRenderer interface {
+ // SanitizerDisabled disabled sanitize if return true
+ SanitizerDisabled() bool
+
+ // DisplayInIFrame represents whether render the content with an iframe
+ DisplayInIFrame() bool
+}
+
// RendererContentDetector detects if the content can be rendered
// by specified renderer
type RendererContentDetector interface {
@@ -142,7 +156,7 @@ func DetectRendererType(filename string, input io.Reader) string {
func Render(ctx *RenderContext, input io.Reader, output io.Writer) error {
if ctx.Type != "" {
return renderByType(ctx, input, output)
- } else if ctx.Filename != "" {
+ } else if ctx.RelativePath != "" {
return renderFile(ctx, input, output)
}
return errors.New("Render options both filename and type missing")
@@ -163,6 +177,27 @@ type nopCloser struct {
func (nopCloser) Close() error { return nil }
+func renderIFrame(ctx *RenderContext, output io.Writer) error {
+ // set height="0" ahead, otherwise the scrollHeight would be max(150, realHeight)
+ // at the moment, only "allow-scripts" is allowed for sandbox mode.
+ // "allow-same-origin" should never be used, it leads to XSS attack, and it makes the JS in iframe can access parent window's config and CSRF token
+ // TODO: when using dark theme, if the rendered content doesn't have proper style, the default text color is black, which is not easy to read
+ _, err := io.WriteString(output, fmt.Sprintf(`
+<iframe src="%s/%s/%s/render/%s/%s"
+name="giteaExternalRender"
+onload="this.height=giteaExternalRender.document.documentElement.scrollHeight"
+width="100%%" height="0" scrolling="no" frameborder="0" style="overflow: hidden"
+sandbox="allow-scripts"
+></iframe>`,
+ setting.AppSubURL,
+ url.PathEscape(ctx.Metas["user"]),
+ url.PathEscape(ctx.Metas["repo"]),
+ ctx.Metas["BranchNameSubURL"],
+ url.PathEscape(ctx.RelativePath),
+ ))
+ return err
+}
+
func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Writer) error {
var wg sync.WaitGroup
var err error
@@ -175,7 +210,12 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr
var pr2 io.ReadCloser
var pw2 io.WriteCloser
- if !renderer.SanitizerDisabled() {
+ var sanitizerDisabled bool
+ if r, ok := renderer.(ExternalRenderer); ok {
+ sanitizerDisabled = r.SanitizerDisabled()
+ }
+
+ if !sanitizerDisabled {
pr2, pw2 = io.Pipe()
defer func() {
_ = pr2.Close()
@@ -194,7 +234,7 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr
wg.Add(1)
go func() {
- if renderer.NeedPostProcess() {
+ if r, ok := renderer.(PostProcessRenderer); ok && r.NeedPostProcess() {
err = PostProcess(ctx, pr, pw2)
} else {
_, err = io.Copy(pw2, pr)
@@ -239,8 +279,15 @@ func (err ErrUnsupportedRenderExtension) Error() string {
}
func renderFile(ctx *RenderContext, input io.Reader, output io.Writer) error {
- extension := strings.ToLower(filepath.Ext(ctx.Filename))
+ extension := strings.ToLower(filepath.Ext(ctx.RelativePath))
if renderer, ok := extRenderers[extension]; ok {
+ if r, ok := renderer.(ExternalRenderer); ok && r.DisplayInIFrame() {
+ if !ctx.InStandalonePage {
+ // for an external render, it could only output its content in a standalone page
+ // otherwise, a <iframe> should be outputted to embed the external rendered page
+ return renderIFrame(ctx, output)
+ }
+ }
return render(ctx, renderer, input, output)
}
return ErrUnsupportedRenderExtension{extension}
diff --git a/modules/repository/init.go b/modules/repository/init.go
index f5cef3301..e984697cd 100644
--- a/modules/repository/init.go
+++ b/modules/repository/init.go
@@ -323,19 +323,17 @@ func initRepoCommit(ctx context.Context, tmpPath string, repo *repo_model.Reposi
"-m", "Initial commit",
}
- if git.CheckGitVersionAtLeast("1.7.9") == nil {
- sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
- if sign {
- args = append(args, "-S"+keyID)
-
- if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
- // need to set the committer to the KeyID owner
- committerName = signer.Name
- committerEmail = signer.Email
- }
- } else if git.CheckGitVersionAtLeast("2.0.0") == nil {
- args = append(args, "--no-gpg-sign")
+ sign, keyID, signer, _ := asymkey_service.SignInitialCommit(ctx, tmpPath, u)
+ if sign {
+ args = append(args, "-S"+keyID)
+
+ if repo.GetTrustModel() == repo_model.CommitterTrustModel || repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
+ // need to set the committer to the KeyID owner
+ committerName = signer.Name
+ committerEmail = signer.Email
}
+ } else {
+ args = append(args, "--no-gpg-sign")
}
env = append(env,
diff --git a/modules/setting/federation.go b/modules/setting/federation.go
index cba1851df..53a83fa84 100644
--- a/modules/setting/federation.go
+++ b/modules/setting/federation.go
@@ -15,6 +15,7 @@ var (
Federation = struct {
Enabled bool
ShareUserStatistics bool
+ MaxSize int64
Algorithms []string
DigestAlgorithm string
GetHeaders []string
@@ -22,6 +23,7 @@ var (
}{
Enabled: true,
ShareUserStatistics: true,
+ MaxSize: 4,
Algorithms: []string{"rsa-sha256", "rsa-sha512"},
DigestAlgorithm: "SHA-256",
GetHeaders: []string{"(request-target)", "Date"},
@@ -40,6 +42,9 @@ func newFederationService() {
return
}
+ // Get MaxSize in bytes instead of MiB
+ Federation.MaxSize = 1 << 20 * Federation.MaxSize
+
HttpsigAlgs = make([]httpsig.Algorithm, len(Federation.Algorithms))
for i, alg := range Federation.Algorithms {
HttpsigAlgs[i] = httpsig.Algorithm(alg)
diff --git a/modules/setting/markup.go b/modules/setting/markup.go
index 5fb6af683..fd41bdd7c 100644
--- a/modules/setting/markup.go
+++ b/modules/setting/markup.go
@@ -20,6 +20,12 @@ var (
MermaidMaxSourceCharacters int
)
+const (
+ RenderContentModeSanitized = "sanitized"
+ RenderContentModeNoSanitizer = "no-sanitizer"
+ RenderContentModeIframe = "iframe"
+)
+
// MarkupRenderer defines the external parser configured in ini
type MarkupRenderer struct {
Enabled bool
@@ -29,7 +35,7 @@ type MarkupRenderer struct {
IsInputFile bool
NeedPostProcess bool
MarkupSanitizerRules []MarkupSanitizerRule
- DisableSanitizer bool
+ RenderContentMode string
}
// MarkupSanitizerRule defines the policy for whitelisting attributes on
@@ -144,13 +150,28 @@ func newMarkupRenderer(name string, sec *ini.Section) {
return
}
+ if sec.HasKey("DISABLE_SANITIZER") {
+ log.Error("Deprecated setting `[markup.*]` `DISABLE_SANITIZER` present. This fallback will be removed in v1.18.0")
+ }
+
+ renderContentMode := sec.Key("RENDER_CONTENT_MODE").MustString(RenderContentModeSanitized)
+ if !sec.HasKey("RENDER_CONTENT_MODE") && sec.Key("DISABLE_SANITIZER").MustBool(false) {
+ renderContentMode = RenderContentModeNoSanitizer // if only the legacy DISABLE_SANITIZER exists, use it
+ }
+ if renderContentMode != RenderContentModeSanitized &&
+ renderContentMode != RenderContentModeNoSanitizer &&
+ renderContentMode != RenderContentModeIframe {
+ log.Error("invalid RENDER_CONTENT_MODE: %q, default to %q", renderContentMode, RenderContentModeSanitized)
+ renderContentMode = RenderContentModeSanitized
+ }
+
ExternalMarkupRenderers = append(ExternalMarkupRenderers, &MarkupRenderer{
- Enabled: sec.Key("ENABLED").MustBool(false),
- MarkupName: name,
- FileExtensions: exts,
- Command: command,
- IsInputFile: sec.Key("IS_INPUT_FILE").MustBool(false),
- NeedPostProcess: sec.Key("NEED_POSTPROCESS").MustBool(true),
- DisableSanitizer: sec.Key("DISABLE_SANITIZER").MustBool(false),
+ Enabled: sec.Key("ENABLED").MustBool(false),
+ MarkupName: name,
+ FileExtensions: exts,
+ Command: command,
+ IsInputFile: sec.Key("IS_INPUT_FILE").MustBool(false),
+ NeedPostProcess: sec.Key("NEED_POSTPROCESS").MustBool(true),
+ RenderContentMode: renderContentMode,
})
}
diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini
index 52f276773..0f66edcab 100644
--- a/options/locale/locale_lv-LV.ini
+++ b/options/locale/locale_lv-LV.ini
@@ -2,6 +2,7 @@ home=Sākums
dashboard=Infopanelis
explore=Izpētīt
help=Palīdzība
+logo=Logo
sign_in=Pierakstīties
sign_in_with=Pierakstīties izmantojot
sign_out=Izrakstīties
@@ -105,6 +106,7 @@ error404=Lapa, ko vēlaties atvērt, <strong>neeksistē</strong> vai arī <stron
never=Nekad
+rss_feed=RSS barotne
[error]
occurred=Radusies kļūda
@@ -269,6 +271,7 @@ search=Meklēt
code=Kods
search.fuzzy=Aptuveni
search.match=Precīzi
+code_search_unavailable=Pašlaik koda meklēšana nav pieejama. Sazinieties ar lapas administratoru.
repo_no_results=Netika atrasts neviens repozitorijs, kas atbilstu kritērijiem.
user_no_results=Netika atrasts neviens lietotājs, kas atbilstu kritērijiem.
org_no_results=Netika atrasta neviena organizācija, kas atbilstu kritērijiem.
@@ -282,6 +285,7 @@ register_helper_msg=Jau ir konts? Pieraksties tagad!
social_register_helper_msg=Jau ir konts? Pievienojies!
disable_register_prompt=Reģistrācija ir atspējota. Lūdzu, sazinieties ar vietnes administratoru.
disable_register_mail=Reģistrācijas e-pasta apstiprināšana ir atspējota.
+manual_activation_only=Sazinieties ar lapas administratoru, lai pabeigtu konta aktivizāciju.
remember_me=Atcerēties šo ierīci
forgot_password_title=Aizmirsu paroli
forgot_password=Aizmirsi paroli?
@@ -439,6 +443,7 @@ size_error=` jābūt %s simbolus garam.`
min_size_error=` jabūt vismaz %s simbolu garumā.`
max_size_error=` jabūt ne mazāk kā %s simbolu garumā.`
email_error=` nav derīga e-pasta adrese.`
+url_error=`'%s' nav korekts URL.`
include_error=` ir jāsatur tekstu '%s'.`
glob_pattern_error=` glob šablons nav korekts: %s.`
regex_pattern_error=` regulārā izteiksme nav korekta: %s.`
@@ -486,7 +491,9 @@ auth_failed=Autentifikācija neizdevās: %v
still_own_repo=Šis konts ir vismaz viena repozitorija īpašnieks, tos sākumā ir nepieciešams izdzēst vai mainīt to īpašnieku.
still_has_org=Jūsu konts ir piesaistīts vismaz vienai organizācijai, sākumā nepieciešams to pamest.
+still_own_packages=Jūsu kontam pieder viena vai vairākas pakotnes, tās nepieciešams izdzēst.
org_still_own_repo=Organizācijai pieder repozitoriji, tos sākumā ir nepieciešams izdzēst vai mainīt to īpašnieku.
+org_still_own_packages=Šai organizācijai pieder viena vai vārākas pakotnes, tās nepieciešams izdzēst.
target_branch_not_exist=Mērķa atzars neeksistē
@@ -549,6 +556,22 @@ continue=Turpināt
cancel=Atcelt
language=Valoda
ui=Motīvs
+hidden_comment_types=Attēlojot paslēpt šauds komentārus:
+comment_type_group_reference=Atsauces
+comment_type_group_label=Etiķetes
+comment_type_group_milestone=Atskaites punktus
+comment_type_group_assignee=Atbildīgos
+comment_type_group_title=Nosaukuma izmaiņas
+comment_type_group_branch=Atzara izmaiņas
+comment_type_group_time_tracking=Laika uzskaiti
+comment_type_group_deadline=Termiņus
+comment_type_group_dependency=Atkarības
+comment_type_group_lock=Slēgšanas maiņu
+comment_type_group_review_request=Izmaiņu pieprasījumus
+comment_type_group_pull_request_push=Pievienotās revīzijas
+comment_type_group_project=Projektus
+comment_type_group_issue_ref=Problēmu atsauces
+saved_successfully=Iestatījumi tika veiksmīgi saglabati.
privacy=Privātums
keep_activity_private=Nerādīt manu aktivitāti profila lapā
keep_activity_private_popup=Savu aktivitāti redzēsiet tikai Jūs un administratori
@@ -694,6 +717,9 @@ generate_token_success=Piekļuves talons tika veiksmīgi uzģenerēts! Nokopēji
generate_token_name_duplicate=Jau eksistē lietotne ar nosaukumu <strong>%s</strong>. Izmantojiet citu nosaukumu.
delete_token=Dzēst
access_token_deletion=Dzēst piekļuves talonu
+access_token_deletion_cancel_action=Atcelt
+access_token_deletion_confirm_action=Dzēst
+access_token_deletion_desc=Izdzēšot talonu, tam tiks liegta piekļuve šim kontam. Šī darbība ir neatgriezeniska. Vai turpināt?
delete_token_success=Piekļuves talons tika noņemts. Neaizmirstiet atjaunot informāciju lietojumprogrammās, kas izmantoja šo talonu.
manage_oauth2_applications=Pārvaldīt OAuth2 lietotnes
@@ -755,6 +781,7 @@ webauthn_delete_key_desc=Noņemot drošības atslēgu ar to vairs nebūs iespēj
manage_account_links=Pārvaldīt saistītos kontus
manage_account_links_desc=Šādi ārējie konti ir piesaistīti Jūsu Gitea kontam.
account_links_not_available=Pašlaik nav neviena ārējā konta piesaistīta šim kontam.
+link_account=Savienot kontu
remove_account_link=Noņemt saistīto kontu
remove_account_link_desc=Noņemot saistīto kontu, tam tiks liegta piekļuve Jūsu Gitea kontam. Vai turpināt?
remove_account_link_success=Saistītais konts tika noņemts.
@@ -835,6 +862,7 @@ default_branch=Noklusējuma atzars
default_branch_helper=Noklusētais atzars nosaka pamata atzaru uz kuru tiks veidoti izmaiņu pieprasījumi un koda revīziju iesūtīšana.
mirror_prune=Izmest
mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē
+mirror_interval=Spoguļošanas intervāls (derīgas laika vienības ir 'h', 'm', 's'). Norādiet 0, lai atslēgtu automātisku spoguļošanu. (Minimālais intervāls: %s)
mirror_interval_invalid=Nekorekts spoguļošanas intervāls.
mirror_address=Spoguļa adrese
mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā.
@@ -986,6 +1014,7 @@ tags=Tagi
issues=Problēmas
pulls=Izmaiņu pieprasījumi
project_board=Projekti
+packages=Pakotnes
labels=Etiķetes
org_labels_desc=Organizācijas līmeņa etiķetes var tikt izmantotas <strong>visiem repozitorijiem</strong> šajā organizācijā
org_labels_desc_manage=pārvaldīt
@@ -1016,6 +1045,7 @@ line_unicode=`Šajā līnijā ir paslēpti unikoda simboli`
escape_control_characters=Kodēt
unescape_control_characters=Atkodēt
file_copy_permalink=Kopēt saiti
+view_git_blame=Aplūkot Git vainīgos
video_not_supported_in_browser=Jūsu pārlūks neatbalsta HTML5 video.
audio_not_supported_in_browser=Jūsu pārlūks neatbalsta HTML5 audio.
stored_lfs=Saglabāts Git LFS
@@ -1054,6 +1084,10 @@ editor.add_tmpl=Pievienot '<fails>'
editor.add=Pievienot '%s'
editor.update=Atjaunināt '%s'
editor.delete=Dzēst '%s'
+editor.patch=Pielietot ielāpu
+editor.patching=Pielieto ielāpu:
+editor.fail_to_apply_patch=Neizdevās pielietot ielāpu '%s'
+editor.new_patch=Jauns ielāps
editor.commit_message_desc=Pievienot neobligātu paplašinātu aprakstu…
editor.signoff_desc=Pievienot revīzijas žurnāla ziņojuma beigās Signed-off-by ar revīzijas autoru.
editor.commit_directly_to_this_branch=Apstiprināt revīzijas izmaiņas atzarā <strong class="branch-name">%s</strong>.
@@ -1089,6 +1123,8 @@ editor.cannot_commit_to_protected_branch=Nav atļauts veikt izmaiņas aizsargāt
editor.no_commit_to_branch=Nevar apstiprināt revīzijas atzarā:
editor.user_no_push_to_branch=Lietotājs nevar iesūtīt izmaiņas šajā atzarā
editor.require_signed_commit=Atzarā var iesūtīt tikai parakstītas revīzijas
+editor.cherry_pick=Izlasīt %s uz:
+editor.revert=Atgriezt %s uz:
commits.desc=Pārlūkot pirmkoda izmaiņu vēsturi.
commits.commits=Revīzijas
@@ -1109,6 +1145,13 @@ commits.signed_by_untrusted_user_unmatched=Parakstījis neuzticams lietotājs, k
commits.gpg_key_id=GPG atslēgas ID
commits.ssh_key_fingerprint=SSH atslēgas identificējošā zīmju virkne
+commit.actions=Darbības
+commit.revert=Atgriezt
+commit.revert-header=Atgriezt: %s
+commit.revert-content=Norādiet atzaru uz kuru atgriezt:
+commit.cherry-pick=Izlasīt
+commit.cherry-pick-header=Izlasīt: %s
+commit.cherry-pick-content=Norādiet atzaru uz kuru izlasīt:
ext_issues=Piekļuve ārējām problēmām
ext_issues.desc=Saite uz ārējo problēmu sekotāju.
@@ -1147,6 +1190,7 @@ projects.board.deletion_desc=Dzēšot projekta dēli visas tam piesaistītās pr
projects.board.color=Krāsa
projects.open=Aktīvie
projects.close=Pabeigtie
+projects.board.assigned_to=Piešķirts
issues.desc=Organizēt kļūdu ziņojumus, uzdevumus un atskaites punktus.
issues.filter_assignees=Filtrēt pēc atbildīgajiem
@@ -1241,6 +1285,7 @@ issues.filter_sort.moststars=Visvairāk atzīmētie
issues.filter_sort.feweststars=Vismazāk atzīmētie
issues.filter_sort.mostforks=Visvairāk atdalītie
issues.filter_sort.fewestforks=Vismazāk atdalītie
+issues.keyword_search_unavailable=Meklēšana pēc atslēgas vārdiem nav pieejama. Sazinieties ar sistēmas administratoru.
issues.action_open=Atvērt
issues.action_close=Aizvērt
issues.action_label=Etiķete
@@ -1336,6 +1381,9 @@ issues.lock.reason=Slēgšanas iemesls
issues.lock.title=Slēgt komentēšanu šai problēmai.
issues.unlock.title=Atļaut komentēšanu šai problēmai.
issues.comment_on_locked=Jūs nevarat komentēt slēgtai problēmai.
+issues.delete=Dzēst
+issues.delete.title=Dzēst šo problēmu?
+issues.delete.text=Vai patiešām vēlaties dzēst šo problemu? (Neatgriezeniski tiks izdzēsts viss saturs. Apsveriet iespēju to aizvērt, ja vēlaties informāciju saglabāt vēsturei)
issues.tracker=Laika uzskaite
issues.start_tracking_short=Uzsākt taimeri
issues.start_tracking=Uzsākt laika uzskaiti
@@ -1376,6 +1424,8 @@ issues.due_date_remove=noņēma izpildes termiņu %s %s
issues.due_date_overdue=Nokavēts
issues.due_date_invalid=Datums līdz nav korekts. Izmantojiet formātu 'gggg-mm-dd'.
issues.dependency.title=Atkarības
+issues.dependency.issue_no_dependencies=Nav atkarību.
+issues.dependency.pr_no_dependencies=Nav atkarību.
issues.dependency.add=Pievienot atkarību…
issues.dependency.cancel=Atcelt
issues.dependency.remove=Noņemt
@@ -1414,6 +1464,7 @@ issues.review.add_review_request=pieprasīja recenziju no %s %s
issues.review.remove_review_request=noņema recenzijas pieprasījumu no %s %s
issues.review.remove_review_request_self=atteicās recenzēt %s
issues.review.pending=Nav iesūtīts
+issues.review.pending.tooltip=Šis komentārs nav redzams citiem lietotājiem. Lai padarītu neiesūtītos komentārus pieejamus citiem, nospiediet '%s' -> '%s/%s/%s' lapas augšpusē.
issues.review.review=Recenzija
issues.review.reviewers=Recenzenti
issues.review.outdated=Novecojis
@@ -1432,6 +1483,7 @@ issues.content_history.created=izveidots
issues.content_history.delete_from_history=Dzēst no vēstures
issues.content_history.delete_from_history_confirm=Vai dzēst no vēstures?
issues.content_history.options=Iespējas
+issues.reference_link=Atsaucas uz: %s
compare.compare_base=pamata
compare.compare_head=salīdzināt
@@ -1440,7 +1492,13 @@ pulls.desc=Iespējot izmaiņu pieprasījumus un koda recenzēšanu.
pulls.new=Jauns izmaiņu pieprasījums
pulls.view=Skatīties izmaiņu pieprasījumu
pulls.compare_changes=Jauns izmaiņu pieprasījums
+pulls.allow_edits_from_maintainers=Atļaut labojumus no uzturētājiem
+pulls.allow_edits_from_maintainers_desc=Lietotāji ar rakstīšanas tiesībām bāzes atzarā, drīkst iesūtīt izmaiņas šajā atzarā
+pulls.allow_edits_from_maintainers_err=Atjaunošana neizdevās
pulls.compare_changes_desc=Izvēlieties atzaru, kurā sapludināt izmaiņas un atzaru, no kura tās saņemt.
+pulls.has_viewed_file=Skatīts
+pulls.has_changed_since_last_review=Mainīts kopš pēdējās recenzijas
+pulls.viewed_files_label=%[1]d no %[2]d failiem apskatīts
pulls.compare_base=pamata
pulls.compare_compare=salīdzināmais
pulls.switch_comparison_type=Mainīt salīdzināšanas tipu
@@ -1540,8 +1598,17 @@ pulls.merge_instruction_hint=`Varat aplūkot arī <a class="show-instruction">ko
pulls.merge_instruction_step1_desc=Projekta repozitorijā izveidojiet jaunu jaunu atzaru un pārbaudiet savas izmaiņas.
pulls.merge_instruction_step2_desc=Sapludināt izmaiņas un atjaunot tās Gitea.
+pulls.auto_merge_button_when_succeed=(Kad pārbaudes veiksmīgas)
+pulls.auto_merge_when_succeed=Automātiski sapludināt, kad visas pārbaudes veiksmīgas
+pulls.auto_merge_newly_scheduled=Šis izmaiņu pieprasījums tika ieplānots automātiskajai sapludināšanai, kas visas pārbaudes būs veiksmīgas.
+pulls.auto_merge_has_pending_schedule=%[1]s ieplānoja šī izmaiņu pieprasījuma automātisko sapludināšanu, kad visas pārbaudes tiks pabeigtas %[2]s.
+pulls.auto_merge_cancel_schedule=Atcelt automātisko sapludināšanu
+pulls.auto_merge_not_scheduled=Šo izmaiņu pieprasījumu nav ieplānots automātiski sapludināt.
+pulls.auto_merge_canceled_schedule=Automātiskā sapludināšana šim izmaiņu pieprasījumam tika atcelta.
+pulls.auto_merge_newly_scheduled_comment=`ieplānoja automātisko sapludināšanu šim izmaiņu pieprasījumam, kad visas pārbaudes būs veiksmīgas %[1]s`
+pulls.auto_merge_canceled_schedule_comment=`atcēla automātisko sapludināšanu šim izmaiņu pieprasījumam %[1]s`
milestones.new=Jauns atskaites punkts
milestones.closed=Aizvērts %s
@@ -1685,6 +1752,8 @@ search.search_repo=Meklēšana repozitorijā
search.fuzzy=Aptuveni
search.match=Precīzi
search.results=Meklēšanas rezultāti nosacījumam "%s" repozitorijā <a href="%s">%s</a>
+search.code_no_results=Netika atrasts pirmkods, kas atbilstu kritērijiem.
+search.code_search_unavailable=Pašlaik koda meklēšana nav pieejama. Sazinieties ar lapas administratoru.
settings=Iestatījumi
settings.desc=Iestatījumi ir vieta, kur varat pārvaldīt repozitorija iestatījumus
@@ -1735,6 +1804,9 @@ settings.tracker_url_format_error=Ārējā problēmu sekotāja URL formāts nav
settings.tracker_issue_style=Ārējā problēmu sekotāja numura formāts
settings.tracker_issue_style.numeric=Cipari
settings.tracker_issue_style.alphanumeric=Burti un cipari
+settings.tracker_issue_style.regexp=Regulārā izteiksme
+settings.tracker_issue_style.regexp_pattern=Regulārās izteiksmes šablons
+settings.tracker_issue_style.regexp_pattern_desc=Pirmā iegultā grupa tiks izmantota <code>{index}</code> vietā.
settings.tracker_url_format_desc=Jūs varat izmantot <code>{user}</code>, <code>{repo}</code> un <code>{index}</code> lietotājvārdam, repozitorija nosaukumam un problēmas identifikatoram.
settings.enable_timetracker=Iespējot laika uzskaiti
settings.allow_only_contributors_to_track_time=Atļaut tikai dalībniekiem uzskaitīt laiku
@@ -1746,7 +1818,9 @@ settings.pulls.allow_rebase_merge_commit=Iespējot pārbāzēšanu sapludinot re
settings.pulls.allow_squash_commits=Iespējot saspiešanu sapludinot revīzijas
settings.pulls.allow_manual_merge=Iespējot atzīmēt izmaiņu pieprasījumu kā manuāli sapludinātu
settings.pulls.enable_autodetect_manual_merge=Iespējot manuālo sapludināšanas noteikšanu (Piezīme: dažos speciālos gadījumos, tas var nostrādāt nekorekti)
+settings.pulls.allow_rebase_update=Iespējot izmaiņu pieprasījuma atjaunošanu ar pārbāzēšanu
settings.pulls.default_delete_branch_after_merge=Pēc noklusējuma dzēst izmaiņu pieprasījuma atzaru pēc sapludināšanas
+settings.packages_desc=Iespējot repozitorija pakotņu reģistru
settings.projects_desc=Iespējot repozitorija projektus
settings.admin_settings=Administratora iestatījumi
settings.admin_enable_health_check=Iespējot veselības pārbaudi (git fsck) šim repozitorijam
@@ -1904,6 +1978,8 @@ settings.event_pull_request_review=Izmaiņu pieprasījums recenzēts
settings.event_pull_request_review_desc=Izmaiņu pieprasījums apstiprināts, noraidīts vai atstāts komentārs.
settings.event_pull_request_sync=Izmaiņu pieprasījums sinhronizēts
settings.event_pull_request_sync_desc=Izmaiņu pieprasījums sinhronizēts.
+settings.event_package=Pakotne
+settings.event_package_desc=Repozitorijā izveidota vai dzēsta pakotne.
settings.branch_filter=Atzaru filtrs
settings.branch_filter_desc=Atzaru ierobežojumi izmaiņu iesūtīšanas, zaru izveidošanas vai dzēšanas notikumiem, izmantojot, glob šablonu. Ja norādīts tukšs vai <code>*</code>, tiks nosūtīti notikumi no visiem zariem. Skatieties <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> pieraksta dokumentāciju. Piemērs: <code>master</code>, <code>{master,release*}</code>.
settings.active=Aktīvs
@@ -1917,6 +1993,23 @@ settings.hook_type=Āķa veids
settings.slack_token=Talons
settings.slack_domain=Domēns
settings.slack_channel=Kanāls
+settings.add_web_hook_desc=Integrēt <a target="_blank" rel="noreferrer" href="%s">%s</a> repozitorijā.
+settings.web_hook_name_gitea=Gitea
+settings.web_hook_name_gogs=Gogs
+settings.web_hook_name_slack=Slack
+settings.web_hook_name_discord=Discord
+settings.web_hook_name_dingtalk=DingTalk
+settings.web_hook_name_telegram=Telegram
+settings.web_hook_name_matrix=Matrix
+settings.web_hook_name_msteams=Microsoft Teams
+settings.web_hook_name_feishu_or_larksuite=Feishu / Lark Suite
+settings.web_hook_name_feishu=Feishu
+settings.web_hook_name_larksuite=Lark Suite
+settings.web_hook_name_wechatwork=WeCom (Wechat Work)
+settings.web_hook_name_packagist=Packagist
+settings.packagist_username=Packagist lietotāja vārds
+settings.packagist_api_token=API talons
+settings.packagist_package_url=Packagist pakotnes URL
settings.deploy_keys=Izvietot atslēgas
settings.add_deploy_key=Pievienot izvietošanas atslēgu
settings.deploy_key_desc=Izvietošanas atslēgām ir lasīšanas piekļuve repozitorijam.
@@ -2172,11 +2265,15 @@ branch.included_desc=Šis atzars ir daļa no noklusēta atzara
branch.included=Iekļauts
branch.create_new_branch=Izveidot jaunu atzaru no atzara:
branch.confirm_create_branch=Izveidot atzaru
+branch.create_branch_operation=Izveidot atzaru
branch.new_branch=Izveidot jaunu atzaru
branch.new_branch_from=Izveidot jaunu atzaru no '%s'
branch.renamed=Atzars %s tika pārsaukts par %s.
tag.create_tag=Izveidot tagu <strong>%s</strong>
+tag.create_tag_operation=Izveidot tagu
+tag.confirm_create_tag=Izveidot tagu
+tag.create_tag_from=Izveidot tagu no '%s'
tag.create_success=Tags '%s' tika izveidots.
@@ -2185,6 +2282,8 @@ topic.done=Gatavs
topic.count_prompt=Nevar pievienot vairāk kā 25 tēmas
topic.format_prompt=Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
+find_file.go_to_file=Iet uz failu
+find_file.no_matching=Atbilstošs fails netika atrasts
error.csv.too_large=Nevar attēlot šo failu, jo tas ir pārāk liels.
error.csv.unexpected=Nevar attēlot šo failu, jo tas satur neparedzētu simbolu %d. līnijas %d. kolonnā.
@@ -2322,9 +2421,11 @@ first_page=Pirmā
last_page=Pēdējā
total=Kopā: %d
+dashboard.new_version_hint=Ir pieejama Gitea versija %s, pašreizējā versija %s. Papildus informācija par jauno versiju ir pieejama <a target="_blank" rel="noreferrer" href="https://blog.gitea.io">mājas lapā</a>.
dashboard.statistic=Kopsavilkums
dashboard.operations=Uzturēšanas darbības
dashboard.system_status=Sistēmas statuss
+dashboard.statistic_info=Gitea datu bāze satur <b>%d</b> lietotājus, <b>%d</b> organizācijas, <b>%d</b> publiskās atslēgas, <b>%d</b> repozitorijus, <b>%d</b> vērošanas, <b>%d</b> atzīmētas zvaigznītes, ~<b>%d</b> darbības, <b>%d</b> piekļuves, <b>%d</b> problēmas, <b>%d</b> komentārus, <b>%d</b> sociālos kontus, <b>%d</b> sekošanas, <b>%d</b> spoguļošanas, <b>%d</b> izlaides, <b>%d</b> autorizācijas avotus, <b>%d</b> tīmekļa āķus, <b>%d</b> starpposmus, <b>%d</b> etiķetes, <b>%d</b> āķu uzdevumus, <b>%d</b> komandas, <b>%d</b> labotus uzdevumus, <b>%d</b> pielikumus.
dashboard.operation_name=Darbības nosaukums
dashboard.operation_switch=Pārslēgt
dashboard.operation_run=Palaist
@@ -2363,6 +2464,7 @@ dashboard.resync_all_hooks=Pārsinhronizēt pirms-saņemšanas, atjaunošanas un
dashboard.reinit_missing_repos=Atkārtoti inicializēt visus pazaudētos Git repozitorijus par kuriem eksistē ieraksti
dashboard.sync_external_users=Sinhronizēt ārējo lietotāju datus
dashboard.cleanup_hook_task_table=Iztīrīt tīmekļa āķu vēsturi
+dashboard.cleanup_packages=Notīrīt novecojušās pakotnes
dashboard.server_uptime=Servera darbības laiks
dashboard.current_goroutine=Izmantotās Gorutīnas
dashboard.current_memory_usage=Pašreiz izmantotā atmiņa
@@ -2394,6 +2496,8 @@ dashboard.last_gc_pause=Pedējās GC izpildes laiks
dashboard.gc_times=GC reizes
dashboard.delete_old_actions=Dzēst visas darbības no datu bāzes
dashboard.delete_old_actions.started=Uzsākta visu novecojušo darbību dzēšana no datu bāzes.
+dashboard.update_checker=Atjauninājumu pārbaudītājs
+dashboard.delete_old_system_notices=Dzēst vecos sistēmas paziņojumus no datubāzes
users.user_manage_panel=Lietotāju kontu pārvaldība
users.new_account=Izveidot lietotāja kontu
@@ -2428,8 +2532,10 @@ users.allow_import_local=Atļauts importēt lokālus repozitorijus
users.allow_create_organization=Atļauts veidot organizācijas
users.update_profile=Mainīt lietotāja kontu
users.delete_account=Dzēst lietotāja kontu
+users.cannot_delete_self=Nevar izdzēst sevi
users.still_own_repo=Lietotājam pieder repozitoriji, tos sākumā ir nepieciešams izdzēst vai mainīt to īpašnieku.
users.still_has_org=Šis lietotājs ir vienas vai vairāku organizāciju biedrs, lietotāju sākumā ir nepieciešams pamest šīs organizācijas vai viņu no tām ir jāizdzēš.
+users.still_own_packages=Šim lietotājam pieder viena vai vairākas pakotnes. Tās nepieciešams izdzēst.
users.deletion_success=Lietotāja konts veiksmīgi izdzēsts.
users.reset_2fa=Noņemt 2FA
users.list_status_filter.menu_text=Filtrs
@@ -2476,6 +2582,16 @@ repos.forks=Atdalītie
repos.issues=Problēmas
repos.size=Izmērs
+packages.package_manage_panel=Pakotņu pārvaldība
+packages.total_size=Kopējais izmērs: %s
+packages.owner=Īpašnieks
+packages.creator=Izveidotājs
+packages.name=Nosaukums
+packages.version=Versija
+packages.type=Veids
+packages.repository=Repozitorijs
+packages.size=Izmērs
+packages.published=Publicēts
defaulthooks=Noklusētie tīmekļa āķi
defaulthooks.desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikumiem, kas notiek Gitea. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Šeit izveidotie tīmekļa āķi tiks pievienoti visiem jaunajajiem repozitorijiem. Lai uzzinātu sīkāk skatieties <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">tīmekļa āķu rokasgrāmatā</a>.
@@ -2519,9 +2635,13 @@ auths.filter=Lietotāju filts
auths.admin_filter=Administratoru filtrs
auths.restricted_filter=Ierobežoto lietotāju filtrs
auths.restricted_filter_helper=Atstājiet tukšu, lai nevienam lietotajam neuzstādīt ierobežots pazīmi. Izmantojiet zvaigznīti ('*'), lai uzstādītu visiem lietotājiem, kas neatbilst administratora filtram.
+auths.verify_group_membership=Pārbaudīt piederību LDAP grupai (atstājiet filtru tukšu, lai neizmantotu)
auths.group_search_base=Grupas pamatnosacījumi
auths.group_attribute_list_users=Grupas atribūts, kas satur sarakstu ar lietotājiem
auths.user_attribute_in_group=Grupas atribūts, kas nosaka lietotāju
+auths.map_group_to_team=Sasaistīt LDAP grupas ar organizācijas komandām (atstājiet tukšu, lai to nedarītu)
+auths.map_group_to_team_removal=Noņemt lietotājus no sinhronizētajām komandām, ja lietotājs nav piesaistīts attiecīgajai LDAP grupai
+auths.enable_ldap_groups=Iespējot LDAP grupas
auths.ms_ad_sa=MS AD meklēšanas atribūti
auths.smtp_auth=SMTP autentifikācijas tips
auths.smtphost=SMTP resursdators
@@ -2740,9 +2860,12 @@ monitor.next=Nākošās izpildes laiks
monitor.previous=Pēdējās izpildes laiks
monitor.execute_times=Izpildes
monitor.process=Darbojošies procesi
+monitor.stacktrace=Steka izsekojamība
+monitor.goroutines=%d gorutīnas
monitor.desc=Apraksts
monitor.start=Sākuma laiks
monitor.execute_time=Izpildes laiks
+monitor.last_execution_result=Rezultāts
monitor.process.cancel=Atcelt procesu
monitor.process.cancel_desc=Procesa atcelšana var radīt datu zaudējumus
monitor.process.cancel_notices=Atcelt: <strong>%s</strong>?
@@ -2754,6 +2877,7 @@ monitor.queue.type=Veids
monitor.queue.exemplar=Eksemplāra veids
monitor.queue.numberworkers=Strādņu skaits
monitor.queue.maxnumberworkers=Maksimālais strādņu skaits
+monitor.queue.numberinqueue=Skaits rindā
monitor.queue.review=Pārbaudīt konfigurāciju
monitor.queue.review_add=Pārbaudīt/Pievienot strādņus
monitor.queue.configuration=Sākotnējā konfigurācija
@@ -2773,6 +2897,12 @@ monitor.queue.pool.flush.title=Izlīdzināšanas rinda
monitor.queue.pool.flush.desc=Izlīdzināsana pievienos strādnieku, kas tiks apturēts tiklīdz rinda ir tukša vai tai iestājas noildze.
monitor.queue.pool.flush.submit=Pievienot izlīdzināsanas strādnieku
monitor.queue.pool.flush.added=Izlīdzināšanas strādnieks pievienots rindai %[1]s
+monitor.queue.pool.pause.title=Apturēt rindu
+monitor.queue.pool.pause.desc=Apturot rindu, tās dati netiks apstrādāti
+monitor.queue.pool.pause.submit=Apturēt rindu
+monitor.queue.pool.resume.title=Atsākt rindu
+monitor.queue.pool.resume.desc=Noteikt šai rindai atsākt darbu
+monitor.queue.pool.resume.submit=Atsākt rindu
monitor.queue.settings.title=Pūla iestatījumi
monitor.queue.settings.desc=Pūli var dinamiski augt un paildzinātu atbildi uz strādņu rindas bloķēšanu. Šis izmaiņas ietekmēs pašreizējās strādņu grupas.
@@ -2903,4 +3033,94 @@ error.no_unit_allowed_repo=Jums nav tiesību aplūkot nevienu šī repozitorija
error.unit_not_allowed=Jums nav tiesību piekļūt šai repozitorija sadaļai.
[packages]
+title=Pakotnes
+desc=Pārvaldīt repozitorija pakotnes.
+empty=Pašlaik šeit nav nevienas pakotnes.
+empty.documentation=Papildus informācija par pakotņu reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/overview">dokumentācijā</a>.
+filter.type=Veids
+filter.type.all=Visas
+filter.no_result=Pēc norādītajiem kritērijiem nekas netika atrasts.
+filter.container.tagged=Ar atzīmi
+filter.container.untagged=Bez atzīmes
+published_by=Publicēja <a href="%[2]s">%[3]s</a> %[1]s
+published_by_in=Publicēja <a href="%[2]s">%[3]s</a> %[1]s repozitorijā <a href="%[4]s"><strong>%[5]s</strong></a>
+installation=Instalācija
+about=Par šo pakotni
+requirements=Prasības
+dependencies=Atkarības
+keywords=Atslēgvārdi
+details=Papildu informācija
+details.author=Autors
+details.project_site=Projekta lapa
+details.license=Licence
+assets=Resursi
+versions=Versijas
+versions.on=publicēta
+versions.view_all=Parādīt visas
+dependency.id=ID
+dependency.version=Versija
+composer.registry=Pievienojiet šo reģistru savā <code>~/.composer/config.json</code> failā:
+composer.install=Lai instalētu Composer pakotni, izpildiet sekojošu komandu:
+composer.documentation=Papildus informācija par Composer reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/composer/">dokumentācijā</a>.
+composer.dependencies=Atkarības
+composer.dependencies.development=Izstrādes atkarības
+conan.details.repository=Repozitorijs
+conan.registry=Konfigurējiet šo reģistru no komandrindas:
+conan.install=Lai instalētu Conan pakotni, izpildiet sekojošu komandu:
+conan.documentation=Papildus informācija par Conan reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/conan/">dokumentācijā</a>.
+container.details.type=Attēla formāts
+container.details.platform=Platforma
+container.details.repository_site=Repozitorija lapa
+container.details.documentation_site=Dokumentācijas lapa
+container.pull=Atgādājiet šo attēlu no komandrindas:
+container.documentation=Papildus informācija par konteineru reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/container/">dokumentācijā</a>.
+container.multi_arch=OS / arhitektūra
+container.layers=Attēla slāņi
+container.labels=Etiķetes
+container.labels.key=Atslēga
+container.labels.value=Vērtība
+generic.download=Lejupielādēt pakotni, izmantojot, komandrindu:
+generic.documentation=Papildus informācija par ģenerisku pakotņu reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/generic">dokumentācijā</a>.
+helm.registry=Konfigurējiet šo reģistru no komandrindas:
+helm.install=Lai instalētu pakotni, nepieciešams izpildīt sekojošu komandu:
+helm.documentation=Papildus informācija par Helm reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/helm/">dokumentācijā</a>.
+maven.registry=Konfigurējiet šo reģistru sava projekta <code>pom.xml</code> failā:
+maven.install=Lai izmantotu pakotni, sadaļā <code>dependencies</code> failā <code>pom.xml</code> ievietojiet sekojošas rindas:
+maven.install2=Izpildiet no komandrindas:
+maven.download=Izpildiet no komandrindas, lai lejupielādētu šo atkarību:
+maven.documentation=Papildus informācija par Maven reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/maven/">dokumentācijā</a>.
+nuget.registry=Konfigurējiet šo reģistru no komandrindas:
+nuget.install=Lai instalētu NuGet pakotni, izpildiet sekojošu komandu:
+nuget.documentation=Papildus informācija par NuGet reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/nuget/">dokumentācijā</a>.
+nuget.dependency.framework=Mērķa ietvars
+npm.registry=Konfigurējiet šo reģistru sava projekta <code>.npmrc</code> failā:
+npm.install=Lai instalētu npm pakotni, izpildiet sekojošu komandu:
+npm.install2=vai pievienojiet failā package.json sekojošas rindas:
+npm.documentation=Papildus informācija par npm reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/npm/">dokumentācijā</a>.
+npm.dependencies=Atkarības
+npm.dependencies.development=Izstrādes atkarības
+npm.dependencies.peer=Netiešās atkarības
+npm.dependencies.optional=Neobligātās atkarības
+npm.details.tag=Tags
+pypi.requires=Nepieciešams Python
+pypi.install=Lai instalētu pip pakotni, izpildiet sekojošu komandu:
+pypi.documentation=Papildus informācija par PyPI reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">dokumentācijā</a>.
+rubygems.install=Lai instalētu gem pakotni, izpildiet sekojošu komandu:
+rubygems.install2=vai pievienojiet Gemfile:
+rubygems.dependencies.runtime=Izpildlaika atkarības
+rubygems.dependencies.development=Izstrādes atkarības
+rubygems.required.ruby=Nepieciešamā Ruby versija
+rubygems.required.rubygems=Nepieciešamā RubyGem versija
+rubygems.documentation=Papildus informācija par RubyGems reģistru pieejama <a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/rubygems/">dokumentācijā</a>.
+settings.link=Piesaistīt pakotni šim repozitorijam
+settings.link.description=Sasaistot pakotni ar repozitoriju, tā tiks attēlota repozitorija pakotņu sarakstā.
+settings.link.select=Norādiet repozitoriju
+settings.link.button=Atjaunot repozitorija saiti
+settings.link.success=Repozitorija saite tika veiksmīgi atjaunota.
+settings.link.error=Neizdevās atjaunot repozitorija saiti.
+settings.delete=Dzēst pakotni
+settings.delete.description=Pakotne tiks neatgriezeniski izdzēsta.
+settings.delete.notice=Tiks dzēsts %s (%s). Šī darbība ir neatgriezeniska. Vai vēlaties turpināt?
+settings.delete.success=Pakotne tika izdzēsta.
+settings.delete.error=Neizdevās izdzēst pakotni.
diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini
index cbd633d13..c65885a1e 100644
--- a/options/locale/locale_zh-TW.ini
+++ b/options/locale/locale_zh-TW.ini
@@ -131,7 +131,7 @@ license_desc=取得 <a target="_blank" rel="noopener noreferrer" href="https://c
install=安裝頁面
title=初始組態
docker_helper=如果您在 Docker 中執行 Gitea,請先閱讀<a target="_blank" rel="noopener noreferrer" href="%s">安裝指南</a>再來調整設定。
-require_db_desc=Gitea 需要 MySQL、PostgreSQL、SQLite3、MSSQL、TiDB(MySQL 協定)等其中一項。
+require_db_desc=Gitea 需要 MySQL、PostgreSQL、SQLite3、MSSQL、TiDB (MySQL 協定) 等其中一項。
db_title=資料庫設定
db_type=資料庫類型
host=主機
@@ -213,7 +213,7 @@ confirm_password=確認密碼
admin_email=電子信箱
install_btn_confirm=安裝 Gitea
test_git_failed=無法識別「git」命令:%v
-sqlite3_not_available=您目前的版本不支援 SQLite3,請從 %s 下載官方的預先編譯版本(不是 gobuild 版本)。
+sqlite3_not_available=您目前的版本不支援 SQLite3,請從 %s 下載官方的預先編譯版本 (不是 gobuild 版本)。
invalid_db_setting=資料庫設定不正確: %v
invalid_db_table=資料庫的資料表「%s」無效:%v
invalid_repo_path=儲存庫根目錄設定不正確:%v
@@ -391,13 +391,13 @@ issue.action.ready_for_review=<b>@%[1]s</b> 標記了此合併請求為準備好
issue.action.new=<b>@%[1]s</b> 建立了 #%[2]d。
issue.in_tree_path=在 %s 中:
-release.new.subject=%[2]s 中的 %[1]s 發佈了
-release.new.text=<b>@%[1]s</b> 於 %[3]s 發佈了 %[2]s
+release.new.subject=%[2]s 中的 %[1]s 發布了
+release.new.text=<b>@%[1]s</b> 於 %[3]s 發布了 %[2]s
release.title=標題:%s
release.note=說明:
release.downloads=下載:
-release.download.zip=原始碼(ZIP)
-release.download.targz=原始碼(TAR.GZ)
+release.download.zip=原始碼 (ZIP)
+release.download.targz=原始碼 (TAR.GZ)
repo.transfer.subject_to=%s 想要把「%s」轉移給 %s
repo.transfer.subject_to_you=%s 想要把「%s」轉移給您
@@ -491,7 +491,9 @@ auth_failed=授權認證失敗:%v
still_own_repo=此帳戶仍然擁有一個或多個儲存庫,您必須先刪除或轉移它們。
still_has_org=此帳戶仍是一個或多個組織的成員,您必須先離開它們。
+still_own_packages=您的帳戶擁有一個或多個套件,請先刪除他們。
org_still_own_repo=該組織仍然是某些儲存庫的擁有者,您必須先轉移或刪除它們才能執行刪除組織!
+org_still_own_packages=此組織擁有一個或多個套件,請先刪除他們。
target_branch_not_exist=目標分支不存在
@@ -768,7 +770,7 @@ or_enter_secret=或者輸入密碼: %s
then_enter_passcode=然後輸入應用程式中顯示的驗證碼:
passcode_invalid=無效的驗證碼,請重試。
twofa_enrolled=您的帳戶已經啟用了兩步驟驗證。請將備用驗證碼 (%s) 保存到一個安全的地方,它只會顯示這麼一次!
-twofa_failed_get_secret=取得密鑰(Secret)失敗。
+twofa_failed_get_secret=取得密鑰 (Secret) 失敗。
webauthn_desc=安全金鑰是包含加密密鑰的硬體設備,它們可以用於兩步驟驗證。安全金鑰必須支援 <a rel="noreferrer" target="_blank" href="https://w3c.github.io/webauthn/#webauthn-authenticator">WebAuthn Authenticator</a> 標準。
webauthn_register_key=新增安全金鑰
@@ -837,7 +839,7 @@ download_bundle=下載 BUNDLE
generate_repo=產生儲存庫
generate_from=產生自
repo_desc=儲存庫描述
-repo_desc_helper=輸入簡介(非必要)
+repo_desc_helper=輸入簡介 (選用)
repo_lang=儲存庫語言
repo_gitignore_helper=選擇 .gitignore 範本
repo_gitignore_helper_desc=從常見語言範本清單中挑選忽略追蹤的檔案。預設情況下各種語言建置工具產生的特殊檔案都包含在 .gitignore 中。
@@ -849,12 +851,12 @@ license_helper_desc=授權條款定義了他人使用您原始碼的允許和禁
readme=讀我檔案
readme_helper=選擇讀我檔案範本。
readme_helper_desc=這是您能為專案撰寫完整描述的地方。
-auto_init=初始化儲存庫(建立 .gitignore、授權條款和讀我檔案)
-trust_model_helper=選擇簽署驗證的信任模型。可用的選項:
-trust_model_helper_collaborator=協作者:信任協作者的簽署
-trust_model_helper_committer=提交者:信任與提交者相符的簽署
-trust_model_helper_collaborator_committer=協作者 + 提交者:信任協作者同時是提交者的簽署
-trust_model_helper_default=預設:使用此 Gitea 的預設儲存庫信任模式
+auto_init=初始化儲存庫 (加入 .gitignore、授權條款和讀我檔案)
+trust_model_helper=選擇簽署驗證的信任模型。可用的選項:
+trust_model_helper_collaborator=協作者: 信任協作者的簽署
+trust_model_helper_committer=提交者: 信任與提交者相符的簽署
+trust_model_helper_collaborator_committer=協作者 + 提交者: 信任協作者同時是提交者的簽署
+trust_model_helper_default=預設: 使用此 Gitea 的預設儲存庫信任模式
create_repo=建立儲存庫
default_branch=預設分支
default_branch_helper=預設分支是合併請求和提交程式碼的基礎分支。
@@ -943,7 +945,7 @@ migrate_items_labels=標籤
migrate_items_issues=問題
migrate_items_pullrequests=合併請求
migrate_items_merge_requests=合併請求
-migrate_items_releases=版本發佈
+migrate_items_releases=版本發布
migrate_repo=遷移儲存庫
migrate.clone_address=從 URL 遷移 / Clone
migrate.clone_address_desc=現有存儲庫的 HTTP(S) 或 Git Clone URL
@@ -974,7 +976,7 @@ migrate.migrating_git=正在遷移 Git 資料
migrate.migrating_topics=正在遷移主題
migrate.migrating_milestones=正在遷移里程碑
migrate.migrating_labels=正在遷移標籤
-migrate.migrating_releases=正在遷移版本發佈
+migrate.migrating_releases=正在遷移版本發布
migrate.migrating_issues=正在遷移問題
migrate.migrating_pulls=正在遷移合併請求
@@ -996,7 +998,7 @@ no_desc=暫無描述
quick_guide=快速幫助
clone_this_repo=Clone 此儲存庫
create_new_repo_command=從命令列建立新儲存庫。
-push_exist_repo=從命令行推送已經建立的儲存庫
+push_exist_repo=從命令列推送已存在的儲存庫
empty_message=此儲存庫未包含任何內容。
broken_message=無法讀取此儲存庫底層的 Git 資料。請聯絡此 Gitea 執行個體的管理員或刪除此儲存庫。
@@ -1012,6 +1014,7 @@ tags=標籤
issues=問題
pulls=合併請求
project_board=專案
+packages=套件
labels=標籤
org_labels_desc=組織層級標籤可用於此組織下的<strong>所有存儲庫</strong>。
org_labels_desc_manage=管理
@@ -1019,10 +1022,10 @@ org_labels_desc_manage=管理
milestones=里程碑
commits=提交歷史
commit=提交
-release=版本發佈
-releases=版本發佈
+release=版本發布
+releases=版本發布
tag=標籤
-released_this=發佈了此版本
+released_this=發布了此版本
file.title=%s 於 %s
file_raw=原始文件
file_history=歷史記錄
@@ -1033,10 +1036,10 @@ file_permalink=永久連結
file_too_large=檔案太大,無法顯示。
bidi_bad_header=`此檔案含有未預期的 Bidirectional Unicode 字元!`
bidi_bad_description=`此檔案含有未預期的 Bidirectional Unicode 字元,這些字元的處理方式可能和下面呈現的不同。若您是有意且合理的使用,您可以放心地忽略此警告。使用 Escape 按鈕顯示隱藏的字元。`
-bidi_bad_description_escaped=`此檔案含有未預期的 Bidirectional Unicode 字元。隱藏的 Unicode 字元已在下面被跳脫(Escaped)。使用 Unescape 按鈕以顯示它們呈現的樣子。`
+bidi_bad_description_escaped=`此檔案含有未預期的 Bidirectional Unicode 字元。隱藏的 Unicode 字元已在下面被跳脫 (Escaped)。使用 Unescape 按鈕以顯示它們呈現的樣子。`
unicode_header=`此檔案含有隱藏的 Unicode 字元!`
unicode_description=`此檔案含有隱藏的 Unicode 字元,這些字元的處理方式可能和下面呈現的不同。若您是有意且合理的使用,您可以放心地忽略此警告。使用 Escape 按鈕顯示隱藏的字元。`
-unicode_description_escaped=`此檔案含有隱藏的 Unicode 字元。隱藏的 Unicode 字元已在下面被跳脫(Escaped)。使用 Unescape 按鈕以顯示它們呈現的樣子。`
+unicode_description_escaped=`此檔案含有隱藏的 Unicode 字元。隱藏的 Unicode 字元已在下面被跳脫 (Escaped)。使用 Unescape 按鈕以顯示它們呈現的樣子。`
line_unicode=`這一行有隱藏的 Unicode 字元`
escape_control_characters=Escape
@@ -1085,7 +1088,7 @@ editor.patch=套用 Patch
editor.patching=正在 Patch:
editor.fail_to_apply_patch=無法套用 Patch「%s」
editor.new_patch=新增 Patch
-editor.commit_message_desc=(選填)加入詳細說明...
+editor.commit_message_desc=(選用) 加入詳細說明...
editor.signoff_desc=在提交訊息底部加入提交者的「Signed-off-by」資訊。
editor.commit_directly_to_this_branch=直接提交到 <strong class="branch-name">%s</strong> 分支。
editor.create_new_branch=為此提交建立<strong>新分支</strong>並提出合併請求。
@@ -1155,7 +1158,7 @@ ext_issues.desc=連結到外部問題追蹤器。
projects=專案
projects.desc=在專案看板中管理問題與合併請求。
-projects.description=描述(非必要)
+projects.description=描述 (選用)
projects.description_placeholder=描述
projects.create=建立專案
projects.title=標題
@@ -1326,7 +1329,7 @@ issues.ref_reopening_from=`<a href="%[3]s">關聯了合併請求 %[4]s 將重新
issues.ref_closed_from=`<a href="%[3]s">關閉了這個問題 %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_reopened_from=`<a href="%[3]s">重新開放了這個問題 %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
issues.ref_from=`自 %[1]s`
-issues.poster=發佈者
+issues.poster=發布者
issues.collaborator=協作者
issues.owner=擁有者
issues.re_request_review=再次請求審核
@@ -1380,7 +1383,7 @@ issues.unlock.title=解鎖此問題的對話。
issues.comment_on_locked=您無法在已鎖定的問題上留言。
issues.delete=刪除
issues.delete.title=刪除此問題?
-issues.delete.text=您真的要刪除此問題嗎?(這將會永久移除所有內容。若您還想保留,請考慮改為關閉它。)
+issues.delete.text=您真的要刪除此問題嗎?(這將會永久移除所有內容。若您還想保留,請考慮改為關閉它。)
issues.tracker=時間追蹤
issues.start_tracking_short=開始計時
issues.start_tracking=開始時間追蹤
@@ -1438,8 +1441,8 @@ issues.dependency.pr_close_blocked=在您合併以前,您必須先關閉所有
issues.dependency.blocks_short=阻擋
issues.dependency.blocked_by_short=先決於
issues.dependency.remove_header=移除先決條件
-issues.dependency.issue_remove_text=即將從此問題移除先決條件。是否繼續?
-issues.dependency.pr_remove_text=即將從此合併請求移除先決條件。是否繼續?
+issues.dependency.issue_remove_text=即將從此問題移除先決條件。是否繼續?
+issues.dependency.pr_remove_text=即將從此合併請求移除先決條件。是否繼續?
issues.dependency.setting=啟用問題及合併請求的先決條件
issues.dependency.add_error_same_issue=您無法將問題設定為自己的先決條件。
issues.dependency.add_error_dep_issue_not_exist=先決條件問題不存在。
@@ -1507,7 +1510,7 @@ pulls.nothing_to_compare_and_allow_empty_pr=這些分支的內容相同,此合
pulls.has_pull_request=`已有介於這些分支間的合併請求:<a href="%[1]s">%[2]s#%[3]d</a>`
pulls.create=建立合併請求
pulls.title_desc=請求將 %[1]d 次程式碼提交從 <code>%[2]s</code> 合併至 <code id="branch_target">%[3]s</code>
-pulls.merged_title_desc=將 %[1]d 次代碼提交從 <code>%[2]s</code> 合併至 <code>%[3]s</code> %[4]s
+pulls.merged_title_desc=將 %[1]d 次提交從 <code>%[2]s</code> 合併至 <code>%[3]s</code> %[4]s
pulls.change_target_branch_at=`將目標分支從 <b>%s</b> 更改為 <b>%s</b> %s`
pulls.tab_conversation=對話內容
pulls.tab_commits=程式碼提交
@@ -1521,7 +1524,7 @@ pulls.manually_merged_as=此合併請求已被手動合併為 <a rel="nofollow"
pulls.is_closed=合併請求已被關閉。
pulls.has_merged=合併請求已合併。
pulls.title_wip_desc=`<a href="#">標題用 <strong>%s</strong> 開頭</a>以避免意外地合併此合併請求。`
-pulls.cannot_merge_work_in_progress=此合併請求被標記為還在進行中(WIP)。
+pulls.cannot_merge_work_in_progress=此合併請求被標記為還在進行中 (WIP)。
pulls.still_in_progress=還在進行中嗎?
pulls.add_prefix=加入 <strong>%s</strong> 前綴
pulls.remove_prefix=移除 <strong>%s</strong> 前綴
@@ -1618,7 +1621,7 @@ milestones.completeness=%d%% 完成
milestones.create=建立里程碑
milestones.title=標題
milestones.desc=描述
-milestones.due_date=截止日期(可選)
+milestones.due_date=截止日期 (選用)
milestones.clear=清除
milestones.invalid_due_date_format=截止日期的格式必須為「yyyy-mm-dd」。
milestones.create_success=已建立里程碑「%s」。
@@ -1720,8 +1723,8 @@ activity.unresolved_conv_desc=這些最近更改的問題和合併請求尚未
activity.unresolved_conv_label=開放
activity.title.releases_1=%d 個版本
activity.title.releases_n=%d 個版本
-activity.title.releases_published_by=%[2]s發佈了 %[1]s
-activity.published_release_label=已發佈
+activity.title.releases_published_by=%[2]s發布了 %[1]s
+activity.published_release_label=已發布
activity.no_git_activity=期間內沒有任何提交動態
activity.git_stats_exclude_merges=不計合併,
activity.git_stats_author_1=%d 位作者
@@ -1814,9 +1817,10 @@ settings.pulls.allow_rebase_merge=啟用 Rebase 合併提交
settings.pulls.allow_rebase_merge_commit=啟用 Rebase 顯式合併提交(--no-ff)
settings.pulls.allow_squash_commits=啟用 Squash 合併提交
settings.pulls.allow_manual_merge=允許將合併請求標記為手動合併
-settings.pulls.enable_autodetect_manual_merge=啟用自動偵測手動合併(注意:在某些特殊情況下可能發生誤判)
+settings.pulls.enable_autodetect_manual_merge=啟用自動偵測手動合併 (注意: 在某些特殊情況下可能發生誤判)
settings.pulls.allow_rebase_update=啟用透過 Rebase 更新合併請求分支
settings.pulls.default_delete_branch_after_merge=預設在合併後刪除合併請求分支
+settings.packages_desc=啟用儲存庫套件註冊中心
settings.projects_desc=啟用儲存庫專案
settings.admin_settings=管理員設定
settings.admin_enable_health_check=啟用儲存庫的健康檢查 (git fsck)
@@ -1850,7 +1854,7 @@ settings.transfer_form_title=輸入儲存庫名稱以確認:
settings.transfer_in_progress=目前正在進行轉移。如果您想要將此儲存庫轉移給其他使用者,請取消他。
settings.transfer_notices_1=- 如果將此儲存庫轉移給個別使用者,您將會失去此儲存庫的存取權。
settings.transfer_notices_2=- 如果將此儲存庫轉移到您(共同)擁有的組織,您將能繼續保有此儲存庫的存取權。
-settings.transfer_notices_3=- 如果此儲存庫為私有儲存庫且將轉移給個別使用者,此動作確保該使用者至少擁有讀取權限(必要時將會修改權限)。
+settings.transfer_notices_3=- 如果此儲存庫為私有儲存庫且將轉移給個別使用者,此動作確保該使用者至少擁有讀取權限 (必要時將會修改權限)。
settings.transfer_owner=新擁有者
settings.transfer_perform=進行轉移
settings.transfer_started=此儲存庫已被標記為待轉移且正在等待「%s」的確認
@@ -1860,13 +1864,13 @@ settings.trust_model=簽署信任模式
settings.trust_model.default=預設信任模式
settings.trust_model.default.desc=使用此 Gitea 的預設儲存庫信任模式。
settings.trust_model.collaborator=協作者
-settings.trust_model.collaborator.long=協作者:信任協作者的簽署
-settings.trust_model.collaborator.desc=此儲存庫協作者的有效簽署將被標記為「受信任」(無論它們是否符合提交者),簽署只符合提交者時將標記為「不受信任」,都不符合時標記為「不符合」。
+settings.trust_model.collaborator.long=協作者: 信任協作者的簽署
+settings.trust_model.collaborator.desc=此儲存庫協作者的有效簽署將被標記為「受信任」(無論它們是否符合提交者),簽署只符合提交者時將標記為「不受信任」,都不符合時標記為「不符合」。
settings.trust_model.committer=提交者
-settings.trust_model.committer.long=提交者:信任與提交者相符的簽署(此選項與 GitHub 相同,這會強制 Gitea 簽署提交並以 Gitea 作為提交者)
+settings.trust_model.committer.long=提交者: 信任與提交者相符的簽署 (此選項與 GitHub 相同,這會強制 Gitea 簽署提交並以 Gitea 作為提交者)
settings.trust_model.committer.desc=提交者的有效簽署將被標記為「受信任」,否則將被標記為「不符合」。這會強制 Gitea 成為受簽署提交的提交者,實際的提交者將於提交訊息結尾被標記為「Co-authored-by:」和「Co-committed-by:」。預設的 Gitea 金鑰必須符合資料庫中的一位使用者。
settings.trust_model.collaboratorcommitter=協作者+提交者
-settings.trust_model.collaboratorcommitter.long=協作者 + 提交者:信任協作者同時是提交者的簽署
+settings.trust_model.collaboratorcommitter.long=協作者 + 提交者: 信任協作者同時是提交者的簽署
settings.trust_model.collaboratorcommitter.desc=此儲存庫協作者的有效簽署在他同時是提交者時將被標記為「受信任」,簽署只符合提交者時將標記為「不受信任」,都不符合時標記為「不符合」。這會強制 Gitea 成為受簽署提交的提交者,實際的提交者將於提交訊息結尾被標記為「Co-Authored-By:」和「Co-Committed-By:」。預設的 Gitea 金鑰必須符合資料庫中的一位使用者。
settings.wiki_delete=刪除 Wiki 資料
settings.wiki_delete_desc=刪除儲存庫 Wiki 資料是永久的且不可還原。
@@ -1942,8 +1946,8 @@ settings.event_delete=刪除
settings.event_delete_desc=刪除分支或標籤。
settings.event_fork=Fork
settings.event_fork_desc=儲存庫已被 fork。
-settings.event_release=版本發佈
-settings.event_release_desc=在儲存庫中發佈、更新或刪除版本。
+settings.event_release=版本發布
+settings.event_release_desc=在儲存庫中發布、更新或刪除版本。
settings.event_push=推送
settings.event_push_desc=推送到儲存庫。
settings.event_repository=儲存庫
@@ -1974,6 +1978,8 @@ settings.event_pull_request_review=合併請求審核
settings.event_pull_request_review_desc=核准、退回或提出審核留言。
settings.event_pull_request_sync=合併請求同步
settings.event_pull_request_sync_desc=合併請求同步。
+settings.event_package=套件
+settings.event_package_desc=套件已在儲存庫中建立或刪除。
settings.branch_filter=分支篩選
settings.branch_filter_desc=推送、建立分支、刪除分支事件的白名單,請使用 glob 比對模式。如果留白或輸入<code>*</code>,所有分支的事件都會被回報。語法參見 <a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a>。範例:<code>master</code>, <code>{master,release*}</code>。
settings.active=啟用
@@ -2054,9 +2060,9 @@ settings.dismiss_stale_approvals=捨棄過時的核可
settings.dismiss_stale_approvals_desc=當新的提交有修改到合併請求的內容,並被推送到此分支時,將捨棄舊的核可。
settings.require_signed_commits=僅接受經簽署的提交
settings.require_signed_commits_desc=拒絕未經簽署或未經驗證的提交推送到此分支。
-settings.protect_protected_file_patterns=受保護的檔案模式(以分號區隔「\;」):
+settings.protect_protected_file_patterns=受保護的檔案模式 (以分號區隔「\;」):
settings.protect_protected_file_patterns_desc=即便使用者有權限新增、修改、刪除此分支的檔案,仍不允許直接修改受保護的檔案。可以用半形分號「\;」分隔多個模式。請於<a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> 文件查看模式格式。範例:<code>.drone.yml</code>, <code>/docs/**/*.txt</code>。
-settings.protect_unprotected_file_patterns=未受保護的檔案模式(以分號區隔「\;」):
+settings.protect_unprotected_file_patterns=未受保護的檔案模式 (以分號區隔「\;」):
settings.protect_unprotected_file_patterns_desc=當使用者有寫入權限時,可繞過推送限制,直接修改未受保護的檔案。可以用半形分號「\;」分隔多個模式。請於<a href="https://pkg.go.dev/github.com/gobwas/glob#Compile">github.com/gobwas/glob</a> 文件查看模式格式。範例:<code>.drone.yml</code>, <code>/docs/**/*.txt</code>。
settings.add_protected_branch=啟用保護
settings.delete_protected_branch=停用保護
@@ -2191,20 +2197,20 @@ diff.image.overlay=重疊
diff.has_escaped=這一行有隱藏的 Unicode 字元
releases.desc=追蹤專案版本和檔案下載。
-release.releases=版本發佈
+release.releases=版本發布
release.detail=版本詳情
release.tags=標籤
-release.new_release=發佈新版本
+release.new_release=發布新版本
release.draft=草稿
-release.prerelease=預發佈版本
+release.prerelease=預發布版本
release.stable=穩定
release.compare=比較
release.edit=編輯
release.ahead.commits=<strong>%d</strong> 次提交
-release.ahead.target=在此版本發佈後被加入到 %s
+release.ahead.target=在此版本發布後被加入到 %s
release.source_code=程式碼
-release.new_subheader=發佈、整理專案的版本。
-release.edit_subheader=發佈、整理專案的版本。
+release.new_subheader=發布、整理專案的版本。
+release.edit_subheader=發布、整理專案的版本。
release.tag_name=標籤名稱
release.target=目標分支
release.tag_helper=新增或選擇一個既有的標籤。
@@ -2213,17 +2219,17 @@ release.content=內容
release.prerelease_desc=標記為 Pre-Release
release.prerelease_helper=標記此版本不適合生產使用。
release.cancel=取消
-release.publish=發佈版本
+release.publish=發布版本
release.save_draft=儲存草稿
-release.edit_release=更新發佈
-release.delete_release=刪除發佈
+release.edit_release=更新發布
+release.delete_release=刪除發布
release.delete_tag=刪除標籤
-release.deletion=刪除發佈
-release.deletion_desc=刪除版本發佈只會將它從 Gitea 移除。儲存庫內容和歷史將保持不變,是否繼續?
-release.deletion_success=已刪除此版本發佈。
+release.deletion=刪除發布
+release.deletion_desc=刪除版本發布只會將它從 Gitea 移除。儲存庫內容和歷史將保持不變,是否繼續?
+release.deletion_success=已刪除此版本發布。
release.deletion_tag_desc=即將從儲存庫移除此標籤。儲存庫內容和歷史將保持不變,是否繼續?
release.deletion_tag_success=已刪除此標籤。
-release.tag_name_already_exist=已經存在使用相同標籤的發佈版本。
+release.tag_name_already_exist=已經存在使用相同標籤的發布版本。
release.tag_name_invalid=標籤名稱無效。
release.tag_name_protected=標籤名稱已受保護。
release.tag_already_exist=此標籤名稱已存在。
@@ -2318,9 +2324,9 @@ settings.permission=權限
settings.repoadminchangeteam=儲存庫管理者可增加與移除團隊權限
settings.visibility=瀏覽權限
settings.visibility.public=公開
-settings.visibility.limited=受限(只有登入的使用者才能看到)
+settings.visibility.limited=受限 (只有登入的使用者才能看到)
settings.visibility.limited_shortname=受限
-settings.visibility.private=私有(只有組織成員才能看到)
+settings.visibility.private=私有 (只有組織成員才能看到)
settings.visibility.private_shortname=私有
settings.update_settings=更新設定
@@ -2419,7 +2425,7 @@ dashboard.new_version_hint=現已推出 Gitea %s,您正在執行 %s。查看<a
dashboard.statistic=摘要
dashboard.operations=維護作業
dashboard.system_status=系統狀態
-dashboard.statistic_info=Gitea 資料庫統計: <b>%d</b> 位使用者,<b>%d</b> 個組織,<b>%d</b> 個公鑰,<b>%d</b> 個儲存庫,<b>%d</b> 個儲存庫關注,<b>%d</b> 個星號,~<b>%d</b> 次行為,<b>%d</b> 條權限記錄,<b>%d</b> 個問題,<b>%d</b> 則留言,<b>%d</b> 個社群帳戶,<b>%d</b> 個使用者關注,<b>%d</b> 個鏡像,<b>%d</b> 個版本發佈,<b>%d</b> 個認證來源,<b>%d</b> 個 Webhook ,<b>%d</b> 個里程碑,<b>%d</b> 個標籤,<b>%d</b> 個 Hook 任務,<b>%d</b> 個團隊,<b>%d</b> 個更新任務,<b>%d</b> 個附件。
+dashboard.statistic_info=Gitea 資料庫統計: <b>%d</b> 位使用者,<b>%d</b> 個組織,<b>%d</b> 個公鑰,<b>%d</b> 個儲存庫,<b>%d</b> 個儲存庫關注,<b>%d</b> 個星號,~<b>%d</b> 次行為,<b>%d</b> 條權限記錄,<b>%d</b> 個問題,<b>%d</b> 則留言,<b>%d</b> 個社群帳戶,<b>%d</b> 個使用者追蹤,<b>%d</b> 個鏡像,<b>%d</b> 個版本發布,<b>%d</b> 個認證來源,<b>%d</b> 個 Webhook ,<b>%d</b> 個里程碑,<b>%d</b> 個標籤,<b>%d</b> 個 Hook 任務,<b>%d</b> 個團隊,<b>%d</b> 個更新任務,<b>%d</b> 個附件。
dashboard.operation_name=作業名稱
dashboard.operation_switch=開關
dashboard.operation_run=執行
@@ -2438,7 +2444,7 @@ dashboard.cron.error=Cron 中的錯誤: %s: %[3]s
dashboard.cron.finished=Cron: %[1]s 已完成
dashboard.delete_inactive_accounts=刪除所有未啟用帳戶
dashboard.delete_inactive_accounts.started=刪除所有未啟用帳戶的任務已啟動。
-dashboard.delete_repo_archives=刪除所有儲存庫存檔(ZIP, TAR.GZ, etc..)
+dashboard.delete_repo_archives=刪除所有儲存庫存檔 (ZIP, TAR.GZ, etc..)
dashboard.delete_repo_archives.started=刪除所有儲存庫存檔的任務已啟動。
dashboard.delete_missing_repos=刪除所有遺失 Git 檔案的儲存庫
dashboard.delete_missing_repos.started=刪除所有遺失 Git 檔案的儲存庫的任務已啟動。
@@ -2448,7 +2454,7 @@ dashboard.repo_health_check=對所有儲存庫進行健康檢查
dashboard.check_repo_stats=檢查所有儲存庫的統計資料
dashboard.archive_cleanup=刪除舊的儲存庫存檔
dashboard.deleted_branches_cleanup=清理已刪除的分支
-dashboard.update_migration_poster_id=更新遷移發佈者 ID
+dashboard.update_migration_poster_id=更新遷移發布者 ID
dashboard.git_gc_repos=對所有儲存庫進行垃圾回收
dashboard.resync_all_sshkeys=使用 Gitea 的 SSH 金鑰更新「.ssh/authorized_keys」檔案。
dashboard.resync_all_sshkeys.desc=(內建 SSH 伺服器無需使用。)
@@ -2458,6 +2464,7 @@ dashboard.resync_all_hooks=重新同步所有儲存庫的 pre-receive、update
dashboard.reinit_missing_repos=重新初始化所有記錄存在但遺失的 Git 儲存庫
dashboard.sync_external_users=同步外部使用者資料
dashboard.cleanup_hook_task_table=清理 hook_task 資料表
+dashboard.cleanup_packages=清理已過期的套件
dashboard.server_uptime=服務執行時間
dashboard.current_goroutine=目前的 Goroutines 數量
dashboard.current_memory_usage=目前記憶體使用量
@@ -2528,6 +2535,7 @@ users.delete_account=刪除使用者帳戶
users.cannot_delete_self=您無法刪除您自己
users.still_own_repo=這個使用者還擁有一個或更多的儲存庫。請先刪除或是轉移這些儲存庫。
users.still_has_org=此使用者是組織的成員。請先將他從組織中移除。
+users.still_own_packages=此使用者擁有一個或多個套件,請先刪除這些套件。
users.deletion_success=使用者帳戶已被刪除。
users.reset_2fa=重設兩步驟驗證
users.list_status_filter.menu_text=篩選
@@ -2554,7 +2562,7 @@ emails.updated=信箱已更新
emails.not_updated=電子信箱更新失敗: %v
emails.duplicate_active=此信箱已被其他使用者使用
emails.change_email_header=更新電子信箱屬性
-emails.change_email_text=您確定要更新這個電子信箱?
+emails.change_email_text=您確定要更新這個電子信箱?
orgs.org_manage_panel=組織管理
orgs.name=組織名稱
@@ -2574,6 +2582,16 @@ repos.forks=Fork 數
repos.issues=問題數
repos.size=大小
+packages.package_manage_panel=套件管理
+packages.total_size=總大小: %s
+packages.owner=擁有者
+packages.creator=建立者
+packages.name=名稱
+packages.version=版本
+packages.type=類型
+packages.repository=儲存庫
+packages.size=大小
+packages.published=已發布
defaulthooks=預設 Webhook
defaulthooks.desc=當觸發某些 Gitea 事件時,Webhook 會自動發出 HTTP POST 請求到指定的伺服器。這裡所定義的 Webhook 是預設的,並且會複製到所有新儲存庫。在 <a target="_blank" rel="noopener" href="https://docs.gitea.io/en-us/webhooks/">Webhook 指南</a>閱讀更多內容。
@@ -2617,11 +2635,11 @@ auths.filter=使用者篩選器
auths.admin_filter=管理者篩選器
auths.restricted_filter=受限制的篩選器
auths.restricted_filter_helper=留白則不限制任何使用者。使用米字「*」將所有不符合管理員篩選條件的使用者設定為受限。
-auths.verify_group_membership=驗證 LDAP 群組成員資格(篩選器留空以跳過)
+auths.verify_group_membership=驗證 LDAP 群組成員資格 (篩選器留空以跳過)
auths.group_search_base=群組搜尋的 Base DN
auths.group_attribute_list_users=包含使用者清單的群組屬性
auths.user_attribute_in_group=群組中列出的使用者屬性
-auths.map_group_to_team=對應 LDAP 群組到組織團隊(欄位留空以跳過)
+auths.map_group_to_team=對應 LDAP 群組到組織團隊 (欄位留空以跳過)
auths.map_group_to_team_removal=如果使用者不屬於相對應的 LDAP 群組,將使用者從已同步的團隊移除。
auths.enable_ldap_groups=啟用 LDAP 群組
auths.ms_ad_sa=MS AD 搜尋屬性
@@ -2632,12 +2650,12 @@ auths.allowed_domains=域名白名單
auths.allowed_domains_helper=留白以允許所有域名。以半形逗號「,」分隔多個域名。
auths.skip_tls_verify=忽略 TLS 驗證
auths.force_smtps=強制 SMTPS
-auths.force_smtps_helper=SMTPS 總是使用 465 埠。設定此選項以強制 SMTPS 使用其他埠。(除此之外若主機支援的話 STARTTLS 也會使用該埠。)
+auths.force_smtps_helper=SMTPS 總是使用 465 埠。設定此選項以強制 SMTPS 使用其他埠。(除此之外若主機支援的話 STARTTLS 也會使用該埠。)
auths.helo_hostname=HELO 主機名稱
auths.helo_hostname_helper=用 HELO 傳送的主機名稱。留空以傳送目前的主機名稱。
auths.disable_helo=停用 HELO
auths.pam_service_name=PAM 服務名稱
-auths.pam_email_domain=PAM 電子信箱域名(非必要)
+auths.pam_email_domain=PAM 電子信箱域名 (選用)
auths.oauth2_provider=OAuth2 提供者
auths.oauth2_icon_url=圖示 URL
auths.oauth2_clientID=客戶端 ID (金鑰)
@@ -2651,23 +2669,23 @@ auths.oauth2_emailURL=電子郵件 URL
auths.skip_local_two_fa=跳過本地兩步驟驗證
auths.skip_local_two_fa_helper=保持未設定代表使用兩步驟驗證的本地使用者仍然需要通過兩步驟驗證才能登入
auths.oauth2_tenant=租戶
-auths.oauth2_scopes=額外的授權範圍(Scope)
+auths.oauth2_scopes=額外的授權範圍 (Scope)
auths.oauth2_required_claim_name=必須填寫 Claim 名稱
auths.oauth2_required_claim_name_helper=填寫此名稱以限制 Claim 中有此名稱的使用者才能從此來源登入
auths.oauth2_required_claim_value=必須填寫 Claim 值
auths.oauth2_required_claim_value_helper=填寫此名稱以限制 Claim 中有此名稱和值的使用者才能從此來源登入
-auths.oauth2_group_claim_name=Claim 名稱提供群組名稱給此來源。(選用)
-auths.oauth2_admin_group=管理員使用者的群組 Claim 值。(選用 - 需要上面的 Claim 名稱)
-auths.oauth2_restricted_group=受限制使用者的群組 Claim 值。(選用 - 需要上面的 Claim 名稱)
+auths.oauth2_group_claim_name=Claim 名稱提供群組名稱給此來源。(選用)
+auths.oauth2_admin_group=管理員使用者的群組 Claim 值。(選用 - 需要上面的 Claim 名稱)
+auths.oauth2_restricted_group=受限制使用者的群組 Claim 值。(選用 - 需要上面的 Claim 名稱)
auths.enable_auto_register=允許授權用戶自動註冊
auths.sspi_auto_create_users=自動建立使用者
auths.sspi_auto_create_users_helper=允許 SSPI 認證方法於使用者首次登入時自動建立新帳戶
auths.sspi_auto_activate_users=自動啟用使用者
auths.sspi_auto_activate_users_helper=允許 SSPI 認證方法自動啟用新使用者
auths.sspi_strip_domain_names=從帳號中移除域名
-auths.sspi_strip_domain_names_helper=勾選後,將從登入名稱中移除域名(例如:「DOMAIN\user」和「user@example.org」都會變成「user」)
+auths.sspi_strip_domain_names_helper=勾選後,將從登入名稱中移除域名 (例如:「DOMAIN\user」和「user@example.org」都會變成「user」)
auths.sspi_separator_replacement=用來替換 \, / 和 @ 的分隔符號
-auths.sspi_separator_replacement_helper=用來替換下級登入名稱分隔符號的字元(例如:「DOMAIN\user」中的「\」)和使用者主體名稱(例如:「user@example.org」中的「@」)。
+auths.sspi_separator_replacement_helper=用來替換下級登入名稱分隔符號的字元 (例如:「DOMAIN\user」中的「\」) 和使用者主體名稱 (例如:「user@example.org」中的「@」)。
auths.sspi_default_language=使用者預設語言
auths.sspi_default_language_helper=SSPI 認證方法自動建立之使用者的預設語言,留白以自動偵測。
auths.tips=幫助提示
@@ -2686,7 +2704,7 @@ auths.tip.twitter=建立應用程式並確保有啟用「Allow this application
auths.tip.discord=註冊新的應用程式。網址:https://discordapp.com/developers/applications/me
auths.tip.gitea=註冊新的 OAuth2 應用程式。到 https://docs.gitea.io/en-us/oauth2-provider/ 觀看指南
auths.tip.yandex=建立新的應用程式,從「Yandex.Passport API」區塊選擇「Access to email address」、「Access to user avatar」和「Access to username, first name and surname, gender」。網址:https://oauth.yandex.com/client/new
-auths.tip.mastodon=輸入您欲認證的 Mastodon 執行個體的自訂網址(或使用預設值)
+auths.tip.mastodon=輸入您欲認證的 Mastodon 執行個體的自訂網址 (或使用預設值)
auths.edit=修改認證來源
auths.activated=該認證來源已啟用
auths.new_success=已增加認證「%s」。
@@ -2813,8 +2831,8 @@ config.enable_federated_avatar=啟用 Federated Avatars
config.git_config=Git 組態
config.git_disable_diff_highlight=停用比較語法高亮
-config.git_max_diff_lines=差異比較時顯示的最多行數(單檔)
-config.git_max_diff_line_characters=差異比較時顯示的最多字元數(單行)
+config.git_max_diff_lines=差異比較時顯示的最多行數 (單檔)
+config.git_max_diff_line_characters=差異比較時顯示的最多字元數 (單行)
config.git_max_diff_files=差異比較時顯示的最多檔案數
config.git_gc_args=GC 參數
config.git_migrate_timeout=遷移逾時
@@ -2952,7 +2970,7 @@ mirror_sync_create=從鏡像同步了新參考 <a href="%[2]s">%[3]s</a> 到 <a
mirror_sync_delete=從鏡像同步並從 <a href="%[1]s">%[3]s</a> 刪除了參考 <code>%[2]s</code>
approve_pull_request=`核可了 <a href="%[1]s">%[3]s#%[2]s</a>`
reject_pull_request=`提出了修改建議 <a href="%[1]s">%[3]s#%[2]s</a>`
-publish_release=`發佈了 <a href="%[1]s">%[3]s</a> 的 <a href="%[2]s"> "%[4]s" </a>`
+publish_release=`發布了 <a href="%[1]s">%[3]s</a> 的 <a href="%[2]s"> "%[4]s" </a>`
review_dismissed=`取消了 <b>%[4]s</b> 對 <a href="%[1]s">%[3]s#%[2]s</a> 的審核`
review_dismissed_reason=原因:
create_branch=在 <a href="%[1]s">%[4]s</a> 中建立了分支 <a href="%[2]s">%[3]s</a>
@@ -3015,6 +3033,94 @@ error.no_unit_allowed_repo=您未被允許存取此儲存庫的任何區域。
error.unit_not_allowed=您未被允許訪問此儲存庫區域
[packages]
+title=套件
+desc=管理儲存庫套件。
+empty=目前還沒有套件。
+empty.documentation=關於套件註冊中心的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/overview">說明文件</a>。
+filter.type=類型
+filter.type.all=所有
+filter.no_result=沒有篩選結果。
+filter.container.tagged=已加標籤
+filter.container.untagged=未加標籤
+published_by=發布於 %[1]s 由 <a href="%[2]s">%[3]s</a>
+published_by_in=發布於 %[1]s 由 <a href="%[2]s">%[3]s</a> 在 <a href="%[4]s"><strong>%[5]s</strong></a>
+installation=安裝
+about=關於此套件
+requirements=需求
+dependencies=相依性
+keywords=關鍵字
+details=詳情
+details.author=作者
+details.project_site=專案網站
+details.license=授權條款
+assets=檔案
+versions=版本
+versions.on=於
+versions.view_all=檢視全部
dependency.id=ID
dependency.version=版本
+composer.registry=在您的 <code>~/.composer/config.json</code> 檔設定此註冊中心:
+composer.install=執行下列命令以使用 Composer 安裝此套件:
+composer.documentation=關於 Composer registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/composer/">說明文件</a>。
+composer.dependencies=相依性
+composer.dependencies.development=開發相依性
+conan.details.repository=儲存庫
+conan.registry=透過下列命令設定此註冊中心:
+conan.install=執行下列命令以使用 Conan 安裝此套件:
+conan.documentation=關於 Conan registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/conan/">說明文件</a>。
+container.details.type=映像檔類型
+container.details.platform=平台
+container.details.repository_site=儲存庫網站
+container.details.documentation_site=文件網站
+container.pull=透過下列命令拉取映像檔:
+container.documentation=關於 Container registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/container/">說明文件</a>。
+container.multi_arch=作業系統 / 架構
+container.layers=映像檔 Layers
+container.labels=標籤
+container.labels.key=鍵
+container.labels.value=值
+generic.download=透過下列命令下載套件:
+generic.documentation=關於通用 registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/generic">說明文件</a>。
+helm.registry=透過下列命令設定此註冊中心:
+helm.install=執行下列命令安裝此套件:
+helm.documentation=關於 Helm registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/helm/">說明文件</a>。
+maven.registry=在您的 <code>pom.xml</code> 檔設定此註冊中心:
+maven.install=若要使用此套件,請在您 <code>pom.xml</code> 檔的 <code>dependencies</code> 段落加入下列內容:
+maven.install2=透過下列命令執行:
+maven.download=透過下列命令下載相依性:
+maven.documentation=關於 Maven registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/maven/">說明文件</a>。
+nuget.registry=透過下列命令設定此註冊中心:
+nuget.install=執行下列命令以使用 NuGet 安裝此套件:
+nuget.documentation=關於 NuGet registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/nuget/">說明文件</a>。
+nuget.dependency.framework=目標框架
+npm.registry=在您的 <code>.npmrc</code> 檔設定此註冊中心:
+npm.install=執行下列命令以使用 npm 安裝此套件:
+npm.install2=或將它加到 package.json 檔:
+npm.documentation=關於 npm registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/npm/">說明文件</a>。
+npm.dependencies=相依性
+npm.dependencies.development=開發相依性
+npm.dependencies.peer=Peer 相依性
+npm.dependencies.optional=選用相依性
+npm.details.tag=標籤
+pypi.requires=需要 Python
+pypi.install=執行下列命令以使用 pip 安裝此套件:
+pypi.documentation=關於 PyPI registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/pypi/">說明文件</a>。
+rubygems.install=執行下列命令以使用 gem 安裝此套件:
+rubygems.install2=或將它加到 Gemfile:
+rubygems.dependencies.runtime=執行階段相依性
+rubygems.dependencies.development=開發相依性
+rubygems.required.ruby=需要的 Ruby 版本
+rubygems.required.rubygems=需要的 RubyGem 版本
+rubygems.documentation=關於 RubyGems registry 的詳情請參閱<a target="_blank" rel="noopener noreferrer" href="https://docs.gitea.io/en-us/packages/rubygems/">說明文件</a>。
+settings.link=連結此套件到儲存庫
+settings.link.description=如果您將套件連結到儲存庫,該套件會顯示在儲存庫的套件清單。
+settings.link.select=選擇儲存庫
+settings.link.button=更新儲存庫連結
+settings.link.success=儲存庫連結更新成功。
+settings.link.error=儲存庫連結更新失敗。
+settings.delete=刪除套件
+settings.delete.description=刪除套件是永久且不可還原的。
+settings.delete.notice=您正要刪除 %s (%s),此動作是無法還原的,您確定嗎?
+settings.delete.success=已刪除該套件。
+settings.delete.error=刪除套件失敗。
diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go
index a1b3d53ed..a27bbc33a 100644
--- a/routers/api/v1/activitypub/person.go
+++ b/routers/api/v1/activitypub/person.go
@@ -20,11 +20,11 @@ import (
ap "github.com/go-ap/activitypub"
)
-// Person function
+// Person function returns the Person actor for a user
func Person(ctx *context.APIContext) {
// swagger:operation GET /activitypub/user/{username} activitypub activitypubPerson
// ---
- // summary: Returns the person
+ // summary: Returns the Person actor for a user
// produces:
// - application/activity+json
// parameters:
@@ -86,7 +86,7 @@ func Person(ctx *context.APIContext) {
response(ctx, binary)
}
-// PersonInbox function
+// PersonInbox function handles the incoming data for a user inbox
func PersonInbox(ctx *context.APIContext) {
// swagger:operation POST /activitypub/user/{username}/inbox activitypub activitypubPersonInbox
// ---
diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go
index 075556438..d5b29fddf 100644
--- a/routers/api/v1/activitypub/reqsignature.go
+++ b/routers/api/v1/activitypub/reqsignature.go
@@ -70,8 +70,8 @@ func verifyHTTPSignatures(ctx *gitea_context.APIContext) (authenticated bool, er
return
}
-// ReqSignature function
-func ReqSignature() func(ctx *gitea_context.APIContext) {
+// ReqHTTPSignature function
+func ReqHTTPSignature() func(ctx *gitea_context.APIContext) {
return func(ctx *gitea_context.APIContext) {
if authenticated, err := verifyHTTPSignatures(ctx); err != nil {
ctx.Error(http.StatusInternalServerError, "verifyHttpSignatures", err)
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 34ce9cc0a..ca2837f49 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -647,7 +647,7 @@ func Routes() *web.Route {
m.Group("/activitypub", func() {
m.Group("/user/{username}", func() {
m.Get("", activitypub.Person)
- m.Post("/inbox", activitypub.ReqSignature(), activitypub.PersonInbox)
+ m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
m.Get("/outbox", activitypub.PersonOutbox)
m.Get("/following", activitypub.PersonFollowing)
m.Get("/followers", activitypub.PersonFollowers)
diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go
index 3fba2be37..3afb2110d 100644
--- a/routers/web/explore/code.go
+++ b/routers/web/explore/code.go
@@ -7,9 +7,7 @@ package explore
import (
"net/http"
- "code.gitea.io/gitea/models"
repo_model "code.gitea.io/gitea/models/repo"
- "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context"
code_indexer "code.gitea.io/gitea/modules/indexer/code"
@@ -44,106 +42,78 @@ func Code(ctx *context.Context) {
queryType := ctx.FormTrim("t")
isMatch := queryType == "match"
- var (
- repoIDs []int64
- err error
- isAdmin bool
- )
- if ctx.Doer != nil {
- isAdmin = ctx.Doer.IsAdmin
- }
-
- // guest user or non-admin user
- if ctx.Doer == nil || !isAdmin {
- repoIDs, err = repo_model.FindUserAccessibleRepoIDs(ctx.Doer)
- if err != nil {
- ctx.ServerError("SearchResults", err)
- return
- }
- }
-
- var (
- total int
- searchResults []*code_indexer.Result
- searchResultLanguages []*code_indexer.SearchResultLanguages
- )
-
- // if non-admin login user, we need check UnitTypeCode at first
- if ctx.Doer != nil && len(repoIDs) > 0 {
- repoMaps, err := repo_model.GetRepositoriesMapByIDs(repoIDs)
- if err != nil {
- ctx.ServerError("SearchResults", err)
- return
+ if keyword != "" {
+ var (
+ repoIDs []int64
+ err error
+ isAdmin bool
+ )
+ if ctx.Doer != nil {
+ isAdmin = ctx.Doer.IsAdmin
}
- rightRepoMap := make(map[int64]*repo_model.Repository, len(repoMaps))
- repoIDs = make([]int64, 0, len(repoMaps))
- for id, repo := range repoMaps {
- if models.CheckRepoUnitUser(ctx, repo, ctx.Doer, unit.TypeCode) {
- rightRepoMap[id] = repo
- repoIDs = append(repoIDs, id)
- }
- }
-
- ctx.Data["RepoMaps"] = rightRepoMap
-
- total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
- if err != nil {
- if code_indexer.IsAvailable() {
+ // guest user or non-admin user
+ if ctx.Doer == nil || !isAdmin {
+ repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx.Doer)
+ if err != nil {
ctx.ServerError("SearchResults", err)
return
}
- ctx.Data["CodeIndexerUnavailable"] = true
- } else {
- ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
}
- // if non-login user or isAdmin, no need to check UnitTypeCode
- } else if (ctx.Doer == nil && len(repoIDs) > 0) || isAdmin {
- total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
- if err != nil {
- if code_indexer.IsAvailable() {
- ctx.ServerError("SearchResults", err)
- return
+
+ var (
+ total int
+ searchResults []*code_indexer.Result
+ searchResultLanguages []*code_indexer.SearchResultLanguages
+ )
+
+ if (len(repoIDs) > 0) || isAdmin {
+ total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
+ if err != nil {
+ if code_indexer.IsAvailable() {
+ ctx.ServerError("SearchResults", err)
+ return
+ }
+ ctx.Data["CodeIndexerUnavailable"] = true
+ } else {
+ ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
}
- ctx.Data["CodeIndexerUnavailable"] = true
- } else {
- ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
- }
- loadRepoIDs := make([]int64, 0, len(searchResults))
- for _, result := range searchResults {
- var find bool
- for _, id := range loadRepoIDs {
- if id == result.RepoID {
- find = true
- break
+ loadRepoIDs := make([]int64, 0, len(searchResults))
+ for _, result := range searchResults {
+ var find bool
+ for _, id := range loadRepoIDs {
+ if id == result.RepoID {
+ find = true
+ break
+ }
+ }
+ if !find {
+ loadRepoIDs = append(loadRepoIDs, result.RepoID)
}
}
- if !find {
- loadRepoIDs = append(loadRepoIDs, result.RepoID)
+
+ repoMaps, err := repo_model.GetRepositoriesMapByIDs(loadRepoIDs)
+ if err != nil {
+ ctx.ServerError("SearchResults", err)
+ return
}
- }
- repoMaps, err := repo_model.GetRepositoriesMapByIDs(loadRepoIDs)
- if err != nil {
- ctx.ServerError("SearchResults", err)
- return
+ ctx.Data["RepoMaps"] = repoMaps
}
- ctx.Data["RepoMaps"] = repoMaps
+ ctx.Data["Keyword"] = keyword
+ ctx.Data["Language"] = language
+ ctx.Data["queryType"] = queryType
+ ctx.Data["SearchResults"] = searchResults
+ ctx.Data["SearchResultLanguages"] = searchResultLanguages
+ ctx.Data["PageIsViewCode"] = true
+
+ pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
+ pager.SetDefaultParams(ctx)
+ pager.AddParam(ctx, "l", "Language")
+ ctx.Data["Page"] = pager
}
- ctx.Data["Keyword"] = keyword
- ctx.Data["Language"] = language
- ctx.Data["queryType"] = queryType
- ctx.Data["SearchResults"] = searchResults
- ctx.Data["SearchResultLanguages"] = searchResultLanguages
- ctx.Data["PageIsViewCode"] = true
-
- pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
- pager.SetDefaultParams(ctx)
- pager.AddParam(ctx, "l", "Language")
- ctx.Data["Page"] = pager
-
ctx.HTML(http.StatusOK, tplExploreCode)
}
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index 605594d5a..5c46882f3 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -139,7 +139,7 @@ func setCsvCompareContext(ctx *context.Context) {
return csvReader, reader, err
}
- baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, Filename: diffFile.OldName}, baseCommit)
+ baseReader, baseBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.OldName}, baseCommit)
if baseBlobCloser != nil {
defer baseBlobCloser.Close()
}
@@ -151,7 +151,7 @@ func setCsvCompareContext(ctx *context.Context) {
return CsvDiffResult{nil, "unable to load file from base commit"}
}
- headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, Filename: diffFile.Name}, headCommit)
+ headReader, headBlobCloser, err := csvReaderFromCommit(&markup.RenderContext{Ctx: ctx, RelativePath: diffFile.Name}, headCommit)
if headBlobCloser != nil {
defer headBlobCloser.Close()
}
diff --git a/routers/web/repo/render.go b/routers/web/repo/render.go
new file mode 100644
index 000000000..28a6d2f42
--- /dev/null
+++ b/routers/web/repo/render.go
@@ -0,0 +1,79 @@
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package repo
+
+import (
+ "bytes"
+ "io"
+ "net/http"
+ "path"
+
+ "code.gitea.io/gitea/modules/charset"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/git"
+ "code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/typesniffer"
+ "code.gitea.io/gitea/modules/util"
+)
+
+// RenderFile renders a file by repos path
+func RenderFile(ctx *context.Context) {
+ blob, err := ctx.Repo.Commit.GetBlobByPath(ctx.Repo.TreePath)
+ if err != nil {
+ if git.IsErrNotExist(err) {
+ ctx.NotFound("GetBlobByPath", err)
+ } else {
+ ctx.ServerError("GetBlobByPath", err)
+ }
+ return
+ }
+
+ dataRc, err := blob.DataAsync()
+ if err != nil {
+ ctx.ServerError("DataAsync", err)
+ return
+ }
+ defer dataRc.Close()
+
+ buf := make([]byte, 1024)
+ n, _ := util.ReadAtMost(dataRc, buf)
+ buf = buf[:n]
+
+ st := typesniffer.DetectContentType(buf)
+ isTextFile := st.IsText()
+
+ rd := charset.ToUTF8WithFallbackReader(io.MultiReader(bytes.NewReader(buf), dataRc))
+
+ if markupType := markup.Type(blob.Name()); markupType == "" {
+ if isTextFile {
+ _, err = io.Copy(ctx.Resp, rd)
+ if err != nil {
+ ctx.ServerError("Copy", err)
+ }
+ return
+ }
+ ctx.Error(http.StatusInternalServerError, "Unsupported file type render")
+ return
+ }
+
+ treeLink := ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
+ if ctx.Repo.TreePath != "" {
+ treeLink += "/" + util.PathEscapeSegments(ctx.Repo.TreePath)
+ }
+
+ ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'; sandbox allow-scripts")
+ err = markup.Render(&markup.RenderContext{
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: path.Dir(treeLink),
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
+ GitRepo: ctx.Repo.GitRepo,
+ InStandalonePage: true,
+ }, rd, ctx.Resp)
+ if err != nil {
+ ctx.ServerError("Render", err)
+ return
+ }
+}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 01bd2d892..fe60cf44c 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -356,11 +356,11 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
ctx.Data["MarkupType"] = string(markupType)
var result strings.Builder
err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- Filename: readmeFile.name,
- URLPrefix: readmeTreelink,
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: readmeTreelink,
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
+ GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
log.Error("Render failed: %v then fallback", err)
@@ -528,18 +528,22 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
if !detected {
markupType = ""
}
+ metas := ctx.Repo.Repository.ComposeDocumentMetas()
+ metas["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- Type: markupType,
- Filename: blob.Name(),
- URLPrefix: path.Dir(treeLink),
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ Type: markupType,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: path.Dir(treeLink),
+ Metas: metas,
+ GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
ctx.ServerError("Render", err)
return
}
+ // to prevent iframe load third-party url
+ ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'")
ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
} else if readmeExist && !shouldRenderSource {
buf := &bytes.Buffer{}
@@ -627,11 +631,11 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
ctx.Data["MarkupType"] = markupType
var result strings.Builder
err := markup.Render(&markup.RenderContext{
- Ctx: ctx,
- Filename: blob.Name(),
- URLPrefix: path.Dir(treeLink),
- Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
- GitRepo: ctx.Repo.GitRepo,
+ Ctx: ctx,
+ RelativePath: ctx.Repo.TreePath,
+ URLPrefix: path.Dir(treeLink),
+ Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
+ GitRepo: ctx.Repo.GitRepo,
}, rd, &result)
if err != nil {
ctx.ServerError("Render", err)
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index 7cd87eb30..bf2660881 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -282,6 +282,7 @@ func Profile(ctx *context.Context) {
pager := context.NewPagination(total, setting.UI.User.RepoPagingNum, page, 5)
pager.SetDefaultParams(ctx)
+ pager.AddParam(ctx, "tab", "TabName")
if tab != "followers" && tab != "following" && tab != "activity" && tab != "projects" {
pager.AddParam(ctx, "language", "Language")
}
diff --git a/routers/web/web.go b/routers/web/web.go
index ad005f74d..374bafbc8 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -1161,6 +1161,13 @@ func RegisterRoutes(m *web.Route) {
m.Get("/*", context.RepoRefByType(context.RepoRefLegacy), repo.SingleDownload)
}, repo.MustBeNotEmpty, reqRepoCodeReader)
+ m.Group("/render", func() {
+ m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RenderFile)
+ m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RenderFile)
+ m.Get("/commit/*", context.RepoRefByType(context.RepoRefCommit), repo.RenderFile)
+ m.Get("/blob/{sha}", context.RepoRefByType(context.RepoRefBlob), repo.RenderFile)
+ }, repo.MustBeNotEmpty, reqRepoCodeReader)
+
m.Group("/commits", func() {
m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.RefCommits)
m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.RefCommits)
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 97daadbc6..37dc0e114 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -1417,37 +1417,8 @@ func GetDiff(gitRepo *git.Repository, opts *DiffOptions, files ...string) (*Diff
}
diff.Start = opts.SkipTo
- var checker *git.CheckAttributeReader
-
- if git.CheckGitVersionAtLeast("1.7.8") == nil {
- indexFilename, worktree, deleteTemporaryFile, err := gitRepo.ReadTreeToTemporaryIndex(opts.AfterCommitID)
- if err == nil {
- defer deleteTemporaryFile()
-
- checker = &git.CheckAttributeReader{
- Attributes: []string{"linguist-vendored", "linguist-generated", "linguist-language", "gitlab-language"},
- Repo: gitRepo,
- IndexFile: indexFilename,
- WorkTree: worktree,
- }
- ctx, cancel := context.WithCancel(gitRepo.Ctx)
- if err := checker.Init(ctx); err != nil {
- log.Error("Unable to open checker for %s. Error: %v", opts.AfterCommitID, err)
- } else {
- go func() {
- err := checker.Run()
- if err != nil && err != ctx.Err() {
- log.Error("Unable to open checker for %s. Error: %v", opts.AfterCommitID, err)
- }
- cancel()
- }()
- }
- defer func() {
- _ = checker.Close()
- cancel()
- }()
- }
- }
+ checker, deferable := gitRepo.CheckAttributeReader(opts.AfterCommitID)
+ defer deferable()
for _, diffFile := range diff.Files {
diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go
index edc5a84d2..013adac0f 100644
--- a/services/mirror/mirror.go
+++ b/services/mirror/mirror.go
@@ -63,7 +63,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
var item SyncRequest
var repo *repo_model.Repository
if m, ok := bean.(*repo_model.Mirror); ok {
- if m.Repo == nil {
+ if m.GetRepository() == nil {
log.Error("Disconnected mirror found: %d", m.ID)
return nil
}
@@ -73,7 +73,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
ReferenceID: m.RepoID,
}
} else if m, ok := bean.(*repo_model.PushMirror); ok {
- if m.Repo == nil {
+ if m.GetRepository() == nil {
log.Error("Disconnected push-mirror found: %d", m.ID)
return nil
}
diff --git a/services/pull/merge.go b/services/pull/merge.go
index aff800a1b..e8bb3a1cd 100644
--- a/services/pull/merge.go
+++ b/services/pull/merge.go
@@ -276,15 +276,8 @@ func rawMerge(ctx context.Context, pr *issues_model.PullRequest, doer *user_mode
return "", fmt.Errorf("Unable to write .git/info/sparse-checkout file in tmpBasePath: %v", err)
}
- var gitConfigCommand func() *git.Command
- if git.CheckGitVersionAtLeast("1.8.0") == nil {
- gitConfigCommand = func() *git.Command {
- return git.NewCommand(ctx, "config", "--local")
- }
- } else {
- gitConfigCommand = func() *git.Command {
- return git.NewCommand(ctx, "config")
- }
+ gitConfigCommand := func() *git.Command {
+ return git.NewCommand(ctx, "config", "--local")
}
// Switch off LFS process (set required, clean and smudge here also)
@@ -366,16 +359,14 @@ func rawMerge(ctx context.Context, pr *issues_model.PullRequest, doer *user_mode
// Determine if we should sign
signArg := ""
- if git.CheckGitVersionAtLeast("1.7.9") == nil {
- sign, keyID, signer, _ := asymkey_service.SignMerge(ctx, pr, doer, tmpBasePath, "HEAD", trackingBranch)
- if sign {
- signArg = "-S" + keyID
- if pr.BaseRepo.GetTrustModel() == repo_model.CommitterTrustModel || pr.BaseRepo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
- committer = signer
- }
- } else if git.CheckGitVersionAtLeast("2.0.0") == nil {
- signArg = "--no-gpg-sign"
+ sign, keyID, signer, _ := asymkey_service.SignMerge(ctx, pr, doer, tmpBasePath, "HEAD", trackingBranch)
+ if sign {
+ signArg = "-S" + keyID
+ if pr.BaseRepo.GetTrustModel() == repo_model.CommitterTrustModel || pr.BaseRepo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
+ committer = signer
}
+ } else {
+ signArg = "--no-gpg-sign"
}
commitTimeStr := time.Now().Format(time.RFC3339)
diff --git a/services/repository/files/temp_repo.go b/services/repository/files/temp_repo.go
index 97a80a96b..1e60d5561 100644
--- a/services/repository/files/temp_repo.go
+++ b/services/repository/files/temp_repo.go
@@ -248,34 +248,31 @@ func (t *TemporaryUploadRepository) CommitTreeWithDate(parent string, author, co
args = []string{"commit-tree", treeHash}
}
- // Determine if we should sign
- if git.CheckGitVersionAtLeast("1.7.9") == nil {
- var sign bool
- var keyID string
- var signer *git.Signature
- if parent != "" {
- sign, keyID, signer, _ = asymkey_service.SignCRUDAction(t.ctx, t.repo.RepoPath(), author, t.basePath, parent)
- } else {
- sign, keyID, signer, _ = asymkey_service.SignInitialCommit(t.ctx, t.repo.RepoPath(), author)
- }
- if sign {
- args = append(args, "-S"+keyID)
- if t.repo.GetTrustModel() == repo_model.CommitterTrustModel || t.repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
- if committerSig.Name != authorSig.Name || committerSig.Email != authorSig.Email {
- // Add trailers
- _, _ = messageBytes.WriteString("\n")
- _, _ = messageBytes.WriteString("Co-authored-by: ")
- _, _ = messageBytes.WriteString(committerSig.String())
- _, _ = messageBytes.WriteString("\n")
- _, _ = messageBytes.WriteString("Co-committed-by: ")
- _, _ = messageBytes.WriteString(committerSig.String())
- _, _ = messageBytes.WriteString("\n")
- }
- committerSig = signer
+ var sign bool
+ var keyID string
+ var signer *git.Signature
+ if parent != "" {
+ sign, keyID, signer, _ = asymkey_service.SignCRUDAction(t.ctx, t.repo.RepoPath(), author, t.basePath, parent)
+ } else {
+ sign, keyID, signer, _ = asymkey_service.SignInitialCommit(t.ctx, t.repo.RepoPath(), author)
+ }
+ if sign {
+ args = append(args, "-S"+keyID)
+ if t.repo.GetTrustModel() == repo_model.CommitterTrustModel || t.repo.GetTrustModel() == repo_model.CollaboratorCommitterTrustModel {
+ if committerSig.Name != authorSig.Name || committerSig.Email != authorSig.Email {
+ // Add trailers
+ _, _ = messageBytes.WriteString("\n")
+ _, _ = messageBytes.WriteString("Co-authored-by: ")
+ _, _ = messageBytes.WriteString(committerSig.String())
+ _, _ = messageBytes.WriteString("\n")
+ _, _ = messageBytes.WriteString("Co-committed-by: ")
+ _, _ = messageBytes.WriteString(committerSig.String())
+ _, _ = messageBytes.WriteString("\n")
}
- } else if git.CheckGitVersionAtLeast("2.0.0") == nil {
- args = append(args, "--no-gpg-sign")
+ committerSig = signer
}
+ } else {
+ args = append(args, "--no-gpg-sign")
}
if signoff {
diff --git a/templates/admin/repo/search.tmpl b/templates/admin/repo/search.tmpl
index e51d50936..7b9c44afd 100644
--- a/templates/admin/repo/search.tmpl
+++ b/templates/admin/repo/search.tmpl
@@ -12,10 +12,10 @@
<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 eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
- <a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
- <a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
- <a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
+ <a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
+ <a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
+ <a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
+ <a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
<a class="{{if eq .SortType "size"}}active{{end}} item" href="{{$.Link}}?sort=size&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.by_size"}}</a>
<a class="{{if eq .SortType "reversesize"}}active{{end}} item" href="{{$.Link}}?sort=reversesize&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.label.filter_sort.reverse_by_size"}}</a>
</div>
diff --git a/templates/explore/code.tmpl b/templates/explore/code.tmpl
index 2801cdfaf..6bd8be7af 100644
--- a/templates/explore/code.tmpl
+++ b/templates/explore/code.tmpl
@@ -3,7 +3,6 @@
{{template "explore/navbar" .}}
<div class="ui container">
<form class="ui form ignore-dirty" style="max-width: 100%">
- <input type="hidden" name="tab" value="{{$.TabName}}">
<div class="ui fluid action input">
<input name="q" value="{{.Keyword}}"{{if .CodeIndexerUnavailable }} disabled{{end}} placeholder="{{.i18n.Tr "explore.search"}}..." autofocus>
<div class="ui dropdown selection{{if .CodeIndexerUnavailable }} disabled{{end}}">
diff --git a/templates/explore/repo_list.tmpl b/templates/explore/repo_list.tmpl
index 03f1928e2..1bc831d9d 100644
--- a/templates/explore/repo_list.tmpl
+++ b/templates/explore/repo_list.tmpl
@@ -40,7 +40,7 @@
</div>
<div class="metas df ac">
{{if .PrimaryLanguage }}
- <a href="{{$.Link}}?tab={{$.TabName}}&q={{$.Keyword}}&sort={{$.SortType}}&language={{.PrimaryLanguage.Language}}">
+ <a href="{{$.Link}}?q={{$.Keyword}}&sort={{$.SortType}}&language={{.PrimaryLanguage.Language}}">
<span class="text grey df ac mr-3"><i class="color-icon mr-3" style="background-color: {{.PrimaryLanguage.Color}}"></i>{{ .PrimaryLanguage.Language }}</span>
</a>
{{end}}
diff --git a/templates/explore/repo_search.tmpl b/templates/explore/repo_search.tmpl
index 3d45305df..a937cad64 100644
--- a/templates/explore/repo_search.tmpl
+++ b/templates/explore/repo_search.tmpl
@@ -6,23 +6,22 @@
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
- <a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
- <a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
- <a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
- <a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.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}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
- <a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
+ <a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
+ <a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
+ <a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
+ <a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&language={{$.Language}}">{{.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}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
+ <a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</a>
{{if not .DisableStars}}
- <a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
- <a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
+ <a class="{{if eq .SortType "moststars"}}active{{end}} item" href="{{$.Link}}?sort=moststars&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.moststars"}}</a>
+ <a class="{{if eq .SortType "feweststars"}}active{{end}} item" href="{{$.Link}}?sort=feweststars&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.feweststars"}}</a>
{{end}}
- <a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
- <a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&tab={{$.TabName}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
+ <a class="{{if eq .SortType "mostforks"}}active{{end}} item" href="{{$.Link}}?sort=mostforks&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.mostforks"}}</a>
+ <a class="{{if eq .SortType "fewestforks"}}active{{end}} item" href="{{$.Link}}?sort=fewestforks&q={{$.Keyword}}&language={{$.Language}}">{{.i18n.Tr "repo.issues.filter_sort.fewestforks"}}</a>
</div>
</div>
</div>
<form class="ui form ignore-dirty" style="max-width: 90%">
- <input type="hidden" name="tab" value="{{$.TabName}}">
<input type="hidden" name="sort" value="{{$.SortType}}">
<input type="hidden" name="language" value="{{$.Language}}">
<div class="ui fluid action input">
diff --git a/templates/explore/search.tmpl b/templates/explore/search.tmpl
index 2c1687f60..c83c75e27 100644
--- a/templates/explore/search.tmpl
+++ b/templates/explore/search.tmpl
@@ -6,17 +6,16 @@
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
</span>
<div class="menu">
- <a class="{{if eq .SortType "newest"}}active{{end}} item" href="{{$.Link}}?sort=newest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.latest"}}</a>
- <a class="{{if eq .SortType "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</a>
- <a class="{{if eq .SortType "alphabetically"}}active{{end}} item" href="{{$.Link}}?sort=alphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.label.filter_sort.alphabetically"}}</a>
- <a class="{{if eq .SortType "reversealphabetically"}}active{{end}} item" href="{{$.Link}}?sort=reversealphabetically&q={{$.Keyword}}&tab={{$.TabName}}">{{.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}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.recentupdate"}}</a>
- <a class="{{if eq .SortType "leastupdate"}}active{{end}} item" href="{{$.Link}}?sort=leastupdate&q={{$.Keyword}}&tab={{$.TabName}}">{{.i18n.Tr "repo.issues.filter_sort.leastupdate"}}</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 "oldest"}}active{{end}} item" href="{{$.Link}}?sort=oldest&q={{$.Keyword}}">{{.i18n.Tr "repo.issues.filter_sort.oldest"}}</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>
</div>
</div>
</div>
<form class="ui form ignore-dirty" style="max-width: 90%">
- <input type="hidden" name="tab" value="{{$.TabName}}">
<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>
diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl
index 73c6702a9..1a0323f5d 100644
--- a/templates/repo/home.tmpl
+++ b/templates/repo/home.tmpl
@@ -74,7 +74,7 @@
</div>
{{end}}
<div class="fitted item mx-0">
- <a href="{{.BaseRepo.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">
+ <a href="{{.Repository.Link}}/find/{{.BranchNameSubURL}}" class="ui compact basic button">
{{.i18n.Tr "repo.find_file.go_to_file"}}
</a>
</div>
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index cd3625858..43277785c 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -31,7 +31,7 @@
"tags": [
"activitypub"
],
- "summary": "Returns the person",
+ "summary": "Returns the Person actor for a user",
"operationId": "activitypubPerson",
"parameters": [
{
diff --git a/web_src/less/_base.less b/web_src/less/_base.less
index bd5754c1e..78f32956e 100644
--- a/web_src/less/_base.less
+++ b/web_src/less/_base.less
@@ -2200,5 +2200,9 @@ table th[data-sortt-desc] {
.item {
width: initial !important;
}
+
+ > .dropdown.item {
+ position: initial;
+ }
}
}