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 {
Id : repo . Id ,
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 {
u , err := models . GetUserById ( opt . Uid )
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 {
2014-11-13 10:32:18 +03:00
Id : repos [ i ] . Id ,
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 ) {
repo , err := models . CreateRepository ( owner , opt . Name , opt . Description ,
opt . Gitignore , opt . License , opt . Private , false , opt . AutoInit )
if err != nil {
if err == models . ErrRepoAlreadyExist ||
err == models . ErrRepoNameIllegal {
ctx . JSON ( 422 , & base . ApiJsonErr { err . Error ( ) , base . DOC_URL } )
} else {
log . Error ( 4 , "CreateRepository: %v" , err )
if repo != nil {
if err = models . DeleteRepository ( ctx . User . Id , repo . Id , ctx . User . Name ) ; err != nil {
log . Error ( 4 , "DeleteRepository: %v" , err )
}
}
ctx . Error ( 500 )
}
return
}
ctx . JSON ( 200 , ToApiRepository ( owner , repo , api . Permission { true , true , true } ) )
}
// 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 {
if err == models . ErrUserNotExist {
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-02-22 17:49:25 +03:00
if err == models . ErrUserNotExist {
ctx . HandleAPI ( 422 , err )
} else {
ctx . HandleAPI ( 500 , err )
}
2014-08-29 13:31:53 +04:00
return
}
if ! u . ValidtePassword ( 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 {
2014-08-29 07:24:37 +04:00
org , err := models . GetUserById ( form . Uid )
2014-08-29 13:31:53 +04:00
if err != nil {
2015-02-22 17:49:25 +03:00
if err == models . ErrUserNotExist {
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-11 16:21:05 +03:00
// Remote address can be HTTP/HTTPS URL or local path.
2015-02-22 17:49:25 +03:00
remoteAddr := form . CloneAddr
if strings . HasPrefix ( form . CloneAddr , "http" ) {
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 {
if errDelete := models . DeleteRepository ( ctxUser . Id , repo . Id , ctxUser . Name ) ; errDelete != nil {
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 {
if err = repo . GetOwner ( ) ; err != nil {
2014-11-17 05:32:26 +03:00
ctx . JSON ( 500 , & base . ApiJsonErr { "GetOwner: " + err . Error ( ) , base . DOC_URL } )
2014-11-13 10:32:18 +03:00
return
}
2015-01-23 10:54:16 +03:00
2015-02-09 14:36:33 +03:00
repos [ i ] = ToApiRepository ( repo . Owner , repo , api . Permission { false , access >= models . ACCESS_MODE_WRITE , true } )
2014-11-13 10:32:18 +03:00
// FIXME: cache result to reduce DB query?
2015-01-23 10:54:16 +03:00
if repo . Owner . IsOrganization ( ) && repo . Owner . IsOwnedBy ( ctx . User . Id ) {
repos [ i ] . Permissions . Admin = true
2014-11-13 10:32:18 +03:00
}
2015-01-23 10:54:16 +03:00
i ++
2014-11-13 10:32:18 +03:00
}
ctx . JSON ( 200 , & repos )
}