diff --git a/apps/console/src/_locales/en-US.json b/apps/console/src/_locales/en-US.json index 9d8bd3ccb..af4d85cd9 100644 --- a/apps/console/src/_locales/en-US.json +++ b/apps/console/src/_locales/en-US.json @@ -1361,10 +1361,10 @@ "peoplePage": { "title": "People", "actions": { "add": "Add Person" } }, "personPage": { "breadcrumb": { "people": "People" }, - "messages": { "archived": "Person archived successfully", "removed": "Person removed successfully" }, - "errors": { "archive": "Failed to archive person", "remove": "Failed to remove person" }, - "confirmations": { "archive": "Are you sure you want to archive {{name}}?", "remove": "Are you sure you want to remove {{name}}?" }, - "actions": { "archive": "Archive", "remove": "Remove" } + "messages": { "deactivated": "Person deactivated successfully", "removed": "Person removed successfully" }, + "errors": { "deactivate": "Failed to deactivate person", "remove": "Failed to remove person" }, + "confirmations": { "deactivate": "Are you sure you want to deactivate {{name}}?", "remove": "Are you sure you want to remove {{name}}?" }, + "actions": { "deactivate": "Deactivate", "remove": "Remove" } }, "addPersonDialog": { "title": "Add Person" }, "peopleList": { @@ -1374,10 +1374,10 @@ "filters": { "allStatuses": "All statuses", "pending": "Pending", "active": "Active", "deactivated": "Deactivated", "allRoles": "All roles", "allTypes": "All types" } }, "peopleListItem": { - "messages": { "invitationSent": "Invitation sent successfully", "roleUpdated": "Role updated successfully", "archived": "Person archived successfully", "removed": "Person removed successfully" }, - "errors": { "sendInvitation": "Failed to send invitation", "updateRole": "Failed to update role", "archive": "Failed to archive person", "remove": "Failed to remove person" }, - "confirmations": { "sendActivationEmail": "Send the activation email to {{name}}?", "archive": "Are you sure you want to archive {{name}}?", "remove": "Are you sure you want to remove {{name}}?" }, - "actions": { "send": "Send", "sendActivationMail": "Send activation mail", "resendActivationMail": "Resend activation mail", "archivePerson": "Archive person", "removePerson": "Remove person" } + "messages": { "invitationSent": "Invitation sent successfully", "roleUpdated": "Role updated successfully", "deactivated": "Person deactivated successfully", "removed": "Person removed successfully" }, + "errors": { "sendInvitation": "Failed to send invitation", "updateRole": "Failed to update role", "deactivate": "Failed to deactivate person", "remove": "Failed to remove person" }, + "confirmations": { "sendActivationEmail": "Send the activation email to {{name}}?", "deactivate": "Are you sure you want to deactivate {{name}}?", "remove": "Are you sure you want to remove {{name}}?" }, + "actions": { "send": "Send", "sendActivationMail": "Send activation mail", "resendActivationMail": "Resend activation mail", "deactivatePerson": "Deactivate person", "removePerson": "Remove person" } }, "personForm": { "messages": { "created": "Person created successfully.", "updated": "Person updated successfully." }, diff --git a/apps/console/src/_locales/fr-FR.json b/apps/console/src/_locales/fr-FR.json index 750f70b5b..512205353 100644 --- a/apps/console/src/_locales/fr-FR.json +++ b/apps/console/src/_locales/fr-FR.json @@ -2427,19 +2427,19 @@ "people": "Personnes" }, "messages": { - "archived": "Personne archivée avec succès", + "deactivated": "Personne désactivée avec succès", "removed": "Personne supprimée avec succès" }, "errors": { - "archive": "Échec de l’archivage de la personne", + "deactivate": "Échec de la désactivation de la personne", "remove": "Échec de la suppression de la personne" }, "confirmations": { - "archive": "Voulez-vous vraiment archiver {{name}} ?", + "deactivate": "Voulez-vous vraiment désactiver {{name}} ?", "remove": "Voulez-vous vraiment supprimer {{name}} ?" }, "actions": { - "archive": "Archiver", + "deactivate": "Désactiver", "remove": "Supprimer" } }, @@ -2469,25 +2469,25 @@ "messages": { "invitationSent": "Invitation envoyée avec succès", "roleUpdated": "Rôle mis à jour avec succès", - "archived": "Personne archivée avec succès", + "deactivated": "Personne désactivée avec succès", "removed": "Personne supprimée avec succès" }, "errors": { "sendInvitation": "Échec de l’envoi de l’invitation", "updateRole": "Échec de la mise à jour du rôle", - "archive": "Échec de l’archivage de la personne", + "deactivate": "Échec de la désactivation de la personne", "remove": "Échec de la suppression de la personne" }, "confirmations": { "sendActivationEmail": "Envoyer l’e-mail d’activation à {{name}} ?", - "archive": "Voulez-vous vraiment archiver {{name}} ?", + "deactivate": "Voulez-vous vraiment désactiver {{name}} ?", "remove": "Voulez-vous vraiment supprimer {{name}} ?" }, "actions": { "send": "Envoyer", "sendActivationMail": "Envoyer l’e-mail d’activation", "resendActivationMail": "Renvoyer l’e-mail d’activation", - "archivePerson": "Archiver la personne", + "deactivatePerson": "Désactiver la personne", "removePerson": "Supprimer la personne" } }, diff --git a/apps/console/src/pages/iam/organizations/people/PersonPage.tsx b/apps/console/src/pages/iam/organizations/people/PersonPage.tsx index 2329cdb6a..549b53307 100644 --- a/apps/console/src/pages/iam/organizations/people/PersonPage.tsx +++ b/apps/console/src/pages/iam/organizations/people/PersonPage.tsx @@ -40,7 +40,7 @@ export const personPageQuery = graphql` emailAddress source state - canDelete: permission(action: "iam:membership-profile:delete") + canDeactivate: permission(action: "iam:membership-profile:deactivate") canRemoveMember: permission(action: "iam:membership:delete") ...PersonFormFragment } @@ -58,12 +58,12 @@ const removeUserMutation = graphql` } `; -const archiveUserMutation = graphql` - mutation PersonPage_archiveMutation( - $input: ArchiveUserInput! +const deactivateUserMutation = graphql` + mutation PersonPage_deactivateMutation( + $input: DeactivateUserInput! ) { - archiveUser(input: $input) { - archivedProfileId + deactivateUser(input: $input) { + success } } `; @@ -81,11 +81,11 @@ export function PersonPage(props: { queryRef: PreloadedQuery }) throw new Error("invalid type for node"); } - const [archiveUser, isArchiving] = useMutationWithToasts( - archiveUserMutation, + const [deactivateUser, isDeactivating] = useMutationWithToasts( + deactivateUserMutation, { - successMessage: t("personPage.messages.archived"), - errorMessage: t("personPage.errors.archive"), + successMessage: t("personPage.messages.deactivated"), + errorMessage: t("personPage.errors.deactivate"), }, ); const [removeUser, isRemoving] = useMutationWithToasts( @@ -95,12 +95,12 @@ export function PersonPage(props: { queryRef: PreloadedQuery }) errorMessage: t("personPage.errors.remove"), }, ); - const isMutating = isArchiving || isRemoving; + const isMutating = isDeactivating || isRemoving; - const handleArchive = () => { + const handleDeactivate = () => { confirm( () => { - return archiveUser({ + return deactivateUser({ variables: { input: { profileId: person.id, @@ -113,7 +113,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery }) }); }, { - message: t("personPage.confirmations.archive", { name: person.fullName }), + message: t("personPage.confirmations.deactivate", { name: person.fullName }), }, ); }; @@ -139,7 +139,7 @@ export function PersonPage(props: { queryRef: PreloadedQuery }) ); }; - const canArchive = person.canDelete && person.source !== "SCIM" && person.state !== "DEACTIVATED"; + const canDeactivate = person.canDeactivate && person.source !== "SCIM" && person.state !== "DEACTIVATED"; const canRemove = person.canRemoveMember && person.source !== "SCIM"; return ( @@ -166,15 +166,15 @@ export function PersonPage(props: { queryRef: PreloadedQuery })
{person.emailAddress}
- {(canArchive || canRemove) && ( + {(canDeactivate || canRemove) && ( - {canArchive && ( + {canDeactivate && ( - {t("personPage.actions.archive")} + {t("personPage.actions.deactivate")} )} {canRemove && ( diff --git a/apps/console/src/pages/iam/organizations/people/_components/PeopleListItem.tsx b/apps/console/src/pages/iam/organizations/people/_components/PeopleListItem.tsx index 399b80afd..2e1d6852f 100644 --- a/apps/console/src/pages/iam/organizations/people/_components/PeopleListItem.tsx +++ b/apps/console/src/pages/iam/organizations/people/_components/PeopleListItem.tsx @@ -71,7 +71,7 @@ const fragment = graphql` createdAt canUpdate: permission(action: "iam:membership-profile:update") canInvite: permission(action: "iam:invitation:create") - canDelete: permission(action: "iam:membership-profile:delete") + canDeactivate: permission(action: "iam:membership-profile:deactivate") canRemoveMember: permission(action: "iam:membership:delete") } `; @@ -116,10 +116,10 @@ const removeUserMutation = graphql` } `; -const archiveUserMutation = graphql` - mutation PeopleListItem_archiveMutation($input: ArchiveUserInput!) { - archiveUser(input: $input) { - archivedProfileId +const deactivateUserMutation = graphql` + mutation PeopleListItem_deactivateMutation($input: DeactivateUserInput!) { + deactivateUser(input: $input) { + success } } `; @@ -149,7 +149,7 @@ export function PeopleListItem(props: { const isInactive = !isActive; const canSendActivationMail = !isActive && profile.source !== "SCIM" && profile.canInvite; - const canArchive = profile.canDelete && profile.source !== "SCIM" && profile.state !== "DEACTIVATED"; + const canDeactivate = profile.canDeactivate && profile.source !== "SCIM" && profile.state !== "DEACTIVATED"; const canRemove = profile.canRemoveMember && profile.source !== "SCIM"; const [inviteUser] @@ -164,11 +164,11 @@ export function PeopleListItem(props: { errorMessage: t("peopleListItem.errors.updateRole"), }, ); - const [archiveUser, isArchiving] = useMutationWithToasts( - archiveUserMutation, + const [deactivateUser, isDeactivating] = useMutationWithToasts( + deactivateUserMutation, { - successMessage: t("peopleListItem.messages.archived"), - errorMessage: t("peopleListItem.errors.archive"), + successMessage: t("peopleListItem.messages.deactivated"), + errorMessage: t("peopleListItem.errors.deactivate"), }, ); const [removeUser, isRemoving] = useMutationWithToasts( @@ -178,7 +178,7 @@ export function PeopleListItem(props: { errorMessage: t("peopleListItem.errors.remove"), }, ); - const isMutating = isArchiving || isRemoving; + const isMutating = isDeactivating || isRemoving; const handleInvite = () => { confirm( @@ -211,10 +211,10 @@ export function PeopleListItem(props: { }, }); }; - const handleArchive = () => { + const handleDeactivate = () => { confirm( () => { - return archiveUser({ + return deactivateUser({ variables: { input: { profileId: profile.id, @@ -227,7 +227,7 @@ export function PeopleListItem(props: { }); }, { - message: t("peopleListItem.confirmations.archive", { name: profile.fullName }), + message: t("peopleListItem.confirmations.deactivate", { name: profile.fullName }), }, ); }; @@ -307,7 +307,7 @@ export function PeopleListItem(props: { {dateFormat(i18n.language, profile.createdAt)} - {(canSendActivationMail || canArchive || canRemove) && ( + {(canSendActivationMail || canDeactivate || canRemove) && ( {canSendActivationMail && ( )} - {canArchive && ( + {canDeactivate && ( - {t("peopleListItem.actions.archivePerson")} + {t("peopleListItem.actions.deactivatePerson")} )} {canRemove && ( diff --git a/e2e/console/user_test.go b/e2e/console/user_test.go index b583aed27..cad121bdf 100644 --- a/e2e/console/user_test.go +++ b/e2e/console/user_test.go @@ -605,13 +605,13 @@ func TestUser_RemoveUser_ProfileInUse(t *testing.T) { assert.Contains(t, gqlErrors[0].Message, "referenced by other resources") } -func TestUser_ArchiveUser(t *testing.T) { +func TestUser_DeactivateUser(t *testing.T) { t.Parallel() owner := testutil.NewClient(t, testutil.RoleOwner) - // Create a user to archive. - userToArchive := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) - _ = userToArchive + // Create a user to deactivate. + userToDeactivate := testutil.NewClientInOrg(t, testutil.RoleViewer, owner) + _ = userToDeactivate query := ` query($id: ID!) { @@ -666,17 +666,17 @@ func TestUser_ArchiveUser(t *testing.T) { require.NotEmpty(t, userID, "Should find viewer member") mutation := ` - mutation($input: ArchiveUserInput!) { - archiveUser(input: $input) { - archivedProfileId + mutation($input: DeactivateUserInput!) { + deactivateUser(input: $input) { + success } } ` var mutationResult struct { - ArchiveUser struct { - ArchivedProfileID string `json:"archivedProfileId"` - } `json:"archiveUser"` + DeactivateUser struct { + Success bool `json:"success"` + } `json:"deactivateUser"` } err = owner.ExecuteConnect(mutation, map[string]any{ @@ -687,24 +687,24 @@ func TestUser_ArchiveUser(t *testing.T) { }, &mutationResult) require.NoError(t, err) - assert.Equal(t, userID, mutationResult.ArchiveUser.ArchivedProfileID) + assert.True(t, mutationResult.DeactivateUser.Success) err = owner.ExecuteConnect(query, map[string]any{ "id": owner.GetOrganizationID().String(), }, &result) require.NoError(t, err) - var archivedUserState string + var deactivatedUserState string for _, edge := range result.Node.Profiles.Edges { if edge.Node.ID == userID { - archivedUserState = edge.Node.State + deactivatedUserState = edge.Node.State break } } - require.NotEmpty(t, archivedUserState, "Should still find archived user") - assert.Equal(t, "DEACTIVATED", archivedUserState) + require.NotEmpty(t, deactivatedUserState, "Should still find deactivated user") + assert.Equal(t, "DEACTIVATED", deactivatedUserState) } func TestUser_DeactivateUserCancelsSignatureRequests(t *testing.T) { diff --git a/packages/n8n-node/nodes/Probo/actions/user/archiveUser.operation.ts b/packages/n8n-node/nodes/Probo/actions/user/deactivateUser.operation.ts similarity index 89% rename from packages/n8n-node/nodes/Probo/actions/user/archiveUser.operation.ts rename to packages/n8n-node/nodes/Probo/actions/user/deactivateUser.operation.ts index ee1fd0fa4..e04c05aec 100644 --- a/packages/n8n-node/nodes/Probo/actions/user/archiveUser.operation.ts +++ b/packages/n8n-node/nodes/Probo/actions/user/deactivateUser.operation.ts @@ -29,7 +29,7 @@ export const description: INodeProperties[] = [ displayOptions: { show: { resource: ['user'], - operation: ['archiveUser'], + operation: ['deactivateUser'], }, }, default: '', @@ -43,11 +43,11 @@ export const description: INodeProperties[] = [ displayOptions: { show: { resource: ['user'], - operation: ['archiveUser'], + operation: ['deactivateUser'], }, }, default: '', - description: 'The ID of the user (profile) to archive in the organization', + description: 'The ID of the user (profile) to deactivate in the organization', required: true, }, ]; @@ -60,9 +60,9 @@ export async function execute( const userId = this.getNodeParameter('userId', itemIndex) as string; const query = ` - mutation ArchiveUser($input: ArchiveUserInput!) { - archiveUser(input: $input) { - archivedProfileId + mutation DeactivateUser($input: DeactivateUserInput!) { + deactivateUser(input: $input) { + success } } `; diff --git a/packages/n8n-node/nodes/Probo/actions/user/index.ts b/packages/n8n-node/nodes/Probo/actions/user/index.ts index a7f850bba..ede88320a 100644 --- a/packages/n8n-node/nodes/Probo/actions/user/index.ts +++ b/packages/n8n-node/nodes/Probo/actions/user/index.ts @@ -19,7 +19,7 @@ // SOFTWARE. import type { INodeProperties } from 'n8n-workflow'; -import * as archiveUserOp from './archiveUser.operation'; +import * as deactivateUserOp from './deactivateUser.operation'; import * as listUsersOp from './listUsers.operation'; import * as getUserOp from './getUser.operation'; import * as createUserOp from './createUser.operation'; @@ -40,18 +40,18 @@ export const description: INodeProperties[] = [ }, }, options: [ - { - name: 'Archive', - value: 'archiveUser', - description: 'Archive a user in the organization', - action: 'Archive a user', - }, { name: 'Create', value: 'createUser', description: 'Create a new user in the organization', action: 'Create a user', }, + { + name: 'Deactivate', + value: 'deactivateUser', + description: 'Deactivate a user in the organization', + action: 'Deactivate a user', + }, { name: 'Get', value: 'getUser', @@ -91,7 +91,7 @@ export const description: INodeProperties[] = [ ], default: 'listUsers', }, - ...archiveUserOp.description, + ...deactivateUserOp.description, ...listUsersOp.description, ...getUserOp.description, ...createUserOp.description, @@ -102,7 +102,7 @@ export const description: INodeProperties[] = [ ]; export { - archiveUserOp as archiveUser, + deactivateUserOp as deactivateUser, listUsersOp as listUsers, getUserOp as getUser, createUserOp as createUser, diff --git a/pkg/cmd/user/archive/archive.go b/pkg/cmd/user/deactivate/deactivate.go similarity index 83% rename from pkg/cmd/user/archive/archive.go rename to pkg/cmd/user/deactivate/deactivate.go index 6e69a63e7..3163f63f9 100644 --- a/pkg/cmd/user/archive/archive.go +++ b/pkg/cmd/user/deactivate/deactivate.go @@ -18,7 +18,7 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. -package archive +package deactivate import ( "fmt" @@ -29,34 +29,34 @@ import ( "go.probo.inc/probo/pkg/cmd/cmdutil" ) -const archiveMutation = ` -mutation($input: ArchiveUserInput!) { - archiveUser(input: $input) { - archivedProfileId +const deactivateMutation = ` +mutation($input: DeactivateUserInput!) { + deactivateUser(input: $input) { + success } } ` -func NewCmdArchive(f *cmdutil.Factory) *cobra.Command { +func NewCmdDeactivate(f *cmdutil.Factory) *cobra.Command { var ( flagOrg string flagYes bool ) cmd := &cobra.Command{ - Use: "archive ", - Short: "Archive a user", + Use: "deactivate ", + Short: "Deactivate a user", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { if !flagYes { if !f.IOStreams.IsInteractive() { - return fmt.Errorf("cannot archive user: confirmation required, use --yes to confirm") + return fmt.Errorf("cannot deactivate user: confirmation required, use --yes to confirm") } var confirmed bool err := huh.NewConfirm(). - Title(fmt.Sprintf("Archive user %s?", args[0])). + Title(fmt.Sprintf("Deactivate user %s?", args[0])). Value(&confirmed). Run() if err != nil { @@ -95,7 +95,7 @@ func NewCmdArchive(f *cmdutil.Factory) *cobra.Command { ) _, err = client.Do( - archiveMutation, + deactivateMutation, map[string]any{ "input": map[string]any{ "organizationId": flagOrg, @@ -107,7 +107,7 @@ func NewCmdArchive(f *cmdutil.Factory) *cobra.Command { return err } - _, _ = fmt.Fprintf(f.IOStreams.Out, "Archived user %s\n", args[0]) + _, _ = fmt.Fprintf(f.IOStreams.Out, "Deactivated user %s\n", args[0]) return nil }, diff --git a/pkg/cmd/user/user.go b/pkg/cmd/user/user.go index ba5406b7d..4aa2623d5 100644 --- a/pkg/cmd/user/user.go +++ b/pkg/cmd/user/user.go @@ -23,7 +23,7 @@ package user import ( "github.com/spf13/cobra" "go.probo.inc/probo/pkg/cmd/cmdutil" - "go.probo.inc/probo/pkg/cmd/user/archive" + "go.probo.inc/probo/pkg/cmd/user/deactivate" "go.probo.inc/probo/pkg/cmd/user/list" "go.probo.inc/probo/pkg/cmd/user/remove" "go.probo.inc/probo/pkg/cmd/user/view" @@ -37,7 +37,7 @@ func NewCmdUser(f *cmdutil.Factory) *cobra.Command { cmd.AddCommand(list.NewCmdList(f)) cmd.AddCommand(view.NewCmdView(f)) - cmd.AddCommand(archive.NewCmdArchive(f)) + cmd.AddCommand(deactivate.NewCmdDeactivate(f)) cmd.AddCommand(remove.NewCmdRemove(f)) return cmd diff --git a/pkg/iam/organization_service.go b/pkg/iam/organization_service.go index d250b29d6..b31f88921 100644 --- a/pkg/iam/organization_service.go +++ b/pkg/iam/organization_service.go @@ -374,7 +374,7 @@ func (s *OrganizationService) RemoveUser( ) } -func (s *OrganizationService) ArchiveUser( +func (s *OrganizationService) DeactivateUser( ctx context.Context, scope coredata.Scoper, organizationID gid.GID, @@ -1183,55 +1183,6 @@ func (s *OrganizationService) UpdateUser(ctx context.Context, req *UpdateUserReq return profile, nil } -func (s *OrganizationService) UpdateUserState( - ctx context.Context, - userID gid.GID, - state coredata.ProfileState, -) (*coredata.MembershipProfile, error) { - var ( - scope = coredata.NewScopeFromObjectID(userID) - profile = &coredata.MembershipProfile{} - ) - - err := s.pg.WithTx( - ctx, - func(ctx context.Context, tx pg.Tx) error { - if err := profile.LoadByID(ctx, tx, scope, userID); err != nil { - return fmt.Errorf("cannot load profile: %w", err) - } - - now := time.Now() - - switch state { - case coredata.ProfileStatePending: - profile.MarkPending(now) - case coredata.ProfileStateActive: - profile.MarkActive(now) - case coredata.ProfileStateDeactivated: - profile.MarkDeactivated(now) - } - - if err := profile.Update(ctx, tx, scope); err != nil { - return fmt.Errorf("cannot update profile: %w", err) - } - - if state == coredata.ProfileStateDeactivated { - signatures := &coredata.DocumentVersionSignatures{} - if err := signatures.DeleteRequestedBySignatory(ctx, tx, scope, profile.ID); err != nil { - return fmt.Errorf("cannot delete requested signatures: %w", err) - } - } - - return nil - }, - ) - if err != nil { - return nil, err - } - - return profile, nil -} - func (s *OrganizationService) GetProfile(ctx context.Context, profileID gid.GID) (*coredata.MembershipProfile, error) { profile := &coredata.MembershipProfile{} diff --git a/pkg/server/api/connect/v1/graphql/profile.graphql b/pkg/server/api/connect/v1/graphql/profile.graphql index 7128be63b..720780383 100644 --- a/pkg/server/api/connect/v1/graphql/profile.graphql +++ b/pkg/server/api/connect/v1/graphql/profile.graphql @@ -104,9 +104,8 @@ extend type Mutation { createUser(input: CreateUserInput!): CreateUserPayload @authentication(required: PRESENT) deactivateUser(input: DeactivateUserInput!): DeactivateUserPayload - updateUser(input: UpdateUserInput!): UpdateUserPayload! - archiveUser(input: ArchiveUserInput!): ArchiveUserPayload @authentication(required: PRESENT) + updateUser(input: UpdateUserInput!): UpdateUserPayload! removeUser(input: RemoveUserInput!): RemoveUserPayload @authentication(required: PRESENT) } @@ -148,11 +147,6 @@ input RemoveUserInput { profileId: ID! } -input ArchiveUserInput { - organizationId: ID! - profileId: ID! -} - type CreateUserPayload { profileEdge: ProfileEdge! } @@ -168,7 +162,3 @@ type UpdateUserPayload { type RemoveUserPayload { deletedProfileId: ID! } - -type ArchiveUserPayload { - archivedProfileId: ID! -} diff --git a/pkg/server/api/connect/v1/profile_resolvers.go b/pkg/server/api/connect/v1/profile_resolvers.go index 02797e82a..4020e9c19 100644 --- a/pkg/server/api/connect/v1/profile_resolvers.go +++ b/pkg/server/api/connect/v1/profile_resolvers.go @@ -64,17 +64,23 @@ func (r *mutationResolver) CreateUser(ctx context.Context, input types.CreateUse // DeactivateUser is the resolver for the deactivateUser field. func (r *mutationResolver) DeactivateUser(ctx context.Context, input types.DeactivateUserInput) (*types.DeactivateUserPayload, error) { - if _, err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDeactivate); err != nil { + scope, err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDeactivate) + if err != nil { return nil, err } - _, err := r.iam.OrganizationService.UpdateUserState( - ctx, - input.ProfileID, - coredata.ProfileStateDeactivated, - ) + err = r.iam.OrganizationService.DeactivateUser(ctx, scope, input.OrganizationID, input.ProfileID) if err != nil { - r.logger.ErrorCtx(ctx, "cannot deactivate profile", log.Error(err)) + if _, ok := errors.AsType[*iam.ErrUserManagedBySCIM](err); ok { + return nil, gqlutils.Conflictf(ctx, "user is managed by SCIM and cannot be deactivated") + } + + if _, ok := errors.AsType[*iam.ErrLastActiveOwner](err); ok { + return nil, gqlutils.Conflictf(ctx, "cannot deactivate last active owner") + } + + r.logger.ErrorCtx(ctx, "cannot deactivate user", log.Error(err)) + return nil, gqlutils.Internal(ctx) } @@ -111,31 +117,6 @@ func (r *mutationResolver) UpdateUser(ctx context.Context, input types.UpdateUse }, nil } -// ArchiveUser is the resolver for the archiveUser field. -func (r *mutationResolver) ArchiveUser(ctx context.Context, input types.ArchiveUserInput) (*types.ArchiveUserPayload, error) { - scope, err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDelete) - if err != nil { - return nil, err - } - - err = r.iam.OrganizationService.ArchiveUser(ctx, scope, input.OrganizationID, input.ProfileID) - if err != nil { - if _, ok := errors.AsType[*iam.ErrUserManagedBySCIM](err); ok { - return nil, gqlutils.Conflictf(ctx, "user is managed by SCIM and cannot be archived") - } - - if _, ok := errors.AsType[*iam.ErrLastActiveOwner](err); ok { - return nil, gqlutils.Conflictf(ctx, "cannot archive last active owner") - } - - r.logger.ErrorCtx(ctx, "cannot archive user from organization", log.Error(err)) - - return nil, gqlutils.Internal(ctx) - } - - return &types.ArchiveUserPayload{ArchivedProfileID: input.ProfileID}, nil -} - // RemoveUser is the resolver for the removeUser field. func (r *mutationResolver) RemoveUser(ctx context.Context, input types.RemoveUserInput) (*types.RemoveUserPayload, error) { scope, err := r.authorize(ctx, input.ProfileID, iam.ActionMembershipDelete) diff --git a/pkg/server/api/mcp/v1/schema.resolvers.go b/pkg/server/api/mcp/v1/schema.resolvers.go index 741398559..d885871b5 100644 --- a/pkg/server/api/mcp/v1/schema.resolvers.go +++ b/pkg/server/api/mcp/v1/schema.resolvers.go @@ -2994,26 +2994,26 @@ func (r *Resolver) RemoveUserTool(ctx context.Context, req *mcp.CallToolRequest, return nil, types.RemoveUserOutput{DeletedUserID: input.ProfileID}, nil } -func (r *Resolver) ArchiveUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.ArchiveUserInput) (*mcp.CallToolResult, types.ArchiveUserOutput, error) { - scope, err := r.Authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDelete) +func (r *Resolver) DeactivateUserTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeactivateUserInput) (*mcp.CallToolResult, types.DeactivateUserOutput, error) { + scope, err := r.Authorize(ctx, input.ProfileID, iam.ActionMembershipProfileDeactivate) if err != nil { - return nil, types.ArchiveUserOutput{}, err + return nil, types.DeactivateUserOutput{}, err } - err = r.iamSvc.OrganizationService.ArchiveUser(ctx, scope, input.OrganizationID, input.ProfileID) + err = r.iamSvc.OrganizationService.DeactivateUser(ctx, scope, input.OrganizationID, input.ProfileID) if err != nil { if _, ok := errors.AsType[*iam.ErrUserManagedBySCIM](err); ok { - return nil, types.ArchiveUserOutput{}, fmt.Errorf("user is managed by SCIM and cannot be archived: %w", err) + return nil, types.DeactivateUserOutput{}, fmt.Errorf("user is managed by SCIM and cannot be deactivated: %w", err) } if _, ok := errors.AsType[*iam.ErrLastActiveOwner](err); ok { - return nil, types.ArchiveUserOutput{}, fmt.Errorf("cannot archive last active owner: %w", err) + return nil, types.DeactivateUserOutput{}, fmt.Errorf("cannot deactivate last active owner: %w", err) } - return nil, types.ArchiveUserOutput{}, fmt.Errorf("archive user: %w", err) + return nil, types.DeactivateUserOutput{}, fmt.Errorf("deactivate user: %w", err) } - return nil, types.ArchiveUserOutput{ArchivedUserID: input.ProfileID}, nil + return nil, types.DeactivateUserOutput{DeactivatedUserID: input.ProfileID}, nil } func (r *Resolver) DeleteDataProtectionImpactAssessmentTool(ctx context.Context, req *mcp.CallToolRequest, input *types.DeleteDataProtectionImpactAssessmentInput) (*mcp.CallToolResult, types.DeleteDataProtectionImpactAssessmentOutput, error) { diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index 318d0940b..0fafb1330 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -1698,7 +1698,7 @@ components: $ref: "#/components/schemas/GID" description: Deleted user (profile) ID - ArchiveUserInput: + DeactivateUserInput: type: object required: - organization_id @@ -1709,16 +1709,16 @@ components: description: Organization ID profile_id: $ref: "#/components/schemas/GID" - description: User (profile) ID to archive + description: User (profile) ID to deactivate - ArchiveUserOutput: + DeactivateUserOutput: type: object required: - - archived_user_id + - deactivated_user_id properties: - archived_user_id: + deactivated_user_id: $ref: "#/components/schemas/GID" - description: Archived user (profile) ID + description: Deactivated user (profile) ID GetProfileInput: type: object @@ -12679,14 +12679,14 @@ tools: $ref: "#/components/schemas/RemoveUserInput" outputSchema: $ref: "#/components/schemas/RemoveUserOutput" - - name: archiveUser - description: Archive a user in the organization + - name: deactivateUser + description: Deactivate a user in the organization hints: readonly: false inputSchema: - $ref: "#/components/schemas/ArchiveUserInput" + $ref: "#/components/schemas/DeactivateUserInput" outputSchema: - $ref: "#/components/schemas/ArchiveUserOutput" + $ref: "#/components/schemas/DeactivateUserOutput" - name: addThirdParty description: Add a new thirdParty to the organization hints: