2014-03-15 20:03:23 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
2017-09-12 09:48:13 +03:00
// Copyright 2017 The Gitea Authors. All rights reserved.
2014-03-15 20:03:23 +04:00
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
2016-03-11 19:56:52 +03:00
package context
2014-03-15 20:03:23 +04:00
import (
2021-05-06 02:30:25 +03:00
"context"
2014-03-20 08:12:33 +04:00
"fmt"
2021-09-22 08:38:34 +03:00
"io"
2021-12-15 09:59:57 +03:00
"net/http"
2019-01-31 00:04:19 +03:00
"net/url"
2015-10-31 19:04:04 +03:00
"path"
2014-03-17 12:47:42 +04:00
"strings"
2014-03-16 10:28:24 +04:00
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
2021-12-10 04:27:50 +03:00
"code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
2021-11-09 22:57:58 +03:00
unit_model "code.gitea.io/gitea/models/unit"
2021-11-24 12:49:20 +03:00
user_model "code.gitea.io/gitea/models/user"
2017-10-26 04:37:33 +03:00
"code.gitea.io/gitea/modules/cache"
2019-03-27 12:33:00 +03:00
"code.gitea.io/gitea/modules/git"
2022-01-27 11:30:51 +03:00
code_indexer "code.gitea.io/gitea/modules/indexer/code"
2017-10-30 05:04:25 +03:00
"code.gitea.io/gitea/modules/log"
2020-09-11 17:48:39 +03:00
"code.gitea.io/gitea/modules/markup/markdown"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/setting"
2020-09-11 17:48:39 +03:00
api "code.gitea.io/gitea/modules/structs"
2020-11-25 23:07:39 +03:00
"code.gitea.io/gitea/modules/util"
2021-12-10 11:14:24 +03:00
asymkey_service "code.gitea.io/gitea/services/asymkey"
2017-10-26 04:37:33 +03:00
2019-10-16 00:24:16 +03:00
"github.com/editorconfig/editorconfig-core-go/v2"
2019-08-23 19:40:30 +03:00
"github.com/unknwon/com"
2014-03-15 20:03:23 +04:00
)
2020-09-11 17:48:39 +03:00
// 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" ,
}
2021-07-08 14:38:13 +03:00
// PullRequest contains information to make a pull request
2016-03-14 00:37:44 +03:00
type PullRequest struct {
2021-12-10 04:27:50 +03:00
BaseRepo * repo_model . Repository
2021-11-16 21:18:25 +03:00
Allowed bool
SameRepo bool
HeadInfoSubURL string // [<user>:]<branch> url segment
2016-03-14 00:37:44 +03:00
}
2017-03-15 03:52:01 +03:00
// Repository contains information to operate a repository
2016-03-14 00:37:44 +03:00
type Repository struct {
2018-11-28 14:26:14 +03:00
models . Permission
2016-03-14 00:37:44 +03:00
IsWatching bool
IsViewBranch bool
IsViewTag bool
IsViewCommit bool
2021-12-10 04:27:50 +03:00
Repository * repo_model . Repository
2021-11-24 12:49:20 +03:00
Owner * user_model . User
2016-03-14 00:37:44 +03:00
Commit * git . Commit
Tag * git . Tag
GitRepo * git . Repository
2021-11-18 02:50:17 +03:00
RefName string
2016-03-14 00:37:44 +03:00
BranchName string
TagName string
2016-08-25 07:35:03 +03:00
TreePath string
2016-03-14 00:37:44 +03:00
CommitID string
RepoLink string
2021-12-10 04:27:50 +03:00
CloneLink repo_model . CloneLink
2016-03-14 00:37:44 +03:00
CommitsCount int64
2021-12-10 04:27:50 +03:00
Mirror * repo_model . Mirror
2016-03-14 00:37:44 +03:00
2016-08-30 12:08:38 +03:00
PullRequest * PullRequest
2016-03-14 00:37:44 +03:00
}
2016-08-30 12:08:38 +03:00
// CanEnableEditor returns true if repository is editable and user has proper access level.
func ( r * Repository ) CanEnableEditor ( ) bool {
2021-11-09 22:57:58 +03:00
return r . Permission . CanWrite ( unit_model . TypeCode ) && r . Repository . CanEnableEditor ( ) && r . IsViewBranch && ! r . Repository . IsArchived
2016-08-30 12:08:38 +03:00
}
2017-10-15 22:59:24 +03:00
// CanCreateBranch returns true if repository is editable and user has proper access level.
func ( r * Repository ) CanCreateBranch ( ) bool {
2021-11-09 22:57:58 +03:00
return r . Permission . CanWrite ( unit_model . TypeCode ) && r . Repository . CanCreateBranch ( )
2017-10-15 22:59:24 +03:00
}
2019-01-23 21:58:38 +03:00
// RepoMustNotBeArchived checks if a repo is archived
2021-01-26 18:36:53 +03:00
func RepoMustNotBeArchived ( ) func ( ctx * Context ) {
2019-01-23 21:58:38 +03:00
return func ( ctx * Context ) {
if ctx . Repo . Repository . IsArchived {
ctx . NotFound ( "IsArchived" , fmt . Errorf ( ctx . Tr ( "repo.archive.title" ) ) )
}
}
}
2020-01-15 11:32:57 +03:00
// CanCommitToBranchResults represents the results of CanCommitToBranch
type CanCommitToBranchResults struct {
CanCommitToBranch bool
EditorEnabled bool
UserCanPush bool
RequireSigned bool
WillSign bool
SigningKey string
WontSignReason string
}
2017-05-02 03:49:55 +03:00
// CanCommitToBranch returns true if repository is editable and user has proper access level
2018-08-08 06:17:11 +03:00
// and branch is not protected for push
2022-01-20 02:26:57 +03:00
func ( r * Repository ) CanCommitToBranch ( ctx context . Context , doer * user_model . User ) ( CanCommitToBranchResults , error ) {
2020-01-15 11:32:57 +03:00
protectedBranch , err := models . GetProtectedBranchBy ( r . Repository . ID , r . BranchName )
2017-05-02 03:49:55 +03:00
if err != nil {
2020-01-15 11:32:57 +03:00
return CanCommitToBranchResults { } , err
2017-05-02 03:49:55 +03:00
}
2020-01-15 11:32:57 +03:00
userCanPush := true
requireSigned := false
if protectedBranch != nil {
userCanPush = protectedBranch . CanUserPush ( doer . ID )
requireSigned = protectedBranch . RequireSignedCommits
}
2022-01-20 02:26:57 +03:00
sign , keyID , _ , err := asymkey_service . SignCRUDAction ( ctx , r . Repository . RepoPath ( ) , doer , r . Repository . RepoPath ( ) , git . BranchPrefix + r . BranchName )
2020-01-15 11:32:57 +03:00
canCommit := r . CanEnableEditor ( ) && userCanPush
if requireSigned {
canCommit = canCommit && sign
}
wontSignReason := ""
if err != nil {
2021-12-10 11:14:24 +03:00
if asymkey_service . IsErrWontSign ( err ) {
wontSignReason = string ( err . ( * asymkey_service . ErrWontSign ) . Reason )
2020-01-15 11:32:57 +03:00
err = nil
} else {
wontSignReason = "error"
}
}
return CanCommitToBranchResults {
CanCommitToBranch : canCommit ,
EditorEnabled : r . CanEnableEditor ( ) ,
UserCanPush : userCanPush ,
RequireSigned : requireSigned ,
WillSign : sign ,
SigningKey : keyID ,
WontSignReason : wontSignReason ,
} , err
2017-05-02 03:49:55 +03:00
}
2017-09-12 09:48:13 +03:00
// CanUseTimetracker returns whether or not a user can use the timetracker.
2021-11-24 12:49:20 +03:00
func ( r * Repository ) CanUseTimetracker ( issue * models . Issue , user * user_model . User ) bool {
2017-09-12 09:48:13 +03:00
// Checking for following:
// 1. Is timetracker enabled
// 2. Is the user a contributor, admin, poster or assignee and do the repository policies require this?
2018-05-09 19:29:04 +03:00
isAssigned , _ := models . IsUserAssignedToIssue ( issue , user )
2017-09-12 09:48:13 +03:00
return r . Repository . IsTimetrackerEnabled ( ) && ( ! r . Repository . AllowOnlyContributorsToTrackTime ( ) ||
2020-01-20 15:00:32 +03:00
r . Permission . CanWriteIssuesOrPulls ( issue . IsPull ) || issue . IsPoster ( user . ID ) || isAssigned )
2017-09-12 09:48:13 +03:00
}
2018-07-18 00:23:58 +03:00
// CanCreateIssueDependencies returns whether or not a user can create dependencies.
2021-11-24 12:49:20 +03:00
func ( r * Repository ) CanCreateIssueDependencies ( user * user_model . User , isPull bool ) bool {
2020-01-19 09:43:38 +03:00
return r . Repository . IsDependenciesEnabled ( ) && r . Permission . CanWriteIssuesOrPulls ( isPull )
2018-07-18 00:23:58 +03:00
}
2017-10-26 04:37:33 +03:00
// GetCommitsCount returns cached commit count for current view
func ( r * Repository ) GetCommitsCount ( ) ( int64 , error ) {
var contextName string
if r . IsViewBranch {
contextName = r . BranchName
} else if r . IsViewTag {
contextName = r . TagName
} else {
contextName = r . CommitID
}
return cache . GetInt64 ( r . Repository . GetCommitsCountCacheKey ( contextName , r . IsViewBranch || r . IsViewTag ) , func ( ) ( int64 , error ) {
return r . Commit . CommitsCount ( )
} )
}
2020-11-08 20:21:54 +03:00
// GetCommitGraphsCount returns cached commit count for current view
2022-01-20 02:26:57 +03:00
func ( r * Repository ) GetCommitGraphsCount ( ctx context . Context , hidePRRefs bool , branches , files [ ] string ) ( int64 , error ) {
2020-11-08 20:21:54 +03:00
cacheKey := fmt . Sprintf ( "commits-count-%d-graph-%t-%s-%s" , r . Repository . ID , hidePRRefs , branches , files )
return cache . GetInt64 ( cacheKey , func ( ) ( int64 , error ) {
if len ( branches ) == 0 {
2022-01-20 02:26:57 +03:00
return git . AllCommitsCount ( ctx , r . Repository . RepoPath ( ) , hidePRRefs , files ... )
2020-11-08 20:21:54 +03:00
}
2022-01-20 02:26:57 +03:00
return git . CommitsCountFiles ( ctx , r . Repository . RepoPath ( ) , branches , files )
2020-11-08 20:21:54 +03:00
} )
}
2017-10-30 05:04:25 +03:00
// BranchNameSubURL sub-URL for the BranchName field
func ( r * Repository ) BranchNameSubURL ( ) string {
switch {
case r . IsViewBranch :
2021-11-16 21:18:25 +03:00
return "branch/" + util . PathEscapeSegments ( r . BranchName )
2017-10-30 05:04:25 +03:00
case r . IsViewTag :
2021-11-18 02:50:17 +03:00
return "tag/" + util . PathEscapeSegments ( r . TagName )
2017-10-30 05:04:25 +03:00
case r . IsViewCommit :
2021-11-18 02:50:17 +03:00
return "commit/" + util . PathEscapeSegments ( r . CommitID )
2017-10-30 05:04:25 +03:00
}
2019-04-02 10:48:31 +03:00
log . Error ( "Unknown view type for repo: %v" , r )
2017-10-30 05:04:25 +03:00
return ""
}
2019-04-17 19:06:35 +03:00
// FileExists returns true if a file exists in the given repo branch
2021-12-20 07:41:31 +03:00
func ( r * Repository ) FileExists ( path , branch string ) ( bool , error ) {
2019-04-17 19:06:35 +03:00
if branch == "" {
branch = r . Repository . DefaultBranch
}
commit , err := r . GitRepo . GetBranchCommit ( branch )
if err != nil {
return false , err
}
if _ , err := commit . GetTreeEntryByPath ( path ) ; err != nil {
return false , err
}
return true , nil
}
2016-08-12 03:07:09 +03:00
// GetEditorconfig returns the .editorconfig definition if found in the
// HEAD of the default repo branch.
func ( r * Repository ) GetEditorconfig ( ) ( * editorconfig . Editorconfig , error ) {
2019-10-13 16:23:14 +03:00
if r . GitRepo == nil {
return nil , nil
}
2016-08-12 03:07:09 +03:00
commit , err := r . GitRepo . GetBranchCommit ( r . Repository . DefaultBranch )
if err != nil {
return nil , err
}
treeEntry , err := commit . GetTreeEntryByPath ( ".editorconfig" )
if err != nil {
return nil , err
}
2017-11-29 04:50:39 +03:00
if treeEntry . Blob ( ) . Size ( ) >= setting . UI . MaxDisplayFileSize {
return nil , git . ErrNotExist { ID : "" , RelPath : ".editorconfig" }
}
2019-04-19 15:17:27 +03:00
reader , err := treeEntry . Blob ( ) . DataAsync ( )
2016-08-12 03:07:09 +03:00
if err != nil {
return nil , err
}
2019-04-19 15:17:27 +03:00
defer reader . Close ( )
2020-10-16 08:06:27 +03:00
return editorconfig . Parse ( reader )
2016-08-12 03:07:09 +03:00
}
2016-11-25 09:51:01 +03:00
// RetrieveBaseRepo retrieves base repository
2021-12-10 04:27:50 +03:00
func RetrieveBaseRepo ( ctx * Context , repo * repo_model . Repository ) {
2015-09-01 18:43:53 +03:00
// Non-fork repository will not return error in this method.
if err := repo . GetBaseRepo ( ) ; err != nil {
2021-12-10 04:27:50 +03:00
if repo_model . IsErrRepoNotExist ( err ) {
2015-09-01 18:43:53 +03:00
repo . IsFork = false
repo . ForkID = 0
return
}
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetBaseRepo" , err )
2015-09-01 18:43:53 +03:00
return
2021-12-10 04:27:50 +03:00
} else if err = repo . BaseRepo . GetOwner ( db . DefaultContext ) ; err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "BaseRepo.GetOwner" , err )
2015-09-01 18:43:53 +03:00
return
}
}
2019-11-11 18:15:29 +03:00
// RetrieveTemplateRepo retrieves template repository used to generate this repository
2021-12-10 04:27:50 +03:00
func RetrieveTemplateRepo ( ctx * Context , repo * repo_model . Repository ) {
2019-11-11 18:15:29 +03:00
// Non-generated repository will not return error in this method.
2021-12-10 04:27:50 +03:00
templateRepo , err := repo_model . GetTemplateRepo ( repo )
if err != nil {
if repo_model . IsErrRepoNotExist ( err ) {
2019-11-11 18:15:29 +03:00
repo . TemplateID = 0
return
}
ctx . ServerError ( "GetTemplateRepo" , err )
return
2021-12-10 04:27:50 +03:00
} else if err = templateRepo . GetOwner ( db . DefaultContext ) ; err != nil {
2019-11-11 18:15:29 +03:00
ctx . ServerError ( "TemplateRepo.GetOwner" , err )
return
}
2021-12-10 04:27:50 +03:00
perm , err := models . GetUserRepoPermission ( templateRepo , ctx . User )
2019-11-20 22:44:35 +03:00
if err != nil {
ctx . ServerError ( "GetUserRepoPermission" , err )
return
}
2021-11-09 22:57:58 +03:00
if ! perm . CanRead ( unit_model . TypeCode ) {
2019-11-11 18:15:29 +03:00
repo . TemplateID = 0
}
}
2017-09-23 16:24:24 +03:00
// ComposeGoGetImport returns go-get-import meta content.
func ComposeGoGetImport ( owner , repo string ) string {
2019-05-28 00:08:38 +03:00
/// setting.AppUrl is guaranteed to be parse as url
appURL , _ := url . Parse ( setting . AppURL )
return path . Join ( appURL . Host , setting . AppSubURL , url . PathEscape ( owner ) , url . PathEscape ( repo ) )
2016-08-08 00:29:16 +03:00
}
2017-09-23 16:24:24 +03:00
// EarlyResponseForGoGetMeta responses appropriate go-get meta with status 200
2016-08-08 00:29:16 +03:00
// if user does not have actual access to the requested repository,
// or the owner or repository does not exist at all.
// This is particular a workaround for "go get" command which does not respect
// .netrc file.
2017-09-23 16:24:24 +03:00
func EarlyResponseForGoGetMeta ( ctx * Context ) {
username := ctx . Params ( ":username" )
2019-09-06 16:44:59 +03:00
reponame := strings . TrimSuffix ( ctx . Params ( ":reponame" ) , ".git" )
if username == "" || reponame == "" {
2021-12-15 09:59:57 +03:00
ctx . PlainText ( http . StatusBadRequest , "invalid repository path" )
2019-09-06 16:44:59 +03:00
return
}
2021-12-15 09:59:57 +03:00
ctx . PlainText ( http . StatusOK , com . Expand ( ` <meta name="go-import" content=" { GoGetImport} git { CloneLink}"> ` ,
2016-08-08 00:29:16 +03:00
map [ string ] string {
2019-09-06 16:44:59 +03:00
"GoGetImport" : ComposeGoGetImport ( username , reponame ) ,
2021-12-10 04:27:50 +03:00
"CloneLink" : repo_model . ComposeHTTPSCloneURL ( username , reponame ) ,
2021-12-15 09:59:57 +03:00
} ) )
2016-08-08 00:29:16 +03:00
}
2017-02-05 17:35:03 +03:00
// RedirectToRepo redirect to a differently-named repository
func RedirectToRepo ( ctx * Context , redirectRepoID int64 ) {
ownerName := ctx . Params ( ":username" )
previousRepoName := ctx . Params ( ":reponame" )
2021-12-10 04:27:50 +03:00
repo , err := repo_model . GetRepositoryByID ( redirectRepoID )
2017-02-05 17:35:03 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetRepositoryByID" , err )
2017-02-05 17:35:03 +03:00
return
}
redirectPath := strings . Replace (
2021-11-16 21:18:25 +03:00
ctx . Req . URL . EscapedPath ( ) ,
url . PathEscape ( ownerName ) + "/" + url . PathEscape ( previousRepoName ) ,
url . PathEscape ( repo . OwnerName ) + "/" + url . PathEscape ( repo . Name ) ,
2017-02-05 17:35:03 +03:00
1 ,
)
2019-04-25 08:51:40 +03:00
if ctx . Req . URL . RawQuery != "" {
redirectPath += "?" + ctx . Req . URL . RawQuery
}
2019-10-22 21:50:24 +03:00
ctx . Redirect ( path . Join ( setting . AppSubURL , redirectPath ) )
2017-02-05 17:35:03 +03:00
}
2017-09-19 14:44:49 +03:00
2021-12-10 04:27:50 +03:00
func repoAssignment ( ctx * Context , repo * repo_model . Repository ) {
2018-11-28 14:26:14 +03:00
var err error
2021-12-10 04:27:50 +03:00
if err = repo . GetOwner ( db . DefaultContext ) ; err != nil {
2019-03-05 23:15:24 +03:00
ctx . ServerError ( "GetOwner" , err )
return
}
2018-11-28 14:26:14 +03:00
ctx . Repo . Permission , err = models . GetUserRepoPermission ( repo , ctx . User )
if err != nil {
ctx . ServerError ( "GetUserRepoPermission" , err )
return
2017-10-05 10:32:25 +03:00
}
// Check access.
2021-10-28 05:54:40 +03:00
if ! ctx . Repo . Permission . HasAccess ( ) {
2021-08-11 03:31:13 +03:00
if ctx . FormString ( "go-get" ) == "1" {
2017-10-05 10:32:25 +03:00
EarlyResponseForGoGetMeta ( ctx )
return
}
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "no access right" , nil )
2017-10-05 10:32:25 +03:00
return
}
ctx . Data [ "HasAccess" ] = true
2018-11-28 14:26:14 +03:00
ctx . Data [ "Permission" ] = & ctx . Repo . Permission
2017-10-05 10:32:25 +03:00
if repo . IsMirror {
var err error
2022-01-08 05:03:51 +03:00
ctx . Repo . Mirror , err = repo_model . GetMirrorByRepoID ( repo . ID )
2017-10-05 10:32:25 +03:00
if err != nil {
2021-06-14 20:20:43 +03:00
ctx . ServerError ( "GetMirrorByRepoID" , err )
2017-10-05 10:32:25 +03:00
return
}
2022-01-08 05:03:51 +03:00
ctx . Data [ "MirrorEnablePrune" ] = ctx . Repo . Mirror . EnablePrune
ctx . Data [ "MirrorInterval" ] = ctx . Repo . Mirror . Interval
ctx . Data [ "Mirror" ] = ctx . Repo . Mirror
2017-10-05 10:32:25 +03:00
}
2021-12-10 04:27:50 +03:00
pushMirrors , err := repo_model . GetPushMirrorsByRepoID ( repo . ID )
if err != nil {
ctx . ServerError ( "GetPushMirrorsByRepoID" , err )
2021-06-14 20:20:43 +03:00
return
}
2017-10-05 10:32:25 +03:00
ctx . Repo . Repository = repo
2021-12-10 04:27:50 +03:00
ctx . Data [ "PushMirrors" ] = pushMirrors
2017-10-05 10:32:25 +03:00
ctx . Data [ "RepoName" ] = ctx . Repo . Repository . Name
2019-01-18 03:01:04 +03:00
ctx . Data [ "IsEmptyRepo" ] = ctx . Repo . Repository . IsEmpty
2017-10-05 10:32:25 +03:00
}
2021-01-29 18:35:30 +03:00
// RepoIDAssignment returns a handler which assigns the repo to the context.
2021-01-26 18:36:53 +03:00
func RepoIDAssignment ( ) func ( ctx * Context ) {
2017-09-18 17:52:20 +03:00
return func ( ctx * Context ) {
repoID := ctx . ParamsInt64 ( ":repoid" )
// Get repository.
2021-12-10 04:27:50 +03:00
repo , err := repo_model . GetRepositoryByID ( repoID )
2017-09-18 17:52:20 +03:00
if err != nil {
2021-12-10 04:27:50 +03:00
if repo_model . IsErrRepoNotExist ( err ) {
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "GetRepositoryByID" , nil )
2017-09-18 17:52:20 +03:00
} else {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetRepositoryByID" , err )
2017-09-18 17:52:20 +03:00
}
return
}
2017-10-05 10:32:25 +03:00
repoAssignment ( ctx , repo )
2017-09-18 17:52:20 +03:00
}
}
2017-02-05 17:35:03 +03:00
2021-01-29 18:35:30 +03:00
// RepoAssignment returns a middleware to handle repository assignment
2021-05-06 02:30:25 +03:00
func RepoAssignment ( ctx * Context ) ( cancel context . CancelFunc ) {
2021-04-10 03:26:08 +03:00
var (
2021-11-24 12:49:20 +03:00
owner * user_model . User
2021-04-10 03:26:08 +03:00
err error
)
userName := ctx . Params ( ":username" )
repoName := ctx . Params ( ":reponame" )
repoName = strings . TrimSuffix ( repoName , ".git" )
2022-03-13 19:40:47 +03:00
repoName = strings . TrimSuffix ( repoName , ".rss" )
repoName = strings . TrimSuffix ( repoName , ".atom" )
2021-04-10 03:26:08 +03:00
// Check if the user is the same as the repository owner
if ctx . IsSigned && ctx . User . LowerName == strings . ToLower ( userName ) {
owner = ctx . User
} else {
2021-11-24 12:49:20 +03:00
owner , err = user_model . GetUserByName ( userName )
2021-04-10 03:26:08 +03:00
if err != nil {
2021-11-24 12:49:20 +03:00
if user_model . IsErrUserNotExist ( err ) {
2021-08-11 03:31:13 +03:00
if ctx . FormString ( "go-get" ) == "1" {
2021-04-10 03:26:08 +03:00
EarlyResponseForGoGetMeta ( ctx )
2021-01-26 18:36:53 +03:00
return
}
2021-04-10 03:26:08 +03:00
ctx . NotFound ( "GetUserByName" , nil )
} else {
ctx . ServerError ( "GetUserByName" , err )
2021-01-26 18:36:53 +03:00
}
2021-04-10 03:26:08 +03:00
return
}
}
ctx . Repo . Owner = owner
ctx . Data [ "Username" ] = ctx . Repo . Owner . Name
2014-03-30 06:09:59 +04:00
2021-04-10 03:26:08 +03:00
// Get repository.
2021-12-10 04:27:50 +03:00
repo , err := repo_model . GetRepositoryByName ( owner . ID , repoName )
2021-04-10 03:26:08 +03:00
if err != nil {
2021-12-10 04:27:50 +03:00
if repo_model . IsErrRepoNotExist ( err ) {
2021-12-12 18:48:20 +03:00
redirectRepoID , err := repo_model . LookupRedirect ( owner . ID , repoName )
2021-04-10 03:26:08 +03:00
if err == nil {
RedirectToRepo ( ctx , redirectRepoID )
2021-12-12 18:48:20 +03:00
} else if repo_model . IsErrRedirectNotExist ( err ) {
2021-08-11 03:31:13 +03:00
if ctx . FormString ( "go-get" ) == "1" {
2021-04-10 03:26:08 +03:00
EarlyResponseForGoGetMeta ( ctx )
return
2014-03-15 20:03:23 +04:00
}
2021-04-10 03:26:08 +03:00
ctx . NotFound ( "GetRepositoryByName" , nil )
} else {
ctx . ServerError ( "LookupRepoRedirect" , err )
2014-03-15 20:03:23 +04:00
}
2021-04-10 03:26:08 +03:00
} else {
ctx . ServerError ( "GetRepositoryByName" , err )
}
return
}
repo . Owner = owner
2014-03-15 20:03:23 +04:00
2021-04-10 03:26:08 +03:00
repoAssignment ( ctx , repo )
if ctx . Written ( ) {
return
}
2014-04-12 05:47:39 +04:00
2021-04-10 03:26:08 +03:00
ctx . Repo . RepoLink = repo . Link ( )
ctx . Data [ "RepoLink" ] = ctx . Repo . RepoLink
ctx . Data [ "RepoRelPath" ] = ctx . Repo . Owner . Name + "/" + ctx . Repo . Repository . Name
2014-03-30 09:30:17 +04:00
2021-11-09 22:57:58 +03:00
unit , err := ctx . Repo . Repository . GetUnit ( unit_model . TypeExternalTracker )
2021-04-10 03:26:08 +03:00
if err == nil {
ctx . Data [ "RepoExternalIssuesLink" ] = unit . ExternalTrackerConfig ( ) . ExternalTrackerURL
}
2014-03-30 07:38:41 +04:00
2021-04-10 03:26:08 +03:00
ctx . Data [ "NumTags" ] , err = models . GetReleaseCountByRepoID ( ctx . Repo . Repository . ID , models . FindReleasesOptions {
IncludeTags : true ,
} )
if err != nil {
ctx . ServerError ( "GetReleaseCountByRepoID" , err )
return
}
ctx . Data [ "NumReleases" ] , err = models . GetReleaseCountByRepoID ( ctx . Repo . Repository . ID , models . FindReleasesOptions { } )
if err != nil {
ctx . ServerError ( "GetReleaseCountByRepoID" , err )
return
}
2019-02-20 02:09:47 +03:00
2021-04-10 03:26:08 +03:00
ctx . Data [ "Title" ] = owner . Name + "/" + repo . Name
ctx . Data [ "Repository" ] = repo
ctx . Data [ "Owner" ] = ctx . Repo . Repository . Owner
ctx . Data [ "IsRepositoryOwner" ] = ctx . Repo . IsOwner ( )
ctx . Data [ "IsRepositoryAdmin" ] = ctx . Repo . IsAdmin ( )
ctx . Data [ "RepoOwnerIsOrganization" ] = repo . Owner . IsOrganization ( )
2021-11-09 22:57:58 +03:00
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 )
2014-04-14 05:00:12 +04:00
2021-12-13 04:59:09 +03:00
canSignedUserFork , err := models . CanUserForkRepo ( ctx . User , ctx . Repo . Repository )
if err != nil {
ctx . ServerError ( "CanUserForkRepo" , err )
return
}
ctx . Data [ "CanSignedUserFork" ] = canSignedUserFork
userAndOrgForks , err := models . GetForksByUserAndOrgs ( ctx . User , ctx . Repo . Repository )
if err != nil {
ctx . ServerError ( "GetForksByUserAndOrgs" , err )
2021-04-10 03:26:08 +03:00
return
}
2021-12-13 04:59:09 +03:00
ctx . Data [ "UserAndOrgForks" ] = userAndOrgForks
// canSignedUserFork is true if the current user doesn't have a fork of this repo yet or
// if he owns an org that doesn't have a fork of this repo yet
// If multiple forks are available or if the user can fork to another account, but there is already a fork: open selection dialog
ctx . Data [ "ShowForkModal" ] = len ( userAndOrgForks ) > 1 || ( canSignedUserFork && len ( userAndOrgForks ) > 0 )
2017-10-15 18:06:07 +03:00
2021-04-10 03:26:08 +03:00
ctx . Data [ "DisableSSH" ] = setting . SSH . Disabled
ctx . Data [ "ExposeAnonSSH" ] = setting . SSH . ExposeAnonymous
ctx . Data [ "DisableHTTP" ] = setting . Repository . DisableHTTPGit
ctx . Data [ "RepoSearchEnabled" ] = setting . Indexer . RepoIndexerEnabled
2022-01-27 11:30:51 +03:00
if setting . Indexer . RepoIndexerEnabled {
ctx . Data [ "CodeIndexerUnavailable" ] = ! code_indexer . IsAvailable ( )
}
2021-04-10 03:26:08 +03:00
ctx . Data [ "CloneLink" ] = repo . CloneLink ( )
ctx . Data [ "WikiCloneLink" ] = repo . WikiCloneLink ( )
2014-03-30 07:38:41 +04:00
2021-04-10 03:26:08 +03:00
if ctx . IsSigned {
2021-12-12 18:48:20 +03:00
ctx . Data [ "IsWatchingRepo" ] = repo_model . IsWatching ( ctx . User . ID , repo . ID )
ctx . Data [ "IsStaringRepo" ] = repo_model . IsStaring ( ctx . User . ID , repo . ID )
2021-04-10 03:26:08 +03:00
}
2015-10-03 02:58:36 +03:00
2021-04-10 03:26:08 +03:00
if repo . IsFork {
RetrieveBaseRepo ( ctx , repo )
if ctx . Written ( ) {
return
}
}
2019-04-15 23:48:35 +03:00
2021-04-10 03:26:08 +03:00
if repo . IsGenerated ( ) {
RetrieveTemplateRepo ( ctx , repo )
if ctx . Written ( ) {
return
}
}
2014-03-15 20:03:23 +04:00
2021-11-23 01:32:16 +03:00
isHomeOrSettings := ctx . Link == ctx . Repo . RepoLink || ctx . Link == ctx . Repo . RepoLink + "/settings" || strings . HasPrefix ( ctx . Link , ctx . Repo . RepoLink + "/settings/" )
2021-04-10 03:26:08 +03:00
// Disable everything when the repo is being created
2021-11-23 01:32:16 +03:00
if ctx . Repo . Repository . IsBeingCreated ( ) || ctx . Repo . Repository . IsBroken ( ) {
2021-04-10 03:26:08 +03:00
ctx . Data [ "BranchName" ] = ctx . Repo . Repository . DefaultBranch
2021-11-23 01:32:16 +03:00
if ! isHomeOrSettings {
ctx . Redirect ( ctx . Repo . RepoLink )
}
2021-04-10 03:26:08 +03:00
return
}
2019-11-13 10:01:19 +03:00
2021-12-10 04:27:50 +03:00
gitRepo , err := git . OpenRepositoryCtx ( ctx , repo_model . RepoPath ( userName , repoName ) )
2021-04-10 03:26:08 +03:00
if err != nil {
2021-11-23 01:32:16 +03:00
if strings . Contains ( err . Error ( ) , "repository does not exist" ) || strings . Contains ( err . Error ( ) , "no such file or directory" ) {
log . Error ( "Repository %-v has a broken repository on the file system: %s Error: %v" , ctx . Repo . Repository , ctx . Repo . Repository . RepoPath ( ) , err )
2021-12-10 04:27:50 +03:00
ctx . Repo . Repository . Status = repo_model . RepositoryBroken
2021-11-23 01:32:16 +03:00
ctx . Repo . Repository . IsEmpty = true
ctx . Data [ "BranchName" ] = ctx . Repo . Repository . DefaultBranch
// Only allow access to base of repo or settings
if ! isHomeOrSettings {
ctx . Redirect ( ctx . Repo . RepoLink )
}
return
}
2021-12-10 04:27:50 +03:00
ctx . ServerError ( "RepoAssignment Invalid repo " + repo_model . RepoPath ( userName , repoName ) , err )
2021-04-10 03:26:08 +03:00
return
}
ctx . Repo . GitRepo = gitRepo
2019-10-16 16:08:01 +03:00
2021-04-10 03:26:08 +03:00
// We opened it, we should close it
2021-05-06 02:30:25 +03:00
cancel = func ( ) {
2021-04-10 03:26:08 +03:00
// If it's been set to nil then assume someone else has closed it.
if ctx . Repo . GitRepo != nil {
ctx . Repo . GitRepo . Close ( )
}
2021-05-06 02:30:25 +03:00
}
2019-10-13 16:23:14 +03:00
2021-04-10 03:26:08 +03:00
// Stop at this point when the repo is empty.
if ctx . Repo . Repository . IsEmpty {
ctx . Data [ "BranchName" ] = ctx . Repo . Repository . DefaultBranch
return
}
2016-03-07 07:57:46 +03:00
2021-09-10 20:30:37 +03:00
tags , err := ctx . Repo . GitRepo . GetTags ( 0 , 0 )
2021-04-10 03:26:08 +03:00
if err != nil {
2021-11-23 01:32:16 +03:00
if strings . Contains ( err . Error ( ) , "fatal: not a git repository " ) {
log . Error ( "Repository %-v has a broken repository on the file system: %s Error: %v" , ctx . Repo . Repository , ctx . Repo . Repository . RepoPath ( ) , err )
2021-12-10 04:27:50 +03:00
ctx . Repo . Repository . Status = repo_model . RepositoryBroken
2021-11-23 01:32:16 +03:00
ctx . Repo . Repository . IsEmpty = true
ctx . Data [ "BranchName" ] = ctx . Repo . Repository . DefaultBranch
// Only allow access to base of repo or settings
if ! isHomeOrSettings {
ctx . Redirect ( ctx . Repo . RepoLink )
}
return
}
2021-04-10 03:26:08 +03:00
ctx . ServerError ( "GetTags" , err )
return
}
ctx . Data [ "Tags" ] = tags
2021-01-26 18:36:53 +03:00
2021-12-08 22:08:16 +03:00
brs , _ , err := ctx . Repo . GitRepo . GetBranchNames ( 0 , 0 )
2021-04-10 03:26:08 +03:00
if err != nil {
ctx . ServerError ( "GetBranches" , err )
return
}
ctx . Data [ "Branches" ] = brs
ctx . Data [ "BranchesCount" ] = len ( brs )
2021-03-01 03:47:30 +03:00
2021-04-10 03:26:08 +03:00
// If not branch selected, try default one.
// If default branch doesn't exists, fall back to some other branch.
if len ( ctx . Repo . BranchName ) == 0 {
if len ( ctx . Repo . Repository . DefaultBranch ) > 0 && gitRepo . IsBranchExist ( ctx . Repo . Repository . DefaultBranch ) {
ctx . Repo . BranchName = ctx . Repo . Repository . DefaultBranch
} else if len ( brs ) > 0 {
ctx . Repo . BranchName = brs [ 0 ]
}
2021-11-18 02:50:17 +03:00
ctx . Repo . RefName = ctx . Repo . BranchName
2021-04-10 03:26:08 +03:00
}
ctx . Data [ "BranchName" ] = ctx . Repo . BranchName
// People who have push access or have forked repository can propose a new pull request.
2021-11-22 18:21:55 +03:00
canPush := ctx . Repo . CanWrite ( unit_model . TypeCode ) ||
2021-12-12 18:48:20 +03:00
( ctx . IsSigned && repo_model . HasForkedRepo ( ctx . User . ID , ctx . Repo . Repository . ID ) )
2021-04-10 03:26:08 +03:00
canCompare := false
// Pull request is allowed if this is a fork repository
// and base repository accepts pull requests.
if repo . BaseRepo != nil && repo . BaseRepo . AllowsPulls ( ) {
canCompare = true
ctx . Data [ "BaseRepo" ] = repo . BaseRepo
ctx . Repo . PullRequest . BaseRepo = repo . BaseRepo
ctx . Repo . PullRequest . Allowed = canPush
2021-11-16 21:18:25 +03:00
ctx . Repo . PullRequest . HeadInfoSubURL = url . PathEscape ( ctx . Repo . Owner . Name ) + ":" + util . PathEscapeSegments ( ctx . Repo . BranchName )
2021-04-10 03:26:08 +03:00
} else if repo . AllowsPulls ( ) {
// Or, this is repository accepts pull requests between branches.
canCompare = true
ctx . Data [ "BaseRepo" ] = repo
ctx . Repo . PullRequest . BaseRepo = repo
ctx . Repo . PullRequest . Allowed = canPush
ctx . Repo . PullRequest . SameRepo = true
2021-11-16 21:18:25 +03:00
ctx . Repo . PullRequest . HeadInfoSubURL = util . PathEscapeSegments ( ctx . Repo . BranchName )
2021-04-10 03:26:08 +03:00
}
ctx . Data [ "CanCompareOrPull" ] = canCompare
ctx . Data [ "PullRequestCtx" ] = ctx . Repo . PullRequest
2021-12-10 04:27:50 +03:00
if ctx . Repo . Repository . Status == repo_model . RepositoryPendingTransfer {
2021-04-10 03:26:08 +03:00
repoTransfer , err := models . GetPendingRepositoryTransfer ( ctx . Repo . Repository )
if err != nil {
ctx . ServerError ( "GetPendingRepositoryTransfer" , err )
return
}
2021-03-01 03:47:30 +03:00
2021-04-10 03:26:08 +03:00
if err := repoTransfer . LoadAttributes ( ) ; err != nil {
ctx . ServerError ( "LoadRecipient" , err )
return
}
ctx . Data [ "RepoTransfer" ] = repoTransfer
if ctx . User != nil {
ctx . Data [ "CanUserAcceptTransfer" ] = repoTransfer . CanUserAcceptTransfer ( ctx . User )
}
}
2021-08-11 03:31:13 +03:00
if ctx . FormString ( "go-get" ) == "1" {
2021-04-10 03:26:08 +03:00
ctx . Data [ "GoGetImport" ] = ComposeGoGetImport ( owner . Name , repo . Name )
2021-11-16 21:18:25 +03:00
prefix := repo . HTMLURL ( ) + "/src/branch/" + util . PathEscapeSegments ( ctx . Repo . BranchName )
2021-04-10 03:26:08 +03:00
ctx . Data [ "GoDocDirectory" ] = prefix + "{/dir}"
ctx . Data [ "GoDocFile" ] = prefix + "{/dir}/{file}#L{line}"
2014-03-15 20:03:23 +04:00
}
2021-05-06 02:30:25 +03:00
return
2014-03-15 20:03:23 +04:00
}
2014-05-06 03:58:13 +04:00
2017-10-30 05:04:25 +03:00
// RepoRefType type of repo reference
type RepoRefType int
const (
// RepoRefLegacy unknown type, make educated guess and redirect.
// for backward compatibility with previous URL scheme
RepoRefLegacy RepoRefType = iota
2017-11-04 02:23:59 +03:00
// RepoRefAny is for usage where educated guess is needed
// but redirect can not be made
RepoRefAny
2017-10-30 05:04:25 +03:00
// RepoRefBranch branch
RepoRefBranch
// RepoRefTag tag
RepoRefTag
// RepoRefCommit commit
RepoRefCommit
2018-11-18 21:45:40 +03:00
// RepoRefBlob blob
RepoRefBlob
2017-10-30 05:04:25 +03:00
)
// RepoRef handles repository reference names when the ref name is not
// explicitly given
2021-05-06 02:30:25 +03:00
func RepoRef ( ) func ( * Context ) context . CancelFunc {
2017-10-30 05:04:25 +03:00
// since no ref name is explicitly specified, ok to just use branch
return RepoRefByType ( RepoRefBranch )
}
2019-11-11 10:37:28 +03:00
// RefTypeIncludesBranches returns true if ref type can be a branch
func ( rt RepoRefType ) RefTypeIncludesBranches ( ) bool {
if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefBranch {
return true
}
return false
}
// RefTypeIncludesTags returns true if ref type can be a tag
func ( rt RepoRefType ) RefTypeIncludesTags ( ) bool {
if rt == RepoRefLegacy || rt == RepoRefAny || rt == RepoRefTag {
return true
}
return false
}
2017-10-30 05:04:25 +03:00
func getRefNameFromPath ( ctx * Context , path string , isExist func ( string ) bool ) string {
refName := ""
parts := strings . Split ( path , "/" )
for i , part := range parts {
refName = strings . TrimPrefix ( refName + "/" + part , "/" )
if isExist ( refName ) {
ctx . Repo . TreePath = strings . Join ( parts [ i + 1 : ] , "/" )
return refName
}
}
return ""
}
func getRefName ( ctx * Context , pathType RepoRefType ) string {
path := ctx . Params ( "*" )
switch pathType {
2017-11-04 02:23:59 +03:00
case RepoRefLegacy , RepoRefAny :
2017-10-30 05:04:25 +03:00
if refName := getRefName ( ctx , RepoRefBranch ) ; len ( refName ) > 0 {
return refName
}
if refName := getRefName ( ctx , RepoRefTag ) ; len ( refName ) > 0 {
return refName
}
2020-11-25 23:07:39 +03:00
// For legacy and API support only full commit sha
parts := strings . Split ( path , "/" )
if len ( parts ) > 0 && len ( parts [ 0 ] ) == 40 {
ctx . Repo . TreePath = strings . Join ( parts [ 1 : ] , "/" )
return parts [ 0 ]
2017-11-04 20:26:38 +03:00
}
2018-11-18 21:45:40 +03:00
if refName := getRefName ( ctx , RepoRefBlob ) ; len ( refName ) > 0 {
return refName
}
2017-11-04 20:26:38 +03:00
ctx . Repo . TreePath = path
return ctx . Repo . Repository . DefaultBranch
2017-10-30 05:04:25 +03:00
case RepoRefBranch :
2021-10-08 20:03:04 +03:00
ref := getRefNameFromPath ( ctx , path , ctx . Repo . GitRepo . IsBranchExist )
if len ( ref ) == 0 {
// maybe it's a renamed branch
return getRefNameFromPath ( ctx , path , func ( s string ) bool {
b , exist , err := models . FindRenamedBranch ( ctx . Repo . Repository . ID , s )
if err != nil {
log . Error ( "FindRenamedBranch" , err )
return false
}
if ! exist {
return false
}
ctx . Data [ "IsRenamedBranch" ] = true
ctx . Data [ "RenamedBranchName" ] = b . To
return true
} )
}
return ref
2017-10-30 05:04:25 +03:00
case RepoRefTag :
return getRefNameFromPath ( ctx , path , ctx . Repo . GitRepo . IsTagExist )
case RepoRefCommit :
parts := strings . Split ( path , "/" )
2020-11-25 23:07:39 +03:00
if len ( parts ) > 0 && len ( parts [ 0 ] ) >= 7 && len ( parts [ 0 ] ) <= 40 {
2017-10-30 05:04:25 +03:00
ctx . Repo . TreePath = strings . Join ( parts [ 1 : ] , "/" )
return parts [ 0 ]
}
2018-11-18 21:45:40 +03:00
case RepoRefBlob :
_ , err := ctx . Repo . GitRepo . GetBlob ( path )
if err != nil {
return ""
}
return path
2017-10-30 05:04:25 +03:00
default :
2019-04-02 10:48:31 +03:00
log . Error ( "Unrecognized path type: %v" , path )
2017-10-30 05:04:25 +03:00
}
return ""
}
// RepoRefByType handles repository reference name for a specific type
// of repository reference
2021-05-06 06:12:50 +03:00
func RepoRefByType ( refType RepoRefType , ignoreNotExistErr ... bool ) func ( * Context ) context . CancelFunc {
2021-05-06 02:30:25 +03:00
return func ( ctx * Context ) ( cancel context . CancelFunc ) {
2021-04-10 03:26:08 +03:00
// Empty repository does not have reference information.
if ctx . Repo . Repository . IsEmpty {
return
}
var (
refName string
err error
)
if ctx . Repo . GitRepo == nil {
2021-12-10 04:27:50 +03:00
repoPath := repo_model . RepoPath ( ctx . Repo . Owner . Name , ctx . Repo . Repository . Name )
2021-11-30 23:06:32 +03:00
ctx . Repo . GitRepo , err = git . OpenRepositoryCtx ( ctx , repoPath )
2021-04-10 03:26:08 +03:00
if err != nil {
ctx . ServerError ( "RepoRef Invalid repo " + repoPath , err )
2015-12-05 01:20:23 +03:00
return
}
2021-04-10 03:26:08 +03:00
// We opened it, we should close it
2021-05-06 02:30:25 +03:00
cancel = func ( ) {
2021-04-10 03:26:08 +03:00
// If it's been set to nil then assume someone else has closed it.
if ctx . Repo . GitRepo != nil {
ctx . Repo . GitRepo . Close ( )
}
2021-05-06 02:30:25 +03:00
}
2021-04-10 03:26:08 +03:00
}
2015-12-05 01:20:23 +03:00
2021-04-10 03:26:08 +03:00
// Get default branch.
if len ( ctx . Params ( "*" ) ) == 0 {
refName = ctx . Repo . Repository . DefaultBranch
if ! ctx . Repo . GitRepo . IsBranchExist ( refName ) {
2021-12-08 22:08:16 +03:00
brs , _ , err := ctx . Repo . GitRepo . GetBranchNames ( 0 , 0 )
2015-12-05 01:20:23 +03:00
if err != nil {
2021-04-10 03:26:08 +03:00
ctx . ServerError ( "GetBranches" , err )
return
} else if len ( brs ) == 0 {
err = fmt . Errorf ( "No branches in non-empty repository %s" ,
ctx . Repo . GitRepo . Path )
ctx . ServerError ( "GetBranches" , err )
2017-07-04 04:29:57 +03:00
return
2015-12-05 01:20:23 +03:00
}
2021-04-10 03:26:08 +03:00
refName = brs [ 0 ]
}
2021-11-18 02:50:17 +03:00
ctx . Repo . RefName = refName
ctx . Repo . BranchName = refName
2021-04-10 03:26:08 +03:00
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetBranchCommit ( refName )
if err != nil {
ctx . ServerError ( "GetBranchCommit" , err )
return
2015-12-05 01:20:23 +03:00
}
2021-04-10 03:26:08 +03:00
ctx . Repo . CommitID = ctx . Repo . Commit . ID . String ( )
ctx . Repo . IsViewBranch = true
} else {
refName = getRefName ( ctx , refType )
2021-11-18 02:50:17 +03:00
ctx . Repo . RefName = refName
2021-10-08 20:03:04 +03:00
isRenamedBranch , has := ctx . Data [ "IsRenamedBranch" ] . ( bool )
if isRenamedBranch && has {
renamedBranchName := ctx . Data [ "RenamedBranchName" ] . ( string )
ctx . Flash . Info ( ctx . Tr ( "repo.branch.renamed" , refName , renamedBranchName ) )
2021-11-16 21:18:25 +03:00
link := setting . AppSubURL + strings . Replace ( ctx . Req . URL . EscapedPath ( ) , util . PathEscapeSegments ( refName ) , util . PathEscapeSegments ( renamedBranchName ) , 1 )
2021-10-08 20:03:04 +03:00
ctx . Redirect ( link )
return
}
2021-04-10 03:26:08 +03:00
if refType . RefTypeIncludesBranches ( ) && ctx . Repo . GitRepo . IsBranchExist ( refName ) {
ctx . Repo . IsViewBranch = true
2021-11-18 02:50:17 +03:00
ctx . Repo . BranchName = refName
2015-12-05 01:20:23 +03:00
2015-12-10 04:46:05 +03:00
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetBranchCommit ( refName )
2015-12-05 01:20:23 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetBranchCommit" , err )
2015-12-05 01:20:23 +03:00
return
}
ctx . Repo . CommitID = ctx . Repo . Commit . ID . String ( )
2021-04-10 03:26:08 +03:00
} else if refType . RefTypeIncludesTags ( ) && ctx . Repo . GitRepo . IsTagExist ( refName ) {
ctx . Repo . IsViewTag = true
2021-11-18 02:50:17 +03:00
ctx . Repo . TagName = refName
2021-04-10 03:26:08 +03:00
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetTagCommit ( refName )
if err != nil {
ctx . ServerError ( "GetTagCommit" , err )
2015-12-05 01:20:23 +03:00
return
}
2021-04-10 03:26:08 +03:00
ctx . Repo . CommitID = ctx . Repo . Commit . ID . String ( )
} else if len ( refName ) >= 7 && len ( refName ) <= 40 {
ctx . Repo . IsViewCommit = true
ctx . Repo . CommitID = refName
2015-12-05 01:20:23 +03:00
2021-04-10 03:26:08 +03:00
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetCommit ( refName )
if err != nil {
ctx . NotFound ( "GetCommit" , err )
2015-12-05 01:20:23 +03:00
return
}
2021-04-10 03:26:08 +03:00
// If short commit ID add canonical link header
if len ( refName ) < 40 {
2021-12-15 09:59:57 +03:00
ctx . RespHeader ( ) . Set ( "Link" , fmt . Sprintf ( "<%s>; rel=\"canonical\"" ,
2021-11-16 21:18:25 +03:00
util . URLJoin ( setting . AppURL , strings . Replace ( ctx . Req . URL . RequestURI ( ) , util . PathEscapeSegments ( refName ) , url . PathEscape ( ctx . Repo . Commit . ID . String ( ) ) , 1 ) ) ) )
2021-04-10 03:26:08 +03:00
}
} else {
2021-05-06 06:12:50 +03:00
if len ( ignoreNotExistErr ) > 0 && ignoreNotExistErr [ 0 ] {
return
}
2021-04-10 03:26:08 +03:00
ctx . NotFound ( "RepoRef invalid repo" , fmt . Errorf ( "branch or tag not exist: %s" , refName ) )
return
2015-12-05 01:20:23 +03:00
}
2017-10-30 05:04:25 +03:00
2021-04-10 03:26:08 +03:00
if refType == RepoRefLegacy {
// redirect from old URL scheme to new URL scheme
2022-02-17 19:11:27 +03:00
prefix := strings . TrimPrefix ( setting . AppSubURL + strings . ToLower ( strings . TrimSuffix ( ctx . Req . URL . Path , ctx . Params ( "*" ) ) ) , strings . ToLower ( ctx . Repo . RepoLink ) )
2021-11-16 21:18:25 +03:00
2021-04-10 03:26:08 +03:00
ctx . Redirect ( path . Join (
2021-11-16 21:18:25 +03:00
ctx . Repo . RepoLink ,
util . PathEscapeSegments ( prefix ) ,
2021-04-10 03:26:08 +03:00
ctx . Repo . BranchNameSubURL ( ) ,
2021-11-16 21:18:25 +03:00
util . PathEscapeSegments ( ctx . Repo . TreePath ) ) )
2017-10-30 05:04:25 +03:00
return
}
2021-04-10 03:26:08 +03:00
}
2015-12-05 01:20:23 +03:00
2021-04-10 03:26:08 +03:00
ctx . Data [ "BranchName" ] = ctx . Repo . BranchName
ctx . Data [ "BranchNameSubURL" ] = ctx . Repo . BranchNameSubURL ( )
2021-11-18 02:50:17 +03:00
ctx . Data [ "TagName" ] = ctx . Repo . TagName
2021-04-10 03:26:08 +03:00
ctx . Data [ "CommitID" ] = ctx . Repo . CommitID
ctx . Data [ "TreePath" ] = ctx . Repo . TreePath
ctx . Data [ "IsViewBranch" ] = ctx . Repo . IsViewBranch
ctx . Data [ "IsViewTag" ] = ctx . Repo . IsViewTag
ctx . Data [ "IsViewCommit" ] = ctx . Repo . IsViewCommit
ctx . Data [ "CanCreateBranch" ] = ctx . Repo . CanCreateBranch ( )
ctx . Repo . CommitsCount , err = ctx . Repo . GetCommitsCount ( )
if err != nil {
ctx . ServerError ( "GetCommitsCount" , err )
return
}
ctx . Data [ "CommitsCount" ] = ctx . Repo . CommitsCount
2021-05-06 02:30:25 +03:00
return
2015-12-05 01:20:23 +03:00
}
}
2014-12-07 04:22:48 +03:00
// GitHookService checks if repository Git hooks service has been enabled.
2021-01-26 18:36:53 +03:00
func GitHookService ( ) func ( ctx * Context ) {
2014-10-07 01:50:00 +04:00
return func ( ctx * Context ) {
2015-11-04 02:40:52 +03:00
if ! ctx . User . CanEditGitHook ( ) {
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "GitHookService" , nil )
2014-10-07 01:50:00 +04:00
return
}
}
}
2017-02-04 18:53:46 +03:00
2021-01-29 18:35:30 +03:00
// UnitTypes returns a middleware to set unit types to context variables.
2021-01-26 18:36:53 +03:00
func UnitTypes ( ) func ( ctx * Context ) {
2017-02-04 18:53:46 +03:00
return func ( ctx * Context ) {
2021-11-09 22:57:58 +03:00
ctx . Data [ "UnitTypeCode" ] = unit_model . TypeCode
ctx . Data [ "UnitTypeIssues" ] = unit_model . TypeIssues
ctx . Data [ "UnitTypePullRequests" ] = unit_model . TypePullRequests
ctx . Data [ "UnitTypeReleases" ] = unit_model . TypeReleases
ctx . Data [ "UnitTypeWiki" ] = unit_model . TypeWiki
ctx . Data [ "UnitTypeExternalWiki" ] = unit_model . TypeExternalWiki
ctx . Data [ "UnitTypeExternalTracker" ] = unit_model . TypeExternalTracker
ctx . Data [ "UnitTypeProjects" ] = unit_model . TypeProjects
2017-02-04 18:53:46 +03:00
}
}
2020-09-11 17:48:39 +03:00
// IssueTemplatesFromDefaultBranch checks for issue templates in the repo's default branch
func ( ctx * Context ) IssueTemplatesFromDefaultBranch ( ) [ ] api . IssueTemplate {
var issueTemplates [ ] api . IssueTemplate
2021-11-23 01:32:16 +03:00
if ctx . Repo . Repository . IsEmpty {
return issueTemplates
}
2020-09-11 17:48:39 +03:00
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
}
}
for _ , dirName := range IssueTemplateDirCandidates {
tree , err := ctx . Repo . Commit . SubTree ( dirName )
if err != nil {
continue
}
entries , err := tree . ListEntries ( )
if err != nil {
return issueTemplates
}
for _ , entry := range entries {
if strings . HasSuffix ( entry . Name ( ) , ".md" ) {
if entry . Blob ( ) . Size ( ) >= setting . UI . MaxDisplayFileSize {
log . Debug ( "Issue template is too large: %s" , entry . Name ( ) )
continue
}
r , err := entry . Blob ( ) . DataAsync ( )
if err != nil {
log . Debug ( "DataAsync: %v" , err )
continue
}
2021-05-10 04:27:03 +03:00
closed := false
defer func ( ) {
if ! closed {
_ = r . Close ( )
}
} ( )
2021-09-22 08:38:34 +03:00
data , err := io . ReadAll ( r )
2020-09-11 17:48:39 +03:00
if err != nil {
log . Debug ( "ReadAll: %v" , err )
continue
}
2021-05-10 04:27:03 +03:00
_ = r . Close ( )
2020-09-11 17:48:39 +03:00
var it api . IssueTemplate
content , err := markdown . ExtractMetadata ( string ( data ) , & it )
if err != nil {
log . Debug ( "ExtractMetadata: %v" , err )
continue
}
it . Content = content
it . FileName = entry . Name ( )
if it . Valid ( ) {
issueTemplates = append ( issueTemplates , it )
}
}
}
if len ( issueTemplates ) > 0 {
return issueTemplates
}
}
return issueTemplates
}