Rework console pages and implement profile update
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -98,6 +98,7 @@ type Mutation {
|
||||
@session(required: PRESENT)
|
||||
deleteInvitation(input: DeleteInvitationInput!): DeleteInvitationPayload
|
||||
@session(required: PRESENT)
|
||||
updateProfile(input: UpdateProfileInput!): UpdateProfilePayload!
|
||||
updateMembership(input: UpdateMembershipInput!): UpdateMembershipPayload!
|
||||
removeMember(input: RemoveMemberInput!): RemoveMemberPayload
|
||||
@session(required: PRESENT)
|
||||
@@ -176,9 +177,20 @@ type Identity implements Node {
|
||||
type MembershipProfile implements Node {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
additionalEmailAddresses: [EmailAddr!]!
|
||||
kind: ProfileKind!
|
||||
position: String
|
||||
contractStartDate: Datetime
|
||||
contractEndDate: Datetime
|
||||
createdAt: Datetime!
|
||||
updatedAt: Datetime!
|
||||
|
||||
identity: Identity @goField(forceResolver: true)
|
||||
organization: Organization @goField(forceResolver: true)
|
||||
|
||||
# TODO: remove when memberships are under profile
|
||||
membershipId: ID!
|
||||
|
||||
permission(action: String!): Boolean!
|
||||
@goField(forceResolver: true)
|
||||
@session(required: PRESENT)
|
||||
@@ -229,6 +241,17 @@ type Organization implements Node {
|
||||
@session(required: PRESENT)
|
||||
}
|
||||
|
||||
enum ProfileKind @goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipProfileKind") {
|
||||
EMPLOYEE
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipProfileKindEmployee")
|
||||
CONTRACTOR
|
||||
@goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipProfileKindContractor")
|
||||
SERVICE_ACCOUNT
|
||||
@goEnum(
|
||||
value: "go.probo.inc/probo/pkg/coredata.MembershipProfileKindServiceAccount"
|
||||
)
|
||||
}
|
||||
|
||||
enum MembershipRole
|
||||
@goModel(model: "go.probo.inc/probo/pkg/coredata.MembershipRole") {
|
||||
OWNER @goEnum(value: "go.probo.inc/probo/pkg/coredata.MembershipRoleOwner")
|
||||
@@ -717,6 +740,16 @@ input InviteMemberInput {
|
||||
role: MembershipRole!
|
||||
}
|
||||
|
||||
input UpdateProfileInput {
|
||||
id: ID!
|
||||
fullName: String!
|
||||
additionalEmailAddresses: [EmailAddr!]
|
||||
kind: ProfileKind!
|
||||
position: String @goField(omittable: true)
|
||||
contractStartDate: Datetime @goField(omittable: true)
|
||||
contractEndDate: Datetime @goField(omittable: true)
|
||||
}
|
||||
|
||||
input UpdateMembershipInput {
|
||||
organizationId: ID!
|
||||
membershipId: ID!
|
||||
@@ -868,6 +901,10 @@ type InviteMemberPayload {
|
||||
invitationEdge: InvitationEdge!
|
||||
}
|
||||
|
||||
type UpdateProfilePayload {
|
||||
profile: MembershipProfile!
|
||||
}
|
||||
|
||||
type UpdateMembershipPayload {
|
||||
membership: Membership!
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,9 +18,21 @@ import "go.probo.inc/probo/pkg/coredata"
|
||||
|
||||
func NewMembershipProfile(profile *coredata.MembershipProfile) *MembershipProfile {
|
||||
return &MembershipProfile{
|
||||
ID: profile.ID,
|
||||
FullName: profile.FullName,
|
||||
CreatedAt: profile.CreatedAt,
|
||||
UpdatedAt: profile.UpdatedAt,
|
||||
ID: profile.ID,
|
||||
FullName: profile.FullName,
|
||||
AdditionalEmailAddresses: profile.AdditionalEmailAddresses,
|
||||
Kind: profile.Kind,
|
||||
Position: profile.Position,
|
||||
ContractStartDate: profile.ContractStartDate,
|
||||
ContractEndDate: profile.ContractEndDate,
|
||||
CreatedAt: profile.CreatedAt,
|
||||
UpdatedAt: profile.UpdatedAt,
|
||||
MembershipID: profile.MembershipID,
|
||||
Identity: &Identity{
|
||||
ID: profile.IdentityID,
|
||||
},
|
||||
Organization: &Organization{
|
||||
ID: profile.OrganizationID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,11 +240,19 @@ type MembershipEdge struct {
|
||||
}
|
||||
|
||||
type MembershipProfile struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FullName string `json:"fullName"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Permission bool `json:"permission"`
|
||||
ID gid.GID `json:"id"`
|
||||
FullName string `json:"fullName"`
|
||||
AdditionalEmailAddresses []mail.Addr `json:"additionalEmailAddresses"`
|
||||
Kind coredata.MembershipProfileKind `json:"kind"`
|
||||
Position *string `json:"position,omitempty"`
|
||||
ContractStartDate *time.Time `json:"contractStartDate,omitempty"`
|
||||
ContractEndDate *time.Time `json:"contractEndDate,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Identity *Identity `json:"identity,omitempty"`
|
||||
Organization *Organization `json:"organization,omitempty"`
|
||||
MembershipID gid.GID `json:"membershipId"`
|
||||
Permission bool `json:"permission"`
|
||||
}
|
||||
|
||||
func (MembershipProfile) IsNode() {}
|
||||
@@ -545,6 +553,20 @@ type UpdateOrganizationPayload struct {
|
||||
Organization *Organization `json:"organization,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateProfileInput struct {
|
||||
ID gid.GID `json:"id"`
|
||||
FullName string `json:"fullName"`
|
||||
AdditionalEmailAddresses []mail.Addr `json:"additionalEmailAddresses,omitempty"`
|
||||
Kind coredata.MembershipProfileKind `json:"kind"`
|
||||
Position graphql.Omittable[*string] `json:"position,omitempty"`
|
||||
ContractStartDate graphql.Omittable[*time.Time] `json:"contractStartDate,omitempty"`
|
||||
ContractEndDate graphql.Omittable[*time.Time] `json:"contractEndDate,omitempty"`
|
||||
}
|
||||
|
||||
type UpdateProfilePayload struct {
|
||||
Profile *MembershipProfile `json:"profile"`
|
||||
}
|
||||
|
||||
type UpdateSAMLConfigurationInput struct {
|
||||
OrganizationID gid.GID `json:"organizationId"`
|
||||
SamlConfigurationID gid.GID `json:"samlConfigurationId"`
|
||||
|
||||
@@ -349,6 +349,53 @@ func (r *membershipConnectionResolver) TotalCount(ctx context.Context, obj *type
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
// Identity is the resolver for the identity field.
|
||||
func (r *membershipProfileResolver) Identity(ctx context.Context, obj *types.MembershipProfile) (*types.Identity, error) {
|
||||
if err := r.authorize(
|
||||
ctx,
|
||||
obj.Identity.ID,
|
||||
iam.ActionIdentityGet,
|
||||
authz.WithAttr("organization_id", obj.Organization.ID.String()),
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyIDSelected(ctx) {
|
||||
return &types.Identity{
|
||||
ID: obj.Identity.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
identity, err := r.iam.AccountService.GetIdentity(ctx, obj.Identity.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get identity for membership", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewIdentity(identity), nil
|
||||
}
|
||||
|
||||
// Organization is the resolver for the organization field.
|
||||
func (r *membershipProfileResolver) Organization(ctx context.Context, obj *types.MembershipProfile) (*types.Organization, error) {
|
||||
if err := r.authorize(ctx, obj.Organization.ID, iam.ActionOrganizationGet, authz.WithSkipAssumptionCheck()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if gqlutils.OnlyIDSelected(ctx) {
|
||||
return &types.Organization{
|
||||
ID: obj.Organization.ID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
organization, err := r.iam.OrganizationService.GetOrganizationForMembership(ctx, obj.ID)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot get organization for membership", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return types.NewOrganization(organization), nil
|
||||
}
|
||||
|
||||
// Permission is the resolver for the permission field.
|
||||
func (r *membershipProfileResolver) Permission(ctx context.Context, obj *types.MembershipProfile, action string) (bool, error) {
|
||||
return r.Resolver.Permission(ctx, obj, action)
|
||||
@@ -991,6 +1038,34 @@ func (r *mutationResolver) DeleteInvitation(ctx context.Context, input types.Del
|
||||
return &types.DeleteInvitationPayload{DeletedInvitationID: input.InvitationID}, nil
|
||||
}
|
||||
|
||||
// UpdateProfile is the resolver for the updateProfile field.
|
||||
func (r *mutationResolver) UpdateProfile(ctx context.Context, input types.UpdateProfileInput) (*types.UpdateProfilePayload, error) {
|
||||
if err := r.authorize(ctx, input.ID, iam.ActionMembershipProfileUpdate); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
profile, err := r.iam.OrganizationService.UpdateProfile(
|
||||
ctx,
|
||||
&iam.UpdateProfileRequest{
|
||||
ID: input.ID,
|
||||
FullName: input.FullName,
|
||||
AdditionalEmailAddresses: input.AdditionalEmailAddresses,
|
||||
Kind: input.Kind,
|
||||
Position: gqlutils.UnwrapOmittable(input.Position),
|
||||
ContractStartDate: gqlutils.UnwrapOmittable(input.ContractStartDate),
|
||||
ContractEndDate: gqlutils.UnwrapOmittable(input.ContractEndDate),
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
r.logger.ErrorCtx(ctx, "cannot update profile", log.Error(err))
|
||||
return nil, gqlutils.Internal(ctx)
|
||||
}
|
||||
|
||||
return &types.UpdateProfilePayload{
|
||||
Profile: types.NewMembershipProfile(profile),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UpdateMembership is the resolver for the updateMembership field.
|
||||
func (r *mutationResolver) UpdateMembership(ctx context.Context, input types.UpdateMembershipInput) (*types.UpdateMembershipPayload, error) {
|
||||
if err := r.authorize(ctx, input.MembershipID, iam.ActionMembershipUpdate); err != nil {
|
||||
@@ -1494,6 +1569,16 @@ func (r *queryResolver) Node(ctx context.Context, id gid.GID) (types.Node, error
|
||||
|
||||
return types.NewSession(session), nil
|
||||
}
|
||||
case coredata.MembershipProfileEntityType:
|
||||
action = iam.ActionMembershipGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
profile, err := r.iam.OrganizationService.GetProfile(ctx, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return types.NewMembershipProfile(profile), nil
|
||||
}
|
||||
case coredata.MembershipEntityType:
|
||||
action = iam.ActionMembershipGet
|
||||
loadNode = func(ctx context.Context, id gid.GID) (types.Node, error) {
|
||||
|
||||
Reference in New Issue
Block a user