mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-10 18:01:59 +00:00
129 lines
3.7 KiB
TypeScript
129 lines
3.7 KiB
TypeScript
import { Service, Inject } from 'typedi';
|
|
import moment from 'moment';
|
|
import { ServiceError } from '@/exceptions';
|
|
import { Invite, SystemUser, Tenant } from '@/system/models';
|
|
import { hashPassword } from 'utils';
|
|
import events from '@/subscribers/events';
|
|
import {
|
|
IAcceptInviteEventPayload,
|
|
IInviteUserInput,
|
|
ICheckInviteEventPayload,
|
|
IUserInvite,
|
|
} from '@/interfaces';
|
|
import { ERRORS } from './constants';
|
|
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
|
import { IAcceptInviteUserService } from '@/interfaces';
|
|
|
|
@Service()
|
|
export default class AcceptInviteUserService
|
|
implements IAcceptInviteUserService
|
|
{
|
|
@Inject()
|
|
private eventPublisher: EventPublisher;
|
|
|
|
/**
|
|
* Accept the received invite.
|
|
* @param {string} token
|
|
* @param {IInviteUserInput} inviteUserInput
|
|
* @throws {ServiceErrors}
|
|
* @returns {Promise<void>}
|
|
*/
|
|
public async acceptInvite(
|
|
token: string,
|
|
inviteUserDTO: IInviteUserInput
|
|
): Promise<void> {
|
|
// Retrieve the invite token or throw not found error.
|
|
const inviteToken = await this.getInviteTokenOrThrowError(token);
|
|
|
|
// Hash the given password.
|
|
const hashedPassword = await hashPassword(inviteUserDTO.password);
|
|
|
|
// Retrieve the system user.
|
|
const user = await SystemUser.query().findOne('email', inviteToken.email);
|
|
|
|
// Sets the invited user details after invite accepting.
|
|
const systemUser = await SystemUser.query().updateAndFetchById(
|
|
inviteToken.userId,
|
|
{
|
|
...inviteUserDTO,
|
|
inviteAcceptedAt: moment().format('YYYY-MM-DD'),
|
|
password: hashedPassword,
|
|
}
|
|
);
|
|
// Clear invite token by the given user id.
|
|
await this.clearInviteTokensByUserId(inviteToken.userId);
|
|
|
|
// Triggers `onUserAcceptInvite` event.
|
|
await this.eventPublisher.emitAsync(events.inviteUser.acceptInvite, {
|
|
inviteToken,
|
|
user: systemUser,
|
|
inviteUserDTO,
|
|
} as IAcceptInviteEventPayload);
|
|
}
|
|
|
|
/**
|
|
* Validate the given invite token.
|
|
* @param {string} token - the given token string.
|
|
* @throws {ServiceError}
|
|
*/
|
|
public async checkInvite(
|
|
token: string
|
|
): Promise<{ inviteToken: IUserInvite; orgName: object }> {
|
|
const inviteToken = await this.getInviteTokenOrThrowError(token);
|
|
|
|
// Find the tenant that associated to the given token.
|
|
const tenant = await Tenant.query()
|
|
.findById(inviteToken.tenantId)
|
|
.withGraphFetched('metadata');
|
|
|
|
// Triggers `onUserCheckInvite` event.
|
|
await this.eventPublisher.emitAsync(events.inviteUser.checkInvite, {
|
|
inviteToken,
|
|
tenant,
|
|
} as ICheckInviteEventPayload);
|
|
|
|
return { inviteToken, orgName: tenant.metadata.name };
|
|
}
|
|
|
|
/**
|
|
* Retrieve invite model from the given token or throw error.
|
|
* @param {string} token - Then given token string.
|
|
* @throws {ServiceError}
|
|
* @returns {Invite}
|
|
*/
|
|
private getInviteTokenOrThrowError = async (
|
|
token: string
|
|
): Promise<IUserInvite> => {
|
|
const inviteToken = await Invite.query()
|
|
.modify('notExpired')
|
|
.findOne('token', token);
|
|
|
|
if (!inviteToken) {
|
|
throw new ServiceError(ERRORS.INVITE_TOKEN_INVALID);
|
|
}
|
|
return inviteToken;
|
|
};
|
|
|
|
/**
|
|
* Validate the given user email and phone number uniquine.
|
|
* @param {IInviteUserInput} inviteUserInput
|
|
*/
|
|
private validateUserPhoneNumberNotExists = async (
|
|
phoneNumber: string
|
|
): Promise<void> => {
|
|
const foundUser = await SystemUser.query().findOne({ phoneNumber });
|
|
|
|
if (foundUser) {
|
|
throw new ServiceError(ERRORS.PHONE_NUMBER_EXISTS);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clear invite tokens of the given user id.
|
|
* @param {number} userId - User id.
|
|
*/
|
|
private clearInviteTokensByUserId = async (userId: number) => {
|
|
await Invite.query().where('user_id', userId).delete();
|
|
};
|
|
}
|