chore: add crude for admin

This commit is contained in:
mahyargdz
2025-04-22 12:28:11 +03:30
parent 368ab0b40a
commit 5ef5edc44b
41 changed files with 2996 additions and 2378 deletions
-5
View File
@@ -1,5 +0,0 @@
node_modules
dist
.eslintrc.js
.prettierrc.js
commitlint.config.ts
-98
View File
@@ -1,98 +0,0 @@
module.exports = {
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint", "prettier", "import"],
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended",
"plugin:import/recommended",
"plugin:import/typescript",
"prettier",
],
parserOptions: {
ecmaVersion: 2022,
sourceType: "module",
tsconfigRootDir: __dirname,
project: "./tsconfig.json",
},
env: {
es6: true,
node: true,
},
rules: {
// turn on errors for missing imports
"sort-imports": [
"error",
{
ignoreCase: false,
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ["none", "all", "multiple", "single"],
allowSeparatedGroups: true,
},
],
"import/no-unresolved": "error",
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", ["sibling", "parent"], "index", "unknown"],
"newlines-between": "always",
alphabetize: {
/* sort in ascending order. Options: ["ignore", "asc", "desc"] */
order: "asc",
/* ignore case. Options: [true, false] */
caseInsensitive: true,
},
},
],
// JavaScript Rules
"no-var": "error",
"prefer-const": "error",
"no-multi-spaces": "error",
"space-in-parens": "error",
"no-multiple-empty-lines": ["error", { max: 1, maxEOF: 0 }],
semi: ["error", "always"],
// Best Practices
"no-async-promise-executor": "warn",
"no-control-regex": "warn",
"no-empty": ["warn", { allowEmptyCatch: true }],
"no-extra-semi": "warn",
"no-prototype-builtins": "warn",
"no-regex-spaces": "warn",
"prefer-rest-params": "warn",
"prefer-spread": "warn",
// TypeScript-Specific Rules
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-loss-of-precision": "warn",
"@typescript-eslint/no-misused-new": "warn",
"@typescript-eslint/no-namespace": "warn",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
"@typescript-eslint/no-var-requires": "warn",
"@typescript-eslint/triple-slash-reference": "warn",
// "@typescript-eslint/explicit-function-return-type": [
// "warn",
// {
// allowExpressions: true,
// allowTypedFunctionExpressions: true,
// },
// ],
// "@typescript-eslint/no-inferrable-types": "warn",
// "@typescript-eslint/no-non-null-assertion": "warn",
},
};
+130
View File
@@ -0,0 +1,130 @@
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";
import eslintPluginPrettier from "eslint-plugin-prettier";
import eslintPluginImport from "eslint-plugin-import";
import globals from "globals";
import prettierConfig from "eslint-config-prettier";
export default tseslint.config(
{
ignores: [
"dist/**",
"node_modules/**",
"jest.config.js",
"coverage/**",
"database/migrations/**",
"pnpm-lock.yaml",
".prettierrc.js",
"commitlint.config.ts",
"eslint.config.mjs",
],
},
eslint.configs.recommended,
...tseslint.configs.recommended,
prettierConfig,
// Base configuration for all TypeScript files
{
files: ["**/*.ts"],
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
ecmaVersion: 2022,
sourceType: "module",
parser: tseslint.parser,
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
"@typescript-eslint": tseslint.plugin,
prettier: eslintPluginPrettier,
import: eslintPluginImport,
},
rules: {
// Import rules
"sort-imports": [
"error",
{
ignoreCase: false,
ignoreDeclarationSort: true,
ignoreMemberSort: false,
memberSyntaxSortOrder: ["none", "all", "multiple", "single"],
allowSeparatedGroups: true,
},
],
"import/order": [
"error",
{
groups: ["builtin", "external", "internal", ["sibling", "parent"], "index", "unknown"],
"newlines-between": "always",
alphabetize: {
order: "asc",
caseInsensitive: true,
},
},
],
// JavaScript Rules
"no-var": "error",
"prefer-const": "error",
"no-multi-spaces": "error",
"space-in-parens": "error",
"no-multiple-empty-lines": ["error", { max: 1, maxEOF: 0 }],
semi: ["error", "always"],
// Best Practices
"no-async-promise-executor": "warn",
"no-control-regex": "warn",
"no-empty": ["warn", { allowEmptyCatch: true }],
"no-extra-semi": "warn",
"no-prototype-builtins": "warn",
"no-regex-spaces": "warn",
"prefer-rest-params": "warn",
"prefer-spread": "warn",
// TypeScript-Specific Rules that don't need type information
"@typescript-eslint/ban-ts-comment": "warn",
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-loss-of-precision": "warn",
"@typescript-eslint/no-misused-new": "warn",
"@typescript-eslint/no-namespace": "warn",
"@typescript-eslint/no-this-alias": "warn",
"@typescript-eslint/no-unnecessary-type-constraint": "warn",
"@typescript-eslint/no-unsafe-declaration-merging": "warn",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_",
varsIgnorePattern: "^_",
caughtErrorsIgnorePattern: "^_",
ignoreRestSiblings: true,
},
],
"@typescript-eslint/no-var-requires": "warn",
"@typescript-eslint/triple-slash-reference": "warn",
},
},
// Additional configuration for type-checked files - disabled for now
{
files: ["**/*.ts"],
// Disable type-aware linting until we can configure it properly
rules: {
"@typescript-eslint/await-thenable": "off",
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/no-misused-promises": "off",
"@typescript-eslint/no-unnecessary-type-assertion": "off",
"@typescript-eslint/no-unsafe-argument": "off",
"@typescript-eslint/no-unsafe-assignment": "off",
"@typescript-eslint/no-unsafe-call": "off",
"@typescript-eslint/no-unsafe-member-access": "off",
"@typescript-eslint/no-unsafe-return": "off",
"@typescript-eslint/require-await": "off",
"@typescript-eslint/restrict-plus-operands": "off",
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/unbound-method": "off",
},
},
);
+44 -40
View File
@@ -12,7 +12,8 @@
"start:dev": "nest start --watch", "start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch", "start:debug": "nest start --debug --watch",
"start": "NODE_ENV=production node --trace-warnings dist/main", "start": "NODE_ENV=production node --trace-warnings dist/main",
"lint:fix": "eslint . --ext .ts --fix", "lint": "eslint . --fix",
"lint:fix": "eslint . --fix",
"test": "jest", "test": "jest",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:cov": "jest --coverage", "test:cov": "jest --coverage",
@@ -29,76 +30,79 @@
"prepare": "husky || true" "prepare": "husky || true"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.735.0", "@aws-sdk/client-s3": "^3.787.0",
"@fastify/static": "^7.0.4", "@fastify/static": "^8.1.1",
"@keyv/redis": "^4.2.0", "@keyv/redis": "^4.3.4",
"@nest-lab/fastify-multer": "^1.3.0", "@nest-lab/fastify-multer": "^1.3.0",
"@nest-lab/throttler-storage-redis": "^1.0.0", "@nest-lab/throttler-storage-redis": "^1.1.0",
"@nestjs-modules/mailer": "^2.0.2", "@nestjs-modules/mailer": "^2.0.2",
"@nestjs/axios": "^4.0.0", "@nestjs/axios": "^4.0.0",
"@nestjs/bullmq": "^11.0.2", "@nestjs/bullmq": "^11.0.2",
"@nestjs/cache-manager": "^3.0.0", "@nestjs/cache-manager": "^3.0.1",
"@nestjs/common": "^10.4.15", "@nestjs/common": "^11.0.20",
"@nestjs/config": "^4.0.0", "@nestjs/config": "^4.0.2",
"@nestjs/core": "^10.4.15", "@nestjs/core": "^11.0.20",
"@nestjs/jwt": "^11.0.0", "@nestjs/jwt": "^11.0.0",
"@nestjs/passport": "^11.0.4", "@nestjs/passport": "^11.0.5",
"@nestjs/platform-fastify": "^10.4.15", "@nestjs/platform-fastify": "^11.0.20",
"@nestjs/swagger": "^8.1.1", "@nestjs/swagger": "^11.1.5",
"@nestjs/throttler": "^6.3.0", "@nestjs/throttler": "^6.4.0",
"@nestjs/typeorm": "^10.0.2", "@nestjs/typeorm": "^11.0.0",
"@types/bcrypt": "^5.0.2", "@types/bcrypt": "^5.0.2",
"aws-sdk": "^2.1692.0", "aws-sdk": "^2.1692.0",
"axios": "^1.7.9", "axios": "^1.8.4",
"bcrypt": "^5.1.1", "bcrypt": "^5.1.1",
"bullmq": "^5.40.0", "bullmq": "^5.49.2",
"cache-manager": "^6.3.2", "cache-manager": "^6.4.2",
"class-transformer": "^0.5.1", "class-transformer": "^0.5.1",
"class-validator": "^0.14.1", "class-validator": "^0.14.1",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
"decimal.js": "^10.5.0", "decimal.js": "^10.5.0",
"dotenv": "^16.4.7", "dotenv": "^16.5.0",
"fastify": "^5.2.1", "fastify": "^5.3.2",
"handlebars": "^4.7.8", "handlebars": "^4.7.8",
"nestjs-telegraf": "^2.8.1", "nestjs-telegraf": "^2.8.1",
"nodemailer": "^6.9.16", "nodemailer": "^6.10.1",
"passport-jwt": "^4.0.1", "passport-jwt": "^4.0.1",
"pg": "^8.13.1", "pg": "^8.14.1",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1", "rxjs": "^7.8.2",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"telegraf": "^4.16.3", "telegraf": "^4.16.3",
"typeorm": "^0.3.20" "typeorm": "^0.3.22"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^19.6.1", "@commitlint/cli": "^19.8.0",
"@commitlint/config-conventional": "^19.6.0", "@commitlint/config-conventional": "^19.8.0",
"@nestjs/cli": "^10.4.9", "@nestjs/cli": "^11.0.6",
"@nestjs/schematics": "^10.2.3", "@nestjs/schematics": "^11.0.5",
"@nestjs/testing": "^10.4.15", "@nestjs/testing": "^11.0.20",
"@types/bcrypt": "^5.0.2", "@types/bcrypt": "^5.0.2",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^20.17.14", "@types/node": "^20.17.30",
"@types/nodemailer": "^6.4.17", "@types/nodemailer": "^6.4.17",
"@types/passport-jwt": "^4.0.1", "@types/passport-jwt": "^4.0.1",
"@types/supertest": "^6.0.2", "@types/supertest": "^6.0.3",
"@typescript-eslint/eslint-plugin": "^8.21.0", "@typescript-eslint/eslint-plugin": "^8.31.0",
"@typescript-eslint/parser": "^8.21.0", "@typescript-eslint/parser": "^8.31.0",
"eslint": "^8.57.1", "eslint": "^9.25.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^10.1.2",
"eslint-import-resolver-typescript": "^3.10.1",
"eslint-plugin-import": "^2.31.0", "eslint-plugin-import": "^2.31.0",
"eslint-plugin-prettier": "^5.2.3", "eslint-plugin-prettier": "^5.2.6",
"globals": "^16.0.0",
"husky": "^9.1.7", "husky": "^9.1.7",
"jest": "^29.7.0", "jest": "^29.7.0",
"lint-staged": "^15.4.1", "lint-staged": "^15.5.1",
"prettier": "^3.4.2", "prettier": "^3.5.3",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"supertest": "^7.0.0", "supertest": "^7.1.0",
"ts-jest": "^29.2.5", "ts-jest": "^29.3.2",
"ts-loader": "^9.5.2", "ts-loader": "^9.5.2",
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsconfig-paths": "^4.2.0", "tsconfig-paths": "^4.2.0",
"typescript": "^5.7.3" "typescript": "^5.8.3",
"typescript-eslint": "^8.31.0"
}, },
"jest": { "jest": {
"moduleFileExtensions": [ "moduleFileExtensions": [
+2620 -2169
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -7,13 +7,13 @@ import { ConfigModule } from "@nestjs/config";
import { ThrottlerModule } from "@nestjs/throttler"; import { ThrottlerModule } from "@nestjs/throttler";
import { TypeOrmModule } from "@nestjs/typeorm"; import { TypeOrmModule } from "@nestjs/typeorm";
import { MailerModule } from "@nestjs-modules/mailer"; import { MailerModule } from "@nestjs-modules/mailer";
import { TelegrafModule } from "nestjs-telegraf"; // import { TelegrafModule } from "nestjs-telegraf";
import { bullMqConfig } from "./configs/bullmq.config"; import { bullMqConfig } from "./configs/bullmq.config";
import { cacheConfig } from "./configs/cache.config"; import { cacheConfig } from "./configs/cache.config";
import { mailerConfig } from "./configs/mailer.config"; import { mailerConfig } from "./configs/mailer.config";
import { rateLimitConfig } from "./configs/rateLimit.config"; import { rateLimitConfig } from "./configs/rateLimit.config";
import { telegrafConfig } from "./configs/telegraf.config"; // import { telegrafConfig } from "./configs/telegraf.config";
import { databaseConfigs } from "./configs/typeorm.config"; import { databaseConfigs } from "./configs/typeorm.config";
import { HTTPLogger } from "./core/middlewares/logger.middleware"; import { HTTPLogger } from "./core/middlewares/logger.middleware";
import { AddressModule } from "./modules/address/address.module"; import { AddressModule } from "./modules/address/address.module";
@@ -42,7 +42,7 @@ import { WalletsModule } from "./modules/wallets/wallets.module";
@Module({ @Module({
imports: [ imports: [
TelegrafModule.forRootAsync(telegrafConfig()), // TelegrafModule.forRootAsync(telegrafConfig()),
MailerModule.forRootAsync(mailerConfig()), MailerModule.forRootAsync(mailerConfig()),
BullModule.forRootAsync(bullMqConfig()), BullModule.forRootAsync(bullMqConfig()),
ThrottlerModule.forRootAsync(rateLimitConfig()), ThrottlerModule.forRootAsync(rateLimitConfig()),
+5 -1
View File
@@ -29,7 +29,6 @@ export const enum AuthMessage {
PHONE_EXISTS = "شماره تلفن قبلا ثبت شده است", PHONE_EXISTS = "شماره تلفن قبلا ثبت شده است",
ADMIN_CREATED = "ادمین با موفقیت ایجاد شد", ADMIN_CREATED = "ادمین با موفقیت ایجاد شد",
PERM_NOT_FOUND = "دسترسی یافت نشد", PERM_NOT_FOUND = "دسترسی یافت نشد",
ADMIN_NOT_FOUND = "ادمین یافت نشد",
INVALID_PASS_FORMAT = "فرمت رمز عبور صحیح نیست", INVALID_PASS_FORMAT = "فرمت رمز عبور صحیح نیست",
PHONE_NOT_EMPTY = "شماره تلفن نمیتواند خالی باشد", PHONE_NOT_EMPTY = "شماره تلفن نمیتواند خالی باشد",
PASSWORD_FORMAT_INVALID = "رمز عبور باید به صورت رشته باشد", PASSWORD_FORMAT_INVALID = "رمز عبور باید به صورت رشته باشد",
@@ -61,6 +60,7 @@ export const enum AuthMessage {
LOGOUT_SUCCESS = "خروج با موفقیت انجام شد", LOGOUT_SUCCESS = "خروج با موفقیت انجام شد",
CURRENT_PASSWORD_INVALID = "رمز عبور فعلی نامعتبر است", CURRENT_PASSWORD_INVALID = "رمز عبور فعلی نامعتبر است",
TOKEN_EXPIRED_OR_INVALID = "توکن منقضی شده یا نامعتبر است", TOKEN_EXPIRED_OR_INVALID = "توکن منقضی شده یا نامعتبر است",
ACCESS_DENIED = "دسترسی شما محدود شده است",
} }
export const enum UserMessage { export const enum UserMessage {
@@ -105,6 +105,7 @@ export const enum UserMessage {
ADMIN_ID_REQUIRED = "شناسه ادمین مورد نیاز است", ADMIN_ID_REQUIRED = "شناسه ادمین مورد نیاز است",
INVALID_ADMIN_ID = "شناسه ادمین نامعتبر است", INVALID_ADMIN_ID = "شناسه ادمین نامعتبر است",
ADMIN_ID_SHOULD_BE_UUID = "شناسه ادمین باید یک UUID باشد", ADMIN_ID_SHOULD_BE_UUID = "شناسه ادمین باید یک UUID باشد",
ADMIN_NOT_FOUND = "ادمین یافت نشد",
} }
export const enum CommonMessage { export const enum CommonMessage {
@@ -593,6 +594,9 @@ export const enum AdminMessage {
ROLE_NAME_LENGTH = "نام نقش باید بین ۳ تا ۱۵۰ کاراکتر باشد", ROLE_NAME_LENGTH = "نام نقش باید بین ۳ تا ۱۵۰ کاراکتر باشد",
ROLE_EXIST = "نقش با این نام قبلا ثبت شده است", ROLE_EXIST = "نقش با این نام قبلا ثبت شده است",
ROLE_CREATED = "نقش با موفقیت ایجاد شد", ROLE_CREATED = "نقش با موفقیت ایجاد شد",
ADMIN_UPDATED = "مدیر با موفقیت به روز رسانی شد",
ADMIN_NOT_FOUND = "مدیری با این شناسه یافت نشد",
ADMIN_DELETED = "مدیر با موفقیت حذف شد",
} }
export const enum AdsMessage { export const enum AdsMessage {
TITLE_REQUIRED = "عنوان الزامی است", TITLE_REQUIRED = "عنوان الزامی است",
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { ValueTransformer } from "typeorm"; import { ValueTransformer } from "typeorm";
+1 -1
View File
@@ -23,7 +23,7 @@ export class HttpExceptionFilter implements ExceptionFilter {
}); });
} }
private extractMessage(response: string | object): string | string[] { private extractMessage(response: string | Record<string, any>): string | string[] {
if (typeof response === "string") { if (typeof response === "string") {
return [response]; return [response];
} }
+1
View File
@@ -18,6 +18,7 @@ async function bootstrap() {
app.enableCors({ app.enableCors({
origin: true, origin: true,
methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
credentials: true, credentials: true,
optionsSuccessStatus: 204, optionsSuccessStatus: 204,
}); });
@@ -113,6 +113,8 @@ export class AuthService {
const isAdmin = this.checkUserIsAdmin(user.roles); const isAdmin = this.checkUserIsAdmin(user.roles);
if (!isAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN); if (!isAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN);
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
const tokens = await this.tokensService.generateTokens(user); const tokens = await this.tokensService.generateTokens(user);
return { return {
@@ -191,6 +193,7 @@ export class AuthService {
const isUserAdmin = this.checkUserIsAdmin(user.roles); const isUserAdmin = this.checkUserIsAdmin(user.roles);
if (!isUserAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN); if (!isUserAdmin) throw new BadRequestException(AuthMessage.NOT_ADMIN);
if (user.deletedAt) throw new BadRequestException(AuthMessage.ACCESS_DENIED);
const tokens = await this.tokensService.generateTokens(user); const tokens = await this.tokensService.generateTokens(user);
+1 -1
View File
@@ -3,7 +3,7 @@ import { IsBoolean, IsNotEmpty, IsString, IsUrl, MaxLength } from "class-validat
import { BlogMessage } from "../../../common/enums/message.enum"; import { BlogMessage } from "../../../common/enums/message.enum";
export class CreateCategoryDto { export class CreateBlogCategoryDto {
@IsNotEmpty({ message: BlogMessage.TITLE_REQUIRED }) @IsNotEmpty({ message: BlogMessage.TITLE_REQUIRED })
@IsString({ message: BlogMessage.TITLE_STRING }) @IsString({ message: BlogMessage.TITLE_STRING })
@MaxLength(100, { message: BlogMessage.TITLE_MAX_LENGTH }) @MaxLength(100, { message: BlogMessage.TITLE_MAX_LENGTH })
+2 -2
View File
@@ -1,5 +1,5 @@
import { PartialType } from "@nestjs/swagger"; import { PartialType } from "@nestjs/swagger";
import { CreateCategoryDto } from "./create-category.dto"; import { CreateBlogCategoryDto } from "./create-category.dto";
export class UpdateCategoryDto extends PartialType(CreateCategoryDto) {} export class UpdateBlogCategoryDto extends PartialType(CreateBlogCategoryDto) {}
@@ -11,12 +11,12 @@ import { ParamDto } from "../../../common/DTO/param.dto";
import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto"; import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto";
import { PermissionEnum } from "../../users/enums/permission.enum"; import { PermissionEnum } from "../../users/enums/permission.enum";
import { CreateBlogDto } from "../DTO/create-blog.dto"; import { CreateBlogDto } from "../DTO/create-blog.dto";
import { CreateCategoryDto } from "../DTO/create-category.dto"; import { CreateBlogCategoryDto } from "../DTO/create-category.dto";
import { CreateCommentDto } from "../DTO/create-comment.dto"; import { CreateCommentDto } from "../DTO/create-comment.dto";
import { BlogSlugDto } from "../DTO/get-blog-by-slug.dto"; import { BlogSlugDto } from "../DTO/get-blog-by-slug.dto";
import { BlogListSearchQueryDto, BlogSearchQueryDto } from "../DTO/search-blog-query.dto"; import { BlogListSearchQueryDto, BlogSearchQueryDto } from "../DTO/search-blog-query.dto";
import { UpdateBlogDto } from "../DTO/update-blog.dto"; import { UpdateBlogDto } from "../DTO/update-blog.dto";
import { UpdateCategoryDto } from "../DTO/update-category.dto"; import { UpdateBlogCategoryDto } from "../DTO/update-category.dto";
import { UpdateCommentStatusDto } from "../DTO/update-comment-status.dto"; import { UpdateCommentStatusDto } from "../DTO/update-comment-status.dto";
import { BlogsService } from "../providers/blogs.service"; import { BlogsService } from "../providers/blogs.service";
@@ -165,7 +165,7 @@ export class BlogsController {
@Post("categories") @Post("categories")
@AdminRoute() @AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS) @PermissionsDec(PermissionEnum.BLOGS)
createCategory(@Body() createCategoryDto: CreateCategoryDto) { createCategory(@Body() createCategoryDto: CreateBlogCategoryDto) {
return this.blogsService.createCategory(createCategoryDto); return this.blogsService.createCategory(createCategoryDto);
} }
@@ -173,7 +173,7 @@ export class BlogsController {
@Patch("categories/:id") @Patch("categories/:id")
@AdminRoute() @AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS) @PermissionsDec(PermissionEnum.BLOGS)
updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateCategoryDto) { updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateBlogCategoryDto) {
return this.blogsService.updateCategory(paramDto.id, updateCategoryDto); return this.blogsService.updateCategory(paramDto.id, updateCategoryDto);
} }
+4 -4
View File
@@ -5,11 +5,11 @@ import { BlogMessage, CommonMessage } from "../../../common/enums/message.enum";
import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto"; import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto";
import { UsersService } from "../../users/providers/users.service"; import { UsersService } from "../../users/providers/users.service";
import { CreateBlogDto } from "../DTO/create-blog.dto"; import { CreateBlogDto } from "../DTO/create-blog.dto";
import { CreateCategoryDto } from "../DTO/create-category.dto"; import { CreateBlogCategoryDto } from "../DTO/create-category.dto";
import { CreateCommentDto } from "../DTO/create-comment.dto"; import { CreateCommentDto } from "../DTO/create-comment.dto";
import { BlogListSearchQueryDto, BlogSearchQueryDto } from "../DTO/search-blog-query.dto"; import { BlogListSearchQueryDto, BlogSearchQueryDto } from "../DTO/search-blog-query.dto";
import { UpdateBlogDto } from "../DTO/update-blog.dto"; import { UpdateBlogDto } from "../DTO/update-blog.dto";
import { UpdateCategoryDto } from "../DTO/update-category.dto"; import { UpdateBlogCategoryDto } from "../DTO/update-category.dto";
import { UpdateCommentStatusDto } from "../DTO/update-comment-status.dto"; import { UpdateCommentStatusDto } from "../DTO/update-comment-status.dto";
import { CommentStatus } from "../enums/comment-status.enum"; import { CommentStatus } from "../enums/comment-status.enum";
import { BlogCategoriesRepository } from "../repositories/blog-categories.repository"; import { BlogCategoriesRepository } from "../repositories/blog-categories.repository";
@@ -25,7 +25,7 @@ export class BlogsService {
) {} ) {}
//*********************************** */ //*********************************** */
async createCategory(createCategoryDto: CreateCategoryDto) { async createCategory(createCategoryDto: CreateBlogCategoryDto) {
const existingCategory = await this.blogCategoriesRepository.findOneBy({ title: createCategoryDto.title }); const existingCategory = await this.blogCategoriesRepository.findOneBy({ title: createCategoryDto.title });
if (existingCategory) throw new BadRequestException(BlogMessage.CATEGORY_ALREADY_EXISTS); if (existingCategory) throw new BadRequestException(BlogMessage.CATEGORY_ALREADY_EXISTS);
@@ -38,7 +38,7 @@ export class BlogsService {
} }
//*********************************** */ //*********************************** */
async updateCategory(id: string, updateCategoryDto: UpdateCategoryDto) { async updateCategory(id: string, updateCategoryDto: UpdateBlogCategoryDto) {
const category = await this.findCategoryById(id); const category = await this.findCategoryById(id);
if (updateCategoryDto.title) { if (updateCategoryDto.title) {
@@ -4,7 +4,7 @@ import { IsNull, Repository } from "typeorm";
import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto"; import { CategoryListSearchQueryDto } from "../../danak-services/DTO/category-search-query.dto";
import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { PaginationUtils } from "../../utils/providers/pagination.utils";
import { CreateCategoryDto } from "../DTO/create-category.dto"; import { CreateBlogCategoryDto } from "../DTO/create-category.dto";
import { BlogCategory } from "../entities/blog-category.entity"; import { BlogCategory } from "../entities/blog-category.entity";
@Injectable() @Injectable()
@@ -44,7 +44,7 @@ export class BlogCategoriesRepository extends Repository<BlogCategory> {
return query.getManyAndCount(); return query.getManyAndCount();
} }
async createCategory(createBlogCategoryDto: CreateCategoryDto) { async createCategory(createBlogCategoryDto: CreateBlogCategoryDto) {
const { title, description, iconUrl, isActive } = createBlogCategoryDto; const { title, description, iconUrl, isActive } = createBlogCategoryDto;
const blogCategory = this.create({ title, description, iconUrl, isActive }); const blogCategory = this.create({ title, description, iconUrl, isActive });
@@ -3,7 +3,7 @@ import { IsBoolean, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Leng
import { CategoryMessage } from "../../../common/enums/message.enum"; import { CategoryMessage } from "../../../common/enums/message.enum";
export class CreateCategoryDto { export class CreateDanakServiceCategoryDto {
@IsNotEmpty({ message: CategoryMessage.TITLE_REQUIRED }) @IsNotEmpty({ message: CategoryMessage.TITLE_REQUIRED })
@IsString({ message: CategoryMessage.TITLE_STRING }) @IsString({ message: CategoryMessage.TITLE_STRING })
@Length(3, 50, { message: CategoryMessage.TITLE_LENGTH }) @Length(3, 50, { message: CategoryMessage.TITLE_LENGTH })
@@ -1,5 +1,5 @@
import { PartialType } from "@nestjs/swagger"; import { PartialType } from "@nestjs/swagger";
import { CreateCategoryDto } from "./create-category.dto"; import { CreateDanakServiceCategoryDto } from "./create-category.dto";
export class UpdateCategoryDto extends PartialType(CreateCategoryDto) {} export class UpdateDanakServiceCategoryDto extends PartialType(CreateDanakServiceCategoryDto) {}
@@ -3,11 +3,11 @@ import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { AddReviewDto } from "./DTO/add-review.dto"; import { AddReviewDto } from "./DTO/add-review.dto";
import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "./DTO/category-search-query.dto"; import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "./DTO/category-search-query.dto";
import { CreateCategoryDto } from "./DTO/create-category.dto"; import { CreateDanakServiceCategoryDto } from "./DTO/create-category.dto";
import { CreateServiceDto } from "./DTO/create-service.dto"; import { CreateServiceDto } from "./DTO/create-service.dto";
import { DanakServiceReviewQueryDto } from "./DTO/danak-service-review-query.dto"; import { DanakServiceReviewQueryDto } from "./DTO/danak-service-review-query.dto";
import { DanakServicesGlobalSearchDto, DanakServicesQueryDto, DanakServicesSearchQueryDto } from "./DTO/danak-services-search-query.dto"; import { DanakServicesGlobalSearchDto, DanakServicesQueryDto, DanakServicesSearchQueryDto } from "./DTO/danak-services-search-query.dto";
import { UpdateCategoryDto } from "./DTO/update-category.dto"; import { UpdateDanakServiceCategoryDto } from "./DTO/update-category.dto";
import { UpdateReviewStatusDto } from "./DTO/update-review-status.dto"; import { UpdateReviewStatusDto } from "./DTO/update-review-status.dto";
import { UpdateServiceDto } from "./DTO/update-service.dto"; import { UpdateServiceDto } from "./DTO/update-service.dto";
import { DanakServicesService } from "./providers/danak-services.service"; import { DanakServicesService } from "./providers/danak-services.service";
@@ -28,7 +28,7 @@ export class DanakServicesController {
@PermissionsDec(PermissionEnum.SERVICES) @PermissionsDec(PermissionEnum.SERVICES)
@ApiOperation({ summary: "Create a new service category => admin route" }) @ApiOperation({ summary: "Create a new service category => admin route" })
@Post("categories") @Post("categories")
createCategory(@Body() createDto: CreateCategoryDto) { createCategory(@Body() createDto: CreateDanakServiceCategoryDto) {
return this.danakServicesService.createCategory(createDto); return this.danakServicesService.createCategory(createDto);
} }
@@ -68,7 +68,7 @@ export class DanakServicesController {
@PermissionsDec(PermissionEnum.SERVICES) @PermissionsDec(PermissionEnum.SERVICES)
@ApiOperation({ summary: "update category by id => admin route" }) @ApiOperation({ summary: "update category by id => admin route" })
@Patch("categories/:id") @Patch("categories/:id")
updateCategory(@Param() paramDto: ParamDto, @Body() updateDto: UpdateCategoryDto) { updateCategory(@Param() paramDto: ParamDto, @Body() updateDto: UpdateDanakServiceCategoryDto) {
return this.danakServicesService.updateCategory(paramDto.id, updateDto); return this.danakServicesService.updateCategory(paramDto.id, updateDto);
} }
@@ -7,11 +7,11 @@ import { SubscriptionStatus } from "../../subscriptions/enums/subscription-statu
import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { PaginationUtils } from "../../utils/providers/pagination.utils";
import { AddReviewDto } from "../DTO/add-review.dto"; import { AddReviewDto } from "../DTO/add-review.dto";
import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "../DTO/category-search-query.dto"; import { CategoryListSearchQueryDto, CategorySearchQueryDto } from "../DTO/category-search-query.dto";
import { CreateCategoryDto } from "../DTO/create-category.dto"; import { CreateDanakServiceCategoryDto } from "../DTO/create-category.dto";
import { CreateServiceDto } from "../DTO/create-service.dto"; import { CreateServiceDto } from "../DTO/create-service.dto";
import { DanakServiceReviewQueryDto } from "../DTO/danak-service-review-query.dto"; import { DanakServiceReviewQueryDto } from "../DTO/danak-service-review-query.dto";
import { DanakServicesGlobalSearchDto, DanakServicesQueryDto, DanakServicesSearchQueryDto } from "../DTO/danak-services-search-query.dto"; import { DanakServicesGlobalSearchDto, DanakServicesQueryDto, DanakServicesSearchQueryDto } from "../DTO/danak-services-search-query.dto";
import { UpdateCategoryDto } from "../DTO/update-category.dto"; import { UpdateDanakServiceCategoryDto } from "../DTO/update-category.dto";
import { UpdateReviewStatusDto } from "../DTO/update-review-status.dto"; import { UpdateReviewStatusDto } from "../DTO/update-review-status.dto";
import { UpdateServiceDto } from "../DTO/update-service.dto"; import { UpdateServiceDto } from "../DTO/update-service.dto";
import { DanakServiceCategory } from "../entities/danak-service-category.entity"; import { DanakServiceCategory } from "../entities/danak-service-category.entity";
@@ -34,7 +34,7 @@ export class DanakServicesService {
) {} ) {}
/******************************************** */ /******************************************** */
async createCategory(createDto: CreateCategoryDto) { async createCategory(createDto: CreateDanakServiceCategoryDto) {
const queryRunner = this.dataSource.createQueryRunner(); const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect(); await queryRunner.connect();
await queryRunner.startTransaction(); await queryRunner.startTransaction();
@@ -98,7 +98,7 @@ export class DanakServicesService {
/******************************************** */ /******************************************** */
async updateCategory(categoryId: string, updateDto: UpdateCategoryDto) { async updateCategory(categoryId: string, updateDto: UpdateDanakServiceCategoryDto) {
const queryRunner = this.dataSource.createQueryRunner(); const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect(); await queryRunner.connect();
await queryRunner.startTransaction(); await queryRunner.startTransaction();
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne } from "typeorm"; import { Column, Entity, ManyToOne } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne } from "typeorm"; import { Column, Entity, ManyToOne } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne, OneToMany } from "typeorm"; import { Column, Entity, ManyToOne, OneToMany } from "typeorm";
@@ -1,9 +1,7 @@
import { InjectQueue } from "@nestjs/bullmq"; import { InjectQueue } from "@nestjs/bullmq";
import { BadRequestException, Injectable, Logger } from "@nestjs/common"; import { BadRequestException, Injectable, Logger } from "@nestjs/common";
// eslint-disable-next-line import/no-named-as-default
import { Queue } from "bullmq"; import { Queue } from "bullmq";
import dayjs from "dayjs"; import dayjs from "dayjs";
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Between, DataSource, QueryRunner } from "typeorm"; import { Between, DataSource, QueryRunner } from "typeorm";
@@ -1,7 +1,6 @@
import { InjectQueue, Processor } from "@nestjs/bullmq"; import { InjectQueue, Processor } from "@nestjs/bullmq";
import { Job, Queue } from "bullmq"; import { Job, Queue } from "bullmq";
import dayjs from "dayjs"; import dayjs from "dayjs";
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { DataSource, QueryRunner } from "typeorm"; import { DataSource, QueryRunner } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne, OneToMany } from "typeorm"; import { Column, Entity, ManyToOne, OneToMany } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne, OneToMany } from "typeorm"; import { Column, Entity, ManyToOne, OneToMany } from "typeorm";
+1 -2
View File
@@ -1,6 +1,5 @@
//------------------ process payment ------------------------- //------------------ process payment -------------------------
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
export interface IProcessPaymentParams { export interface IProcessPaymentParams {
@@ -3,7 +3,6 @@ import { BadRequestException, HttpException, HttpStatus, Injectable, InternalSer
import { ConfigService } from "@nestjs/config"; import { ConfigService } from "@nestjs/config";
import { Queue } from "bullmq"; import { Queue } from "bullmq";
import dayjs from "dayjs"; import dayjs from "dayjs";
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { FastifyReply } from "fastify"; import { FastifyReply } from "fastify";
import { DataSource, Not, QueryRunner } from "typeorm"; import { DataSource, Not, QueryRunner } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne } from "typeorm"; import { Column, Entity, ManyToOne } from "typeorm";
@@ -1,7 +1,6 @@
import { randomBytes } from "node:crypto"; import { randomBytes } from "node:crypto";
import { BadRequestException, Injectable } from "@nestjs/common"; import { BadRequestException, Injectable } from "@nestjs/common";
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { QueryRunner } from "typeorm"; import { QueryRunner } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, DeleteDateColumn, Entity, Index, ManyToOne, OneToMany } from "typeorm"; import { Column, DeleteDateColumn, Entity, Index, ManyToOne, OneToMany } from "typeorm";
@@ -1,6 +1,5 @@
import { BadRequestException, Injectable } from "@nestjs/common"; import { BadRequestException, Injectable } from "@nestjs/common";
import dayjs from "dayjs"; import dayjs from "dayjs";
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { DataSource, In, Not, QueryRunner } from "typeorm"; import { DataSource, In, Not, QueryRunner } from "typeorm";
@@ -0,0 +1,5 @@
import { PartialType } from "@nestjs/swagger";
import { CreateAdminDto } from "./create-admin.dto";
export class UpdateAdminDto extends PartialType(CreateAdminDto) {}
+4 -1
View File
@@ -1,5 +1,5 @@
import { Exclude } from "class-transformer"; import { Exclude } from "class-transformer";
import { Column, Entity, JoinTable, ManyToMany, OneToMany, OneToOne } from "typeorm"; import { Column, DeleteDateColumn, Entity, JoinTable, ManyToMany, OneToMany, OneToOne } from "typeorm";
import { LegalUser } from "./legal-user.entity"; import { LegalUser } from "./legal-user.entity";
import { RealUser } from "./real-user.entity"; import { RealUser } from "./real-user.entity";
@@ -63,6 +63,9 @@ export class User extends BaseEntity {
@Column({ type: "enum", enum: FinancialType, nullable: true, default: null }) @Column({ type: "enum", enum: FinancialType, nullable: true, default: null })
financialType: FinancialType | null; financialType: FinancialType | null;
@DeleteDateColumn({ nullable: true })
deletedAt?: Date;
//----------------------------------------- //-----------------------------------------
@ManyToMany(() => Role, (role) => role.users) @ManyToMany(() => Role, (role) => role.users)
+117 -15
View File
@@ -1,6 +1,6 @@
import { BadRequestException, Injectable } from "@nestjs/common"; import { BadRequestException, Injectable } from "@nestjs/common";
import slugify from "slugify"; import slugify from "slugify";
import { In } from "typeorm"; import { DataSource, In, Not } from "typeorm";
import { AdminMessage, AdsMessage, UserMessage } from "../../../common/enums/message.enum"; import { AdminMessage, AdsMessage, UserMessage } from "../../../common/enums/message.enum";
import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { PaginationUtils } from "../../utils/providers/pagination.utils";
@@ -9,6 +9,7 @@ import { CreateAdminDto } from "../DTO/create-admin.dto";
import { CreateRoleDto } from "../DTO/create-role.dto"; import { CreateRoleDto } from "../DTO/create-role.dto";
import { SearchAdminQueryDto } from "../DTO/search-admins-query.dto"; import { SearchAdminQueryDto } from "../DTO/search-admins-query.dto";
import { SearchRolesQueryDto } from "../DTO/search-roles.dto"; import { SearchRolesQueryDto } from "../DTO/search-roles.dto";
import { UpdateAdminDto } from "../DTO/update-admin.dto";
import { PermissionsRepository } from "../repositories/permissions.repository"; import { PermissionsRepository } from "../repositories/permissions.repository";
import { RoleRepository } from "../repositories/roles.repository"; import { RoleRepository } from "../repositories/roles.repository";
import { UserRepository } from "../repositories/users.repository"; import { UserRepository } from "../repositories/users.repository";
@@ -20,33 +21,127 @@ export class AdminsService {
private readonly rolesRepository: RoleRepository, private readonly rolesRepository: RoleRepository,
private readonly permissionsRepository: PermissionsRepository, private readonly permissionsRepository: PermissionsRepository,
private readonly passwordService: PasswordService, private readonly passwordService: PasswordService,
private readonly dataSource: DataSource,
) {} ) {}
async createAdmin(createDto: CreateAdminDto) { async createAdmin(createDto: CreateAdminDto) {
const existEmail = await this.userRepository.findOneBy({ email: createDto.email }); const queryRunner = this.dataSource.createQueryRunner();
if (existEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST);
const existPhone = await this.userRepository.findOneBy({ phone: createDto.phone }); try {
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST); await queryRunner.connect();
await queryRunner.startTransaction();
const role = await this.rolesRepository.findOne({ where: { id: createDto.roleId }, relations: { permissions: true } }); const existEmail = await queryRunner.manager.findOneBy(this.userRepository.target, { email: createDto.email });
if (!role) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND); if (existEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST);
await this.rolesRepository.save(role); const existPhone = await queryRunner.manager.findOneBy(this.userRepository.target, { phone: createDto.phone });
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
if (createDto.password !== createDto.repeatPassword) throw new BadRequestException(AdminMessage.PASSWORD_NOT_MATCH); const role = await queryRunner.manager.findOne(this.rolesRepository.target, {
where: { id: createDto.roleId },
relations: { permissions: true },
});
if (!role) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND);
const hashedPassword = await this.passwordService.hashPassword(createDto.password); if (createDto.password !== createDto.repeatPassword) throw new BadRequestException(AdminMessage.PASSWORD_NOT_MATCH);
const userName = slugify(`${createDto.firstName} ${Date.now().toString().slice(-5)}`, { lower: true, trim: true }); const hashedPassword = await this.passwordService.hashPassword(createDto.password);
const userName = slugify(`${createDto.firstName} ${Date.now().toString().slice(-5)}`, { lower: true, trim: true });
const adminUser = this.userRepository.create({ ...createDto, roles: [role], password: hashedPassword, userName }); await queryRunner.manager.save(this.rolesRepository.target, role);
await this.userRepository.save(adminUser);
const adminUser = queryRunner.manager.create(this.userRepository.target, {
...createDto,
roles: [role],
password: hashedPassword,
userName,
});
await queryRunner.manager.save(this.userRepository.target, adminUser);
await queryRunner.commitTransaction();
return {
message: AdminMessage.ADMIN_CREATED,
adminUser,
};
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
/************************************************************ */
async updateAdmin(id: string, updateDto: UpdateAdminDto) {
const queryRunner = this.dataSource.createQueryRunner();
try {
await queryRunner.connect();
await queryRunner.startTransaction();
const admin = await queryRunner.manager.findOne(this.userRepository.target, {
where: { id, roles: { isAdmin: true } },
relations: { roles: true },
});
if (!admin) throw new BadRequestException(UserMessage.ADMIN_NOT_FOUND);
if (updateDto.email && updateDto.email !== admin.email) {
const existEmail = await queryRunner.manager.findOneBy(this.userRepository.target, { email: updateDto.email, id: Not(id) });
if (existEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST);
}
if (updateDto.phone && updateDto.phone !== admin.phone) {
const existPhone = await queryRunner.manager.findOneBy(this.userRepository.target, { phone: updateDto.phone, id: Not(id) });
if (existPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
}
if (updateDto.roleId) {
const role = await queryRunner.manager.findOne(this.rolesRepository.target, {
where: { id: updateDto.roleId },
relations: { permissions: true },
});
if (!role) throw new BadRequestException(AdsMessage.ROLE_NOT_FOUND);
await queryRunner.manager.save(this.rolesRepository.target, role);
admin.roles = [role];
await queryRunner.manager.save(this.userRepository.target, admin);
}
if (updateDto.password) {
if (updateDto.password !== updateDto.repeatPassword) throw new BadRequestException(AdminMessage.PASSWORD_NOT_MATCH);
admin.password = await this.passwordService.hashPassword(updateDto.password);
}
await queryRunner.manager.save(this.userRepository.target, { ...admin, ...updateDto, password: admin.password });
await queryRunner.commitTransaction();
return {
message: AdminMessage.ADMIN_UPDATED,
};
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
/************************************************************ */
async deleteAdmin(id: string) {
const admin = await this.userRepository.findOne({ where: { id, roles: { isAdmin: true } } });
if (!admin) throw new BadRequestException(AdminMessage.ADMIN_NOT_FOUND);
await this.userRepository.softDelete(id);
return { return {
message: AdminMessage.ADMIN_CREATED, message: AdminMessage.ADMIN_DELETED,
adminUser,
}; };
} }
/************************************************************ */ /************************************************************ */
async createRole(createDto: CreateRoleDto) { async createRole(createDto: CreateRoleDto) {
@@ -78,6 +173,13 @@ export class AdminsService {
/************************************************************ */ /************************************************************ */
async getAdminById(id: string) {
const admin = await this.userRepository.findOne({ where: { id, roles: { isAdmin: true } }, relations: { roles: true } });
if (!admin) throw new BadRequestException(AdminMessage.ADMIN_NOT_FOUND);
return { admin };
}
/************************************************************ */
async getPermissions() { async getPermissions() {
const permissions = await this.permissionsRepository.find({ select: { id: true, name: true } }); const permissions = await this.permissionsRepository.find({ select: { id: true, name: true } });
return { return {
@@ -117,7 +117,8 @@ export class UserRepository extends Repository<User> {
// .addSelect(["role.id", "role.name"]) // .addSelect(["role.id", "role.name"])
.where("role.isAdmin = :isAdmin", { isAdmin: true }) .where("role.isAdmin = :isAdmin", { isAdmin: true })
.leftJoinAndSelect("user.groups", "groups") .leftJoinAndSelect("user.groups", "groups")
.leftJoinAndSelect("role.permissions", "permissions"); .leftJoinAndSelect("role.permissions", "permissions")
.andWhere("user.deletedAt IS NULL");
// .where("permissions.name IN (:...adminPermissions)", { // .where("permissions.name IN (:...adminPermissions)", {
// adminPermissions: [PermissionEnum.ADMINS], // adminPermissions: [PermissionEnum.ADMINS],
// }); // });
+26 -1
View File
@@ -1,4 +1,4 @@
import { Body, Controller, Get, HttpCode, HttpStatus, Param, Patch, Post, Query, Res } from "@nestjs/common"; import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Query, Res } from "@nestjs/common";
import { ApiOperation, ApiTags } from "@nestjs/swagger"; import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { FastifyReply } from "fastify"; import { FastifyReply } from "fastify";
@@ -12,6 +12,7 @@ import { CreateRoleDto } from "./DTO/create-role.dto";
import { SearchAdminQueryDto } from "./DTO/search-admins-query.dto"; import { SearchAdminQueryDto } from "./DTO/search-admins-query.dto";
import { SearchCustomersDto } from "./DTO/search-customers.dto"; import { SearchCustomersDto } from "./DTO/search-customers.dto";
import { SearchRolesQueryDto } from "./DTO/search-roles.dto"; import { SearchRolesQueryDto } from "./DTO/search-roles.dto";
import { UpdateAdminDto } from "./DTO/update-admin.dto";
import { UpdateCustomerDto } from "./DTO/update-customer.dto"; import { UpdateCustomerDto } from "./DTO/update-customer.dto";
import { UpdateProfileDto } from "./DTO/update-profile.dto"; import { UpdateProfileDto } from "./DTO/update-profile.dto";
import { CreateUserGroupDto } from "./DTO/user-group.dto"; import { CreateUserGroupDto } from "./DTO/user-group.dto";
@@ -183,6 +184,30 @@ export class UsersController {
return this.adminsService.getAdmins(queryDto); return this.adminsService.getAdmins(queryDto);
} }
@ApiOperation({ summary: "get admin by id ==> admin route" })
@AuthGuards()
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
@Get("admins/:id")
getAdminById(@Param() paramDto: ParamDto) {
return this.adminsService.getAdminById(paramDto.id);
}
@ApiOperation({ summary: "update admin ==> admin route" })
@AuthGuards()
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
@Patch("admins/:id")
updateAdmin(@Param() paramDto: ParamDto, @Body() updateDto: UpdateAdminDto) {
return this.adminsService.updateAdmin(paramDto.id, updateDto);
}
@ApiOperation({ summary: "delete admin ==> admin route" })
@AuthGuards()
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
@Delete("admins/:id")
deleteAdmin(@Param() paramDto: ParamDto) {
return this.adminsService.deleteAdmin(paramDto.id);
}
@ApiOperation({ summary: "create admin ==> admin route" }) @ApiOperation({ summary: "create admin ==> admin route" })
@AuthGuards() @AuthGuards()
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS) @PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, ManyToOne } from "typeorm"; import { Column, Entity, ManyToOne } from "typeorm";
@@ -1,4 +1,4 @@
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { Column, Entity, JoinColumn, OneToMany, OneToOne } from "typeorm"; import { Column, Entity, JoinColumn, OneToMany, OneToOne } from "typeorm";
@@ -1,5 +1,4 @@
import { BadRequestException, Injectable } from "@nestjs/common"; import { BadRequestException, Injectable } from "@nestjs/common";
// eslint-disable-next-line import/no-named-as-default
import Decimal from "decimal.js"; import Decimal from "decimal.js";
import { QueryRunner } from "typeorm"; import { QueryRunner } from "typeorm";