new perms and fix email
Build and Deploy Docker Images / build_and_deploy (push) Has been cancelled

This commit is contained in:
2026-07-26 09:31:08 +03:30
parent be6e4a8d32
commit 77783549fa
8 changed files with 265 additions and 35 deletions
+1 -1
View File
@@ -33,7 +33,7 @@ SMS_PATTERN_NEW_TICKET_GLOBAL=536596
SMS_PATTERN_NEW_CRITICISM=983724
SMS_PATTERN_USER_PASSWORD=486237
SMTP_HOST=smtps.danakcorp.com
SMTP_PORT=465
SMTP_PORT=587
SMTP_USER=no-reply-danakcorp.com
SMTP_PASS=Mahyar.SR4@
MAIL_FROM=no-reply <no-reply@danakcorp.com>
@@ -0,0 +1,191 @@
import { MigrationInterface, QueryRunner } from "typeorm";
const NEW_PERMISSIONS = [
{ name: "blog_categories_create", title: "ایجاد دسته‌بندی بلاگ", source: "blogs_create" },
{ name: "blog_categories_read", title: "مشاهده دسته‌بندی بلاگ", source: "blogs_read" },
{ name: "blog_categories_update", title: "ویرایش دسته‌بندی بلاگ", source: "blogs_update" },
{ name: "blog_categories_delete", title: "حذف دسته‌بندی بلاگ", source: "blogs_delete" },
{ name: "blog_comments_create", title: "ایجاد نظرات بلاگ", source: "blogs_create" },
{ name: "blog_comments_read", title: "مشاهده نظرات بلاگ", source: "blogs_read" },
{ name: "blog_comments_update", title: "ویرایش نظرات بلاگ", source: "blogs_update" },
{ name: "blog_comments_delete", title: "حذف نظرات بلاگ", source: "blogs_delete" },
{ name: "sliders_create", title: "ایجاد اسلایدر", source: "blogs_create" },
{ name: "sliders_read", title: "مشاهده اسلایدر", source: "blogs_read" },
{ name: "sliders_update", title: "ویرایش اسلایدر", source: "blogs_update" },
{ name: "sliders_delete", title: "حذف اسلایدر", source: "blogs_delete" },
] as const;
const CURRENT_ENUM_VALUES = [
"services_create",
"services_read",
"services_update",
"services_delete",
"customers_create",
"customers_read",
"customers_update",
"customers_delete",
"agents_create",
"agents_read",
"agents_update",
"agents_delete",
"developers_create",
"developers_read",
"developers_update",
"developers_delete",
"invoices_create",
"invoices_read",
"invoices_update",
"invoices_delete",
"transactions_create",
"transactions_read",
"transactions_update",
"transactions_delete",
"discounts_create",
"discounts_read",
"discounts_update",
"discounts_delete",
"admins_create",
"admins_read",
"admins_update",
"admins_delete",
"tickets_create",
"tickets_read",
"tickets_update",
"tickets_delete",
"ticket_categories_create",
"ticket_categories_read",
"ticket_categories_update",
"ticket_categories_delete",
"ticket_masters_create",
"ticket_masters_read",
"ticket_masters_update",
"ticket_masters_delete",
"criticisms_create",
"criticisms_read",
"criticisms_update",
"criticisms_delete",
"contacts_us_create",
"contacts_us_read",
"contacts_us_update",
"contacts_us_delete",
"advertisements_create",
"advertisements_read",
"advertisements_update",
"advertisements_delete",
"announcements_create",
"announcements_read",
"announcements_update",
"announcements_delete",
"blogs_create",
"blogs_read",
"blogs_update",
"blogs_delete",
"learnings_create",
"learnings_read",
"learnings_update",
"learnings_delete",
"settings_create",
"settings_read",
"settings_update",
"settings_delete",
"bank_accounts_create",
"bank_accounts_read",
"bank_accounts_update",
"bank_accounts_delete",
"payments_create",
"payments_read",
"payments_update",
"payments_delete",
"support_plan_create",
"support_plan_read",
"support_plan_update",
"support_plan_delete",
"reseller_create",
"reseller_read",
"reseller_update",
"reseller_delete",
"workspace_create",
"workspace_read",
"workspace_update",
"workspace_delete",
"project_create",
"project_read",
"project_update",
"project_delete",
"task_create",
"task_read",
"task_update",
"task_delete",
"task_phase_create",
"task_phase_read",
"task_phase_update",
"task_phase_delete",
"logs",
"manage_sso_clients",
"dmenu",
"dkala",
"dpage",
"dmail",
"view_all_workspaces",
"view_all_projects",
];
const UPDATED_ENUM_VALUES = [
...CURRENT_ENUM_VALUES.slice(0, CURRENT_ENUM_VALUES.indexOf("blogs_delete") + 1),
...NEW_PERMISSIONS.map((p) => p.name),
...CURRENT_ENUM_VALUES.slice(CURRENT_ENUM_VALUES.indexOf("blogs_delete") + 1),
];
export class AddBlogCategoriesCommentsSlidersPermissions1785200000000 implements MigrationInterface {
name = "AddBlogCategoriesCommentsSlidersPermissions1785200000000";
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE text USING "name"::text`);
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
const enumList = UPDATED_ENUM_VALUES.map((v) => `'${v}'`).join(", ");
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM(${enumList})`);
await queryRunner.query(
`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"public"."permission_name_enum"`,
);
for (const perm of NEW_PERMISSIONS) {
const inserted = await queryRunner.query(
`INSERT INTO "permission" ("id", "name", "title", "group", "createdAt", "updatedAt")
VALUES (uuid_generate_v4(), $1, $2, 'content', NOW(), NOW())
RETURNING id`,
[perm.name, perm.title],
);
const newId = inserted[0].id as string;
const sourcePerm = await queryRunner.query(`SELECT id FROM "permission" WHERE "name" = $1`, [perm.source]);
if (!sourcePerm.length) continue;
await queryRunner.query(
`INSERT INTO "role_permission_relation" ("roleId", "permissionId")
SELECT "roleId", $1 FROM "role_permission_relation" WHERE "permissionId" = $2
ON CONFLICT ("roleId", "permissionId") DO NOTHING`,
[newId, sourcePerm[0].id],
);
}
}
public async down(queryRunner: QueryRunner): Promise<void> {
for (const perm of NEW_PERMISSIONS) {
const rows = await queryRunner.query(`SELECT id FROM "permission" WHERE "name" = $1`, [perm.name]);
if (!rows.length) continue;
await queryRunner.query(`DELETE FROM "role_permission_relation" WHERE "permissionId" = $1`, [rows[0].id]);
await queryRunner.query(`DELETE FROM "permission" WHERE "id" = $1`, [rows[0].id]);
}
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE text USING "name"::text`);
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
const enumList = CURRENT_ENUM_VALUES.map((v) => `'${v}'`).join(", ");
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM(${enumList})`);
await queryRunner.query(
`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"public"."permission_name_enum"`,
);
}
}
+2 -2
View File
@@ -1,10 +1,10 @@
{
"folders": [
{
"path": "./"
"path": "."
},
{
"path": "./danak-admin"
"path": "../danak-admin"
}
],
"settings": {}
+26 -20
View File
@@ -5,27 +5,33 @@ import { MailerAsyncOptions } from "@nestjs-modules/mailer/dist/interfaces/maile
export function mailerConfig(): MailerAsyncOptions {
return {
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
transport: {
host: configService.getOrThrow<string>("SMTP_HOST"),
port: configService.getOrThrow<number>("SMTP_PORT"),
secure: true,
auth: {
user: configService.getOrThrow<string>("SMTP_USER"),
pass: configService.getOrThrow<string>("SMTP_PASS"),
},
},
defaults: {
from: configService.getOrThrow<string>("MAIL_FROM"),
},
useFactory: (configService: ConfigService) => {
const port = Number(configService.getOrThrow<number>("SMTP_PORT"));
// 465 = implicit TLS; 587 = STARTTLS (required by zone-mta behind Traefik)
const secure = port === 465;
template: {
dir: process.cwd() + "/src/modules/templates/email",
adapter: new HandlebarsAdapter(),
options: {
strict: true,
return {
transport: {
host: configService.getOrThrow<string>("SMTP_HOST"),
port,
secure,
requireTLS: !secure,
auth: {
user: configService.getOrThrow<string>("SMTP_USER"),
pass: configService.getOrThrow<string>("SMTP_PASS"),
},
},
},
}),
defaults: {
from: configService.getOrThrow<string>("MAIL_FROM"),
},
template: {
dir: process.cwd() + "/src/modules/templates/email",
adapter: new HandlebarsAdapter(),
options: {
strict: true,
},
},
};
},
};
}
+7 -7
View File
@@ -149,7 +149,7 @@ export class BlogsController {
@ApiOperation({ summary: "Get all comments for a blog (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_READ)
@PermissionsDec(PermissionEnum.BLOG_COMMENTS_READ)
@Get(":id/comments")
getBlogCommentsForAdmin(@Param() paramDto: ParamDto) {
return this.blogCommentService.getBlogCommentsForAdmin(paramDto.id);
@@ -157,7 +157,7 @@ export class BlogsController {
@ApiOperation({ summary: "Get all comments for a blog (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_READ)
@PermissionsDec(PermissionEnum.BLOG_COMMENTS_READ)
@Get("comments")
getAllCommentForAdmin(@Query() queryDto: BlogCommentQueryDto) {
return this.blogCommentService.getAllCommentForAdmin(queryDto);
@@ -165,7 +165,7 @@ export class BlogsController {
@ApiOperation({ summary: "Update the status of a comment (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
@PermissionsDec(PermissionEnum.BLOG_COMMENTS_UPDATE)
@Patch("comments/:id/status")
updateCommentStatus(@Param() paramDto: ParamDto, @Body() updateCommentStatusDto: UpdateCommentStatusDto) {
return this.blogCommentService.updateCommentStatus(paramDto.id, updateCommentStatusDto);
@@ -196,7 +196,7 @@ export class BlogsController {
@ApiOperation({ summary: "Create a new category (admin route)" })
@Post("categories")
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
@PermissionsDec(PermissionEnum.BLOG_CATEGORIES_CREATE)
createCategory(@Body() createCategoryDto: CreateBlogCategoryDto) {
return this.blogsService.createCategory(createCategoryDto);
}
@@ -204,7 +204,7 @@ export class BlogsController {
@ApiOperation({ summary: "Update a category (admin route)" })
@Patch("categories/:id")
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
@PermissionsDec(PermissionEnum.BLOG_CATEGORIES_UPDATE)
updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateBlogCategoryDto) {
return this.blogsService.updateCategory(paramDto.id, updateCategoryDto);
}
@@ -212,13 +212,13 @@ export class BlogsController {
@ApiOperation({ summary: "Delete a category (admin route)" })
@Delete("categories/:id")
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_DELETE)
@PermissionsDec(PermissionEnum.BLOG_CATEGORIES_DELETE)
deleteCategory(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
return this.blogsService.deleteCategory(paramDto.id, userIpAndHeaders);
}
@ApiOperation({ summary: "toggle status of categories (admin route)" })
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
@PermissionsDec(PermissionEnum.BLOG_CATEGORIES_UPDATE)
@HttpCode(HttpStatus.OK)
@Post("categories/toggle-status/:id")
toggleCategoryStatus(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
+5 -5
View File
@@ -18,7 +18,7 @@ export class SlidersController {
@ApiOperation({ summary: "create slider (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
@PermissionsDec(PermissionEnum.SLIDERS_CREATE)
@Post()
create(@Body() createSliderDto: CreateSliderDto) {
return this.slidersService.create(createSliderDto);
@@ -26,7 +26,7 @@ export class SlidersController {
@ApiOperation({ summary: "Get all sliders (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_READ)
@PermissionsDec(PermissionEnum.SLIDERS_READ)
@Get()
getSlidersList(@Query() queryDto: PaginationDto) {
return this.slidersService.getSlidersList(queryDto);
@@ -34,7 +34,7 @@ export class SlidersController {
@ApiOperation({ summary: "Get a slider by id (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_READ)
@PermissionsDec(PermissionEnum.SLIDERS_READ)
@Get(":id")
getSliderById(@Param() paramDto: ParamDto) {
return this.slidersService.getSliderById(paramDto.id);
@@ -42,7 +42,7 @@ export class SlidersController {
@ApiOperation({ summary: "Update a slider (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
@PermissionsDec(PermissionEnum.SLIDERS_UPDATE)
@Patch(":id")
update(@Param() paramDto: ParamDto, @Body() updateSliderDto: UpdateSliderDto) {
return this.slidersService.update(paramDto.id, updateSliderDto);
@@ -50,7 +50,7 @@ export class SlidersController {
@ApiOperation({ summary: "Delete a slider (admin route)" })
@AdminRoute()
@PermissionsDec(PermissionEnum.BLOGS_DELETE)
@PermissionsDec(PermissionEnum.SLIDERS_DELETE)
@Delete(":id")
remove(@Param() paramDto: ParamDto) {
return this.slidersService.remove(paramDto.id);
@@ -87,6 +87,21 @@ export const permissionMeta: Record<PermissionEnum, PermissionMeta> = {
[PermissionEnum.BLOGS_UPDATE]: { title: "ویرایش بلاگ‌ها", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOGS_DELETE]: { title: "حذف بلاگ‌ها", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_CATEGORIES_CREATE]: { title: "ایجاد دسته‌بندی بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_CATEGORIES_READ]: { title: "مشاهده دسته‌بندی بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_CATEGORIES_UPDATE]: { title: "ویرایش دسته‌بندی بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_CATEGORIES_DELETE]: { title: "حذف دسته‌بندی بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_COMMENTS_CREATE]: { title: "ایجاد نظرات بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_COMMENTS_READ]: { title: "مشاهده نظرات بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_COMMENTS_UPDATE]: { title: "ویرایش نظرات بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.BLOG_COMMENTS_DELETE]: { title: "حذف نظرات بلاگ", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.SLIDERS_CREATE]: { title: "ایجاد اسلایدر", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.SLIDERS_READ]: { title: "مشاهده اسلایدر", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.SLIDERS_UPDATE]: { title: "ویرایش اسلایدر", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.SLIDERS_DELETE]: { title: "حذف اسلایدر", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.LEARNINGS_CREATE]: { title: "ایجاد آموزش‌ها", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.LEARNINGS_READ]: { title: "مشاهده آموزش‌ها", group: PermissionGroupEnum.CONTENT },
[PermissionEnum.LEARNINGS_UPDATE]: { title: "ویرایش آموزش‌ها", group: PermissionGroupEnum.CONTENT },
@@ -95,6 +95,24 @@ export enum PermissionEnum {
BLOGS_UPDATE = "blogs_update",
BLOGS_DELETE = "blogs_delete",
// blog_categories
BLOG_CATEGORIES_CREATE = "blog_categories_create",
BLOG_CATEGORIES_READ = "blog_categories_read",
BLOG_CATEGORIES_UPDATE = "blog_categories_update",
BLOG_CATEGORIES_DELETE = "blog_categories_delete",
// blog_comments
BLOG_COMMENTS_CREATE = "blog_comments_create",
BLOG_COMMENTS_READ = "blog_comments_read",
BLOG_COMMENTS_UPDATE = "blog_comments_update",
BLOG_COMMENTS_DELETE = "blog_comments_delete",
// sliders
SLIDERS_CREATE = "sliders_create",
SLIDERS_READ = "sliders_read",
SLIDERS_UPDATE = "sliders_update",
SLIDERS_DELETE = "sliders_delete",
// learnings
LEARNINGS_CREATE = "learnings_create",
LEARNINGS_READ = "learnings_read",