Skip to content

Commit def4956

Browse files
wxiaoguangGiteaBot
andauthored
Improve Gitea's web context, decouple "issue template" code into service package (#24590)
1. Remove unused fields/methods in web context. 2. Make callers call target function directly instead of the light wrapper like "IsUserRepoReaderSpecific" 3. The "issue template" code shouldn't be put in the "modules/context" package, so move them to the service package. --------- Co-authored-by: Giteabot <[email protected]>
1 parent c4303ef commit def4956

File tree

10 files changed

+228
-250
lines changed

10 files changed

+228
-250
lines changed

modules/context/context.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,20 @@ type Render interface {
3636

3737
// Context represents context of a request.
3838
type Context struct {
39-
Resp ResponseWriter
40-
Req *http.Request
39+
Resp ResponseWriter
40+
Req *http.Request
41+
Render Render
42+
4143
Data middleware.ContextData // data used by MVC templates
4244
PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
43-
Render Render
44-
Locale translation.Locale
45-
Cache cache.Cache
46-
Csrf CSRFProtector
47-
Flash *middleware.Flash
48-
Session session.Store
49-
50-
Link string // current request URL
51-
EscapedLink string
45+
46+
Locale translation.Locale
47+
Cache cache.Cache
48+
Csrf CSRFProtector
49+
Flash *middleware.Flash
50+
Session session.Store
51+
52+
Link string // current request URL (without query string)
5253
Doer *user_model.User
5354
IsSigned bool
5455
IsBasicAuth bool

modules/context/context_cookie.go

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package context
66
import (
77
"encoding/hex"
88
"net/http"
9-
"strconv"
109
"strings"
1110

1211
"code.gitea.io/gitea/modules/setting"
@@ -85,21 +84,3 @@ func (ctx *Context) CookieEncrypt(secret, value string) string {
8584

8685
return hex.EncodeToString(text)
8786
}
88-
89-
// GetCookieInt returns cookie result in int type.
90-
func (ctx *Context) GetCookieInt(name string) int {
91-
r, _ := strconv.Atoi(ctx.GetSiteCookie(name))
92-
return r
93-
}
94-
95-
// GetCookieInt64 returns cookie result in int64 type.
96-
func (ctx *Context) GetCookieInt64(name string) int64 {
97-
r, _ := strconv.ParseInt(ctx.GetSiteCookie(name), 10, 64)
98-
return r
99-
}
100-
101-
// GetCookieFloat64 returns cookie result in float64 type.
102-
func (ctx *Context) GetCookieFloat64(name string) float64 {
103-
v, _ := strconv.ParseFloat(ctx.GetSiteCookie(name), 64)
104-
return v
105-
}

modules/context/context_model.go

Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,14 @@
44
package context
55

66
import (
7-
"path"
8-
"strings"
9-
107
"code.gitea.io/gitea/models/unit"
11-
"code.gitea.io/gitea/modules/git"
12-
"code.gitea.io/gitea/modules/issue/template"
13-
"code.gitea.io/gitea/modules/log"
14-
api "code.gitea.io/gitea/modules/structs"
158
)
169

1710
// IsUserSiteAdmin returns true if current user is a site admin
1811
func (ctx *Context) IsUserSiteAdmin() bool {
1912
return ctx.IsSigned && ctx.Doer.IsAdmin
2013
}
2114

22-
// IsUserRepoOwner returns true if current user owns current repo
23-
func (ctx *Context) IsUserRepoOwner() bool {
24-
return ctx.Repo.IsOwner()
25-
}
26-
2715
// IsUserRepoAdmin returns true if current user is admin in current repo
2816
func (ctx *Context) IsUserRepoAdmin() bool {
2917
return ctx.Repo.IsAdmin()
@@ -39,100 +27,3 @@ func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool {
3927

4028
return false
4129
}
42-
43-
// IsUserRepoReaderSpecific returns true if current user can read current repo's specific part
44-
func (ctx *Context) IsUserRepoReaderSpecific(unitType unit.Type) bool {
45-
return ctx.Repo.CanRead(unitType)
46-
}
47-
48-
// IsUserRepoReaderAny returns true if current user can read any part of current repo
49-
func (ctx *Context) IsUserRepoReaderAny() bool {
50-
return ctx.Repo.HasAccess()
51-
}
52-
53-
// IssueTemplatesFromDefaultBranch checks for valid issue templates in the repo's default branch,
54-
func (ctx *Context) IssueTemplatesFromDefaultBranch() []*api.IssueTemplate {
55-
ret, _ := ctx.IssueTemplatesErrorsFromDefaultBranch()
56-
return ret
57-
}
58-
59-
// IssueTemplatesErrorsFromDefaultBranch checks for issue templates in the repo's default branch,
60-
// returns valid templates and the errors of invalid template files.
61-
func (ctx *Context) IssueTemplatesErrorsFromDefaultBranch() ([]*api.IssueTemplate, map[string]error) {
62-
var issueTemplates []*api.IssueTemplate
63-
64-
if ctx.Repo.Repository.IsEmpty {
65-
return issueTemplates, nil
66-
}
67-
68-
if ctx.Repo.Commit == nil {
69-
var err error
70-
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
71-
if err != nil {
72-
return issueTemplates, nil
73-
}
74-
}
75-
76-
invalidFiles := map[string]error{}
77-
for _, dirName := range IssueTemplateDirCandidates {
78-
tree, err := ctx.Repo.Commit.SubTree(dirName)
79-
if err != nil {
80-
log.Debug("get sub tree of %s: %v", dirName, err)
81-
continue
82-
}
83-
entries, err := tree.ListEntries()
84-
if err != nil {
85-
log.Debug("list entries in %s: %v", dirName, err)
86-
return issueTemplates, nil
87-
}
88-
for _, entry := range entries {
89-
if !template.CouldBe(entry.Name()) {
90-
continue
91-
}
92-
fullName := path.Join(dirName, entry.Name())
93-
if it, err := template.UnmarshalFromEntry(entry, dirName); err != nil {
94-
invalidFiles[fullName] = err
95-
} else {
96-
if !strings.HasPrefix(it.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref>
97-
it.Ref = git.BranchPrefix + it.Ref
98-
}
99-
issueTemplates = append(issueTemplates, it)
100-
}
101-
}
102-
}
103-
return issueTemplates, invalidFiles
104-
}
105-
106-
// IssueConfigFromDefaultBranch returns the issue config for this repo.
107-
// It never returns a nil config.
108-
func (ctx *Context) IssueConfigFromDefaultBranch() (api.IssueConfig, error) {
109-
if ctx.Repo.Repository.IsEmpty {
110-
return GetDefaultIssueConfig(), nil
111-
}
112-
113-
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
114-
if err != nil {
115-
return GetDefaultIssueConfig(), err
116-
}
117-
118-
for _, configName := range IssueConfigCandidates {
119-
if _, err := commit.GetTreeEntryByPath(configName + ".yaml"); err == nil {
120-
return ctx.Repo.GetIssueConfig(configName+".yaml", commit)
121-
}
122-
123-
if _, err := commit.GetTreeEntryByPath(configName + ".yml"); err == nil {
124-
return ctx.Repo.GetIssueConfig(configName+".yml", commit)
125-
}
126-
}
127-
128-
return GetDefaultIssueConfig(), nil
129-
}
130-
131-
func (ctx *Context) HasIssueTemplatesOrContactLinks() bool {
132-
if len(ctx.IssueTemplatesFromDefaultBranch()) > 0 {
133-
return true
134-
}
135-
136-
issueConfig, _ := ctx.IssueConfigFromDefaultBranch()
137-
return len(issueConfig.ContactLinks) > 0
138-
}

modules/context/repo.go

Lines changed: 0 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"context"
99
"fmt"
1010
"html"
11-
"io"
1211
"net/http"
1312
"net/url"
1413
"path"
@@ -28,33 +27,12 @@ import (
2827
"code.gitea.io/gitea/modules/log"
2928
repo_module "code.gitea.io/gitea/modules/repository"
3029
"code.gitea.io/gitea/modules/setting"
31-
api "code.gitea.io/gitea/modules/structs"
3230
"code.gitea.io/gitea/modules/util"
3331
asymkey_service "code.gitea.io/gitea/services/asymkey"
3432

3533
"github.com/editorconfig/editorconfig-core-go/v2"
36-
"gopkg.in/yaml.v3"
3734
)
3835

39-
// IssueTemplateDirCandidates issue templates directory
40-
var IssueTemplateDirCandidates = []string{
41-
"ISSUE_TEMPLATE",
42-
"issue_template",
43-
".gitea/ISSUE_TEMPLATE",
44-
".gitea/issue_template",
45-
".github/ISSUE_TEMPLATE",
46-
".github/issue_template",
47-
".gitlab/ISSUE_TEMPLATE",
48-
".gitlab/issue_template",
49-
}
50-
51-
var IssueConfigCandidates = []string{
52-
".gitea/ISSUE_TEMPLATE/config",
53-
".gitea/issue_template/config",
54-
".github/ISSUE_TEMPLATE/config",
55-
".github/issue_template/config",
56-
}
57-
5836
// PullRequest contains information to make a pull request
5937
type PullRequest struct {
6038
BaseRepo *repo_model.Repository
@@ -1061,74 +1039,3 @@ func UnitTypes() func(ctx *Context) {
10611039
ctx.Data["UnitTypeActions"] = unit_model.TypeActions
10621040
}
10631041
}
1064-
1065-
func GetDefaultIssueConfig() api.IssueConfig {
1066-
return api.IssueConfig{
1067-
BlankIssuesEnabled: true,
1068-
ContactLinks: make([]api.IssueConfigContactLink, 0),
1069-
}
1070-
}
1071-
1072-
// GetIssueConfig loads the given issue config file.
1073-
// It never returns a nil config.
1074-
func (r *Repository) GetIssueConfig(path string, commit *git.Commit) (api.IssueConfig, error) {
1075-
if r.GitRepo == nil {
1076-
return GetDefaultIssueConfig(), nil
1077-
}
1078-
1079-
var err error
1080-
1081-
treeEntry, err := commit.GetTreeEntryByPath(path)
1082-
if err != nil {
1083-
return GetDefaultIssueConfig(), err
1084-
}
1085-
1086-
reader, err := treeEntry.Blob().DataAsync()
1087-
if err != nil {
1088-
log.Debug("DataAsync: %v", err)
1089-
return GetDefaultIssueConfig(), nil
1090-
}
1091-
1092-
defer reader.Close()
1093-
1094-
configContent, err := io.ReadAll(reader)
1095-
if err != nil {
1096-
return GetDefaultIssueConfig(), err
1097-
}
1098-
1099-
issueConfig := api.IssueConfig{}
1100-
if err := yaml.Unmarshal(configContent, &issueConfig); err != nil {
1101-
return GetDefaultIssueConfig(), err
1102-
}
1103-
1104-
for pos, link := range issueConfig.ContactLinks {
1105-
if link.Name == "" {
1106-
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing name key", pos+1)
1107-
}
1108-
1109-
if link.URL == "" {
1110-
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing url key", pos+1)
1111-
}
1112-
1113-
if link.About == "" {
1114-
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing about key", pos+1)
1115-
}
1116-
1117-
_, err = url.ParseRequestURI(link.URL)
1118-
if err != nil {
1119-
return GetDefaultIssueConfig(), fmt.Errorf("%s is not a valid URL", link.URL)
1120-
}
1121-
}
1122-
1123-
return issueConfig, nil
1124-
}
1125-
1126-
// IsIssueConfig returns if the given path is a issue config file.
1127-
func (r *Repository) IsIssueConfig(path string) bool {
1128-
for _, configName := range IssueConfigCandidates {
1129-
if path == configName+".yaml" || path == configName+".yml" {
1130-
return true
1131-
}
1132-
}
1133-
return false
1134-
}

routers/api/v1/api.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ func reqSiteAdmin() func(ctx *context.APIContext) {
316316
// reqOwner user should be the owner of the repo or site admin.
317317
func reqOwner() func(ctx *context.APIContext) {
318318
return func(ctx *context.APIContext) {
319-
if !ctx.IsUserRepoOwner() && !ctx.IsUserSiteAdmin() {
319+
if !ctx.Repo.IsOwner() && !ctx.IsUserSiteAdmin() {
320320
ctx.Error(http.StatusForbidden, "reqOwner", "user should be the owner of the repo")
321321
return
322322
}
@@ -355,7 +355,7 @@ func reqRepoBranchWriter(ctx *context.APIContext) {
355355
// reqRepoReader user should have specific read permission or be a repo admin or a site admin
356356
func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) {
357357
return func(ctx *context.APIContext) {
358-
if !ctx.IsUserRepoReaderSpecific(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
358+
if !ctx.Repo.CanRead(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
359359
ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin")
360360
return
361361
}
@@ -365,7 +365,7 @@ func reqRepoReader(unitType unit.Type) func(ctx *context.APIContext) {
365365
// reqAnyRepoReader user should have any permission to read repository or permissions of site admin
366366
func reqAnyRepoReader() func(ctx *context.APIContext) {
367367
return func(ctx *context.APIContext) {
368-
if !ctx.IsUserRepoReaderAny() && !ctx.IsUserSiteAdmin() {
368+
if !ctx.Repo.HasAccess() && !ctx.IsUserSiteAdmin() {
369369
ctx.Error(http.StatusForbidden, "reqAnyRepoReader", "user should have any permission to read repository or permissions of site admin")
370370
return
371371
}

routers/api/v1/repo/repo.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"code.gitea.io/gitea/modules/web"
3131
"code.gitea.io/gitea/routers/api/v1/utils"
3232
"code.gitea.io/gitea/services/convert"
33+
"code.gitea.io/gitea/services/issue"
3334
repo_service "code.gitea.io/gitea/services/repository"
3435
)
3536

@@ -1144,8 +1145,12 @@ func GetIssueTemplates(ctx *context.APIContext) {
11441145
// responses:
11451146
// "200":
11461147
// "$ref": "#/responses/IssueTemplates"
1147-
1148-
ctx.JSON(http.StatusOK, ctx.IssueTemplatesFromDefaultBranch())
1148+
ret, err := issue.GetTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo)
1149+
if err != nil {
1150+
ctx.Error(http.StatusInternalServerError, "GetTemplatesFromDefaultBranch", err)
1151+
return
1152+
}
1153+
ctx.JSON(http.StatusOK, ret)
11491154
}
11501155

11511156
// GetIssueConfig returns the issue config for a repo
@@ -1169,7 +1174,7 @@ func GetIssueConfig(ctx *context.APIContext) {
11691174
// responses:
11701175
// "200":
11711176
// "$ref": "#/responses/RepoIssueConfig"
1172-
issueConfig, _ := ctx.IssueConfigFromDefaultBranch()
1177+
issueConfig, _ := issue.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo)
11731178
ctx.JSON(http.StatusOK, issueConfig)
11741179
}
11751180

@@ -1194,7 +1199,7 @@ func ValidateIssueConfig(ctx *context.APIContext) {
11941199
// responses:
11951200
// "200":
11961201
// "$ref": "#/responses/RepoIssueConfigValidation"
1197-
_, err := ctx.IssueConfigFromDefaultBranch()
1202+
_, err := issue.GetTemplateConfigFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo)
11981203

11991204
if err == nil {
12001205
ctx.JSON(http.StatusOK, api.IssueConfigValidation{Valid: true, Message: ""})

0 commit comments

Comments
 (0)