mirror of
https://github.com/SyncrowIOT/backend.git
synced 2026-03-11 06:31:43 +00:00
Compare commits
1 Commits
task/imple
...
task/get-u
| Author | SHA1 | Date | |
|---|---|---|---|
| 97da07f80a |
@ -424,6 +424,10 @@ export class ControllerRoute {
|
|||||||
public static readonly ROUTE = '/user';
|
public static readonly ROUTE = '/user';
|
||||||
|
|
||||||
static ACTIONS = class {
|
static ACTIONS = class {
|
||||||
|
public static readonly GET_USERS_WITH_BOOKABLE_SPACES_SUMMARY =
|
||||||
|
'Retrieve list of users that has bookable spaces';
|
||||||
|
public static readonly GET_USERS_WITH_BOOKABLE_SPACES_DESCRIPTION =
|
||||||
|
'This endpoint retrieves all the users that have access to bookable spaces, paginated & accepts sorting';
|
||||||
public static readonly GET_USER_DETAILS_SUMMARY =
|
public static readonly GET_USER_DETAILS_SUMMARY =
|
||||||
'Retrieve user details by user UUID';
|
'Retrieve user details by user UUID';
|
||||||
public static readonly GET_USER_DETAILS_DESCRIPTION =
|
public static readonly GET_USER_DETAILS_DESCRIPTION =
|
||||||
@ -448,11 +452,6 @@ export class ControllerRoute {
|
|||||||
public static readonly UPDATE_NAME_DESCRIPTION =
|
public static readonly UPDATE_NAME_DESCRIPTION =
|
||||||
'This endpoint updates the name for a user identified by their UUID.';
|
'This endpoint updates the name for a user identified by their UUID.';
|
||||||
|
|
||||||
public static readonly UPDATE_BOOKING_SETTINGS_SUMMARY =
|
|
||||||
'Update booking settings by user UUID';
|
|
||||||
public static readonly UPDATE_BOOKING_SETTINGS_DESCRIPTION =
|
|
||||||
'This endpoint updates the booking settings for a user identified by their UUID.';
|
|
||||||
|
|
||||||
public static readonly DELETE_USER_SUMMARY = 'Delete user by UUID';
|
public static readonly DELETE_USER_SUMMARY = 'Delete user by UUID';
|
||||||
public static readonly DELETE_USER_DESCRIPTION =
|
public static readonly DELETE_USER_DESCRIPTION =
|
||||||
'This endpoint deletes a user identified by their UUID. Accessible only by users with the Super Admin role.';
|
'This endpoint deletes a user identified by their UUID. Accessible only by users with the Super Admin role.';
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import {
|
|||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
import { OtpType } from '../../../../src/constants/otp-type.enum';
|
import { OtpType } from '../../../../src/constants/otp-type.enum';
|
||||||
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
|
||||||
import { BookingEntity } from '../../booking/entities/booking.entity';
|
|
||||||
import { ClientEntity } from '../../client/entities';
|
import { ClientEntity } from '../../client/entities';
|
||||||
import {
|
import {
|
||||||
DeviceNotificationEntity,
|
DeviceNotificationEntity,
|
||||||
@ -30,6 +29,7 @@ import {
|
|||||||
UserOtpDto,
|
UserOtpDto,
|
||||||
UserSpaceDto,
|
UserSpaceDto,
|
||||||
} from '../dtos';
|
} from '../dtos';
|
||||||
|
import { BookingEntity } from '../../booking/entities/booking.entity';
|
||||||
|
|
||||||
@Entity({ name: 'user' })
|
@Entity({ name: 'user' })
|
||||||
export class UserEntity extends AbstractEntity<UserDto> {
|
export class UserEntity extends AbstractEntity<UserDto> {
|
||||||
@ -44,6 +44,7 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
|||||||
nullable: true,
|
nullable: true,
|
||||||
type: 'text',
|
type: 'text',
|
||||||
default: defaultProfilePicture,
|
default: defaultProfilePicture,
|
||||||
|
select: false,
|
||||||
})
|
})
|
||||||
public profilePicture: string;
|
public profilePicture: string;
|
||||||
|
|
||||||
@ -101,9 +102,6 @@ export class UserEntity extends AbstractEntity<UserDto> {
|
|||||||
@Column({ type: 'timestamp', nullable: true })
|
@Column({ type: 'timestamp', nullable: true })
|
||||||
appAgreementAcceptedAt: Date;
|
appAgreementAcceptedAt: Date;
|
||||||
|
|
||||||
@Column({ type: Boolean, default: false })
|
|
||||||
bookingEnabled: boolean;
|
|
||||||
|
|
||||||
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.user, {
|
@OneToMany(() => UserSpaceEntity, (userSpace) => userSpace.user, {
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { ControllerRoute } from '@app/common/constants/controller-route';
|
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||||
|
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||||
|
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
||||||
import { Controller, Get, Param, UseGuards } from '@nestjs/common';
|
import { Controller, Get, Param, UseGuards } from '@nestjs/common';
|
||||||
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
import { UserSpaceService } from '../services';
|
|
||||||
import { JwtAuthGuard } from '@app/common/guards/jwt.auth.guard';
|
|
||||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
|
||||||
import { UserParamDto } from '../dtos';
|
import { UserParamDto } from '../dtos';
|
||||||
|
import { UserSpaceService } from '../services';
|
||||||
|
|
||||||
@ApiTags('User Module')
|
@ApiTags('User Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
Param,
|
Param,
|
||||||
Patch,
|
Patch,
|
||||||
Put,
|
Put,
|
||||||
|
Query,
|
||||||
Req,
|
Req,
|
||||||
UseGuards,
|
UseGuards,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
@ -24,8 +25,8 @@ import {
|
|||||||
UpdateRegionDataDto,
|
UpdateRegionDataDto,
|
||||||
UpdateTimezoneDataDto,
|
UpdateTimezoneDataDto,
|
||||||
} from '../dtos';
|
} from '../dtos';
|
||||||
|
import { UsersWithBookableSpacesFilterDto } from '../dtos/users-with-bookable-spaces-filter.dto';
|
||||||
import { UserService } from '../services/user.service';
|
import { UserService } from '../services/user.service';
|
||||||
import { UpdateBookingSettingsDto } from '../dtos/update-user-booking-settings.dto';
|
|
||||||
|
|
||||||
@ApiTags('User Module')
|
@ApiTags('User Module')
|
||||||
@Controller({
|
@Controller({
|
||||||
@ -35,6 +36,21 @@ import { UpdateBookingSettingsDto } from '../dtos/update-user-booking-settings.d
|
|||||||
export class UserController {
|
export class UserController {
|
||||||
constructor(private readonly userService: UserService) {}
|
constructor(private readonly userService: UserService) {}
|
||||||
|
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@Get('with-bookable-spaces')
|
||||||
|
@ApiOperation({
|
||||||
|
summary:
|
||||||
|
ControllerRoute.USER.ACTIONS.GET_USERS_WITH_BOOKABLE_SPACES_SUMMARY,
|
||||||
|
description:
|
||||||
|
ControllerRoute.USER.ACTIONS.GET_USERS_WITH_BOOKABLE_SPACES_DESCRIPTION,
|
||||||
|
})
|
||||||
|
async getUsersWithBookableSpaces(
|
||||||
|
@Query() dto: UsersWithBookableSpacesFilterDto,
|
||||||
|
): Promise<BaseResponseDto> {
|
||||||
|
return this.userService.getUsersWithBookableSpaces(dto);
|
||||||
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@Get(':userUuid')
|
@Get(':userUuid')
|
||||||
@ -139,30 +155,6 @@ export class UserController {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiBearerAuth()
|
|
||||||
@UseGuards(JwtAuthGuard)
|
|
||||||
@Put('/booking-settings/:userUuid')
|
|
||||||
@ApiOperation({
|
|
||||||
summary: ControllerRoute.USER.ACTIONS.UPDATE_BOOKING_SETTINGS_SUMMARY,
|
|
||||||
description:
|
|
||||||
ControllerRoute.USER.ACTIONS.UPDATE_BOOKING_SETTINGS_DESCRIPTION,
|
|
||||||
})
|
|
||||||
async updateBookingSettingsByUserUuid(
|
|
||||||
@Param('userUuid') userUuid: string,
|
|
||||||
@Body() dto: UpdateBookingSettingsDto,
|
|
||||||
) {
|
|
||||||
const userData = await this.userService.updateBookingSettingsByUserUuid(
|
|
||||||
userUuid,
|
|
||||||
dto,
|
|
||||||
);
|
|
||||||
return {
|
|
||||||
statusCode: HttpStatus.CREATED,
|
|
||||||
success: true,
|
|
||||||
message: 'Booking settings updated successfully',
|
|
||||||
data: userData,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@UseGuards(SuperAdminRoleGuard)
|
@UseGuards(SuperAdminRoleGuard)
|
||||||
@Delete('/:userUuid')
|
@Delete('/:userUuid')
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
import { ApiProperty } from '@nestjs/swagger';
|
|
||||||
import { IsBoolean, IsInt, IsOptional, IsPositive, Min } from 'class-validator';
|
|
||||||
|
|
||||||
export class UpdateBookingSettingsDto {
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'bookingEnable',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsBoolean()
|
|
||||||
@IsOptional()
|
|
||||||
bookingEnable?: boolean;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'increase user booking balance by top up amount',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsPositive()
|
|
||||||
@IsOptional()
|
|
||||||
topUp?: number;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: 'replace user booking balance by required amount',
|
|
||||||
required: false,
|
|
||||||
})
|
|
||||||
@IsInt()
|
|
||||||
@Min(0)
|
|
||||||
@IsOptional()
|
|
||||||
balance?: number;
|
|
||||||
}
|
|
||||||
21
src/users/dtos/users-with-bookable-spaces-filter.dto.ts
Normal file
21
src/users/dtos/users-with-bookable-spaces-filter.dto.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { PaginationRequestGetListDto } from '@app/common/dto/pagination.request.dto';
|
||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { IsEnum, IsOptional, ValidateIf } from 'class-validator';
|
||||||
|
|
||||||
|
export class UsersWithBookableSpacesFilterDto extends PaginationRequestGetListDto {
|
||||||
|
@ApiProperty({
|
||||||
|
enum: ['accessStartDate', 'accessEndDate'],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsEnum(['accessStartDate', 'accessEndDate'])
|
||||||
|
@ValidateIf((o) => o.sortDirection)
|
||||||
|
sortBy: 'accessStartDate' | 'accessEndDate';
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
enum: ['asc', 'desc'],
|
||||||
|
required: false,
|
||||||
|
})
|
||||||
|
@IsEnum(['asc', 'desc'])
|
||||||
|
@IsOptional()
|
||||||
|
sortDirection: 'asc' | 'desc';
|
||||||
|
}
|
||||||
@ -1,16 +1,18 @@
|
|||||||
|
import { PageResponse } from '@app/common/dto/pagination.response.dto';
|
||||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||||
import { removeBase64Prefix } from '@app/common/helper/removeBase64Prefix';
|
import { removeBase64Prefix } from '@app/common/helper/removeBase64Prefix';
|
||||||
import { RegionRepository } from '@app/common/modules/region/repositories';
|
import { RegionRepository } from '@app/common/modules/region/repositories';
|
||||||
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
import { TimeZoneRepository } from '@app/common/modules/timezone/repositories';
|
||||||
import { UserEntity } from '@app/common/modules/user/entities';
|
import { UserEntity } from '@app/common/modules/user/entities';
|
||||||
import { UserRepository } from '@app/common/modules/user/repositories';
|
import { UserRepository } from '@app/common/modules/user/repositories';
|
||||||
|
import { getPaginationResponseDto } from '@app/common/util/getPaginationResponseDto';
|
||||||
import {
|
import {
|
||||||
BadRequestException,
|
BadRequestException,
|
||||||
HttpException,
|
HttpException,
|
||||||
HttpStatus,
|
HttpStatus,
|
||||||
Injectable,
|
Injectable,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { UpdateBookingSettingsDto } from '../dtos/update-user-booking-settings.dto';
|
import { UsersWithBookableSpacesFilterDto } from '../dtos/users-with-bookable-spaces-filter.dto';
|
||||||
import {
|
import {
|
||||||
UpdateNameDto,
|
UpdateNameDto,
|
||||||
UpdateProfilePictureDataDto,
|
UpdateProfilePictureDataDto,
|
||||||
@ -34,7 +36,7 @@ export class UserService {
|
|||||||
relations: ['region', 'timezone', 'roleType', 'project'],
|
relations: ['region', 'timezone', 'roleType', 'project'],
|
||||||
});
|
});
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new BadRequestException('Invalid user UUID');
|
throw new BadRequestException('Invalid room UUID');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use the utility function to remove the base64 prefix
|
// Use the utility function to remove the base64 prefix
|
||||||
@ -54,8 +56,6 @@ export class UserService {
|
|||||||
appAgreementAcceptedAt: user?.appAgreementAcceptedAt,
|
appAgreementAcceptedAt: user?.appAgreementAcceptedAt,
|
||||||
role: user?.roleType,
|
role: user?.roleType,
|
||||||
project: user?.project,
|
project: user?.project,
|
||||||
bookingPoints: user?.bookingPoints ?? 0,
|
|
||||||
bookingEnabled: user?.bookingEnabled ?? false,
|
|
||||||
};
|
};
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err instanceof BadRequestException) {
|
if (err instanceof BadRequestException) {
|
||||||
@ -66,6 +66,38 @@ export class UserService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getUsersWithBookableSpaces({
|
||||||
|
sortBy,
|
||||||
|
sortDirection,
|
||||||
|
page,
|
||||||
|
size,
|
||||||
|
}: UsersWithBookableSpacesFilterDto) {
|
||||||
|
size = size ?? 10;
|
||||||
|
page = page ?? 1;
|
||||||
|
const qb = this.userRepository
|
||||||
|
.createQueryBuilder('user')
|
||||||
|
.innerJoin('user.userSpaces', 'userSpaces')
|
||||||
|
.innerJoin('userSpaces.space', 'space')
|
||||||
|
.innerJoin('space.bookableConfig', 'bookableConfig')
|
||||||
|
.where('bookableConfig.uuid IS NOT NULL')
|
||||||
|
.leftJoinAndSelect('user.inviteUser', 'inviteUser')
|
||||||
|
.take(size)
|
||||||
|
.skip((page - 1) * size)
|
||||||
|
.distinct(true);
|
||||||
|
if (sortBy) {
|
||||||
|
qb.orderBy(
|
||||||
|
':sortBy',
|
||||||
|
sortDirection == 'desc' ? 'DESC' : 'ASC',
|
||||||
|
).setParameter('sortBy', sortBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [data, count] = await qb.getManyAndCount();
|
||||||
|
return new PageResponse(
|
||||||
|
{ message: 'users fetched successfully', data },
|
||||||
|
getPaginationResponseDto(count, page, size),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async updateProfilePictureByUserUuid(
|
async updateProfilePictureByUserUuid(
|
||||||
userUuid: string,
|
userUuid: string,
|
||||||
updateProfilePictureDataDto: UpdateProfilePictureDataDto,
|
updateProfilePictureDataDto: UpdateProfilePictureDataDto,
|
||||||
@ -248,48 +280,6 @@ export class UserService {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateBookingSettingsByUserUuid(
|
|
||||||
userUuid: string,
|
|
||||||
{ balance, bookingEnable, topUp }: UpdateBookingSettingsDto,
|
|
||||||
) {
|
|
||||||
try {
|
|
||||||
let user = await this.getUserDetailsByUserUuid(userUuid);
|
|
||||||
if (!user) {
|
|
||||||
throw new HttpException('User not found', HttpStatus.NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (balance && topUp) {
|
|
||||||
throw new BadRequestException(
|
|
||||||
'Please provide either balance or topUp, not both',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topUp) {
|
|
||||||
user.bookingPoints += topUp;
|
|
||||||
}
|
|
||||||
if (balance) {
|
|
||||||
user.bookingPoints = balance;
|
|
||||||
}
|
|
||||||
if (bookingEnable !== undefined) {
|
|
||||||
user.bookingEnabled = bookingEnable;
|
|
||||||
}
|
|
||||||
|
|
||||||
user = await this.userRepository.save(user);
|
|
||||||
|
|
||||||
return {
|
|
||||||
uuid: user.uuid,
|
|
||||||
bookingEnabled: user.bookingEnabled,
|
|
||||||
bookingPoints: user.bookingPoints,
|
|
||||||
};
|
|
||||||
} catch (err) {
|
|
||||||
throw new HttpException(
|
|
||||||
err.message || 'User not found',
|
|
||||||
HttpStatus.NOT_FOUND,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async acceptWebAgreement(userUuid: string) {
|
async acceptWebAgreement(userUuid: string) {
|
||||||
await this.userRepository.update(
|
await this.userRepository.update(
|
||||||
{ uuid: userUuid },
|
{ uuid: userUuid },
|
||||||
|
|||||||
Reference in New Issue
Block a user