diff --git a/database/seeder.runner.ts b/database/seeder.runner.ts index 22a533e..cfb92f2 100644 --- a/database/seeder.runner.ts +++ b/database/seeder.runner.ts @@ -2,6 +2,7 @@ import { Logger } from "@nestjs/common"; import { connectionSource } from "./connection"; import { seedAdmin } from "./seeders/admin.seeder"; +import { seedNotifSettings } from "./seeders/notif-settting.seeder"; import { seedRole } from "./seeders/role.seeder"; const logger = new Logger("Seeder"); @@ -11,6 +12,7 @@ export const runSeeder = async () => { logger.log("start seeding database"); await seedRole(connectionSource, logger); await seedAdmin(connectionSource, logger); + await seedNotifSettings(connectionSource, logger); logger.log("seeding completed"); process.exit(0); diff --git a/database/seeders/notif-settting.seeder.ts b/database/seeders/notif-settting.seeder.ts new file mode 100644 index 0000000..f67c893 --- /dev/null +++ b/database/seeders/notif-settting.seeder.ts @@ -0,0 +1,31 @@ +import { Logger } from "@nestjs/common"; +import { DataSource } from "typeorm"; + +import { NotifSetting } from "../../src/modules/settings/entities/notif-setting.entity"; +import { FarsiNotifSettingsEnum, NotifSettingsEnum } from "../../src/modules/settings/enums/notif-settings.enum"; + +const notifSettings = [ + { title: NotifSettingsEnum.ANNOUNCE_NOTIF, title_fa: FarsiNotifSettingsEnum.ANNOUNCE_NOTIF }, + { title: NotifSettingsEnum.ANSWER_TICKET, title_fa: FarsiNotifSettingsEnum.ANSWER_TICKET }, + { title: NotifSettingsEnum.BILL_PAYMENT, title_fa: FarsiNotifSettingsEnum.BILL_PAYMENT }, + { title: NotifSettingsEnum.BILL_PAYMENT_REMINDER, title_fa: FarsiNotifSettingsEnum.BILL_PAYMENT_REMINDER }, + { title: NotifSettingsEnum.BLOCKING_SERVICE, title_fa: FarsiNotifSettingsEnum.BLOCKING_SERVICE }, + { title: NotifSettingsEnum.CREATE_INVOICE, title_fa: FarsiNotifSettingsEnum.CREATE_INVOICE }, + { title: NotifSettingsEnum.CREATE_TICKET, title_fa: FarsiNotifSettingsEnum.CREATE_TICKET }, + { title: NotifSettingsEnum.UNBLOCKING_SERVICE, title_fa: FarsiNotifSettingsEnum.UNBLOCKING_SERVICE }, + { title: NotifSettingsEnum.CREATE_SERIVCE, title_fa: FarsiNotifSettingsEnum.CREATE_SERIVCE }, +]; + +export const seedNotifSettings = async (dataSource: DataSource, logger: Logger) => { + try { + const notifSettingRepo = dataSource.getRepository(NotifSetting); + for (const setting of notifSettings) { + const newSetting = notifSettingRepo.create(setting); + await notifSettingRepo.save(newSetting); + } + logger.log("Notif Settings Successfully"); + } catch (error) { + logger.error("Error in seeding settings", error); + process.exit(1); + } +}; diff --git a/src/app.module.ts b/src/app.module.ts index c518487..14e28b9 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -13,6 +13,7 @@ import { AnnouncementsModule } from "./modules/announcements/announcement.module import { AuthModule } from "./modules/auth/auth.module"; import { CriticismModule } from "./modules/criticisms/criticisms.module"; import { DanakServicesModule } from "./modules/danak-services/danak-services.module"; +import { SettingModule } from "./modules/settings/settings.module"; import { TicketsModule } from "./modules/tickets/tickets.module"; import { UploaderModule } from "./modules/uploader/uploader.module"; import { UsersModule } from "./modules/users/users.module"; @@ -31,6 +32,7 @@ import { UsersModule } from "./modules/users/users.module"; AnnouncementsModule, UploaderModule, CriticismModule, + SettingModule, ], controllers: [], providers: [], diff --git a/src/common/enums/message.enum.ts b/src/common/enums/message.enum.ts index 3729548..3f6609e 100644 --- a/src/common/enums/message.enum.ts +++ b/src/common/enums/message.enum.ts @@ -14,6 +14,7 @@ export const enum AuthMessage { INVALID_OTP = "کد صحیح نمی‌باشد یا منقضی شده است", PASSWORD_MISMATCH = "رمز عبور یکسان نیست", INVALID_PASSWORD = "ایمیل یا رمز عبور اشتباه است", + INVALID_REAPET_PASSWORD = "تکرار رمز عبور اشتباه است", EMAIL_NOT_EMPTY = "ایمیل نمیتواند خالی باشد.", INVALID_EMAIL_FORMAT = "فرمت ایمیل صحیح نیست", PasswordNotEmpty = "پسورد نمیتواند خالی باشد.", @@ -36,6 +37,7 @@ export const enum AuthMessage { PHONE_FORMAT_INVALID = "شماره تلفن باید معتبر و به فرمت ایران باشد", TOKEN_NOT_EMPTY = "توکن نمی‌تواند خالی باشد", PASSWORD_NOT_EMPTY = "رمز عبور نمی‌تواند خالی باشد", + PASSWORD_CHANGED_SUCCESSFULLY = "رمز عبور با موفقیت تغییر کرد", PASSWORD_CONFIRMATION_NOT_EMPTY = "تایید رمز عبور نمی‌تواند خالی باشد", PASSWORD_LENGTH = "رمز عبور باید حداقل ۸ کاراکتر باشد", OTP_NOT_EMPTY = "کد یکبار مصرف نمی‌تواند خالی باشد", @@ -178,3 +180,10 @@ export const enum TicketMessageEnum { TICKET_NOT_FOUND = "تیکت مورد نظر یافت نشد", CLOSED = "تیکت با موفقیت بسته شد", } + +export const enum SettingMessageEnum { + NOTIF_NOT_FOUND = "تنظیمات نوتیف پیدا نشد", + NOT_FOUND = "تنظیمات پیدا نشد", + SMS_MUST_BE_BOOLEAN = "تنظیمات اسمس باید از نوع BOOLEAN باشد", + EMAIL_MUST_BE_BOOLEAN = "تنظیمات ایمیل باید از نوع BOOLEAN باشد", +} diff --git a/src/modules/auth/DTO/update-password.dto.ts b/src/modules/auth/DTO/update-password.dto.ts new file mode 100644 index 0000000..7322e1c --- /dev/null +++ b/src/modules/auth/DTO/update-password.dto.ts @@ -0,0 +1,24 @@ +import { ApiProperty } from "@nestjs/swagger"; +import { IsNotEmpty, IsString, MinLength } from "class-validator"; + +import { AuthMessage } from "../../../common/enums/message.enum"; + +export class UpdatePasswordDto { + @IsNotEmpty({ message: AuthMessage.PASSWORD_NOT_EMPTY }) + @IsString({ message: AuthMessage.PASSWORD_FORMAT_INVALID }) + @ApiProperty({ description: "old password", example: "12S345SS678" }) + @MinLength(8, { message: AuthMessage.PASSWORD_LENGTH }) + password: string; + + @IsNotEmpty({ message: AuthMessage.PASSWORD_NOT_EMPTY }) + @IsString({ message: AuthMessage.PASSWORD_FORMAT_INVALID }) + @ApiProperty({ description: "new password", example: "12S345SS678" }) + @MinLength(8, { message: AuthMessage.PASSWORD_LENGTH }) + newPassword: string; + + @IsNotEmpty({ message: AuthMessage.PASSWORD_NOT_EMPTY }) + @IsString({ message: AuthMessage.PASSWORD_FORMAT_INVALID }) + @ApiProperty({ description: "re new password", example: "12S345SS678" }) + @MinLength(8, { message: AuthMessage.PASSWORD_LENGTH }) + repeatPassword: string; +} diff --git a/src/modules/auth/auth.controller.ts b/src/modules/auth/auth.controller.ts index 217d6cb..d8b9d20 100644 --- a/src/modules/auth/auth.controller.ts +++ b/src/modules/auth/auth.controller.ts @@ -1,13 +1,17 @@ -import { Body, Controller, HttpCode, HttpStatus, Post, UseGuards } from "@nestjs/common"; +import { Body, Controller, HttpCode, HttpStatus, Patch, Post, UseGuards } from "@nestjs/common"; import { ApiOperation, ApiTags } from "@nestjs/swagger"; import { Throttle, ThrottlerGuard } from "@nestjs/throttler"; import { CompleteRegistrationDto } from "./DTO/complete-register.dto"; import { CheckUserExistDto, LoginPasswordDTO } from "./DTO/loginPassword.dto"; import { RequestOtpDto } from "./DTO/request-otp.dto"; +import { UpdatePasswordDto } from "./DTO/update-password.dto"; import { VerifyOtpDto } from "./DTO/verify-otp.dto"; import { AuthService } from "./providers/auth.service"; import { AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL } from "../../common/constants"; +import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; +import { UserDec } from "../../common/decorators/user.decorator"; +import { User } from "../users/entities/user.entity"; @ApiTags("Auth") @Controller("auth") @@ -71,6 +75,14 @@ export class AuthController { adminVerifyOtp(@Body() verifyOtpDto: VerifyOtpDto) { return this.authService.adminVerifyLoginOtp(verifyOtpDto); } + + @AuthGuards() + @ApiOperation({ summary: "Update user password" }) + @HttpCode(HttpStatus.OK) + @Patch("password") + updatePassword(@UserDec() user: User, @Body() updatePasswordDto: UpdatePasswordDto) { + return this.authService.updatePassword(user.id, updatePasswordDto); + } //***************************** */ // @Post("forgot-password") diff --git a/src/modules/auth/providers/auth.service.ts b/src/modules/auth/providers/auth.service.ts index 5664574..65ae8ae 100644 --- a/src/modules/auth/providers/auth.service.ts +++ b/src/modules/auth/providers/auth.service.ts @@ -9,6 +9,7 @@ import { PasswordService } from "../../utils/providers/password.service"; import { CompleteRegistrationDto } from "../DTO/complete-register.dto"; import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto"; import { RequestOtpDto } from "../DTO/request-otp.dto"; +import { UpdatePasswordDto } from "../DTO/update-password.dto"; import { VerifyOtpDto } from "../DTO/verify-otp.dto"; @Injectable() @@ -152,6 +153,23 @@ export class AuthService { }; } //****************** */ + + async updatePassword(userId: string, updateDto: UpdatePasswordDto) { + const { user } = await this.usersService.findOneById(userId); + + const passCompare = await this.passwordService.comparePassword(updateDto.password, user.password); + if (!passCompare) throw new BadRequestException(AuthMessage.INVALID_PASSWORD); + + if (updateDto.newPassword !== updateDto.repeatPassword) throw new BadRequestException(AuthMessage.INVALID_REAPET_PASSWORD); + + const hashedPassword = await this.passwordService.hashPassword(updateDto.newPassword); + await this.usersService.updateUserPassword(user.id, hashedPassword); + + return { + message: AuthMessage.PASSWORD_CHANGED_SUCCESSFULLY, + }; + } + //****************** */ private async checkUserLoginCredentialWithEmail(email: string, password: string) { diff --git a/src/modules/settings/DTO/update-settings.dto.ts b/src/modules/settings/DTO/update-settings.dto.ts new file mode 100644 index 0000000..68d3846 --- /dev/null +++ b/src/modules/settings/DTO/update-settings.dto.ts @@ -0,0 +1,16 @@ +import { ApiPropertyOptional } from "@nestjs/swagger"; +import { IsNotEmpty, IsOptional } from "class-validator"; + +import { SettingMessageEnum } from "../../../common/enums/message.enum"; + +export class UpdateUserSettingsDto { + @IsOptional() + @IsNotEmpty({ message: SettingMessageEnum.SMS_MUST_BE_BOOLEAN }) + @ApiPropertyOptional({ description: "Sms Setting", example: true }) + sms: boolean; + + @IsOptional() + @IsNotEmpty({ message: SettingMessageEnum.EMAIL_MUST_BE_BOOLEAN }) + @ApiPropertyOptional({ description: "email Setting", example: false }) + email: boolean; +} diff --git a/src/modules/settings/entities/notif-setting.entity.ts b/src/modules/settings/entities/notif-setting.entity.ts new file mode 100644 index 0000000..6397084 --- /dev/null +++ b/src/modules/settings/entities/notif-setting.entity.ts @@ -0,0 +1,17 @@ +import { Column, Entity, OneToMany } from "typeorm"; + +import { UserSetting } from "./user-setting.entity"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { FarsiNotifSettingsEnum, NotifSettingsEnum } from "../enums/notif-settings.enum"; + +@Entity() +export class NotifSetting extends BaseEntity { + @Column({ type: "enum", enum: NotifSettingsEnum, unique: true }) + title: string; + + @Column({ type: "enum", enum: FarsiNotifSettingsEnum }) + title_fa: string; + + @OneToMany(() => UserSetting, (userSettings) => userSettings.notifSetting) + userSettings: UserSetting[]; +} diff --git a/src/modules/settings/entities/user-setting.entity.ts b/src/modules/settings/entities/user-setting.entity.ts new file mode 100644 index 0000000..48320c8 --- /dev/null +++ b/src/modules/settings/entities/user-setting.entity.ts @@ -0,0 +1,20 @@ +import { Column, Entity, ManyToOne } from "typeorm"; + +import { NotifSetting } from "./notif-setting.entity"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { User } from "../../users/entities/user.entity"; + +@Entity() +export class UserSetting extends BaseEntity { + @Column({ type: "boolean", default: true }) + sms: boolean; + + @Column({ type: "boolean", default: false }) + email: boolean; + + @ManyToOne(() => NotifSetting, (notifSetting) => notifSetting.userSettings) + notifSetting: NotifSetting; + + @ManyToOne(() => User, (user) => user.settings, { nullable: false }) + user: User; +} diff --git a/src/modules/settings/enums/notif-settings.enum.ts b/src/modules/settings/enums/notif-settings.enum.ts new file mode 100644 index 0000000..ee1a23d --- /dev/null +++ b/src/modules/settings/enums/notif-settings.enum.ts @@ -0,0 +1,23 @@ +export enum NotifSettingsEnum { + ANNOUNCE_NOTIF = "ANNOUNCE_NOTIF", + BILL_PAYMENT = "BILL_PAYMENT", + CREATE_SERIVCE = "CREATE_SERIVCE", + UNBLOCKING_SERVICE = "UNBLOCKING_SERVICE", + ANSWER_TICKET = "ANSWER_TICKET", + CREATE_INVOICE = "CREATE_INVOICE", + BILL_PAYMENT_REMINDER = "BILL_PAYMENT_REMINDER", + BLOCKING_SERVICE = "BLOCKING_SERVICE", + CREATE_TICKET = "CREATE_TICKET", +} + +export enum FarsiNotifSettingsEnum { + ANNOUNCE_NOTIF = "اعلانات و اطلاعیه ها", + BILL_PAYMENT = "پرداخت صورت حساب", + CREATE_SERIVCE = "ایجاد سرویس", + UNBLOCKING_SERVICE = "رفع انسداد سرویس", + ANSWER_TICKET = "پاسخ تیکت", + CREATE_INVOICE = "ایجاد صورت حساب", + BILL_PAYMENT_REMINDER = "یادآوری پرداخت صورت حساب", + BLOCKING_SERVICE = "انسداد سرویس", + CREATE_TICKET = "ثبت تیکت جدبد", +} diff --git a/src/modules/settings/enums/user-settings.ts b/src/modules/settings/enums/user-settings.ts new file mode 100644 index 0000000..c1a0c5e --- /dev/null +++ b/src/modules/settings/enums/user-settings.ts @@ -0,0 +1,67 @@ +import { NotifSettingsEnum } from "./notif-settings.enum"; + +export const userSettings = [ + { + title: NotifSettingsEnum.ANNOUNCE_NOTIF, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.ANSWER_TICKET, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.BILL_PAYMENT, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.BILL_PAYMENT_REMINDER, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.BLOCKING_SERVICE, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.CREATE_INVOICE, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.CREATE_SERIVCE, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.CREATE_TICKET, + fields: { + sms: true, + email: false, + }, + }, + { + title: NotifSettingsEnum.UNBLOCKING_SERVICE, + fields: { + sms: true, + email: false, + }, + }, +]; diff --git a/src/modules/settings/providers/notif-settings.service.ts b/src/modules/settings/providers/notif-settings.service.ts new file mode 100644 index 0000000..5906a2c --- /dev/null +++ b/src/modules/settings/providers/notif-settings.service.ts @@ -0,0 +1,13 @@ +import { Injectable } from "@nestjs/common"; + +import { NotifSettingsRepository } from "../repositories/notif-settings.repository"; + +@Injectable() +export class NotifSettingsService { + constructor(private readonly notifSettingsRepository: NotifSettingsRepository) {} + + async getAll() { + const notifSettings = this.notifSettingsRepository.find(); + return { notifSettings }; + } +} diff --git a/src/modules/settings/providers/user-settings.service.ts b/src/modules/settings/providers/user-settings.service.ts new file mode 100644 index 0000000..a1d14f0 --- /dev/null +++ b/src/modules/settings/providers/user-settings.service.ts @@ -0,0 +1,79 @@ +import { BadRequestException, Injectable } from "@nestjs/common"; +import { QueryRunner } from "typeorm"; + +import { CommonMessage, SettingMessageEnum, UserMessage } from "../../../common/enums/message.enum"; +import { User } from "../../users/entities/user.entity"; +import { UpdateUserSettingsDto } from "../DTO/update-settings.dto"; +import { NotifSetting } from "../entities/notif-setting.entity"; +import { UserSetting } from "../entities/user-setting.entity"; +import { userSettings } from "../enums/user-settings"; +import { UserSettingsRepository } from "../repositories/user-settings.repository"; + +@Injectable() +export class UserSettingsService { + constructor(private readonly userSettingsRepository: UserSettingsRepository) {} + + async createUserSettings(userId: string, queryRunner: QueryRunner) { + const user = await queryRunner.manager.findOneBy(User, { + id: userId, + }); + if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND); + for (const setting of userSettings) { + const notifSetting = await queryRunner.manager.findOneBy(NotifSetting, { + title: setting.title, + }); + console.log({ notifSetting }); + if (!notifSetting) throw new BadRequestException(SettingMessageEnum.NOTIF_NOT_FOUND); + const userSetting = queryRunner.manager.create(UserSetting, { + ...setting, + notifSetting, + user, + }); + console.log({ userSetting }); + await queryRunner.manager.save(userSetting); + } + return { + message: CommonMessage.CREATED, + }; + } + + async getSettings(userId: string) { + const settings = await this.userSettingsRepository.find({ + where: { + user: { + id: userId, + }, + }, + relations: ["notifSetting"], + order: { + createdAt: "ASC", + }, + }); + return { settings }; + } + + async updateUserSetting(settingId: string, updateDto: UpdateUserSettingsDto) { + const setting = await this.userSettingsRepository.findOne({ + where: { + id: settingId, + }, + order: { + createdAt: "ASC", + }, + }); + + if (!setting) throw new BadRequestException(SettingMessageEnum.NOT_FOUND); + + if (updateDto.sms !== undefined) { + setting.sms = updateDto.sms; + } + + if (updateDto.email !== undefined) { + setting.email = updateDto.email; + } + + await this.userSettingsRepository.save(setting); + + return setting; + } +} diff --git a/src/modules/settings/repositories/notif-settings.repository.ts b/src/modules/settings/repositories/notif-settings.repository.ts new file mode 100644 index 0000000..9922248 --- /dev/null +++ b/src/modules/settings/repositories/notif-settings.repository.ts @@ -0,0 +1,12 @@ +import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; + +import { NotifSetting } from "../entities/notif-setting.entity"; + +@Injectable() +export class NotifSettingsRepository extends Repository { + constructor(@InjectRepository(NotifSetting) notifSettingsRepository: Repository) { + super(notifSettingsRepository.target, notifSettingsRepository.manager, notifSettingsRepository.queryRunner); + } +} diff --git a/src/modules/user-settings/repositories/user-settings.repository.ts b/src/modules/settings/repositories/user-settings.repository.ts similarity index 66% rename from src/modules/user-settings/repositories/user-settings.repository.ts rename to src/modules/settings/repositories/user-settings.repository.ts index 2ffc623..13d5652 100644 --- a/src/modules/user-settings/repositories/user-settings.repository.ts +++ b/src/modules/settings/repositories/user-settings.repository.ts @@ -2,11 +2,11 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; -import { UserSettings } from "../entities/user-settings.entity"; +import { UserSetting } from "../entities/user-setting.entity"; @Injectable() -export class UserSettingsRepository extends Repository { - constructor(@InjectRepository(UserSettings) userSettingsRepository: Repository) { +export class UserSettingsRepository extends Repository { + constructor(@InjectRepository(UserSetting) userSettingsRepository: Repository) { super(userSettingsRepository.target, userSettingsRepository.manager, userSettingsRepository.queryRunner); } } diff --git a/src/modules/settings/settings.controller.ts b/src/modules/settings/settings.controller.ts new file mode 100644 index 0000000..cb772ab --- /dev/null +++ b/src/modules/settings/settings.controller.ts @@ -0,0 +1,30 @@ +import { Body, Controller, Get, HttpCode, HttpStatus, Param, Patch } from "@nestjs/common"; +import { ApiOperation, ApiTags } from "@nestjs/swagger"; + +import { UpdateUserSettingsDto } from "./DTO/update-settings.dto"; +import { UserSettingsService } from "./providers/user-settings.service"; +import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; +import { UserDec } from "../../common/decorators/user.decorator"; +import { ParamDto } from "../../common/DTO/param.dto"; +import { User } from "../users/entities/user.entity"; + +@Controller("settings") +@ApiTags("Settings") +export class SettingsController { + constructor(private readonly userSettingsService: UserSettingsService) {} + + @AuthGuards() + @ApiOperation({ summary: "Get all settings" }) + @Get() + async getSettings(@UserDec() user: User) { + return await this.userSettingsService.getSettings(user.id); + } + + @AuthGuards() + @ApiOperation({ summary: "update status of setting" }) + @HttpCode(HttpStatus.OK) + @Patch(":id/update") + updateStatus(@Param() paramDto: ParamDto, @Body() createDto: UpdateUserSettingsDto) { + return this.userSettingsService.updateUserSetting(paramDto.id, createDto); + } +} diff --git a/src/modules/settings/settings.module.ts b/src/modules/settings/settings.module.ts new file mode 100644 index 0000000..6ca6b5d --- /dev/null +++ b/src/modules/settings/settings.module.ts @@ -0,0 +1,19 @@ +import { Module, forwardRef } from "@nestjs/common"; +import { TypeOrmModule } from "@nestjs/typeorm"; + +import { NotifSetting } from "./entities/notif-setting.entity"; +import { UserSetting } from "./entities/user-setting.entity"; +import { NotifSettingsService } from "./providers/notif-settings.service"; +import { UserSettingsService } from "./providers/user-settings.service"; +import { NotifSettingsRepository } from "./repositories/notif-settings.repository"; +import { UserSettingsRepository } from "./repositories/user-settings.repository"; +import { SettingsController } from "./settings.controller"; +import { UsersModule } from "../users/users.module"; + +@Module({ + imports: [TypeOrmModule.forFeature([UserSetting, NotifSetting]), forwardRef(() => UsersModule)], + providers: [UserSettingsService, NotifSettingsService, UserSettingsRepository, NotifSettingsRepository], + controllers: [SettingsController], + exports: [UserSettingsService, UserSettingsRepository], +}) +export class SettingModule {} diff --git a/src/modules/user-settings/entities/user-settings.entity.ts b/src/modules/user-settings/entities/user-settings.entity.ts deleted file mode 100644 index 2b7b778..0000000 --- a/src/modules/user-settings/entities/user-settings.entity.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Column, Entity } from "typeorm"; - -import { BaseEntity } from "../../../common/entities/base.entity"; - -@Entity() -export class UserSettings extends BaseEntity { - @Column({ type: "varchar", length: 150 }) - title: string; - - @Column({ type: "json" }) - fields: Record; -} diff --git a/src/modules/user-settings/providers/user-setttings.service.ts b/src/modules/user-settings/providers/user-setttings.service.ts deleted file mode 100644 index 7434936..0000000 --- a/src/modules/user-settings/providers/user-setttings.service.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Injectable } from "@nestjs/common"; - -@Injectable() -export class UserSettingsService { - constructor() {} -} diff --git a/src/modules/user-settings/user-settings.controller.ts b/src/modules/user-settings/user-settings.controller.ts deleted file mode 100644 index d8ba68a..0000000 --- a/src/modules/user-settings/user-settings.controller.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Controller } from "@nestjs/common"; - -@Controller("user-settings") -export class UserSettingsController { - constructor() {} -} diff --git a/src/modules/user-settings/user-settings.module.ts b/src/modules/user-settings/user-settings.module.ts deleted file mode 100644 index f3f692c..0000000 --- a/src/modules/user-settings/user-settings.module.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Module } from "@nestjs/common"; -import { TypeOrmModule } from "@nestjs/typeorm"; - -import { UserSettings } from "./entities/user-settings.entity"; -import { UserSettingsService } from "./providers/user-setttings.service"; -import { UserSettingsRepository } from "./repositories/user-settings.repository"; -import { UserSettingsController } from "./user-settings.controller"; - -@Module({ - imports: [TypeOrmModule.forFeature([UserSettings])], - providers: [UserSettingsService, UserSettingsRepository], - controllers: [UserSettingsController], - exports: [TypeOrmModule], -}) -export class UserSettingsModule {} diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index 1fd5618..70d9454 100644 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -7,6 +7,7 @@ import { BaseEntity } from "../../../common/entities/base.entity"; import { UserAnnouncement } from "../../announcements/entities/user-announcement.entity"; import { Criticism } from "../../criticisms/entities/criticism.entity"; import { DanakService } from "../../danak-services/entities/danak-service.entity"; +import { UserSetting } from "../../settings/entities/user-setting.entity"; import { TicketMessage } from "../../tickets/entities/ticket-message.entity"; import { Ticket } from "../../tickets/entities/ticket.entity"; @@ -58,4 +59,7 @@ export class User extends BaseEntity { @OneToMany(() => UserAnnouncement, (userAnnouncement) => userAnnouncement.user) userAnnouncements: UserAnnouncement[]; + + @OneToMany(() => UserSetting, (settings) => settings.user, { nullable: false }) + settings: UserSetting; } diff --git a/src/modules/users/providers/users.service.ts b/src/modules/users/providers/users.service.ts index 048ccbc..4b9f807 100644 --- a/src/modules/users/providers/users.service.ts +++ b/src/modules/users/providers/users.service.ts @@ -1,17 +1,18 @@ import { BadRequestException, Injectable } from "@nestjs/common"; import slugify from "slugify"; -import { In, Not } from "typeorm"; +import { DataSource, In, Not } from "typeorm"; // import { roles } from "../../../../database/seeders/role.seeder"; import { CommonMessage, UserMessage } from "../../../common/enums/message.enum"; import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto"; +import { UserSettingsService } from "../../settings/providers/user-settings.service"; import { CheckValidityDTO } from "../DTO/check-validity.dto"; import { UpdateProfileDto } from "../DTO/update-profile.dto"; import { CreateUserGroupDto } from "../DTO/user-group.dto"; +import { Role } from "../entities/role.entity"; import { User } from "../entities/user.entity"; import { RoleEnum } from "../enums/role.enum"; import { ValidityType } from "../enums/validity-type.enum"; -import { RoleRepository } from "../repositories/roles.repository"; import { UserGroupRepository } from "../repositories/user-group.repository"; import { UserRepository } from "../repositories/users.repository"; @@ -33,8 +34,9 @@ export class UsersService { }; constructor( private userRepository: UserRepository, - private roleRepository: RoleRepository, private userGroupRepository: UserGroupRepository, + private readonly userSettingsService: UserSettingsService, + private readonly dataSource: DataSource, ) {} /************************************************************ */ @@ -96,11 +98,47 @@ export class UsersService { // const existEmail = await this.userRepository.findOneWithEmail(registerDto.email); // if (existEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST); - const role = await this.roleRepository.findOneBy({ name: RoleEnum.USER }); - if (!role) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND); + const queryRunner = this.dataSource.createQueryRunner(); - const user = this.userRepository.create({ ...registerDto, password: hashedPassword, role }); - return await this.userRepository.save(user); + await queryRunner.connect(); // Establish a connection + await queryRunner.startTransaction(); // Start the transaction + + try { + // Find the USER role + const role = await queryRunner.manager.findOne(Role, { + where: { name: RoleEnum.USER }, + }); + if (!role) { + throw new BadRequestException(UserMessage.ROLE_NOT_FOUND); + } + + // Create and save the User entity + const user = queryRunner.manager.create(User, { + ...registerDto, + password: hashedPassword, + role, + }); + await queryRunner.manager.save(user); + + await this.userSettingsService.createUserSettings(user.id, queryRunner); + + // Commit the transaction + await queryRunner.commitTransaction(); + + return user; // Return the created user + } catch (error) { + await queryRunner.rollbackTransaction(); + throw error; + } finally { + await queryRunner.release(); + } + + // const role = await this.roleRepository.findOneBy({ name: RoleEnum.USER }); + // if (!role) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND); + + // const user = this.userRepository.create({ ...registerDto, password: hashedPassword, role }); + // await this.userSettingsService.createUserSettings(user.id); + // return await this.userRepository.save(user); } /************************************************************ */ @@ -153,4 +191,17 @@ export class UsersService { userGroups, }; } + + ///****************************************************** */ + async updateUserPassword(userId: string, newPassword: string) { + const updatedUser = await this.userRepository.update( + { id: userId }, + { + password: newPassword, + }, + ); + return { + updatedUser, + }; + } } diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 586d723..8e439a9 100644 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -9,10 +9,13 @@ import { RoleRepository } from "./repositories/roles.repository"; import { UserGroupRepository } from "./repositories/user-group.repository"; import { UserRepository } from "./repositories/users.repository"; import { UsersController } from "./users.controller"; +import { UserSetting } from "../settings/entities/user-setting.entity"; +import { UserSettingsService } from "../settings/providers/user-settings.service"; +import { UserSettingsRepository } from "../settings/repositories/user-settings.repository"; @Module({ - imports: [TypeOrmModule.forFeature([User, Role, UserGroup])], - providers: [UsersService, UserRepository, RoleRepository, UserGroupRepository], + imports: [TypeOrmModule.forFeature([User, Role, UserGroup, UserSetting])], + providers: [UsersService, UserRepository, RoleRepository, UserGroupRepository, UserSettingsRepository, UserSettingsService], controllers: [UsersController], exports: [UsersService, TypeOrmModule], })