mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 06:10:31 +00:00
refactor: authentication module to nestjs
This commit is contained in:
@@ -79,6 +79,7 @@ import { SubscriptionModule } from '../Subscription/Subscription.module';
|
||||
import { OrganizationModule } from '../Organization/Organization.module';
|
||||
import { TenantDBManagerModule } from '../TenantDBManager/TenantDBManager.module';
|
||||
import { PaymentServicesModule } from '../PaymentServices/PaymentServices.module';
|
||||
import { AuthModule } from '../Auth/Auth.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -193,6 +194,7 @@ import { PaymentServicesModule } from '../PaymentServices/PaymentServices.module
|
||||
OrganizationModule,
|
||||
TenantDBManagerModule,
|
||||
PaymentServicesModule,
|
||||
AuthModule,
|
||||
],
|
||||
controllers: [AppController],
|
||||
providers: [
|
||||
|
||||
@@ -2,3 +2,18 @@ export const jwtConstants = {
|
||||
secret:
|
||||
'DO NOT USE THIS VALUE. INSTEAD, CREATE A COMPLEX SECRET AND KEEP IT SAFE OUTSIDE OF THE SOURCE CODE.',
|
||||
};
|
||||
|
||||
export const ERRORS = {
|
||||
INVALID_DETAILS: 'INVALID_DETAILS',
|
||||
USER_INACTIVE: 'USER_INACTIVE',
|
||||
EMAIL_NOT_FOUND: 'EMAIL_NOT_FOUND',
|
||||
TOKEN_INVALID: 'TOKEN_INVALID',
|
||||
USER_NOT_FOUND: 'USER_NOT_FOUND',
|
||||
TOKEN_EXPIRED: 'TOKEN_EXPIRED',
|
||||
PHONE_NUMBER_EXISTS: 'PHONE_NUMBER_EXISTS',
|
||||
EMAIL_EXISTS: 'EMAIL_EXISTS',
|
||||
SIGNUP_RESTRICTED_NOT_ALLOWED: 'SIGNUP_RESTRICTED_NOT_ALLOWED',
|
||||
SIGNUP_RESTRICTED: 'SIGNUP_RESTRICTED',
|
||||
SIGNUP_CONFIRM_TOKEN_INVALID: 'SIGNUP_CONFIRM_TOKEN_INVALID',
|
||||
USER_ALREADY_VERIFIED: 'USER_ALREADY_VERIFIED',
|
||||
};
|
||||
|
||||
25
packages/server-nest/src/modules/Auth/Auth.controller.ts
Normal file
25
packages/server-nest/src/modules/Auth/Auth.controller.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { Body, Controller, Post, Request } from '@nestjs/common';
|
||||
import { PublicRoute } from './Jwt.guard';
|
||||
import { AuthenticationApplication } from './AuthApplication.sevice';
|
||||
import { AuthSignupDto } from './dtos/AuthSignup.dto';
|
||||
import { AuthSigninDto } from './dtos/AuthSignin.dto';
|
||||
|
||||
@Controller('/auth')
|
||||
@PublicRoute()
|
||||
export class AuthController {
|
||||
constructor(private readonly authApp: AuthenticationApplication) {}
|
||||
@Post('/signin')
|
||||
signin(@Request() req: Request, @Body() signinDto: AuthSigninDto) {
|
||||
return this.authApp.signIn(signinDto);
|
||||
}
|
||||
|
||||
@Post('/signup')
|
||||
signup(@Request() req: Request, @Body() signupDto: AuthSignupDto) {
|
||||
this.authApp.signUp(signupDto);
|
||||
}
|
||||
|
||||
@Post('/signup/confirm')
|
||||
signupConfirm(@Body('email') email: string, @Body('token') token: string) {
|
||||
return this.authApp.signUpConfirm(email, token);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,72 @@
|
||||
import { ModelObject } from 'objection';
|
||||
import { SystemUser } from '../System/models/SystemUser';
|
||||
import { TenantModel } from '../System/models/TenantModel';
|
||||
import { AuthSignupDto } from './dtos/AuthSignup.dto';
|
||||
|
||||
export interface IAuthSignedInEventPayload {}
|
||||
|
||||
export interface IAuthSigningInEventPayload {}
|
||||
|
||||
export interface IAuthSignInPOJO {}
|
||||
|
||||
export interface IAuthSigningInEventPayload {
|
||||
email: string;
|
||||
password: string;
|
||||
user: ModelObject<SystemUser>;
|
||||
}
|
||||
|
||||
export interface IAuthSignedInEventPayload {
|
||||
email: string;
|
||||
password: string;
|
||||
user: ModelObject<SystemUser>;
|
||||
}
|
||||
|
||||
export interface IAuthSigningUpEventPayload {
|
||||
signupDTO: AuthSignupDto;
|
||||
}
|
||||
|
||||
export interface IAuthSignedUpEventPayload {
|
||||
signupDTO: AuthSignupDto;
|
||||
tenant: TenantModel;
|
||||
user: SystemUser;
|
||||
}
|
||||
|
||||
export interface IAuthSignInPOJO {
|
||||
user: ModelObject<SystemUser>;
|
||||
token: string;
|
||||
tenant: ModelObject<TenantModel>;
|
||||
}
|
||||
|
||||
export interface IAuthResetedPasswordEventPayload {
|
||||
user: SystemUser;
|
||||
token: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface IAuthSendingResetPassword {
|
||||
user: SystemUser;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface IAuthSendedResetPassword {
|
||||
user: SystemUser;
|
||||
token: string;
|
||||
}
|
||||
|
||||
export interface IAuthGetMetaPOJO {
|
||||
signupDisabled: boolean;
|
||||
oneClickDemo: {
|
||||
enable: boolean;
|
||||
demoUrl: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IAuthSignUpVerifingEventPayload {
|
||||
email: string;
|
||||
verifyToken: string;
|
||||
userId: number;
|
||||
}
|
||||
|
||||
export interface IAuthSignUpVerifiedEventPayload {
|
||||
email: string;
|
||||
verifyToken: string;
|
||||
userId: number;
|
||||
}
|
||||
|
||||
34
packages/server-nest/src/modules/Auth/Auth.module.ts
Normal file
34
packages/server-nest/src/modules/Auth/Auth.module.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { AuthService } from './AuthService';
|
||||
import { AuthController } from './Auth.controller';
|
||||
import { JwtModule } from '@nestjs/jwt';
|
||||
import { JwtStrategy } from './Jwt.strategy';
|
||||
import { AuthenticationApplication } from './AuthApplication.sevice';
|
||||
import { AuthSendResetPasswordService } from './commands/AuthSendResetPassword.service';
|
||||
import { AuthResetPasswordService } from './commands/AuthResetPassword.service';
|
||||
import { AuthSignupConfirmResendService } from './commands/AuthSignupConfirmResend.service';
|
||||
import { AuthSignupConfirmService } from './commands/AuthSignupConfirm.service';
|
||||
import { AuthSignupService } from './commands/AuthSignup.service';
|
||||
import { AuthSigninService } from './commands/AuthSignin.service';
|
||||
|
||||
@Module({
|
||||
controllers: [AuthController],
|
||||
imports: [
|
||||
JwtModule.register({
|
||||
secret: 'asdfasdfasdf',
|
||||
signOptions: { expiresIn: '60s' },
|
||||
}),
|
||||
],
|
||||
providers: [
|
||||
AuthService,
|
||||
JwtStrategy,
|
||||
AuthenticationApplication,
|
||||
AuthSendResetPasswordService,
|
||||
AuthResetPasswordService,
|
||||
AuthSignupConfirmResendService,
|
||||
AuthSignupConfirmService,
|
||||
AuthSignupService,
|
||||
AuthSigninService,
|
||||
],
|
||||
})
|
||||
export class AuthModule {}
|
||||
10
packages/server-nest/src/modules/Auth/Auth.utils.ts
Normal file
10
packages/server-nest/src/modules/Auth/Auth.utils.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import * as bcrypt from 'bcrypt';
|
||||
|
||||
export const hashPassword = (password: string): Promise<string> =>
|
||||
new Promise((resolve) => {
|
||||
bcrypt.genSalt(10, (error, salt) => {
|
||||
bcrypt.hash(password, salt, (err, hash: string) => {
|
||||
resolve(hash);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,86 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { AuthSigninService } from './commands/AuthSignin.service';
|
||||
import { AuthSignupService } from './commands/AuthSignup.service';
|
||||
import { AuthSignupConfirmService } from './commands/AuthSignupConfirm.service';
|
||||
import { AuthSignupConfirmResendService } from './commands/AuthSignupConfirmResend.service';
|
||||
import { AuthSigninDto } from './dtos/AuthSignin.dto';
|
||||
import { AuthSignupDto } from './dtos/AuthSignup.dto';
|
||||
import { AuthSendResetPasswordService } from './commands/AuthSendResetPassword.service';
|
||||
import { AuthResetPasswordService } from './commands/AuthResetPassword.service';
|
||||
|
||||
export class AuthApplication {
|
||||
|
||||
@Injectable()
|
||||
export class AuthenticationApplication {
|
||||
constructor(
|
||||
private readonly authSigninService: AuthSigninService,
|
||||
private readonly authSignupService: AuthSignupService,
|
||||
private readonly authSignupConfirmService: AuthSignupConfirmService,
|
||||
private readonly authSignUpConfirmResendService: AuthSignupConfirmResendService,
|
||||
private readonly authResetPasswordService: AuthResetPasswordService,
|
||||
private readonly authSendResetPasswordService: AuthSendResetPasswordService,
|
||||
// private readonly authGetMeta: GetAuthMeta,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Signin and generates JWT token.
|
||||
* @throws {ServiceError}
|
||||
* @param {string} email - Email address.
|
||||
* @param {string} password - Password.
|
||||
*/
|
||||
public async signIn(signinDto: AuthSigninDto) {
|
||||
return this.authSigninService.signIn(signinDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signup a new user.
|
||||
* @param {IRegisterDTO} signupDTO
|
||||
*/
|
||||
public async signUp(signupDto: AuthSignupDto) {
|
||||
return this.authSignupService.signUp(signupDto);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifying the provided user's email after signin-up.
|
||||
* @param {string} email - User email.
|
||||
* @param {string} token - Verification token.
|
||||
* @returns {Promise<SystemUser>}
|
||||
*/
|
||||
public async signUpConfirm(email: string, token: string) {
|
||||
return this.authSignupConfirmService.signupConfirm(email, token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-sends the confirmation email of the given system user.
|
||||
* @param {number} userId - System user id.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async signUpConfirmResend(userId: number) {
|
||||
return this.authSignUpConfirmResendService.signUpConfirmResend(userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates and retrieve password reset token for the given user email.
|
||||
* @param {string} email
|
||||
* @return {<Promise<IPasswordReset>}
|
||||
*/
|
||||
public async sendResetPassword(email: string) {
|
||||
return this.authSendResetPasswordService.sendResetPassword(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets a user password from given token.
|
||||
* @param {string} token - Password reset token.
|
||||
* @param {string} password - New Password.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public async resetPassword(token: string, password: string) {
|
||||
return this.authResetPasswordService.resetPassword(token, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the authentication meta for SPA.
|
||||
* @returns {Promise<IAuthGetMetaPOJO>}
|
||||
*/
|
||||
public async getAuthMeta() {
|
||||
// return this.authGetMeta.getAuthMeta();
|
||||
}
|
||||
}
|
||||
|
||||
22
packages/server-nest/src/modules/Auth/AuthService.ts
Normal file
22
packages/server-nest/src/modules/Auth/AuthService.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { SystemUser } from '@/modules/System/models/SystemUser';
|
||||
|
||||
@Injectable()
|
||||
export class AuthService {
|
||||
constructor(
|
||||
@Inject(SystemUser.name)
|
||||
private readonly systemUserModel: typeof SystemUser,
|
||||
) {}
|
||||
|
||||
async validateUser(username: string, pass: string): Promise<any> {
|
||||
const user = await this.systemUserModel
|
||||
.query()
|
||||
.findOne({ email: username });
|
||||
|
||||
if (user && user.password === pass) {
|
||||
const { password, ...result } = user;
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AuthResetPasswordService {
|
||||
resetPassword(token: string, password: string): Promise<{ message: string }> {
|
||||
return new Promise((resolve) => {
|
||||
resolve({ message: 'Reset password link sent to your email' });
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class AuthSendResetPasswordService {
|
||||
sendResetPassword(email: string): Promise<{ message: string }> {
|
||||
return new Promise((resolve) => {
|
||||
resolve({ message: 'Reset password link sent to your email' });
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { SystemUser } from '@/modules/System/models/SystemUser';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { AuthSigninDto } from '../dtos/AuthSignin.dto';
|
||||
|
||||
@Injectable()
|
||||
export class AuthSigninService {
|
||||
constructor(
|
||||
private readonly jwtService: JwtService,
|
||||
|
||||
@Inject(SystemUser.name)
|
||||
private readonly systemUserModel: typeof SystemUser,
|
||||
) {}
|
||||
|
||||
private async validate() {}
|
||||
|
||||
private getUserByEmail(email: string) {
|
||||
return this.systemUserModel.query().findOne({ email });
|
||||
}
|
||||
|
||||
public async signIn(signinDto: AuthSigninDto) {}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
import crypto from 'crypto';
|
||||
import { events } from '@/common/events/events';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { SystemUser } from '@/modules/System/models/SystemUser';
|
||||
import { TenantsManagerService } from '@/modules/TenantDBManager/TenantsManager';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { isEmpty } from 'class-validator';
|
||||
import { AuthSignupDto } from '../dtos/AuthSignup.dto';
|
||||
import {
|
||||
IAuthSignedUpEventPayload,
|
||||
IAuthSigningUpEventPayload,
|
||||
} from '../Auth.interfaces';
|
||||
import { defaultTo } from 'ramda';
|
||||
import { ERRORS } from '../Auth.constants';
|
||||
import { hashPassword } from '../Auth.utils';
|
||||
|
||||
@Injectable()
|
||||
export class AuthSignupService {
|
||||
/**
|
||||
* @param {ConfigService} configService - Config service
|
||||
* @param {EventEmitter2} eventEmitter - Event emitter
|
||||
* @param {TenantsManagerService} tenantsManager - Tenants manager
|
||||
* @param {typeof SystemUser} systemUserModel - System user model
|
||||
*/
|
||||
constructor(
|
||||
private readonly configService: ConfigService,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly tenantsManager: TenantsManagerService,
|
||||
|
||||
@Inject(SystemUser.name)
|
||||
private readonly systemUserModel: typeof SystemUser,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Registers a new tenant with user from user input.
|
||||
* @param {AuthSignupDto} signupDTO
|
||||
*/
|
||||
public async signUp(signupDTO: AuthSignupDto) {
|
||||
// Validates the signup disable restrictions.
|
||||
await this.validateSignupRestrictions(signupDTO.email);
|
||||
|
||||
// Validates the given email uniqiness.
|
||||
await this.validateEmailUniqiness(signupDTO.email);
|
||||
|
||||
const hashedPassword = await hashPassword(signupDTO.password);
|
||||
const signupConfirmation = this.configService.get('signupConfirmation');
|
||||
|
||||
const verifyTokenCrypto = crypto.randomBytes(64).toString('hex');
|
||||
const verifiedEnabed = defaultTo(signupConfirmation.enabled, false);
|
||||
const verifyToken = verifiedEnabed ? verifyTokenCrypto : '';
|
||||
const verified = !verifiedEnabed;
|
||||
|
||||
const inviteAcceptedAt = moment().format('YYYY-MM-DD');
|
||||
|
||||
// Triggers signin up event.
|
||||
await this.eventEmitter.emitAsync(events.auth.signingUp, {
|
||||
signupDTO,
|
||||
} as IAuthSigningUpEventPayload);
|
||||
|
||||
const tenant = await this.tenantsManager.createTenant();
|
||||
const user = await this.systemUserModel.query().insert({
|
||||
...signupDTO,
|
||||
verifyToken,
|
||||
verified,
|
||||
active: true,
|
||||
password: hashedPassword,
|
||||
tenantId: tenant.id,
|
||||
inviteAcceptedAt,
|
||||
});
|
||||
// Triggers signed up event.
|
||||
await this.eventEmitter.emitAsync(events.auth.signUp, {
|
||||
signupDTO,
|
||||
tenant,
|
||||
user,
|
||||
} as IAuthSignedUpEventPayload);
|
||||
|
||||
return {
|
||||
userId: user.id,
|
||||
tenantId: user.tenantId,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates email uniqiness on the storage.
|
||||
* @param {string} email - Email address
|
||||
*/
|
||||
private async validateEmailUniqiness(email: string) {
|
||||
const isEmailExists = await this.systemUserModel.query().findOne({ email });
|
||||
|
||||
if (isEmailExists) {
|
||||
throw new ServiceError(ERRORS.EMAIL_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate sign-up disable restrictions.
|
||||
* @param {string} email - Signup email address
|
||||
*/
|
||||
private async validateSignupRestrictions(email: string) {
|
||||
const signupRestrictions = this.configService.get('signupRestrictions');
|
||||
|
||||
// Can't continue if the signup is not disabled.
|
||||
if (!signupRestrictions.disabled) return;
|
||||
|
||||
// Validate the allowed email addresses and domains.
|
||||
if (
|
||||
!isEmpty(signupRestrictions.allowedEmails) ||
|
||||
!isEmpty(signupRestrictions.allowedDomains)
|
||||
) {
|
||||
const emailDomain = email.split('@').pop();
|
||||
const isAllowedEmail =
|
||||
signupRestrictions.allowedEmails.indexOf(email) !== -1;
|
||||
|
||||
const isAllowedDomain = signupRestrictions.allowedDomains.some(
|
||||
(domain) => emailDomain === domain,
|
||||
);
|
||||
|
||||
if (!isAllowedEmail && !isAllowedDomain) {
|
||||
throw new ServiceError(ERRORS.SIGNUP_RESTRICTED_NOT_ALLOWED);
|
||||
}
|
||||
// Throw error if the signup is disabled with no exceptions.
|
||||
} else {
|
||||
throw new ServiceError(ERRORS.SIGNUP_RESTRICTED);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { SystemUser } from '@/modules/System/models/SystemUser';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { ERRORS } from '../Auth.constants';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IAuthSignUpVerifiedEventPayload,
|
||||
IAuthSignUpVerifingEventPayload,
|
||||
} from '../Auth.interfaces';
|
||||
import { events } from '@/common/events/events';
|
||||
|
||||
@Injectable()
|
||||
export class AuthSignupConfirmService {
|
||||
constructor(
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
|
||||
@Inject(SystemUser.name)
|
||||
private readonly systemUserModel: typeof SystemUser,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Verifies the provided user's email after signing-up.
|
||||
* @throws {ServiceErrors}
|
||||
* @param {IRegisterDTO} signupDTO
|
||||
* @returns {Promise<ISystemUser>}
|
||||
*/
|
||||
public async signupConfirm(
|
||||
email: string,
|
||||
verifyToken: string,
|
||||
): Promise<SystemUser> {
|
||||
const foundUser = await this.systemUserModel
|
||||
.query()
|
||||
.findOne({ email, verifyToken });
|
||||
|
||||
if (!foundUser) {
|
||||
throw new ServiceError(ERRORS.SIGNUP_CONFIRM_TOKEN_INVALID);
|
||||
}
|
||||
const userId = foundUser.id;
|
||||
|
||||
// Triggers `signUpConfirming` event.
|
||||
await this.eventPublisher.emitAsync(events.auth.signUpConfirming, {
|
||||
email,
|
||||
verifyToken,
|
||||
userId,
|
||||
} as IAuthSignUpVerifingEventPayload);
|
||||
|
||||
const updatedUser = await this.systemUserModel
|
||||
.query()
|
||||
.patchAndFetchById(foundUser.id, {
|
||||
verified: true,
|
||||
verifyToken: '',
|
||||
});
|
||||
// Triggers `signUpConfirmed` event.
|
||||
await this.eventPublisher.emitAsync(events.auth.signUpConfirmed, {
|
||||
email,
|
||||
verifyToken,
|
||||
userId,
|
||||
} as IAuthSignUpVerifiedEventPayload);
|
||||
|
||||
return updatedUser as SystemUser;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export class AuthSignupConfirmResendService {
|
||||
signUpConfirmResend(userId: number) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
11
packages/server-nest/src/modules/Auth/dtos/AuthSignin.dto.ts
Normal file
11
packages/server-nest/src/modules/Auth/dtos/AuthSignin.dto.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class AuthSigninDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
password: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
email: string;
|
||||
}
|
||||
20
packages/server-nest/src/modules/Auth/dtos/AuthSignup.dto.ts
Normal file
20
packages/server-nest/src/modules/Auth/dtos/AuthSignup.dto.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class AuthSignupDto {
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
firstName: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
lastName: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
@IsEmail()
|
||||
email: string;
|
||||
|
||||
@IsNotEmpty()
|
||||
@IsString()
|
||||
password: string;
|
||||
}
|
||||
@@ -1,26 +1,22 @@
|
||||
/* eslint-disable global-require */
|
||||
import * as moment from 'moment';
|
||||
import { Model } from 'objection';
|
||||
// import TenantModel from 'models/TenantModel';
|
||||
// import ModelSettings from './ModelSetting';
|
||||
// import UncategorizedCashflowTransactionMeta from './UncategorizedCashflowTransaction.meta';
|
||||
import { BaseModel } from '@/models/Model';
|
||||
|
||||
export class UncategorizedBankTransaction extends BaseModel {
|
||||
amount!: number;
|
||||
date!: Date | string;
|
||||
categorized!: boolean;
|
||||
accountId!: number;
|
||||
referenceNo!: string;
|
||||
payee!: string;
|
||||
description!: string;
|
||||
plaidTransactionId!: string;
|
||||
recognizedTransactionId!: number;
|
||||
excludedAt: Date;
|
||||
pending: boolean;
|
||||
|
||||
categorizeRefId!: number;
|
||||
categorizeRefType!: string;
|
||||
readonly amount!: number;
|
||||
readonly date!: Date | string;
|
||||
readonly categorized!: boolean;
|
||||
readonly accountId!: number;
|
||||
readonly referenceNo!: string;
|
||||
readonly payee!: string;
|
||||
readonly description!: string;
|
||||
readonly plaidTransactionId!: string;
|
||||
readonly recognizedTransactionId!: number;
|
||||
readonly excludedAt: Date;
|
||||
readonly pending: boolean;
|
||||
readonly categorizeRefId!: number;
|
||||
readonly categorizeRefType!: string;
|
||||
|
||||
/**
|
||||
* Table name.
|
||||
@@ -199,7 +195,9 @@ export class UncategorizedBankTransaction extends BaseModel {
|
||||
const {
|
||||
RecognizedBankTransaction,
|
||||
} = require('../../BankingTranasctionsRegonize/models/RecognizedBankTransaction');
|
||||
const { MatchedBankTransaction } = require('../../BankingMatching/models/MatchedBankTransaction');
|
||||
const {
|
||||
MatchedBankTransaction,
|
||||
} = require('../../BankingMatching/models/MatchedBankTransaction');
|
||||
|
||||
return {
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,6 @@ import { OrganizationBuildProcessor } from './processors/OrganizationBuild.proce
|
||||
import { CommandOrganizationValidators } from './commands/CommandOrganizationValidators.service';
|
||||
import { TenancyContext } from '../Tenancy/TenancyContext.service';
|
||||
import { TenantDBManagerModule } from '../TenantDBManager/TenantDBManager.module';
|
||||
import { TenantsManagerService } from '../TenantDBManager/TenantsManager';
|
||||
import { OrganizationBaseCurrencyLocking } from './Organization/OrganizationBaseCurrencyLocking.service';
|
||||
|
||||
@Module({
|
||||
|
||||
@@ -3,10 +3,14 @@ import { BaseModel } from '@/models/Model';
|
||||
export class SystemUser extends BaseModel {
|
||||
public readonly firstName: string;
|
||||
public readonly lastName: string;
|
||||
public readonly active: boolean;
|
||||
public readonly password: string;
|
||||
public readonly email: string;
|
||||
public readonly password: string;
|
||||
|
||||
public readonly active: boolean;
|
||||
public readonly tenantId: number;
|
||||
public readonly verifyToken: string;
|
||||
public readonly verified: boolean;
|
||||
public readonly inviteAcceptedAt!: string;
|
||||
|
||||
static get tableName() {
|
||||
return 'users';
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import { Controller, Put, Get, Body, Param, UseGuards } from '@nestjs/common';
|
||||
import { Controller, Put, Get, Body, Param } from '@nestjs/common';
|
||||
import { TransactionsLockingService } from './commands/CommandTransactionsLockingService';
|
||||
import { TransactionsLockingGroup } from './types/TransactionsLocking.types';
|
||||
import { ITransactionsLockingAllDTO } from './types/TransactionsLocking.types';
|
||||
import { ICancelTransactionsLockingDTO } from './types/TransactionsLocking.types';
|
||||
import { ITransactionLockingPartiallyDTO } from './types/TransactionsLocking.types';
|
||||
import { QueryTransactionsLocking } from './queries/QueryTransactionsLocking';
|
||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||
import { ApiOperation } from '@nestjs/swagger';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { CancelTransactionsLockingDto, TransactionsLockingDto, UnlockTransactionsLockingDto } from './dtos/TransactionsLocking.dto';
|
||||
import {
|
||||
CancelTransactionsLockingDto,
|
||||
TransactionsLockingDto,
|
||||
} from './dtos/TransactionsLocking.dto';
|
||||
|
||||
@Controller('transactions-locking')
|
||||
@ApiTags('Transactions Locking')
|
||||
@@ -20,7 +21,9 @@ export class TransactionsLockingController {
|
||||
) {}
|
||||
|
||||
@Put('lock')
|
||||
@ApiOperation({ summary: 'Lock all transactions for a module or all modules' })
|
||||
@ApiOperation({
|
||||
summary: 'Lock all transactions for a module or all modules',
|
||||
})
|
||||
async commandTransactionsLocking(
|
||||
@Body('module') module: TransactionsLockingGroup,
|
||||
@Body() transactionLockingDTO: TransactionsLockingDto,
|
||||
@@ -37,7 +40,9 @@ export class TransactionsLockingController {
|
||||
}
|
||||
|
||||
@Put('cancel-lock')
|
||||
@ApiOperation({ summary: 'Cancel all transactions locking for a module or all modules' })
|
||||
@ApiOperation({
|
||||
summary: 'Cancel all transactions locking for a module or all modules',
|
||||
})
|
||||
async cancelTransactionLocking(
|
||||
@Body('module') module: TransactionsLockingGroup,
|
||||
@Body() cancelLockingDTO: CancelTransactionsLockingDto,
|
||||
@@ -53,7 +58,10 @@ export class TransactionsLockingController {
|
||||
}
|
||||
|
||||
@Put('unlock-partial')
|
||||
@ApiOperation({ summary: 'Partial unlock all transactions locking for a module or all modules' })
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Partial unlock all transactions locking for a module or all modules',
|
||||
})
|
||||
async unlockTransactionsLockingBetweenPeriod(
|
||||
@Body('module') module: TransactionsLockingGroup,
|
||||
@Body() unlockDTO: ITransactionLockingPartiallyDTO,
|
||||
@@ -70,7 +78,10 @@ export class TransactionsLockingController {
|
||||
}
|
||||
|
||||
@Put('cancel-unlock-partial')
|
||||
@ApiOperation({ summary: 'Cancel partial unlocking all transactions locking for a module or all modules' })
|
||||
@ApiOperation({
|
||||
summary:
|
||||
'Cancel partial unlocking all transactions locking for a module or all modules',
|
||||
})
|
||||
async cancelPartialUnlocking(
|
||||
@Body('module') module: TransactionsLockingGroup,
|
||||
) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { omit } from 'lodash';
|
||||
import {
|
||||
ICancelTransactionsLockingDTO,
|
||||
ITransactionLockingPartiallyDTO,
|
||||
ITransactionMeta,
|
||||
ITransactionsLockingAllDTO,
|
||||
@@ -15,7 +14,10 @@ import { Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { CancelTransactionsLockingDto, TransactionsLockingDto } from '../dtos/TransactionsLocking.dto';
|
||||
import {
|
||||
CancelTransactionsLockingDto,
|
||||
TransactionsLockingDto,
|
||||
} from '../dtos/TransactionsLocking.dto';
|
||||
|
||||
const Modules = ['all', 'sales', 'purchases', 'financial'];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user