Skip to content

Commit

Permalink
feat: add slug support for group, org, and projects API (#117)
Browse files Browse the repository at this point in the history
* Used Query Builder

* Error Handling for query builder

* Typo corrected in a function call

* Rectified error in GetGroup() function

* feat: Used Query Builder in user.go

* feat: Used Query Builder in user.go

* Rectified errors in user.go

* Delete user_test.go

* Update gitignore

* Locally generated proto

* Implemented pagination, filteration - query params

* feat: Implemented Pagination, filtration

* Error handling and global scope for dialect

* Updated user_test.go test structure

* feat(shield): Cursor pagination and fiter

* Test func paramas changed
TODO: Test func returns and validations

* Add constants for freq used strings

* Fix: user_test.go

* Refactor raw queries
namespace.go
relation.go
org.go

* lint changes

* Uncomment Admin APIs

* Pagination changes

* Refactor: Used Query builder

* feat(shield): Offset pagination and filter

* Lint changes

* Sync with pagination

* Sync with pagination

* feat: add support for slug in groups API

* .gitignore

* Add slug support
APIs: Groups, Org, Projects

* feat: allow storing bool and num in metadata

* golang version upgrade 1.16 -> 1.18

* golang version upgrade 1.16 -> 1.18

* lint changes

* Update .gitignore

* Go version upgrade from 1.16 -> 1.18

* Go version upgrade from 1.16 -> 1.18

* Add slug support for update API

* Add slug support for update API

* increase slug support for APIs

* increase slug support for APIs

* slug support for add/rem admin APIs

* fix: errors
  • Loading branch information
niharbansal02 authored Jul 25, 2022
1 parent e7930c5 commit 9723d67
Show file tree
Hide file tree
Showing 10 changed files with 247 additions and 102 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ rules/test.yaml
ignore/
vendor/
buf.lock
buf.yaml
buf.yaml
19 changes: 11 additions & 8 deletions internal/group/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ package group
import (
"context"
"errors"

"github.com/odpf/shield/internal/bootstrap/definition"
shieldError "github.com/odpf/shield/utils/errors"
"strings"

"github.com/odpf/shield/internal/authz"
"github.com/odpf/shield/internal/bootstrap/definition"
"github.com/odpf/shield/internal/permission"

"github.com/odpf/shield/model"
shieldError "github.com/odpf/shield/utils/errors"
)

type Service struct {
Expand Down Expand Up @@ -88,14 +87,15 @@ func (s Service) AddUsersToGroup(ctx context.Context, groupId string, userIds []
return []model.User{}, err
}

groupId = strings.TrimSpace(groupId)
group, err := s.Store.GetGroup(ctx, groupId)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: groupId,
Idxa: group.Id,
Namespace: definition.TeamNamespace,
},
definition.ManageTeamAction,
Expand Down Expand Up @@ -130,14 +130,15 @@ func (s Service) RemoveUserFromGroup(ctx context.Context, groupId string, userId
return []model.User{}, err
}

groupId = strings.TrimSpace(groupId)
group, err := s.Store.GetGroup(ctx, groupId)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: groupId,
Idxa: group.Id,
Namespace: definition.TeamNamespace,
},
definition.ManageTeamAction,
Expand Down Expand Up @@ -187,14 +188,15 @@ func (s Service) AddAdminsToGroup(ctx context.Context, groupId string, userIds [
return []model.User{}, err
}

groupId = strings.TrimSpace(groupId)
group, err := s.Store.GetGroup(ctx, groupId)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: groupId,
Idxa: group.Id,
Namespace: definition.TeamNamespace,
},
definition.ManageTeamAction,
Expand Down Expand Up @@ -234,14 +236,15 @@ func (s Service) RemoveAdminFromGroup(ctx context.Context, groupId string, userI
return []model.User{}, err
}

groupId = strings.TrimSpace(groupId)
group, err := s.Store.GetGroup(ctx, groupId)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: groupId,
Idxa: group.Id,
Namespace: definition.TeamNamespace,
},
definition.ManageTeamAction,
Expand Down
10 changes: 6 additions & 4 deletions internal/org/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package org
import (
"context"
"errors"
"strings"

"github.com/odpf/shield/internal/bootstrap/definition"
"github.com/odpf/shield/internal/permission"
shieldError "github.com/odpf/shield/utils/errors"

"github.com/odpf/shield/model"
shieldError "github.com/odpf/shield/utils/errors"
)

type Service struct {
Expand Down Expand Up @@ -75,14 +75,15 @@ func (s Service) AddAdmin(ctx context.Context, id string, userIds []string) ([]m
return []model.User{}, err
}

id = strings.TrimSpace(id)
org, err := s.Store.GetOrg(ctx, id)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: id,
Idxa: org.Id,
Namespace: definition.OrgNamespace,
},
definition.ManageOrganizationAction,
Expand Down Expand Up @@ -121,14 +122,15 @@ func (s Service) RemoveAdmin(ctx context.Context, id string, userId string) ([]m
return []model.User{}, err
}

