diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/fileicon/basic.go | 20 | ||||
-rw-r--r-- | modules/fileicon/entry.go | 31 | ||||
-rw-r--r-- | modules/fileicon/material.go | 70 | ||||
-rw-r--r-- | modules/fileicon/material_test.go | 9 | ||||
-rw-r--r-- | modules/fileicon/render.go | 17 | ||||
-rw-r--r-- | modules/git/tree_entry_mode.go | 25 | ||||
-rw-r--r-- | modules/git/tree_entry_nogogit.go | 10 | ||||
-rw-r--r-- | modules/session/key.go | 11 | ||||
-rw-r--r-- | modules/setting/security.go | 10 | ||||
-rw-r--r-- | modules/structs/user_app.go | 4 |
10 files changed, 144 insertions, 63 deletions
diff --git a/modules/fileicon/basic.go b/modules/fileicon/basic.go index 040a8e87de..9c513ccbd9 100644 --- a/modules/fileicon/basic.go +++ b/modules/fileicon/basic.go @@ -6,22 +6,26 @@ package fileicon import ( "html/template" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/svg" + "code.gitea.io/gitea/modules/util" ) -func BasicThemeIcon(entry *git.TreeEntry) template.HTML { +func BasicEntryIconName(entry *EntryInfo) string { svgName := "octicon-file" switch { - case entry.IsLink(): + case entry.EntryMode.IsLink(): svgName = "octicon-file-symlink-file" - if te, err := entry.FollowLink(); err == nil && te.IsDir() { + if entry.SymlinkToMode.IsDir() { svgName = "octicon-file-directory-symlink" } - case entry.IsDir(): - svgName = "octicon-file-directory-fill" - case entry.IsSubModule(): + case entry.EntryMode.IsDir(): + svgName = util.Iif(entry.IsOpen, "octicon-file-directory-open-fill", "octicon-file-directory-fill") + case entry.EntryMode.IsSubModule(): svgName = "octicon-file-submodule" } - return svg.RenderHTML(svgName) + return svgName +} + +func BasicEntryIconHTML(entry *EntryInfo) template.HTML { + return svg.RenderHTML(BasicEntryIconName(entry)) } diff --git a/modules/fileicon/entry.go b/modules/fileicon/entry.go new file mode 100644 index 0000000000..e4ded363e5 --- /dev/null +++ b/modules/fileicon/entry.go @@ -0,0 +1,31 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package fileicon + +import "code.gitea.io/gitea/modules/git" + +type EntryInfo struct { + FullName string + EntryMode git.EntryMode + SymlinkToMode git.EntryMode + IsOpen bool +} + +func EntryInfoFromGitTreeEntry(gitEntry *git.TreeEntry) *EntryInfo { + ret := &EntryInfo{FullName: gitEntry.Name(), EntryMode: gitEntry.Mode()} + if gitEntry.IsLink() { + if te, err := gitEntry.FollowLink(); err == nil && te.IsDir() { + ret.SymlinkToMode = te.Mode() + } + } + return ret +} + +func EntryInfoFolder() *EntryInfo { + return &EntryInfo{EntryMode: git.EntryModeTree} +} + +func EntryInfoFolderOpen() *EntryInfo { + return &EntryInfo{EntryMode: git.EntryModeTree, IsOpen: true} +} diff --git a/modules/fileicon/material.go b/modules/fileicon/material.go index 557f7ca9e4..449f527ee8 100644 --- a/modules/fileicon/material.go +++ b/modules/fileicon/material.go @@ -9,11 +9,12 @@ import ( "strings" "sync" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/json" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/options" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/svg" + "code.gitea.io/gitea/modules/util" ) type materialIconRulesData struct { @@ -69,41 +70,51 @@ func (m *MaterialIconProvider) renderFileIconSVG(p *RenderedIconPool, name, svg, } svgID := "svg-mfi-" + name svgCommonAttrs := `class="svg git-entry-icon ` + extraClass + `" width="16" height="16" aria-hidden="true"` + svgHTML := template.HTML(`<svg id="` + svgID + `" ` + svgCommonAttrs + svg[4:]) + if p == nil { + return svgHTML + } if p.IconSVGs[svgID] == "" { - p.IconSVGs[svgID] = template.HTML(`<svg id="` + svgID + `" ` + svgCommonAttrs + svg[4:]) + p.IconSVGs[svgID] = svgHTML } return template.HTML(`<svg ` + svgCommonAttrs + `><use xlink:href="#` + svgID + `"></use></svg>`) } -func (m *MaterialIconProvider) FileIcon(p *RenderedIconPool, entry *git.TreeEntry) template.HTML { +func (m *MaterialIconProvider) EntryIconHTML(p *RenderedIconPool, entry *EntryInfo) template.HTML { if m.rules == nil { - return BasicThemeIcon(entry) + return BasicEntryIconHTML(entry) } - if entry.IsLink() { - if te, err := entry.FollowLink(); err == nil && te.IsDir() { + if entry.EntryMode.IsLink() { + if entry.SymlinkToMode.IsDir() { // keep the old "octicon-xxx" class name to make some "theme plugin selector" could still work return svg.RenderHTML("material-folder-symlink", 16, "octicon-file-directory-symlink") } return svg.RenderHTML("octicon-file-symlink-file") // TODO: find some better icons for them } - name := m.findIconNameByGit(entry) - // the material icon pack's "folder" icon doesn't look good, so use our built-in one - // keep the old "octicon-xxx" class name to make some "theme plugin selector" could still work - if iconSVG, ok := m.svgs[name]; ok && name != "folder" && iconSVG != "" { - // keep the old "octicon-xxx" class name to make some "theme plugin selector" could still work - extraClass := "octicon-file" - switch { - case entry.IsDir(): - extraClass = "octicon-file-directory-fill" - case entry.IsSubModule(): - extraClass = "octicon-file-submodule" + name := m.FindIconName(entry) + iconSVG := m.svgs[name] + if iconSVG == "" { + name = "file" + if entry.EntryMode.IsDir() { + name = util.Iif(entry.IsOpen, "folder-open", "folder") + } + iconSVG = m.svgs[name] + if iconSVG == "" { + setting.PanicInDevOrTesting("missing file icon for %s", name) } - return m.renderFileIconSVG(p, name, iconSVG, extraClass) } - // TODO: use an interface or wrapper for git.Entry to make the code testable. - return BasicThemeIcon(entry) + + // keep the old "octicon-xxx" class name to make some "theme plugin selector" could still work + extraClass := "octicon-file" + switch { + case entry.EntryMode.IsDir(): + extraClass = BasicEntryIconName(entry) + case entry.EntryMode.IsSubModule(): + extraClass = "octicon-file-submodule" + } + return m.renderFileIconSVG(p, name, iconSVG, extraClass) } func (m *MaterialIconProvider) findIconNameWithLangID(s string) string { @@ -118,13 +129,17 @@ func (m *MaterialIconProvider) findIconNameWithLangID(s string) string { return "" } -func (m *MaterialIconProvider) FindIconName(name string, isDir bool) string { - fileNameLower := strings.ToLower(path.Base(name)) - if isDir { +func (m *MaterialIconProvider) FindIconName(entry *EntryInfo) string { + if entry.EntryMode.IsSubModule() { + return "folder-git" + } + + fileNameLower := strings.ToLower(path.Base(entry.FullName)) + if entry.EntryMode.IsDir() { if s, ok := m.rules.FolderNames[fileNameLower]; ok { return s } - return "folder" + return util.Iif(entry.IsOpen, "folder-open", "folder") } if s, ok := m.rules.FileNames[fileNameLower]; ok { @@ -146,10 +161,3 @@ func (m *MaterialIconProvider) FindIconName(name string, isDir bool) string { return "file" } - -func (m *MaterialIconProvider) findIconNameByGit(entry *git.TreeEntry) string { - if entry.IsSubModule() { - return "folder-git" - } - return m.FindIconName(entry.Name(), entry.IsDir()) -} diff --git a/modules/fileicon/material_test.go b/modules/fileicon/material_test.go index f36385aaf3..68353d2189 100644 --- a/modules/fileicon/material_test.go +++ b/modules/fileicon/material_test.go @@ -8,6 +8,7 @@ import ( "code.gitea.io/gitea/models/unittest" "code.gitea.io/gitea/modules/fileicon" + "code.gitea.io/gitea/modules/git" "github.com/stretchr/testify/assert" ) @@ -19,8 +20,8 @@ func TestMain(m *testing.M) { func TestFindIconName(t *testing.T) { unittest.PrepareTestEnv(t) p := fileicon.DefaultMaterialIconProvider() - assert.Equal(t, "php", p.FindIconName("foo.php", false)) - assert.Equal(t, "php", p.FindIconName("foo.PHP", false)) - assert.Equal(t, "javascript", p.FindIconName("foo.js", false)) - assert.Equal(t, "visualstudio", p.FindIconName("foo.vba", false)) + assert.Equal(t, "php", p.FindIconName(&fileicon.EntryInfo{FullName: "foo.php", EntryMode: git.EntryModeBlob})) + assert.Equal(t, "php", p.FindIconName(&fileicon.EntryInfo{FullName: "foo.PHP", EntryMode: git.EntryModeBlob})) + assert.Equal(t, "javascript", p.FindIconName(&fileicon.EntryInfo{FullName: "foo.js", EntryMode: git.EntryModeBlob})) + assert.Equal(t, "visualstudio", p.FindIconName(&fileicon.EntryInfo{FullName: "foo.vba", EntryMode: git.EntryModeBlob})) } diff --git a/modules/fileicon/render.go b/modules/fileicon/render.go index 1d014693fd..8ed86b9ac0 100644 --- a/modules/fileicon/render.go +++ b/modules/fileicon/render.go @@ -7,7 +7,6 @@ import ( "html/template" "strings" - "code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/setting" ) @@ -34,19 +33,9 @@ func (p *RenderedIconPool) RenderToHTML() template.HTML { return template.HTML(sb.String()) } -// TODO: use an interface or struct to replace "*git.TreeEntry", to decouple the fileicon module from git module - -func RenderEntryIcon(renderedIconPool *RenderedIconPool, entry *git.TreeEntry) template.HTML { - if setting.UI.FileIconTheme == "material" { - return DefaultMaterialIconProvider().FileIcon(renderedIconPool, entry) - } - return BasicThemeIcon(entry) -} - -func RenderEntryIconOpen(renderedIconPool *RenderedIconPool, entry *git.TreeEntry) template.HTML { - // TODO: add "open icon" support +func RenderEntryIconHTML(renderedIconPool *RenderedIconPool, entry *EntryInfo) template.HTML { if setting.UI.FileIconTheme == "material" { - return DefaultMaterialIconProvider().FileIcon(renderedIconPool, entry) + return DefaultMaterialIconProvider().EntryIconHTML(renderedIconPool, entry) } - return BasicThemeIcon(entry) + return BasicEntryIconHTML(entry) } diff --git a/modules/git/tree_entry_mode.go b/modules/git/tree_entry_mode.go index 1193bec4f1..d815a8bc2e 100644 --- a/modules/git/tree_entry_mode.go +++ b/modules/git/tree_entry_mode.go @@ -30,6 +30,31 @@ func (e EntryMode) String() string { return strconv.FormatInt(int64(e), 8) } +// IsSubModule if the entry is a sub module +func (e EntryMode) IsSubModule() bool { + return e == EntryModeCommit +} + +// IsDir if the entry is a sub dir +func (e EntryMode) IsDir() bool { + return e == EntryModeTree +} + +// IsLink if the entry is a symlink +func (e EntryMode) IsLink() bool { + return e == EntryModeSymlink +} + +// IsRegular if the entry is a regular file +func (e EntryMode) IsRegular() bool { + return e == EntryModeBlob +} + +// IsExecutable if the entry is an executable file (not necessarily binary) +func (e EntryMode) IsExecutable() bool { + return e == EntryModeExec +} + func ParseEntryMode(mode string) (EntryMode, error) { switch mode { case "000000": diff --git a/modules/git/tree_entry_nogogit.go b/modules/git/tree_entry_nogogit.go index 81fb638d56..0c0e1835f1 100644 --- a/modules/git/tree_entry_nogogit.go +++ b/modules/git/tree_entry_nogogit.go @@ -59,27 +59,27 @@ func (te *TreeEntry) Size() int64 { // IsSubModule if the entry is a sub module func (te *TreeEntry) IsSubModule() bool { - return te.entryMode == EntryModeCommit + return te.entryMode.IsSubModule() } // IsDir if the entry is a sub dir func (te *TreeEntry) IsDir() bool { - return te.entryMode == EntryModeTree + return te.entryMode.IsDir() } // IsLink if the entry is a symlink func (te *TreeEntry) IsLink() bool { - return te.entryMode == EntryModeSymlink + return te.entryMode.IsLink() } // IsRegular if the entry is a regular file func (te *TreeEntry) IsRegular() bool { - return te.entryMode == EntryModeBlob + return te.entryMode.IsRegular() } // IsExecutable if the entry is an executable file (not necessarily binary) func (te *TreeEntry) IsExecutable() bool { - return te.entryMode == EntryModeExec + return te.entryMode.IsExecutable() } // Blob returns the blob object the entry diff --git a/modules/session/key.go b/modules/session/key.go new file mode 100644 index 0000000000..c3da997c67 --- /dev/null +++ b/modules/session/key.go @@ -0,0 +1,11 @@ +// Copyright 2025 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package session + +const ( + KeyUID = "uid" + KeyUname = "uname" + + KeyUserHasTwoFactorAuth = "userHasTwoFactorAuth" +) diff --git a/modules/setting/security.go b/modules/setting/security.go index 2f798b75c7..3ae4c005c7 100644 --- a/modules/setting/security.go +++ b/modules/setting/security.go @@ -39,6 +39,7 @@ var ( CSRFCookieName = "_csrf" CSRFCookieHTTPOnly = true RecordUserSignupMetadata = false + TwoFactorAuthEnforced = false ) // loadSecret load the secret from ini by uriKey or verbatimKey, only one of them could be set @@ -142,6 +143,15 @@ func loadSecurityFrom(rootCfg ConfigProvider) { PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false) SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20) + twoFactorAuth := sec.Key("TWO_FACTOR_AUTH").String() + switch twoFactorAuth { + case "": + case "enforced": + TwoFactorAuthEnforced = true + default: + log.Fatal("Invalid two-factor auth option: %s", twoFactorAuth) + } + InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN") if InstallLock && InternalToken == "" { // if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate diff --git a/modules/structs/user_app.go b/modules/structs/user_app.go index a7d2e28b41..8401252bd6 100644 --- a/modules/structs/user_app.go +++ b/modules/structs/user_app.go @@ -23,9 +23,11 @@ type AccessToken struct { type AccessTokenList []*AccessToken // CreateAccessTokenOption options when create access token +// swagger:model CreateAccessTokenOption type CreateAccessTokenOption struct { // required: true - Name string `json:"name" binding:"Required"` + Name string `json:"name" binding:"Required"` + // example: ["all", "read:activitypub","read:issue", "write:misc", "read:notification", "read:organization", "read:package", "read:repository", "read:user"] Scopes []string `json:"scopes"` } |