diff --git a/build/backport-locales.go b/build/backport-locales.go
index a717b37367dc4..054b623d698e8 100644
--- a/build/backport-locales.go
+++ b/build/backport-locales.go
@@ -62,6 +62,7 @@ func main() {
// use old en-US as the base, and copy the new translations to the old locales
enUsOld := inisOld["options/locale/locale_en-US.ini"]
+ brokenWarned := map[string]bool{}
for path, iniOld := range inisOld {
if iniOld == enUsOld {
continue
@@ -77,11 +78,14 @@ func main() {
if secNew.HasKey(keyEnUs.Name()) {
oldStr := secOld.Key(keyEnUs.Name()).String()
newStr := secNew.Key(keyEnUs.Name()).String()
- if oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%") {
- fmt.Printf("WARNING: locale %s [%s]%s has different number of arguments, skipping\n", path, secEnUS.Name(), keyEnUs.Name())
- fmt.Printf("\told: %s\n", oldStr)
- fmt.Printf("\tnew: %s\n", newStr)
- fmt.Println("---- ")
+ broken := oldStr != "" && strings.Count(oldStr, "%") != strings.Count(newStr, "%")
+ broken = broken || strings.Contains(oldStr, "\n") || strings.Contains(oldStr, "\n")
+ if broken {
+ brokenWarned[secOld.Name()+"."+keyEnUs.Name()] = true
+ fmt.Println("----")
+ fmt.Printf("WARNING: skip broken locale: %s , [%s] %s\n", path, secEnUS.Name(), keyEnUs.Name())
+ fmt.Printf("\told: %s\n", strings.ReplaceAll(oldStr, "\n", "\\n"))
+ fmt.Printf("\tnew: %s\n", strings.ReplaceAll(newStr, "\n", "\\n"))
continue
}
secOld.Key(keyEnUs.Name()).SetValue(newStr)
@@ -90,4 +94,25 @@ func main() {
}
mustNoErr(iniOld.SaveTo(path))
}
+
+ fmt.Println("========")
+
+ for path, iniNew := range inisNew {
+ for _, sec := range iniNew.Sections() {
+ for _, key := range sec.Keys() {
+ str := sec.Key(key.Name()).String()
+ broken := strings.Contains(str, "\n")
+ broken = broken || strings.HasPrefix(str, "`") != strings.HasSuffix(str, "`")
+ broken = broken || strings.HasPrefix(str, "\"`")
+ broken = broken || strings.HasPrefix(str, "`\"")
+ broken = broken || strings.Count(str, `"`)%2 == 1
+ broken = broken || strings.Count(str, "`")%2 == 1
+ if broken && !brokenWarned[sec.Name()+"."+key.Name()] {
+ fmt.Printf("WARNING: found broken locale: %s , [%s] %s\n", path, sec.Name(), key.Name())
+ fmt.Printf("\tstr: %s\n", strings.ReplaceAll(str, "\n", "\\n"))
+ fmt.Println("----")
+ }
+ }
+ }
+ }
}
diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini
index 2a840d5ef1fc7..0543c85d50daa 100644
--- a/custom/conf/app.example.ini
+++ b/custom/conf/app.example.ini
@@ -947,10 +947,10 @@ ROUTER = console
;USE_COMPAT_SSH_URI = false
;;
;; Close issues as long as a commit on any branch marks it as fixed
-;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages
+;; Comma separated list of globally disabled repo units. Allowed values: repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions.
;DISABLED_REPO_UNITS =
;;
-;; Comma separated list of default new repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages.
+;; Comma separated list of default new repo units. Allowed values: repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages, repo.actions.
;; Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility.
;; External wiki and issue tracker can't be enabled by default as it requires additional settings.
;; Disabled repo units will not be added to new repositories regardless if it is in the default list.
diff --git a/docs/content/doc/administration/config-cheat-sheet.en-us.md b/docs/content/doc/administration/config-cheat-sheet.en-us.md
index f8082bd3784f2..67618d05b675e 100644
--- a/docs/content/doc/administration/config-cheat-sheet.en-us.md
+++ b/docs/content/doc/administration/config-cheat-sheet.en-us.md
@@ -103,8 +103,8 @@ In addition there is _`StaticRootPath`_ which can be set as a built-in at build
- `DEFAULT_CLOSE_ISSUES_VIA_COMMITS_IN_ANY_BRANCH`: **false**: Close an issue if a commit on a non default branch marks it as closed.
- `ENABLE_PUSH_CREATE_USER`: **false**: Allow users to push local repositories to Gitea and have them automatically created for a user.
- `ENABLE_PUSH_CREATE_ORG`: **false**: Allow users to push local repositories to Gitea and have them automatically created for an org.
-- `DISABLED_REPO_UNITS`: **_empty_**: Comma separated list of globally disabled repo units. Allowed values: \[repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects\]
-- `DEFAULT_REPO_UNITS`: **repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages**: Comma separated list of default new repo units. Allowed values: \[repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects\]. Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. External wiki and issue tracker can't be enabled by default as it requires additional settings. Disabled repo units will not be added to new repositories regardless if it is in the default list.
+- `DISABLED_REPO_UNITS`: **_empty_**: Comma separated list of globally disabled repo units. Allowed values: \[repo.issues, repo.ext_issues, repo.pulls, repo.wiki, repo.ext_wiki, repo.projects, repo.packages, repo.actions\]
+- `DEFAULT_REPO_UNITS`: **repo.code,repo.releases,repo.issues,repo.pulls,repo.wiki,repo.projects,repo.packages**: Comma separated list of default new repo units. Allowed values: \[repo.code, repo.releases, repo.issues, repo.pulls, repo.wiki, repo.projects, repo.packages, repo.actions\]. Note: Code and Releases can currently not be deactivated. If you specify default repo units you should still list them for future compatibility. External wiki and issue tracker can't be enabled by default as it requires additional settings. Disabled repo units will not be added to new repositories regardless if it is in the default list.
- `DEFAULT_FORK_REPO_UNITS`: **repo.code,repo.pulls**: Comma separated list of default forked repo units. The set of allowed values and rules is the same as `DEFAULT_REPO_UNITS`.
- `PREFIX_ARCHIVE_FILES`: **true**: Prefix archive files by placing them in a directory named after the repository.
- `DISABLE_MIGRATIONS`: **false**: Disable migrating feature.
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index ea3619db97ab9..07240c8e69ed5 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -479,6 +479,8 @@ var migrations = []Migration{
NewMigration("Improve Action table indices v3", v1_20.ImproveActionTableIndices),
// v250 -> v251
NewMigration("Change Container Metadata", v1_20.ChangeContainerMetadataMultiArch),
+ // v251 -> v252
+ NewMigration("Fix incorrect owner team unit access mode", v1_20.FixIncorrectOwnerTeamUnitAccessMode),
}
// GetCurrentDBVersion returns the current db version
diff --git a/models/migrations/v1_20/v251.go b/models/migrations/v1_20/v251.go
new file mode 100644
index 0000000000000..7743248a3f17b
--- /dev/null
+++ b/models/migrations/v1_20/v251.go
@@ -0,0 +1,47 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_20 //nolint
+
+import (
+ "code.gitea.io/gitea/modules/log"
+
+ "xorm.io/xorm"
+)
+
+func FixIncorrectOwnerTeamUnitAccessMode(x *xorm.Engine) error {
+ type UnitType int
+ type AccessMode int
+
+ type TeamUnit struct {
+ ID int64 `xorm:"pk autoincr"`
+ OrgID int64 `xorm:"INDEX"`
+ TeamID int64 `xorm:"UNIQUE(s)"`
+ Type UnitType `xorm:"UNIQUE(s)"`
+ AccessMode AccessMode
+ }
+
+ const (
+ // AccessModeOwner owner access
+ AccessModeOwner = 4
+ )
+
+ sess := x.NewSession()
+ defer sess.Close()
+
+ if err := sess.Begin(); err != nil {
+ return err
+ }
+
+ count, err := sess.Table("team_unit").
+ Where("team_id IN (SELECT id FROM team WHERE authorize = ?)", AccessModeOwner).
+ Update(&TeamUnit{
+ AccessMode: AccessModeOwner,
+ })
+ if err != nil {
+ return err
+ }
+ log.Debug("Updated %d owner team unit access mode to belong to owner instead of none", count)
+
+ return sess.Commit()
+}
diff --git a/models/organization/org.go b/models/organization/org.go
index 269b3e83288dc..fa2a604721288 100644
--- a/models/organization/org.go
+++ b/models/organization/org.go
@@ -338,9 +338,10 @@ func CreateOrganization(org *Organization, owner *user_model.User) (err error) {
units := make([]TeamUnit, 0, len(unit.AllRepoUnitTypes))
for _, tp := range unit.AllRepoUnitTypes {
units = append(units, TeamUnit{
- OrgID: org.ID,
- TeamID: t.ID,
- Type: tp,
+ OrgID: org.ID,
+ TeamID: t.ID,
+ Type: tp,
+ AccessMode: perm.AccessModeOwner,
})
}
diff --git a/models/repo/release.go b/models/repo/release.go
index f7b24044b9c2c..c8dd7fbc7a368 100644
--- a/models/repo/release.go
+++ b/models/repo/release.go
@@ -79,7 +79,7 @@ type Release struct {
RenderedNote string `xorm:"-"`
IsDraft bool `xorm:"NOT NULL DEFAULT false"`
IsPrerelease bool `xorm:"NOT NULL DEFAULT false"`
- IsTag bool `xorm:"NOT NULL DEFAULT false"`
+ IsTag bool `xorm:"NOT NULL DEFAULT false"` // will be true only if the record is a tag and has no related releases
Attachments []*Attachment `xorm:"-"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX"`
}
diff --git a/models/unit/unit.go b/models/unit/unit.go
index a2a9079dc25c7..3d5a8842cd638 100644
--- a/models/unit/unit.go
+++ b/models/unit/unit.go
@@ -151,7 +151,11 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
// LoadUnitConfig load units from settings
func LoadUnitConfig() {
- DisabledRepoUnits = FindUnitTypes(setting.Repository.DisabledRepoUnits...)
+ var invalidKeys []string
+ DisabledRepoUnits, invalidKeys = FindUnitTypes(setting.Repository.DisabledRepoUnits...)
+ if len(invalidKeys) > 0 {
+ log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", "))
+ }
// Check that must units are not disabled
for i, disabledU := range DisabledRepoUnits {
if !disabledU.CanDisable() {
@@ -160,9 +164,15 @@ func LoadUnitConfig() {
}
}
- setDefaultRepoUnits := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
+ setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
+ if len(invalidKeys) > 0 {
+ log.Warn("Invalid keys in default repo units: %s", strings.Join(invalidKeys, ", "))
+ }
DefaultRepoUnits = validateDefaultRepoUnits(DefaultRepoUnits, setDefaultRepoUnits)
- setDefaultForkRepoUnits := FindUnitTypes(setting.Repository.DefaultForkRepoUnits...)
+ setDefaultForkRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultForkRepoUnits...)
+ if len(invalidKeys) > 0 {
+ log.Warn("Invalid keys in default fork repo units: %s", strings.Join(invalidKeys, ", "))
+ }
DefaultForkRepoUnits = validateDefaultRepoUnits(DefaultForkRepoUnits, setDefaultForkRepoUnits)
}
@@ -312,7 +322,7 @@ var (
UnitActions = Unit{
TypeActions,
- "actions.actions",
+ "repo.actions",
"/actions",
"actions.unit.desc",
7,
@@ -334,22 +344,19 @@ var (
}
)
-// FindUnitTypes give the unit key names and return unit
-func FindUnitTypes(nameKeys ...string) (res []Type) {
+// FindUnitTypes give the unit key names and return valid unique units and invalid keys
+func FindUnitTypes(nameKeys ...string) (res []Type, invalidKeys []string) {
+ m := map[Type]struct{}{}
for _, key := range nameKeys {
- var found bool
- for t, u := range Units {
- if strings.EqualFold(key, u.NameKey) {
- res = append(res, t)
- found = true
- break
- }
- }
- if !found {
- res = append(res, TypeInvalid)
+ t := TypeFromKey(key)
+ if t == TypeInvalid {
+ invalidKeys = append(invalidKeys, key)
+ } else if _, ok := m[t]; !ok {
+ res = append(res, t)
+ m[t] = struct{}{}
}
}
- return res
+ return res, invalidKeys
}
// TypeFromKey give the unit key name and return unit
diff --git a/models/unit/unit_test.go b/models/unit/unit_test.go
new file mode 100644
index 0000000000000..50d781719771d
--- /dev/null
+++ b/models/unit/unit_test.go
@@ -0,0 +1,53 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package unit
+
+import (
+ "testing"
+
+ "code.gitea.io/gitea/modules/setting"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestLoadUnitConfig(t *testing.T) {
+ defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
+ DisabledRepoUnits = disabledRepoUnits
+ DefaultRepoUnits = defaultRepoUnits
+ DefaultForkRepoUnits = defaultForkRepoUnits
+ }(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
+ defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
+ setting.Repository.DisabledRepoUnits = disabledRepoUnits
+ setting.Repository.DefaultRepoUnits = defaultRepoUnits
+ setting.Repository.DefaultForkRepoUnits = defaultForkRepoUnits
+ }(setting.Repository.DisabledRepoUnits, setting.Repository.DefaultRepoUnits, setting.Repository.DefaultForkRepoUnits)
+
+ t.Run("regular", func(t *testing.T) {
+ setting.Repository.DisabledRepoUnits = []string{"repo.issues"}
+ setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"}
+ setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"}
+ LoadUnitConfig()
+ assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
+ assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
+ assert.Equal(t, []Type{TypeCode, TypeReleases}, DefaultForkRepoUnits)
+ })
+ t.Run("invalid", func(t *testing.T) {
+ setting.Repository.DisabledRepoUnits = []string{"repo.issues", "invalid.1"}
+ setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"}
+ setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"}
+ LoadUnitConfig()
+ assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
+ assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
+ assert.Equal(t, []Type{TypeCode, TypeReleases}, DefaultForkRepoUnits)
+ })
+ t.Run("duplicate", func(t *testing.T) {
+ setting.Repository.DisabledRepoUnits = []string{"repo.issues", "repo.issues"}
+ setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"}
+ setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
+ LoadUnitConfig()
+ assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
+ assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
+ assert.Equal(t, []Type{TypeCode, TypeReleases}, DefaultForkRepoUnits)
+ })
+}
diff --git a/modules/base/tool.go b/modules/base/tool.go
index 94f19576b48d7..bd3a8458eeb29 100644
--- a/modules/base/tool.go
+++ b/modules/base/tool.go
@@ -22,7 +22,6 @@ import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/util"
"github.com/dustin/go-humanize"
"github.com/minio/sha256-simd"
@@ -142,12 +141,6 @@ func FileSize(s int64) string {
return humanize.IBytes(uint64(s))
}
-// PrettyNumber produces a string form of the given number in base 10 with
-// commas after every three orders of magnitude
-func PrettyNumber(i interface{}) string {
- return humanize.Comma(util.NumberIntoInt64(i))
-}
-
// Subtract deals with subtraction of all types of number.
func Subtract(left, right interface{}) interface{} {
var rleft, rright int64
diff --git a/modules/base/tool_test.go b/modules/base/tool_test.go
index 81f4b464e6d36..33677a910cc22 100644
--- a/modules/base/tool_test.go
+++ b/modules/base/tool_test.go
@@ -114,13 +114,6 @@ func TestFileSize(t *testing.T) {
assert.Equal(t, "2.0 EiB", FileSize(size))
}
-func TestPrettyNumber(t *testing.T) {
- assert.Equal(t, "23,342,432", PrettyNumber(23342432))
- assert.Equal(t, "23,342,432", PrettyNumber(int32(23342432)))
- assert.Equal(t, "0", PrettyNumber(0))
- assert.Equal(t, "-100,000", PrettyNumber(-100000))
-}
-
func TestSubtract(t *testing.T) {
toFloat64 := func(n interface{}) float64 {
switch v := n.(type) {
diff --git a/modules/context/context.go b/modules/context/context.go
index 5876e23cc40a2..1eff1459a14af 100644
--- a/modules/context/context.go
+++ b/modules/context/context.go
@@ -628,7 +628,9 @@ func (ctx *Context) Value(key interface{}) interface{} {
if key == git.RepositoryContextKey && ctx.Repo != nil {
return ctx.Repo.GitRepo
}
-
+ if key == translation.ContextKey && ctx.Locale != nil {
+ return ctx.Locale
+ }
return ctx.Req.Context().Value(key)
}
diff --git a/modules/markup/html.go b/modules/markup/html.go
index 76fc54cf465eb..11888b8536353 100644
--- a/modules/markup/html.go
+++ b/modules/markup/html.go
@@ -22,6 +22,7 @@ import (
"code.gitea.io/gitea/modules/regexplru"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates/vars"
+ "code.gitea.io/gitea/modules/translation"
"code.gitea.io/gitea/modules/util"
"golang.org/x/net/html"
@@ -97,14 +98,30 @@ var issueFullPattern *regexp.Regexp
// Once for to prevent races
var issueFullPatternOnce sync.Once
+// regexp for full links to hash comment in pull request files changed tab
+var filesChangedFullPattern *regexp.Regexp
+
+// Once for to prevent races
+var filesChangedFullPatternOnce sync.Once
+
func getIssueFullPattern() *regexp.Regexp {
issueFullPatternOnce.Do(func() {
+ // example: https://domain/org/repo/pulls/27#hash
issueFullPattern = regexp.MustCompile(regexp.QuoteMeta(setting.AppURL) +
`[\w_.-]+/[\w_.-]+/(?:issues|pulls)/((?:\w{1,10}-)?[1-9][0-9]*)([\?|#](\S+)?)?\b`)
})
return issueFullPattern
}
+func getFilesChangedFullPattern() *regexp.Regexp {
+ filesChangedFullPatternOnce.Do(func() {
+ // example: https://domain/org/repo/pulls/27/files#hash
+ filesChangedFullPattern = regexp.MustCompile(regexp.QuoteMeta(setting.AppURL) +
+ `[\w_.-]+/[\w_.-]+/pulls/((?:\w{1,10}-)?[1-9][0-9]*)/files([\?|#](\S+)?)?\b`)
+ })
+ return filesChangedFullPattern
+}
+
// CustomLinkURLSchemes allows for additional schemes to be detected when parsing links within text
func CustomLinkURLSchemes(schemes []string) {
schemes = append(schemes, "http", "https")
@@ -793,15 +810,30 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
if ctx.Metas == nil {
return
}
-
next := node.NextSibling
for node != nil && node != next {
m := getIssueFullPattern().FindStringSubmatchIndex(node.Data)
if m == nil {
return
}
+
+ mDiffView := getFilesChangedFullPattern().FindStringSubmatchIndex(node.Data)
+ // leave it as it is if the link is from "Files Changed" tab in PR Diff View https://domain/org/repo/pulls/27/files
+ if mDiffView != nil {
+ return
+ }
+
link := node.Data[m[0]:m[1]]
- id := "#" + node.Data[m[2]:m[3]]
+ text := "#" + node.Data[m[2]:m[3]]
+ // if m[4] and m[5] is not -1, then link is to a comment
+ // indicate that in the text by appending (comment)
+ if m[4] != -1 && m[5] != -1 {
+ if locale, ok := ctx.Ctx.Value(translation.ContextKey).(translation.Locale); ok {
+ text += " " + locale.Tr("repo.from_comment")
+ } else {
+ text += " (comment)"
+ }
+ }
// extract repo and org name from matched link like
// http://localhost:3000/gituser/myrepo/issues/1
@@ -810,12 +842,10 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) {
matchRepo := linkParts[len(linkParts)-3]
if matchOrg == ctx.Metas["user"] && matchRepo == ctx.Metas["repo"] {
- // TODO if m[4]:m[5] is not nil, then link is to a comment,
- // and we should indicate that in the text somehow
- replaceContent(node, m[0], m[1], createLink(link, id, "ref-issue"))
+ replaceContent(node, m[0], m[1], createLink(link, text, "ref-issue"))
} else {
- orgRepoID := matchOrg + "/" + matchRepo + id
- replaceContent(node, m[0], m[1], createLink(link, orgRepoID, "ref-issue"))
+ text = matchOrg + "/" + matchRepo + text
+ replaceContent(node, m[0], m[1], createLink(link, text, "ref-issue"))
}
node = node.NextSibling.NextSibling
}
diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go
index a048f1f527889..7e04b03531d87 100644
--- a/modules/markup/html_internal_test.go
+++ b/modules/markup/html_internal_test.go
@@ -330,13 +330,17 @@ func TestRender_FullIssueURLs(t *testing.T) {
test("Look here http://localhost:3000/person/repo/issues/4",
`Look here person/repo#4`)
test("http://localhost:3000/person/repo/issues/4#issuecomment-1234",
- `person/repo#4`)
+ `person/repo#4 (comment)`)
test("http://localhost:3000/gogits/gogs/issues/4",
`#4`)
test("http://localhost:3000/gogits/gogs/issues/4 test",
`#4 test`)
test("http://localhost:3000/gogits/gogs/issues/4?a=1&b=2#comment-123 test",
- `#4 test`)
+ `#4 (comment) test`)
+ test("http://localhost:3000/testOrg/testOrgRepo/pulls/2/files#issuecomment-24",
+ "http://localhost:3000/testOrg/testOrgRepo/pulls/2/files#issuecomment-24")
+ test("http://localhost:3000/testOrg/testOrgRepo/pulls/2/files",
+ "http://localhost:3000/testOrg/testOrgRepo/pulls/2/files")
}
func TestRegExp_sha1CurrentPattern(t *testing.T) {
diff --git a/modules/templates/helper.go b/modules/templates/helper.go
index a8343428dc19b..54c85863bd827 100644
--- a/modules/templates/helper.go
+++ b/modules/templates/helper.go
@@ -19,7 +19,6 @@ import (
"reflect"
"regexp"
"runtime"
- "strconv"
"strings"
texttmpl "text/template"
"time"
@@ -112,18 +111,17 @@ func NewFuncMap() []template.FuncMap {
"IsShowFullName": func() bool {
return setting.UI.DefaultShowFullName
},
- "Safe": Safe,
- "SafeJS": SafeJS,
- "JSEscape": JSEscape,
- "Str2html": Str2html,
- "TimeSince": timeutil.TimeSince,
- "TimeSinceUnix": timeutil.TimeSinceUnix,
- "FileSize": base.FileSize,
- "PrettyNumber": base.PrettyNumber,
- "JsPrettyNumber": JsPrettyNumber,
- "Subtract": base.Subtract,
- "EntryIcon": base.EntryIcon,
- "MigrationIcon": MigrationIcon,
+ "Safe": Safe,
+ "SafeJS": SafeJS,
+ "JSEscape": JSEscape,
+ "Str2html": Str2html,
+ "TimeSince": timeutil.TimeSince,
+ "TimeSinceUnix": timeutil.TimeSinceUnix,
+ "FileSize": base.FileSize,
+ "LocaleNumber": LocaleNumber,
+ "Subtract": base.Subtract,
+ "EntryIcon": base.EntryIcon,
+ "MigrationIcon": MigrationIcon,
"Add": func(a ...int) int {
sum := 0
for _, val := range a {
@@ -410,62 +408,9 @@ func NewFuncMap() []template.FuncMap {
"Join": strings.Join,
"QueryEscape": url.QueryEscape,
"DotEscape": DotEscape,
- "Iterate": func(arg interface{}) (items []uint64) {
- count := uint64(0)
- switch val := arg.(type) {
- case uint64:
- count = val
- case *uint64:
- count = *val
- case int64:
- if val < 0 {
- val = 0
- }
- count = uint64(val)
- case *int64:
- if *val < 0 {
- *val = 0
- }
- count = uint64(*val)
- case int:
- if val < 0 {
- val = 0
- }
- count = uint64(val)
- case *int:
- if *val < 0 {
- *val = 0
- }
- count = uint64(*val)
- case uint:
- count = uint64(val)
- case *uint:
- count = uint64(*val)
- case int32:
- if val < 0 {
- val = 0
- }
- count = uint64(val)
- case *int32:
- if *val < 0 {
- *val = 0
- }
- count = uint64(*val)
- case uint32:
- count = uint64(val)
- case *uint32:
- count = uint64(*val)
- case string:
- cnt, _ := strconv.ParseInt(val, 10, 64)
- if cnt < 0 {
- cnt = 0
- }
- count = uint64(cnt)
- }
- if count <= 0 {
- return items
- }
- for i := uint64(0); i < count; i++ {
+ "Iterate": func(arg interface{}) (items []int64) {
+ count := util.ToInt64(arg)
+ for i := int64(0); i < count; i++ {
items = append(items, i)
}
return items
@@ -1067,10 +1012,8 @@ func mirrorRemoteAddress(ctx context.Context, m *repo_model.Repository, remoteNa
return a
}
-// JsPrettyNumber renders a number using english decimal separators, e.g. 1,200 and subsequent
-// JS will replace the number with locale-specific separators, based on the user's selected language
-func JsPrettyNumber(i interface{}) template.HTML {
- num := util.NumberIntoInt64(i)
-
- return template.HTML(`` + base.PrettyNumber(num) + ``)
+// LocaleNumber renders a number with a Custom Element, browser will render it with a locale number
+func LocaleNumber(v interface{}) template.HTML {
+ num := util.ToInt64(v)
+ return template.HTML(fmt.Sprintf(`.drone.yml
, /docs/**/*.txt
+settings.protect_unprotected_file_patterns=保護しないファイルのパターン (セミコロン';'で区切る):
+settings.protect_unprotected_file_patterns_desc=保護しないファイルは、ユーザーに書き込み権限があればプッシュ制限をバイパスして直接変更できます。 セミコロン(';')で区切って複数のパターンを指定できます。 パターンの文法については github.com/gobwas/glob を参照してください。 例: .drone.yml
, /docs/**/*.txt
settings.add_protected_branch=保護を有効にする
settings.delete_protected_branch=保護を無効にする
settings.update_protect_branch_success=ルール '%s' に対するブランチ保護を更新しました。
@@ -2276,6 +2280,8 @@ diff.image.side_by_side=並べて表示
diff.image.swipe=スワイプ
diff.image.overlay=オーバーレイ
diff.has_escaped=この行には不可視Unicode文字があります
+diff.show_file_tree=ファイルツリーを表示
+diff.hide_file_tree=ファイルツリーを隠す
releases.desc=プロジェクトバージョンとダウンロードの追跡。
release.releases=リリース
@@ -3361,6 +3367,7 @@ runners.status.idle=アイドル
runners.status.active=稼働中
runners.status.offline=オフライン
runners.version=バージョン
+runners.reset_registration_token_success=ランナー登録トークンをリセットしました
runs.all_workflows=すべてのワークフロー
runs.open_tab=%d オープン
diff --git a/package-lock.json b/package-lock.json
index 9d0c83f65641b..b9d998a69d2a8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@citation-js/plugin-csl": "0.6.7",
"@citation-js/plugin-software-formats": "0.6.1",
"@claviska/jquery-minicolors": "2.3.6",
+ "@github/markdown-toolbar-element": "2.1.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "18.3.0",
"@vue/compiler-sfc": "3.2.47",
@@ -838,6 +839,11 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@github/markdown-toolbar-element": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@github/markdown-toolbar-element/-/markdown-toolbar-element-2.1.1.tgz",
+ "integrity": "sha512-J++rpd5H9baztabJQB82h26jtueOeBRSTqetk9Cri+Lj/s28ndu6Tovn0uHQaOKtBWDobFunk9b5pP5vcqt7cA=="
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.8",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz",
diff --git a/package.json b/package.json
index 8ac5c312f6b11..3ccf0c0840baa 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"@citation-js/plugin-csl": "0.6.7",
"@citation-js/plugin-software-formats": "0.6.1",
"@claviska/jquery-minicolors": "2.3.6",
+ "@github/markdown-toolbar-element": "2.1.1",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@primer/octicons": "18.3.0",
"@vue/compiler-sfc": "3.2.47",
diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go
index 492930b84929b..bc6b82b179921 100644
--- a/routers/api/v1/activitypub/person.go
+++ b/routers/api/v1/activitypub/person.go
@@ -4,6 +4,7 @@
package activitypub
import (
+ "fmt"
"net/http"
"strings"
@@ -18,22 +19,23 @@ import (
// Person function returns the Person actor for a user
func Person(ctx *context.APIContext) {
- // swagger:operation GET /activitypub/user/{username} activitypub activitypubPerson
+ // swagger:operation GET /activitypub/user-id/{user-id} activitypub activitypubPerson
// ---
// summary: Returns the Person actor for a user
// produces:
// - application/json
// parameters:
- // - name: username
+ // - name: user-id
// in: path
- // description: username of the user
- // type: string
+ // description: user ID of the user
+ // type: integer
// required: true
// responses:
// "200":
// "$ref": "#/responses/ActivityPub"
- link := strings.TrimSuffix(setting.AppURL, "/") + "/api/v1/activitypub/user/" + ctx.ContextUser.Name
+ // TODO: the setting.AppURL during the test doesn't follow the definition: "It always has a '/' suffix"
+ link := fmt.Sprintf("%s/api/v1/activitypub/user-id/%d", strings.TrimSuffix(setting.AppURL, "/"), ctx.ContextUser.ID)
person := ap.PersonNew(ap.IRI(link))
person.Name = ap.NaturalLanguageValuesNew()
@@ -85,16 +87,16 @@ func Person(ctx *context.APIContext) {
// PersonInbox function handles the incoming data for a user inbox
func PersonInbox(ctx *context.APIContext) {
- // swagger:operation POST /activitypub/user/{username}/inbox activitypub activitypubPersonInbox
+ // swagger:operation POST /activitypub/user-id/{user-id}/inbox activitypub activitypubPersonInbox
// ---
// summary: Send to the inbox
// produces:
// - application/json
// parameters:
- // - name: username
+ // - name: user-id
// in: path
- // description: username of the user
- // type: string
+ // description: user ID of the user
+ // type: integer
// required: true
// responses:
// "204":
diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go
index 8b13f5492c148..21797bd1a0aaf 100644
--- a/routers/api/v1/api.go
+++ b/routers/api/v1/api.go
@@ -704,10 +704,15 @@ func Routes(ctx gocontext.Context) *web.Route {
if setting.Federation.Enabled {
m.Get("/nodeinfo", misc.NodeInfo)
m.Group("/activitypub", func() {
+ // deprecated, remove in 1.20, use /user-id/{user-id} instead
m.Group("/user/{username}", func() {
m.Get("", activitypub.Person)
m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
}, context_service.UserAssignmentAPI())
+ m.Group("/user-id/{user-id}", func() {
+ m.Get("", activitypub.Person)
+ m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox)
+ }, context_service.UserIDAssignmentAPI())
})
}
m.Get("/signing-key.gpg", misc.SigningKey)
diff --git a/routers/api/v1/org/team.go b/routers/api/v1/org/team.go
index 0c6926759a768..597f846206043 100644
--- a/routers/api/v1/org/team.go
+++ b/routers/api/v1/org/team.go
@@ -135,7 +135,7 @@ func GetTeam(ctx *context.APIContext) {
}
func attachTeamUnits(team *organization.Team, units []string) {
- unitTypes := unit_model.FindUnitTypes(units...)
+ unitTypes, _ := unit_model.FindUnitTypes(units...)
team.Units = make([]*organization.TeamUnit, 0, len(units))
for _, tp := range unitTypes {
team.Units = append(team.Units, &organization.TeamUnit{
diff --git a/routers/web/devtest/devtest.go b/routers/web/devtest/devtest.go
new file mode 100644
index 0000000000000..eb77d0b927b6b
--- /dev/null
+++ b/routers/web/devtest/devtest.go
@@ -0,0 +1,35 @@
+// Copyright 2023 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package devtest
+
+import (
+ "net/http"
+ "path"
+ "strings"
+
+ "code.gitea.io/gitea/modules/base"
+ "code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/templates"
+)
+
+// List all devtest templates, they will be used for e2e tests for the UI components
+func List(ctx *context.Context) {
+ templateNames := templates.GetTemplateAssetNames()
+ var subNames []string
+ const prefix = "templates/devtest/"
+ for _, tmplName := range templateNames {
+ if strings.HasPrefix(tmplName, prefix) {
+ subName := strings.TrimSuffix(strings.TrimPrefix(tmplName, prefix), ".tmpl")
+ if subName != "list" {
+ subNames = append(subNames, subName)
+ }
+ }
+ }
+ ctx.Data["SubNames"] = subNames
+ ctx.HTML(http.StatusOK, "devtest/list")
+}
+
+func Tmpl(ctx *context.Context) {
+ ctx.HTML(http.StatusOK, base.TplName("devtest"+path.Clean("/"+ctx.Params("sub"))))
+}
diff --git a/routers/web/misc/markup.go b/routers/web/misc/markup.go
index f678316f4429f..169037894530c 100644
--- a/routers/web/misc/markup.go
+++ b/routers/web/misc/markup.go
@@ -15,24 +15,6 @@ import (
// Markup render markup document to HTML
func Markup(ctx *context.Context) {
- // swagger:operation POST /markup miscellaneous renderMarkup
- // ---
- // summary: Render a markup document as HTML
- // parameters:
- // - name: body
- // in: body
- // schema:
- // "$ref": "#/definitions/MarkupOption"
- // consumes:
- // - application/json
- // produces:
- // - text/html
- // responses:
- // "200":
- // "$ref": "#/responses/MarkupRender"
- // "422":
- // "$ref": "#/responses/validationError"
-
form := web.GetForm(ctx).(*api.MarkupOption)
if ctx.HasAPIError() {
diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go
index 654e9000fa1b5..7d84c101d8a60 100644
--- a/routers/web/org/setting.go
+++ b/routers/web/org/setting.go
@@ -246,7 +246,6 @@ func Labels(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.labels")
ctx.Data["PageIsOrgSettings"] = true
ctx.Data["PageIsOrgSettingsLabels"] = true
- ctx.Data["RequireTribute"] = true
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.HTML(http.StatusOK, tplSettingsLabels)
}
diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go
index 843b1d8dfd01d..7439c2411b908 100644
--- a/routers/web/repo/commit.go
+++ b/routers/web/repo/commit.go
@@ -253,7 +253,6 @@ func FileHistory(ctx *context.Context) {
// Diff show different from current commit to previous commit
func Diff(ctx *context.Context) {
ctx.Data["PageIsDiff"] = true
- ctx.Data["RequireTribute"] = true
userName := ctx.Repo.Owner.Name
repoName := ctx.Repo.Repository.Name
diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go
index d7e7bac7b7815..c49eb762d8a66 100644
--- a/routers/web/repo/compare.go
+++ b/routers/web/repo/compare.go
@@ -781,7 +781,6 @@ func CompareDiff(ctx *context.Context) {
ctx.Data["IsRepoToolbarCommits"] = true
ctx.Data["IsDiffCompare"] = true
- ctx.Data["RequireTribute"] = true
templateErrs := setTemplateIfExists(ctx, pullRequestTemplateKey, pullRequestTemplateCandidates)
if len(templateErrs) > 0 {
diff --git a/routers/web/repo/editor.go b/routers/web/repo/editor.go
index 2b66be22aeb96..f65e1ad3d81b1 100644
--- a/routers/web/repo/editor.go
+++ b/routers/web/repo/editor.go
@@ -538,7 +538,6 @@ func DeleteFilePost(ctx *context.Context) {
// UploadFile render upload file page
func UploadFile(ctx *context.Context) {
ctx.Data["PageIsUpload"] = true
- ctx.Data["RequireTribute"] = true
upload.AddUploadContext(ctx, "repo")
canCommit := renderCommitRights(ctx)
treePath := cleanUploadFileName(ctx.Repo.TreePath)
@@ -573,7 +572,6 @@ func UploadFile(ctx *context.Context) {
func UploadFilePost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.UploadRepoFileForm)
ctx.Data["PageIsUpload"] = true
- ctx.Data["RequireTribute"] = true
upload.AddUploadContext(ctx, "repo")
canCommit := renderCommitRights(ctx)
diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go
index 612222598f2fa..e4f1172dd966c 100644
--- a/routers/web/repo/issue.go
+++ b/routers/web/repo/issue.go
@@ -849,7 +849,6 @@ func NewIssue(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
ctx.Data["PageIsIssueList"] = true
ctx.Data["NewIssueChooseTemplate"] = ctx.HasIssueTemplatesOrContactLinks()
- ctx.Data["RequireTribute"] = true
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
title := ctx.FormString("title")
ctx.Data["TitleQuery"] = title
@@ -1295,7 +1294,6 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["IssueType"] = "all"
}
- ctx.Data["RequireTribute"] = true
ctx.Data["IsProjectsEnabled"] = ctx.Repo.CanRead(unit.TypeProjects)
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "comment")
diff --git a/routers/web/repo/issue_label.go b/routers/web/repo/issue_label.go
index 31bf85fedb29a..3123359a65e6f 100644
--- a/routers/web/repo/issue_label.go
+++ b/routers/web/repo/issue_label.go
@@ -28,7 +28,6 @@ func Labels(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.labels")
ctx.Data["PageIsIssueList"] = true
ctx.Data["PageIsLabels"] = true
- ctx.Data["RequireTribute"] = true
ctx.Data["LabelTemplates"] = repo_module.LabelTemplates
ctx.HTML(http.StatusOK, tplLabels)
}
diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go
index 4f99687738247..30004cefb70be 100644
--- a/routers/web/repo/pull.go
+++ b/routers/web/repo/pull.go
@@ -203,6 +203,7 @@ func Fork(ctx *context.Context) {
func ForkPost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.CreateRepoForm)
ctx.Data["Title"] = ctx.Tr("new_fork")
+ ctx.Data["CanForkRepo"] = true
ctxUser := checkContextUser(ctx, form.UID)
if ctx.Written() {
@@ -791,7 +792,6 @@ func ViewPullFiles(ctx *context.Context) {
setCompareContext(ctx, baseCommit, commit, ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
- ctx.Data["RequireTribute"] = true
if ctx.Data["Assignees"], err = repo_model.GetRepoAssignees(ctx, ctx.Repo.Repository); err != nil {
ctx.ServerError("GetAssignees", err)
return
@@ -1160,7 +1160,6 @@ func CompareAndPullRequestPost(ctx *context.Context) {
ctx.Data["PageIsComparePull"] = true
ctx.Data["IsDiffCompare"] = true
ctx.Data["IsRepoToolbarCommits"] = true
- ctx.Data["RequireTribute"] = true
ctx.Data["PullRequestWorkInProgressPrefixes"] = setting.Repository.PullRequest.WorkInProgressPrefixes
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "comment")
diff --git a/routers/web/repo/release.go b/routers/web/repo/release.go
index 3ffadd34ace7b..b8c5f67f45a7e 100644
--- a/routers/web/repo/release.go
+++ b/routers/web/repo/release.go
@@ -308,7 +308,6 @@ func LatestRelease(ctx *context.Context) {
func NewRelease(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["PageIsReleaseList"] = true
- ctx.Data["RequireTribute"] = true
ctx.Data["tag_target"] = ctx.Repo.Repository.DefaultBranch
if tagName := ctx.FormString("tag"); len(tagName) > 0 {
rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName)
@@ -351,7 +350,6 @@ func NewReleasePost(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.NewReleaseForm)
ctx.Data["Title"] = ctx.Tr("repo.release.new_release")
ctx.Data["PageIsReleaseList"] = true
- ctx.Data["RequireTribute"] = true
if ctx.HasError() {
ctx.HTML(http.StatusOK, tplReleaseNew)
@@ -469,7 +467,6 @@ func EditRelease(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["PageIsReleaseList"] = true
ctx.Data["PageIsEditRelease"] = true
- ctx.Data["RequireTribute"] = true
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
upload.AddUploadContext(ctx, "release")
@@ -514,7 +511,6 @@ func EditReleasePost(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("repo.release.edit_release")
ctx.Data["PageIsReleaseList"] = true
ctx.Data["PageIsEditRelease"] = true
- ctx.Data["RequireTribute"] = true
tagName := ctx.Params("*")
rel, err := repo_model.GetRelease(ctx.Repo.Repository.ID, tagName)
diff --git a/routers/web/web.go b/routers/web/web.go
index 4bd2f76c571f1..6b62ff6f83722 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -27,6 +27,7 @@ import (
"code.gitea.io/gitea/modules/web/routing"
"code.gitea.io/gitea/routers/web/admin"
"code.gitea.io/gitea/routers/web/auth"
+ "code.gitea.io/gitea/routers/web/devtest"
"code.gitea.io/gitea/routers/web/events"
"code.gitea.io/gitea/routers/web/explore"
"code.gitea.io/gitea/routers/web/feed"
@@ -1491,6 +1492,12 @@ func RegisterRoutes(m *web.Route) {
if setting.API.EnableSwagger {
m.Get("/swagger.v1.json", SwaggerV1Json)
}
+
+ if !setting.IsProd {
+ m.Any("/devtest", devtest.List)
+ m.Any("/devtest/{sub}", devtest.Tmpl)
+ }
+
m.NotFound(func(w http.ResponseWriter, req *http.Request) {
ctx := context.GetContext(req)
ctx.NotFound("", nil)
diff --git a/routers/web/webfinger.go b/routers/web/webfinger.go
index a8e816d7b7ab4..1442e09a31431 100644
--- a/routers/web/webfinger.go
+++ b/routers/web/webfinger.go
@@ -85,7 +85,7 @@ func WebfingerQuery(ctx *context.Context) {
aliases := []string{
u.HTMLURL(),
- appURL.String() + "api/v1/activitypub/user/" + url.PathEscape(u.Name),
+ appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
}
if !u.KeepEmailPrivate {
aliases = append(aliases, fmt.Sprintf("mailto:%s", u.Email))
@@ -104,7 +104,7 @@ func WebfingerQuery(ctx *context.Context) {
{
Rel: "self",
Type: "application/activity+json",
- Href: appURL.String() + "api/v1/activitypub/user/" + url.PathEscape(u.Name),
+ Href: appURL.String() + "api/v1/activitypub/user-id/" + fmt.Sprint(u.ID),
},
}
diff --git a/services/context/user.go b/services/context/user.go
index 9dc84c3ac15e1..c713667bca75a 100644
--- a/services/context/user.go
+++ b/services/context/user.go
@@ -29,6 +29,27 @@ func UserAssignmentWeb() func(ctx *context.Context) {
}
}
+// UserIDAssignmentAPI returns a middleware to handle context-user assignment for api routes
+func UserIDAssignmentAPI() func(ctx *context.APIContext) {
+ return func(ctx *context.APIContext) {
+ userID := ctx.ParamsInt64(":user-id")
+
+ if ctx.IsSigned && ctx.Doer.ID == userID {
+ ctx.ContextUser = ctx.Doer
+ } else {
+ var err error
+ ctx.ContextUser, err = user_model.GetUserByID(ctx, userID)
+ if err != nil {
+ if user_model.IsErrUserNotExist(err) {
+ ctx.Error(http.StatusNotFound, "GetUserByID", err)
+ } else {
+ ctx.Error(http.StatusInternalServerError, "GetUserByID", err)
+ }
+ }
+ }
+ }
+}
+
// UserAssignmentAPI returns a middleware to handle context-user assignment for api routes
func UserAssignmentAPI() func(ctx *context.APIContext) {
return func(ctx *context.APIContext) {
diff --git a/templates/admin/auth/edit.tmpl b/templates/admin/auth/edit.tmpl
index 9b07774653478..49007e572da96 100644
--- a/templates/admin/auth/edit.tmpl
+++ b/templates/admin/auth/edit.tmpl
@@ -212,7 +212,7 @@