This commit is contained in:
@@ -14,25 +14,25 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
git_model "code.gitea.io/gitea/models/git"
|
||||
issues_model "code.gitea.io/gitea/models/issues"
|
||||
access_model "code.gitea.io/gitea/models/perm/access"
|
||||
repo_model "code.gitea.io/gitea/models/repo"
|
||||
unit_model "code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/cache"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
"code.gitea.io/gitea/modules/gitrepo"
|
||||
"code.gitea.io/gitea/modules/httplib"
|
||||
code_indexer "code.gitea.io/gitea/modules/indexer/code"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/optional"
|
||||
repo_module "code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
asymkey_service "code.gitea.io/gitea/services/asymkey"
|
||||
asymkey_model "gitea.dev/models/asymkey"
|
||||
"gitea.dev/models/db"
|
||||
git_model "gitea.dev/models/git"
|
||||
issues_model "gitea.dev/models/issues"
|
||||
access_model "gitea.dev/models/perm/access"
|
||||
repo_model "gitea.dev/models/repo"
|
||||
unit_model "gitea.dev/models/unit"
|
||||
user_model "gitea.dev/models/user"
|
||||
"gitea.dev/modules/cache"
|
||||
"gitea.dev/modules/git"
|
||||
"gitea.dev/modules/gitrepo"
|
||||
"gitea.dev/modules/httplib"
|
||||
code_indexer "gitea.dev/modules/indexer/code"
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/optional"
|
||||
repo_module "gitea.dev/modules/repository"
|
||||
"gitea.dev/modules/setting"
|
||||
"gitea.dev/modules/util"
|
||||
asymkey_service "gitea.dev/services/asymkey"
|
||||
|
||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||
)
|
||||
@@ -58,16 +58,30 @@ func (prc *PullRequestContext) CanCreateNewPull() bool {
|
||||
ctx := prc.ctx
|
||||
// People who have push access or have forked repository can propose a new pull request.
|
||||
can := prc.baseRepo.CanContentChange() &&
|
||||
(ctx.Repo.CanWrite(unit_model.TypeCode) || (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)))
|
||||
(ctx.Repo.Permission.CanWrite(unit_model.TypeCode) || (ctx.IsSigned && repo_model.HasForkedRepo(ctx, ctx.Doer.ID, ctx.Repo.Repository.ID)))
|
||||
prc.canCreateNewPull = &can
|
||||
return can
|
||||
}
|
||||
|
||||
// CompareHeadRef formats the head side of a compare link, "owner/repo:branch" is only needed when a fork can share its base repo's owner
|
||||
func CompareHeadRef(baseRepo, headRepo *repo_model.Repository, headBranch string) string {
|
||||
if baseRepo.ID == headRepo.ID /* same repo */ {
|
||||
return headBranch
|
||||
} else if baseRepo.OwnerID == headRepo.OwnerID /* same owner */ {
|
||||
return headRepo.FullName() + ":" + headBranch
|
||||
}
|
||||
// not the same owner: if there can be multiple forks in one owner, we still need the full name
|
||||
if setting.Repository.AllowForkIntoSameOwner {
|
||||
return headRepo.FullName() + ":" + headBranch
|
||||
}
|
||||
// if there is only one fork in the different owner, we only need the owner's name for the head ref
|
||||
return headRepo.OwnerName + ":" + headBranch
|
||||
}
|
||||
|
||||
func (prc *PullRequestContext) MakeDefaultCompareLink(headBranch string) string {
|
||||
return prc.baseRepo.Link() + "/compare/" +
|
||||
util.PathEscapeSegments(prc.DefaultTargetBranch()) + "..." +
|
||||
util.Iif(prc.SameRepo(), "", util.PathEscapeSegments(prc.headRepo.OwnerName)+":") +
|
||||
util.PathEscapeSegments(headBranch)
|
||||
util.PathEscapeSegments(CompareHeadRef(prc.baseRepo, prc.headRepo, headBranch))
|
||||
}
|
||||
|
||||
func (prc *PullRequestContext) DefaultTargetBranch() string {
|
||||
@@ -81,7 +95,7 @@ func (prc *PullRequestContext) DefaultTargetBranch() string {
|
||||
|
||||
// Repository contains information to operate a repository
|
||||
type Repository struct {
|
||||
access_model.Permission
|
||||
Permission access_model.Permission
|
||||
|
||||
Repository *repo_model.Repository
|
||||
Owner *user_model.User
|
||||
@@ -242,7 +256,7 @@ func (r *Repository) CanUseTimetracker(ctx context.Context, issue *issues_model.
|
||||
// Checking for following:
|
||||
// 1. Is timetracker enabled
|
||||
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
|
||||
isAssigned, _ := issues_model.IsUserAssignedToIssue(ctx, issue, user)
|
||||
isAssigned, _ := issues_model.IsUserAssignedToIssue(ctx, issue, user.ID)
|
||||
return r.Repository.IsTimetrackerEnabled(ctx) && (!r.Repository.AllowOnlyContributorsToTrackTime(ctx) ||
|
||||
r.Permission.CanWriteIssuesOrPulls(issue.IsPull) || issue.IsPoster(user.ID) || isAssigned)
|
||||
}
|
||||
@@ -421,8 +435,9 @@ func RedirectToRepo(ctx *Base, redirectRepoID int64) {
|
||||
ctx.Redirect(path.Join(setting.AppSubURL, redirectPath), http.StatusMovedPermanently)
|
||||
}
|
||||
|
||||
func repoAssignment(ctx *Context, repo *repo_model.Repository) {
|
||||
func repoAssignmentLegacy(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
var err error
|
||||
repo := data.repo
|
||||
if err = repo.LoadOwner(ctx); err != nil {
|
||||
ctx.ServerError("LoadOwner", err)
|
||||
return
|
||||
@@ -469,13 +484,25 @@ func InitRepoPullRequestCtx(ctx *Context, base, head *repo_model.Repository) {
|
||||
ctx.Data["PullRequestCtx"] = ctx.Repo.PullRequestCtx
|
||||
}
|
||||
|
||||
// RepoAssignment returns a middleware to handle repository assignment
|
||||
func RepoAssignment(ctx *Context) {
|
||||
type repoAssignmentPrepareDataStruct struct {
|
||||
ownerName string
|
||||
repoName string
|
||||
repo *repo_model.Repository
|
||||
}
|
||||
|
||||
func repoAssignmentPreCheck(ctx *Context) {
|
||||
if ctx.Data["Repository"] != nil {
|
||||
setting.PanicInDevOrTesting("RepoAssignment should not be executed twice")
|
||||
}
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
setting.PanicInDevOrTesting("RepoAssignment: GitRepo should be nil")
|
||||
_ = ctx.Repo.GitRepo.Close()
|
||||
ctx.Repo.GitRepo = nil
|
||||
}
|
||||
}
|
||||
|
||||
var err error
|
||||
func repoAssignmentPrepareData(ctx *Context) *repoAssignmentPrepareDataStruct {
|
||||
// HINT: here it doesn't handle ".wiki" extension, it is handled in repoAssignmentAutoRedirectWiki, need to be refactored in the future
|
||||
userName := ctx.PathParam("username")
|
||||
repoName := ctx.PathParam("reponame")
|
||||
repoName = strings.TrimSuffix(repoName, ".git")
|
||||
@@ -484,7 +511,12 @@ func RepoAssignment(ctx *Context) {
|
||||
repoName = strings.TrimSuffix(repoName, ".rss")
|
||||
repoName = strings.TrimSuffix(repoName, ".atom")
|
||||
}
|
||||
return &repoAssignmentPrepareDataStruct{ownerName: userName, repoName: repoName}
|
||||
}
|
||||
|
||||
func repoAssignmentPrepareOwner(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
var err error
|
||||
userName := data.ownerName
|
||||
// Check if the user is the same as the repository owner
|
||||
if ctx.IsSigned && strings.EqualFold(ctx.Doer.LowerName, userName) {
|
||||
ctx.Repo.Owner = ctx.Doer
|
||||
@@ -514,7 +546,10 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
ctx.ContextUser = ctx.Repo.Owner
|
||||
ctx.Data["ContextUser"] = ctx.ContextUser
|
||||
}
|
||||
|
||||
func repoAssignmentAutoRedirectWiki(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
userName, repoName := data.ownerName, data.repoName
|
||||
// redirect link to wiki
|
||||
if strings.HasSuffix(repoName, ".wiki") {
|
||||
// ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added
|
||||
@@ -534,7 +569,10 @@ func RepoAssignment(ctx *Context) {
|
||||
ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func repoAssignmentPrepareRepo(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
repoName := data.repoName
|
||||
// Get repository.
|
||||
repo, err := repo_model.GetRepositoryByName(ctx, ctx.Repo.Owner.ID, repoName)
|
||||
if err != nil {
|
||||
@@ -557,12 +595,11 @@ func RepoAssignment(ctx *Context) {
|
||||
return
|
||||
}
|
||||
repo.Owner = ctx.Repo.Owner
|
||||
data.repo = repo
|
||||
}
|
||||
|
||||
repoAssignment(ctx, repo)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
|
||||
func repoAssignmentPrepareTemplateData(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
repo := data.repo
|
||||
ctx.Repo.RepoLink = repo.Link()
|
||||
ctx.Data["RepoLink"] = ctx.Repo.RepoLink
|
||||
ctx.Data["FeedURL"] = ctx.Repo.RepoLink
|
||||
@@ -584,7 +621,7 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
ctx.Data["NumReleases"], err = db.Count[repo_model.Release](ctx, repo_model.FindReleasesOptions{
|
||||
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
||||
IncludeDrafts: ctx.Repo.CanWrite(unit_model.TypeReleases),
|
||||
IncludeDrafts: ctx.Repo.Permission.CanWrite(unit_model.TypeReleases),
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -596,10 +633,10 @@ func RepoAssignment(ctx *Context) {
|
||||
ctx.Data["PageTitleCommon"] = repo.Name + " - " + setting.AppName
|
||||
ctx.Data["Repository"] = repo
|
||||
ctx.Data["Owner"] = ctx.Repo.Repository.Owner
|
||||
ctx.Data["CanWriteCode"] = ctx.Repo.CanWrite(unit_model.TypeCode)
|
||||
ctx.Data["CanWriteIssues"] = ctx.Repo.CanWrite(unit_model.TypeIssues)
|
||||
ctx.Data["CanWritePulls"] = ctx.Repo.CanWrite(unit_model.TypePullRequests)
|
||||
ctx.Data["CanWriteActions"] = ctx.Repo.CanWrite(unit_model.TypeActions)
|
||||
ctx.Data["CanWriteCode"] = ctx.Repo.Permission.CanWrite(unit_model.TypeCode)
|
||||
ctx.Data["CanWriteIssues"] = ctx.Repo.Permission.CanWrite(unit_model.TypeIssues)
|
||||
ctx.Data["CanWritePulls"] = ctx.Repo.Permission.CanWrite(unit_model.TypePullRequests)
|
||||
ctx.Data["CanWriteActions"] = ctx.Repo.Permission.CanWrite(unit_model.TypeActions)
|
||||
|
||||
canSignedUserFork, err := repo_module.CanUserForkRepo(ctx, ctx.Doer, ctx.Repo.Repository)
|
||||
if err != nil {
|
||||
@@ -655,33 +692,38 @@ func RepoAssignment(ctx *Context) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink ||
|
||||
ctx.Link == ctx.Repo.RepoLink+"/settings" ||
|
||||
strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") ||
|
||||
ctx.Link == ctx.Repo.RepoLink+"/-/migrate/status"
|
||||
func repoAssignmentIsHomeOrSettings(ctx *Context, data *repoAssignmentPrepareDataStruct) bool {
|
||||
repoLink := data.repo.Link()
|
||||
return ctx.Link == repoLink ||
|
||||
strings.HasPrefix(ctx.Link+"/", repoLink+"/settings/") ||
|
||||
ctx.Link == repoLink+"/-/migrate/status"
|
||||
}
|
||||
|
||||
func repoAssignmentAutoRedirectNotReady(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
// Disable everything when the repo is being created
|
||||
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {
|
||||
if !isHomeOrSettings {
|
||||
if !repoAssignmentIsHomeOrSettings(ctx, data) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.Repo.GitRepo != nil {
|
||||
setting.PanicInDevOrTesting("RepoAssignment: GitRepo should be nil")
|
||||
_ = ctx.Repo.GitRepo.Close()
|
||||
ctx.Repo.GitRepo = nil
|
||||
}
|
||||
|
||||
func repoAssignmentPrepareGitRepo(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
var err error
|
||||
repo := data.repo
|
||||
ctx.Repo.GitRepo, err = gitrepo.RepositoryFromRequestContextOrOpen(ctx, repo)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "repository does not exist") || strings.Contains(err.Error(), "no such file or directory") {
|
||||
if ctx.Repo.Repository.IsBeingCreated() {
|
||||
return
|
||||
}
|
||||
log.Error("Repository %-v has a broken repository on the file system: %s Error: %v", ctx.Repo.Repository, ctx.Repo.Repository.RelativePath(), err)
|
||||
ctx.Repo.Repository.MarkAsBrokenEmpty()
|
||||
// Only allow access to base of repo or settings
|
||||
if !isHomeOrSettings {
|
||||
if !repoAssignmentIsHomeOrSettings(ctx, data) {
|
||||
ctx.Redirect(ctx.Repo.RepoLink)
|
||||
}
|
||||
return
|
||||
@@ -689,12 +731,12 @@ func RepoAssignment(ctx *Context) {
|
||||
ctx.ServerError("RepoAssignment Invalid repo "+repo.FullName(), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Stop at this point when the repo is empty.
|
||||
if ctx.Repo.Repository.IsEmpty {
|
||||
func repoAssignmentPrepareBranches(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
if data.repo.IsEmpty {
|
||||
return
|
||||
}
|
||||
|
||||
branchOpts := git_model.FindBranchOptions{
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
IsDeletedBranch: optional.Some(false),
|
||||
@@ -716,7 +758,13 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
|
||||
ctx.Data["BranchesCount"] = branchesTotal
|
||||
}
|
||||
|
||||
func repoAssignmentPreparePullRequests(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
repo := data.repo
|
||||
if repo.IsEmpty {
|
||||
return
|
||||
}
|
||||
// Pull request is allowed if this is a fork repository, and base repository accepts pull requests.
|
||||
if repo.BaseRepo != nil && repo.BaseRepo.AllowsPulls(ctx) {
|
||||
// TODO: this (and below) "BaseRepo" var is not clear and should be removed in the future
|
||||
@@ -727,7 +775,9 @@ func RepoAssignment(ctx *Context) {
|
||||
ctx.Data["BaseRepo"] = repo
|
||||
InitRepoPullRequestCtx(ctx, repo, repo)
|
||||
}
|
||||
}
|
||||
|
||||
func repoAssignmentPrepareRepoTransfer(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
if ctx.Repo.Repository.Status == repo_model.RepositoryPendingTransfer {
|
||||
repoTransfer, err := repo_model.GetPendingRepositoryTransfer(ctx, ctx.Repo.Repository)
|
||||
if err != nil {
|
||||
@@ -736,16 +786,17 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
|
||||
if err := repoTransfer.LoadAttributes(ctx); err != nil {
|
||||
ctx.ServerError("LoadRecipient", err)
|
||||
ctx.ServerError("LoadAttributes", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["RepoTransfer"] = repoTransfer
|
||||
if ctx.Doer != nil {
|
||||
ctx.Data["CanUserAcceptOrRejectTransfer"] = repoTransfer.CanUserAcceptOrRejectTransfer(ctx, ctx.Doer)
|
||||
}
|
||||
ctx.Data["CanUserAcceptOrRejectTransfer"] = ctx.Doer != nil && repoTransfer.CanUserAcceptOrRejectTransfer(ctx, ctx.Doer)
|
||||
}
|
||||
}
|
||||
|
||||
func repoAssignmentHandleGoGet(ctx *Context, data *repoAssignmentPrepareDataStruct) {
|
||||
repo := data.repo
|
||||
if ctx.FormString("go-get") == "1" {
|
||||
ctx.Data["GoGetImport"] = ComposeGoGetImport(ctx, repo.Owner.Name, repo.Name)
|
||||
fullURLPrefix := repo.HTMLURL() + "/src/branch/" + util.PathEscapeSegments(ctx.Repo.BranchName)
|
||||
@@ -754,6 +805,32 @@ func RepoAssignment(ctx *Context) {
|
||||
}
|
||||
}
|
||||
|
||||
// RepoAssignment returns a middleware to handle repository assignment
|
||||
func RepoAssignment(ctx *Context) {
|
||||
repoAssignmentPreCheck(ctx)
|
||||
|
||||
prepareData := repoAssignmentPrepareData(ctx)
|
||||
funcs := []func(ctx *Context, data *repoAssignmentPrepareDataStruct){
|
||||
repoAssignmentPrepareOwner,
|
||||
repoAssignmentAutoRedirectWiki,
|
||||
repoAssignmentPrepareRepo,
|
||||
repoAssignmentLegacy,
|
||||
repoAssignmentPrepareTemplateData,
|
||||
repoAssignmentAutoRedirectNotReady,
|
||||
repoAssignmentPrepareGitRepo,
|
||||
repoAssignmentPrepareRepoTransfer,
|
||||
repoAssignmentPrepareBranches,
|
||||
repoAssignmentPreparePullRequests,
|
||||
repoAssignmentHandleGoGet,
|
||||
}
|
||||
for _, f := range funcs {
|
||||
f(ctx, prepareData)
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const headRefName = "HEAD"
|
||||
|
||||
func getRefNameFromPath(repo *Repository, path string, isExist func(string) bool) string {
|
||||
@@ -912,12 +989,9 @@ func RepoRefByType(detectRefType git.RefType) func(*Context) {
|
||||
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refShortName)
|
||||
if err == nil {
|
||||
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
|
||||
} else if strings.Contains(err.Error(), "fatal: not a git repository") || strings.Contains(err.Error(), "object does not exist") {
|
||||
} else {
|
||||
// if the repository is broken, we can continue to the handler code, to show "Settings -> Delete Repository" for end users
|
||||
log.Error("GetBranchCommit: %v", err)
|
||||
} else {
|
||||
ctx.ServerError("GetBranchCommit", err)
|
||||
return
|
||||
}
|
||||
} else { // there is a path in request
|
||||
guessLegacyPath := refType == ""
|
||||
|
||||
Reference in New Issue
Block a user