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 <teabot@gitea.io>
This commit is contained in:
parent
c4303efc23
commit
def4956122
10 changed files with 227 additions and 249 deletions
|
@ -36,19 +36,20 @@ type Render interface {
|
|||
|
||||
// Context represents context of a request.
|
||||
type Context struct {
|
||||
Resp ResponseWriter
|
||||
Req *http.Request
|
||||
Resp ResponseWriter
|
||||
Req *http.Request
|
||||
Render Render
|
||||
|
||||
Data middleware.ContextData // data used by MVC templates
|
||||
PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData`
|
||||
Render Render
|
||||
Locale translation.Locale
|
||||
Cache cache.Cache
|
||||
Csrf CSRFProtector
|
||||
Flash *middleware.Flash
|
||||
Session session.Store
|
||||
|
||||
Link string // current request URL
|
||||
EscapedLink string
|
||||
Locale translation.Locale
|
||||
Cache cache.Cache
|
||||
Csrf CSRFProtector
|
||||
Flash *middleware.Flash
|
||||
Session session.Store
|
||||
|
||||
Link string // current request URL (without query string)
|
||||
Doer *user_model.User
|
||||
IsSigned bool
|
||||
IsBasicAuth bool
|
||||
|
|
|
@ -6,7 +6,6 @@ package context
|
|||
import (
|
||||
"encoding/hex"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
|
@ -85,21 +84,3 @@ func (ctx *Context) CookieEncrypt(secret, value string) string {
|
|||
|
||||
return hex.EncodeToString(text)
|
||||
}
|
||||
|
||||
// GetCookieInt returns cookie result in int type.
|
||||
func (ctx *Context) GetCookieInt(name string) int {
|
||||
r, _ := strconv.Atoi(ctx.GetSiteCookie(name))
|
||||
return r
|
||||
}
|
||||
|
||||
// GetCookieInt64 returns cookie result in int64 type.
|
||||
func (ctx *Context) GetCookieInt64(name string) int64 {
|
||||
r, _ := strconv.ParseInt(ctx.GetSiteCookie(name), 10, 64)
|
||||
return r
|
||||
}
|
||||
|
||||
// GetCookieFloat64 returns cookie result in float64 type.
|
||||
func (ctx *Context) GetCookieFloat64(name string) float64 {
|
||||
v, _ := strconv.ParseFloat(ctx.GetSiteCookie(name), 64)
|
||||
return v
|
||||
}
|
||||
|
|
|
@ -4,14 +4,7 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/issue/template"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
)
|
||||
|
||||
// IsUserSiteAdmin returns true if current user is a site admin
|
||||
|
@ -19,11 +12,6 @@ func (ctx *Context) IsUserSiteAdmin() bool {
|
|||
return ctx.IsSigned && ctx.Doer.IsAdmin
|
||||
}
|
||||
|
||||
// IsUserRepoOwner returns true if current user owns current repo
|
||||
func (ctx *Context) IsUserRepoOwner() bool {
|
||||
return ctx.Repo.IsOwner()
|
||||
}
|
||||
|
||||
// IsUserRepoAdmin returns true if current user is admin in current repo
|
||||
func (ctx *Context) IsUserRepoAdmin() bool {
|
||||
return ctx.Repo.IsAdmin()
|
||||
|
@ -39,100 +27,3 @@ func (ctx *Context) IsUserRepoWriter(unitTypes []unit.Type) bool {
|
|||
|
||||
return false
|
||||
}
|
||||
|
||||
// IsUserRepoReaderSpecific returns true if current user can read current repo's specific part
|
||||
func (ctx *Context) IsUserRepoReaderSpecific(unitType unit.Type) bool {
|
||||
return ctx.Repo.CanRead(unitType)
|
||||
}
|
||||
|
||||
// IsUserRepoReaderAny returns true if current user can read any part of current repo
|
||||
func (ctx *Context) IsUserRepoReaderAny() bool {
|
||||
return ctx.Repo.HasAccess()
|
||||
}
|
||||
|
||||
// IssueTemplatesFromDefaultBranch checks for valid issue templates in the repo's default branch,
|
||||
func (ctx *Context) IssueTemplatesFromDefaultBranch() []*api.IssueTemplate {
|
||||
ret, _ := ctx.IssueTemplatesErrorsFromDefaultBranch()
|
||||
return ret
|
||||
}
|
||||
|
||||
// IssueTemplatesErrorsFromDefaultBranch checks for issue templates in the repo's default branch,
|
||||
// returns valid templates and the errors of invalid template files.
|
||||
func (ctx *Context) IssueTemplatesErrorsFromDefaultBranch() ([]*api.IssueTemplate, map[string]error) {
|
||||
var issueTemplates []*api.IssueTemplate
|
||||
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
return issueTemplates, nil
|
||||
}
|
||||
|
||||
if ctx.Repo.Commit == nil {
|
||||
var err error
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
return issueTemplates, nil
|
||||
}
|
||||
}
|
||||
|
||||
invalidFiles := map[string]error{}
|
||||
for _, dirName := range IssueTemplateDirCandidates {
|
||||
tree, err := ctx.Repo.Commit.SubTree(dirName)
|
||||
if err != nil {
|
||||
log.Debug("get sub tree of %s: %v", dirName, err)
|
||||
continue
|
||||
}
|
||||
entries, err := tree.ListEntries()
|
||||
if err != nil {
|
||||
log.Debug("list entries in %s: %v", dirName, err)
|
||||
return issueTemplates, nil
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !template.CouldBe(entry.Name()) {
|
||||
continue
|
||||
}
|
||||
fullName := path.Join(dirName, entry.Name())
|
||||
if it, err := template.UnmarshalFromEntry(entry, dirName); err != nil {
|
||||
invalidFiles[fullName] = err
|
||||
} else {
|
||||
if !strings.HasPrefix(it.Ref, "refs/") { // Assume that the ref intended is always a branch - for tags users should use refs/tags/<ref>
|
||||
it.Ref = git.BranchPrefix + it.Ref
|
||||
}
|
||||
issueTemplates = append(issueTemplates, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
return issueTemplates, invalidFiles
|
||||
}
|
||||
|
||||
// IssueConfigFromDefaultBranch returns the issue config for this repo.
|
||||
// It never returns a nil config.
|
||||
func (ctx *Context) IssueConfigFromDefaultBranch() (api.IssueConfig, error) {
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
return GetDefaultIssueConfig(), nil
|
||||
}
|
||||
|
||||
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.Repository.DefaultBranch)
|
||||
if err != nil {
|
||||
return GetDefaultIssueConfig(), err
|
||||
}
|
||||
|
||||
for _, configName := range IssueConfigCandidates {
|
||||
if _, err := commit.GetTreeEntryByPath(configName + ".yaml"); err == nil {
|
||||
return ctx.Repo.GetIssueConfig(configName+".yaml", commit)
|
||||
}
|
||||
|
||||
if _, err := commit.GetTreeEntryByPath(configName + ".yml"); err == nil {
|
||||
return ctx.Repo.GetIssueConfig(configName+".yml", commit)
|
||||
}
|
||||
}
|
||||
|
||||
return GetDefaultIssueConfig(), nil
|
||||
}
|
||||
|
||||
func (ctx *Context) HasIssueTemplatesOrContactLinks() bool {
|
||||
if len(ctx.IssueTemplatesFromDefaultBranch()) > 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
issueConfig, _ := ctx.IssueConfigFromDefaultBranch()
|
||||
return len(issueConfig.ContactLinks) > 0
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"context"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
@ -28,33 +27,12 @@ import (
|
|||
"code.gitea.io/gitea/modules/log"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||
|
||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// IssueTemplateDirCandidates issue templates directory
|
||||
var IssueTemplateDirCandidates = []string{
|
||||
"ISSUE_TEMPLATE",
|
||||
"issue_template",
|
||||
".gitea/ISSUE_TEMPLATE",
|
||||
".gitea/issue_template",
|
||||
".github/ISSUE_TEMPLATE",
|
||||
".github/issue_template",
|
||||
".gitlab/ISSUE_TEMPLATE",
|
||||
".gitlab/issue_template",
|
||||
}
|
||||
|
||||
var IssueConfigCandidates = []string{
|
||||
".gitea/ISSUE_TEMPLATE/config",
|
||||
".gitea/issue_template/config",
|
||||
".github/ISSUE_TEMPLATE/config",
|
||||
".github/issue_template/config",
|
||||
}
|
||||
|
||||
// PullRequest contains information to make a pull request
|
||||
type PullRequest struct {
|
||||
BaseRepo *repo_model.Repository
|
||||
|
@ -1061,74 +1039,3 @@ func UnitTypes() func(ctx *Context) {
|
|||
ctx.Data["UnitTypeActions"] = unit_model.TypeActions
|
||||
}
|
||||
}
|
||||
|
||||
func GetDefaultIssueConfig() api.IssueConfig {
|
||||
return api.IssueConfig{
|
||||
BlankIssuesEnabled: true,
|
||||
ContactLinks: make([]api.IssueConfigContactLink, 0),
|
||||
}
|
||||
}
|
||||
|
||||
// GetIssueConfig loads the given issue config file.
|
||||
// It never returns a nil config.
|
||||
func (r *Repository) GetIssueConfig(path string, commit *git.Commit) (api.IssueConfig, error) {
|
||||
if r.GitRepo == nil {
|
||||
return GetDefaultIssueConfig(), nil
|
||||
}
|
||||
|
||||
var err error
|
||||
|
||||
treeEntry, err := commit.GetTreeEntryByPath(path)
|
||||
if err != nil {
|
||||
return GetDefaultIssueConfig(), err
|
||||
}
|
||||
|
||||
reader, err := treeEntry.Blob().DataAsync()
|
||||
if err != nil {
|
||||
log.Debug("DataAsync: %v", err)
|
||||
return GetDefaultIssueConfig(), nil
|
||||
}
|
||||
|
||||
defer reader.Close()
|
||||
|
||||
configContent, err := io.ReadAll(reader)
|
||||
if err != nil {
|
||||
return GetDefaultIssueConfig(), err
|
||||
}
|
||||
|
||||
issueConfig := api.IssueConfig{}
|
||||
if err := yaml.Unmarshal(configContent, &issueConfig); err != nil {
|
||||
return GetDefaultIssueConfig(), err
|
||||
}
|
||||
|
||||
for pos, link := range issueConfig.ContactLinks {
|
||||
if link.Name == "" {
|
||||
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing name key", pos+1)
|
||||
}
|
||||
|
||||
if link.URL == "" {
|
||||
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing url key", pos+1)
|
||||
}
|
||||
|
||||
if link.About == "" {
|
||||
return GetDefaultIssueConfig(), fmt.Errorf("contact_link at position %d is missing about key", pos+1)
|
||||
}
|
||||
|
||||
_, err = url.ParseRequestURI(link.URL)
|
||||
if err != nil {
|
||||
return GetDefaultIssueConfig(), fmt.Errorf("%s is not a valid URL", link.URL)
|
||||
}
|
||||
}
|
||||
|
||||
return issueConfig, nil
|
||||
}
|
||||
|
||||
// IsIssueConfig returns if the given path is a issue config file.
|
||||
func (r *Repository) IsIssueConfig(path string) bool {
|
||||
for _, configName := range IssueConfigCandidates {
|
||||
if path == configName+".yaml" || path == configName+".yml" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue