Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions core/servicedata/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ package servicedata
import "errors"

var (
ErrInvalidDetail = errors.New("invalid service data detail")
ErrConflict = errors.New("key already exist")
ErrNotExist = errors.New("service data not exist")
ErrInvalidDetail = errors.New("invalid service data detail")
ErrConflict = errors.New("key already exist")
ErrNotExist = errors.New("service data not exist")
ErrProjectMissing = errors.New("project details missing")
)
59 changes: 59 additions & 0 deletions core/servicedata/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package servicedata

import (
"context"
"fmt"
"slices"

"github.com/goto/shield/core/action"
Expand All @@ -11,6 +12,8 @@ import (
"github.com/goto/shield/core/resource"
"github.com/goto/shield/core/user"
"github.com/goto/shield/internal/schema"
"github.com/goto/shield/pkg/errors"
"github.com/goto/shield/pkg/uuid"
)

const (
Expand Down Expand Up @@ -234,3 +237,59 @@ func (s Service) Get(ctx context.Context, filter Filter) ([]ServiceData, error)

return resultSD, nil
}

func (s Service) ListUsers(ctx context.Context, filter ListUsersFilter) ([]user.User, error) {
// fetch current user
currentUser, err := s.userService.FetchCurrentUser(ctx)
if err != nil {
return []user.User{}, err
}

if len(filter.ServiceData) > 0 && filter.Project == "" {
return []user.User{}, ErrProjectMissing
}

servicedataKeyResourceIds := []string{}

if len(filter.ServiceData) > 0 {
projectSlug := filter.Project
if uuid.IsValid(filter.Project) {
prj, err := s.projectService.Get(ctx, filter.Project)
if err != nil {
return []user.User{}, err
}
projectSlug = prj.Slug
}
for k, _ := range filter.ServiceData {
key, err := s.repository.GetKeyByURN(ctx, fmt.Sprintf("%s:servicedata_key:%s", projectSlug, k))
if err != nil {
return []user.User{}, err
}

permission, err := s.relationService.CheckPermission(ctx, currentUser, namespace.Namespace{ID: schema.ServiceDataKeyNamespace}, key.ResourceID, action.Action{ID: editActionID})
if err != nil {
return []user.User{}, err
}
if !permission {
return []user.User{}, errors.ErrForbidden
}
}
} else if filter.WithServiceData {
servicedataKeyResourceIds, err = s.relationService.LookupResources(ctx, keyNamespace, viewActionID, userNamespace, currentUser.ID)
if err != nil {
return []user.User{}, err
}
}
fmt.Println(servicedataKeyResourceIds)

if len(filter.ServiceData) > 0 {
serviceData := [][]string{}
for k, v := range filter.ServiceData {
serviceData = append(serviceData, []string{k, v})
}

s.repository.ListUsersHavingData(ctx, filter, serviceData)
}

return []user.User{}, nil
}
11 changes: 11 additions & 0 deletions core/servicedata/servicedata.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package servicedata
import (
"context"
"fmt"

"github.com/goto/shield/core/user"
)

type Repository interface {
Expand All @@ -11,6 +13,7 @@ type Repository interface {
Upsert(ctx context.Context, servicedata ServiceData) (ServiceData, error)
GetKeyByURN(ctx context.Context, URN string) (Key, error)
Get(ctx context.Context, filter Filter) ([]ServiceData, error)
ListUsers(ctx context.Context, filter ListUsersFilter, servicedataKeyResourceIds []string) ([]user.User, error)
}

type Transactor interface {
Expand Down Expand Up @@ -45,6 +48,14 @@ type Filter struct {
Project string
}

type ListUsersFilter struct {
ServiceData map[string]string
Project string
Limit int32
Page int32
WithServiceData bool
}

func (key Key) CreateURN() string {
return fmt.Sprintf("%s:servicedata_key:%s", key.ProjectSlug, key.Key)
}
55 changes: 55 additions & 0 deletions internal/store/postgres/servicedata_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (

"github.com/doug-martin/goqu/v9"
"github.com/goto/shield/core/servicedata"
"github.com/goto/shield/core/user"
"github.com/goto/shield/internal/schema"
"github.com/goto/shield/pkg/db"
newrelic "github.com/newrelic/go-agent/v3/newrelic"
"go.nhat.io/otelsql"
Expand Down Expand Up @@ -244,6 +246,59 @@ func (r ServiceDataRepository) Get(ctx context.Context, filter servicedata.Filte
return transformedServiceData, nil
}

func (r ServiceDataRepository) ListUsersHavingData(ctx context.Context, filter servicedata.ListUsersFilter, serviceData [][]string) ([]user.User, error) {
var defaultLimit int32 = 50
var defaultPage int32 = 1
if filter.Limit < 1 {
filter.Limit = defaultLimit
}
if filter.Page < 1 {
filter.Page = defaultPage
}

_ = (filter.Page - 1) * filter.Limit

subquery := dialect.Select("sd.entity_id").From(goqu.T(TABLE_SERVICE_DATA).As("sd")).
Join(goqu.T(TABLE_SERVICE_DATA_KEYS).As("sk"), goqu.On(
goqu.I("sk.id").Eq(goqu.I("sd.key_id")))).
Where(goqu.Ex{"sk.project_id": filter.Project},
goqu.Ex{"sd.namespace_id": schema.UserPrincipal},
goqu.L(
"(sk.key, sd.value)",
).In(serviceData)).
GroupBy(goqu.I("sd.entity_id"))

// Main query
query, params, err := dialect.Select(
goqu.I("u.id"),
goqu.I("u.name"),
goqu.I("u.email"),
goqu.I("u.created_at"),
goqu.I("u.updated_at"),
).From(goqu.T(TABLE_USERS).As("u")).Join(subquery.As("sd"), goqu.On(
goqu.Cast(goqu.C("id"), "TEXT").Eq(goqu.I("sd.entity_id")))).ToSQL()
if err != nil {
return []user.User{}, nil
}

var users []User
if err = r.dbc.WithTimeout(ctx, func(ctx context.Context) error {
return r.dbc.SelectContext(ctx, &users, query, params...)
}); err != nil {
err = checkPostgresError(err)
switch {
case errors.Is(err, sql.ErrNoRows):
return []user.User{}, nil
case errors.Is(err, errInvalidTexRepresentation):
return []user.User{}, servicedata.ErrInvalidDetail
default:
return []user.User{}, err
}
}

return []user.User{}, nil
}

func (r ServiceDataRepository) WithTransaction(ctx context.Context) context.Context {
return r.dbc.WithTransaction(ctx, sql.TxOptions{})
}
Expand Down