Skip to content

Commit

Permalink
fix(api): get projects from provider with username (#4916)
Browse files Browse the repository at this point in the history
  • Loading branch information
fsamin authored and richardlt committed Jan 24, 2020
1 parent a607902 commit c08ddfe
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 69 deletions.
172 changes: 110 additions & 62 deletions engine/api/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,100 @@ import (
"github.com/ovh/cds/sdk/log"
)

func (api *API) getProjectsHandler_FilterByRepo(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
withPermissions := r.FormValue("permission")
filterByRepo := r.FormValue("repo")

var projects sdk.Projects
var err error
var filterByRepoFunc = func(db gorp.SqlExecutor, store cache.Store, p *sdk.Project) error {
//Filter the applications by repo
apps := []sdk.Application{}
for i := range p.Applications {
if p.Applications[i].RepositoryFullname == filterByRepo {
apps = append(apps, p.Applications[i])
}
}
p.Applications = apps
ws := []sdk.Workflow{}
//Filter the workflow by applications
for i := range p.Workflows {
w, err := workflow.LoadByID(ctx, db, store, p, p.Workflows[i].ID, workflow.LoadOptions{})
if err != nil {
return err
}

//Checks the workflow use one of the applications
wapps:
for _, a := range w.Applications {
for _, b := range apps {
if a.Name == b.Name {
ws = append(ws, p.Workflows[i])
break wapps
}
}
}
}
p.Workflows = ws
return nil
}

opts := []project.LoadOptionFunc{
project.LoadOptions.WithPermission,
}
opts = append(opts, filterByRepoFunc)

if isMaintainer(ctx) || isAdmin(ctx) {
projects, err = project.LoadAllByRepo(ctx, api.mustDB(), api.Cache, filterByRepo, opts...)
if err != nil {
return err
}
} else {
projects, err = project.LoadAllByRepoAndGroupIDs(ctx, api.mustDB(), api.Cache, getAPIConsumer(ctx).GetGroupIDs(), filterByRepo, opts...)
if err != nil {
return err
}
}

pKeys := projects.Keys()
perms, err := permission.LoadProjectMaxLevelPermission(ctx, api.mustDB(), pKeys, getAPIConsumer(ctx).GetGroupIDs())
if err != nil {
return err
}
for i := range projects {
if isAdmin(ctx) {
projects[i].Permissions = sdk.Permissions{Readable: true, Writable: true, Executable: true}
continue
}
projects[i].Permissions = perms[projects[i].Key]
if isMaintainer(ctx) {
projects[i].Permissions.Readable = true
}
}

if strings.ToUpper(withPermissions) == "W" {
res := make([]sdk.Project, 0, len(projects))
for _, p := range projects {
if p.Permissions.Writable {
res = append(res, p)
}
}
projects = res
}

return service.WriteJSON(w, projects, http.StatusOK)
}

func (api *API) getProjectsHandler() service.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
withPermissions := r.FormValue("permission")
filterByRepo := r.FormValue("repo")
if filterByRepo != "" {
return api.getProjectsHandler_FilterByRepo(ctx, w, r)
}

withApplications := FormBool(r, "application")
withWorkflows := FormBool(r, "workflow")
filterByRepo := r.FormValue("repo")
withPermissions := r.FormValue("permission")
withIcon := FormBool(r, "withIcon")

requestedUserName := r.Header.Get("X-Cds-Username")
Expand Down Expand Up @@ -64,7 +152,6 @@ func (api *API) getProjectsHandler() service.Handler {

var projects sdk.Projects
var err error

switch {
case isMaintainer(ctx) && requestedUser == nil:
projects, err = project.LoadAll(ctx, api.mustDB(), api.Cache, opts...)
Expand All @@ -83,71 +170,32 @@ func (api *API) getProjectsHandler() service.Handler {
return err
}

var groupIDs []int64
var admin bool
var maintainer bool
if requestedUser == nil {
groupIDs = getAPIConsumer(ctx).GetGroupIDs()
admin = isAdmin(ctx)
maintainer = isMaintainer(ctx)
} else {
groupIDs = requestedUser.GetGroupIDs()
admin = requestedUser.Ring == sdk.UserRingAdmin
maintainer = requestedUser.Ring == sdk.UserRingMaintainer
}

pKeys := projects.Keys()
perms, err := permission.LoadProjectMaxLevelPermission(ctx, api.mustDB(), pKeys, getAPIConsumer(ctx).GetGroupIDs())
perms, err := permission.LoadProjectMaxLevelPermission(ctx, api.mustDB(), pKeys, groupIDs)
if err != nil {
return err
}
for i := range projects {
projects[i].Permissions = perms[projects[i].Key]
}

if filterByRepo == "" {
if strings.ToUpper(withPermissions) == "W" {
res := make([]sdk.Project, 0, len(projects))
for _, p := range projects {
if p.Permissions.Writable {
res = append(res, p)
}
}
projects = res
if admin {
projects[i].Permissions = sdk.Permissions{Readable: true, Writable: true, Executable: true}
continue
}

return service.WriteJSON(w, projects, http.StatusOK)
}

var filterByRepoFunc = func(db gorp.SqlExecutor, store cache.Store, p *sdk.Project) error {
//Filter the applications by repo
apps := []sdk.Application{}
for i := range p.Applications {
if p.Applications[i].RepositoryFullname == filterByRepo {
apps = append(apps, p.Applications[i])
}
}
p.Applications = apps
ws := []sdk.Workflow{}
//Filter the workflow by applications
for i := range p.Workflows {
w, err := workflow.LoadByID(ctx, db, store, p, p.Workflows[i].ID, workflow.LoadOptions{})
if err != nil {
return err
}

//Checks the workflow use one of the applications
wapps:
for _, a := range w.Applications {
for _, b := range apps {
if a.Name == b.Name {
ws = append(ws, p.Workflows[i])
break wapps
}
}
}
}
p.Workflows = ws
return nil
}
opts = append(opts, filterByRepoFunc)

if isMaintainer(ctx) || isAdmin(ctx) {
projects, err = project.LoadAllByRepo(ctx, api.mustDB(), api.Cache, filterByRepo, opts...)
if err != nil {
return err
}
} else {
projects, err = project.LoadAllByRepoAndGroupIDs(ctx, api.mustDB(), api.Cache, getAPIConsumer(ctx).GetGroupIDs(), filterByRepo, opts...)
if err != nil {
return err
projects[i].Permissions = perms[projects[i].Key]
if maintainer {
projects[i].Permissions.Readable = true
}
}

Expand Down
29 changes: 22 additions & 7 deletions engine/api/project_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ func Test_getProjectsHandler_WithWPermissionShouldReturnOneProject(t *testing.T)
assert.Len(t, projs, 1, "should have one project")
}

func Test_getprojectsHandler_AsProvider(t *testing.T) {
func Test_getProjectsHandler_AsProvider(t *testing.T) {
api, tsURL, tsClose := newTestServer(t)
defer tsClose()

Expand Down Expand Up @@ -339,19 +339,34 @@ func Test_getprojectsHandler_AsProviderWithRequestedUsername(t *testing.T) {
app := &sdk.Application{
Name: sdk.RandomString(10),
}
test.NoError(t, application.Insert(api.mustDB(), api.Cache, proj, app))
require.NoError(t, application.Insert(api.mustDB(), api.Cache, proj, app))

sdkclient := cdsclient.NewProviderClient(cdsclient.ProviderConfig{
// Call with an admin
sdkclientAdmin := cdsclient.NewProviderClient(cdsclient.ProviderConfig{
Host: tsURL,
Token: jws,
})

projs, err := sdkclient.ProjectsList(cdsclient.FilterByUser(u.Username))
test.NoError(t, err)
projs, err := sdkclientAdmin.ProjectsList()
require.NoError(t, err)
assert.True(t, len(projs) >= 1)

apps, err := sdkclientAdmin.ApplicationsList(pkey, cdsclient.FilterByUser(u.Username), cdsclient.WithUsage(), cdsclient.FilterByWritablePermission())
require.NoError(t, err)
assert.True(t, len(apps) >= 1)

// Call like a provider
sdkclientProvider := cdsclient.NewProviderClient(cdsclient.ProviderConfig{
Host: tsURL,
Token: jws,
})

projs, err = sdkclientProvider.ProjectsList(cdsclient.FilterByUser(u.Username), cdsclient.FilterByWritablePermission())
require.NoError(t, err)
assert.Len(t, projs, 1)

apps, err := sdkclient.ApplicationsList(pkey, cdsclient.FilterByUser(u.Username), cdsclient.WithUsage())
test.NoError(t, err)
apps, err = sdkclientProvider.ApplicationsList(pkey, cdsclient.FilterByUser(u.Username), cdsclient.WithUsage(), cdsclient.FilterByWritablePermission())
require.NoError(t, err)
assert.Len(t, apps, 1)
}

Expand Down
4 changes: 4 additions & 0 deletions sdk/cdsclient/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,10 @@ func (c *client) RequestJSON(ctx context.Context, method, path string, in interf
return res, nil, code, sdk.WithStack(fmt.Errorf("HTTP %d", code))
}

if code == 204 {
return res, header, code, nil
}

if out != nil {
if err := json.Unmarshal(res, out); err != nil {
return res, nil, code, sdk.WithStack(err)
Expand Down

0 comments on commit c08ddfe

Please sign in to comment.