2014-02-19 21:45:43 -05: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 02:28:04 -04:00
"fmt"
2014-07-26 00:24:27 -04:00
"os"
2014-03-22 13:50:50 -04:00
"path"
2014-07-26 02:28:04 -04:00
"strings"
2014-03-22 13:50:50 -04:00
2014-07-26 00:24:27 -04:00
"github.com/Unknwon/com"
2014-05-05 19:58:13 -04:00
2016-11-06 14:18:34 +01:00
"github.com/go-gitea/git"
2015-12-09 20:46:05 -05:00
2016-11-03 13:29:56 +01:00
"github.com/go-gitea/gitea/models"
"github.com/go-gitea/gitea/modules/auth"
"github.com/go-gitea/gitea/modules/base"
"github.com/go-gitea/gitea/modules/context"
"github.com/go-gitea/gitea/modules/log"
"github.com/go-gitea/gitea/modules/setting"
2014-02-19 21:45:43 -05:00
)
2014-06-22 23:11:12 -04:00
const (
CREATE base . TplName = "repo/create"
MIGRATE base . TplName = "repo/migrate"
)
2016-03-11 11:56:52 -05:00
func MustBeNotBare ( ctx * context . Context ) {
2016-01-07 11:07:17 +08:00
if ctx . Repo . Repository . IsBare {
ctx . Handle ( 404 , "MustBeNotBare" , nil )
}
}
2016-03-11 11:56:52 -05:00
func checkContextUser ( ctx * context . Context , uid int64 ) * models . User {
2016-07-24 01:08:22 +08:00
orgs , err := models . GetOwnedOrgsByUserIDDesc ( ctx . User . ID , "updated_unix" )
2015-09-07 13:58:23 -04:00
if err != nil {
2015-09-07 14:02:09 -04:00
ctx . Handle ( 500 , "GetOwnedOrgsByUserIDDesc" , err )
2015-08-28 18:33:09 +08:00
return nil
}
2015-09-07 13:58:23 -04:00
ctx . Data [ "Orgs" ] = orgs
2015-08-28 18:33:09 +08:00
2015-07-19 17:11:16 +08:00
// Not equal means current user is an organization.
2016-07-24 01:08:22 +08:00
if uid == ctx . User . ID || uid == 0 {
2015-07-19 17:11:16 +08:00
return ctx . User
}
2015-08-08 22:43:14 +08:00
org , err := models . GetUserByID ( uid )
2015-08-05 11:14:17 +08:00
if models . IsErrUserNotExist ( err ) {
2015-07-19 17:11:16 +08:00
return ctx . User
}
if err != nil {
2015-10-25 04:26:26 -04:00
ctx . Handle ( 500 , "GetUserByID" , fmt . Errorf ( "[%d]: %v" , uid , err ) )
2015-07-19 17:11:16 +08:00
return nil
2015-08-28 18:33:09 +08:00
}
// Check ownership of organization.
2016-07-24 01:08:22 +08:00
if ! org . IsOrganization ( ) || ! ( ctx . User . IsAdmin || org . IsOwnedBy ( ctx . User . ID ) ) {
2015-07-19 17:11:16 +08:00
ctx . Error ( 403 )
return nil
2014-11-05 23:30:04 -05:00
}
2015-07-19 17:11:16 +08:00
return org
2014-11-05 23:30:04 -05:00
}
2016-03-11 11:56:52 -05:00
func Create ( ctx * context . Context ) {
2014-07-26 00:24:27 -04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_repo" )
// Give default value for template to render.
ctx . Data [ "Gitignores" ] = models . Gitignores
2014-03-19 13:14:56 -04:00
ctx . Data [ "Licenses" ] = models . Licenses
2015-08-28 16:44:04 +08:00
ctx . Data [ "Readmes" ] = models . Readmes
ctx . Data [ "readme" ] = "Default"
2015-08-28 18:45:25 +08:00
ctx . Data [ "private" ] = ctx . User . LastRepoVisibility
2015-10-25 04:26:26 -04:00
ctx . Data [ "IsForcedPrivate" ] = setting . Repository . ForcePrivate
2014-06-25 03:55:59 -04:00
2015-07-19 17:11:16 +08:00
ctxUser := checkContextUser ( ctx , ctx . QueryInt64 ( "org" ) )
if ctx . Written ( ) {
2014-11-05 23:30:04 -05:00
return
2014-07-26 02:28:04 -04:00
}
2014-06-28 15:43:25 -04:00
ctx . Data [ "ContextUser" ] = ctxUser
2014-06-22 23:11:12 -04:00
ctx . HTML ( 200 , CREATE )
2014-04-10 18:09:57 -04:00
}
2014-03-07 16:05:18 -05:00
2016-03-11 11:56:52 -05:00
func handleCreateError ( ctx * context . Context , owner * models . User , err error , name string , tpl base . TplName , form interface { } ) {
2015-08-28 18:33:09 +08:00
switch {
2015-12-10 12:37:53 -05:00
case models . IsErrReachLimitOfRepo ( err ) :
ctx . RenderWithErr ( ctx . Tr ( "repo.form.reach_limit_of_creation" , owner . RepoCreationNum ( ) ) , tpl , form )
2015-08-28 18:33:09 +08:00
case models . IsErrRepoAlreadyExist ( err ) :
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "form.repo_name_been_taken" ) , tpl , form )
case models . IsErrNameReserved ( err ) :
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_reserved" , err . ( models . ErrNameReserved ) . Name ) , tpl , form )
case models . IsErrNamePatternNotAllowed ( err ) :
ctx . Data [ "Err_RepoName" ] = true
ctx . RenderWithErr ( ctx . Tr ( "repo.form.name_pattern_not_allowed" , err . ( models . ErrNamePatternNotAllowed ) . Pattern ) , tpl , form )
default :
ctx . Handle ( 500 , name , err )
}
}
2016-03-11 11:56:52 -05:00
func CreatePost ( ctx * context . Context , form auth . CreateRepoForm ) {
2014-07-26 00:24:27 -04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_repo" )
ctx . Data [ "Gitignores" ] = models . Gitignores
2014-04-10 18:09:57 -04:00
ctx . Data [ "Licenses" ] = models . Licenses
2015-08-28 16:44:04 +08:00
ctx . Data [ "Readmes" ] = models . Readmes
2014-02-19 21:45:43 -05:00
2015-07-19 17:11:16 +08:00
ctxUser := checkContextUser ( ctx , form . Uid )
if ctx . Written ( ) {
return
2014-07-26 02:28:04 -04:00
}
2014-07-26 00:24:27 -04:00
ctx . Data [ "ContextUser" ] = ctxUser
2014-03-22 16:00:46 -04:00
if ctx . HasError ( ) {
2014-06-22 23:11:12 -04:00
ctx . HTML ( 200 , CREATE )
2014-03-22 16:00:46 -04:00
return
}
2015-08-28 18:33:09 +08:00
repo , err := models . CreateRepository ( ctxUser , models . CreateRepoOptions {
Name : form . RepoName ,
Description : form . Description ,
Gitignores : form . Gitignores ,
License : form . License ,
Readme : form . Readme ,
2015-10-25 04:26:26 -04:00
IsPrivate : form . Private || setting . Repository . ForcePrivate ,
2015-08-28 18:33:09 +08:00
AutoInit : form . AutoInit ,
} )
2014-03-17 11:56:50 -04:00
if err == nil {
2016-08-15 05:53:47 -07:00
log . Trace ( "Repository created [%d]: %s/%s" , repo . ID , ctxUser . Name , repo . Name )
2014-11-05 23:30:04 -05:00
ctx . Redirect ( setting . AppSubUrl + "/" + ctxUser . Name + "/" + repo . Name )
2014-03-08 21:25:38 -05:00
return
2014-03-09 20:06:29 -04:00
}
2014-04-12 20:35:35 -04:00
if repo != nil {
2016-07-24 01:08:22 +08:00
if errDelete := models . DeleteRepository ( ctxUser . ID , repo . ID ) ; errDelete != nil {
2014-07-26 00:24:27 -04:00
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
2014-04-12 20:35:35 -04:00
}
}
2015-03-26 17:11:47 -04:00
2015-12-10 12:37:53 -05:00
handleCreateError ( ctx , ctxUser , err , "CreatePost" , CREATE , & form )
2014-04-10 18:09:57 -04:00
}
2014-04-09 21:28:00 +08:00
2016-03-11 11:56:52 -05:00
func Migrate ( ctx * context . Context ) {
2014-08-01 00:06:19 -04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_migrate" )
2015-08-28 18:45:25 +08:00
ctx . Data [ "private" ] = ctx . User . LastRepoVisibility
2015-10-25 04:26:26 -04:00
ctx . Data [ "IsForcedPrivate" ] = setting . Repository . ForcePrivate
2015-12-09 11:24:56 -05:00
ctx . Data [ "mirror" ] = ctx . Query ( "mirror" ) == "1"
2014-08-01 00:06:19 -04:00
2015-07-19 17:11:16 +08:00
ctxUser := checkContextUser ( ctx , ctx . QueryInt64 ( "org" ) )
if ctx . Written ( ) {
2014-11-05 23:30:04 -05:00
return
2014-08-01 00:06:19 -04:00
}
ctx . Data [ "ContextUser" ] = ctxUser
2014-07-26 00:24:27 -04:00
2014-07-26 02:28:04 -04:00
ctx . HTML ( 200 , MIGRATE )
}
2014-07-26 00:24:27 -04:00
2016-03-11 11:56:52 -05:00
func MigratePost ( ctx * context . Context , form auth . MigrateRepoForm ) {
2014-08-01 00:06:19 -04:00
ctx . Data [ "Title" ] = ctx . Tr ( "new_migrate" )
2015-07-19 17:11:16 +08:00
ctxUser := checkContextUser ( ctx , form . Uid )
if ctx . Written ( ) {
return
2014-08-01 00:06:19 -04:00
}
ctx . Data [ "ContextUser" ] = ctxUser
2014-07-26 00:24:27 -04:00
2014-07-26 02:28:04 -04:00
if ctx . HasError ( ) {
ctx . HTML ( 200 , MIGRATE )
return
}
2014-07-26 00:24:27 -04:00
2015-11-03 18:40:52 -05:00
remoteAddr , err := form . ParseRemoteAddr ( ctx . User )
if err != nil {
if models . IsErrInvalidCloneAddr ( err ) {
2015-02-22 09:49:25 -05:00
ctx . Data [ "Err_CloneAddr" ] = true
2015-11-03 18:40:52 -05:00
addrErr := err . ( models . ErrInvalidCloneAddr )
switch {
case addrErr . IsURLError :
ctx . RenderWithErr ( ctx . Tr ( "form.url_error" ) , MIGRATE , & form )
case addrErr . IsPermissionDenied :
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.permission_denied" ) , MIGRATE , & form )
case addrErr . IsInvalidPath :
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.invalid_local_path" ) , MIGRATE , & form )
default :
ctx . Handle ( 500 , "Unknown error" , err )
}
} else {
ctx . Handle ( 500 , "ParseRemoteAddr" , err )
2015-02-22 09:49:25 -05:00
}
2015-01-02 12:14:11 +02:00
return
}
2015-10-25 04:26:26 -04:00
repo , err := models . MigrateRepository ( ctxUser , models . MigrateRepoOptions {
Name : form . RepoName ,
Description : form . Description ,
IsPrivate : form . Private || setting . Repository . ForcePrivate ,
IsMirror : form . Mirror ,
RemoteAddr : remoteAddr ,
} )
2014-07-26 02:28:04 -04:00
if err == nil {
2015-12-08 20:06:12 -05:00
log . Trace ( "Repository migrated [%d]: %s/%s" , repo . ID , ctxUser . Name , form . RepoName )
2014-09-19 20:11:34 -04:00
ctx . Redirect ( setting . AppSubUrl + "/" + ctxUser . Name + "/" + form . RepoName )
2014-07-26 02:28:04 -04:00
return
}
2014-07-26 00:24:27 -04:00
2014-07-26 02:28:04 -04:00
if repo != nil {
2016-07-24 01:08:22 +08:00
if errDelete := models . DeleteRepository ( ctxUser . ID , repo . ID ) ; errDelete != nil {
2014-07-26 02:28:04 -04:00
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
}
}
2014-07-26 00:24:27 -04:00
2015-11-19 13:45:07 -05:00
if strings . Contains ( err . Error ( ) , "Authentication failed" ) ||
2015-09-06 08:54:08 -04:00
strings . Contains ( err . Error ( ) , "could not read Username" ) {
2014-08-01 00:06:19 -04:00
ctx . Data [ "Err_Auth" ] = true
2015-12-08 20:06:12 -05:00
ctx . RenderWithErr ( ctx . Tr ( "form.auth_failed" , models . HandleCloneUserCredentials ( err . Error ( ) , true ) ) , MIGRATE , & form )
2014-07-26 02:28:04 -04:00
return
2015-11-19 13:45:07 -05:00
} else if strings . Contains ( err . Error ( ) , "fatal:" ) {
ctx . Data [ "Err_CloneAddr" ] = true
2015-12-08 20:06:12 -05:00
ctx . RenderWithErr ( ctx . Tr ( "repo.migrate.failed" , models . HandleCloneUserCredentials ( err . Error ( ) , true ) ) , MIGRATE , & form )
2015-11-19 13:45:07 -05:00
return
2014-07-26 02:28:04 -04:00
}
2015-03-26 17:11:47 -04:00
2015-12-10 12:37:53 -05:00
handleCreateError ( ctx , ctxUser , err , "MigratePost" , MIGRATE , & form )
2014-07-26 02:28:04 -04:00
}
2014-07-26 00:24:27 -04:00
2016-03-11 11:56:52 -05:00
func Action ( ctx * context . Context ) {
2014-08-10 20:11:18 -07:00
var err error
switch ctx . Params ( ":action" ) {
case "watch" :
2016-07-24 01:08:22 +08:00
err = models . WatchRepo ( ctx . User . ID , ctx . Repo . Repository . ID , true )
2014-08-10 20:11:18 -07:00
case "unwatch" :
2016-07-24 01:08:22 +08:00
err = models . WatchRepo ( ctx . User . ID , ctx . Repo . Repository . ID , false )
2014-08-10 20:11:18 -07:00
case "star" :
2016-07-24 01:08:22 +08:00
err = models . StarRepo ( ctx . User . ID , ctx . Repo . Repository . ID , true )
2014-08-10 20:11:18 -07:00
case "unstar" :
2016-07-24 01:08:22 +08:00
err = models . StarRepo ( ctx . User . ID , ctx . Repo . Repository . ID , false )
2016-01-07 11:07:17 +08:00
case "desc" : // FIXME: this is not used
2015-02-16 12:51:56 +02:00
if ! ctx . Repo . IsOwner ( ) {
2014-08-10 20:11:18 -07:00
ctx . Error ( 404 )
return
}
ctx . Repo . Repository . Description = ctx . Query ( "desc" )
ctx . Repo . Repository . Website = ctx . Query ( "site" )
2015-03-16 04:52:11 -04:00
err = models . UpdateRepository ( ctx . Repo . Repository , false )
2014-08-10 20:11:18 -07:00
}
if err != nil {
2015-12-21 04:24:11 -08:00
ctx . Handle ( 500 , fmt . Sprintf ( "Action (%s)" , ctx . Params ( ":action" ) ) , err )
2014-08-10 20:11:18 -07:00
return
}
2015-07-24 04:50:05 +08:00
redirectTo := ctx . Query ( "redirect_to" )
if len ( redirectTo ) == 0 {
redirectTo = ctx . Repo . RepoLink
}
ctx . Redirect ( redirectTo )
2014-08-10 20:11:18 -07:00
}
2014-07-26 00:24:27 -04:00
2016-03-11 11:56:52 -05:00
func Download ( ctx * context . Context ) {
2014-09-24 17:43:33 -04:00
var (
uri = ctx . Params ( "*" )
refName string
ext string
archivePath string
2014-11-02 14:18:37 +09:00
archiveType git . ArchiveType
2014-09-24 17:43:33 -04:00
)
switch {
case strings . HasSuffix ( uri , ".zip" ) :
ext = ".zip"
2014-07-26 00:24:27 -04:00
archivePath = path . Join ( ctx . Repo . GitRepo . Path , "archives/zip" )
2014-11-02 14:18:37 +09:00
archiveType = git . ZIP
2014-09-24 17:43:33 -04:00
case strings . HasSuffix ( uri , ".tar.gz" ) :
ext = ".tar.gz"
2014-07-26 00:24:27 -04:00
archivePath = path . Join ( ctx . Repo . GitRepo . Path , "archives/targz" )
2014-11-02 14:18:37 +09:00
archiveType = git . TARGZ
2014-07-26 00:24:27 -04:00
default :
2015-12-13 18:20:39 -05:00
log . Trace ( "Unknown format: %s" , uri )
2014-07-26 00:24:27 -04:00
ctx . Error ( 404 )
2014-06-25 05:35:23 -04:00
return
}
2014-09-24 17:43:33 -04:00
refName = strings . TrimSuffix ( uri , ext )
2014-06-25 05:35:23 -04:00
2014-07-26 00: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 05:35:23 -04:00
return
}
}
2014-09-24 17:43:33 -04:00
// Get corresponding commit.
var (
commit * git . Commit
err error
)
gitRepo := ctx . Repo . GitRepo
if gitRepo . IsBranchExist ( refName ) {
2015-12-09 20:46:05 -05:00
commit , err = gitRepo . GetBranchCommit ( refName )
2014-09-24 17:43:33 -04:00
if err != nil {
2015-12-09 20:46:05 -05:00
ctx . Handle ( 500 , "GetBranchCommit" , err )
2014-09-24 17:43:33 -04:00
return
}
} else if gitRepo . IsTagExist ( refName ) {
2015-12-09 20:46:05 -05:00
commit , err = gitRepo . GetTagCommit ( refName )
2014-09-24 17:43:33 -04:00
if err != nil {
2015-12-09 20:46:05 -05:00
ctx . Handle ( 500 , "GetTagCommit" , err )
2014-09-24 17:43:33 -04:00
return
}
} else if len ( refName ) == 40 {
commit , err = gitRepo . GetCommit ( refName )
if err != nil {
2015-12-09 20:46:05 -05:00
ctx . Handle ( 404 , "GetCommit" , nil )
2014-09-24 17:43:33 -04:00
return
}
} else {
2015-12-13 18:20:39 -05:00
ctx . Handle ( 404 , "Download" , nil )
2014-09-24 17:43:33 -04:00
return
}
2015-11-03 22:49:06 -05:00
archivePath = path . Join ( archivePath , base . ShortSha ( commit . ID . String ( ) ) + ext )
2014-07-26 00:24:27 -04:00
if ! com . IsFile ( archivePath ) {
2014-11-02 14:18:37 +09:00
if err := commit . CreateArchive ( archivePath , archiveType ) ; err != nil {
2014-07-26 00:24:27 -04:00
ctx . Handle ( 500 , "Download -> CreateArchive " + archivePath , err )
2014-03-22 13:50:50 -04:00
return
}
}
2016-01-07 14:28:38 -06:00
ctx . ServeFile ( archivePath , ctx . Repo . Repository . Name + "-" + refName + ext )
2014-03-22 13:50:50 -04:00
}