2014-02-20 06:45:43 +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 repo
import (
2014-07-26 10:28:04 +04:00
"fmt"
2015-01-02 13:14:11 +03:00
"net/url"
2014-07-26 08:24:27 +04:00
"os"
2014-03-22 21:50:50 +04:00
"path"
2014-07-26 10:28:04 +04:00
"strings"
2014-03-22 21:50:50 +04:00
2014-07-26 08:24:27 +04:00
"github.com/Unknwon/com"
2014-05-06 03:58:13 +04:00
2014-02-20 06:45:43 +04:00
"github.com/gogits/gogs/models"
2014-03-08 01:05:18 +04:00
"github.com/gogits/gogs/modules/auth"
2014-03-22 21:50:50 +04:00
"github.com/gogits/gogs/modules/base"
2014-07-26 08:24:27 +04:00
"github.com/gogits/gogs/modules/git"
2014-03-19 12:48:45 +04:00
"github.com/gogits/gogs/modules/log"
2014-03-15 17:17:16 +04:00
"github.com/gogits/gogs/modules/middleware"
2014-09-14 21:35:22 +04:00
"github.com/gogits/gogs/modules/setting"
2014-02-20 06:45:43 +04:00
)
2014-06-23 07:11:12 +04:00
const (
CREATE base . TplName = "repo/create"
MIGRATE base . TplName = "repo/migrate"
2014-11-06 07:30:04 +03:00
FORK base . TplName = "repo/fork"
2014-06-23 07:11:12 +04:00
)
2014-11-06 07:30:04 +03:00
func checkContextUser ( ctx * middleware . Context , uid int64 ) ( * models . User , error ) {
ctxUser := ctx . User
if uid > 0 {
org , err := models . GetUserById ( uid )
if err != models . ErrUserNotExist {
if err != nil {
return nil , fmt . Errorf ( "GetUserById: %v" , err )
}
ctxUser = org
}
}
return ctxUser , nil
}
2014-04-11 02:09:57 +04:00
func Create ( ctx * middleware . Context ) {
2014-07-26 08:24:27 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_repo" )
// Give default value for template to render.
ctx . Data [ "gitignore" ] = "0"
ctx . Data [ "license" ] = "0"
ctx . Data [ "Gitignores" ] = models . Gitignores
2014-03-19 21:14:56 +04:00
ctx . Data [ "Licenses" ] = models . Licenses
2014-06-25 11:55:59 +04:00
2014-11-06 07:30:04 +03:00
ctxUser , err := checkContextUser ( ctx , ctx . QueryInt64 ( "org" ) )
if err != nil {
ctx . Handle ( 500 , "checkContextUser" , err )
return
2014-07-26 10:28:04 +04:00
}
2014-06-28 23:43:25 +04:00
ctx . Data [ "ContextUser" ] = ctxUser
2014-07-26 10:28:04 +04:00
if err := ctx . User . GetOrganizations ( ) ; err != nil {
2014-07-27 07:53:16 +04:00
ctx . Handle ( 500 , "GetOrganizations" , err )
2014-07-26 10:28:04 +04:00
return
}
2014-07-27 07:53:16 +04:00
ctx . Data [ "Orgs" ] = ctx . User . Orgs
2014-06-25 11:55:59 +04:00
2014-06-23 07:11:12 +04:00
ctx . HTML ( 200 , CREATE )
2014-04-11 02:09:57 +04:00
}
2014-03-08 01:05:18 +04:00
2014-04-11 02:09:57 +04:00
func CreatePost ( ctx * middleware . Context , form auth . CreateRepoForm ) {
2014-07-26 08:24:27 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_repo" )
ctx . Data [ "Gitignores" ] = models . Gitignores
2014-04-11 02:09:57 +04:00
ctx . Data [ "Licenses" ] = models . Licenses
2014-02-20 06:45:43 +04:00
2014-07-26 08:24:27 +04:00
ctxUser := ctx . User
2014-07-27 07:53:16 +04:00
// Not equal means current user is an organization.
if form . Uid != ctx . User . Id {
2014-11-06 07:30:04 +03:00
var err error
ctxUser , err = checkContextUser ( ctx , form . Uid )
if err != nil {
ctx . Handle ( 500 , "checkContextUser" , err )
2014-07-26 10:28:04 +04:00
return
}
}
2014-07-26 08:24:27 +04:00
ctx . Data [ "ContextUser" ] = ctxUser
2014-07-26 10:28:04 +04:00
if err := ctx . User . GetOrganizations ( ) ; err != nil {
2014-07-27 07:53:16 +04:00
ctx . Handle ( 500 , "GetOrganizations" , err )
2014-07-26 10:28:04 +04:00
return
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
2014-06-25 11:55:59 +04:00
2014-03-23 00:00:46 +04:00
if ctx . HasError ( ) {
2014-06-23 07:11:12 +04:00
ctx . HTML ( 200 , CREATE )
2014-03-23 00:00:46 +04:00
return
}
2014-07-27 07:53:16 +04:00
if ctxUser . IsOrganization ( ) {
2014-06-28 23:43:25 +04:00
// Check ownership of organization.
2014-12-13 04:30:32 +03:00
if ! ctxUser . IsOwnedBy ( ctx . User . Id ) {
2014-06-28 23:43:25 +04:00
ctx . Error ( 403 )
return
}
2014-06-25 13:14:36 +04:00
}
2014-07-27 07:53:16 +04:00
repo , err := models . CreateRepository ( ctxUser , form . RepoName , form . Description ,
2014-12-13 04:30:32 +03:00
form . Gitignore , form . License , form . Private , false , form . AutoInit )
2014-03-17 19:56:50 +04:00
if err == nil {
2014-11-06 07:30:04 +03:00
log . Trace ( "Repository created: %s/%s" , ctxUser . Name , repo . Name )
ctx . Redirect ( setting . AppSubUrl + "/" + ctxUser . Name + "/" + repo . Name )
2014-03-09 06:25:38 +04:00
return
2014-03-17 10:36:28 +04:00
} else if err == models . ErrRepoAlreadyExist {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Err_RepoName" ] = true
2014-07-26 08:24:27 +04:00
ctx . RenderWithErr ( ctx . Tr ( "form.repo_name_been_taken" ) , CREATE , & form )
2014-03-10 04:06:29 +04:00
return
2014-03-20 19:41:24 +04:00
} else if err == models . ErrRepoNameIllegal {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Err_RepoName" ] = true
2014-07-26 08:24:27 +04:00
ctx . RenderWithErr ( ctx . Tr ( "form.illegal_repo_name" ) , CREATE , & form )
2014-03-20 19:41:24 +04:00
return
2014-03-10 04:06:29 +04:00
}
2014-04-13 04:35:35 +04:00
if repo != nil {
2014-07-27 07:53:16 +04:00
if errDelete := models . DeleteRepository ( ctxUser . Id , repo . Id , ctxUser . Name ) ; errDelete != nil {
2014-07-26 08:24:27 +04:00
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
2014-04-13 04:35:35 +04:00
}
}
2014-08-01 08:06:19 +04:00
ctx . Handle ( 500 , "CreatePost" , err )
2014-04-11 02:09:57 +04:00
}
2014-04-09 17:28:00 +04:00
2014-07-26 10:28:04 +04:00
func Migrate ( ctx * middleware . Context ) {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_migrate" )
2014-11-06 07:30:04 +03:00
ctxUser , err := checkContextUser ( ctx , ctx . QueryInt64 ( "org" ) )
if err != nil {
ctx . Handle ( 500 , "checkContextUser" , err )
return
2014-08-01 08:06:19 +04:00
}
ctx . Data [ "ContextUser" ] = ctxUser
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
if err := ctx . User . GetOrganizations ( ) ; err != nil {
2014-07-27 07:53:16 +04:00
ctx . Handle ( 500 , "GetOrganizations" , err )
2014-07-26 10:28:04 +04:00
return
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
ctx . HTML ( 200 , MIGRATE )
}
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
func MigratePost ( ctx * middleware . Context , form auth . MigrateRepoForm ) {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_migrate" )
ctxUser := ctx . User
2014-08-27 12:39:36 +04:00
// Not equal means current user is an organization.
if form . Uid != ctx . User . Id {
2014-11-06 07:30:04 +03:00
var err error
ctxUser , err = checkContextUser ( ctx , form . Uid )
2014-08-29 13:31:53 +04:00
if err != nil {
2014-11-06 07:30:04 +03:00
ctx . Handle ( 500 , "checkContextUser" , err )
2014-08-01 08:06:19 +04:00
return
}
}
ctx . Data [ "ContextUser" ] = ctxUser
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
if err := ctx . User . GetOrganizations ( ) ; err != nil {
2014-07-27 07:53:16 +04:00
ctx . Handle ( 500 , "GetOrganizations" , err )
2014-07-26 10:28:04 +04:00
return
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , MIGRATE )
return
}
2014-07-26 08:24:27 +04:00
2014-08-01 08:06:19 +04:00
if ctxUser . IsOrganization ( ) {
// Check ownership of organization.
2014-12-13 04:30:32 +03:00
if ! ctxUser . IsOwnedBy ( ctx . User . Id ) {
2014-08-01 08:06:19 +04:00
ctx . Error ( 403 )
2014-07-26 10:28:04 +04:00
return
}
}
2014-07-26 08:24:27 +04:00
2015-03-20 16:52:49 +03:00
// Remote address can be HTTP/HTTPS/Git URL or local path.
2015-02-22 17:49:25 +03:00
remoteAddr := form . CloneAddr
2015-03-20 16:52:49 +03:00
if strings . HasPrefix ( form . CloneAddr , "http://" ) || strings . HasPrefix ( form . CloneAddr , "https://" ) || strings . HasPrefix ( form . CloneAddr , "git://" ) {
2015-02-22 17:49:25 +03:00
u , err := url . Parse ( form . CloneAddr )
if err != nil {
ctx . Data [ "Err_CloneAddr" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.url_error" ) , MIGRATE , & form )
return
}
2015-03-11 16:21:05 +03:00
if len ( form . AuthUsername ) > 0 || len ( form . AuthPassword ) > 0 {
u . User = url . UserPassword ( form . AuthUsername , form . AuthPassword )
2015-02-22 17:49:25 +03:00
}
remoteAddr = u . String ( )
} else if ! com . IsDir ( remoteAddr ) {
ctx . Data [ "Err_CloneAddr" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.invalid_local_path" ) , MIGRATE , & form )
2015-01-02 13:14:11 +03:00
return
}
2015-02-22 17:49:25 +03:00
repo , err := models . MigrateRepository ( ctxUser , form . RepoName , form . Description , form . Private , form . Mirror , remoteAddr )
2014-07-26 10:28:04 +04:00
if err == nil {
2014-08-01 08:06:19 +04:00
log . Trace ( "Repository migrated: %s/%s" , ctxUser . Name , form . RepoName )
2014-09-20 04:11:34 +04:00
ctx . Redirect ( setting . AppSubUrl + "/" + ctxUser . Name + "/" + form . RepoName )
2014-07-26 10:28:04 +04:00
return
} else if err == models . ErrRepoAlreadyExist {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.repo_name_been_taken" ) , MIGRATE , & form )
2014-07-26 10:28:04 +04:00
return
} else if err == models . ErrRepoNameIllegal {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.illegal_repo_name" ) , MIGRATE , & form )
2014-07-26 10:28:04 +04:00
return
}
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
if repo != nil {
2014-08-01 08:06:19 +04:00
if errDelete := models . DeleteRepository ( ctxUser . Id , repo . Id , ctxUser . Name ) ; errDelete != nil {
2014-07-26 10:28:04 +04:00
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
}
}
2014-07-26 08:24:27 +04:00
2014-07-26 10:28:04 +04:00
if strings . Contains ( err . Error ( ) , "Authentication failed" ) {
2014-08-01 08:06:19 +04:00
ctx . Data [ "Err_Auth" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.auth_failed" , err ) , MIGRATE , & form )
2014-07-26 10:28:04 +04:00
return
}
2014-08-01 08:06:19 +04:00
ctx . Handle ( 500 , "MigratePost" , err )
2014-07-26 10:28:04 +04:00
}
2014-07-26 08:24:27 +04:00
2014-11-06 07:30:04 +03:00
func getForkRepository ( ctx * middleware . Context ) ( * models . Repository , error ) {
forkId := ctx . QueryInt64 ( "fork_id" )
ctx . Data [ "ForkId" ] = forkId
forkRepo , err := models . GetRepositoryById ( forkId )
if err != nil {
return nil , fmt . Errorf ( "GetRepositoryById: %v" , err )
}
ctx . Data [ "repo_name" ] = forkRepo . Name
ctx . Data [ "desc" ] = forkRepo . Description
if err = forkRepo . GetOwner ( ) ; err != nil {
return nil , fmt . Errorf ( "GetOwner: %v" , err )
}
ctx . Data [ "ForkFrom" ] = forkRepo . Owner . Name + "/" + forkRepo . Name
return forkRepo , nil
}
func Fork ( ctx * middleware . Context ) {
ctx . Data [ "Title" ] = ctx . Tr ( "new_fork" )
if _ , err := getForkRepository ( ctx ) ; err != nil {
2015-03-16 11:04:27 +03:00
if models . IsErrRepoNotExist ( err ) {
2014-11-06 07:30:04 +03:00
ctx . Redirect ( setting . AppSubUrl + "/" )
} else {
ctx . Handle ( 500 , "getForkRepository" , err )
}
return
}
// FIXME: maybe sometime can directly fork to organization?
ctx . Data [ "ContextUser" ] = ctx . User
if err := ctx . User . GetOrganizations ( ) ; err != nil {
ctx . Handle ( 500 , "GetOrganizations" , err )
return
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
ctx . HTML ( 200 , FORK )
}
func ForkPost ( ctx * middleware . Context , form auth . CreateRepoForm ) {
ctx . Data [ "Title" ] = ctx . Tr ( "new_fork" )
forkRepo , err := getForkRepository ( ctx )
if err != nil {
2015-03-16 11:04:27 +03:00
if models . IsErrRepoNotExist ( err ) {
2014-11-06 07:30:04 +03:00
ctx . Redirect ( setting . AppSubUrl + "/" )
} else {
ctx . Handle ( 500 , "getForkRepository" , err )
}
return
}
ctxUser := ctx . User
// Not equal means current user is an organization.
if form . Uid != ctx . User . Id {
var err error
ctxUser , err = checkContextUser ( ctx , form . Uid )
if err != nil {
ctx . Handle ( 500 , "checkContextUser" , err )
return
}
}
ctx . Data [ "ContextUser" ] = ctxUser
if err := ctx . User . GetOrganizations ( ) ; err != nil {
ctx . Handle ( 500 , "GetOrganizations" , err )
return
}
ctx . Data [ "Orgs" ] = ctx . User . Orgs
if ctx . HasError ( ) {
ctx . HTML ( 200 , CREATE )
return
}
if ctxUser . IsOrganization ( ) {
// Check ownership of organization.
2014-12-13 04:30:32 +03:00
if ! ctxUser . IsOwnedBy ( ctx . User . Id ) {
2014-11-06 07:30:04 +03:00
ctx . Error ( 403 )
return
}
}
repo , err := models . ForkRepository ( ctxUser , forkRepo , form . RepoName , form . Description )
if err == nil {
log . Trace ( "Repository forked: %s/%s" , ctxUser . Name , repo . Name )
ctx . Redirect ( setting . AppSubUrl + "/" + ctxUser . Name + "/" + repo . Name )
return
} else if err == models . ErrRepoAlreadyExist {
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.repo_name_been_taken" ) , FORK , & form )
return
} else if err == models . ErrRepoNameIllegal {
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.illegal_repo_name" ) , CREATE , & form )
return
}
if repo != nil {
if errDelete := models . DeleteRepository ( ctxUser . Id , repo . Id , ctxUser . Name ) ; errDelete != nil {
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
}
}
ctx . Handle ( 500 , "ForkPost" , err )
}
2014-08-11 07:11:18 +04:00
func Action ( ctx * middleware . Context ) {
var err error
switch ctx . Params ( ":action" ) {
case "watch" :
err = models . WatchRepo ( ctx . User . Id , ctx . Repo . Repository . Id , true )
case "unwatch" :
err = models . WatchRepo ( ctx . User . Id , ctx . Repo . Repository . Id , false )
case "star" :
err = models . StarRepo ( ctx . User . Id , ctx . Repo . Repository . Id , true )
case "unstar" :
err = models . StarRepo ( ctx . User . Id , ctx . Repo . Repository . Id , false )
case "desc" :
2015-02-16 13:51:56 +03:00
if ! ctx . Repo . IsOwner ( ) {
2014-08-11 07:11:18 +04:00
ctx . Error ( 404 )
return
}
ctx . Repo . Repository . Description = ctx . Query ( "desc" )
ctx . Repo . Repository . Website = ctx . Query ( "site" )
2015-03-16 11:52:11 +03:00
err = models . UpdateRepository ( ctx . Repo . Repository , false )
2014-08-11 07:11:18 +04:00
}
if err != nil {
2014-08-15 14:29:41 +04:00
log . Error ( 4 , "Action(%s): %v" , ctx . Params ( ":action" ) , err )
2014-08-11 07:11:18 +04:00
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : false ,
"err" : err . Error ( ) ,
} )
return
}
ctx . Redirect ( ctx . Repo . RepoLink )
return
ctx . JSON ( 200 , map [ string ] interface { } {
"ok" : true ,
} )
}
2014-07-26 08:24:27 +04:00
func Download ( ctx * middleware . Context ) {
2014-09-25 01:43:33 +04:00
var (
uri = ctx . Params ( "*" )
refName string
ext string
archivePath string
2014-11-02 08:18:37 +03:00
archiveType git . ArchiveType
2014-09-25 01:43:33 +04:00
)
switch {
case strings . HasSuffix ( uri , ".zip" ) :
ext = ".zip"
2014-07-26 08:24:27 +04:00
archivePath = path . Join ( ctx . Repo . GitRepo . Path , "archives/zip" )
2014-11-02 08:18:37 +03:00
archiveType = git . ZIP
2014-09-25 01:43:33 +04:00
case strings . HasSuffix ( uri , ".tar.gz" ) :
ext = ".tar.gz"
2014-07-26 08:24:27 +04:00
archivePath = path . Join ( ctx . Repo . GitRepo . Path , "archives/targz" )
2014-11-02 08:18:37 +03:00
archiveType = git . TARGZ
2014-07-26 08:24:27 +04:00
default :
ctx . Error ( 404 )
2014-06-25 13:35:23 +04:00
return
}
2014-09-25 01:43:33 +04:00
refName = strings . TrimSuffix ( uri , ext )
2014-06-25 13:35:23 +04:00
2014-07-26 08:24:27 +04:00
if ! com . IsDir ( archivePath ) {
if err := os . MkdirAll ( archivePath , os . ModePerm ) ; err != nil {
ctx . Handle ( 500 , "Download -> os.MkdirAll(archivePath)" , err )
2014-06-25 13:35:23 +04:00
return
}
}
2014-09-25 01:43:33 +04:00
// Get corresponding commit.
var (
commit * git . Commit
err error
)
gitRepo := ctx . Repo . GitRepo
if gitRepo . IsBranchExist ( refName ) {
commit , err = gitRepo . GetCommitOfBranch ( refName )
if err != nil {
ctx . Handle ( 500 , "Download" , err )
return
}
} else if gitRepo . IsTagExist ( refName ) {
commit , err = gitRepo . GetCommitOfTag ( refName )
if err != nil {
ctx . Handle ( 500 , "Download" , err )
return
}
} else if len ( refName ) == 40 {
commit , err = gitRepo . GetCommit ( refName )
if err != nil {
ctx . Handle ( 404 , "Download" , nil )
return
}
} else {
ctx . Error ( 404 )
return
}
2014-10-30 22:13:52 +03:00
archivePath = path . Join ( archivePath , base . ShortSha ( commit . Id . String ( ) ) + ext )
2014-07-26 08:24:27 +04:00
if ! com . IsFile ( archivePath ) {
2014-11-02 08:18:37 +03:00
if err := commit . CreateArchive ( archivePath , archiveType ) ; err != nil {
2014-07-26 08:24:27 +04:00
ctx . Handle ( 500 , "Download -> CreateArchive " + archivePath , err )
2014-03-22 21:50:50 +04:00
return
}
}
2014-09-25 01:43:33 +04:00
ctx . ServeFile ( archivePath , ctx . Repo . Repository . Name + "-" + base . ShortSha ( commit . Id . String ( ) ) + ext )
2014-03-22 21:50:50 +04:00
}