feat(SPG-885): add validation login admin queue
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
14dd2880bc
commit
c897e4fcde
|
@ -0,0 +1,17 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddColumnItemId1726139426994 implements MigrationInterface {
|
||||||
|
name = 'AddColumnItemId1726139426994';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "users_login" ADD "item_id" uuid`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "log_users_login" ADD "item_id" uuid`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "log_users_login" DROP COLUMN "item_id"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "users_login" DROP COLUMN "item_id"`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
import { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
|
export class AddColumnItemName1726141393404 implements MigrationInterface {
|
||||||
|
name = 'AddColumnItemName1726141393404';
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "users_login" ADD "item_name" character varying`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "log_users_login" ADD "item_name" character varying`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "log_users_login" DROP COLUMN "item_name"`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "users_login" DROP COLUMN "item_name"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,11 +13,15 @@ import { AuthAdminQueueController } from './infrastructure/auth-admin-queue.cont
|
||||||
import { AuthAdminQueueOrchestrator } from './domain/auth-admin-queue.orchestrator';
|
import { AuthAdminQueueOrchestrator } from './domain/auth-admin-queue.orchestrator';
|
||||||
import { LoginAdminQueueManager } from './domain/managers/admin-queue/login-admin-queue.manager';
|
import { LoginAdminQueueManager } from './domain/managers/admin-queue/login-admin-queue.manager';
|
||||||
import { LogoutAdminQueueManager } from './domain/managers/admin-queue/logout-admin-queue.manager';
|
import { LogoutAdminQueueManager } from './domain/managers/admin-queue/logout-admin-queue.manager';
|
||||||
|
import { UserLoginModel } from 'src/modules/user-related/user/data/models/user-login.model';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
TypeOrmModule.forFeature([UserModel], CONNECTION_NAME.DEFAULT),
|
TypeOrmModule.forFeature(
|
||||||
|
[UserModel, UserLoginModel],
|
||||||
|
CONNECTION_NAME.DEFAULT,
|
||||||
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
],
|
],
|
||||||
controllers: [AuthController, AuthAdminQueueController],
|
controllers: [AuthController, AuthAdminQueueController],
|
||||||
|
|
|
@ -33,6 +33,10 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async process(): Promise<void> {
|
async process(): Promise<void> {
|
||||||
|
const itemLogin = await this.dataService.getLoginUserByItem(
|
||||||
|
this.data.item_id,
|
||||||
|
);
|
||||||
|
|
||||||
// get user active by username
|
// get user active by username
|
||||||
this.userLogin = await this.dataService.getOneByOptions({
|
this.userLogin = await this.dataService.getOneByOptions({
|
||||||
where: {
|
where: {
|
||||||
|
@ -42,6 +46,7 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
},
|
},
|
||||||
relations: ['user_login'],
|
relations: ['user_login'],
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!this.userLogin) this.throwError();
|
if (!this.userLogin) this.throwError();
|
||||||
|
|
||||||
// validasi password
|
// validasi password
|
||||||
|
@ -51,13 +56,22 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
);
|
);
|
||||||
if (!valid) this.throwError();
|
if (!valid) this.throwError();
|
||||||
|
|
||||||
if (
|
const userLoginItem = await this.dataService.getOneByOptions({
|
||||||
this.userLogin.user_login &&
|
where: {
|
||||||
this.userLogin.role === UserRole.QUEUE_ADMIN
|
id: itemLogin?.user_id,
|
||||||
) {
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.userLogin.user_login) {
|
||||||
throw new UnauthorizedException({
|
throw new UnauthorizedException({
|
||||||
statusCode: HttpStatus.UNAUTHORIZED,
|
statusCode: HttpStatus.UNAUTHORIZED,
|
||||||
message: `Gagal! akun anda sudah login di perangkat lain.`,
|
message: `Akun anda sudah login di perangkat lain.`,
|
||||||
|
error: 'Unauthorized',
|
||||||
|
});
|
||||||
|
} else if (itemLogin) {
|
||||||
|
throw new UnauthorizedException({
|
||||||
|
statusCode: HttpStatus.UNAUTHORIZED,
|
||||||
|
message: `"${userLoginItem.name}" masih login sebagai admin antrian `,
|
||||||
error: 'Unauthorized',
|
error: 'Unauthorized',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -69,6 +83,8 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
username: this.userLogin.username,
|
username: this.userLogin.username,
|
||||||
role: this.userLogin.role,
|
role: this.userLogin.role,
|
||||||
user_privilege_id: this.userLogin.user_privilege_id,
|
user_privilege_id: this.userLogin.user_privilege_id,
|
||||||
|
item_id: this.data.item_id,
|
||||||
|
item_name: this.data.item_name,
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger.debug('Sign Token Admin Queue', 'LoginAdminQueueManager');
|
Logger.debug('Sign Token Admin Queue', 'LoginAdminQueueManager');
|
||||||
|
@ -79,22 +95,21 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
|
|
||||||
Logger.debug('Update Refresh Token Admin Queue', 'LoginAdminQueueManager');
|
Logger.debug('Update Refresh Token Admin Queue', 'LoginAdminQueueManager');
|
||||||
|
|
||||||
const newDataUser = { refresh_token: refreshToken };
|
|
||||||
if (this.userLogin.role === UserRole.QUEUE_ADMIN) {
|
|
||||||
Object.assign(newDataUser, {
|
|
||||||
user_login: {
|
|
||||||
user_id: this.userLogin.id,
|
|
||||||
login_token: this.token,
|
|
||||||
login_date: new Date().getTime(),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Update refresh token
|
// Update refresh token
|
||||||
await this.dataService.update(
|
await this.dataService.update(
|
||||||
this.queryRunner,
|
this.queryRunner,
|
||||||
this.entityTarget,
|
this.entityTarget,
|
||||||
{ id: this.userLogin.id },
|
{ id: this.userLogin.id },
|
||||||
newDataUser,
|
{
|
||||||
|
refresh_token: refreshToken,
|
||||||
|
user_login: {
|
||||||
|
user_id: this.userLogin.id,
|
||||||
|
login_token: this.token,
|
||||||
|
login_date: new Date().getTime(),
|
||||||
|
item_id: this.data.item_id,
|
||||||
|
item_name: this.data.item_name,
|
||||||
|
},
|
||||||
|
},
|
||||||
);
|
);
|
||||||
await this.publishEvents();
|
await this.publishEvents();
|
||||||
|
|
||||||
|
@ -113,6 +128,8 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
username: this.userLogin.username,
|
username: this.userLogin.username,
|
||||||
role: this.userLogin.role,
|
role: this.userLogin.role,
|
||||||
token: this.token,
|
token: this.token,
|
||||||
|
item_id: this.data.item_id,
|
||||||
|
item_name: this.data.item_name,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +147,8 @@ export class LoginAdminQueueManager extends BaseCustomManager<UserEntity> {
|
||||||
user_id: this.userLogin.id,
|
user_id: this.userLogin.id,
|
||||||
username: this.userLogin.username,
|
username: this.userLogin.username,
|
||||||
created_at: new Date().getTime(),
|
created_at: new Date().getTime(),
|
||||||
|
item_id: this.data.item_id,
|
||||||
|
item_name: this.data.item_name,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Body, Controller, Delete, Param, Post, Put } from '@nestjs/common';
|
import { Body, Controller, Delete, Param, Post, Put } from '@nestjs/common';
|
||||||
import { ExcludePrivilege, Public } from 'src/core/guards';
|
import { ExcludePrivilege, Public } from 'src/core/guards';
|
||||||
import { ApiBearerAuth } from '@nestjs/swagger';
|
import { ApiBearerAuth } from '@nestjs/swagger';
|
||||||
import { LoginDto } from './dto/login.dto';
|
import { LoginQueueDto } from './dto/login.dto';
|
||||||
import { AuthAdminQueueOrchestrator } from '../domain/auth-admin-queue.orchestrator';
|
import { AuthAdminQueueOrchestrator } from '../domain/auth-admin-queue.orchestrator';
|
||||||
|
|
||||||
@Controller('v1/auth/queue')
|
@Controller('v1/auth/queue')
|
||||||
|
@ -10,7 +10,7 @@ export class AuthAdminQueueController {
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@Public(true)
|
@Public(true)
|
||||||
async login(@Body() body: LoginDto) {
|
async login(@Body() body: LoginQueueDto) {
|
||||||
return await this.orchestrator.login(body);
|
return await this.orchestrator.login(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,3 +11,21 @@ export class LoginDto implements LoginRequest {
|
||||||
@IsString()
|
@IsString()
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class LoginQueueDto implements LoginRequest {
|
||||||
|
@ApiProperty({ name: 'username', required: true, default: 'superadmin' })
|
||||||
|
@IsString()
|
||||||
|
username: string;
|
||||||
|
|
||||||
|
@ApiProperty({ name: 'password', required: true, default: 'Eigen123!' })
|
||||||
|
@IsString()
|
||||||
|
password: string;
|
||||||
|
|
||||||
|
@ApiProperty({ name: 'item_id', required: true, default: 'string' })
|
||||||
|
@IsString()
|
||||||
|
item_id: string;
|
||||||
|
|
||||||
|
@ApiProperty({ name: 'item_name', required: true, default: 'string' })
|
||||||
|
@IsString()
|
||||||
|
item_name: string;
|
||||||
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ import {
|
||||||
import { SeasonPeriodDataService } from 'src/modules/season-related/season-period/data/services/season-period-data.service';
|
import { SeasonPeriodDataService } from 'src/modules/season-related/season-period/data/services/season-period-data.service';
|
||||||
import { SeasonPeriodModel } from 'src/modules/season-related/season-period/data/models/season-period.model';
|
import { SeasonPeriodModel } from 'src/modules/season-related/season-period/data/models/season-period.model';
|
||||||
import { TransactionDemographyModel } from 'src/modules/transaction/transaction/data/models/transaction-demography.model';
|
import { TransactionDemographyModel } from 'src/modules/transaction/transaction/data/models/transaction-demography.model';
|
||||||
|
import { UserLoginModel } from 'src/modules/user-related/user/data/models/user-login.model';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -61,6 +62,7 @@ import { TransactionDemographyModel } from 'src/modules/transaction/transaction/
|
||||||
ItemRateModel,
|
ItemRateModel,
|
||||||
SeasonPeriodModel,
|
SeasonPeriodModel,
|
||||||
UserModel,
|
UserModel,
|
||||||
|
UserLoginModel,
|
||||||
TransactionModel,
|
TransactionModel,
|
||||||
TransactionTaxModel,
|
TransactionTaxModel,
|
||||||
TransactionItemModel,
|
TransactionItemModel,
|
||||||
|
|
|
@ -20,6 +20,12 @@ export class LogUserLoginModel
|
||||||
@Column({ type: 'uuid', nullable: true })
|
@Column({ type: 'uuid', nullable: true })
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
|
||||||
|
@Column({ type: 'uuid', nullable: true })
|
||||||
|
item_id: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', nullable: true })
|
||||||
|
item_name: string;
|
||||||
|
|
||||||
@Column({ type: 'varchar', nullable: true })
|
@Column({ type: 'varchar', nullable: true })
|
||||||
username: string;
|
username: string;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ export interface LogUserLoginEntity extends BaseCoreEntity {
|
||||||
type: LogUserType;
|
type: LogUserType;
|
||||||
role: UserRole;
|
role: UserRole;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
item_id: string;
|
||||||
|
item_name: string;
|
||||||
username: string;
|
username: string;
|
||||||
created_at: number;
|
created_at: number;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,15 @@ import { UserDataService } from '../user/data/services/user-data.service';
|
||||||
import { UserReadService } from '../user/data/services/user-read.service';
|
import { UserReadService } from '../user/data/services/user-read.service';
|
||||||
import { TenantItemReadController } from './infrastructure/tenant-item-read.controller';
|
import { TenantItemReadController } from './infrastructure/tenant-item-read.controller';
|
||||||
import { TenantItemDataController } from './infrastructure/tenant-item-data.controller';
|
import { TenantItemDataController } from './infrastructure/tenant-item-data.controller';
|
||||||
|
import { UserLoginModel } from '../user/data/models/user-login.model';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot(),
|
ConfigModule.forRoot(),
|
||||||
TypeOrmModule.forFeature([UserModel], CONNECTION_NAME.DEFAULT),
|
TypeOrmModule.forFeature(
|
||||||
|
[UserModel, UserLoginModel],
|
||||||
|
CONNECTION_NAME.DEFAULT,
|
||||||
|
),
|
||||||
CqrsModule,
|
CqrsModule,
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
|
|
|
@ -19,6 +19,12 @@ export class UserLoginModel
|
||||||
@Column('varchar', { name: 'user_id', nullable: true })
|
@Column('varchar', { name: 'user_id', nullable: true })
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
|
||||||
|
@Column({ type: 'uuid', nullable: true })
|
||||||
|
item_id: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', nullable: true })
|
||||||
|
item_name: string;
|
||||||
|
|
||||||
@OneToOne(() => UserModel, (model) => model.user_login, {
|
@OneToOne(() => UserModel, (model) => model.user_login, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
|
|
|
@ -4,14 +4,24 @@ import { UserEntity } from '../../domain/entities/user.entity';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { UserModel } from '../models/user.model';
|
import { UserModel } from '../models/user.model';
|
||||||
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants';
|
||||||
import { Repository } from 'typeorm';
|
import { IsNull, Not, Repository } from 'typeorm';
|
||||||
|
import { UserLoginModel } from '../models/user-login.model';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UserDataService extends BaseDataService<UserEntity> {
|
export class UserDataService extends BaseDataService<UserEntity> {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(UserModel, CONNECTION_NAME.DEFAULT)
|
@InjectRepository(UserModel, CONNECTION_NAME.DEFAULT)
|
||||||
private repo: Repository<UserModel>,
|
private repo: Repository<UserModel>,
|
||||||
|
|
||||||
|
@InjectRepository(UserLoginModel, CONNECTION_NAME.DEFAULT)
|
||||||
|
private repoLoginUser: Repository<UserLoginModel>,
|
||||||
) {
|
) {
|
||||||
super(repo);
|
super(repo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getLoginUserByItem(itemId: string) {
|
||||||
|
return this.repoLoginUser.findOne({
|
||||||
|
where: { item_id: itemId, user_id: Not(IsNull()) },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,4 +3,6 @@ import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entit
|
||||||
export interface UserLoginEntity extends BaseCoreEntity {
|
export interface UserLoginEntity extends BaseCoreEntity {
|
||||||
login_date: number;
|
login_date: number;
|
||||||
login_token: string;
|
login_token: string;
|
||||||
|
item_id: string;
|
||||||
|
item_name: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,8 @@ export class IndexUserManager extends BaseIndexManager<UserEntity> {
|
||||||
|
|
||||||
'user_login.id',
|
'user_login.id',
|
||||||
'user_login.login_date',
|
'user_login.login_date',
|
||||||
|
'user_login.item_id',
|
||||||
|
'user_login.item_name',
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue