Add organization member list

Signed-off-by: gearnode <bryan@frimin.fr>
This commit is contained in:
gearnode
2025-03-14 09:38:01 +01:00
parent b3751636b2
commit 87f7654b10
17 changed files with 1401 additions and 344 deletions

View File

@@ -109,6 +109,13 @@ type Organization implements Node {
name: String!
logoUrl: String @goField(forceResolver: true)
users(
first: Int
after: CursorKey
last: Int
before: CursorKey
): UserConnection! @goField(forceResolver: true)
frameworks(
first: Int
after: CursorKey
@@ -298,18 +305,20 @@ type Evidence implements Node {
updatedAt: Datetime!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
}
type UserEdge {
cursor: CursorKey!
node: User!
}
type User implements Node {
id: ID!
fullName: String!
email: String!
organizations(
first: Int
after: CursorKey
last: Int
before: CursorKey
): OrganizationConnection! @goField(forceResolver: true)
createdAt: Datetime!
updatedAt: Datetime!
}
@@ -321,7 +330,20 @@ type Session {
type Query {
node(id: ID!): Node!
viewer: User!
viewer: Viewer!
}
type Viewer {
id: ID!
user: User!
organizations(
first: Int
after: CursorKey
last: Int
before: CursorKey
): OrganizationConnection! @goField(forceResolver: true)
}
type Mutation {

File diff suppressed because it is too large Load Diff

View File

@@ -254,6 +254,7 @@ type Organization struct {
ID gid.GID `json:"id"`
Name string `json:"name"`
LogoURL *string `json:"logoUrl,omitempty"`
Users *UserConnection `json:"users"`
Frameworks *FrameworkConnection `json:"frameworks"`
Vendors *VendorConnection `json:"vendors"`
Peoples *PeopleConnection `json:"peoples"`
@@ -477,17 +478,26 @@ type UploadEvidencePayload struct {
}
type User struct {
ID gid.GID `json:"id"`
FullName string `json:"fullName"`
Email string `json:"email"`
Organizations *OrganizationConnection `json:"organizations"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
ID gid.GID `json:"id"`
FullName string `json:"fullName"`
Email string `json:"email"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
func (User) IsNode() {}
func (this User) GetID() gid.GID { return this.ID }
type UserConnection struct {
Edges []*UserEdge `json:"edges"`
PageInfo *PageInfo `json:"pageInfo"`
}
type UserEdge struct {
Cursor page.CursorKey `json:"cursor"`
Node *User `json:"node"`
}
type Vendor struct {
ID gid.GID `json:"id"`
Name string `json:"name"`
@@ -516,3 +526,9 @@ type VendorEdge struct {
Cursor page.CursorKey `json:"cursor"`
Node *Vendor `json:"node"`
}
type Viewer struct {
ID gid.GID `json:"id"`
User *User `json:"user"`
Organizations *OrganizationConnection `json:"organizations"`
}

View File

@@ -16,8 +16,28 @@ package types
import (
"github.com/getprobo/probo/pkg/coredata"
"github.com/getprobo/probo/pkg/page"
)
func NewUserConnection(p *page.Page[*coredata.User]) *UserConnection {
var edges = make([]*UserEdge, len(p.Data))
for i := range edges {
edges[i] = NewUserEdge(p.Data[i])
}
return &UserConnection{
Edges: edges,
PageInfo: NewPageInfo(p),
}
}
func NewUserEdge(user *coredata.User) *UserEdge {
return &UserEdge{
Node: NewUser(user),
}
}
func NewUser(u *coredata.User) *User {
return &User{
ID: u.ID,

View File

@@ -517,6 +517,18 @@ func (r *organizationResolver) LogoURL(ctx context.Context, obj *types.Organizat
return svc.Organizations.GenerateLogoURL(ctx, obj.ID, 1*time.Hour)
}
// Users is the resolver for the users field.
func (r *organizationResolver) Users(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.UserConnection, error) {
cursor := types.NewCursor(first, after, last, before)
page, err := r.usrmgrSvc.ListUsersForTenant(ctx, obj.ID, cursor)
if err != nil {
return nil, fmt.Errorf("cannot list users: %w", err)
}
return types.NewUserConnection(page), nil
}
// Frameworks is the resolver for the frameworks field.
func (r *organizationResolver) Frameworks(ctx context.Context, obj *types.Organization, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.FrameworkConnection, error) {
svc := r.GetTenantServiceIfAuthorized(ctx, obj.ID.TenantID())
@@ -657,9 +669,14 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
}
// Viewer is the resolver for the viewer field.
func (r *queryResolver) Viewer(ctx context.Context) (*types.User, error) {
func (r *queryResolver) Viewer(ctx context.Context) (*types.Viewer, error) {
user := UserFromContext(ctx)
return types.NewUser(user), nil
session := SessionFromContext(ctx)
return &types.Viewer{
ID: session.ID,
User: types.NewUser(user),
}, nil
}
// AssignedTo is the resolver for the assignedTo field.
@@ -697,8 +714,10 @@ func (r *taskResolver) Evidences(ctx context.Context, obj *types.Task, first *in
}
// Organizations is the resolver for the organizations field.
func (r *userResolver) Organizations(ctx context.Context, obj *types.User, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.OrganizationConnection, error) {
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, obj.ID)
func (r *viewerResolver) Organizations(ctx context.Context, obj *types.Viewer, first *int, after *page.CursorKey, last *int, before *page.CursorKey) (*types.OrganizationConnection, error) {
user := UserFromContext(ctx)
organizations, err := r.usrmgrSvc.ListOrganizationsForUserID(ctx, user.ID)
if err != nil {
panic(fmt.Errorf("failed to list organizations for user: %w", err))
}
@@ -738,8 +757,8 @@ func (r *Resolver) Query() schema.QueryResolver { return &queryResolver{r} }
// Task returns schema.TaskResolver implementation.
func (r *Resolver) Task() schema.TaskResolver { return &taskResolver{r} }
// User returns schema.UserResolver implementation.
func (r *Resolver) User() schema.UserResolver { return &userResolver{r} }
// Viewer returns schema.ViewerResolver implementation.
func (r *Resolver) Viewer() schema.ViewerResolver { return &viewerResolver{r} }
type controlResolver struct{ *Resolver }
type evidenceResolver struct{ *Resolver }
@@ -749,4 +768,4 @@ type organizationResolver struct{ *Resolver }
type policyResolver struct{ *Resolver }
type queryResolver struct{ *Resolver }
type taskResolver struct{ *Resolver }
type userResolver struct{ *Resolver }
type viewerResolver struct{ *Resolver }