Skip to content

Commit

Permalink
feat(cli): Add functionality to operate on Workspace Membership (#589)
Browse files Browse the repository at this point in the history
Co-authored-by: Rajdip Bhattacharya <[email protected]>
  • Loading branch information
muntaxir4 and rajdip-b authored Dec 16, 2024
1 parent 89aa84f commit 0fde62b
Show file tree
Hide file tree
Showing 17 changed files with 571 additions and 23 deletions.
12 changes: 6 additions & 6 deletions apps/api/src/mail/emails/components/base-email-template.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,13 @@ export const BaseEmailTemplate: React.FC<BaseEmailTemplateProps> = ({
<Heading style={h1}>{heading}</Heading>
{children}
<Text style={text}>
If you believe this action was taken in error or have any
questions regarding this change, please contact your project
administrator or our support team.
If you believe this action was taken in error or have any
questions regarding this change, please contact your project
administrator or our support team.
</Text>
<Text style={text}>
We appreciate your understanding and thank you for your
contributions to the project.
We appreciate your understanding and thank you for your
contributions to the project.
</Text>
<Text style={text}>
Cheers,
Expand Down Expand Up @@ -81,4 +81,4 @@ export const BaseEmailTemplate: React.FC<BaseEmailTemplateProps> = ({
)
}

export default BaseEmailTemplate
export default BaseEmailTemplate
15 changes: 6 additions & 9 deletions apps/api/src/mail/emails/workspace-invitation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,11 @@ export const WorkspaceInvitationEmail = ({
: 'You are Invited to Join the Workspace'

return (
<BaseEmailTemplate
previewText={previewText}
heading={previewText}
>
<BaseEmailTemplate previewText={previewText} heading={previewText}>
<Text style={text}>Dear User,</Text>
<Text style={text}>
We're excited to inform you that you've been invited to join a
workspace on Keyshade. Here are the details of your invitation:
We're excited to inform you that you've been invited to join a workspace
on Keyshade. Here are the details of your invitation:
</Text>
<Section style={workspaceDetails}>
<Text style={workspaceInfo}>
Expand All @@ -54,8 +51,8 @@ export const WorkspaceInvitationEmail = ({
</Text>
</Section>
<Text style={text}>
Join the project by clicking the button below - we're excited to
have you!
Join the project by clicking the button below - we're excited to have
you!
</Text>
<Button href={actionUrl} style={ctaButton}>
Get started
Expand All @@ -64,4 +61,4 @@ export const WorkspaceInvitationEmail = ({
)
}

export default WorkspaceInvitationEmail
export default WorkspaceInvitationEmail
6 changes: 3 additions & 3 deletions apps/api/src/mail/emails/workspace-removal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export const RemovedFromWorkspaceEmail = ({
>
<Text style={text}>Dear User,</Text>
<Text style={text}>
We hope this email finds you well. We are writing to inform you
that your access to the following workspace has been removed:
We hope this email finds you well. We are writing to inform you that
your access to the following workspace has been removed:
</Text>
<Section style={workspaceDetails}>
<Text style={workspaceInfo}>
Expand All @@ -39,4 +39,4 @@ export const RemovedFromWorkspaceEmail = ({
)
}

export default RemovedFromWorkspaceEmail
export default RemovedFromWorkspaceEmail
4 changes: 3 additions & 1 deletion apps/cli/src/commands/workspace.command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import ListWorkspace from '@/commands/workspace/list.workspace'
import SearchWorkspace from '@/commands/workspace/search.workspace'
import UpdateWorkspace from '@/commands/workspace/update.workspace'
import WorkspaceRoleCommand from '@/commands/workspace/role.workspace'
import WorkspaceMembershipCommand from './workspace/membership.workspace'

export default class WorkspaceCommand extends BaseCommand {
getName(): string {
Expand All @@ -26,7 +27,8 @@ export default class WorkspaceCommand extends BaseCommand {
new ListWorkspace(),
new SearchWorkspace(),
new UpdateWorkspace(),
new WorkspaceRoleCommand()
new WorkspaceRoleCommand(),
new WorkspaceMembershipCommand()
]
}
}
34 changes: 34 additions & 0 deletions apps/cli/src/commands/workspace/membership.workspace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import BaseCommand from '../base.command'
import AcceptInvitationCommand from './membership/accept-invitation.membership'
import CancelInvitationCommand from './membership/cancel-invitation.membership'
import DeclineInvitationCommand from './membership/decline-invitation.membership'
import GetAllMembersOfWorkspaceCommand from './membership/get-all-members.membership'
import InviteUserCommand from './membership/invite.membership'
import { LeaveWorkspaceCommand } from './membership/leave.membership'
import RemoveUserCommand from './membership/remove.membership'
import TransferOwnershipCommand from './membership/transfer-ownership.membership copy'
import UpdateRolesCommand from './membership/update-role.membership'

export default class WorkspaceMembershipCommand extends BaseCommand {
getName(): string {
return 'membership'
}

getDescription(): string {
return 'Manage workspace memberships'
}

getSubCommands(): BaseCommand[] {
return [
new AcceptInvitationCommand(),
new CancelInvitationCommand(),
new DeclineInvitationCommand(),
new GetAllMembersOfWorkspaceCommand(),
new InviteUserCommand(),
new LeaveWorkspaceCommand(),
new RemoveUserCommand(),
new TransferOwnershipCommand(),
new UpdateRolesCommand()
]
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import BaseCommand from '@/commands/base.command'
import {
type CommandActionData,
type CommandArgument
} from '@/types/command/command.types'
import ControllerInstance from '@/util/controller-instance'
import { Logger } from '@/util/logger'

export default class AcceptInvitationCommand extends BaseCommand {
getName(): string {
return 'accept-invitation'
}

getDescription(): string {
return 'Accept invitation for a workspace'
}

getArguments(): CommandArgument[] {
return [
{
name: '<Workspace Slug>',
description: 'Slug of the workspace which you want to fetch.'
}
]
}

canMakeHttpRequests(): boolean {
return true
}

async action({ args }: CommandActionData): Promise<void> {
const [workspaceSlug] = args

const { error, success } =
await ControllerInstance.getInstance().workspaceMembershipController.acceptInvitation(
{
workspaceSlug
},
this.headers
)

if (success) {
Logger.info('Accepted invitation sucessfully!')
Logger.info(`Workspace slug: ${workspaceSlug}`)
} else {
Logger.error(`Failed to accept invitation: ${error.message}`)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import BaseCommand from '@/commands/base.command'
import {
type CommandActionData,
type CommandArgument
} from '@/types/command/command.types'
import { Logger } from '@/util/logger'
import ControllerInstance from '@/util/controller-instance'

export default class CancelInvitationCommand extends BaseCommand {
getName(): string {
return 'cancel-invitation'
}

getDescription(): string {
return 'Cancel invitation sent to a user'
}

getArguments(): CommandArgument[] {
return [
{
name: '<Workspace Slug>',
description: 'Slug of the workspace which you want to fetch.'
},
{
name: '<Invitee Email>',
description: 'Email of the user that was invited.'
}
]
}

canMakeHttpRequests(): boolean {
return true
}

async action({ args }: CommandActionData): Promise<void> {
const [workspaceSlug, userEmail] = args

const { error, success } =
await ControllerInstance.getInstance().workspaceMembershipController.cancelInvitation(
{
workspaceSlug,
userEmail
},
this.headers
)

if (success) {
Logger.info('Cancelled an invitation for workspace successfully!')
Logger.info(`Workspace slug: ${workspaceSlug}`)
Logger.info(`Invitee: ${userEmail}`)
} else {
Logger.error(`Failed to cancel invitation: ${error.message}`)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import BaseCommand from '@/commands/base.command'
import {
type CommandActionData,
type CommandArgument
} from '@/types/command/command.types'
import ControllerInstance from '@/util/controller-instance'
import { Logger } from '@/util/logger'

export default class DeclineInvitationCommand extends BaseCommand {
getName(): string {
return 'decline-invitation'
}

getDescription(): string {
return 'Decline invitation of a workspace'
}

getArguments(): CommandArgument[] {
return [
{
name: '<Workspace Slug>',
description: 'Slug of the workspace which you want to fetch.'
}
]
}

canMakeHttpRequests(): boolean {
return true
}

async action({ args }: CommandActionData): Promise<void> {
const [workspaceSlug] = args

const { error, success } =
await ControllerInstance.getInstance().workspaceMembershipController.declineInvitation(
{
workspaceSlug
},
this.headers
)

if (success) {
Logger.info('Declined invitation sucessfully!')
Logger.info(`Workspace slug: ${workspaceSlug}`)
} else {
Logger.error(`Failed to decline invitation: ${error.message}`)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import BaseCommand from '@/commands/base.command'
import {
type CommandActionData,
type CommandArgument,
type CommandOption
} from '@/types/command/command.types'
import { Logger } from '@/util/logger'
import ControllerInstance from '@/util/controller-instance'
import { PAGINATION_OPTION } from '@/util/pagination-options'

export default class GetAllMembersOfWorkspaceCommand extends BaseCommand {
getName(): string {
return 'list'
}

getDescription(): string {
return 'List all members of a workspace'
}

getArguments(): CommandArgument[] {
return [
{
name: '<Workspace Slug>',
description: 'Slug of the workspace whose roles you want.'
}
]
}

getOptions(): CommandOption[] {
return PAGINATION_OPTION
}

async action({ args, options }: CommandActionData): Promise<void> {
Logger.info("Fetching workspace's members...")

const [workspaceSlug] = args

const { data, error, success } =
await ControllerInstance.getInstance().workspaceMembershipController.getMembers(
{
workspaceSlug,
...options
},
this.headers
)

if (success) {
Logger.info('Workspace Members fetched successfully:')
const members = data.items
if (members.length > 0) {
Logger.info('Email\tRole')
members.forEach((member) => {
Logger.info(
`- ${member.user.email} (${member.roles.map((role) => role.role.name).join(', ')})`
)
})
} else {
Logger.info('No members found')
}
} else {
Logger.error(`Failed fetching members: ${error.message}`)
}
}
}
Loading

0 comments on commit 0fde62b

Please sign in to comment.