id = strings.TrimSpace(id)
org, err := s.Store.GetOrg(ctx, id)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: id,
Idxa: org.Id,
Namespace: definition.OrgNamespace,
},
definition.ManageOrganizationAction,
Expand Down
10 changes: 6 additions & 4 deletions internal/project/project.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ package project
import (
"context"
"errors"
"strings"

"github.com/odpf/shield/internal/bootstrap/definition"
"github.com/odpf/shield/internal/permission"
shieldError "github.com/odpf/shield/utils/errors"

"github.com/odpf/shield/model"
shieldError "github.com/odpf/shield/utils/errors"
)

type Service struct {
Expand Down Expand Up @@ -83,14 +83,15 @@ func (s Service) AddAdmin(ctx context.Context, id string, userIds []string) ([]m
return []model.User{}, err
}

id = strings.TrimSpace(id)
project, err := s.Store.GetProject(ctx, id)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: id,
Idxa: project.Id,
Namespace: definition.ProjectNamespace,
},
definition.ManageProjectAction,
Expand Down Expand Up @@ -129,14 +130,15 @@ func (s Service) RemoveAdmin(ctx context.Context, id string, userId string) ([]m
return []model.User{}, err
}

id = strings.TrimSpace(id)
project, err := s.Store.GetProject(ctx, id)

if err != nil {
return []model.User{}, err
}

