2014-08-26 14:11:15 +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 v1
import (
2015-02-22 17:49:25 +03:00
"net/url"
2014-08-26 14:11:15 +04:00
"path"
2014-08-29 07:24:37 +04:00
"strings"
2014-08-26 14:11:15 +04:00
"github.com/Unknwon/com"
2014-11-15 01:11:30 +03:00
api "github.com/gogits/go-gogs-client"
2014-08-26 14:11:15 +04:00
"github.com/gogits/gogs/models"
2014-08-29 07:24:37 +04:00
"github.com/gogits/gogs/modules/auth"
2014-11-17 05:32:26 +03:00
"github.com/gogits/gogs/modules/base"
2014-08-29 07:24:37 +04:00
"github.com/gogits/gogs/modules/log"
2014-08-26 14:11:15 +04:00
"github.com/gogits/gogs/modules/middleware"
2014-11-13 10:32:18 +03:00
"github.com/gogits/gogs/modules/setting"
2014-08-26 14:11:15 +04:00
)
2014-12-13 04:30:32 +03:00
// ToApiRepository converts repository to API format.
func ToApiRepository ( owner * models . User , repo * models . Repository , permission api . Permission ) * api . Repository {
2014-12-14 00:46:00 +03:00
cl , err := repo . CloneLink ( )
if err != nil {
log . Error ( 4 , "CloneLink: %v" , err )
2014-12-13 04:30:32 +03:00
}
return & api . Repository {
2015-08-08 17:43:14 +03:00
Id : repo . ID ,
2014-12-13 04:30:32 +03:00
Owner : * ToApiUser ( owner ) ,
FullName : owner . Name + "/" + repo . Name ,
Private : repo . IsPrivate ,
Fork : repo . IsFork ,
2014-12-14 00:46:00 +03:00
HtmlUrl : setting . AppUrl + owner . Name + "/" + repo . Name ,
CloneUrl : cl . HTTPS ,
SshUrl : cl . SSH ,
2014-12-13 04:30:32 +03:00
Permissions : permission ,
}
}
2014-08-26 14:11:15 +04:00
func SearchRepos ( ctx * middleware . Context ) {
opt := models . SearchOption {
Keyword : path . Base ( ctx . Query ( "q" ) ) ,
Uid : com . StrTo ( ctx . Query ( "uid" ) ) . MustInt64 ( ) ,
Limit : com . StrTo ( ctx . Query ( "limit" ) ) . MustInt ( ) ,
}
if opt . Limit == 0 {
opt . Limit = 10
}
2014-10-25 15:50:19 +04:00
// Check visibility.
if ctx . IsSigned && opt . Uid > 0 {
if ctx . User . Id == opt . Uid {
opt . Private = true
} else {
2015-08-08 17:43:14 +03:00
u , err := models . GetUserByID ( opt . Uid )
2014-10-25 15:50:19 +04:00
if err != nil {
ctx . JSON ( 500 , map [ string ] interface { } {
"ok" : false ,
"error" : err . Error ( ) ,
} )
return
}
2014-12-13 04:30:32 +03:00
if u . IsOrganization ( ) && u . IsOwnedBy ( ctx . User . Id ) {
2014-10-25 15:50:19 +04:00
opt . Private = true
}
// FIXME: how about collaborators?
}
}
2014-08-26 14:11:15 +04:00
repos , err := models . SearchRepositoryByName ( opt )
if err != nil {
ctx . JSON ( 500 , map [ string ] interface { } {
"ok" : false ,
"error" : err . Error ( ) ,
} )
return
}
2014-11-15 01:11:30 +03:00
results := make ( [ ] * api . Repository , len ( repos ) )
2014-08-26 14:11:15 +04:00
for i := range repos {
if err = repos [ i ] . GetOwner ( ) ; err != nil {
ctx . JSON ( 500 , map [ string ] interface { } {
"ok" : false ,
"error" : err . Error ( ) ,
} )
return
}
2014-11-15 01:11:30 +03:00
results [ i ] = & api . Repository {
2015-08-08 17:43:14 +03:00
Id : repos [ i ] . ID ,
2014-11-13 10:32:18 +03:00
FullName : path . Join ( repos [ i ] . Owner . Name , repos [ i ] . Name ) ,
2014-08-26 14:11:15 +04:00
}
}
2014-12-13 04:30:32 +03:00
ctx . JSON ( 200 , map [ string ] interface { } {
2014-08-26 14:11:15 +04:00
"ok" : true ,
"data" : results ,
} )
}
2014-08-29 07:24:37 +04:00
2014-12-13 04:30:32 +03:00
func createRepo ( ctx * middleware . Context , owner * models . User , opt api . CreateRepoOption ) {
2015-08-28 13:33:09 +03:00
repo , err := models . CreateRepository ( owner , models . CreateRepoOptions {
Name : opt . Name ,
Description : opt . Description ,
Gitignores : opt . Gitignore ,
License : opt . License ,
// Readme: form.Readme,
IsPrivate : opt . Private ,
AutoInit : opt . AutoInit ,
} )
2014-12-13 04:30:32 +03:00
if err != nil {
2015-08-08 12:10:34 +03:00
if models . IsErrRepoAlreadyExist ( err ) ||
2015-03-27 00:11:47 +03:00
models . IsErrNameReserved ( err ) ||
models . IsErrNamePatternNotAllowed ( err ) {
2014-12-13 04:30:32 +03:00
ctx . JSON ( 422 , & base . ApiJsonErr { err . Error ( ) , base . DOC_URL } )
} else {
log . Error ( 4 , "CreateRepository: %v" , err )
if repo != nil {
2015-08-08 17:43:14 +03:00
if err = models . DeleteRepository ( ctx . User . Id , repo . ID , ctx . User . Name ) ; err != nil {
2014-12-13 04:30:32 +03:00
log . Error ( 4 , "DeleteRepository: %v" , err )
}
}
ctx . Error ( 500 )
}
return
}
2015-08-19 15:08:57 +03:00
ctx . JSON ( 201 , ToApiRepository ( owner , repo , api . Permission { true , true , true } ) )
2014-12-13 04:30:32 +03:00
}
// POST /user/repos
// https://developer.github.com/v3/repos/#create
func CreateRepo ( ctx * middleware . Context , opt api . CreateRepoOption ) {
// Shouldn't reach this condition, but just in case.
if ctx . User . IsOrganization ( ) {
ctx . JSON ( 422 , "not allowed creating repository for organization" )
return
}
createRepo ( ctx , ctx . User , opt )
}
// POST /orgs/:org/repos
// https://developer.github.com/v3/repos/#create
func CreateOrgRepo ( ctx * middleware . Context , opt api . CreateRepoOption ) {
org , err := models . GetOrgByName ( ctx . Params ( ":org" ) )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2014-12-13 04:30:32 +03:00
ctx . Error ( 404 )
} else {
ctx . Error ( 500 )
}
return
}
if ! org . IsOwnedBy ( ctx . User . Id ) {
ctx . Error ( 403 )
return
}
createRepo ( ctx , org , opt )
}
func MigrateRepo ( ctx * middleware . Context , form auth . MigrateRepoForm ) {
2014-08-29 13:31:53 +04:00
u , err := models . GetUserByName ( ctx . Query ( "username" ) )
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2015-02-22 17:49:25 +03:00
ctx . HandleAPI ( 422 , err )
} else {
ctx . HandleAPI ( 500 , err )
}
2014-08-29 13:31:53 +04:00
return
}
2015-04-16 21:42:24 +03:00
if ! u . ValidatePassword ( ctx . Query ( "password" ) ) {
2015-02-22 17:49:25 +03:00
ctx . HandleAPI ( 422 , "Username or password is not correct." )
2014-08-29 13:31:53 +04:00
return
}
ctxUser := u
2014-08-29 07:24:37 +04:00
// Not equal means current user is an organization.
2014-08-29 13:31:53 +04:00
if form . Uid != u . Id {
2015-08-08 17:43:14 +03:00
org , err := models . GetUserByID ( form . Uid )
2014-08-29 13:31:53 +04:00
if err != nil {
2015-08-05 06:14:17 +03:00
if models . IsErrUserNotExist ( err ) {
2015-02-22 17:49:25 +03:00
ctx . HandleAPI ( 422 , err )
} else {
ctx . HandleAPI ( 500 , err )
}
2014-08-29 07:24:37 +04:00
return
}
ctxUser = org
}
if ctx . HasError ( ) {
2015-02-22 17:49:25 +03:00
ctx . HandleAPI ( 422 , ctx . GetErrMsg ( ) )
2014-08-29 07:24:37 +04:00
return
}
if ctxUser . IsOrganization ( ) {
// Check ownership of organization.
2014-12-13 04:30:32 +03:00
if ! ctxUser . IsOwnedBy ( u . Id ) {
2015-02-22 17:49:25 +03:00
ctx . HandleAPI ( 403 , "Given user is not owner of organization." )
2014-08-29 07:24:37 +04:00
return
}
}
2015-03-25 15:43:07 +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-25 15:43:07 +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 . HandleAPI ( 422 , err )
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 . HandleAPI ( 422 , "Invalid local path, it does not exist or not a directory." )
2014-08-29 07:24:37 +04:00
return
}
2015-02-22 17:49:25 +03:00
repo , err := models . MigrateRepository ( ctxUser , form . RepoName , form . Description , form . Private , form . Mirror , remoteAddr )
if err != nil {
if repo != nil {
2015-08-08 17:43:14 +03:00
if errDelete := models . DeleteRepository ( ctxUser . Id , repo . ID , ctxUser . Name ) ; errDelete != nil {
2015-02-22 17:49:25 +03:00
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
}
2014-08-29 07:24:37 +04:00
}
2015-02-22 17:49:25 +03:00
ctx . HandleAPI ( 500 , err )
return
2014-08-29 07:24:37 +04:00
}
2015-02-22 17:49:25 +03:00
log . Trace ( "Repository migrated: %s/%s" , ctxUser . Name , form . RepoName )
ctx . WriteHeader ( 200 )
2014-08-29 07:24:37 +04:00
}
2014-11-13 10:32:18 +03:00
2014-11-13 20:57:00 +03:00
// GET /user/repos
// https://developer.github.com/v3/repos/#list-your-repositories
2014-11-13 10:32:18 +03:00
func ListMyRepos ( ctx * middleware . Context ) {
ownRepos , err := models . GetRepositories ( ctx . User . Id , true )
if err != nil {
2014-11-17 05:32:26 +03:00
ctx . JSON ( 500 , & base . ApiJsonErr { "GetRepositories: " + err . Error ( ) , base . DOC_URL } )
2014-11-13 10:32:18 +03:00
return
}
numOwnRepos := len ( ownRepos )
2015-01-23 10:54:16 +03:00
accessibleRepos , err := ctx . User . GetAccessibleRepositories ( )
2014-11-13 10:32:18 +03:00
if err != nil {
2015-01-23 10:54:16 +03:00
ctx . JSON ( 500 , & base . ApiJsonErr { "GetAccessibleRepositories: " + err . Error ( ) , base . DOC_URL } )
2014-11-13 10:32:18 +03:00
return
}
2015-01-23 10:54:16 +03:00
repos := make ( [ ] * api . Repository , numOwnRepos + len ( accessibleRepos ) )
2014-11-13 10:32:18 +03:00
for i := range ownRepos {
2014-12-13 04:30:32 +03:00
repos [ i ] = ToApiRepository ( ctx . User , ownRepos [ i ] , api . Permission { true , true , true } )
2014-11-13 10:32:18 +03:00
}
2015-01-23 10:54:16 +03:00
i := numOwnRepos
for repo , access := range accessibleRepos {
2015-08-19 15:08:57 +03:00
repos [ i ] = ToApiRepository ( repo . Owner , repo , api . Permission {
Admin : access >= models . ACCESS_MODE_ADMIN ,
Push : access >= models . ACCESS_MODE_WRITE ,
Pull : true ,
} )
2015-01-23 10:54:16 +03:00
i ++
2014-11-13 10:32:18 +03:00
}
ctx . JSON ( 200 , & repos )
}