feat: log staff sign-in and sign-out and force logout at a set time
This commit is contained in:
@@ -89,6 +89,14 @@ export class UpdateUserCommissionDto {
|
||||
commissionPercent!: number;
|
||||
}
|
||||
|
||||
export class UpdateLogoutTimeDto {
|
||||
@IsOptional()
|
||||
@ValidateIf((_, value) => value != null && value !== '')
|
||||
@IsString()
|
||||
@Matches(/^([01]\d|2[0-3]):[0-5]\d$/, { message: 'ساعت خروج معتبر نیست' })
|
||||
logoutTime?: string | null;
|
||||
}
|
||||
|
||||
export class UpdateUserVisibilityDto {
|
||||
@IsOptional()
|
||||
@IsIn(['own', 'team', 'org'])
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
InviteUserDto,
|
||||
UpdateOrgUserDto,
|
||||
UpdateUserCommissionDto,
|
||||
UpdateLogoutTimeDto,
|
||||
UpdateUserRoleDto,
|
||||
UpdateUserStatusDto,
|
||||
UpdateUserVisibilityDto,
|
||||
@@ -66,6 +67,21 @@ export class UsersController {
|
||||
);
|
||||
}
|
||||
|
||||
@Patch(':id/logout-time')
|
||||
@Roles('owner', 'admin')
|
||||
updateLogoutTime(
|
||||
@CurrentUser() user: { organizationId: string; role: UserRole },
|
||||
@Param('id') id: string,
|
||||
@Body() dto: UpdateLogoutTimeDto,
|
||||
) {
|
||||
return this.usersService.updateLogoutTime(
|
||||
user.organizationId,
|
||||
user.role,
|
||||
id,
|
||||
dto.logoutTime ?? null,
|
||||
);
|
||||
}
|
||||
|
||||
@Patch(':id/commission')
|
||||
@Roles('owner', 'admin')
|
||||
updateCommission(
|
||||
|
||||
@@ -45,6 +45,7 @@ type MembershipRow = {
|
||||
dataVisibility?: string | null;
|
||||
dataVisibilityScopes?: unknown;
|
||||
priorArchiveEnabled?: boolean;
|
||||
logoutTime?: string | null;
|
||||
createdAt: Date;
|
||||
orgRole: { id: string; name: string; color: string } | null;
|
||||
user: {
|
||||
@@ -242,6 +243,31 @@ export class UsersService {
|
||||
return this.dtoOf(organizationId, targetId);
|
||||
}
|
||||
|
||||
async updateLogoutTime(
|
||||
organizationId: string,
|
||||
actorRole: UserRole,
|
||||
targetId: string,
|
||||
logoutTime: string | null,
|
||||
): Promise<OrgUserDto> {
|
||||
if (actorRole !== 'owner' && actorRole !== 'admin') {
|
||||
throw new ForbiddenException('فقط مالک یا مدیر میتواند ساعت خروج را تعیین کند');
|
||||
}
|
||||
const target = await this.memberships.findUserInOrgById(organizationId, targetId);
|
||||
if (!target) throw new NotFoundException('کاربر پیدا نشد');
|
||||
if (target.role === 'owner') {
|
||||
throw new BadRequestException('برای مالک ساعت خروج تعیین نمیشود');
|
||||
}
|
||||
const value = logoutTime?.trim() || null;
|
||||
if (value && !/^([01]\d|2[0-3]):[0-5]\d$/.test(value)) {
|
||||
throw new BadRequestException('ساعت خروج معتبر نیست');
|
||||
}
|
||||
await this.prisma.membership.update({
|
||||
where: { id: target.id },
|
||||
data: { logoutTime: value },
|
||||
});
|
||||
return this.dtoOf(organizationId, targetId);
|
||||
}
|
||||
|
||||
async updatePriorArchive(
|
||||
organizationId: string,
|
||||
actorRole: UserRole,
|
||||
@@ -506,6 +532,7 @@ export class UsersService {
|
||||
? {}
|
||||
: parseVisibilityScopes(row.dataVisibilityScopes),
|
||||
priorArchiveEnabled: Boolean(row.priorArchiveEnabled),
|
||||
logoutTime: row.role === 'owner' ? null : row.logoutTime ?? null,
|
||||
createdAt: row.createdAt.toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user