isAuthorized, err := s.Permissions.CheckPermission(ctx, currentUser, model.Resource{
Idxa: id,
Idxa: project.Id,
Namespace: definition.ProjectNamespace,
},
definition.ManageProjectAction,
Expand Down
112 changes: 82 additions & 30 deletions store/postgres/groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"strings"
"time"

"github.com/doug-martin/goqu/v9"
Expand All @@ -27,6 +28,7 @@ type Group struct {
DeletedAt sql.NullTime `db:"deleted_at"`
}

// *Get Groups Query
func buildGetGroupsBySlugQuery(dialect goqu.DialectWrapper) (string, error) {
getGroupsBySlugQuery, _, err := dialect.From(TABLE_GROUPS).Where(goqu.Ex{
"slug": goqu.L("$1"),
Expand All @@ -35,6 +37,16 @@ func buildGetGroupsBySlugQuery(dialect goqu.DialectWrapper) (string, error) {
return getGroupsBySlugQuery, err
}

func buildGetGroupsByIdQuery(dialect goqu.DialectWrapper) (string, error) {
getGroupsByIdQuery, _, err := dialect.From(TABLE_GROUPS).Where(goqu.ExOr{
"id": goqu.L("$1"),
"slug": goqu.L("$2"),
}).ToSQL()

return getGroupsByIdQuery, err
}

// *Create Group Query
func buildCreateGroupQuery(dialect goqu.DialectWrapper) (string, error) {
createGroupsQuery, _, err := dialect.Insert(TABLE_GROUPS).Rows(
goqu.Record{
Expand All @@ -46,35 +58,13 @@ func buildCreateGroupQuery(dialect goqu.DialectWrapper) (string, error) {
return createGroupsQuery, err
}

func buildGetGroupsByIdQuery(dialect goqu.DialectWrapper) (string, error) {
getGroupsByIdQuery, _, err := dialect.From(TABLE_GROUPS).Where(goqu.Or(
goqu.C("id").Eq(goqu.L("$1")),
goqu.C("slug").Eq(goqu.L("$2")),
)).ToSQL()

return getGroupsByIdQuery, err
}

// *List Groups Query
func buildListGroupsQuery(dialect goqu.DialectWrapper) (string, error) {
listGroupsQuery, _, err := dialect.From(TABLE_GROUPS).ToSQL()

return listGroupsQuery, err
}

func buildUpdateGroupQuery(dialect goqu.DialectWrapper) (string, error) {
updateGroupQuery, _, err := dialect.Update(TABLE_GROUPS).
Set(goqu.Record{
"name": goqu.L("$2"),
"slug": goqu.L("$3"),
"org_id": goqu.L("$4"),
"metadata": goqu.L("$5"),
"updated_at": goqu.L("now()"),
}).Where(goqu.Ex{"id": goqu.L("$1")}).
Returning(&Group{}).ToSQL()

return updateGroupQuery, err
}

func buildListGroupUsersQuery(dialect goqu.DialectWrapper) (string, error) {
listGroupUsersQuery, _, err := dialect.Select(
goqu.I("u.id").As("id"),
Expand All @@ -99,20 +89,53 @@ func buildListGroupUsersQuery(dialect goqu.DialectWrapper) (string, error) {

func buildListUserGroupRelationsQuery(dialect goqu.DialectWrapper) (string, error) {
listUserGroupRelationsQuery, _, err := dialect.From(TABLE_RELATION).Where(goqu.Ex{
"subject_namespace_id": goqu.L(definition.UserNamespace.Id),
"object_namespace_id": goqu.L(definition.TeamNamespace.Id),
"subject_namespace_id": definition.UserNamespace.Id,
"object_namespace_id": definition.TeamNamespace.Id,
"subject_id": goqu.L("$1"),
"object_id": goqu.L("$2"),
}).ToSQL()

return listUserGroupRelationsQuery, err
}

// *Update Group Query
func buildUpdateGroupBySlugQuery(dialect goqu.DialectWrapper) (string, error) {
updateGroupQuery, _, err := dialect.Update(TABLE_GROUPS).Set(
goqu.Record{
"name": goqu.L("$2"),
"slug": goqu.L("$3"),
"org_id": goqu.L("$4"),
"metadata": goqu.L("$5"),
"updated_at": goqu.L("now()"),
}).Where(goqu.Ex{
"slug": goqu.L("$1"),
}).Returning(&Group{}).ToSQL()

return updateGroupQuery, err
}

func buildUpdateGroupByIdQuery(dialect goqu.DialectWrapper) (string, error) {
updateGroupQuery, _, err := dialect.Update(TABLE_GROUPS).Set(
goqu.Record{
"name": goqu.L("$3"),
"slug": goqu.L("$4"),
"org_id": goqu.L("$5"),
"metadata": goqu.L("$6"),
"updated_at": goqu.L("now()"),
}).Where(goqu.ExOr{
"id": goqu.L("$1"),
"slug": goqu.L("$2"),
}).Returning(&Group{}).ToSQL()

return updateGroupQuery, err
}

func (s Store) GetGroup(ctx context.Context, id string) (model.Group, error) {
var fetchedGroup Group
var getGroupsQuery string
var err error
var isUuid = isUUID(id)
id = strings.TrimSpace(id)
isUuid := isUUID(id)

if isUuid {
getGroupsQuery, err = buildGetGroupsByIdQuery(dialect)
Expand Down Expand Up @@ -224,15 +247,30 @@ func (s Store) UpdateGroup(ctx context.Context, toUpdate model.Group) (model.Gro
return model.Group{}, fmt.Errorf("%w: %s", parseErr, err)
}

updateGroupQuery, err := buildUpdateGroupQuery(dialect)
var updateGroupQuery string
toUpdate.Id = strings.TrimSpace(toUpdate.Id)
isUuid := isUUID(toUpdate.Id)

if isUuid {
updateGroupQuery, err = buildUpdateGroupByIdQuery(dialect)
} else {
updateGroupQuery, err = buildUpdateGroupBySlugQuery(dialect)
}
if err != nil {
return model.Group{}, fmt.Errorf("%w: %s", queryErr, err)
}

var updatedGroup Group
err = s.DB.WithTimeout(ctx, func(ctx context.Context) error {
return s.DB.GetContext(ctx, &updatedGroup, updateGroupQuery, toUpdate.Id, toUpdate.Name, toUpdate.Slug, toUpdate.Organization.Id, marshaledMetadata)
})

if isUuid {
err = s.DB.WithTimeout(ctx, func(ctx context.Context) error {
return s.DB.GetContext(ctx, &updatedGroup, updateGroupQuery, toUpdate.Id, toUpdate.Id, toUpdate.Name, toUpdate.Slug, toUpdate.Organization.Id, marshaledMetadata)
})
} else {
err = s.DB.WithTimeout(ctx, func(ctx context.Context) error {
return s.DB.GetContext(ctx, &updatedGroup, updateGroupQuery, toUpdate.Id, toUpdate.Name, toUpdate.Slug, toUpdate.Organization.Id, marshaledMetadata)
})
}

if errors.Is(err, sql.ErrNoRows) {
return model.Group{}, group.GroupDoesntExist
Expand All @@ -254,6 +292,13 @@ func (s Store) ListGroupUsers(ctx context.Context, groupId string, roleId string
role = roleId
}

groupId = strings.TrimSpace(groupId) //groupId can be uuid or slug
fetchedGroup, err := s.GetGroup(ctx, groupId)
if err != nil {
return []model.User{}, err
}
groupId = fetchedGroup.Id

listGroupUsersQuery, err := buildListGroupUsersQuery(dialect)
if err != nil {
return []model.User{}, fmt.Errorf("%w: %s", queryErr, err)
Expand Down Expand Up @@ -294,6 +339,13 @@ func (s Store) ListUserGroupRelations(ctx context.Context, userId string, groupI
return []model.Relation{}, fmt.Errorf("%w: %s", queryErr, err)
}

groupId = strings.TrimSpace(groupId)
fetchedGroup, err := s.GetGroup(ctx, groupId)
if err != nil {
return []model.Relation{}, err
}
groupId = fetchedGroup.Id

err = s.DB.WithTimeout(ctx, func(ctx context.Context) error {
return s.DB.SelectContext(ctx, &fetchedRelations, listUserGroupRelationsQuery, userId, groupId)
})
Expand Down
Loading

0 comments on commit 9723d67

Please sign in to comment.