2014-03-15 20:03:23 +04:00
// Copyright 2014 The Gogs Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package middleware
import (
2014-03-16 10:28:24 +04:00
"errors"
2014-03-20 08:12:33 +04:00
"fmt"
2014-05-06 03:58:13 +04:00
"net/url"
2014-03-17 12:47:42 +04:00
"strings"
2014-03-16 10:28:24 +04:00
2014-07-26 08:24:27 +04:00
"github.com/Unknwon/macaron"
2014-03-30 06:09:59 +04:00
2014-03-15 20:03:23 +04:00
"github.com/gogits/gogs/models"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/git"
2014-04-11 08:01:38 +04:00
"github.com/gogits/gogs/modules/log"
2014-05-26 04:11:25 +04:00
"github.com/gogits/gogs/modules/setting"
2014-03-15 20:03:23 +04:00
)
2014-07-26 08:24:27 +04:00
func RepoAssignment ( redirect bool , args ... bool ) macaron . Handler {
return func ( ctx * Context ) {
2014-08-14 10:12:21 +04:00
var (
validBranch bool // To valid brach name.
displayBare bool // To display bare page if it is a bare repo.
)
2014-03-30 09:30:17 +04:00
if len ( args ) >= 1 {
2014-06-13 01:47:23 +04:00
validBranch = args [ 0 ]
2014-03-30 09:30:17 +04:00
}
if len ( args ) >= 2 {
2014-06-13 01:47:23 +04:00
displayBare = args [ 1 ]
2014-03-30 09:30:17 +04:00
}
2014-03-15 20:03:23 +04:00
var (
2014-07-26 08:24:27 +04:00
u * 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" )
refName := ctx . Params ( ":branchname" )
if len ( refName ) == 0 {
refName = ctx . Params ( ":path" )
}
2014-03-30 06:09:59 +04:00
2014-05-08 20:24:11 +04:00
// Collaborators who have write access can be seen as owners.
if ctx . IsSigned {
2014-06-25 08:44:48 +04:00
ctx . Repo . IsOwner , err = models . HasAccess ( ctx . User . Name , userName + "/" + repoName , models . WRITABLE )
2014-05-08 20:24:11 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "HasAccess" , err )
2014-05-08 20:24:11 +04:00
return
}
2014-07-04 09:23:11 +04:00
ctx . Repo . IsTrueOwner = ctx . User . LowerName == strings . ToLower ( userName )
2014-05-08 20:24:11 +04:00
}
2014-03-15 20:03:23 +04:00
2014-07-04 09:23:11 +04:00
if ! ctx . Repo . IsTrueOwner {
2014-07-26 08:24:27 +04:00
u , err = models . GetUserByName ( userName )
2014-03-15 20:03:23 +04:00
if err != nil {
2014-04-30 11:44:28 +04:00
if err == models . ErrUserNotExist {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 404 , "GetUserByName" , err )
2014-04-30 11:44:28 +04:00
} else if redirect {
2014-08-24 17:09:05 +04:00
log . Error ( 4 , "GetUserByName" , err )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-08-14 10:12:21 +04:00
} else {
ctx . Handle ( 500 , "GetUserByName" , err )
2014-03-15 20:03:23 +04:00
}
return
}
} else {
2014-07-26 08:24:27 +04:00
u = ctx . User
2014-03-15 20:03:23 +04:00
}
2014-07-26 08:24:27 +04:00
if u == nil {
2014-03-15 20:03:23 +04:00
if redirect {
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-03-15 20:03:23 +04:00
return
}
2014-07-26 08:24:27 +04:00
ctx . Handle ( 404 , "RepoAssignment" , errors . New ( "invliad user account for single repository" ) )
2014-03-15 20:03:23 +04:00
return
}
2014-07-26 08:24:27 +04:00
ctx . Repo . Owner = u
2014-03-15 20:03:23 +04:00
2014-07-04 09:23:11 +04:00
// Organization owner team members are true owners as well.
2014-07-07 01:32:36 +04:00
if ctx . IsSigned && ctx . Repo . Owner . IsOrganization ( ) && ctx . Repo . Owner . IsOrgOwner ( ctx . User . Id ) {
2014-07-04 09:23:11 +04:00
ctx . Repo . IsTrueOwner = true
}
2014-08-24 17:09:05 +04:00
// Get repository.
2014-07-26 08:24:27 +04:00
repo , err := models . GetRepositoryByName ( u . Id , repoName )
2014-03-15 20:03:23 +04:00
if err != nil {
2014-03-28 05:15:53 +04:00
if err == models . ErrRepoNotExist {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 404 , "GetRepositoryByName" , err )
2014-04-12 05:47:39 +04:00
return
2014-03-28 05:15:53 +04:00
} else if redirect {
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" )
2014-03-15 20:03:23 +04:00
return
}
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "GetRepositoryByName" , err )
return
} else if err = repo . GetOwner ( ) ; err != nil {
ctx . Handle ( 500 , "GetOwner" , err )
2014-03-30 06:09:59 +04:00
return
}
2014-04-12 05:47:39 +04:00
2014-05-14 03:26:13 +04:00
// Check if the mirror repository owner(mirror repository doesn't have access).
2014-08-24 17:09:05 +04:00
if ctx . IsSigned && ! ctx . Repo . IsOwner {
if repo . OwnerId == ctx . User . Id {
ctx . Repo . IsOwner = true
}
// Check if current user has admin permission to repository.
if u . IsOrganization ( ) {
2014-09-13 05:36:26 +04:00
auth , err := models . GetHighestAuthorize ( u . Id , ctx . User . Id , repo . Id , 0 )
2014-08-24 17:09:05 +04:00
if err != nil {
ctx . Handle ( 500 , "GetHighestAuthorize" , err )
return
}
if auth == models . ORG_ADMIN {
ctx . Repo . IsOwner = true
ctx . Repo . IsAdmin = true
}
}
2014-05-14 03:26:13 +04:00
}
2014-04-12 05:47:39 +04:00
// Check access.
2014-05-09 03:17:43 +04:00
if repo . IsPrivate && ! ctx . Repo . IsOwner {
2014-04-12 05:47:39 +04:00
if ctx . User == nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 404 , "HasAccess" , nil )
2014-04-12 05:47:39 +04:00
return
}
2014-06-25 08:44:48 +04:00
hasAccess , err := models . HasAccess ( ctx . User . Name , ctx . Repo . Owner . Name + "/" + repo . Name , models . READABLE )
2014-04-12 05:47:39 +04:00
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "HasAccess" , err )
2014-04-12 05:47:39 +04:00
return
} else if ! hasAccess {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 404 , "HasAccess" , nil )
2014-04-12 05:47:39 +04:00
return
}
}
ctx . Repo . HasAccess = true
ctx . Data [ "HasAccess" ] = true
2014-04-13 06:30:00 +04:00
if repo . IsMirror {
ctx . Repo . Mirror , err = models . GetMirror ( repo . Id )
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "GetMirror" , err )
2014-04-13 06:30:00 +04:00
return
}
ctx . Data [ "MirrorInterval" ] = ctx . Repo . Mirror . Interval
}
2014-04-02 20:43:31 +04:00
repo . NumOpenIssues = repo . NumIssues - repo . NumClosedIssues
2014-05-12 22:06:42 +04:00
repo . NumOpenMilestones = repo . NumMilestones - repo . NumClosedMilestones
2014-03-30 06:09:59 +04:00
ctx . Repo . Repository = repo
2014-03-30 09:30:17 +04:00
ctx . Data [ "IsBareRepo" ] = ctx . Repo . Repository . IsBare
2014-03-30 06:09:59 +04:00
gitRepo , err := git . OpenRepository ( models . RepoPath ( userName , repoName ) )
if err != nil {
2014-04-11 06:03:31 +04:00
ctx . Handle ( 500 , "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
2014-10-19 09:35:24 +04:00
ctx . Repo . RepoLink , err = repo . RepoLink ( )
if err != nil {
ctx . Handle ( 500 , "RepoLink" , err )
return
}
2014-08-15 14:29:41 +04:00
ctx . Data [ "RepoLink" ] = ctx . Repo . RepoLink
2014-03-30 07:38:41 +04:00
2014-04-14 05:00:12 +04:00
tags , err := ctx . Repo . GitRepo . GetTags ( )
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "GetTags" , err )
2014-04-14 05:00:12 +04:00
return
}
2014-09-23 21:47:54 +04:00
ctx . Data [ "Tags" ] = tags
2014-04-14 05:00:12 +04:00
ctx . Repo . Repository . NumTags = len ( tags )
2014-10-19 09:35:24 +04:00
// Non-fork repository will not return error in this method.
if err = repo . GetForkRepo ( ) ; err != nil {
ctx . Handle ( 500 , "GetForkRepo" , err )
return
}
2014-07-26 08:24:27 +04:00
ctx . Data [ "Title" ] = u . Name + "/" + repo . Name
2014-03-30 07:38:41 +04:00
ctx . Data [ "Repository" ] = repo
2014-07-26 08:24:27 +04:00
ctx . Data [ "Owner" ] = ctx . Repo . Repository . Owner
2014-03-30 07:38:41 +04:00
ctx . Data [ "IsRepositoryOwner" ] = ctx . Repo . IsOwner
2014-07-04 09:23:11 +04:00
ctx . Data [ "IsRepositoryTrueOwner" ] = ctx . Repo . IsTrueOwner
2014-03-30 07:38:41 +04:00
2014-05-26 04:11:25 +04:00
if setting . SshPort != 22 {
2014-07-30 18:02:31 +04:00
ctx . Repo . CloneLink . SSH = fmt . Sprintf ( "ssh://%s@%s:%d/%s/%s.git" , setting . RunUser , setting . Domain , setting . SshPort , u . LowerName , repo . LowerName )
2014-05-11 20:17:10 +04:00
} else {
2014-07-26 08:24:27 +04:00
ctx . Repo . CloneLink . SSH = fmt . Sprintf ( "%s@%s:%s/%s.git" , setting . RunUser , setting . Domain , u . LowerName , repo . LowerName )
2014-05-11 19:18:10 +04:00
}
2014-07-26 08:24:27 +04:00
ctx . Repo . CloneLink . HTTPS = fmt . Sprintf ( "%s%s/%s.git" , setting . AppUrl , u . LowerName , repo . LowerName )
2014-03-30 07:38:41 +04:00
ctx . Data [ "CloneLink" ] = ctx . Repo . CloneLink
2014-04-13 12:08:25 +04:00
if ctx . Repo . Repository . IsGoget {
2014-07-26 08:24:27 +04:00
ctx . Data [ "GoGetLink" ] = fmt . Sprintf ( "%s%s/%s" , setting . AppUrl , u . LowerName , repo . LowerName )
ctx . Data [ "GoGetImport" ] = fmt . Sprintf ( "%s/%s/%s" , setting . Domain , u . LowerName , repo . LowerName )
2014-04-13 12:08:25 +04:00
}
2014-03-30 09:30:17 +04:00
// when repo is bare, not valid branch
if ! ctx . Repo . Repository . IsBare && validBranch {
detect :
2014-04-16 01:43:25 +04:00
if len ( refName ) > 0 {
if gitRepo . IsBranchExist ( refName ) {
2014-03-30 09:30:17 +04:00
ctx . Repo . IsBranch = true
2014-04-16 01:43:25 +04:00
ctx . Repo . BranchName = refName
2014-03-30 09:30:17 +04:00
2014-04-16 01:43:25 +04:00
ctx . Repo . Commit , err = gitRepo . GetCommitOfBranch ( refName )
2014-03-30 09:30:17 +04:00
if err != nil {
2014-09-25 01:43:33 +04:00
ctx . Handle ( 500 , "RepoAssignment invalid branch" , err )
2014-03-30 09:30:17 +04:00
return
}
2014-04-16 01:43:25 +04:00
ctx . Repo . CommitId = ctx . Repo . Commit . Id . String ( )
} else if gitRepo . IsTagExist ( refName ) {
2014-06-28 19:56:41 +04:00
ctx . Repo . IsTag = true
2014-04-16 01:43:25 +04:00
ctx . Repo . BranchName = refName
2014-09-30 12:39:53 +04:00
ctx . Repo . Commit , err = ctx . Repo . GitRepo . GetCommitOfTag ( refName )
2014-04-16 01:43:25 +04:00
if err != nil {
2014-09-30 12:39:53 +04:00
ctx . Handle ( 500 , "Fail to get tag commit" , err )
2014-09-23 21:06:25 +04:00
return
}
2014-04-13 05:35:36 +04:00
ctx . Repo . CommitId = ctx . Repo . Commit . Id . String ( )
2014-04-16 01:43:25 +04:00
} else if len ( refName ) == 40 {
2014-03-30 09:30:17 +04:00
ctx . Repo . IsCommit = true
2014-04-16 01:43:25 +04:00
ctx . Repo . CommitId = refName
ctx . Repo . BranchName = refName
2014-03-30 09:30:17 +04:00
2014-04-16 01:43:25 +04:00
ctx . Repo . Commit , err = gitRepo . GetCommit ( refName )
2014-03-30 09:30:17 +04:00
if err != nil {
ctx . Handle ( 404 , "RepoAssignment invalid commit" , nil )
return
}
} else {
2014-09-23 21:06:25 +04:00
ctx . Handle ( 404 , "RepoAssignment invalid repo" , fmt . Errorf ( "branch or tag not exist: %s" , refName ) )
2014-03-30 06:09:59 +04:00
return
}
} else {
2014-04-16 01:43:25 +04:00
if len ( refName ) == 0 {
2014-05-01 20:03:10 +04:00
if gitRepo . IsBranchExist ( ctx . Repo . Repository . DefaultBranch ) {
refName = ctx . Repo . Repository . DefaultBranch
} else {
brs , err := gitRepo . GetBranches ( )
if err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "GetBranches" , err )
2014-05-01 20:03:10 +04:00
return
}
refName = brs [ 0 ]
}
2014-04-11 06:03:31 +04:00
}
2014-03-30 09:30:17 +04:00
goto detect
2014-03-30 06:09:59 +04:00
}
2014-03-30 13:09:19 +04:00
ctx . Data [ "IsBranch" ] = ctx . Repo . IsBranch
2014-09-23 21:47:54 +04:00
ctx . Data [ "IsTag" ] = ctx . Repo . IsTag
2014-03-30 13:09:19 +04:00
ctx . Data [ "IsCommit" ] = ctx . Repo . IsCommit
2014-07-26 08:24:27 +04:00
ctx . Repo . CommitsCount , err = ctx . Repo . Commit . CommitsCount ( )
if err != nil {
ctx . Handle ( 500 , "CommitsCount" , err )
return
}
ctx . Data [ "CommitsCount" ] = ctx . Repo . CommitsCount
2014-03-30 09:30:17 +04:00
}
2014-03-30 06:09:59 +04:00
2014-03-30 09:30:17 +04:00
// repo is bare and display enable
2014-08-11 07:11:18 +04:00
if ctx . Repo . Repository . IsBare {
2014-04-20 06:13:22 +04:00
log . Debug ( "Bare repository: %s" , ctx . Repo . RepoLink )
2014-08-11 07:11:18 +04:00
if displayBare {
ctx . HTML ( 200 , "repo/bare" )
}
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-03-30 06:09:59 +04:00
if ctx . IsSigned {
2014-08-10 04:25:02 +04:00
ctx . Data [ "IsWatchingRepo" ] = models . IsWatching ( ctx . User . Id , repo . Id )
2014-08-11 07:11:18 +04:00
ctx . Data [ "IsStaringRepo" ] = models . IsStaring ( ctx . User . Id , repo . Id )
2014-03-20 10:25:21 +04:00
}
2014-03-30 06:09:59 +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 {
2014-09-23 21:47:54 +04:00
ctx . Handle ( 500 , "GetBranches" , err )
return
2014-04-11 08:01:38 +04:00
}
ctx . Data [ "Branches" ] = brs
2014-07-26 08:24:27 +04:00
ctx . Data [ "BrancheCount" ] = 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.
if ctx . Repo . BranchName == "" {
if ctx . Repo . Repository . DefaultBranch != "" && gitRepo . IsBranchExist ( ctx . Repo . Repository . DefaultBranch ) {
ctx . Repo . BranchName = ctx . Repo . Repository . DefaultBranch
} else if len ( brs ) > 0 {
ctx . Repo . BranchName = brs [ 0 ]
}
}
ctx . Data [ "BranchName" ] = ctx . Repo . BranchName
2014-03-30 06:09:59 +04:00
ctx . Data [ "CommitId" ] = ctx . Repo . CommitId
2014-03-15 20:03:23 +04:00
}
}
2014-05-06 03:58:13 +04:00
2014-07-26 08:24:27 +04:00
func RequireTrueOwner ( ) macaron . Handler {
2014-05-06 03:58:13 +04:00
return func ( ctx * Context ) {
2014-08-24 17:09:05 +04:00
if ! ctx . Repo . IsTrueOwner && ! ctx . Repo . IsAdmin {
2014-05-06 03:58:13 +04:00
if ! ctx . IsSigned {
2014-09-21 16:07:00 +04:00
ctx . SetCookie ( "redirect_to" , "/" + url . QueryEscape ( setting . AppSubUrl + ctx . Req . RequestURI ) , 0 , setting . AppSubUrl )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/user/login" )
2014-05-06 03:58:13 +04:00
return
}
ctx . Handle ( 404 , ctx . Req . RequestURI , nil )
return
}
}
}
2014-10-07 01:50:00 +04:00
// GitHookService checks if repsitory Git hooks service has been enabled.
func GitHookService ( ) macaron . Handler {
return func ( ctx * Context ) {
if ! setting . Service . EnableGitHooks {
ctx . Handle ( 404 , "GitHookService" , nil )
return
}
}
}