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 (
2014-03-20 08:12:33 +04:00
"fmt"
2016-08-12 03:07:09 +03:00
"io/ioutil"
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"
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"
2017-10-30 05:04:25 +03:00
"code.gitea.io/gitea/modules/log"
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/modules/setting"
2017-10-26 04:37:33 +03:00
2016-11-11 15:11:45 +03:00
"github.com/Unknwon/com"
2017-09-12 09:48:13 +03:00
"gopkg.in/editorconfig/editorconfig-core-go.v1"
"gopkg.in/macaron.v1"
2014-03-15 20:03:23 +04:00
)
2016-11-25 09:51:01 +03:00
// PullRequest contains informations to make a pull request
2016-03-14 00:37:44 +03:00
type PullRequest struct {
BaseRepo * models . Repository
Allowed bool
SameRepo bool
HeadInfo string // [<user>:]<branch>
}
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
Repository * models . Repository
Owner * models . User
Commit * git . Commit
Tag * git . Tag
GitRepo * git . Repository
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
CloneLink models . CloneLink
CommitsCount int64
Mirror * models . Mirror
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 {
2019-01-23 21:58:38 +03:00
return r . Permission . CanWrite ( models . UnitTypeCode ) && 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 {
2018-11-28 14:26:14 +03:00
return r . Permission . CanWrite ( models . UnitTypeCode ) && 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
func RepoMustNotBeArchived ( ) macaron . Handler {
return func ( ctx * Context ) {
if ctx . Repo . Repository . IsArchived {
ctx . NotFound ( "IsArchived" , fmt . Errorf ( ctx . Tr ( "repo.archive.title" ) ) )
}
}
}
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
2017-09-14 11:16:22 +03:00
func ( r * Repository ) CanCommitToBranch ( doer * models . User ) ( bool , error ) {
2018-08-08 06:17:11 +03:00
protectedBranch , err := r . Repository . IsProtectedBranchForPush ( r . BranchName , doer )
2017-05-02 03:49:55 +03:00
if err != nil {
return false , err
}
return r . CanEnableEditor ( ) && ! protectedBranch , nil
}
2017-09-12 09:48:13 +03:00
// CanUseTimetracker returns whether or not a user can use the timetracker.
func ( r * Repository ) CanUseTimetracker ( issue * models . Issue , user * models . User ) bool {
// 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 ( ) ||
2018-11-28 14:26:14 +03:00
r . Permission . CanWrite ( models . UnitTypeIssues ) || 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.
func ( r * Repository ) CanCreateIssueDependencies ( user * models . User ) bool {
2018-11-28 14:26:14 +03:00
return r . Permission . CanWrite ( models . UnitTypeIssues ) && r . Repository . IsDependenciesEnabled ( )
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 ( )
} )
}
2017-10-30 05:04:25 +03:00
// BranchNameSubURL sub-URL for the BranchName field
func ( r * Repository ) BranchNameSubURL ( ) string {
switch {
case r . IsViewBranch :
return "branch/" + r . BranchName
case r . IsViewTag :
return "tag/" + r . BranchName
case r . IsViewCommit :
return "commit/" + r . BranchName
}
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
func ( r * Repository ) FileExists ( path string , branch string ) ( bool , error ) {
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 ) {
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 ( )
2016-08-12 03:07:09 +03:00
data , err := ioutil . ReadAll ( reader )
if err != nil {
return nil , err
}
return editorconfig . ParseBytes ( data )
}
2016-11-25 09:51:01 +03:00
// RetrieveBaseRepo retrieves base repository
2015-09-01 18:43:53 +03:00
func RetrieveBaseRepo ( ctx * Context , repo * models . Repository ) {
// Non-fork repository will not return error in this method.
if err := repo . GetBaseRepo ( ) ; err != nil {
if models . IsErrRepoNotExist ( err ) {
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
} else if err = repo . BaseRepo . GetOwner ( ) ; err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "BaseRepo.GetOwner" , err )
2015-09-01 18:43:53 +03:00
return
}
}
2017-09-23 16:24:24 +03:00
// ComposeGoGetImport returns go-get-import meta content.
func ComposeGoGetImport ( owner , repo string ) string {
2019-03-18 17:00:23 +03:00
return path . Join ( setting . Domain , 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" )
reponame := ctx . Params ( ":reponame" )
2016-08-08 00:29:16 +03:00
ctx . PlainText ( 200 , [ ] byte ( com . Expand ( ` <meta name="go-import" content=" { GoGetImport} git { CloneLink}"> ` ,
map [ string ] string {
2017-09-23 16:24:24 +03:00
"GoGetImport" : ComposeGoGetImport ( username , strings . TrimSuffix ( reponame , ".git" ) ) ,
"CloneLink" : models . ComposeHTTPSCloneURL ( username , reponame ) ,
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" )
repo , err := models . GetRepositoryByID ( redirectRepoID )
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 (
ctx . Req . URL . Path ,
fmt . Sprintf ( "%s/%s" , ownerName , previousRepoName ) ,
2019-02-28 06:51:46 +03:00
fmt . Sprintf ( "%s/%s" , repo . MustOwnerName ( ) , repo . Name ) ,
2017-02-05 17:35:03 +03:00
1 ,
)
ctx . Redirect ( redirectPath )
}
2017-09-19 14:44:49 +03:00
2017-10-05 10:32:25 +03:00
func repoAssignment ( ctx * Context , repo * models . Repository ) {
2018-11-28 14:26:14 +03:00
var err error
2019-03-05 23:15:24 +03:00
if err = repo . GetOwner ( ) ; err != nil {
ctx . ServerError ( "GetOwner" , err )
return
}
if repo . Owner . IsOrganization ( ) {
if ! models . HasOrgVisible ( repo . Owner , ctx . User ) {
ctx . NotFound ( "HasOrgVisible" , nil )
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.
2018-11-28 14:26:14 +03:00
if ctx . Repo . Permission . AccessMode == models . AccessModeNone {
2017-10-05 10:32:25 +03:00
if ctx . Query ( "go-get" ) == "1" {
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
ctx . Repo . Mirror , err = models . GetMirrorByRepoID ( repo . ID )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetMirror" , err )
2017-10-05 10:32:25 +03:00
return
}
ctx . Data [ "MirrorEnablePrune" ] = ctx . Repo . Mirror . EnablePrune
ctx . Data [ "MirrorInterval" ] = ctx . Repo . Mirror . Interval
ctx . Data [ "Mirror" ] = ctx . Repo . Mirror
}
ctx . Repo . Repository = repo
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
}
// RepoIDAssignment returns a macaron handler which assigns the repo to the context.
2017-09-18 17:52:20 +03:00
func RepoIDAssignment ( ) macaron . Handler {
return func ( ctx * Context ) {
repoID := ctx . ParamsInt64 ( ":repoid" )
// Get repository.
repo , err := models . GetRepositoryByID ( repoID )
if err != nil {
if models . 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
2016-11-25 09:51:01 +03:00
// RepoAssignment returns a macaron to handle repository assignment
2017-03-18 13:59:07 +03:00
func RepoAssignment ( ) macaron . Handler {
2014-07-26 08:24:27 +04:00
return func ( ctx * Context ) {
2014-03-15 20:03:23 +04:00
var (
2015-10-31 19:04:04 +03:00
owner * models . User
err error
2014-03-15 20:03:23 +04:00
)
2014-07-26 08:24:27 +04:00
userName := ctx . Params ( ":username" )
repoName := ctx . Params ( ":reponame" )
2014-03-30 06:09:59 +04:00
2015-02-05 16:29:08 +03:00
// Check if the user is the same as the repository owner
2015-02-13 10:14:57 +03:00
if ctx . IsSigned && ctx . User . LowerName == strings . ToLower ( userName ) {
2015-10-31 19:04:04 +03:00
owner = ctx . User
2015-02-05 16:29:08 +03:00
} else {
2015-10-31 19:04:04 +03:00
owner , err = models . GetUserByName ( userName )
2014-03-15 20:03:23 +04:00
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2016-08-08 00:29:16 +03:00
if ctx . Query ( "go-get" ) == "1" {
2017-09-23 16:24:24 +03:00
EarlyResponseForGoGetMeta ( ctx )
2016-08-08 00:29:16 +03:00
return
}
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "GetUserByName" , nil )
2014-08-14 10:12:21 +04:00
} else {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetUserByName" , err )
2014-03-15 20:03:23 +04:00
}
return
}
}
2015-10-31 19:04:04 +03:00
ctx . Repo . Owner = owner
2016-08-30 12:08:38 +03:00
ctx . Data [ "Username" ] = ctx . Repo . Owner . Name
2014-03-15 20:03:23 +04:00
2014-08-24 17:09:05 +04:00
// Get repository.
2016-07-23 20:08:22 +03:00
repo , err := models . GetRepositoryByName ( owner . ID , repoName )
2014-03-15 20:03:23 +04:00
if err != nil {
2015-03-16 11:04:27 +03:00
if models . IsErrRepoNotExist ( err ) {
2017-02-05 17:35:03 +03:00
redirectRepoID , err := models . LookupRepoRedirect ( owner . ID , repoName )
if err == nil {
RedirectToRepo ( ctx , redirectRepoID )
} else if models . IsErrRepoRedirectNotExist ( err ) {
if ctx . Query ( "go-get" ) == "1" {
2017-09-23 16:24:24 +03:00
EarlyResponseForGoGetMeta ( ctx )
2017-02-05 17:35:03 +03:00
return
}
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "GetRepositoryByName" , nil )
2017-02-05 17:35:03 +03:00
} else {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "LookupRepoRedirect" , err )
2016-08-08 00:29:16 +03:00
}
2015-02-05 16:29:08 +03:00
} else {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetRepositoryByName" , err )
2014-03-15 20:03:23 +04:00
}
2014-07-26 08:24:27 +04:00
return
2014-03-30 06:09:59 +04:00
}
2017-02-02 15:33:56 +03:00
repo . Owner = owner
2014-04-12 05:47:39 +04:00
2017-10-05 10:32:25 +03:00
repoAssignment ( ctx , repo )
if ctx . Written ( ) {
2015-02-05 16:29:08 +03:00
return
2014-04-12 05:47:39 +04:00
}
2014-03-30 09:30:17 +04:00
2014-03-30 06:09:59 +04:00
gitRepo , err := git . OpenRepository ( models . RepoPath ( userName , repoName ) )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "RepoAssignment Invalid repo " + models . RepoPath ( userName , repoName ) , err )
2014-03-15 20:03:23 +04:00
return
}
2014-03-30 06:09:59 +04:00
ctx . Repo . GitRepo = gitRepo
2016-07-15 16:53:43 +03:00
ctx . Repo . RepoLink = repo . Link ( )
2014-08-15 14:29:41 +04:00
ctx . Data [ "RepoLink" ] = ctx . Repo . RepoLink
2015-09-02 12:09:12 +03:00
ctx . Data [ "RepoRelPath" ] = ctx . Repo . Owner . Name + "/" + ctx . Repo . Repository . Name
2014-03-30 07:38:41 +04:00
2019-02-20 02:09:47 +03:00
unit , err := ctx . Repo . Repository . GetUnit ( models . UnitTypeExternalTracker )
if err == nil {
ctx . Data [ "RepoExternalIssuesLink" ] = unit . ExternalTrackerConfig ( ) . ExternalTrackerURL
}
2014-04-14 05:00:12 +04:00
tags , err := ctx . Repo . GitRepo . GetTags ( )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetTags" , err )
2014-04-14 05:00:12 +04:00
return
}
2014-09-23 21:47:54 +04:00
ctx . Data [ "Tags" ] = tags
2017-08-28 17:06:10 +03:00
count , err := models . GetReleaseCountByRepoID ( ctx . Repo . Repository . ID , models . FindReleasesOptions {
IncludeDrafts : false ,
2017-09-20 08:26:49 +03:00
IncludeTags : true ,
2017-08-28 17:06:10 +03:00
} )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetReleaseCountByRepoID" , err )
2017-08-28 17:06:10 +03:00
return
}
ctx . Repo . Repository . NumReleases = int ( count )
2014-04-14 05:00:12 +04:00
2016-03-04 23:43:01 +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 ( )
2018-11-28 14:26:14 +03:00
ctx . Data [ "CanWriteCode" ] = ctx . Repo . CanWrite ( models . UnitTypeCode )
ctx . Data [ "CanWriteIssues" ] = ctx . Repo . CanWrite ( models . UnitTypeIssues )
ctx . Data [ "CanWritePulls" ] = ctx . Repo . CanWrite ( models . UnitTypePullRequests )
2016-03-04 23:43:01 +03:00
2017-10-15 18:06:07 +03:00
if ctx . Data [ "CanSignedUserFork" ] , err = ctx . Repo . Repository . CanUserFork ( ctx . User ) ; err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "CanUserFork" , err )
2017-10-15 18:06:07 +03:00
return
}
2016-02-28 04:48:39 +03:00
ctx . Data [ "DisableSSH" ] = setting . SSH . Disabled
2017-07-15 17:21:51 +03:00
ctx . Data [ "ExposeAnonSSH" ] = setting . SSH . ExposeAnonymous
2016-10-04 19:58:14 +03:00
ctx . Data [ "DisableHTTP" ] = setting . Repository . DisableHTTPGit
2017-10-27 09:10:54 +03:00
ctx . Data [ "RepoSearchEnabled" ] = setting . Indexer . RepoIndexerEnabled
2015-12-01 04:45:55 +03:00
ctx . Data [ "CloneLink" ] = repo . CloneLink ( )
ctx . Data [ "WikiCloneLink" ] = repo . WikiCloneLink ( )
2014-03-30 07:38:41 +04:00
2015-10-03 02:58:36 +03:00
if ctx . IsSigned {
2016-07-23 20:08:22 +03:00
ctx . Data [ "IsWatchingRepo" ] = models . IsWatching ( ctx . User . ID , repo . ID )
ctx . Data [ "IsStaringRepo" ] = models . IsStaring ( ctx . User . ID , repo . ID )
2015-10-03 02:58:36 +03:00
}
2019-04-15 23:48:35 +03:00
if repo . IsFork {
RetrieveBaseRepo ( ctx , repo )
if ctx . Written ( ) {
return
}
}
2019-01-18 03:01:04 +03:00
// repo is empty and display enable
if ctx . Repo . Repository . IsEmpty {
2017-03-18 13:59:07 +03:00
ctx . Data [ "BranchName" ] = ctx . Repo . Repository . DefaultBranch
2014-03-30 09:30:17 +04:00
return
2014-03-30 06:09:59 +04:00
}
2014-03-15 20:03:23 +04:00
2014-06-28 19:56:41 +04:00
ctx . Data [ "TagName" ] = ctx . Repo . TagName
2014-04-13 05:35:36 +04:00
brs , err := ctx . Repo . GitRepo . GetBranches ( )
2014-04-11 08:01:38 +04:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetBranches" , err )
2014-09-23 21:47:54 +04:00
return
2014-04-11 08:01:38 +04:00
}
ctx . Data [ "Branches" ] = brs
2017-12-03 23:52:30 +03:00
ctx . Data [ "BranchesCount" ] = len ( brs )
2014-07-22 16:46:04 +04:00
// If not branch selected, try default one.
// If default branch doesn't exists, fall back to some other branch.
2015-08-08 17:43:14 +03:00
if len ( ctx . Repo . BranchName ) == 0 {
if len ( ctx . Repo . Repository . DefaultBranch ) > 0 && gitRepo . IsBranchExist ( ctx . Repo . Repository . DefaultBranch ) {
2014-07-22 16:46:04 +04:00
ctx . Repo . BranchName = ctx . Repo . Repository . DefaultBranch
} else if len ( brs ) > 0 {
ctx . Repo . BranchName = brs [ 0 ]
}
}
ctx . Data [ "BranchName" ] = ctx . Repo . BranchName
2015-08-31 10:24:28 +03:00
ctx . Data [ "CommitID" ] = ctx . Repo . CommitID
2015-08-03 22:27:07 +03:00
2017-03-15 03:52:01 +03:00
// People who have push access or have forked repository can propose a new pull request.
2018-11-28 14:26:14 +03:00
if ctx . Repo . CanWrite ( models . UnitTypeCode ) || ( ctx . IsSigned && ctx . User . HasForkedRepo ( ctx . Repo . Repository . ID ) ) {
2016-03-07 07:57:46 +03:00
// Pull request is allowed if this is a fork repository
// and base repository accepts pull requests.
2017-05-30 15:04:12 +03:00
if repo . BaseRepo != nil && repo . BaseRepo . AllowsPulls ( ) {
ctx . Data [ "BaseRepo" ] = repo . BaseRepo
ctx . Repo . PullRequest . BaseRepo = repo . BaseRepo
ctx . Repo . PullRequest . Allowed = true
ctx . Repo . PullRequest . HeadInfo = ctx . Repo . Owner . Name + ":" + ctx . Repo . BranchName
2016-03-07 07:57:46 +03:00
} else {
// Or, this is repository accepts pull requests between branches.
if repo . AllowsPulls ( ) {
ctx . Data [ "BaseRepo" ] = repo
ctx . Repo . PullRequest . BaseRepo = repo
ctx . Repo . PullRequest . Allowed = true
ctx . Repo . PullRequest . SameRepo = true
ctx . Repo . PullRequest . HeadInfo = ctx . Repo . BranchName
}
}
}
ctx . Data [ "PullRequestCtx" ] = ctx . Repo . PullRequest
2015-10-31 19:04:04 +03:00
if ctx . Query ( "go-get" ) == "1" {
2017-09-23 16:24:24 +03:00
ctx . Data [ "GoGetImport" ] = ComposeGoGetImport ( owner . Name , repo . Name )
2017-11-27 03:58:54 +03:00
prefix := setting . AppURL + path . Join ( owner . Name , repo . Name , "src" , "branch" , ctx . Repo . BranchName )
2015-10-31 19:04:04 +03:00
ctx . Data [ "GoDocDirectory" ] = prefix + "{/dir}"
ctx . Data [ "GoDocFile" ] = prefix + "{/dir}/{file}#L{line}"
}
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
2015-12-05 01:20:23 +03:00
func RepoRef ( ) macaron . Handler {
2017-10-30 05:04:25 +03:00
// since no ref name is explicitly specified, ok to just use branch
return RepoRefByType ( RepoRefBranch )
}
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
}
2017-11-04 20:26:38 +03:00
if refName := getRefName ( ctx , RepoRefCommit ) ; len ( refName ) > 0 {
return refName
}
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 :
return getRefNameFromPath ( ctx , path , ctx . Repo . GitRepo . IsBranchExist )
case RepoRefTag :
return getRefNameFromPath ( ctx , path , ctx . Repo . GitRepo . IsTagExist )
case RepoRefCommit :
parts := strings . Split ( path , "/" )
if len ( parts ) > 0 && len ( parts [ 0 ] ) == 40 {
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
func RepoRefByType ( refType RepoRefType ) macaron . Handler {
2015-12-05 01:20:23 +03:00
return func ( ctx * Context ) {
// Empty repository does not have reference information.
2019-01-18 03:01:04 +03:00
if ctx . Repo . Repository . IsEmpty {
2015-12-05 01:20:23 +03:00
return
}
var (
refName string
err error
)
// For API calls.
if ctx . Repo . GitRepo == nil {
repoPath := models . RepoPath ( ctx . Repo . Owner . Name , ctx . Repo . Repository . Name )
2016-08-30 12:08:38 +03:00
ctx . Repo . GitRepo , err = git . OpenRepository ( repoPath )
2015-12-05 01:20:23 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "RepoRef Invalid repo " + repoPath , err )
2015-12-05 01:20:23 +03:00
return
}
}
// Get default branch.
if len ( ctx . Params ( "*" ) ) == 0 {
refName = ctx . Repo . Repository . DefaultBranch
2017-10-30 05:04:25 +03:00
ctx . Repo . BranchName = refName
2015-12-05 01:20:23 +03:00
if ! ctx . Repo . GitRepo . IsBranchExist ( refName ) {
brs , err := ctx . Repo . GitRepo . GetBranches ( )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetBranches" , err )
2015-12-05 01:20:23 +03:00
return
2017-05-29 05:25:23 +03:00
} else if len ( brs ) == 0 {
2019-01-18 03:01:04 +03:00
err = fmt . Errorf ( "No branches in non-empty repository %s" ,
2017-05-29 05:25:23 +03:00
ctx . Repo . GitRepo . Path )
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetBranches" , err )
2017-07-04 04:29:57 +03:00
return
2015-12-05 01:20:23 +03:00
}
refName = brs [ 0 ]
}
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 ( )
2015-12-09 08:32:53 +03:00
ctx . Repo . IsViewBranch = true
2015-12-05 01:20:23 +03:00
} else {
2017-10-30 05:04:25 +03:00
refName = getRefName ( ctx , refType )
ctx . Repo . BranchName = refName
2015-12-05 01:20:23 +03:00
if ctx . Repo . GitRepo . IsBranchExist ( refName ) {
2015-12-09 08:32:53 +03:00
ctx . Repo . IsViewBranch = true
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 ( )
} else if ctx . Repo . GitRepo . IsTagExist ( refName ) {
2015-12-09 08:32:53 +03:00
ctx . Repo . IsViewTag = true
2015-12-10 04:46:05 +03:00
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetTagCommit ( refName )
2015-12-05 01:20:23 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetTagCommit" , err )
2015-12-05 01:20:23 +03:00
return
}
ctx . Repo . CommitID = ctx . Repo . Commit . ID . String ( )
} else if len ( refName ) == 40 {
2015-12-09 08:32:53 +03:00
ctx . Repo . IsViewCommit = true
2015-12-05 01:20:23 +03:00
ctx . Repo . CommitID = refName
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetCommit ( refName )
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "GetCommit" , nil )
2015-12-05 01:20:23 +03:00
return
}
} else {
2018-01-11 00:34:17 +03:00
ctx . NotFound ( "RepoRef invalid repo" , fmt . Errorf ( "branch or tag not exist: %s" , refName ) )
2015-12-05 01:20:23 +03:00
return
}
2017-10-30 05:04:25 +03:00
if refType == RepoRefLegacy {
// redirect from old URL scheme to new URL scheme
2017-12-07 04:09:02 +03:00
ctx . Redirect ( path . Join (
setting . AppSubURL ,
2018-09-07 04:37:02 +03:00
strings . TrimSuffix ( ctx . Req . URL . Path , ctx . Params ( "*" ) ) ,
2017-12-07 04:09:02 +03:00
ctx . Repo . BranchNameSubURL ( ) ,
ctx . Repo . TreePath ) )
2017-10-30 05:04:25 +03:00
return
}
2015-12-05 01:20:23 +03:00
}
ctx . Data [ "BranchName" ] = ctx . Repo . BranchName
2017-10-30 05:04:25 +03:00
ctx . Data [ "BranchNameSubURL" ] = ctx . Repo . BranchNameSubURL ( )
2015-12-05 01:20:23 +03:00
ctx . Data [ "CommitID" ] = ctx . Repo . CommitID
2016-08-30 12:08:38 +03:00
ctx . Data [ "TreePath" ] = ctx . Repo . TreePath
2015-12-09 08:32:53 +03:00
ctx . Data [ "IsViewBranch" ] = ctx . Repo . IsViewBranch
ctx . Data [ "IsViewTag" ] = ctx . Repo . IsViewTag
ctx . Data [ "IsViewCommit" ] = ctx . Repo . IsViewCommit
2017-10-15 22:59:24 +03:00
ctx . Data [ "CanCreateBranch" ] = ctx . Repo . CanCreateBranch ( )
2015-12-05 01:20:23 +03:00
2017-10-26 04:37:33 +03:00
ctx . Repo . CommitsCount , err = ctx . Repo . GetCommitsCount ( )
2015-12-05 01:20:23 +03:00
if err != nil {
2018-01-11 00:34:17 +03:00
ctx . ServerError ( "GetCommitsCount" , err )
2015-12-05 01:20:23 +03:00
return
}
ctx . Data [ "CommitsCount" ] = ctx . Repo . CommitsCount
}
}
2014-12-07 04:22:48 +03:00
// GitHookService checks if repository Git hooks service has been enabled.
2014-10-07 01:50:00 +04:00
func GitHookService ( ) macaron . Handler {
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
// UnitTypes returns a macaron middleware to set unit types to context variables.
func UnitTypes ( ) macaron . Handler {
return func ( ctx * Context ) {
ctx . Data [ "UnitTypeCode" ] = models . UnitTypeCode
ctx . Data [ "UnitTypeIssues" ] = models . UnitTypeIssues
ctx . Data [ "UnitTypePullRequests" ] = models . UnitTypePullRequests
ctx . Data [ "UnitTypeReleases" ] = models . UnitTypeReleases
ctx . Data [ "UnitTypeWiki" ] = models . UnitTypeWiki
ctx . Data [ "UnitTypeExternalWiki" ] = models . UnitTypeExternalWiki
ctx . Data [ "UnitTypeExternalTracker" ] = models . UnitTypeExternalTracker
}
}