feat: revokeUserInviteByAdmin mutation added and invitedUsers query updated
This commit is contained in:
@@ -269,6 +269,25 @@ export class AdminResolver {
|
||||
return invitedUser.right;
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean, { description: 'Revoke a user invite by ID' })
|
||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||
async revokeUserInviteByAdmin(
|
||||
@GqlAdmin() adminUser: Admin,
|
||||
@Args({
|
||||
name: 'inviteeEmail',
|
||||
description: 'Invite Email',
|
||||
type: () => ID,
|
||||
})
|
||||
inviteeEmail: string,
|
||||
): Promise<boolean> {
|
||||
const invite = await this.adminService.revokeUserInvite(
|
||||
inviteeEmail,
|
||||
adminUser,
|
||||
);
|
||||
if (E.isLeft(invite)) throwErr(invite.left);
|
||||
return invite.right;
|
||||
}
|
||||
|
||||
@Mutation(() => Boolean, {
|
||||
description: 'Delete an user account from infra',
|
||||
})
|
||||
@@ -471,4 +490,14 @@ export class AdminResolver {
|
||||
userInvited(@GqlUser() admin: AuthUser) {
|
||||
return this.pubsub.asyncIterator(`admin/${admin.uid}/invited`);
|
||||
}
|
||||
|
||||
@Subscription(() => InvitedUser, {
|
||||
description: 'Listen for User Revocation',
|
||||
resolve: (value) => value,
|
||||
})
|
||||
@SkipThrottle()
|
||||
@UseGuards(GqlAuthGuard, GqlAdminGuard)
|
||||
userRevoked(@GqlUser() admin: AuthUser) {
|
||||
return this.pubsub.asyncIterator(`admin/${admin.uid}/revoked`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,10 +11,10 @@ import {
|
||||
INVALID_EMAIL,
|
||||
ONLY_ONE_ADMIN_ACCOUNT,
|
||||
TEAM_INVITE_ALREADY_MEMBER,
|
||||
TEAM_INVITE_NO_INVITE_FOUND,
|
||||
USER_ALREADY_INVITED,
|
||||
USER_IS_ADMIN,
|
||||
USER_NOT_FOUND,
|
||||
USER_NOT_INVITED,
|
||||
} from '../errors';
|
||||
import { MailerService } from '../mailer/mailer.service';
|
||||
import { InvitedUser } from './invited-user.model';
|
||||
@@ -26,6 +26,7 @@ import { TeamInvitationService } from '../team-invitation/team-invitation.servic
|
||||
import { TeamMemberRole } from '../team/team.model';
|
||||
import { ShortcodeService } from 'src/shortcode/shortcode.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Admin } from './admin.model';
|
||||
|
||||
@Injectable()
|
||||
export class AdminService {
|
||||
@@ -110,18 +111,69 @@ export class AdminService {
|
||||
return E.right(invitedUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke the invitation of a user to join infra.
|
||||
* @param inviteeEmail Invitee's email
|
||||
* @param adminUser Admin object
|
||||
* @returns an Either of array of `InvitedUser` object or error string
|
||||
*/
|
||||
async revokeUserInvite(inviteeEmail: string, adminUser: Admin) {
|
||||
try {
|
||||
const deletedInvitee = await this.prisma.invitedUsers.delete({
|
||||
where: {
|
||||
inviteeEmail,
|
||||
},
|
||||
});
|
||||
|
||||
const invitedUser = <InvitedUser>{
|
||||
adminEmail: deletedInvitee.adminEmail,
|
||||
adminUid: deletedInvitee.adminUid,
|
||||
inviteeEmail: deletedInvitee.inviteeEmail,
|
||||
invitedOn: deletedInvitee.invitedOn,
|
||||
};
|
||||
|
||||
this.pubsub.publish(`admin/${adminUser.uid}/revoked`, invitedUser);
|
||||
|
||||
return E.right(true);
|
||||
} catch (error) {
|
||||
return E.left(USER_NOT_INVITED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the list of invited users by the admin.
|
||||
* @returns an Either of array of `InvitedUser` object or error
|
||||
*/
|
||||
async fetchInvitedUsers() {
|
||||
const invitedUsers = await this.prisma.invitedUsers.findMany();
|
||||
const dbInvitedUsers = await this.prisma.invitedUsers.findMany();
|
||||
|
||||
const users: InvitedUser[] = invitedUsers.map(
|
||||
(user) => <InvitedUser>{ ...user },
|
||||
);
|
||||
const invitationAcceptedUsers = await this.prisma.user.findMany({
|
||||
where: {
|
||||
email: {
|
||||
in: dbInvitedUsers.map((user) => user.inviteeEmail),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return users;
|
||||
let invitedUsers: InvitedUser[] = [];
|
||||
|
||||
dbInvitedUsers.forEach((dbInvitedUser) => {
|
||||
const isUserAccepts = invitationAcceptedUsers.find(
|
||||
(user) => user.email === dbInvitedUser.inviteeEmail,
|
||||
);
|
||||
|
||||
const invitedUser: InvitedUser = {
|
||||
adminEmail: dbInvitedUser.adminEmail,
|
||||
adminUid: dbInvitedUser.adminUid,
|
||||
inviteeEmail: dbInvitedUser.inviteeEmail,
|
||||
invitedOn: dbInvitedUser.invitedOn,
|
||||
isInvitationAccepted: isUserAccepts ? true : false,
|
||||
};
|
||||
|
||||
invitedUsers.push(invitedUser);
|
||||
});
|
||||
|
||||
return invitedUsers;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,4 +21,10 @@ export class InvitedUser {
|
||||
description: 'Date when the user invitation was sent',
|
||||
})
|
||||
invitedOn: Date;
|
||||
|
||||
@Field({
|
||||
description: 'Boolean status if invitation was accepted or not',
|
||||
defaultValue: false,
|
||||
})
|
||||
isInvitationAccepted: boolean;
|
||||
}
|
||||
|
||||
@@ -65,6 +65,11 @@ export const USER_FB_DOCUMENT_DELETION_FAILED =
|
||||
*/
|
||||
export const USER_NOT_FOUND = 'user/not_found' as const;
|
||||
|
||||
/**
|
||||
* User is not invited by admin
|
||||
*/
|
||||
export const USER_NOT_INVITED = 'admin/user_not_invited' as const;
|
||||
|
||||
/**
|
||||
* User is already invited by admin
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ import { Shortcode } from 'src/shortcode/shortcode.model';
|
||||
// A custom message type that defines the topic and the corresponding payload.
|
||||
// For every module that publishes a subscription add its type def and the possible subscription type.
|
||||
export type TopicDef = {
|
||||
[topic: `admin/${string}/${'invited'}`]: InvitedUser;
|
||||
[topic: `admin/${string}/${'invited' | 'revoked'}`]: InvitedUser;
|
||||
[topic: `user/${string}/${'updated' | 'deleted'}`]: User;
|
||||
[topic: `user_settings/${string}/${'created' | 'updated'}`]: UserSettings;
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user