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.
2015-12-05 01:16:42 +03:00
package repo
2014-08-26 14:11:15 +04:00
import (
2017-08-17 04:31:34 +03:00
"fmt"
2017-02-11 07:00:01 +03:00
"strings"
2014-08-26 14:11:15 +04:00
2016-11-11 12:39:44 +03:00
api "code.gitea.io/sdk/gitea"
2014-11-15 01:11:30 +03:00
2016-11-10 19:24:48 +03:00
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/convert"
2014-08-26 14:11:15 +04:00
)
2016-11-24 10:04:31 +03:00
// Search repositories via options
2016-03-14 01:49:16 +03:00
func Search ( ctx * context . APIContext ) {
2017-08-21 14:13:47 +03:00
// swagger:route GET /repos/search repository repoSearch
2017-05-02 16:35:59 +03:00
//
// Produces:
// - application/json
//
// Responses:
// 200: SearchResults
// 500: SearchError
2016-03-11 23:33:12 +03:00
opts := & models . SearchRepoOptions {
2017-02-11 07:00:01 +03:00
Keyword : strings . Trim ( ctx . Query ( "q" ) , " " ) ,
2016-07-04 12:27:06 +03:00
OwnerID : ctx . QueryInt64 ( "uid" ) ,
PageSize : convert . ToCorrectPageSize ( ctx . QueryInt ( "limit" ) ) ,
2014-08-26 14:11:15 +04:00
}
2017-05-18 20:35:06 +03:00
if ctx . User != nil && ctx . User . ID == opts . OwnerID {
2017-05-18 17:28:29 +03:00
opts . Searcher = ctx . User
2014-08-26 14:11:15 +04:00
}
2014-10-25 15:50:19 +04:00
// Check visibility.
2016-03-11 23:33:12 +03:00
if ctx . IsSigned && opts . OwnerID > 0 {
2016-07-23 20:08:22 +03:00
if ctx . User . ID == opts . OwnerID {
2016-03-11 23:33:12 +03:00
opts . Private = true
2017-08-23 04:30:54 +03:00
opts . Collaborate = true
2014-10-25 15:50:19 +04:00
} else {
2016-03-11 23:33:12 +03:00
u , err := models . GetUserByID ( opts . OwnerID )
2014-10-25 15:50:19 +04:00
if err != nil {
2017-05-02 16:35:59 +03:00
ctx . JSON ( 500 , api . SearchError {
OK : false ,
Error : err . Error ( ) ,
2014-10-25 15:50:19 +04:00
} )
return
}
2016-07-23 20:08:22 +03:00
if u . IsOrganization ( ) && u . IsOwnedBy ( ctx . User . ID ) {
2016-03-11 23:33:12 +03:00
opts . Private = true
2014-10-25 15:50:19 +04:00
}
2017-08-23 04:30:54 +03:00
if ! u . IsOrganization ( ) {
opts . Collaborate = true
}
2014-10-25 15:50:19 +04:00
}
}
2016-07-04 12:27:06 +03:00
repos , count , err := models . SearchRepositoryByName ( opts )
2014-08-26 14:11:15 +04:00
if err != nil {
2017-05-02 16:35:59 +03:00
ctx . JSON ( 500 , api . SearchError {
OK : false ,
Error : err . Error ( ) ,
2014-08-26 14:11:15 +04:00
} )
return
}
2017-04-30 08:08:09 +03:00
var userID int64
if ctx . IsSigned {
userID = ctx . User . ID
}
2014-11-15 01:11:30 +03:00
results := make ( [ ] * api . Repository , len ( repos ) )
2017-02-10 04:30:26 +03:00
for i , repo := range repos {
if err = repo . GetOwner ( ) ; err != nil {
2017-05-02 16:35:59 +03:00
ctx . JSON ( 500 , api . SearchError {
OK : false ,
Error : err . Error ( ) ,
2014-08-26 14:11:15 +04:00
} )
return
}
2017-04-30 08:08:09 +03:00
accessMode , err := models . AccessLevel ( userID , repo )
2017-02-10 04:30:26 +03:00
if err != nil {
2017-05-02 16:35:59 +03:00
ctx . JSON ( 500 , api . SearchError {
OK : false ,
Error : err . Error ( ) ,
2017-02-10 04:30:26 +03:00
} )
2014-08-26 14:11:15 +04:00
}
2017-02-10 04:30:26 +03:00
results [ i ] = repo . APIFormat ( accessMode )
2014-08-26 14:11:15 +04:00
}
2016-07-04 12:27:06 +03:00
ctx . SetLinkHeader ( int ( count ) , setting . API . MaxResponseItems )
2017-08-17 04:31:34 +03:00
ctx . Header ( ) . Set ( "X-Total-Count" , fmt . Sprintf ( "%d" , count ) )
2017-05-02 16:35:59 +03:00
ctx . JSON ( 200 , api . SearchResults {
OK : true ,
Data : results ,
2014-08-26 14:11:15 +04:00
} )
}
2014-08-29 07:24:37 +04:00
2016-11-24 10:04:31 +03:00
// CreateUserRepo create a repository for a user
2016-03-14 01:49:16 +03:00
func CreateUserRepo ( ctx * context . APIContext , owner * models . User , opt api . CreateRepoOption ) {
2017-09-03 11:20:24 +03:00
repo , err := models . CreateRepository ( ctx . User , owner , models . CreateRepoOptions {
2015-08-28 13:33:09 +03:00
Name : opt . Name ,
Description : opt . Description ,
2015-08-28 14:06:18 +03:00
Gitignores : opt . Gitignores ,
2015-08-28 13:33:09 +03:00
License : opt . License ,
2015-08-28 14:06:18 +03:00
Readme : opt . Readme ,
IsPrivate : opt . Private ,
AutoInit : opt . AutoInit ,
2015-08-28 13:33:09 +03:00
} )
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 ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , err )
2014-12-13 04:30:32 +03:00
} else {
if repo != nil {
2017-09-03 11:20:24 +03:00
if err = models . DeleteRepository ( ctx . User , ctx . User . ID , repo . ID ) ; err != nil {
2014-12-13 04:30:32 +03:00
log . Error ( 4 , "DeleteRepository: %v" , err )
}
}
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "CreateRepository" , err )
2014-12-13 04:30:32 +03:00
}
return
}
2016-12-06 02:48:51 +03:00
ctx . JSON ( 201 , repo . APIFormat ( models . AccessModeOwner ) )
2014-12-13 04:30:32 +03:00
}
2016-10-07 20:17:27 +03:00
// Create one repository of mine
2016-03-14 01:49:16 +03:00
func Create ( ctx * context . APIContext , opt api . CreateRepoOption ) {
2017-08-21 14:13:47 +03:00
// swagger:route POST /user/repos repository user createCurrentUserRepo
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Responses:
// 201: Repository
// 403: forbidden
// 422: validationError
// 500: error
2014-12-13 04:30:32 +03:00
// Shouldn't reach this condition, but just in case.
if ctx . User . IsOrganization ( ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , "not allowed creating repository for organization" )
2014-12-13 04:30:32 +03:00
return
}
2015-12-18 06:57:41 +03:00
CreateUserRepo ( ctx , ctx . User , opt )
2014-12-13 04:30:32 +03:00
}
2016-11-24 10:04:31 +03:00
// CreateOrgRepo create one repository of the organization
2016-03-14 01:49:16 +03:00
func CreateOrgRepo ( ctx * context . APIContext , opt api . CreateRepoOption ) {
2017-08-21 14:13:47 +03:00
// swagger:route POST /org/{org}/repos organization createOrgRepo
2017-05-02 16:35:59 +03:00
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Responses:
// 201: Repository
// 422: validationError
// 403: forbidden
// 500: error
2014-12-13 04:30:32 +03:00
org , err := models . GetOrgByName ( ctx . Params ( ":org" ) )
if err != nil {
2017-07-06 16:30:19 +03:00
if models . IsErrOrgNotExist ( err ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , err )
2014-12-13 04:30:32 +03:00
} else {
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "GetOrgByName" , err )
2014-12-13 04:30:32 +03:00
}
return
}
2016-07-23 20:08:22 +03:00
if ! org . IsOwnedBy ( ctx . User . ID ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 403 , "" , "Given user is not owner of organization." )
2014-12-13 04:30:32 +03:00
return
}
2015-12-18 06:57:41 +03:00
CreateUserRepo ( ctx , org , opt )
2014-12-13 04:30:32 +03:00
}
2016-11-24 10:04:31 +03:00
// Migrate migrate remote git repository to gitea
2016-03-14 01:49:16 +03:00
func Migrate ( ctx * context . APIContext , form auth . MigrateRepoForm ) {
2017-08-21 14:13:47 +03:00
// swagger:route POST /repos/migrate repository repoMigrate
2017-05-02 16:35:59 +03:00
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
//
// Responses:
// 201: Repository
// 422: validationError
// 500: error
2015-09-03 13:17:33 +03:00
ctxUser := ctx . User
2015-11-25 08:55:37 +03:00
// Not equal means context user is an organization,
// or is another user/organization if current user is admin.
2016-11-27 09:03:59 +03:00
if form . UID != ctxUser . ID {
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 ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , err )
2015-02-22 17:49:25 +03:00
} else {
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "GetUserByID" , err )
2015-02-22 17:49:25 +03:00
}
2014-08-29 07:24:37 +04:00
return
}
ctxUser = org
}
if ctx . HasError ( ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , ctx . GetErrMsg ( ) )
2014-08-29 07:24:37 +04:00
return
}
2015-11-25 08:55:37 +03:00
if ctxUser . IsOrganization ( ) && ! ctx . User . IsAdmin {
2014-08-29 07:24:37 +04:00
// Check ownership of organization.
2016-07-23 20:08:22 +03:00
if ! ctxUser . IsOwnedBy ( ctx . User . ID ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 403 , "" , "Given user is not owner of organization." )
2014-08-29 07:24:37 +04:00
return
}
}
2015-11-04 02:40:52 +03:00
remoteAddr , err := form . ParseRemoteAddr ( ctx . User )
if err != nil {
if models . IsErrInvalidCloneAddr ( err ) {
addrErr := err . ( models . ErrInvalidCloneAddr )
switch {
case addrErr . IsURLError :
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , err )
2015-11-04 02:40:52 +03:00
case addrErr . IsPermissionDenied :
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , "You are not allowed to import local repositories." )
2015-11-04 02:40:52 +03:00
case addrErr . IsInvalidPath :
2016-03-14 01:49:16 +03:00
ctx . Error ( 422 , "" , "Invalid local path, it does not exist or not a directory." )
2015-11-04 02:40:52 +03:00
default :
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "ParseRemoteAddr" , "Unknown error type (ErrInvalidCloneAddr): " + err . Error ( ) )
2015-11-04 02:40:52 +03:00
}
} else {
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "ParseRemoteAddr" , err )
2015-02-22 17:49:25 +03:00
}
2014-08-29 07:24:37 +04:00
return
}
2017-09-03 11:20:24 +03:00
repo , err := models . MigrateRepository ( ctx . User , ctxUser , models . MigrateRepoOptions {
2015-10-25 11:26:26 +03:00
Name : form . RepoName ,
Description : form . Description ,
IsPrivate : form . Private || setting . Repository . ForcePrivate ,
IsMirror : form . Mirror ,
RemoteAddr : remoteAddr ,
} )
2015-02-22 17:49:25 +03:00
if err != nil {
if repo != nil {
2017-09-03 11:20:24 +03:00
if errDelete := models . DeleteRepository ( ctx . User , ctxUser . ID , repo . ID ) ; errDelete != nil {
2015-02-22 17:49:25 +03:00
log . Error ( 4 , "DeleteRepository: %v" , errDelete )
}
2014-08-29 07:24:37 +04:00
}
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "MigrateRepository" , models . HandleCloneUserCredentials ( err . Error ( ) , true ) )
2015-02-22 17:49:25 +03:00
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 )
2016-12-06 02:48:51 +03:00
ctx . JSON ( 201 , repo . APIFormat ( models . AccessModeAdmin ) )
2014-08-29 07:24:37 +04:00
}
2015-10-04 18:09:16 +03:00
2016-10-07 20:17:27 +03:00
// Get one repository
2016-03-14 01:49:16 +03:00
func Get ( ctx * context . APIContext ) {
2017-08-21 14:13:47 +03:00
// swagger:route GET /repos/{username}/{reponame} repository repoGet
2017-05-02 16:35:59 +03:00
//
// Produces:
// - application/json
//
// Responses:
// 200: Repository
// 500: error
2017-07-12 04:23:41 +03:00
ctx . JSON ( 200 , ctx . Repo . Repository . APIFormat ( ctx . Repo . AccessMode ) )
2015-10-23 00:46:07 +03:00
}
2016-10-03 13:35:42 +03:00
// GetByID returns a single Repository
func GetByID ( ctx * context . APIContext ) {
2017-08-21 14:13:47 +03:00
// swagger:route GET /repositories/{id} repository repoGetByID
2017-05-02 16:35:59 +03:00
//
// Produces:
// - application/json
//
// Responses:
// 200: Repository
// 500: error
2016-10-03 13:35:42 +03:00
repo , err := models . GetRepositoryByID ( ctx . ParamsInt64 ( ":id" ) )
if err != nil {
if models . IsErrRepoNotExist ( err ) {
ctx . Status ( 404 )
} else {
ctx . Error ( 500 , "GetRepositoryByID" , err )
}
return
}
2017-03-15 03:51:46 +03:00
access , err := models . AccessLevel ( ctx . User . ID , repo )
2016-12-06 02:48:51 +03:00
if err != nil {
2017-07-30 04:13:33 +03:00
ctx . Error ( 500 , "AccessLevel" , err )
return
} else if access < models . AccessModeRead {
ctx . Status ( 404 )
2016-12-06 02:48:51 +03:00
return
}
ctx . JSON ( 200 , repo . APIFormat ( access ) )
2016-10-03 13:35:42 +03:00
}
2016-10-07 20:17:27 +03:00
// Delete one repository
2016-03-14 01:49:16 +03:00
func Delete ( ctx * context . APIContext ) {
2017-08-21 14:13:47 +03:00
// swagger:route DELETE /repos/{username}/{reponame} repository repoDelete
2017-05-02 16:35:59 +03:00
//
// Produces:
// - application/json
//
// Responses:
// 204: empty
// 403: forbidden
// 500: error
2016-12-29 16:17:32 +03:00
if ! ctx . Repo . IsAdmin ( ) {
ctx . Error ( 403 , "" , "Must have admin rights" )
return
}
2016-11-15 01:33:58 +03:00
owner := ctx . Repo . Owner
repo := ctx . Repo . Repository
2015-10-04 18:09:16 +03:00
2016-07-23 20:08:22 +03:00
if owner . IsOrganization ( ) && ! owner . IsOwnedBy ( ctx . User . ID ) {
2016-03-14 01:49:16 +03:00
ctx . Error ( 403 , "" , "Given user is not owner of organization." )
2015-10-04 18:09:16 +03:00
return
}
2017-09-03 11:20:24 +03:00
if err := models . DeleteRepository ( ctx . User , owner . ID , repo . ID ) ; err != nil {
2016-03-14 01:49:16 +03:00
ctx . Error ( 500 , "DeleteRepository" , err )
2015-10-04 18:09:16 +03:00
return
}
2015-10-23 00:46:07 +03:00
log . Trace ( "Repository deleted: %s/%s" , owner . Name , repo . Name )
2015-10-04 18:09:16 +03:00
ctx . Status ( 204 )
}
2017-04-19 14:09:49 +03:00
// MirrorSync adds a mirrored repository to the sync queue
func MirrorSync ( ctx * context . APIContext ) {
2017-08-21 14:13:47 +03:00
// swagger:route POST /repos/{username}/{reponame}/mirror-sync repository repoMirrorSync
2017-05-19 03:20:06 +03:00
//
// Produces:
// - application/json
//
// Responses:
// 200: empty
// 403: forbidden
2017-04-19 14:09:49 +03:00
repo := ctx . Repo . Repository
if ! ctx . Repo . IsWriter ( ) {
ctx . Error ( 403 , "MirrorSync" , "Must have write access" )
}
go models . MirrorQueue . Add ( repo . ID )
ctx . Status ( 200 )
}