refactor API routes and some work for #976
parent
e0bae9547a
commit
56dd430a10
@ -1,73 +0,0 @@ |
||||
// 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 apiv1 |
||||
|
||||
import ( |
||||
"reflect" |
||||
|
||||
"github.com/go-macaron/binding" |
||||
"gopkg.in/macaron.v1" |
||||
|
||||
"github.com/gogits/gogs/modules/auth" |
||||
) |
||||
|
||||
type MarkdownForm struct { |
||||
Text string |
||||
Mode string |
||||
Context string |
||||
} |
||||
|
||||
func (f *MarkdownForm) Validate(ctx *macaron.Context, errs binding.Errors) binding.Errors { |
||||
return validateApiReq(errs, ctx.Data, f) |
||||
} |
||||
|
||||
func validateApiReq(errs binding.Errors, data map[string]interface{}, f auth.Form) binding.Errors { |
||||
if errs.Len() == 0 { |
||||
return errs |
||||
} |
||||
|
||||
data["HasError"] = true |
||||
|
||||
typ := reflect.TypeOf(f) |
||||
val := reflect.ValueOf(f) |
||||
|
||||
if typ.Kind() == reflect.Ptr { |
||||
typ = typ.Elem() |
||||
val = val.Elem() |
||||
} |
||||
|
||||
for i := 0; i < typ.NumField(); i++ { |
||||
field := typ.Field(i) |
||||
|
||||
fieldName := field.Tag.Get("form") |
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" { |
||||
continue |
||||
} |
||||
|
||||
if errs[0].FieldNames[0] == field.Name { |
||||
switch errs[0].Classification { |
||||
case binding.ERR_REQUIRED: |
||||
data["ErrorMsg"] = fieldName + " cannot be empty" |
||||
case binding.ERR_ALPHA_DASH: |
||||
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) characters" |
||||
case binding.ERR_ALPHA_DASH_DOT: |
||||
data["ErrorMsg"] = fieldName + " must be valid alpha or numeric or dash(-_) or dot characters" |
||||
case binding.ERR_MIN_SIZE: |
||||
data["ErrorMsg"] = fieldName + " must contain at least " + auth.GetMinSize(field) + " characters" |
||||
case binding.ERR_MAX_SIZE: |
||||
data["ErrorMsg"] = fieldName + " must contain at most " + auth.GetMaxSize(field) + " characters" |
||||
case binding.ERR_EMAIL: |
||||
data["ErrorMsg"] = fieldName + " is not a valid e-mail address" |
||||
case binding.ERR_URL: |
||||
data["ErrorMsg"] = fieldName + " is not a valid URL" |
||||
default: |
||||
data["ErrorMsg"] = "Unknown error: " + errs[0].Classification |
||||
} |
||||
return errs |
||||
} |
||||
} |
||||
return errs |
||||
} |
@ -0,0 +1,185 @@ |
||||
// Copyright 2015 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 ( |
||||
"strings" |
||||
|
||||
"github.com/go-macaron/binding" |
||||
"gopkg.in/macaron.v1" |
||||
|
||||
api "github.com/gogits/go-gogs-client" |
||||
|
||||
"github.com/gogits/gogs/models" |
||||
"github.com/gogits/gogs/modules/auth" |
||||
"github.com/gogits/gogs/modules/middleware" |
||||
"github.com/gogits/gogs/routers/api/v1/misc" |
||||
"github.com/gogits/gogs/routers/api/v1/repo" |
||||
"github.com/gogits/gogs/routers/api/v1/user" |
||||
) |
||||
|
||||
func RepoAssignment() macaron.Handler { |
||||
return func(ctx *middleware.Context) { |
||||
ctx.Repo = &middleware.RepoContext{} |
||||
|
||||
userName := ctx.Params(":username") |
||||
repoName := ctx.Params(":reponame") |
||||
|
||||
var ( |
||||
owner *models.User |
||||
err error |
||||
) |
||||
|
||||
// Check if the user is the same as the repository owner.
|
||||
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) { |
||||
owner = ctx.User |
||||
} else { |
||||
owner, err = models.GetUserByName(userName) |
||||
if err != nil { |
||||
if models.IsErrUserNotExist(err) { |
||||
ctx.Error(404) |
||||
} else { |
||||
ctx.APIError(500, "GetUserByName", err) |
||||
} |
||||
return |
||||
} |
||||
} |
||||
ctx.Repo.Owner = owner |
||||
|
||||
// Get repository.
|
||||
repo, err := models.GetRepositoryByName(owner.Id, repoName) |
||||
if err != nil { |
||||
if models.IsErrRepoNotExist(err) { |
||||
ctx.Error(404) |
||||
} else { |
||||
ctx.APIError(500, "GetRepositoryByName", err) |
||||
} |
||||
return |
||||
} else if err = repo.GetOwner(); err != nil { |
||||
ctx.APIError(500, "GetOwner", err) |
||||
return |
||||
} |
||||
|
||||
mode, err := models.AccessLevel(ctx.User, repo) |
||||
if err != nil { |
||||
ctx.APIError(500, "AccessLevel", err) |
||||
return |
||||
} |
||||
|
||||
ctx.Repo.AccessMode = mode |
||||
|
||||
// Check access.
|
||||
if ctx.Repo.AccessMode == models.ACCESS_MODE_NONE { |
||||
ctx.Error(404) |
||||
return |
||||
} |
||||
|
||||
ctx.Repo.Repository = repo |
||||
} |
||||
} |
||||
|
||||
// Contexter middleware already checks token for user sign in process.
|
||||
func ReqToken() macaron.Handler { |
||||
return func(ctx *middleware.Context) { |
||||
if !ctx.IsSigned { |
||||
ctx.Error(401) |
||||
return |
||||
} |
||||
} |
||||
} |
||||
|
||||
func ReqBasicAuth() macaron.Handler { |
||||
return func(ctx *middleware.Context) { |
||||
if !ctx.IsBasicAuth { |
||||
ctx.Error(401) |
||||
return |
||||
} |
||||
} |
||||
} |
||||
|
||||
func ReqAdmin() macaron.Handler { |
||||
return func(ctx *middleware.Context) { |
||||
if !ctx.User.IsAdmin { |
||||
ctx.Error(403) |
||||
return |
||||
} |
||||
} |
||||
} |
||||
|
||||
// RegisterRoutes registers all v1 APIs routes to web application.
|
||||
// FIXME: custom form error response
|
||||
func RegisterRoutes(m *macaron.Macaron) { |
||||
bind := binding.Bind |
||||
|
||||
m.Group("/v1", func() { |
||||
// Miscellaneous
|
||||
m.Post("/markdown", bind(api.MarkdownOption{}), misc.Markdown) |
||||
m.Post("/markdown/raw", misc.MarkdownRaw) |
||||
|
||||
// Users
|
||||
m.Group("/users", func() { |
||||
m.Get("/search", user.Search) |
||||
|
||||
m.Group("/:username", func() { |
||||
m.Get("", user.GetInfo) |
||||
|
||||
m.Group("/tokens", func() { |
||||
m.Combo("").Get(user.ListAccessTokens). |
||||
Post(bind(api.CreateAccessTokenOption{}), user.CreateAccessToken) |
||||
}, ReqBasicAuth()) |
||||
}) |
||||
}) |
||||
|
||||
m.Group("/users", func() { |
||||
m.Group("/:username", func() { |
||||
m.Combo("/keys").Get(user.ListPublicKeys). |
||||
Post(ReqAdmin(), user.CreateUserPublicKey) |
||||
}) |
||||
}, ReqToken()) |
||||
|
||||
m.Group("/user", func() { |
||||
m.Group("/keys", func() { |
||||
m.Combo("").Get(user.ListMyPublicKeys). |
||||
Post(bind(api.CreateKeyOption{}), user.CreatePublicKey) |
||||
m.Combo("/:id").Get(user.GetPublicKey). |
||||
Delete(user.DeletePublicKey) |
||||
}) |
||||
}, ReqToken()) |
||||
|
||||
// Repositories
|
||||
m.Combo("/user/repos", ReqToken()).Get(repo.ListMyRepos). |
||||
Post(bind(api.CreateRepoOption{}), repo.Create) |
||||
m.Post("/org/:org/repos", ReqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepo) |
||||
|
||||
m.Group("/repos", func() { |
||||
m.Get("/search", repo.Search) |
||||
}) |
||||
|
||||
m.Group("/repos", func() { |
||||
m.Post("/migrate", bind(auth.MigrateRepoForm{}), repo.Migrate) |
||||
m.Combo("/:username/:reponame").Get(repo.Get). |
||||
Delete(repo.Delete) |
||||
|
||||
m.Group("/:username/:reponame", func() { |
||||
m.Combo("/hooks").Get(repo.ListHooks). |
||||
Post(bind(api.CreateHookOption{}), repo.CreateHook) |
||||
m.Patch("/hooks/:id:int", bind(api.EditHookOption{}), repo.EditHook) |
||||
m.Get("/raw/*", middleware.RepoRef(), repo.GetRawFile) |
||||
m.Get("/archive/*", repo.GetArchive) |
||||
|
||||
m.Group("/keys", func() { |
||||
m.Combo("").Get(repo.ListDeployKeys). |
||||
Post(bind(api.CreateKeyOption{}), repo.CreateDeployKey) |
||||
m.Combo("/:id").Get(repo.GetDeployKey). |
||||
Delete(repo.DeleteDeploykey) |
||||
}) |
||||
}, RepoAssignment()) |
||||
}, ReqToken()) |
||||
|
||||
m.Any("/*", func(ctx *middleware.Context) { |
||||
ctx.Error(404) |
||||
}) |
||||
}) |
||||
} |
@ -0,0 +1,92 @@ |
||||
// Copyright 2015 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 utils |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/Unknwon/com" |
||||
|
||||
api "github.com/gogits/go-gogs-client" |
||||
|
||||
"github.com/gogits/gogs/models" |
||||
"github.com/gogits/gogs/modules/setting" |
||||
) |
||||
|
||||
// ApiUser converts user to its API format.
|
||||
func ApiUser(u *models.User) *api.User { |
||||
return &api.User{ |
||||
ID: u.Id, |
||||
UserName: u.Name, |
||||
FullName: u.FullName, |
||||
Email: u.Email, |
||||
AvatarUrl: u.AvatarLink(), |
||||
} |
||||
} |
||||
|
||||
// ApiRepository converts repository to API format.
|
||||
func ApiRepository(owner *models.User, repo *models.Repository, permission api.Permission) *api.Repository { |
||||
cl := repo.CloneLink() |
||||
return &api.Repository{ |
||||
Id: repo.ID, |
||||
Owner: *ApiUser(owner), |
||||
FullName: owner.Name + "/" + repo.Name, |
||||
Private: repo.IsPrivate, |
||||
Fork: repo.IsFork, |
||||
HtmlUrl: setting.AppUrl + owner.Name + "/" + repo.Name, |
||||
CloneUrl: cl.HTTPS, |
||||
SshUrl: cl.SSH, |
||||
Permissions: permission, |
||||
} |
||||
} |
||||
|
||||
// ApiPublicKey converts public key to its API format.
|
||||
func ApiPublicKey(apiLink string, key *models.PublicKey) *api.PublicKey { |
||||
return &api.PublicKey{ |
||||
ID: key.ID, |
||||
Key: key.Content, |
||||
URL: apiLink + com.ToStr(key.ID), |
||||
Title: key.Name, |
||||
Created: key.Created, |
||||
} |
||||
} |
||||
|
||||
// ApiHook converts webhook to its API format.
|
||||
func ApiHook(repoLink string, w *models.Webhook) *api.Hook { |
||||
config := map[string]string{ |
||||
"url": w.URL, |
||||
"content_type": w.ContentType.Name(), |
||||
} |
||||
if w.HookTaskType == models.SLACK { |
||||
s := w.GetSlackHook() |
||||
config["channel"] = s.Channel |
||||
config["username"] = s.Username |
||||
config["icon_url"] = s.IconURL |
||||
config["color"] = s.Color |
||||
} |
||||
|
||||
return &api.Hook{ |
||||
ID: w.ID, |
||||
Type: w.HookTaskType.Name(), |
||||
URL: fmt.Sprintf("%s/settings/hooks/%d", repoLink, w.ID), |
||||
Active: w.IsActive, |
||||
Config: config, |
||||
Events: w.EventsArray(), |
||||
Updated: w.Updated, |
||||
Created: w.Created, |
||||
} |
||||
} |
||||
|
||||
// ApiDeployKey converts deploy key to its API format.
|
||||
func ApiDeployKey(apiLink string, key *models.DeployKey) *api.DeployKey { |
||||
return &api.DeployKey{ |
||||
ID: key.ID, |
||||
Key: key.Content, |
||||
URL: apiLink + com.ToStr(key.ID), |
||||
Title: key.Name, |
||||
Created: key.Created, |
||||
ReadOnly: true, // All deploy keys are read-only.
|
||||
} |
||||
} |
@ -1 +1 @@ |
||||
0.7.28.1203 Beta |
||||
0.7.29.1204 Beta |
Loading…
Reference in new issue