Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f66bc9fa8c | |||
| 6b222db890 | |||
| c82cc654f0 | |||
| c956bc0deb | |||
| 30d86c9775 | |||
| 4263d7118e | |||
| 0e8e0cba2e | |||
| 3a84740d9a | |||
| f35df6492c | |||
| 008bddb97a | |||
| cb77a55281 | |||
| 11445f0a07 | |||
| 8e23a06793 | |||
| c2a861041f | |||
| 1440b62373 | |||
| d93e4be6ef | |||
| 50d9fb2274 | |||
| 9ded147354 | |||
| 2768611a7c | |||
| b1a02d6b0d | |||
| 8b901e4d02 | |||
| 43b4f05894 | |||
| 7bef7d414a | |||
| 4cb20f6c0d | |||
| 95c947a587 | |||
| 8348692481 | |||
| 677fc5b384 | |||
| 8481a0e86f | |||
| b32d613a1b | |||
| b0668c7b2c | |||
| ff08da1330 | |||
| 29d647556c | |||
| a22d6ceb81 | |||
| eb6fbc3ce5 | |||
| 9565eda0fd | |||
| 8533682303 | |||
| e5c14bf5cc | |||
| e310411a4d | |||
| 0cd5a6a0cc | |||
| da71c20d6d | |||
| 263ede68b2 | |||
| d9283e3a90 | |||
| 5964a9b20d | |||
| 5715cbe9b1 | |||
| 2590a222b4 | |||
| 16a0c14149 | |||
| 9f61152d94 | |||
| a14bd490be | |||
| 47a5a2abb4 | |||
| 5763cb7d6c | |||
| 35d0d9f7cd | |||
| d4bd593f5b | |||
| c5b2cb93f0 | |||
| 30dba5ae37 | |||
| e57dd84ebc | |||
| 8d962ea6ee | |||
| 06ec73be92 | |||
| c22a41d29b | |||
| 4b95d35d87 | |||
| fc23a94fb6 | |||
| 1b70e49d93 | |||
| 3ad73a5271 | |||
| a51b19f85c | |||
| a199623eb4 | |||
| 4f76af87a6 | |||
| 27e9ad76a5 | |||
| c99a8a435c |
@@ -0,0 +1,75 @@
|
|||||||
|
NODE_ENV=production
|
||||||
|
PORT=3500
|
||||||
|
DB_NAME=dscDev
|
||||||
|
DB_USER=postgres
|
||||||
|
DB_PASS=1RWVdlUcZSf6PoFBQO8cprZk2DTkC89ttqeJN7aU2WQRDUEusK4z2FfNqNtV4I10
|
||||||
|
DB_HOST=78.157.34.13
|
||||||
|
DB_PORT=5432
|
||||||
|
SMS_API_URL=https://api.sms.ir/v1
|
||||||
|
SMS_API_KEY=QkkNxhyXZ6GtEf1soOTtikomO3mA4LaNQDH8mol8huDIwh00
|
||||||
|
SMS_PATTERN_OTP=842088
|
||||||
|
SMS_PATTERN_INVOICE=683883
|
||||||
|
SMS_PATTERN_LOGIN=149141
|
||||||
|
SMS_PATTERN_INVOICE_CREATED=829067
|
||||||
|
SMS_PATTERN_ANNOUNCEMENT=752330
|
||||||
|
SMS_PATTERN_WALLET_CHARGE=727726
|
||||||
|
SMS_PATTERN_WALLET_DEDUCTION=360785
|
||||||
|
SMS_PATTERN_TICKET_CREATED=853506
|
||||||
|
SMS_PATTERN_TICKET_ANSWERED=179464
|
||||||
|
SMS_PATTERN_TICKET_ASSIGNED_ADMIN=321927
|
||||||
|
SMS_PATTERN_INVOICE_APPROVED=303807
|
||||||
|
SMS_PATTERN_INVOICE_PAID=533817
|
||||||
|
SMS_PATTERN_RECURRING_INVOICE_DRAFT=219287
|
||||||
|
SMS_PATTERN_SUBSCRIPTION_CANCELLED=166142
|
||||||
|
SMS_PATTERN_INVOICE_REMINDER=370266
|
||||||
|
SMS_PATTERN_INVOICE_OVERDUE=160735
|
||||||
|
SMS_PATTERN_PAYMENT_REMINDER=629772
|
||||||
|
SMS_PATTERN_PAYMENT_CANCELLATION=197945
|
||||||
|
SMS_PATTERN_BLOG_NEW_COMMENT=378881
|
||||||
|
SMS_PATTERN_NEW_SERVICE_REVIEW=593446
|
||||||
|
SMS_PATTERN_NEW_CUSTOMER=966214
|
||||||
|
SMS_PATTERN_NEW_SUBSCRIPTION=757095
|
||||||
|
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_USER=no-reply-danakcorp.com
|
||||||
|
SMTP_PASS=Mahyar.SR4@
|
||||||
|
MAIL_FROM=no-reply <no-reply@danakcorp.com>
|
||||||
|
EMAIL_SECRET=xDkdptbC2N7LoR2Aa4Q9U/aAGOi4DxG2748
|
||||||
|
REDIS_URI=redis://localhost:6379/1
|
||||||
|
CACHE_TTL=180000
|
||||||
|
THROTTLE_TTL=300000
|
||||||
|
THROTTLE_LIMIT=10
|
||||||
|
JWT_SECRET_KEY=2ygxIB1PJhK/L2PToqR3+52gRmUIdPfwTguYlB7ZRCdRyvA/N36jjkjbYJLoMxEL\n6xGmk5CQmCmn9c0FsBlN1g
|
||||||
|
JWT_ISSUER=console-danak
|
||||||
|
ACCESS_TOKEN_EXPIRE=80000
|
||||||
|
REFRESH_TOKEN_EXPIRE=6
|
||||||
|
BUCKET_NAME=danak-project
|
||||||
|
BUCKET_REGION=default
|
||||||
|
BUCKET_URL=https://s3.ir-thr-at1.arvanstorage.ir
|
||||||
|
BUCKET_ACCESS_KEY=4bd15218-60f1-4ce7-a7aa-3fd319b13372
|
||||||
|
BUCKET_SECRET_KEY=de772e5bd62fb04fb3669e67e09ddb101db60c65d77eea66b215ce58275e6a76
|
||||||
|
BUCKET_UPLOAD_URL=https://storage.danakcorp.com
|
||||||
|
ZARINPAL_MERCHANT_ID=fc0b7503-bba5-40d1-9f9d-dae52ac02eef
|
||||||
|
PARSIAN_LOGIN_ACCOUNT=uqXnB2q8rjkL6vN0xOh0
|
||||||
|
SITE_URL=https://console.danakcorp.com
|
||||||
|
API_URL=https://api.danakcorp.com
|
||||||
|
CALLBACK_URL=https://api.danakcorp.com/payments/verify
|
||||||
|
TELEGRAM_BOT_TOKEN=7839690719:AAGsyfwympR4rDLm2JCx43CQh52s1o865uY
|
||||||
|
TELEGRAM_BOT_NAME=danak_logs_bot
|
||||||
|
TELEGRAM_CHAT_ID=7801476800
|
||||||
|
EXTERNAL_API_KEYS=uqXssnB2q8rs2soa9almm1jkL6vN0xOh0
|
||||||
|
DMENU_BACKEND_URL=https://dmenu-api.danakcorp.com
|
||||||
|
DMENU_USERNAME=danak@dsc.com
|
||||||
|
DMENU_PASSWORD=DsCdAnAk?@ABC
|
||||||
|
DKALA_BACKEND_URL=https://dkala-api.danakcorp.com
|
||||||
|
DKALA_USERNAME=danak@dsc.com
|
||||||
|
DKALA_PASSWORD=DsCdAnAk?@ABC
|
||||||
|
DPAGE_BACKEND_URL=https://dpage-api.danakcorp.com
|
||||||
|
DPAGE_USERNAME=danak@dsc.com
|
||||||
|
DPAGE_PASSWORD=DsCdAnAk?@ABC
|
||||||
|
DMAIL_BACKEND_URL=https://dmail-api.danakcorp.com
|
||||||
|
DMAIL_USERNAME=danak@dsc.com
|
||||||
|
DMAIL_PASSWORD=DsCdAnAk?@ABC
|
||||||
+11
-7
@@ -2,10 +2,14 @@
|
|||||||
FROM node:22-alpine AS base
|
FROM node:22-alpine AS base
|
||||||
|
|
||||||
ENV TZ=Asia/Tehran
|
ENV TZ=Asia/Tehran
|
||||||
|
# Use the public npm registry to avoid paid/unstable mirror outages.
|
||||||
|
ENV NPM_CONFIG_REGISTRY=https://package-mirror.liara.ir/repository/npm
|
||||||
|
|
||||||
# Runflare build hosts cannot reach registry.npmjs.org; use their npm mirror.
|
# Change Alpine repo
|
||||||
# RUN npm install -g pnpm@9.15.9 --registry=https://mirror-npm.runflare.com
|
RUN sed -i 's|https://dl-cdn.alpinelinux.org/alpine|https://mirror.de.velop.ir/alpine|g' /etc/apk/repositories
|
||||||
RUN npm install -g pnpm@9.15.9
|
|
||||||
|
# Install pnpm globally (uses NPM_CONFIG_REGISTRY mirror above).
|
||||||
|
RUN npm install -g pnpm@9.15.9 --registry=https://package-mirror.liara.ir/repository/npm
|
||||||
|
|
||||||
# Stage 2: Install all dependencies (including dev)
|
# Stage 2: Install all dependencies (including dev)
|
||||||
FROM base AS deps
|
FROM base AS deps
|
||||||
@@ -15,9 +19,9 @@ COPY package.json pnpm-lock.yaml ./
|
|||||||
# @nestjs/cli and typescript are required for the build step.
|
# @nestjs/cli and typescript are required for the build step.
|
||||||
ENV NODE_ENV=development
|
ENV NODE_ENV=development
|
||||||
# RUN pnpm install --frozen-lockfile --loglevel info \
|
# RUN pnpm install --frozen-lockfile --loglevel info \
|
||||||
# --registry=https://mirror-npm.runflare.com
|
# --registry=https://package-mirror.liara.ir/repository/npm
|
||||||
|
|
||||||
RUN pnpm install --frozen-lockfile --loglevel info
|
RUN pnpm install --frozen-lockfile --loglevel info --registry=https://package-mirror.liara.ir/repository/npm
|
||||||
|
|
||||||
|
|
||||||
# Stage 3: Build
|
# Stage 3: Build
|
||||||
@@ -32,8 +36,8 @@ FROM base AS prod-deps
|
|||||||
WORKDIR /temp-deps
|
WORKDIR /temp-deps
|
||||||
COPY package.json pnpm-lock.yaml ./
|
COPY package.json pnpm-lock.yaml ./
|
||||||
# RUN pnpm install --prod --frozen-lockfile --loglevel info \
|
# RUN pnpm install --prod --frozen-lockfile --loglevel info \
|
||||||
# --registry=https://mirror-npm.runflare.com
|
# --registry=https://package-mirror.liara.ir/repository/npm
|
||||||
RUN pnpm install --prod --frozen-lockfile --loglevel info
|
RUN pnpm install --prod --frozen-lockfile --loglevel info --registry=https://package-mirror.liara.ir/repository/npm
|
||||||
|
|
||||||
|
|
||||||
# Stage 5: Runner
|
# Stage 5: Runner
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class Taskmanager1783150480192 implements MigrationInterface {
|
||||||
|
name = 'Taskmanager1783150480192'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_workspaces" DROP CONSTRAINT "FK_253e36f065cfc1eca58abaefb22"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_workspaces" DROP COLUMN "workspaceTypeId"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_workspaces" ADD "workspaceTypeId" uuid NOT NULL`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_workspaces" ADD CONSTRAINT "FK_253e36f065cfc1eca58abaefb22" FOREIGN KEY ("workspaceTypeId") REFERENCES "tm_workspace_types"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class Taskmanager31783244669371 implements MigrationInterface {
|
||||||
|
name = 'Taskmanager31783244669371'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_workspaces" ADD CONSTRAINT "UQ_6496168de3e6c5f006d494ebac5" UNIQUE ("name")`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_workspaces" DROP CONSTRAINT "UQ_6496168de3e6c5f006d494ebac5"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class TaskmanagerAddingNewEnumValueForPermissionEnumType1783324039378 implements MigrationInterface {
|
||||||
|
name = 'TaskmanagerAddingNewEnumValueForPermissionEnumType1783324039378'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum" RENAME TO "permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace', 'project')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"text"::"public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum_old"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum_old" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum_old" USING "name"::"text"::"public"."permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum_old" RENAME TO "permission_name_enum"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class TMAddingTaskPhasePermissionToPermissionEnumType1783335279945 implements MigrationInterface {
|
||||||
|
name = 'TMAddingTaskPhasePermissionToPermissionEnumType1783335279945'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum" RENAME TO "permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace', 'project', 'task_phase')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"text"::"public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum_old"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum_old" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace', 'project')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum_old" USING "name"::"text"::"public"."permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum_old" RENAME TO "permission_name_enum"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class TMaddingSomeNewPermissionsToTheEnum1783428145772 implements MigrationInterface {
|
||||||
|
name = 'TMaddingSomeNewPermissionsToTheEnum1783428145772'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum" RENAME TO "permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace', 'view_all_workspaces', 'project', 'view_all_projects', 'task', 'task_phase', 'remark')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"text"::"public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum_old"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum_old" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace', 'project', 'task_phase')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum_old" USING "name"::"text"::"public"."permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum_old" RENAME TO "permission_name_enum"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class TMChangingFewLastPermissions1783759715100 implements MigrationInterface {
|
||||||
|
name = 'TMChangingFewLastPermissions1783759715100'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum" RENAME TO "permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM('services', 'customers', 'agents', 'developers', 'invoices', 'transactions', 'discounts', 'admins', 'tickets', 'criticisms', 'contacts_us', 'advertisements', 'announcements', 'blogs', 'learnings', 'logs', 'settings', 'bank_accounts', 'payments', 'manage_sso_clients', 'support_plan', 'dmenu', 'dkala', 'dpage', 'dmail', 'reseller', 'workspace', 'view_all_workspaces', 'project', 'view_all_projects', 'task', 'task_phase')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"text"::"public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum_old"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum_old" AS ENUM('admins', 'advertisements', 'agents', 'announcements', 'bank_accounts', 'blogs', 'contacts_us', 'criticisms', 'customers', 'developers', 'discounts', 'dkala', 'dmail', 'dmenu', 'dpage', 'invoices', 'learnings', 'logs', 'manage_sso_clients', 'payments', 'project', 'remark', 'reseller', 'services', 'settings', 'support_plan', 'task', 'task_phase', 'tickets', 'transactions', 'view_all_projects', 'view_all_workspaces', 'workspace')`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum_old" USING "name"::"text"::"public"."permission_name_enum_old"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
|
||||||
|
await queryRunner.query(`ALTER TYPE "public"."permission_name_enum_old" RENAME TO "permission_name_enum"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class AddedPriorityToTaskEntity1784014433653 implements MigrationInterface {
|
||||||
|
name = 'AddedPriorityToTaskEntity1784014433653'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_tasks" ADD "priority" integer NOT NULL DEFAULT '1'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_tasks" DROP COLUMN "priority"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class AddTaskTimeTable1784100000000 implements MigrationInterface {
|
||||||
|
name = "AddTaskTimeTable1784100000000";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`
|
||||||
|
CREATE TABLE "tm_times" (
|
||||||
|
"id" uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
|
"createdAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
||||||
|
"updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(),
|
||||||
|
"startedAt" TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
|
"endedAt" TIMESTAMP WITH TIME ZONE NOT NULL,
|
||||||
|
"duration" integer NOT NULL,
|
||||||
|
"adminId" uuid NOT NULL,
|
||||||
|
"taskId" uuid NOT NULL,
|
||||||
|
CONSTRAINT "PK_tm_times" PRIMARY KEY ("id")
|
||||||
|
)
|
||||||
|
`);
|
||||||
|
await queryRunner.query(`
|
||||||
|
ALTER TABLE "tm_times"
|
||||||
|
ADD CONSTRAINT "FK_tm_times_admin"
|
||||||
|
FOREIGN KEY ("adminId") REFERENCES "user"("id")
|
||||||
|
ON DELETE RESTRICT ON UPDATE NO ACTION
|
||||||
|
`);
|
||||||
|
await queryRunner.query(`
|
||||||
|
ALTER TABLE "tm_times"
|
||||||
|
ADD CONSTRAINT "FK_tm_times_task"
|
||||||
|
FOREIGN KEY ("taskId") REFERENCES "tm_tasks"("id")
|
||||||
|
ON DELETE CASCADE ON UPDATE NO ACTION
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_times" DROP CONSTRAINT "FK_tm_times_task"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "tm_times" DROP CONSTRAINT "FK_tm_times_admin"`);
|
||||||
|
await queryRunner.query(`DROP TABLE "tm_times"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class MakeTaskTimeEndedAtAndDurationNullable1784200000000
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = "MakeTaskTimeEndedAtAndDurationNullable1784200000000";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "tm_times" ALTER COLUMN "endedAt" DROP NOT NULL`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "tm_times" ALTER COLUMN "duration" DROP NOT NULL`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "tm_times" ALTER COLUMN "endedAt" SET NOT NULL`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "tm_times" ALTER COLUMN "duration" SET NOT NULL`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
export class AddTitleToPermission1784465631499 implements MigrationInterface {
|
||||||
|
name = "AddTitleToPermission1784465631499";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ADD "title" character varying(150)`);
|
||||||
|
await queryRunner.query(`UPDATE "permission" SET "title" = "name"::text WHERE "title" IS NULL`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "title" SET NOT NULL`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" DROP COLUMN "title"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,300 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
type CrudResource = {
|
||||||
|
old: string;
|
||||||
|
group: string;
|
||||||
|
titles: { create: string; read: string; update: string; delete: string };
|
||||||
|
};
|
||||||
|
|
||||||
|
const CRUD_RESOURCES: CrudResource[] = [
|
||||||
|
{
|
||||||
|
old: "services",
|
||||||
|
group: "services",
|
||||||
|
titles: { create: "ایجاد سرویسها", read: "مشاهده سرویسها", update: "ویرایش سرویسها", delete: "حذف سرویسها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "customers",
|
||||||
|
group: "customers",
|
||||||
|
titles: { create: "ایجاد مشتریان", read: "مشاهده مشتریان", update: "ویرایش مشتریان", delete: "حذف مشتریان" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "agents",
|
||||||
|
group: "representatives",
|
||||||
|
titles: { create: "ایجاد نمایندگان", read: "مشاهده نمایندگان", update: "ویرایش نمایندگان", delete: "حذف نمایندگان" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "developers",
|
||||||
|
group: "users",
|
||||||
|
titles: {
|
||||||
|
create: "ایجاد توسعهدهندگان",
|
||||||
|
read: "مشاهده توسعهدهندگان",
|
||||||
|
update: "ویرایش توسعهدهندگان",
|
||||||
|
delete: "حذف توسعهدهندگان",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "invoices",
|
||||||
|
group: "financial",
|
||||||
|
titles: { create: "ایجاد صورتحسابها", read: "مشاهده صورتحسابها", update: "ویرایش صورتحسابها", delete: "حذف صورتحسابها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "transactions",
|
||||||
|
group: "financial",
|
||||||
|
titles: { create: "ایجاد تراکنشها", read: "مشاهده تراکنشها", update: "ویرایش تراکنشها", delete: "حذف تراکنشها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "discounts",
|
||||||
|
group: "financial",
|
||||||
|
titles: { create: "ایجاد تخفیفها", read: "مشاهده تخفیفها", update: "ویرایش تخفیفها", delete: "حذف تخفیفها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "admins",
|
||||||
|
group: "users",
|
||||||
|
titles: { create: "ایجاد ادمینها", read: "مشاهده ادمینها", update: "ویرایش ادمینها", delete: "حذف ادمینها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "tickets",
|
||||||
|
group: "support",
|
||||||
|
titles: { create: "ایجاد تیکتها", read: "مشاهده تیکتها", update: "ویرایش تیکتها", delete: "حذف تیکتها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "criticisms",
|
||||||
|
group: "other",
|
||||||
|
titles: { create: "ایجاد انتقادات", read: "مشاهده انتقادات", update: "ویرایش انتقادات", delete: "حذف انتقادات" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "contacts_us",
|
||||||
|
group: "other",
|
||||||
|
titles: { create: "ایجاد تماس با ما", read: "مشاهده تماس با ما", update: "ویرایش تماس با ما", delete: "حذف تماس با ما" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "advertisements",
|
||||||
|
group: "content",
|
||||||
|
titles: { create: "ایجاد تبلیغات", read: "مشاهده تبلیغات", update: "ویرایش تبلیغات", delete: "حذف تبلیغات" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "announcements",
|
||||||
|
group: "content",
|
||||||
|
titles: { create: "ایجاد اطلاعیهها", read: "مشاهده اطلاعیهها", update: "ویرایش اطلاعیهها", delete: "حذف اطلاعیهها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "blogs",
|
||||||
|
group: "content",
|
||||||
|
titles: { create: "ایجاد بلاگها", read: "مشاهده بلاگها", update: "ویرایش بلاگها", delete: "حذف بلاگها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "learnings",
|
||||||
|
group: "content",
|
||||||
|
titles: { create: "ایجاد آموزشها", read: "مشاهده آموزشها", update: "ویرایش آموزشها", delete: "حذف آموزشها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "settings",
|
||||||
|
group: "other",
|
||||||
|
titles: { create: "ایجاد تنظیمات", read: "مشاهده تنظیمات", update: "ویرایش تنظیمات", delete: "حذف تنظیمات" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "bank_accounts",
|
||||||
|
group: "financial",
|
||||||
|
titles: {
|
||||||
|
create: "ایجاد حسابهای بانکی",
|
||||||
|
read: "مشاهده حسابهای بانکی",
|
||||||
|
update: "ویرایش حسابهای بانکی",
|
||||||
|
delete: "حذف حسابهای بانکی",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "payments",
|
||||||
|
group: "financial",
|
||||||
|
titles: { create: "ایجاد پرداختها", read: "مشاهده پرداختها", update: "ویرایش پرداختها", delete: "حذف پرداختها" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "support_plan",
|
||||||
|
group: "support",
|
||||||
|
titles: {
|
||||||
|
create: "ایجاد پلن پشتیبانی",
|
||||||
|
read: "مشاهده پلن پشتیبانی",
|
||||||
|
update: "ویرایش پلن پشتیبانی",
|
||||||
|
delete: "حذف پلن پشتیبانی",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "reseller",
|
||||||
|
group: "representatives",
|
||||||
|
titles: {
|
||||||
|
create: "ایجاد نمایندگی فروش",
|
||||||
|
read: "مشاهده نمایندگی فروش",
|
||||||
|
update: "ویرایش نمایندگی فروش",
|
||||||
|
delete: "حذف نمایندگی فروش",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "workspace",
|
||||||
|
group: "task_manager",
|
||||||
|
titles: { create: "ایجاد فضای کار", read: "مشاهده فضای کار", update: "ویرایش فضای کار", delete: "حذف فضای کار" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "project",
|
||||||
|
group: "task_manager",
|
||||||
|
titles: { create: "ایجاد پروژه", read: "مشاهده پروژه", update: "ویرایش پروژه", delete: "حذف پروژه" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "task",
|
||||||
|
group: "task_manager",
|
||||||
|
titles: { create: "ایجاد وظیفه", read: "مشاهده وظیفه", update: "ویرایش وظیفه", delete: "حذف وظیفه" },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
old: "task_phase",
|
||||||
|
group: "task_manager",
|
||||||
|
titles: { create: "ایجاد فاز وظیفه", read: "مشاهده فاز وظیفه", update: "ویرایش فاز وظیفه", delete: "حذف فاز وظیفه" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const SINGLE_PERMISSIONS: { name: string; group: string; title: string }[] = [
|
||||||
|
{ name: "logs", group: "other", title: "لاگها" },
|
||||||
|
{ name: "manage_sso_clients", group: "other", title: "مدیریت کلاینتهای SSO" },
|
||||||
|
{ name: "dmenu", group: "products", title: "دیمنو" },
|
||||||
|
{ name: "dkala", group: "products", title: "دیکالا" },
|
||||||
|
{ name: "dpage", group: "products", title: "دیپیج" },
|
||||||
|
{ name: "dmail", group: "products", title: "دیمیل" },
|
||||||
|
{ name: "view_all_workspaces", group: "task_manager", title: "مشاهده همه فضاهای کار" },
|
||||||
|
{ name: "view_all_projects", group: "task_manager", title: "مشاهده همه پروژهها" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const NEW_ENUM_VALUES = [
|
||||||
|
...CRUD_RESOURCES.flatMap((r) => [`${r.old}_create`, `${r.old}_read`, `${r.old}_update`, `${r.old}_delete`]),
|
||||||
|
...SINGLE_PERMISSIONS.map((p) => p.name),
|
||||||
|
];
|
||||||
|
|
||||||
|
const OLD_ENUM_VALUES = [
|
||||||
|
"services",
|
||||||
|
"customers",
|
||||||
|
"agents",
|
||||||
|
"developers",
|
||||||
|
"invoices",
|
||||||
|
"transactions",
|
||||||
|
"discounts",
|
||||||
|
"admins",
|
||||||
|
"tickets",
|
||||||
|
"criticisms",
|
||||||
|
"contacts_us",
|
||||||
|
"advertisements",
|
||||||
|
"announcements",
|
||||||
|
"blogs",
|
||||||
|
"learnings",
|
||||||
|
"logs",
|
||||||
|
"settings",
|
||||||
|
"bank_accounts",
|
||||||
|
"payments",
|
||||||
|
"manage_sso_clients",
|
||||||
|
"support_plan",
|
||||||
|
"dmenu",
|
||||||
|
"dkala",
|
||||||
|
"dpage",
|
||||||
|
"dmail",
|
||||||
|
"reseller",
|
||||||
|
"workspace",
|
||||||
|
"view_all_workspaces",
|
||||||
|
"project",
|
||||||
|
"view_all_projects",
|
||||||
|
"task",
|
||||||
|
"task_phase",
|
||||||
|
];
|
||||||
|
|
||||||
|
export class RefactorPermissionsToCrudAndGroup1784500000000 implements MigrationInterface {
|
||||||
|
name = "RefactorPermissionsToCrudAndGroup1784500000000";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`CREATE TYPE "public"."permission_group_enum" AS ENUM('services', 'customers', 'users', 'financial', 'content', 'support', 'other', 'products', 'representatives', 'task_manager')`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ADD "group" "public"."permission_group_enum"`);
|
||||||
|
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "name" TYPE text USING "name"::text`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_name_enum"`);
|
||||||
|
|
||||||
|
for (const resource of CRUD_RESOURCES) {
|
||||||
|
const oldPerm = await queryRunner.query(`SELECT id FROM "permission" WHERE "name" = $1`, [resource.old]);
|
||||||
|
if (!oldPerm.length) continue;
|
||||||
|
|
||||||
|
const oldId = oldPerm[0].id as string;
|
||||||
|
const actions = ["create", "read", "update", "delete"] as const;
|
||||||
|
|
||||||
|
for (const action of actions) {
|
||||||
|
const newName = `${resource.old}_${action}`;
|
||||||
|
const title = resource.titles[action];
|
||||||
|
const inserted = await queryRunner.query(
|
||||||
|
`INSERT INTO "permission" ("id", "name", "title", "group", "createdAt", "updatedAt")
|
||||||
|
VALUES (uuid_generate_v4(), $1, $2, $3, NOW(), NOW())
|
||||||
|
RETURNING id`,
|
||||||
|
[newName, title, resource.group],
|
||||||
|
);
|
||||||
|
const newId = inserted[0].id as string;
|
||||||
|
|
||||||
|
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, oldId],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.query(`DELETE FROM "role_permission_relation" WHERE "permissionId" = $1`, [oldId]);
|
||||||
|
await queryRunner.query(`DELETE FROM "permission" WHERE "id" = $1`, [oldId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const perm of SINGLE_PERMISSIONS) {
|
||||||
|
await queryRunner.query(`UPDATE "permission" SET "group" = $1, "title" = COALESCE(NULLIF("title", ''), $2) WHERE "name" = $3`, [
|
||||||
|
perm.group,
|
||||||
|
perm.title,
|
||||||
|
perm.name,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" ALTER COLUMN "group" SET NOT NULL`);
|
||||||
|
|
||||||
|
const enumList = NEW_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"`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(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"`);
|
||||||
|
|
||||||
|
for (const resource of CRUD_RESOURCES) {
|
||||||
|
// const actions = ["create", "read", "update", "delete"];
|
||||||
|
const crudRows = await queryRunner.query(`SELECT id, name FROM "permission" WHERE "name" LIKE $1`, [`${resource.old}_%`]);
|
||||||
|
if (!crudRows.length) continue;
|
||||||
|
|
||||||
|
const inserted = await queryRunner.query(
|
||||||
|
`INSERT INTO "permission" ("id", "name", "title", "group", "createdAt", "updatedAt")
|
||||||
|
VALUES (uuid_generate_v4(), $1, $2, $3, NOW(), NOW())
|
||||||
|
RETURNING id`,
|
||||||
|
[resource.old, resource.old, resource.group],
|
||||||
|
);
|
||||||
|
const oldId = inserted[0].id as string;
|
||||||
|
|
||||||
|
for (const row of crudRows) {
|
||||||
|
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`,
|
||||||
|
[oldId, row.id],
|
||||||
|
);
|
||||||
|
await queryRunner.query(`DELETE FROM "role_permission_relation" WHERE "permissionId" = $1`, [row.id]);
|
||||||
|
await queryRunner.query(`DELETE FROM "permission" WHERE "id" = $1`, [row.id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldEnumList = OLD_ENUM_VALUES.map((v) => `'${v}'`).join(", ");
|
||||||
|
await queryRunner.query(`CREATE TYPE "public"."permission_name_enum" AS ENUM(${oldEnumList})`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "permission" ALTER COLUMN "name" TYPE "public"."permission_name_enum" USING "name"::"public"."permission_name_enum"`,
|
||||||
|
);
|
||||||
|
|
||||||
|
await queryRunner.query(`ALTER TABLE "permission" DROP COLUMN "group"`);
|
||||||
|
await queryRunner.query(`DROP TYPE "public"."permission_group_enum"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,9 +5,9 @@ import { connectionSource } from "./connection";
|
|||||||
// import { seedCityAndProvince } from "./seeders/iran-city.seeder";
|
// import { seedCityAndProvince } from "./seeders/iran-city.seeder";
|
||||||
// import { seedNotifSettings } from "./seeders/notif-setting.seeder";
|
// import { seedNotifSettings } from "./seeders/notif-setting.seeder";
|
||||||
// import { seedPaymentGateways } from "./seeders/payment-gateway.seeder";
|
// import { seedPaymentGateways } from "./seeders/payment-gateway.seeder";
|
||||||
// import { seedPermissionsAndRoles } from "./seeders/role.seeder";
|
import { seedPermissionsAndRoles } from "./seeders/role.seeder";
|
||||||
import { seedBlogCommentReplies } from "./seeders/blog-comment-reply.seeder";
|
// import { seedBlogCommentReplies } from "./seeders/blog-comment-reply.seeder";
|
||||||
import { seedBlogComments } from "./seeders/blog-comment.seeder";
|
// import { seedBlogComments } from "./seeders/blog-comment.seeder";
|
||||||
|
|
||||||
const logger = new Logger("Seeder");
|
const logger = new Logger("Seeder");
|
||||||
|
|
||||||
@@ -15,14 +15,14 @@ export const runSeeder = async () => {
|
|||||||
await connectionSource.initialize();
|
await connectionSource.initialize();
|
||||||
logger.log("start seeding database");
|
logger.log("start seeding database");
|
||||||
//
|
//
|
||||||
// await seedPermissionsAndRoles(connectionSource, logger);
|
await seedPermissionsAndRoles(connectionSource, logger);
|
||||||
// await seedAdmin(connectionSource, logger);
|
// await seedAdmin(connectionSource, logger);
|
||||||
// await seedNotifSettings(connectionSource, logger);
|
// await seedNotifSettings(connectionSource, logger);
|
||||||
// await seedPaymentGateways(connectionSource, logger);
|
// await seedPaymentGateways(connectionSource, logger);
|
||||||
// await seedCityAndProvince(connectionSource, logger);
|
// await seedCityAndProvince(connectionSource, logger);
|
||||||
|
|
||||||
await seedBlogComments(connectionSource, logger);
|
// await seedBlogComments(connectionSource, logger);
|
||||||
await seedBlogCommentReplies(connectionSource, logger);
|
// await seedBlogCommentReplies(connectionSource, logger);
|
||||||
|
|
||||||
logger.log("seeding completed");
|
logger.log("seeding completed");
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
|
|||||||
@@ -1,13 +1,51 @@
|
|||||||
import { Logger } from "@nestjs/common";
|
import { Logger } from "@nestjs/common";
|
||||||
import { DataSource } from "typeorm";
|
import { DataSource } from "typeorm";
|
||||||
|
|
||||||
import { Permission } from "../../src/modules/users/entities/permission.entity";
|
// import { Permission } from "../../src/modules/users/entities/permission.entity";
|
||||||
import { Role } from "../../src/modules/users/entities/role.entity";
|
// import { Role } from "../../src/modules/users/entities/role.entity";
|
||||||
import { PermissionEnum } from "../../src/modules/users/enums/permission.enum";
|
import { PermissionEnum } from "../../src/modules/users/enums/permission.enum";
|
||||||
import { RoleEnum } from "../../src/modules/users/enums/role.enum";
|
import { RoleEnum } from "../../src/modules/users/enums/role.enum";
|
||||||
|
|
||||||
|
const permissionTitles: Record<PermissionEnum, string> = {
|
||||||
|
[PermissionEnum.SERVICES]: "سرویسها",
|
||||||
|
[PermissionEnum.CUSTOMERS]: "مشتریان",
|
||||||
|
[PermissionEnum.AGENTS]: "نمایندگان",
|
||||||
|
[PermissionEnum.DEVELOPERS]: "توسعهدهندگان",
|
||||||
|
[PermissionEnum.INVOICES]: "صورتحسابها",
|
||||||
|
[PermissionEnum.TRANSACTIONS]: "تراکنشها",
|
||||||
|
[PermissionEnum.DISCOUNTS]: "تخفیفها",
|
||||||
|
[PermissionEnum.ADMINS]: "ادمینها",
|
||||||
|
[PermissionEnum.TICKETS]: "تیکتها",
|
||||||
|
[PermissionEnum.CRITICISMS]: "انتقادات",
|
||||||
|
[PermissionEnum.CONTACTS_US]: "تماس با ما",
|
||||||
|
[PermissionEnum.ADVERTISEMENTS]: "تبلیغات",
|
||||||
|
[PermissionEnum.ANNOUNCEMENTS]: "اطلاعیهها",
|
||||||
|
[PermissionEnum.BLOGS]: "بلاگها",
|
||||||
|
[PermissionEnum.LEARNINGS]: "آموزشها",
|
||||||
|
[PermissionEnum.LOGS]: "لاگها",
|
||||||
|
[PermissionEnum.SETTINGS]: "تنظیمات",
|
||||||
|
[PermissionEnum.BANK_ACCOUNTS]: "حسابهای بانکی",
|
||||||
|
[PermissionEnum.PAYMENTS]: "پرداختها",
|
||||||
|
[PermissionEnum.MANAGE_SSO_CLIENTS]: "مدیریت کلاینتهای SSO",
|
||||||
|
[PermissionEnum.SUPPORT_PLAN]: "پلن پشتیبانی",
|
||||||
|
[PermissionEnum.DMENU]: "دیمنو",
|
||||||
|
[PermissionEnum.DKALA]: "دیکالا",
|
||||||
|
[PermissionEnum.DPAGE]: "دیپیج",
|
||||||
|
[PermissionEnum.DMAIL]: "دیمیل",
|
||||||
|
[PermissionEnum.RESELLER]: "نمایندگی فروش",
|
||||||
|
[PermissionEnum.WORKSPACE]: "فضای کار",
|
||||||
|
[PermissionEnum.VIEW_ALL_WORKSPACES]: "مشاهده همه فضاهای کار",
|
||||||
|
[PermissionEnum.PROJECT]: "پروژه",
|
||||||
|
[PermissionEnum.VIEW_ALL_PROJECTS]: "مشاهده همه پروژهها",
|
||||||
|
[PermissionEnum.TASK]: "وظیفه",
|
||||||
|
[PermissionEnum.TASK_PHASE]: "فاز وظیفه",
|
||||||
|
};
|
||||||
|
|
||||||
// Define permissions
|
// Define permissions
|
||||||
const permissions = Object.values(PermissionEnum).map((perm) => ({ name: perm }));
|
const permissions = Object.values(PermissionEnum).map((perm) => ({
|
||||||
|
name: perm,
|
||||||
|
title: permissionTitles[perm],
|
||||||
|
}));
|
||||||
|
|
||||||
// Define roles with their default permissions
|
// Define roles with their default permissions
|
||||||
const rolesWithPermissions: { name: RoleEnum; permissions: PermissionEnum[] }[] = [
|
const rolesWithPermissions: { name: RoleEnum; permissions: PermissionEnum[] }[] = [
|
||||||
@@ -23,8 +61,8 @@ const rolesWithPermissions: { name: RoleEnum; permissions: PermissionEnum[] }[]
|
|||||||
|
|
||||||
export const seedPermissionsAndRoles = async (dataSource: DataSource, logger: Logger) => {
|
export const seedPermissionsAndRoles = async (dataSource: DataSource, logger: Logger) => {
|
||||||
try {
|
try {
|
||||||
const permissionRepo = dataSource.getRepository(Permission);
|
const permissionRepo = dataSource.getRepository("Permission");
|
||||||
const roleRepo = dataSource.getRepository(Role);
|
const roleRepo = dataSource.getRepository("Role");
|
||||||
|
|
||||||
// Seed Permissions
|
// Seed Permissions
|
||||||
logger.log("Seeding Permissions...");
|
logger.log("Seeding Permissions...");
|
||||||
@@ -33,6 +71,9 @@ export const seedPermissionsAndRoles = async (dataSource: DataSource, logger: Lo
|
|||||||
if (!existingPerm) {
|
if (!existingPerm) {
|
||||||
const newPerm = permissionRepo.create(perm);
|
const newPerm = permissionRepo.create(perm);
|
||||||
await permissionRepo.save(newPerm);
|
await permissionRepo.save(newPerm);
|
||||||
|
} else if (!existingPerm.title || existingPerm.title !== perm.title) {
|
||||||
|
existingPerm.title = perm.title;
|
||||||
|
await permissionRepo.save(existingPerm);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.log("Permissions seeded successfully");
|
logger.log("Permissions seeded successfully");
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
|
import { Type } from "class-transformer";
|
||||||
|
import { IsEnum, IsInt, IsOptional, IsString, Max, Min } from "class-validator";
|
||||||
|
|
||||||
|
export enum CursorDirection {
|
||||||
|
NEXT = "next",
|
||||||
|
PREV = "prev",
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CursorPaginationDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@ApiPropertyOptional({
|
||||||
|
type: "string",
|
||||||
|
description:
|
||||||
|
"Base64‑encoded cursor containing the priority, createdAt (ISO) and id of the last seen item. Leave empty for the first page.",
|
||||||
|
example: "MjAyNi0wNy0wMVQxMDowMDowMC4wMDBafDU=",
|
||||||
|
})
|
||||||
|
cursor?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(1)
|
||||||
|
@Max(50)
|
||||||
|
@Type(() => Number)
|
||||||
|
@ApiPropertyOptional({ type: "number", required: false, default: 10 })
|
||||||
|
limit?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsEnum(CursorDirection)
|
||||||
|
@ApiPropertyOptional({ enum: CursorDirection, default: CursorDirection.NEXT, description: "Direction to page in relative to 'cursor'." })
|
||||||
|
direction?: CursorDirection;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { applyDecorators } from "@nestjs/common";
|
||||||
|
import { ApiQuery } from "@nestjs/swagger";
|
||||||
|
import { CursorDirection } from "../DTO/cursor-pagination.dto";
|
||||||
|
|
||||||
|
export function CursorPagination() {
|
||||||
|
return applyDecorators(
|
||||||
|
ApiQuery({
|
||||||
|
name: "cursor",
|
||||||
|
required: false,
|
||||||
|
type: "string",
|
||||||
|
description: "Base64‑encoded cursor of the last item (contains priority, createdAt and id). Leave empty for the first page.",
|
||||||
|
example: "MjAyNi0wNy0wMVQxMDowMDowMC4wMDBafDU=",
|
||||||
|
}),
|
||||||
|
ApiQuery({
|
||||||
|
name: "limit",
|
||||||
|
required: false,
|
||||||
|
type: "number",
|
||||||
|
description: "Number of items per page (max 50)",
|
||||||
|
example: 10,
|
||||||
|
}),
|
||||||
|
ApiQuery({
|
||||||
|
name: "direction",
|
||||||
|
required: false,
|
||||||
|
enum: CursorDirection,
|
||||||
|
description: "Direction to page in relative to 'cursor': 'next' (default) or 'prev'.",
|
||||||
|
example: CursorDirection.NEXT,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -915,3 +915,51 @@ export const enum UploaderMessage {
|
|||||||
export const enum AccessLogMessage {
|
export const enum AccessLogMessage {
|
||||||
ACCESS_LOG_NOT_FOUND = "لاگ دسترسی مورد نظر یافت نشد",
|
ACCESS_LOG_NOT_FOUND = "لاگ دسترسی مورد نظر یافت نشد",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const enum WorkSpaceMessage {
|
||||||
|
WORKSPACE_EXISTS = "فضای کار با این اسم وجود دارد!",
|
||||||
|
WORKSPACE_NOT_FOUND = "فضای کار مورد نظر شما وجود ندارد!",
|
||||||
|
USERS_DONT_BELONG_TO_THIS_WORKSPACE = "کاربران تعیین شده برای این فضای کاری نیستند!",
|
||||||
|
WORKSPACE_SAME_NAME_EXISTS = "فضای کاری با این اسم از قبل وجود دارد!",
|
||||||
|
WORKSPACE_ID_PARAM_NOT_EMPTY = "پارامتر شناسه فضای کار نباید خالی باشد!",
|
||||||
|
WORKSPACE_ID_UUID = "شناسه فضای کار باید uuid باشد",
|
||||||
|
FORBIDDEN = "شما اجازه دسترسی به این فضای کار را ندارید و یا عضو آن نیستید!"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum ProjectMessage {
|
||||||
|
PROJECT_EXISTS = "پروژه مورد نظر شما از قبل وجود دارد!",
|
||||||
|
PROJECT_NOT_FOUND = "پروژه مورد نظر شما وجود ندارد!",
|
||||||
|
PROJECT_CONTAINS_TASK_PHASES = "پروژه شامل فاز تسک است. لطفا ابتدا فاز تسک های این پروژه را حذف کنید.",
|
||||||
|
NOT_MEMBER_OF_PROJECT = "شما عضو این پروژه نیستید!",
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum TaskPhaseMessage {
|
||||||
|
TASK_PHASE_NOT_FOUND = "فاز تسک مورد نظر پیدا نشد!",
|
||||||
|
TASK_PHASE_NOT_SAME_PROJECT = "فاز تسک جدید با فاز تسک قبلی در یک پروژه نیستند!"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum TaskMessage {
|
||||||
|
TASK_NOT_FOUND = "تسک مورد نظر پیدا نشد!",
|
||||||
|
USERS_ASSIGNED_TO_TASK_NOT_PROJECT_MEMBER = "حداقل یکی از کاربران تعیین شده عضو پروژه نیستند!",
|
||||||
|
USER_NOT_TASK_MEMBER = "شما عضو این تسک نیستید!",
|
||||||
|
TASKS_NOT_IN_THE_SAME_TASK_PHASE = "تسک های مورد نظر داخل یک فاز تسک یکسان نیستند!"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum remarkMessage {
|
||||||
|
REMARK_NOT_FOUND = "برچسب مورد نظر پیدا نشد!"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum checkListItemMessage {
|
||||||
|
CHECKLISTITEM_NOT_FOUND = "آیتم چک لیست پیدا نشد!"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum attachmentMessage {
|
||||||
|
ATTACHMENT_NOT_FOUND = "ضمیمه پیدا نشد!"
|
||||||
|
}
|
||||||
|
|
||||||
|
export const enum timeMessage {
|
||||||
|
TIME_NOT_FOUND = "زمان ثبت شده پیدا نشد!",
|
||||||
|
INVALID_TIME_RANGE = "زمان پایان باید بعد از زمان شروع باشد!",
|
||||||
|
TIME_ALREADY_STARTED = "برای این تسک یک زمان در حال اجرا وجود دارد!",
|
||||||
|
NO_RUNNING_TIME = "زمان در حال اجرایی برای این تسک پیدا نشد!"
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
export interface ICursorPageFormat {
|
||||||
|
limit: number;
|
||||||
|
nextCursor: string | null;
|
||||||
|
previousCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ import { FastifyRequest } from "fastify";
|
|||||||
import { Observable, map } from "rxjs";
|
import { Observable, map } from "rxjs";
|
||||||
|
|
||||||
import { IPageFormat } from "../../common/interfaces/IPagination";
|
import { IPageFormat } from "../../common/interfaces/IPagination";
|
||||||
|
import { ICursorPageFormat } from "../../common/interfaces/ICursor-pagination";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PaginationInterceptor implements NestInterceptor {
|
export class PaginationInterceptor implements NestInterceptor {
|
||||||
@@ -10,7 +11,11 @@ export class PaginationInterceptor implements NestInterceptor {
|
|||||||
|
|
||||||
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {
|
||||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||||
const query = request.query as { page: string; limit: string };
|
const query = request.query as {
|
||||||
|
page: string;
|
||||||
|
limit: string;
|
||||||
|
cursor?: string; // for cursor pagination
|
||||||
|
};
|
||||||
|
|
||||||
const page = parseInt(query.page, 10) || 1;
|
const page = parseInt(query.page, 10) || 1;
|
||||||
const limit = parseInt(query.limit, 10) || 10;
|
const limit = parseInt(query.limit, 10) || 10;
|
||||||
@@ -20,17 +25,40 @@ export class PaginationInterceptor implements NestInterceptor {
|
|||||||
|
|
||||||
return next.handle().pipe(
|
return next.handle().pipe(
|
||||||
map((data) => {
|
map((data) => {
|
||||||
|
// ---------- Offset (page‑based) pagination ----------
|
||||||
if (data && (data.paginate || data.count)) {
|
if (data && (data.paginate || data.count)) {
|
||||||
const { count, paginate, ...response } = data;
|
const { count, paginate, ...response } = data;
|
||||||
this.logger.log(`paginate response from ${className}.${handlerName}`);
|
this.logger.log(`offset paginate response from ${className}.${handlerName}`);
|
||||||
const pager = this.formatPage(page, limit, count, request);
|
const pager = this.formatPage(page, limit, count, request);
|
||||||
|
return { pager, ...response };
|
||||||
return {
|
|
||||||
pager,
|
|
||||||
...response,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---------- Cursor‑based pagination ----------
|
||||||
|
if (data && data.cursorPaginate === true) {
|
||||||
|
const {
|
||||||
|
data: items,
|
||||||
|
nextCursor,
|
||||||
|
previousCursor,
|
||||||
|
hasNextPage,
|
||||||
|
hasPreviousPage,
|
||||||
|
cursorPaginate,
|
||||||
|
...rest
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
this.logger.log(`cursor paginate response from ${className}.${handlerName}`);
|
||||||
|
|
||||||
|
const pager: ICursorPageFormat = {
|
||||||
|
limit,
|
||||||
|
nextCursor,
|
||||||
|
previousCursor,
|
||||||
|
hasNextPage,
|
||||||
|
hasPreviousPage,
|
||||||
|
};
|
||||||
|
|
||||||
|
return { items, pager, ...rest };
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------- No pagination ----------
|
||||||
return data;
|
return data;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,41 +19,41 @@ export class AdsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Create new ads" })
|
@ApiOperation({ summary: "Create new ads" })
|
||||||
@Post()
|
@Post()
|
||||||
@PermissionsDec(PermissionEnum.ADVERTISEMENTS)
|
@PermissionsDec(PermissionEnum.ADVERTISEMENTS_CREATE)
|
||||||
createAds(@Body() createDto: CreateAdsDto) {
|
createAds(@Body() createDto: CreateAdsDto) {
|
||||||
return this.adsService.createAds(createDto);
|
return this.adsService.createAds(createDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Get all ads" })
|
@ApiOperation({ summary: "Get all ads" })
|
||||||
@PermissionsDec(PermissionEnum.ADVERTISEMENTS)
|
@PermissionsDec(PermissionEnum.ADVERTISEMENTS_READ)
|
||||||
@Get("list")
|
@Get("list")
|
||||||
getAdsList(@Query() queryDto: AdsSearchQueryDto) {
|
getAdsList(@Query() queryDto: AdsSearchQueryDto) {
|
||||||
return this.adsService.getAdsList(queryDto);
|
return this.adsService.getAdsList(queryDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Get ads by id" })
|
@ApiOperation({ summary: "Get ads by id" })
|
||||||
@PermissionsDec(PermissionEnum.ADVERTISEMENTS)
|
@PermissionsDec(PermissionEnum.ADVERTISEMENTS_READ)
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
getAdsById(@Param() paramDto: ParamDto) {
|
getAdsById(@Param() paramDto: ParamDto) {
|
||||||
return this.adsService.getAdsById(paramDto.id);
|
return this.adsService.getAdsById(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Update ads by id" })
|
@ApiOperation({ summary: "Update ads by id" })
|
||||||
@PermissionsDec(PermissionEnum.ADVERTISEMENTS)
|
@PermissionsDec(PermissionEnum.ADVERTISEMENTS_UPDATE)
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
updateAdsById(@Param() paramDto: ParamDto, @Body() updateDto: UpdateAdsDto) {
|
updateAdsById(@Param() paramDto: ParamDto, @Body() updateDto: UpdateAdsDto) {
|
||||||
return this.adsService.updateAdsById(paramDto.id, updateDto);
|
return this.adsService.updateAdsById(paramDto.id, updateDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Delete ads by id" })
|
@ApiOperation({ summary: "Delete ads by id" })
|
||||||
@PermissionsDec(PermissionEnum.ADVERTISEMENTS)
|
@PermissionsDec(PermissionEnum.ADVERTISEMENTS_DELETE)
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
deleteAdsById(@Param() paramDto: ParamDto) {
|
deleteAdsById(@Param() paramDto: ParamDto) {
|
||||||
return this.adsService.deleteAdsById(paramDto.id);
|
return this.adsService.deleteAdsById(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Toggle ads status" })
|
@ApiOperation({ summary: "Toggle ads status" })
|
||||||
@PermissionsDec(PermissionEnum.ADVERTISEMENTS)
|
@PermissionsDec(PermissionEnum.ADVERTISEMENTS_UPDATE)
|
||||||
@Patch("toggle-status/:id")
|
@Patch("toggle-status/:id")
|
||||||
toggleAdsStatus(@Param() paramDto: ParamDto) {
|
toggleAdsStatus(@Param() paramDto: ParamDto) {
|
||||||
return this.adsService.toggleAdsStatus(paramDto.id);
|
return this.adsService.toggleAdsStatus(paramDto.id);
|
||||||
|
|||||||
@@ -16,14 +16,14 @@ import { PermissionEnum } from "../users/enums/permission.enum";
|
|||||||
export class AnnouncementController {
|
export class AnnouncementController {
|
||||||
constructor(private readonly announcementService: AnnouncementService) {}
|
constructor(private readonly announcementService: AnnouncementService) {}
|
||||||
|
|
||||||
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS)
|
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS_CREATE)
|
||||||
@ApiProperty({ description: "Create a new announcement (admin route)" })
|
@ApiProperty({ description: "Create a new announcement (admin route)" })
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() createAnnouncementDto: CreateAnnouncementDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
create(@Body() createAnnouncementDto: CreateAnnouncementDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.announcementService.createAnnouncement(createAnnouncementDto, userIpAndHeaders);
|
return this.announcementService.createAnnouncement(createAnnouncementDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS)
|
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS_UPDATE)
|
||||||
@ApiProperty({ description: "Update an announcement (admin route)" })
|
@ApiProperty({ description: "Update an announcement (admin route)" })
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
update(
|
update(
|
||||||
@@ -34,7 +34,7 @@ export class AnnouncementController {
|
|||||||
return this.announcementService.updateAnnouncement(paramDto.id, updateAnnouncementDto, userIpAndHeaders);
|
return this.announcementService.updateAnnouncement(paramDto.id, updateAnnouncementDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS)
|
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS_DELETE)
|
||||||
@ApiProperty({ description: "Delete an announcement (admin route)" })
|
@ApiProperty({ description: "Delete an announcement (admin route)" })
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
delete(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
delete(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
@@ -42,7 +42,7 @@ export class AnnouncementController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiProperty({ description: "Get all announcements (admin route)" })
|
@ApiProperty({ description: "Get all announcements (admin route)" })
|
||||||
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS)
|
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS_READ)
|
||||||
@Get()
|
@Get()
|
||||||
getAnnouncements(@Query() queryDto: SearchAnnouncementQueryDto) {
|
getAnnouncements(@Query() queryDto: SearchAnnouncementQueryDto) {
|
||||||
return this.announcementService.getAnnouncements(queryDto);
|
return this.announcementService.getAnnouncements(queryDto);
|
||||||
@@ -61,7 +61,7 @@ export class AnnouncementController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiProperty({ description: "Get one announcements with id (admin route)" })
|
@ApiProperty({ description: "Get one announcements with id (admin route)" })
|
||||||
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS)
|
@PermissionsDec(PermissionEnum.ANNOUNCEMENTS_READ)
|
||||||
@Get(":id/admin")
|
@Get(":id/admin")
|
||||||
getAnnouncementByIdAdmin(@Param() paramDto: ParamDto) {
|
getAnnouncementByIdAdmin(@Param() paramDto: ParamDto) {
|
||||||
return this.announcementService.getAnnouncementByIdAdmin(paramDto.id);
|
return this.announcementService.getAnnouncementByIdAdmin(paramDto.id);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ export class BlogsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get all blogs (admin route)" })
|
@ApiOperation({ summary: "Get all blogs (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_READ)
|
||||||
@Get("list")
|
@Get("list")
|
||||||
getBlogList(@Query() queryDto: BlogListSearchQueryDto) {
|
getBlogList(@Query() queryDto: BlogListSearchQueryDto) {
|
||||||
return this.blogsService.getBlogList(queryDto);
|
return this.blogsService.getBlogList(queryDto);
|
||||||
@@ -85,7 +85,7 @@ export class BlogsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "toggle status of blogs (admin route)" })
|
@ApiOperation({ summary: "toggle status of blogs (admin route)" })
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post(":id/toggle-status")
|
@Post(":id/toggle-status")
|
||||||
toggleBlogStatus(@Param() paramDto: ParamDto) {
|
toggleBlogStatus(@Param() paramDto: ParamDto) {
|
||||||
@@ -103,7 +103,7 @@ export class BlogsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Toggle pinned status of a blog (admin route)" })
|
@ApiOperation({ summary: "Toggle pinned status of a blog (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
|
||||||
@Post(":id/toggle-pinned")
|
@Post(":id/toggle-pinned")
|
||||||
togglePinnedStatus(@Param() paramDto: ParamDto) {
|
togglePinnedStatus(@Param() paramDto: ParamDto) {
|
||||||
return this.blogsService.togglePinnedStatus(paramDto.id);
|
return this.blogsService.togglePinnedStatus(paramDto.id);
|
||||||
@@ -112,7 +112,7 @@ export class BlogsController {
|
|||||||
@ApiOperation({ summary: "Create a new blog (admin route)" })
|
@ApiOperation({ summary: "Create a new blog (admin route)" })
|
||||||
@Post()
|
@Post()
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
|
||||||
createBlog(@Body() createBlogDto: CreateBlogDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createBlog(@Body() createBlogDto: CreateBlogDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.blogsService.createBlog(createBlogDto, userIpAndHeaders);
|
return this.blogsService.createBlog(createBlogDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ export class BlogsController {
|
|||||||
@ApiOperation({ summary: "Update a blog (admin route)" })
|
@ApiOperation({ summary: "Update a blog (admin route)" })
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
|
||||||
updateBlog(@Param() paramDto: ParamDto, @Body() updateBlogDto: UpdateBlogDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
updateBlog(@Param() paramDto: ParamDto, @Body() updateBlogDto: UpdateBlogDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.blogsService.updateBlog(paramDto.id, updateBlogDto, userIpAndHeaders);
|
return this.blogsService.updateBlog(paramDto.id, updateBlogDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
@@ -128,7 +128,7 @@ export class BlogsController {
|
|||||||
@ApiOperation({ summary: "Delete a blog (admin route) " })
|
@ApiOperation({ summary: "Delete a blog (admin route) " })
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_DELETE)
|
||||||
deleteBlog(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
deleteBlog(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.blogsService.deleteBlog(paramDto.id, userIpAndHeaders);
|
return this.blogsService.deleteBlog(paramDto.id, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ export class BlogsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get all comments for a blog (admin route)" })
|
@ApiOperation({ summary: "Get all comments for a blog (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_READ)
|
||||||
@Get(":id/comments")
|
@Get(":id/comments")
|
||||||
getBlogCommentsForAdmin(@Param() paramDto: ParamDto) {
|
getBlogCommentsForAdmin(@Param() paramDto: ParamDto) {
|
||||||
return this.blogCommentService.getBlogCommentsForAdmin(paramDto.id);
|
return this.blogCommentService.getBlogCommentsForAdmin(paramDto.id);
|
||||||
@@ -157,7 +157,7 @@ export class BlogsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get all comments for a blog (admin route)" })
|
@ApiOperation({ summary: "Get all comments for a blog (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_READ)
|
||||||
@Get("comments")
|
@Get("comments")
|
||||||
getAllCommentForAdmin(@Query() queryDto: BlogCommentQueryDto) {
|
getAllCommentForAdmin(@Query() queryDto: BlogCommentQueryDto) {
|
||||||
return this.blogCommentService.getAllCommentForAdmin(queryDto);
|
return this.blogCommentService.getAllCommentForAdmin(queryDto);
|
||||||
@@ -165,7 +165,7 @@ export class BlogsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Update the status of a comment (admin route)" })
|
@ApiOperation({ summary: "Update the status of a comment (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
|
||||||
@Patch("comments/:id/status")
|
@Patch("comments/:id/status")
|
||||||
updateCommentStatus(@Param() paramDto: ParamDto, @Body() updateCommentStatusDto: UpdateCommentStatusDto) {
|
updateCommentStatus(@Param() paramDto: ParamDto, @Body() updateCommentStatusDto: UpdateCommentStatusDto) {
|
||||||
return this.blogCommentService.updateCommentStatus(paramDto.id, updateCommentStatusDto);
|
return this.blogCommentService.updateCommentStatus(paramDto.id, updateCommentStatusDto);
|
||||||
@@ -196,7 +196,7 @@ export class BlogsController {
|
|||||||
@ApiOperation({ summary: "Create a new category (admin route)" })
|
@ApiOperation({ summary: "Create a new category (admin route)" })
|
||||||
@Post("categories")
|
@Post("categories")
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
|
||||||
createCategory(@Body() createCategoryDto: CreateBlogCategoryDto) {
|
createCategory(@Body() createCategoryDto: CreateBlogCategoryDto) {
|
||||||
return this.blogsService.createCategory(createCategoryDto);
|
return this.blogsService.createCategory(createCategoryDto);
|
||||||
}
|
}
|
||||||
@@ -204,7 +204,7 @@ export class BlogsController {
|
|||||||
@ApiOperation({ summary: "Update a category (admin route)" })
|
@ApiOperation({ summary: "Update a category (admin route)" })
|
||||||
@Patch("categories/:id")
|
@Patch("categories/:id")
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
|
||||||
updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateBlogCategoryDto) {
|
updateCategory(@Param() paramDto: ParamDto, @Body() updateCategoryDto: UpdateBlogCategoryDto) {
|
||||||
return this.blogsService.updateCategory(paramDto.id, updateCategoryDto);
|
return this.blogsService.updateCategory(paramDto.id, updateCategoryDto);
|
||||||
}
|
}
|
||||||
@@ -212,13 +212,13 @@ export class BlogsController {
|
|||||||
@ApiOperation({ summary: "Delete a category (admin route)" })
|
@ApiOperation({ summary: "Delete a category (admin route)" })
|
||||||
@Delete("categories/:id")
|
@Delete("categories/:id")
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_DELETE)
|
||||||
deleteCategory(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
deleteCategory(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.blogsService.deleteCategory(paramDto.id, userIpAndHeaders);
|
return this.blogsService.deleteCategory(paramDto.id, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "toggle status of categories (admin route)" })
|
@ApiOperation({ summary: "toggle status of categories (admin route)" })
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("categories/toggle-status/:id")
|
@Post("categories/toggle-status/:id")
|
||||||
toggleCategoryStatus(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
toggleCategoryStatus(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export class ContactUsController {
|
|||||||
|
|
||||||
//******************** */
|
//******************** */
|
||||||
|
|
||||||
@PermissionsDec(PermissionEnum.CONTACTS_US)
|
@PermissionsDec(PermissionEnum.CONTACTS_US_READ)
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@ApiOperation({ summary: "Get all contact us (admin route)" })
|
@ApiOperation({ summary: "Get all contact us (admin route)" })
|
||||||
@Get()
|
@Get()
|
||||||
@@ -36,7 +36,7 @@ export class ContactUsController {
|
|||||||
//******************** */
|
//******************** */
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.CONTACTS_US)
|
@PermissionsDec(PermissionEnum.CONTACTS_US_READ)
|
||||||
@ApiOperation({ summary: "Get one contact us with id (admin route)" })
|
@ApiOperation({ summary: "Get one contact us with id (admin route)" })
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
getOneContactUs(@Param() paramDto: ParamDto) {
|
getOneContactUs(@Param() paramDto: ParamDto) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class CriticismController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.CRITICISMS)
|
@PermissionsDec(PermissionEnum.CRITICISMS_READ)
|
||||||
@ApiOperation({ summary: "Get all Criticism ===> login as admin" })
|
@ApiOperation({ summary: "Get all Criticism ===> login as admin" })
|
||||||
@Get()
|
@Get()
|
||||||
findAll(@Query() queryDto: SearchCriticismQueryDto) {
|
findAll(@Query() queryDto: SearchCriticismQueryDto) {
|
||||||
@@ -31,7 +31,7 @@ export class CriticismController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.CRITICISMS)
|
@PermissionsDec(PermissionEnum.CRITICISMS_READ)
|
||||||
@ApiOperation({ summary: "Get one Criticism with id ===> login as admin" })
|
@ApiOperation({ summary: "Get one Criticism with id ===> login as admin" })
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
fineOne(@Param() paramDto: ParamDto) {
|
fineOne(@Param() paramDto: ParamDto) {
|
||||||
@@ -39,7 +39,7 @@ export class CriticismController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.CRITICISMS)
|
@PermissionsDec(PermissionEnum.CRITICISMS_DELETE)
|
||||||
@ApiOperation({ summary: "Delete one Criticism with id ===> login as admin" })
|
@ApiOperation({ summary: "Delete one Criticism with id ===> login as admin" })
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
delete(@Param() paramDto: ParamDto) {
|
delete(@Param() paramDto: ParamDto) {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
//------------------------ service categories ------------------------
|
//------------------------ service categories ------------------------
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@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: CreateDanakServiceCategoryDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createCategory(@Body() createDto: CreateDanakServiceCategoryDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
@@ -45,7 +45,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@ApiOperation({ summary: "Get all service categories => admin route" })
|
@ApiOperation({ summary: "Get all service categories => admin route" })
|
||||||
@Get("categories")
|
@Get("categories")
|
||||||
getCategories(@Query() queryDto: CategorySearchQueryDto) {
|
getCategories(@Query() queryDto: CategorySearchQueryDto) {
|
||||||
@@ -53,7 +53,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@ApiOperation({ summary: "Get all service categories => admin route" })
|
@ApiOperation({ summary: "Get all service categories => admin route" })
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@Get("categories/list")
|
@Get("categories/list")
|
||||||
@@ -69,7 +69,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@ApiOperation({ summary: "Get category by id => admin route" })
|
@ApiOperation({ summary: "Get category by id => admin route" })
|
||||||
@Get("categories/:id")
|
@Get("categories/:id")
|
||||||
getCategoryById(@Param() paramDto: ParamDto) {
|
getCategoryById(@Param() paramDto: ParamDto) {
|
||||||
@@ -77,7 +77,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_UPDATE)
|
||||||
@ApiOperation({ summary: "update category by id => admin route" })
|
@ApiOperation({ summary: "update category by id => admin route" })
|
||||||
@Patch("categories/:id")
|
@Patch("categories/:id")
|
||||||
updateCategory(
|
updateCategory(
|
||||||
@@ -89,7 +89,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_DELETE)
|
||||||
@ApiOperation({ summary: "delete category by id => admin route" })
|
@ApiOperation({ summary: "delete category by id => admin route" })
|
||||||
@Delete("categories/:id")
|
@Delete("categories/:id")
|
||||||
deleteCategoryById(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
deleteCategoryById(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
@@ -97,7 +97,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@ApiOperation({ summary: "toggle status of categories => admin route" })
|
@ApiOperation({ summary: "toggle status of categories => admin route" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("categories/toggle-status/:id")
|
@Post("categories/toggle-status/:id")
|
||||||
@@ -106,7 +106,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
//-------------------- service management --------------------------
|
//-------------------- service management --------------------------
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@ApiOperation({ summary: "create new danak services => admin route" })
|
@ApiOperation({ summary: "create new danak services => admin route" })
|
||||||
@Post()
|
@Post()
|
||||||
createService(@Body() createDto: CreateServiceDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createService(@Body() createDto: CreateServiceDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
@@ -114,7 +114,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@ApiOperation({ summary: "get all danak services ==> admin route" })
|
@ApiOperation({ summary: "get all danak services ==> admin route" })
|
||||||
@Get()
|
@Get()
|
||||||
getServices(@Query() queryDto: DanakServicesSearchQueryDto) {
|
getServices(@Query() queryDto: DanakServicesSearchQueryDto) {
|
||||||
@@ -136,7 +136,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@ApiOperation({ summary: "toggle status of danak service => admin route" })
|
@ApiOperation({ summary: "toggle status of danak service => admin route" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("toggle-status/:id")
|
@Post("toggle-status/:id")
|
||||||
@@ -145,7 +145,7 @@ export class DanakServicesController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@ApiOperation({ summary: "toggle status of danak service slider => admin route" })
|
@ApiOperation({ summary: "toggle status of danak service slider => admin route" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("toggle-slider/:id")
|
@Post("toggle-slider/:id")
|
||||||
@@ -192,7 +192,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "update danak service" })
|
@ApiOperation({ summary: "update danak service" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_UPDATE)
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
updateDanakService(
|
updateDanakService(
|
||||||
@Param() paramDto: ParamDto,
|
@Param() paramDto: ParamDto,
|
||||||
@@ -204,7 +204,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "delete danak service" })
|
@ApiOperation({ summary: "delete danak service" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_DELETE)
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
deleteServiceById(@Param() paramDto: ParamDto) {
|
deleteServiceById(@Param() paramDto: ParamDto) {
|
||||||
return this.danakServicesService.deleteServiceById(paramDto.id);
|
return this.danakServicesService.deleteServiceById(paramDto.id);
|
||||||
@@ -212,7 +212,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "get service users" })
|
@ApiOperation({ summary: "get service users" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@Get(":id/users")
|
@Get(":id/users")
|
||||||
getServiceUsers(@Param() paramDto: ParamDto) {
|
getServiceUsers(@Param() paramDto: ParamDto) {
|
||||||
return this.danakServicesService.getServiceUsers(paramDto.id);
|
return this.danakServicesService.getServiceUsers(paramDto.id);
|
||||||
@@ -235,7 +235,7 @@ export class DanakServicesController {
|
|||||||
@ApiOperation({ summary: "get danak service reviews ==> admin route" })
|
@ApiOperation({ summary: "get danak service reviews ==> admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@Get("reviews")
|
@Get("reviews")
|
||||||
getDanakServiceReviews(@Query() queryDto: DanakServiceReviewQueryDto) {
|
getDanakServiceReviews(@Query() queryDto: DanakServiceReviewQueryDto) {
|
||||||
return this.danakServiceReviewService.getDanakServiceReviews(queryDto);
|
return this.danakServiceReviewService.getDanakServiceReviews(queryDto);
|
||||||
@@ -243,7 +243,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "update danak service review status ==> admin route" })
|
@ApiOperation({ summary: "update danak service review status ==> admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_UPDATE)
|
||||||
@Patch("reviews/:id/:status")
|
@Patch("reviews/:id/:status")
|
||||||
updateDanakServiceReviewStatus(@Param() updateParamDto: UpdateReviewStatusDto) {
|
updateDanakServiceReviewStatus(@Param() updateParamDto: UpdateReviewStatusDto) {
|
||||||
return this.danakServiceReviewService.updateDanakServiceReviewStatus(updateParamDto);
|
return this.danakServiceReviewService.updateDanakServiceReviewStatus(updateParamDto);
|
||||||
@@ -252,7 +252,7 @@ export class DanakServicesController {
|
|||||||
//------------------------ service guides ------------------------
|
//------------------------ service guides ------------------------
|
||||||
@ApiOperation({ summary: "Create a service guide => admin route" })
|
@ApiOperation({ summary: "Create a service guide => admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@Post("guides")
|
@Post("guides")
|
||||||
createServiceGuide(@Body() createDto: CreateServiceGuideDto) {
|
createServiceGuide(@Body() createDto: CreateServiceGuideDto) {
|
||||||
return this.danakServicesService.createServiceGuide(createDto);
|
return this.danakServicesService.createServiceGuide(createDto);
|
||||||
@@ -266,7 +266,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Update service guide => admin route" })
|
@ApiOperation({ summary: "Update service guide => admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_UPDATE)
|
||||||
@Patch("guides/:id")
|
@Patch("guides/:id")
|
||||||
updateServiceGuide(@Param() paramDto: ParamDto, @Body() updateDto: UpdateServiceGuideDto) {
|
updateServiceGuide(@Param() paramDto: ParamDto, @Body() updateDto: UpdateServiceGuideDto) {
|
||||||
return this.danakServicesService.updateServiceGuide(paramDto.id, updateDto);
|
return this.danakServicesService.updateServiceGuide(paramDto.id, updateDto);
|
||||||
@@ -274,7 +274,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Delete service guide => admin route" })
|
@ApiOperation({ summary: "Delete service guide => admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_DELETE)
|
||||||
@Delete("guides/:id")
|
@Delete("guides/:id")
|
||||||
@HttpCode(HttpStatus.NO_CONTENT)
|
@HttpCode(HttpStatus.NO_CONTENT)
|
||||||
deleteServiceGuide(@Param() paramDto: ParamDto) {
|
deleteServiceGuide(@Param() paramDto: ParamDto) {
|
||||||
@@ -283,7 +283,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get service guide by id => admin route" })
|
@ApiOperation({ summary: "Get service guide by id => admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@Get("guides/:id")
|
@Get("guides/:id")
|
||||||
getServiceGuideById(@Param() paramDto: ParamDto) {
|
getServiceGuideById(@Param() paramDto: ParamDto) {
|
||||||
return this.danakServicesService.getServiceGuideById(paramDto.id);
|
return this.danakServicesService.getServiceGuideById(paramDto.id);
|
||||||
@@ -299,7 +299,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get service feedbacks => admin route" })
|
@ApiOperation({ summary: "Get service feedbacks => admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@Get("feedback")
|
@Get("feedback")
|
||||||
getServiceFeedbacks(@Query() queryDto: ServiceFeedbackQueryDto) {
|
getServiceFeedbacks(@Query() queryDto: ServiceFeedbackQueryDto) {
|
||||||
@@ -308,7 +308,7 @@ export class DanakServicesController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get service feedback statistics => admin route" })
|
@ApiOperation({ summary: "Get service feedback statistics => admin route" })
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@Get(":id/feedback")
|
@Get(":id/feedback")
|
||||||
getServiceFeedbackStats(@Param() paramDto: ParamDto) {
|
getServiceFeedbackStats(@Param() paramDto: ParamDto) {
|
||||||
return this.danakServicesService.getServiceFeedback(paramDto.id);
|
return this.danakServicesService.getServiceFeedback(paramDto.id);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class DiscountsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Create a new discount" })
|
@ApiOperation({ summary: "Create a new discount" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.DISCOUNTS)
|
@PermissionsDec(PermissionEnum.DISCOUNTS_CREATE)
|
||||||
@Post()
|
@Post()
|
||||||
@ApiResponse({ status: 201, description: "Discount created successfully" })
|
@ApiResponse({ status: 201, description: "Discount created successfully" })
|
||||||
create(@Body() createDiscountDto: CreateDiscountDto) {
|
create(@Body() createDiscountDto: CreateDiscountDto) {
|
||||||
@@ -28,7 +28,7 @@ export class DiscountsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get all discounts for admin" })
|
@ApiOperation({ summary: "Get all discounts for admin" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.DISCOUNTS)
|
@PermissionsDec(PermissionEnum.DISCOUNTS_READ)
|
||||||
@Get()
|
@Get()
|
||||||
@ApiResponse({ status: 200, description: "Discounts fetched successfully" })
|
@ApiResponse({ status: 200, description: "Discounts fetched successfully" })
|
||||||
getDiscountsForAdmin(@Query() queryDto: SearchDiscountQueryDto) {
|
getDiscountsForAdmin(@Query() queryDto: SearchDiscountQueryDto) {
|
||||||
@@ -37,7 +37,7 @@ export class DiscountsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get discount by id" })
|
@ApiOperation({ summary: "Get discount by id" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.DISCOUNTS)
|
@PermissionsDec(PermissionEnum.DISCOUNTS_READ)
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
@ApiResponse({ status: 200, description: "Discount fetched successfully" })
|
@ApiResponse({ status: 200, description: "Discount fetched successfully" })
|
||||||
getDiscountById(@Param() paramDto: ParamDto) {
|
getDiscountById(@Param() paramDto: ParamDto) {
|
||||||
@@ -46,7 +46,7 @@ export class DiscountsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Toggle discount status" })
|
@ApiOperation({ summary: "Toggle discount status" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.DISCOUNTS)
|
@PermissionsDec(PermissionEnum.DISCOUNTS_CREATE)
|
||||||
@Post(":id/toggle-status")
|
@Post(":id/toggle-status")
|
||||||
toggleDiscountStatus(@Param() paramDto: ParamDto) {
|
toggleDiscountStatus(@Param() paramDto: ParamDto) {
|
||||||
return this.discountsService.toggleDiscountStatus(paramDto.id);
|
return this.discountsService.toggleDiscountStatus(paramDto.id);
|
||||||
@@ -54,7 +54,7 @@ export class DiscountsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Delete discount" })
|
@ApiOperation({ summary: "Delete discount" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.DISCOUNTS)
|
@PermissionsDec(PermissionEnum.DISCOUNTS_DELETE)
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
deleteDiscount(@Param() paramDto: ParamDto) {
|
deleteDiscount(@Param() paramDto: ParamDto) {
|
||||||
return this.discountsService.softDeleteDiscount(paramDto.id);
|
return this.discountsService.softDeleteDiscount(paramDto.id);
|
||||||
@@ -62,7 +62,7 @@ export class DiscountsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Update discount" })
|
@ApiOperation({ summary: "Update discount" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.DISCOUNTS)
|
@PermissionsDec(PermissionEnum.DISCOUNTS_UPDATE)
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
updateDiscount(@Param() paramDto: ParamDto, @Body() updateDiscountDto: UpdateDiscountDto) {
|
updateDiscount(@Param() paramDto: ParamDto, @Body() updateDiscountDto: UpdateDiscountDto) {
|
||||||
return this.discountsService.updateDiscount(paramDto.id, updateDiscountDto);
|
return this.discountsService.updateDiscount(paramDto.id, updateDiscountDto);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import { FindBusinessesDto } from './dto/find-businesses.dto';
|
|||||||
import { AuthGuards } from '../../common/decorators/auth-guard.decorator';
|
import { AuthGuards } from '../../common/decorators/auth-guard.decorator';
|
||||||
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
|
||||||
import { AdminRoute } from '../../common/decorators/admin.decorator';
|
import { AdminRoute } from '../../common/decorators/admin.decorator';
|
||||||
|
import { PermissionsDec } from '../../common/decorators/permission.decorator';
|
||||||
|
import { PermissionEnum } from '../users/enums/permission.enum';
|
||||||
|
|
||||||
@Controller('dmail')
|
@Controller('dmail')
|
||||||
@ApiTags('d-mail')
|
@ApiTags('d-mail')
|
||||||
@@ -15,6 +17,7 @@ export class DmailController {
|
|||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
|
@PermissionsDec(PermissionEnum.DMAIL)
|
||||||
findAll(@Query() query: FindBusinessesDto) {
|
findAll(@Query() query: FindBusinessesDto) {
|
||||||
return this.dmailService.findAllBusinesses(query)
|
return this.dmailService.findAllBusinesses(query)
|
||||||
}
|
}
|
||||||
@@ -27,6 +30,7 @@ export class DmailController {
|
|||||||
|
|
||||||
@Patch(':id/active')
|
@Patch(':id/active')
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
|
@PermissionsDec(PermissionEnum.DMAIL)
|
||||||
update(@Param('id') id: string, @Body() updateDmailDto: UpdateDmailAciveStatusDto) {
|
update(@Param('id') id: string, @Body() updateDmailDto: UpdateDmailAciveStatusDto) {
|
||||||
return this.dmailService.updateDMailActiveStatus(id, updateDmailDto.isActive);
|
return this.dmailService.updateDMailActiveStatus(id, updateDmailDto.isActive);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -444,6 +444,46 @@ export class RestaurantService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async finishChargeRequest(invoiceId: string) {
|
||||||
|
this.logger.log(`Finishing charge request for invoice ${invoiceId}`);
|
||||||
|
try {
|
||||||
|
const url = `${this.config.baseUrl}/super-admin/restaurants/charge-request/finish`;
|
||||||
|
const { data } = await firstValueFrom(
|
||||||
|
this.httpService
|
||||||
|
.post(url, { invoiceId }, {
|
||||||
|
headers: this.getHeaders(),
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
catchError((err: AxiosError) => {
|
||||||
|
this.logger.error(
|
||||||
|
`Failed to finish charge request for invoice ${invoiceId}: ${err.message}`,
|
||||||
|
err.stack,
|
||||||
|
);
|
||||||
|
return throwError(() => err);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
this.logger.log(`Successfully finished charge request for invoice ${invoiceId}`);
|
||||||
|
return data;
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (error instanceof AxiosError && error.response) {
|
||||||
|
this.logger.error(
|
||||||
|
`External API error finishing charge request for invoice ${invoiceId} (status ${error.response.status}):`,
|
||||||
|
error.response.data,
|
||||||
|
);
|
||||||
|
const errorResponse = {
|
||||||
|
...error.response.data,
|
||||||
|
message: error.response.data.error?.message || error.message,
|
||||||
|
};
|
||||||
|
throw new HttpException(errorResponse, error.response.status);
|
||||||
|
}
|
||||||
|
this.logger.error(
|
||||||
|
`Error finishing charge request for invoice ${invoiceId}: ${error instanceof Error ? error.message : "Unknown error"}`,
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async directLogin(userSubscriptionId: string, userId: string) {
|
async directLogin(userSubscriptionId: string, userId: string) {
|
||||||
try {
|
try {
|
||||||
// 1. Get userSubscription by id
|
// 1. Get userSubscription by id
|
||||||
|
|||||||
@@ -21,28 +21,28 @@ export class InvoicesController {
|
|||||||
constructor(private readonly invoiceService: InvoicesService) {}
|
constructor(private readonly invoiceService: InvoicesService) {}
|
||||||
|
|
||||||
@ApiOperation({ summary: "create an invoice ==> admin route" })
|
@ApiOperation({ summary: "create an invoice ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.INVOICES)
|
@PermissionsDec(PermissionEnum.INVOICES_CREATE)
|
||||||
@Post()
|
@Post()
|
||||||
createInvoice(@Body() createDto: CreateInvoiceDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createInvoice(@Body() createDto: CreateInvoiceDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.invoiceService.createInvoiceAdmin(createDto, userIpAndHeaders);
|
return this.invoiceService.createInvoiceAdmin(createDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "update an invoice ==> admin route" })
|
@ApiOperation({ summary: "update an invoice ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.INVOICES)
|
@PermissionsDec(PermissionEnum.INVOICES_UPDATE)
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
updateInvoice(@Param() paramDto: ParamDto, @Body() updateDto: UpdateInvoiceDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
updateInvoice(@Param() paramDto: ParamDto, @Body() updateDto: UpdateInvoiceDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.invoiceService.updateInvoiceAdmin(paramDto.id, updateDto, userIpAndHeaders);
|
return this.invoiceService.updateInvoiceAdmin(paramDto.id, updateDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "delete an invoice ==> admin route" })
|
@ApiOperation({ summary: "delete an invoice ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.INVOICES)
|
@PermissionsDec(PermissionEnum.INVOICES_DELETE)
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
deleteInvoice(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
deleteInvoice(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.invoiceService.deleteInvoiceAdmin(paramDto.id, userIpAndHeaders);
|
return this.invoiceService.deleteInvoiceAdmin(paramDto.id, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all invoices ==> admin route" })
|
@ApiOperation({ summary: "get all invoices ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.INVOICES)
|
@PermissionsDec(PermissionEnum.INVOICES_READ)
|
||||||
@Get()
|
@Get()
|
||||||
getInvoices(@Query() queryDto: InvoicesSearchQueryDto) {
|
getInvoices(@Query() queryDto: InvoicesSearchQueryDto) {
|
||||||
return this.invoiceService.getInvoices(queryDto);
|
return this.invoiceService.getInvoices(queryDto);
|
||||||
|
|||||||
@@ -948,9 +948,13 @@ export class InvoicesService {
|
|||||||
await this.addNotifyForWalletDeduction(invoice, user, userWallet, WalletMessage.SUPPORT_PLAN_WALLET_TRANSFER);
|
await this.addNotifyForWalletDeduction(invoice, user, userWallet, WalletMessage.SUPPORT_PLAN_WALLET_TRANSFER);
|
||||||
//
|
//
|
||||||
} else if (invoice.isExternal) {
|
} else if (invoice.isExternal) {
|
||||||
if (invoice.items[0]?.name == 'purchase_design') {
|
if (invoice.items[0]?.name == 'dmenu_wallet_charge') {
|
||||||
|
this.restaurantService.finishChargeRequest(invoice.id);
|
||||||
|
} else if (invoice.items[0]?.name == 'purchase_plan') {
|
||||||
this.dpageService.finishPurchaseDesign(invoice.externalBusinessId!, invoice.id)
|
this.dpageService.finishPurchaseDesign(invoice.externalBusinessId!, invoice.id)
|
||||||
} else if (invoice.items[0]?.name == 'purchase_new_catalogue') {
|
}
|
||||||
|
|
||||||
|
else if (invoice.items[0]?.name == 'purchase_new_catalogue') {
|
||||||
// call dpage api
|
// call dpage api
|
||||||
const businessId = invoice.externalBusinessId
|
const businessId = invoice.externalBusinessId
|
||||||
if (!businessId) {
|
if (!businessId) {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class LearningController {
|
|||||||
constructor(private readonly learningService: LearningService) {}
|
constructor(private readonly learningService: LearningService) {}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Create learning video" })
|
@ApiOperation({ summary: "Create learning video" })
|
||||||
@PermissionsDec(PermissionEnum.LEARNINGS)
|
@PermissionsDec(PermissionEnum.LEARNINGS_CREATE)
|
||||||
@Post()
|
@Post()
|
||||||
createLearningVideo(@Body() createDto: CreateLearningDto) {
|
createLearningVideo(@Body() createDto: CreateLearningDto) {
|
||||||
return this.learningService.createLearningVideo(createDto);
|
return this.learningService.createLearningVideo(createDto);
|
||||||
@@ -37,14 +37,14 @@ export class LearningController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "delete learning video by id" })
|
@ApiOperation({ summary: "delete learning video by id" })
|
||||||
@PermissionsDec(PermissionEnum.LEARNINGS)
|
@PermissionsDec(PermissionEnum.LEARNINGS_DELETE)
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
deleteLearningVideoById(@Param() paramDto: ParamDto) {
|
deleteLearningVideoById(@Param() paramDto: ParamDto) {
|
||||||
return this.learningService.deleteLearningVideoById(paramDto.id);
|
return this.learningService.deleteLearningVideoById(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "update learning video by id" })
|
@ApiOperation({ summary: "update learning video by id" })
|
||||||
@PermissionsDec(PermissionEnum.LEARNINGS)
|
@PermissionsDec(PermissionEnum.LEARNINGS_UPDATE)
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
updateLearningVideoById(@Param() paramDto: ParamDto, @Body() updateDto: UpdateLearningDto) {
|
updateLearningVideoById(@Param() paramDto: ParamDto, @Body() updateDto: UpdateLearningDto) {
|
||||||
return this.learningService.updateLearningVideo(paramDto.id, updateDto);
|
return this.learningService.updateLearningVideo(paramDto.id, updateDto);
|
||||||
@@ -53,7 +53,7 @@ export class LearningController {
|
|||||||
//----------------- category management ----------------------
|
//----------------- category management ----------------------
|
||||||
|
|
||||||
@ApiOperation({ summary: "Create learning category" })
|
@ApiOperation({ summary: "Create learning category" })
|
||||||
@PermissionsDec(PermissionEnum.LEARNINGS)
|
@PermissionsDec(PermissionEnum.LEARNINGS_CREATE)
|
||||||
@Post("category")
|
@Post("category")
|
||||||
createCategory(@Body() createDto: CreateLearningCategoryDto) {
|
createCategory(@Body() createDto: CreateLearningCategoryDto) {
|
||||||
return this.learningService.createLearningCategory(createDto);
|
return this.learningService.createLearningCategory(createDto);
|
||||||
@@ -72,14 +72,14 @@ export class LearningController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "update learning category ==> admin route" })
|
@ApiOperation({ summary: "update learning category ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.LEARNINGS)
|
@PermissionsDec(PermissionEnum.LEARNINGS_UPDATE)
|
||||||
@Patch("category/:id")
|
@Patch("category/:id")
|
||||||
updateLearningCategory(@Param() paramDto: ParamDto, @Body() updateDto: UpdateLearningCategoryDto) {
|
updateLearningCategory(@Param() paramDto: ParamDto, @Body() updateDto: UpdateLearningCategoryDto) {
|
||||||
return this.learningService.updateLearningCategory(paramDto.id, updateDto);
|
return this.learningService.updateLearningCategory(paramDto.id, updateDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "delete category by id" })
|
@ApiOperation({ summary: "delete category by id" })
|
||||||
@PermissionsDec(PermissionEnum.LEARNINGS)
|
@PermissionsDec(PermissionEnum.LEARNINGS_DELETE)
|
||||||
@Delete("category/:id")
|
@Delete("category/:id")
|
||||||
deleteCategoryById(@Param() paramDto: ParamDto) {
|
deleteCategoryById(@Param() paramDto: ParamDto) {
|
||||||
return this.learningService.deleteCategoryById(paramDto.id);
|
return this.learningService.deleteCategoryById(paramDto.id);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export class PaymentsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get deposit request of users ==> admin route" })
|
@ApiOperation({ summary: "get deposit request of users ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_READ)
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@Get("deposit/transfer")
|
@Get("deposit/transfer")
|
||||||
@@ -54,7 +54,7 @@ export class PaymentsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get deposit gateway payment ==> admin route" })
|
@ApiOperation({ summary: "get deposit gateway payment ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_READ)
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@Get("deposit/gateway")
|
@Get("deposit/gateway")
|
||||||
@@ -63,7 +63,7 @@ export class PaymentsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "approve deposit request ==> admin route" })
|
@ApiOperation({ summary: "approve deposit request ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_UPDATE)
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Post("deposit/transfer/approve/:id")
|
@Post("deposit/transfer/approve/:id")
|
||||||
approverDepositRequest(@Param() paramDto: ParamDto) {
|
approverDepositRequest(@Param() paramDto: ParamDto) {
|
||||||
@@ -71,7 +71,7 @@ export class PaymentsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "reject deposit request ==> admin route" })
|
@ApiOperation({ summary: "reject deposit request ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_UPDATE)
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Post("deposit/transfer/reject/:id")
|
@Post("deposit/transfer/reject/:id")
|
||||||
rejectDepositRequest(@Param() paramDto: ParamDto, @Body() rejectDto: RejectDepositRequestDto) {
|
rejectDepositRequest(@Param() paramDto: ParamDto, @Body() rejectDto: RejectDepositRequestDto) {
|
||||||
@@ -79,7 +79,7 @@ export class PaymentsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get transaction for admin" })
|
@ApiOperation({ summary: "get transaction for admin" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_READ)
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@Get("transactions")
|
@Get("transactions")
|
||||||
@@ -108,7 +108,7 @@ export class PaymentsController {
|
|||||||
///------------------- bank account -----------------------------
|
///------------------- bank account -----------------------------
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS, PermissionEnum.BANK_ACCOUNTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_CREATE, PermissionEnum.BANK_ACCOUNTS_CREATE)
|
||||||
@ApiOperation({ summary: "add bank account for transfer and deposit ==> admin route" })
|
@ApiOperation({ summary: "add bank account for transfer and deposit ==> admin route" })
|
||||||
@Post("bank-account")
|
@Post("bank-account")
|
||||||
addBankAccount(@Body() createDto: CreateBankAccountDto) {
|
addBankAccount(@Body() createDto: CreateBankAccountDto) {
|
||||||
@@ -124,7 +124,7 @@ export class PaymentsController {
|
|||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@ApiOperation({ summary: "update bank account with its id" })
|
@ApiOperation({ summary: "update bank account with its id" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS, PermissionEnum.BANK_ACCOUNTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_UPDATE, PermissionEnum.BANK_ACCOUNTS_UPDATE)
|
||||||
@Patch("bank-account/:id")
|
@Patch("bank-account/:id")
|
||||||
updateBankAccount(@Body() updateDto: UpdateBankAccountDto, @Param() paramDto: ParamDto) {
|
updateBankAccount(@Body() updateDto: UpdateBankAccountDto, @Param() paramDto: ParamDto) {
|
||||||
return this.paymentsService.updateBankAccount(updateDto, paramDto.id);
|
return this.paymentsService.updateBankAccount(updateDto, paramDto.id);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export class ResellerController {
|
|||||||
//***************** DSC Endpoints **************** */
|
//***************** DSC Endpoints **************** */
|
||||||
@ApiOperation({ summary: "Create reseller ==> admin route" })
|
@ApiOperation({ summary: "Create reseller ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.RESELLER)
|
@PermissionsDec(PermissionEnum.RESELLER_CREATE)
|
||||||
@Post()
|
@Post()
|
||||||
createReseller(@Body() dto: CreateResellerDto) {
|
createReseller(@Body() dto: CreateResellerDto) {
|
||||||
return this.resellerService.create(dto);
|
return this.resellerService.create(dto);
|
||||||
@@ -42,7 +42,7 @@ export class ResellerController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get resellers ==> admin route" })
|
@ApiOperation({ summary: "Get resellers ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.RESELLER)
|
@PermissionsDec(PermissionEnum.RESELLER_READ)
|
||||||
@Get()
|
@Get()
|
||||||
getResellers() {
|
getResellers() {
|
||||||
return this.resellerService.findAll();
|
return this.resellerService.findAll();
|
||||||
@@ -52,7 +52,7 @@ export class ResellerController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get withdraw requests ==> admin route" })
|
@ApiOperation({ summary: "Get withdraw requests ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.RESELLER)
|
@PermissionsDec(PermissionEnum.RESELLER_READ)
|
||||||
@Pagination()
|
@Pagination()
|
||||||
@Get("withdraw-request/admin")
|
@Get("withdraw-request/admin")
|
||||||
getRewardRequests(@Query() query: SearchWithdrawRequestQueryDto) {
|
getRewardRequests(@Query() query: SearchWithdrawRequestQueryDto) {
|
||||||
@@ -61,7 +61,7 @@ export class ResellerController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Confirm withdraw request ==> admin route" })
|
@ApiOperation({ summary: "Confirm withdraw request ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.RESELLER)
|
@PermissionsDec(PermissionEnum.RESELLER_UPDATE)
|
||||||
@Patch("withdraw-request/:id")
|
@Patch("withdraw-request/:id")
|
||||||
confirmWithdrawRequests(@Param() paramDto: ParamDto, @Body() dto: ConfirmwithdrawRequestDto) {
|
confirmWithdrawRequests(@Param() paramDto: ParamDto, @Body() dto: ConfirmwithdrawRequestDto) {
|
||||||
return this.resellerService.confirmWithdrawRequest(paramDto.id, dto.transactionId);
|
return this.resellerService.confirmWithdrawRequest(paramDto.id, dto.transactionId);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export class SlidersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "create slider (admin route)" })
|
@ApiOperation({ summary: "create slider (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_CREATE)
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() createSliderDto: CreateSliderDto) {
|
create(@Body() createSliderDto: CreateSliderDto) {
|
||||||
return this.slidersService.create(createSliderDto);
|
return this.slidersService.create(createSliderDto);
|
||||||
@@ -26,7 +26,7 @@ export class SlidersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get all sliders (admin route)" })
|
@ApiOperation({ summary: "Get all sliders (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_READ)
|
||||||
@Get()
|
@Get()
|
||||||
getSlidersList(@Query() queryDto: PaginationDto) {
|
getSlidersList(@Query() queryDto: PaginationDto) {
|
||||||
return this.slidersService.getSlidersList(queryDto);
|
return this.slidersService.getSlidersList(queryDto);
|
||||||
@@ -34,7 +34,7 @@ export class SlidersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get a slider by id (admin route)" })
|
@ApiOperation({ summary: "Get a slider by id (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_READ)
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
getSliderById(@Param() paramDto: ParamDto) {
|
getSliderById(@Param() paramDto: ParamDto) {
|
||||||
return this.slidersService.getSliderById(paramDto.id);
|
return this.slidersService.getSliderById(paramDto.id);
|
||||||
@@ -42,7 +42,7 @@ export class SlidersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Update a slider (admin route)" })
|
@ApiOperation({ summary: "Update a slider (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_UPDATE)
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
update(@Param() paramDto: ParamDto, @Body() updateSliderDto: UpdateSliderDto) {
|
update(@Param() paramDto: ParamDto, @Body() updateSliderDto: UpdateSliderDto) {
|
||||||
return this.slidersService.update(paramDto.id, updateSliderDto);
|
return this.slidersService.update(paramDto.id, updateSliderDto);
|
||||||
@@ -50,7 +50,7 @@ export class SlidersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Delete a slider (admin route)" })
|
@ApiOperation({ summary: "Delete a slider (admin route)" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.BLOGS)
|
@PermissionsDec(PermissionEnum.BLOGS_DELETE)
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
remove(@Param() paramDto: ParamDto) {
|
remove(@Param() paramDto: ParamDto) {
|
||||||
return this.slidersService.remove(paramDto.id);
|
return this.slidersService.remove(paramDto.id);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export class SubscriptionsController {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Delete subscription =. admin route" })
|
@ApiOperation({ summary: "Delete subscription =. admin route" })
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_DELETE)
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
deleteSubscription(@Param('id') id :string) {
|
deleteSubscription(@Param('id') id :string) {
|
||||||
@@ -39,14 +39,14 @@ export class SubscriptionsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Create a subscription plan" })
|
@ApiOperation({ summary: "Create a subscription plan" })
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@Post()
|
@Post()
|
||||||
createSubscription(@Body() createDto: AddSubscriptionsToServiceDto) {
|
createSubscription(@Body() createDto: AddSubscriptionsToServiceDto) {
|
||||||
return this.subscriptionService.createSubscriptionsPlan(createDto);
|
return this.subscriptionService.createSubscriptionsPlan(createDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all subscription plans" })
|
@ApiOperation({ summary: "get all subscription plans" })
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
@Get("service/:serviceId")
|
@Get("service/:serviceId")
|
||||||
getServiceSubscriptions(@Param() paramDto: ServiceIdParamDto, @Query() queryDto: ServiceSubsQueryDto) {
|
getServiceSubscriptions(@Param() paramDto: ServiceIdParamDto, @Query() queryDto: ServiceSubsQueryDto) {
|
||||||
return this.subscriptionService.getServiceSubscriptions(paramDto.serviceId, queryDto);
|
return this.subscriptionService.getServiceSubscriptions(paramDto.serviceId, queryDto);
|
||||||
@@ -65,7 +65,7 @@ export class SubscriptionsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "toggle status of service subs" })
|
@ApiOperation({ summary: "toggle status of service subs" })
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_CREATE)
|
||||||
@Post("toggle-status/:id")
|
@Post("toggle-status/:id")
|
||||||
toggleStatusOfServiceSub(@Param() paramDto: ParamDto) {
|
toggleStatusOfServiceSub(@Param() paramDto: ParamDto) {
|
||||||
return this.subscriptionService.toggleSubStatus(paramDto.id);
|
return this.subscriptionService.toggleSubStatus(paramDto.id);
|
||||||
@@ -73,14 +73,14 @@ export class SubscriptionsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "get a subscription plan by id" })
|
@ApiOperation({ summary: "get a subscription plan by id" })
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_READ)
|
||||||
getSubscription(@Param() paramDto: ParamDto) {
|
getSubscription(@Param() paramDto: ParamDto) {
|
||||||
return this.subscriptionService.getSubscriptionPlanById(paramDto.id);
|
return this.subscriptionService.getSubscriptionPlanById(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "update a subscription plan by id" })
|
@ApiOperation({ summary: "update a subscription plan by id" })
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
@PermissionsDec(PermissionEnum.SERVICES)
|
@PermissionsDec(PermissionEnum.SERVICES_UPDATE)
|
||||||
updateSubscription(@Param() paramDto: ParamDto, @Body() updateDto: UpdateSubscriptionPlanDto) {
|
updateSubscription(@Param() paramDto: ParamDto, @Body() updateDto: UpdateSubscriptionPlanDto) {
|
||||||
return this.subscriptionService.updateSubscriptionPlan(paramDto.id, updateDto);
|
return this.subscriptionService.updateSubscriptionPlan(paramDto.id, updateDto);
|
||||||
}
|
}
|
||||||
@@ -144,7 +144,7 @@ export class SubscriptionsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all user subscriptions with pagination and filters ==> admin route" })
|
@ApiOperation({ summary: "get all user subscriptions with pagination and filters ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.PAYMENTS)
|
@PermissionsDec(PermissionEnum.PAYMENTS_READ)
|
||||||
@Get("admin/user-subscriptions/all")
|
@Get("admin/user-subscriptions/all")
|
||||||
getAllUserSubscriptions(@Query() queryDto: AdminUserSubscriptionsQueryDto) {
|
getAllUserSubscriptions(@Query() queryDto: AdminUserSubscriptionsQueryDto) {
|
||||||
return this.subscriptionService.getAllUserSubscriptions(queryDto);
|
return this.subscriptionService.getAllUserSubscriptions(queryDto);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class SupportPlansController {
|
|||||||
constructor(private readonly supportPlansService: SupportPlansService) {}
|
constructor(private readonly supportPlansService: SupportPlansService) {}
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.SUPPORT_PLAN)
|
@PermissionsDec(PermissionEnum.SUPPORT_PLAN_CREATE)
|
||||||
@ApiOperation({ summary: "Create a new support plan (admin)" })
|
@ApiOperation({ summary: "Create a new support plan (admin)" })
|
||||||
@Post()
|
@Post()
|
||||||
createSupportPlan(@Body() createSupportPlanDto: CreateSupportPlanDto) {
|
createSupportPlan(@Body() createSupportPlanDto: CreateSupportPlanDto) {
|
||||||
@@ -27,7 +27,7 @@ export class SupportPlansController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.SUPPORT_PLAN)
|
@PermissionsDec(PermissionEnum.SUPPORT_PLAN_READ)
|
||||||
@ApiOperation({ summary: "Get all support plans (admin)" })
|
@ApiOperation({ summary: "Get all support plans (admin)" })
|
||||||
@Get("list")
|
@Get("list")
|
||||||
getSupportPlansList(@Query() queryDto: GetSupportPlanListQueryDto) {
|
getSupportPlansList(@Query() queryDto: GetSupportPlanListQueryDto) {
|
||||||
@@ -35,7 +35,7 @@ export class SupportPlansController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.SUPPORT_PLAN)
|
@PermissionsDec(PermissionEnum.SUPPORT_PLAN_READ)
|
||||||
@ApiOperation({ summary: "Get a support plan by id (admin)" })
|
@ApiOperation({ summary: "Get a support plan by id (admin)" })
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
getSupportPlanById(@Param() paramDto: ParamDto) {
|
getSupportPlanById(@Param() paramDto: ParamDto) {
|
||||||
@@ -43,7 +43,7 @@ export class SupportPlansController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.SUPPORT_PLAN)
|
@PermissionsDec(PermissionEnum.SUPPORT_PLAN_DELETE)
|
||||||
@ApiOperation({ summary: "Delete a support plan by id (admin)" })
|
@ApiOperation({ summary: "Delete a support plan by id (admin)" })
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
deleteSupportPlanById(@Param() paramDto: ParamDto) {
|
deleteSupportPlanById(@Param() paramDto: ParamDto) {
|
||||||
@@ -51,7 +51,7 @@ export class SupportPlansController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.SUPPORT_PLAN)
|
@PermissionsDec(PermissionEnum.SUPPORT_PLAN_UPDATE)
|
||||||
@ApiOperation({ summary: "Update a support plan by id (admin)" })
|
@ApiOperation({ summary: "Update a support plan by id (admin)" })
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
updateSupportPlanById(@Param() paramDto: ParamDto, @Body() updateSupportPlanDto: UpdateSupportPlanDto) {
|
updateSupportPlanById(@Param() paramDto: ParamDto, @Body() updateSupportPlanDto: UpdateSupportPlanDto) {
|
||||||
@@ -71,7 +71,7 @@ export class SupportPlansController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.SUPPORT_PLAN)
|
@PermissionsDec(PermissionEnum.SUPPORT_PLAN_READ)
|
||||||
@ApiOperation({ summary: "Get support plan users (admin)" })
|
@ApiOperation({ summary: "Get support plan users (admin)" })
|
||||||
@Get(":id/users")
|
@Get(":id/users")
|
||||||
getSupportPlanUsers(@Param() paramDto: ParamDto, @Query() queryDto: SearchSupportPlanUsersQueryDto) {
|
getSupportPlanUsers(@Param() paramDto: ParamDto, @Query() queryDto: SearchSupportPlanUsersQueryDto) {
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { Controller, Post, Patch, Delete, Param, Body } from '@nestjs/common';
|
||||||
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from '@nestjs/swagger';
|
||||||
|
import { AttachmentService } from '../providers/attachment.service';
|
||||||
|
import { CreateAttachmentDto } from '../dto/attachment/create-attachment.dto';
|
||||||
|
import { UpdateAttachmentDto } from '../dto/attachment/update-attachment.dto';
|
||||||
|
import { TMAttachment } from '../entities/attachment.entity';
|
||||||
|
import { AuthGuards } from '../../../common/decorators/auth-guard.decorator';
|
||||||
|
import { AdminRoute } from '../../../common/decorators/admin.decorator';
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@AdminRoute()
|
||||||
|
@ApiTags('Task Manager - Attachments')
|
||||||
|
@Controller('task-manager/attachments')
|
||||||
|
export class AttachmentController {
|
||||||
|
constructor(private readonly attachmentService: AttachmentService) {}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@ApiOperation({ summary: 'Create a new attachment' })
|
||||||
|
@ApiResponse({ status: 201, description: 'Attachment created', type: TMAttachment })
|
||||||
|
@ApiResponse({ status: 404, description: 'Task not found' })
|
||||||
|
create(@Body() body: CreateAttachmentDto): Promise<TMAttachment> {
|
||||||
|
return this.attachmentService.create(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(':id')
|
||||||
|
@ApiOperation({ summary: 'Update an attachment' })
|
||||||
|
@ApiParam({ name: 'id', description: 'Attachment ID' })
|
||||||
|
@ApiResponse({ status: 200, description: 'Attachment updated', type: TMAttachment })
|
||||||
|
@ApiResponse({ status: 404, description: 'Attachment or Task not found' })
|
||||||
|
update(@Param('id') id: string, @Body() body: UpdateAttachmentDto): Promise<TMAttachment> {
|
||||||
|
return this.attachmentService.update(id, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(':id')
|
||||||
|
@ApiOperation({ summary: 'Delete an attachment' })
|
||||||
|
@ApiParam({ name: 'id', description: 'Attachment ID' })
|
||||||
|
@ApiResponse({ status: 200, description: 'Attachment deleted' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Attachment not found' })
|
||||||
|
remove(@Param('id') id: string): Promise<void> {
|
||||||
|
return this.attachmentService.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,56 +1,52 @@
|
|||||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common';
|
import { Controller, Post, Patch, Delete, Param, Body } from "@nestjs/common";
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
||||||
import { CheckListItemService } from '../providers/check-list-item.service';
|
import { CheckListItemService } from "../providers/check-list-item.service";
|
||||||
import { CreateCheckListItemDto } from '../dto/check-list-item/create-check-list-item.dto';
|
import { CreateCheckListItemDto } from "../dto/check-list-item/create-check-list-item.dto";
|
||||||
import { UpdateCheckListItemDto } from '../dto/check-list-item/update-check-list-item.dto';
|
import { UpdateCheckListItemDto } from "../dto/check-list-item/update-check-list-item.dto";
|
||||||
import { TMCheckListItem } from '../entities/check-list-item.entity';
|
import { TMCheckListItem } from "../entities/check-list-item.entity";
|
||||||
|
import { AuthGuards } from "../../../common/decorators/auth-guard.decorator";
|
||||||
|
import { AdminRoute } from "../../../common/decorators/admin.decorator";
|
||||||
|
import { ParamDto } from "../../../common/DTO/param.dto";
|
||||||
|
|
||||||
@ApiTags('Task Manager - Check List Items')
|
@AuthGuards()
|
||||||
@Controller('task-manager/check-list-items')
|
@AdminRoute()
|
||||||
|
@ApiTags("Task Manager - Check List Items")
|
||||||
|
@Controller("task-manager/check-list-items")
|
||||||
export class CheckListItemController {
|
export class CheckListItemController {
|
||||||
constructor(private readonly checkListItemService: CheckListItemService) {}
|
constructor(private readonly checkListItemService: CheckListItemService) {}
|
||||||
|
|
||||||
@Get()
|
|
||||||
@ApiOperation({ summary: 'Get all check list items, optionally filtered by task' })
|
|
||||||
@ApiQuery({ name: 'taskId', required: false, description: 'Filter check list items by task ID' })
|
|
||||||
@ApiResponse({ status: 200, description: 'List of check list items', type: [TMCheckListItem] })
|
|
||||||
findAll(@Query('taskId') taskId?: string): Promise<TMCheckListItem[]> {
|
|
||||||
if (taskId) return this.checkListItemService.findByTask(taskId);
|
|
||||||
return this.checkListItemService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(':id')
|
|
||||||
@ApiOperation({ summary: 'Get a check list item by ID' })
|
|
||||||
@ApiParam({ name: 'id', description: 'CheckListItem ID' })
|
|
||||||
@ApiResponse({ status: 200, description: 'CheckListItem found', type: TMCheckListItem })
|
|
||||||
@ApiResponse({ status: 404, description: 'CheckListItem not found' })
|
|
||||||
findOne(@Param('id') id: string): Promise<TMCheckListItem> {
|
|
||||||
return this.checkListItemService.findOne(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a new check list item' })
|
@ApiOperation({ summary: "Create a new check list item" })
|
||||||
@ApiResponse({ status: 201, description: 'CheckListItem created', type: TMCheckListItem })
|
@ApiResponse({ status: 201, description: "CheckListItem created", type: TMCheckListItem })
|
||||||
@ApiResponse({ status: 404, description: 'Task not found' })
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
create(@Body() body: CreateCheckListItemDto): Promise<TMCheckListItem> {
|
create(@Body() body: CreateCheckListItemDto): Promise<TMCheckListItem> {
|
||||||
return this.checkListItemService.create(body);
|
return this.checkListItemService.create(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(":id")
|
||||||
@ApiOperation({ summary: 'Update a check list item' })
|
@ApiOperation({ summary: "Update a check list item" })
|
||||||
@ApiParam({ name: 'id', description: 'CheckListItem ID' })
|
@ApiParam({ name: "id", description: "CheckListItem ID" })
|
||||||
@ApiResponse({ status: 200, description: 'CheckListItem updated', type: TMCheckListItem })
|
@ApiResponse({ status: 200, description: "CheckListItem updated", type: TMCheckListItem })
|
||||||
@ApiResponse({ status: 404, description: 'CheckListItem or Task not found' })
|
@ApiResponse({ status: 404, description: "CheckListItem or Task not found" })
|
||||||
update(@Param('id') id: string, @Body() body: UpdateCheckListItemDto): Promise<TMCheckListItem> {
|
update(@Param("id") id: string, @Body() body: UpdateCheckListItemDto): Promise<TMCheckListItem> {
|
||||||
return this.checkListItemService.update(id, body);
|
return this.checkListItemService.update(id, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(":id")
|
||||||
@ApiOperation({ summary: 'Delete a check list item' })
|
@ApiOperation({ summary: "Delete a check list item" })
|
||||||
@ApiParam({ name: 'id', description: 'CheckListItem ID' })
|
@ApiParam({ name: "id", description: "CheckListItem ID" })
|
||||||
@ApiResponse({ status: 200, description: 'CheckListItem deleted' })
|
@ApiResponse({ status: 200, description: "CheckListItem deleted", type: TMCheckListItem })
|
||||||
@ApiResponse({ status: 404, description: 'CheckListItem not found' })
|
@ApiResponse({ status: 404, description: "CheckListItem not found" })
|
||||||
remove(@Param('id') id: string): Promise<void> {
|
remove(@Param("id") id: string): Promise<TMCheckListItem> {
|
||||||
return this.checkListItemService.remove(id);
|
return this.checkListItemService.remove(id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Patch("change-status/:id")
|
||||||
|
@ApiOperation({summary: "change status of a check list item."})
|
||||||
|
@ApiParam({name: "id", description: "CheckListItem ID"})
|
||||||
|
@ApiResponse({status: 200, description: "successfully changed the status!"})
|
||||||
|
@ApiResponse({ status: 404, description: "CheckListItem not found" })
|
||||||
|
changeStatus(@Param() paramDto: ParamDto) {
|
||||||
|
return this.checkListItemService.toggleStatus(paramDto.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,58 +1,83 @@
|
|||||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common';
|
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from "@nestjs/common";
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
||||||
import { ProjectService } from '../providers/project.service';
|
import { ProjectService } from "../providers/project.service";
|
||||||
import { CreateProjectDto } from '../dto/project/create-project.dto';
|
import { CreateProjectDto } from "../dto/project/create-project.dto";
|
||||||
import { UpdateProjectDto } from '../dto/project/update-project.dto';
|
import { UpdateProjectDto } from "../dto/project/update-project.dto";
|
||||||
import { TMProject } from '../entities/project.entity';
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
|
import { TMProject } from "../entities/project.entity";
|
||||||
|
import { AdminRoute } from "../../../common/decorators/admin.decorator";
|
||||||
|
import { PermissionsDec } from "../../../common/decorators/permission.decorator";
|
||||||
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
import { UserDec } from "../../../common/decorators/user.decorator";
|
||||||
|
import { AuthGuards } from "../../../common/decorators/auth-guard.decorator";
|
||||||
|
import { ParamDto } from "../../../common/DTO/param.dto";
|
||||||
|
import { ITokenPayload } from "../../auth/interfaces/IToken-payload";
|
||||||
|
|
||||||
@ApiTags('Task Manager - Projects')
|
@AuthGuards()
|
||||||
@Controller('task-manager/projects')
|
@AdminRoute()
|
||||||
|
@ApiTags("Task Manager - Projects")
|
||||||
|
@Controller("task-manager/projects")
|
||||||
export class ProjectController {
|
export class ProjectController {
|
||||||
constructor(private readonly projectService: ProjectService) {}
|
constructor(private readonly projectService: ProjectService) {}
|
||||||
|
|
||||||
@Get()
|
|
||||||
@ApiOperation({ summary: 'Get all projects, optionally filtered by workspace' })
|
|
||||||
@ApiQuery({ name: 'workspaceId', required: false, description: 'Filter projects by workspace ID' })
|
|
||||||
@ApiResponse({ status: 200, description: 'List of projects', type: [TMProject] })
|
|
||||||
findAll(@Query('workspaceId') workspaceId?: string): Promise<TMProject[]> {
|
|
||||||
if (workspaceId) return this.projectService.findByWorkspace(workspaceId);
|
|
||||||
return this.projectService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
@ApiOperation({ summary: 'Get a project by ID' })
|
@ApiOperation({summary: 'Get one project by ID'})
|
||||||
@ApiParam({ name: 'id', description: 'Project ID' })
|
@ApiResponse({status: 200, description: 'received the project successfully!'})
|
||||||
@ApiResponse({ status: 200, description: 'Project found', type: TMProject })
|
@ApiResponse({status: 404, description: 'Project Not Found!'})
|
||||||
@ApiResponse({ status: 404, description: 'Project not found' })
|
@ApiResponse({status: 400, description: 'Bad Request!'})
|
||||||
findOne(@Param('id') id: string): Promise<TMProject> {
|
findOne(@Param('id') id: string) {
|
||||||
return this.projectService.findOne(id);
|
return this.projectService.findOneOrFail(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a new project' })
|
@PermissionsDec(PermissionEnum.PROJECT_CREATE)
|
||||||
@ApiResponse({ status: 201, description: 'Project created', type: TMProject })
|
@ApiOperation({ summary: "Create a new project" })
|
||||||
@ApiResponse({ status: 400, description: 'One or more users are not members of the workspace' })
|
@ApiResponse({ status: 201, description: "Project created", type: TMProject })
|
||||||
@ApiResponse({ status: 404, description: 'Workspace not found' })
|
@ApiResponse({ status: 400, description: "One or more users are not members of the workspace" })
|
||||||
|
@ApiResponse({ status: 404, description: "Workspace not found" })
|
||||||
create(@Body() body: CreateProjectDto): Promise<TMProject> {
|
create(@Body() body: CreateProjectDto): Promise<TMProject> {
|
||||||
return this.projectService.create(body);
|
return this.projectService.create(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(":id")
|
||||||
@ApiOperation({ summary: 'Update a project' })
|
@PermissionsDec(PermissionEnum.PROJECT_UPDATE)
|
||||||
@ApiParam({ name: 'id', description: 'Project ID' })
|
@ApiOperation({ summary: "Update a project" })
|
||||||
@ApiResponse({ status: 200, description: 'Project updated', type: TMProject })
|
@ApiParam({ name: "id", description: "Project ID" })
|
||||||
@ApiResponse({ status: 400, description: 'One or more users are not members of the workspace' })
|
@ApiResponse({ status: 200, description: "Project updated", type: TMProject })
|
||||||
@ApiResponse({ status: 404, description: 'Project not found' })
|
@ApiResponse({ status: 400, description: "One or more users are not members of the workspace" })
|
||||||
update(@Param('id') id: string, @Body() body: UpdateProjectDto): Promise<TMProject> {
|
@ApiResponse({ status: 404, description: "Project not found" })
|
||||||
|
update(@Param("id") id: string, @Body() body: UpdateProjectDto): Promise<TMProject> {
|
||||||
return this.projectService.update(id, body);
|
return this.projectService.update(id, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(":id")
|
||||||
@ApiOperation({ summary: 'Delete a project' })
|
@PermissionsDec(PermissionEnum.PROJECT_DELETE)
|
||||||
@ApiParam({ name: 'id', description: 'Project ID' })
|
@ApiOperation({ summary: "Delete a project" })
|
||||||
@ApiResponse({ status: 200, description: 'Project deleted' })
|
@ApiParam({ name: "id", description: "Project ID" })
|
||||||
@ApiResponse({ status: 404, description: 'Project not found' })
|
@ApiResponse({ status: 200, description: "Project deleted", type: TMProject })
|
||||||
remove(@Param('id') id: string): Promise<TMProject> {
|
@ApiResponse({ status: 404, description: "Project not found" })
|
||||||
|
remove(@Param("id") id: string): Promise<TMProject> {
|
||||||
return this.projectService.remove(id);
|
return this.projectService.remove(id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Get("user/workspace/:id")
|
||||||
|
@ApiOperation({ summary: "Get user projects in a specific workspace!" })
|
||||||
|
@ApiResponse({ status: 200, description: "Got user projects successfully!" })
|
||||||
|
@ApiResponse({ status: 400, description: "Bad Request!" })
|
||||||
|
findUserProjectsByWorkspace(
|
||||||
|
@UserDec() user: ITokenPayload,
|
||||||
|
@Param() paramDto: ParamDto,
|
||||||
|
@Query() pagination: PaginationDto,
|
||||||
|
): Promise<{ projects: TMProject[]; count: number; paginate: true }> {
|
||||||
|
return this.projectService.findUserProjectsByWorkspace(user.id, user.permissions, paramDto.id, pagination);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("detail/:id")
|
||||||
|
@ApiOperation({ summary: "Get project detail" })
|
||||||
|
@ApiResponse({ status: 200, description: "Got Project Detail Successfully!" })
|
||||||
|
@ApiResponse({ status: 400, description: "Bad request!" })
|
||||||
|
@ApiResponse({ status: 404, description: "The project was not found!" })
|
||||||
|
getProjectDetail(@Param() paramDto: ParamDto, @UserDec() user: ITokenPayload): Promise<TMProject | null> {
|
||||||
|
return this.projectService.getProjectDetail(paramDto.id, user.id, user.permissions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import { Controller, Post, Patch, Delete, Param, Body } from "@nestjs/common";
|
||||||
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
||||||
|
import { RemarkService } from "../providers/remark.service";
|
||||||
|
import { CreateRemarkDto } from "../dto/remark/create-remark.dto";
|
||||||
|
import { UpdateRemarkDto } from "../dto/remark/update-remark.dto";
|
||||||
|
import { TMRemark } from "../entities/remark.entity";
|
||||||
|
import { AuthGuards } from "../../../common/decorators/auth-guard.decorator";
|
||||||
|
import { AdminRoute } from "../../../common/decorators/admin.decorator";
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@AdminRoute()
|
||||||
|
@ApiTags("Task Manager - Remarks")
|
||||||
|
@Controller("task-manager/remarks")
|
||||||
|
export class RemarkController {
|
||||||
|
constructor(private readonly remarkService: RemarkService) {}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@ApiOperation({ summary: "Create a new remark" })
|
||||||
|
@ApiResponse({ status: 201, description: "Remark created", type: TMRemark })
|
||||||
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
|
create(@Body() body: CreateRemarkDto): Promise<TMRemark> {
|
||||||
|
return this.remarkService.create(body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(":id")
|
||||||
|
@ApiOperation({ summary: "Update a remark" })
|
||||||
|
@ApiParam({ name: "id", description: "Remark ID" })
|
||||||
|
@ApiResponse({ status: 200, description: "Remark updated", type: TMRemark })
|
||||||
|
@ApiResponse({ status: 404, description: "Remark or Task not found" })
|
||||||
|
update(@Param("id") id: string, @Body() body: UpdateRemarkDto): Promise<TMRemark> {
|
||||||
|
return this.remarkService.update(id, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(":id")
|
||||||
|
@ApiOperation({ summary: "Delete a remark" })
|
||||||
|
@ApiParam({ name: "id", description: "Remark ID" })
|
||||||
|
@ApiResponse({ status: 200, description: "Remark deleted" })
|
||||||
|
@ApiResponse({ status: 404, description: "Remark not found" })
|
||||||
|
remove(@Param("id") id: string): Promise<void> {
|
||||||
|
return this.remarkService.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,34 +1,23 @@
|
|||||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from "@nestjs/common";
|
import { Controller, Post, Patch, Delete, Param, Body } from "@nestjs/common";
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from "@nestjs/swagger";
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
||||||
import { TaskPhaseService } from "../providers/task-phase.service";
|
import { TaskPhaseService } from "../providers/task-phase.service";
|
||||||
import { CreateTaskPhaseDto } from "../dto/task-phase/create-task-phase.dto";
|
import { CreateTaskPhaseDto } from "../dto/task-phase/create-task-phase.dto";
|
||||||
import { UpdateTaskPhaseDto } from "../dto/task-phase/update-task-phase.dto";
|
import { UpdateTaskPhaseDto } from "../dto/task-phase/update-task-phase.dto";
|
||||||
import { TMTaskPhase } from "../entities/task-phase.entity";
|
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||||
|
import { AuthGuards } from "../../../common/decorators/auth-guard.decorator";
|
||||||
|
import { AdminRoute } from "../../../common/decorators/admin.decorator";
|
||||||
|
import { PermissionsDec } from "../../../common/decorators/permission.decorator";
|
||||||
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@AdminRoute()
|
||||||
@ApiTags("Task Manager - Task Phases")
|
@ApiTags("Task Manager - Task Phases")
|
||||||
@Controller("task-manager/task-phases")
|
@Controller("task-manager/task-phases")
|
||||||
export class TaskPhaseController {
|
export class TaskPhaseController {
|
||||||
constructor(private readonly taskPhaseService: TaskPhaseService) {}
|
constructor(private readonly taskPhaseService: TaskPhaseService) {}
|
||||||
|
|
||||||
@Get()
|
|
||||||
@ApiOperation({ summary: "Get all task phases, optionally filtered by project" })
|
|
||||||
@ApiQuery({ name: "projectId", required: false, description: "Filter task phases by project ID" })
|
|
||||||
@ApiResponse({ status: 200, description: "List of task phases", type: [TMTaskPhase] })
|
|
||||||
findAll(@Query("projectId") projectId?: string): Promise<TMTaskPhase[]> {
|
|
||||||
if (projectId) return this.taskPhaseService.findByProject(projectId);
|
|
||||||
return this.taskPhaseService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(":id")
|
|
||||||
@ApiOperation({ summary: "Get a task phase by ID" })
|
|
||||||
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
|
||||||
@ApiResponse({ status: 200, description: "TaskPhase found", type: TMTaskPhase })
|
|
||||||
@ApiResponse({ status: 404, description: "TaskPhase not found" })
|
|
||||||
findOne(@Param("id") id: string): Promise<TMTaskPhase> {
|
|
||||||
return this.taskPhaseService.findOne(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
|
@PermissionsDec(PermissionEnum.TASK_PHASE_CREATE)
|
||||||
@ApiOperation({ summary: "Create a new task phase" })
|
@ApiOperation({ summary: "Create a new task phase" })
|
||||||
@ApiResponse({ status: 201, description: "TaskPhase created", type: TMTaskPhase })
|
@ApiResponse({ status: 201, description: "TaskPhase created", type: TMTaskPhase })
|
||||||
@ApiResponse({ status: 404, description: "Project not found" })
|
@ApiResponse({ status: 404, description: "Project not found" })
|
||||||
@@ -37,6 +26,7 @@ export class TaskPhaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
|
@PermissionsDec(PermissionEnum.TASK_PHASE_UPDATE)
|
||||||
@ApiOperation({ summary: "Update a task phase" })
|
@ApiOperation({ summary: "Update a task phase" })
|
||||||
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
||||||
@ApiResponse({ status: 200, description: "TaskPhase updated", type: TMTaskPhase })
|
@ApiResponse({ status: 200, description: "TaskPhase updated", type: TMTaskPhase })
|
||||||
@@ -46,6 +36,7 @@ export class TaskPhaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
|
@PermissionsDec(PermissionEnum.TASK_PHASE_DELETE)
|
||||||
@ApiOperation({ summary: "Delete a task phase" })
|
@ApiOperation({ summary: "Delete a task phase" })
|
||||||
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
@ApiParam({ name: "id", description: "TaskPhase ID" })
|
||||||
@ApiResponse({ status: 200, description: "TaskPhase deleted" })
|
@ApiResponse({ status: 200, description: "TaskPhase deleted" })
|
||||||
|
|||||||
@@ -1,67 +1,103 @@
|
|||||||
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from '@nestjs/common';
|
import { Controller, Get, Post, Patch, Delete, Param, Body, Query } from "@nestjs/common";
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam, ApiQuery } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
||||||
import { TaskService } from '../providers/task.service';
|
import { TaskService } from "../providers/task.service";
|
||||||
import { CreateTaskDto } from '../dto/task/create-task.dto';
|
import { CreateTaskDto } from "../dto/task/create-task.dto";
|
||||||
import { UpdateTaskDto } from '../dto/task/update-task.dto';
|
import { UpdateTaskDto } from "../dto/task/update-task.dto";
|
||||||
import { ChangeTaskPhaseDto } from '../dto/task/change-task-phase.dto';
|
import { ChangeTaskPhaseDto } from "../dto/task/change-task-phase.dto";
|
||||||
import { TMTask } from '../entities/task.entity';
|
import { TMTask } from "../entities/task.entity";
|
||||||
|
import { AuthGuards } from "../../../common/decorators/auth-guard.decorator";
|
||||||
|
import { AdminRoute } from "../../../common/decorators/admin.decorator";
|
||||||
|
import { UserDec } from "../../../common/decorators/user.decorator";
|
||||||
|
import { ParamDto } from "../../../common/DTO/param.dto";
|
||||||
|
import { PermissionsDec } from "../../../common/decorators/permission.decorator";
|
||||||
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
import { ITokenPayload } from "../../auth/interfaces/IToken-payload";
|
||||||
|
import { CursorPagination } from "../../../common/decorators/cursor-pagination.decorator";
|
||||||
|
import { CursorPaginationDto } from "../../../common/DTO/cursor-pagination.dto";
|
||||||
|
|
||||||
@ApiTags('Task Manager - Tasks')
|
@AuthGuards()
|
||||||
@Controller('task-manager/tasks')
|
@AdminRoute()
|
||||||
|
@ApiTags("Task Manager - Tasks")
|
||||||
|
@Controller("task-manager/tasks")
|
||||||
export class TaskController {
|
export class TaskController {
|
||||||
constructor(private readonly taskService: TaskService) {}
|
constructor(private readonly taskService: TaskService) {}
|
||||||
|
|
||||||
@Get()
|
|
||||||
@ApiOperation({ summary: 'Get all tasks, optionally filtered by phase' })
|
|
||||||
@ApiQuery({ name: 'taskPhaseId', required: false, description: 'Filter tasks by task phase ID' })
|
|
||||||
@ApiResponse({ status: 200, description: 'List of tasks', type: [TMTask] })
|
|
||||||
findAll(@Query('taskPhaseId') taskPhaseId?: string): Promise<TMTask[]> {
|
|
||||||
if (taskPhaseId) return this.taskService.findByPhase(taskPhaseId);
|
|
||||||
return this.taskService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(':id')
|
|
||||||
@ApiOperation({ summary: 'Get a task by ID' })
|
|
||||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
|
||||||
@ApiResponse({ status: 200, description: 'Task found', type: TMTask })
|
|
||||||
@ApiResponse({ status: 404, description: 'Task not found' })
|
|
||||||
findOne(@Param('id') id: string): Promise<TMTask> {
|
|
||||||
return this.taskService.findOne(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a new task' })
|
@PermissionsDec(PermissionEnum.TASK_CREATE)
|
||||||
@ApiResponse({ status: 201, description: 'Task created', type: TMTask })
|
@ApiOperation({ summary: "Create a new task" })
|
||||||
@ApiResponse({ status: 404, description: 'TaskPhase not found' })
|
@ApiResponse({ status: 201, description: "Task created", type: TMTask })
|
||||||
|
@ApiResponse({ status: 404, description: "TaskPhase not found" })
|
||||||
create(@Body() body: CreateTaskDto): Promise<TMTask> {
|
create(@Body() body: CreateTaskDto): Promise<TMTask> {
|
||||||
return this.taskService.create(body);
|
return this.taskService.create(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(":id")
|
||||||
@ApiOperation({ summary: 'Update a task' })
|
@PermissionsDec(PermissionEnum.TASK_UPDATE)
|
||||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
@ApiOperation({ summary: "Update a task" })
|
||||||
@ApiResponse({ status: 200, description: 'Task updated', type: TMTask })
|
@ApiParam({ name: "id", description: "Task ID" })
|
||||||
@ApiResponse({ status: 404, description: 'Task or TaskPhase not found' })
|
@ApiResponse({ status: 200, description: "Task updated", type: TMTask })
|
||||||
update(@Param('id') id: string, @Body() body: UpdateTaskDto): Promise<TMTask> {
|
@ApiResponse({ status: 404, description: "Task or TaskPhase not found" })
|
||||||
|
update(@Param("id") id: string, @Body() body: UpdateTaskDto): Promise<TMTask> {
|
||||||
return this.taskService.update(id, body);
|
return this.taskService.update(id, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id/change-phase')
|
@Patch(":id/change-phase")
|
||||||
@ApiOperation({ summary: 'Move a task to a different phase within the same project' })
|
@ApiOperation({ summary: "Move a task to a different phase within the same project" })
|
||||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
@ApiParam({ name: "id", description: "Task ID" })
|
||||||
@ApiResponse({ status: 200, description: 'Task phase changed', type: TMTask })
|
@ApiResponse({ status: 200, description: "Task phase changed", type: TMTask })
|
||||||
@ApiResponse({ status: 400, description: 'Target phase belongs to a different project' })
|
@ApiResponse({ status: 400, description: "Target phase belongs to a different project" })
|
||||||
@ApiResponse({ status: 404, description: 'Task or TaskPhase not found' })
|
@ApiResponse({ status: 404, description: "Task or TaskPhase not found" })
|
||||||
changePhase(@Param('id') id: string, @Body() body: ChangeTaskPhaseDto): Promise<TMTask> {
|
changePhase(@Param("id") id: string,@UserDec() user: ITokenPayload, @Body() body: ChangeTaskPhaseDto): Promise<TMTask> {
|
||||||
return this.taskService.changePhase(id, body);
|
return this.taskService.changePhase(id, user.permissions, user.id, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(":id")
|
||||||
@ApiOperation({ summary: 'Delete a task' })
|
@PermissionsDec(PermissionEnum.TASK_DELETE)
|
||||||
@ApiParam({ name: 'id', description: 'Task ID' })
|
@ApiOperation({ summary: "Delete a task" })
|
||||||
@ApiResponse({ status: 200, description: 'Task deleted' })
|
@ApiParam({ name: "id", description: "Task ID" })
|
||||||
@ApiResponse({ status: 404, description: 'Task not found' })
|
@ApiResponse({ status: 200, description: "Task deleted" })
|
||||||
remove(@Param('id') id: string): Promise<void> {
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
|
remove(@Param("id") id: string): Promise<void> {
|
||||||
return this.taskService.remove(id);
|
return this.taskService.remove(id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Get("detail/:id")
|
||||||
|
@ApiOperation({ summary: "Get Task Detail" })
|
||||||
|
@ApiParam({ name: "id", description: "Task ID" })
|
||||||
|
@ApiResponse({ status: 200, description: "Task detail received!" })
|
||||||
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
|
getTaskDetail(@UserDec() user: ITokenPayload, @Param() paramDto: ParamDto): Promise<TMTask | null> {
|
||||||
|
return this.taskService.getTaskDetail(user.id, user.permissions, paramDto.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("task-phase/:id")
|
||||||
|
@ApiOperation({ summary: "Get Tasks by task phase" })
|
||||||
|
@ApiParam({ name: "id", description: "Task phase id" })
|
||||||
|
@ApiResponse({ status: 200, description: "Got Tasks by task phase successfully!" })
|
||||||
|
@ApiResponse({ status: 400, description: "Bad request from user." })
|
||||||
|
@CursorPagination()
|
||||||
|
findByTaskPhase(
|
||||||
|
@Param("id") taskPhaseId: string,
|
||||||
|
@Query() pagination: CursorPaginationDto,
|
||||||
|
): Promise<{
|
||||||
|
data: TMTask[];
|
||||||
|
nextCursor: string | null;
|
||||||
|
previousCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
cursorPaginate: true;
|
||||||
|
}> {
|
||||||
|
return this.taskService.findTasksByTaskPhase(taskPhaseId, pagination);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch("change-priority/:srcid/:desid")
|
||||||
|
@ApiOperation({ summary: "changing the task priority" })
|
||||||
|
@ApiParam({ name: "srcid", description: "ID of the source task" })
|
||||||
|
@ApiParam({ name: "desid", description: "ID of the destination task" })
|
||||||
|
@ApiResponse({ status: 200, description: "Changed the task priority successfully!" })
|
||||||
|
@ApiResponse({ status: 400, description: "Bad Request from user." })
|
||||||
|
@ApiResponse({ status: 404, description: "Task not found!" })
|
||||||
|
changePriority(@Param("srcid") srcId: string, @Param("desid") desId: string,@UserDec() user: ITokenPayload): Promise<TMTask> {
|
||||||
|
return this.taskService.changePriority(srcId, user.permissions, user.id, desId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { Controller, Post, Patch, Delete, Param, Body, Get } from "@nestjs/common";
|
||||||
|
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
||||||
|
import { TimeService } from "../providers/time.service";
|
||||||
|
import { CreateTimeDto } from "../dto/time/create-time.dto";
|
||||||
|
import { UpdateTimeDto } from "../dto/time/update-time.dto";
|
||||||
|
import { TMTime } from "../entities/time.entity";
|
||||||
|
import { AuthGuards } from "../../../common/decorators/auth-guard.decorator";
|
||||||
|
import { AdminRoute } from "../../../common/decorators/admin.decorator";
|
||||||
|
import { UserDec } from "../../../common/decorators/user.decorator";
|
||||||
|
|
||||||
|
@AuthGuards()
|
||||||
|
@AdminRoute()
|
||||||
|
@ApiTags("Task Manager - Times")
|
||||||
|
@Controller("task-manager/times")
|
||||||
|
export class TimeController {
|
||||||
|
constructor(private readonly timeService: TimeService) { }
|
||||||
|
@Get("task/:taskId")
|
||||||
|
@ApiOperation({ summary: "Get all time entries for a task" })
|
||||||
|
@ApiParam({ name: "taskId", description: "Task ID" })
|
||||||
|
getTaskTimes(@UserDec("id") adminId: string, @Param("taskId") taskId: string): Promise<TMTime[]> {
|
||||||
|
return this.timeService.getTaskTimes(adminId, taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post()
|
||||||
|
@ApiOperation({ summary: "Create a new time entry for a task" })
|
||||||
|
@ApiResponse({ status: 201, description: "Time entry created", type: TMTime })
|
||||||
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
|
create(@UserDec("id") adminId: string, @Body() body: CreateTimeDto): Promise<TMTime> {
|
||||||
|
return this.timeService.create(adminId, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("start/:taskId")
|
||||||
|
@ApiOperation({ summary: "Start tracking time for a task" })
|
||||||
|
@ApiParam({ name: "taskId", description: "Task ID" })
|
||||||
|
@ApiResponse({ status: 201, description: "Time tracking started", type: TMTime })
|
||||||
|
@ApiResponse({ status: 400, description: "A running time entry already exists" })
|
||||||
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
|
start(@UserDec("id") adminId: string, @Param("taskId") taskId: string): Promise<TMTime> {
|
||||||
|
return this.timeService.start(adminId, taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Post("end/:taskId")
|
||||||
|
@ApiOperation({ summary: "Stop the current running time entry for a task" })
|
||||||
|
@ApiParam({ name: "taskId", description: "Task ID" })
|
||||||
|
@ApiResponse({ status: 200, description: "Time tracking stopped", type: TMTime })
|
||||||
|
@ApiResponse({ status: 400, description: "No running time entry found" })
|
||||||
|
@ApiResponse({ status: 404, description: "Task not found" })
|
||||||
|
end(@UserDec("id") adminId: string, @Param("taskId") taskId: string): Promise<TMTime> {
|
||||||
|
return this.timeService.end(adminId, taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch(":id")
|
||||||
|
@ApiOperation({ summary: "Update a time entry" })
|
||||||
|
@ApiParam({ name: "id", description: "Time entry ID" })
|
||||||
|
@ApiResponse({ status: 200, description: "Time entry updated", type: TMTime })
|
||||||
|
@ApiResponse({ status: 404, description: "Time entry or Task not found" })
|
||||||
|
update(@Param("id") id: string, @Body() body: UpdateTimeDto): Promise<TMTime> {
|
||||||
|
return this.timeService.update(id, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete(":id")
|
||||||
|
@ApiOperation({ summary: "Delete a time entry" })
|
||||||
|
@ApiParam({ name: "id", description: "Time entry ID" })
|
||||||
|
@ApiResponse({ status: 200, description: "Time entry deleted" })
|
||||||
|
@ApiResponse({ status: 404, description: "Time entry not found" })
|
||||||
|
remove(@Param("id") id: string): Promise<void> {
|
||||||
|
return this.timeService.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
import { Controller, Get, Post, Patch, Delete, Param, Body } from "@nestjs/common";
|
|
||||||
import { ApiTags, ApiOperation, ApiResponse, ApiParam } from "@nestjs/swagger";
|
|
||||||
import { WorkspaceTypeService } from "../providers/workspace-type.service";
|
|
||||||
import { CreateWorkspaceTypeDto } from "../dto/workspace-type/create-workspace-type.dto";
|
|
||||||
import { UpdateWorkspaceTypeDto } from "../dto/workspace-type/update-workspace-type.dto";
|
|
||||||
import { TMWorkspaceType } from "../entities/workspace-type.entity";
|
|
||||||
|
|
||||||
@ApiTags("Task Manager")
|
|
||||||
@Controller("task-manager/workspace-types")
|
|
||||||
export class WorkspaceTypeController {
|
|
||||||
constructor(private readonly workspaceTypeService: WorkspaceTypeService) {}
|
|
||||||
|
|
||||||
@Get()
|
|
||||||
@ApiOperation({ summary: "Get all workspace types" })
|
|
||||||
@ApiResponse({ status: 200, description: "List of workspace types", type: [TMWorkspaceType] })
|
|
||||||
findAll(): Promise<TMWorkspaceType[]> {
|
|
||||||
return this.workspaceTypeService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(":id")
|
|
||||||
@ApiOperation({ summary: "Get a workspace type by ID" })
|
|
||||||
@ApiParam({ name: "id", description: "WorkspaceType ID" })
|
|
||||||
@ApiResponse({ status: 200, description: "WorkspaceType found", type: TMWorkspaceType })
|
|
||||||
@ApiResponse({ status: 404, description: "WorkspaceType not found" })
|
|
||||||
findOne(@Param("id") id: string): Promise<TMWorkspaceType> {
|
|
||||||
return this.workspaceTypeService.findOne(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Post()
|
|
||||||
@ApiOperation({ summary: "Create a new workspace type" })
|
|
||||||
@ApiResponse({ status: 201, description: "WorkspaceType created", type: TMWorkspaceType })
|
|
||||||
@ApiResponse({ status: 409, description: "WorkspaceType with this name already exists" })
|
|
||||||
create(@Body() body: CreateWorkspaceTypeDto): Promise<TMWorkspaceType> {
|
|
||||||
return this.workspaceTypeService.create(body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Patch(":id")
|
|
||||||
@ApiOperation({ summary: "Update a workspace type" })
|
|
||||||
@ApiParam({ name: "id", description: "WorkspaceType ID" })
|
|
||||||
@ApiResponse({ status: 200, description: "WorkspaceType updated", type: TMWorkspaceType })
|
|
||||||
@ApiResponse({ status: 404, description: "WorkspaceType not found" })
|
|
||||||
@ApiResponse({ status: 409, description: "WorkspaceType with this name already exists" })
|
|
||||||
update(@Param("id") id: string, @Body() body: UpdateWorkspaceTypeDto): Promise<TMWorkspaceType> {
|
|
||||||
return this.workspaceTypeService.update(id, body);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Delete(":id")
|
|
||||||
@ApiOperation({ summary: "Delete a workspace type" })
|
|
||||||
@ApiParam({ name: "id", description: "WorkspaceType ID" })
|
|
||||||
@ApiResponse({ status: 200, description: "WorkspaceType deleted" })
|
|
||||||
@ApiResponse({ status: 404, description: "WorkspaceType not found" })
|
|
||||||
remove(@Param("id") id: string): Promise<TMWorkspaceType> {
|
|
||||||
return this.workspaceTypeService.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,29 +4,32 @@ import { WorkspaceService } from '../providers/workspace.service';
|
|||||||
import { CreateWorkspaceDto } from '../dto/workspace/create-workspace.dto';
|
import { CreateWorkspaceDto } from '../dto/workspace/create-workspace.dto';
|
||||||
import { UpdateWorkspaceDto } from '../dto/workspace/update-workspace.dto';
|
import { UpdateWorkspaceDto } from '../dto/workspace/update-workspace.dto';
|
||||||
import { TMWorkspace } from '../entities/workspace.entity';
|
import { TMWorkspace } from '../entities/workspace.entity';
|
||||||
|
import { AdminRoute } from '../../../common/decorators/admin.decorator';
|
||||||
|
import { PermissionsDec } from '../../../common/decorators/permission.decorator';
|
||||||
|
import { PermissionEnum } from '../../users/enums/permission.enum';
|
||||||
|
import { UserDec } from '../../../common/decorators/user.decorator';
|
||||||
|
import { AuthGuards } from '../../../common/decorators/auth-guard.decorator';
|
||||||
|
import { ITokenPayload } from '../../auth/interfaces/IToken-payload';
|
||||||
|
|
||||||
@ApiTags('Task Manager')
|
@AuthGuards()
|
||||||
|
@AdminRoute()
|
||||||
|
@ApiTags('Task Manager - Workspaces')
|
||||||
@Controller('task-manager/workspaces')
|
@Controller('task-manager/workspaces')
|
||||||
export class WorkspaceController {
|
export class WorkspaceController {
|
||||||
constructor(private readonly workspaceService: WorkspaceService) {}
|
constructor(private readonly workspaceService: WorkspaceService) {}
|
||||||
|
|
||||||
@Get()
|
|
||||||
@ApiOperation({ summary: 'Get all workspaces' })
|
|
||||||
@ApiResponse({ status: 200, description: 'List of workspaces', type: [TMWorkspace] })
|
|
||||||
findAll(): Promise<TMWorkspace[]> {
|
|
||||||
return this.workspaceService.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Get(':id')
|
@Get(':id')
|
||||||
@ApiOperation({ summary: 'Get a workspace by ID' })
|
@PermissionsDec(PermissionEnum.WORKSPACE_READ)
|
||||||
@ApiParam({ name: 'id', description: 'Workspace ID' })
|
@ApiOperation({summary: "Get one workspace by ID"})
|
||||||
@ApiResponse({ status: 200, description: 'Workspace found', type: TMWorkspace })
|
@ApiResponse({status: 200, description: 'Received workspace', type: TMWorkspace})
|
||||||
@ApiResponse({ status: 404, description: 'Workspace not found' })
|
@ApiResponse({status: 404, description: 'Workspace Not Found!'})
|
||||||
|
@ApiResponse({status: 400, description: 'Bad Request!'})
|
||||||
findOne(@Param('id') id: string): Promise<TMWorkspace> {
|
findOne(@Param('id') id: string): Promise<TMWorkspace> {
|
||||||
return this.workspaceService.findOneOrFail(id);
|
return this.workspaceService.findOneOrFail(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
|
@PermissionsDec(PermissionEnum.WORKSPACE_CREATE)
|
||||||
@ApiOperation({ summary: 'Create a new workspace' })
|
@ApiOperation({ summary: 'Create a new workspace' })
|
||||||
@ApiResponse({ status: 201, description: 'Workspace created', type: TMWorkspace })
|
@ApiResponse({ status: 201, description: 'Workspace created', type: TMWorkspace })
|
||||||
create(@Body() body: CreateWorkspaceDto): Promise<TMWorkspace> {
|
create(@Body() body: CreateWorkspaceDto): Promise<TMWorkspace> {
|
||||||
@@ -34,6 +37,7 @@ export class WorkspaceController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@Patch(':id')
|
||||||
|
@PermissionsDec(PermissionEnum.WORKSPACE_UPDATE)
|
||||||
@ApiOperation({ summary: 'Update a workspace' })
|
@ApiOperation({ summary: 'Update a workspace' })
|
||||||
@ApiParam({ name: 'id', description: 'Workspace ID' })
|
@ApiParam({ name: 'id', description: 'Workspace ID' })
|
||||||
@ApiResponse({ status: 200, description: 'Workspace updated', type: TMWorkspace })
|
@ApiResponse({ status: 200, description: 'Workspace updated', type: TMWorkspace })
|
||||||
@@ -43,6 +47,7 @@ export class WorkspaceController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Delete(':id')
|
@Delete(':id')
|
||||||
|
@PermissionsDec(PermissionEnum.WORKSPACE_DELETE)
|
||||||
@ApiOperation({ summary: 'Delete a workspace' })
|
@ApiOperation({ summary: 'Delete a workspace' })
|
||||||
@ApiParam({ name: 'id', description: 'Workspace ID' })
|
@ApiParam({ name: 'id', description: 'Workspace ID' })
|
||||||
@ApiResponse({ status: 200, description: 'Workspace deleted' })
|
@ApiResponse({ status: 200, description: 'Workspace deleted' })
|
||||||
@@ -50,4 +55,12 @@ export class WorkspaceController {
|
|||||||
remove(@Param('id') id: string): Promise<TMWorkspace> {
|
remove(@Param('id') id: string): Promise<TMWorkspace> {
|
||||||
return this.workspaceService.remove(id);
|
return this.workspaceService.remove(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get('byuser')
|
||||||
|
@ApiOperation({summary: 'Get User WorkSpaces'})
|
||||||
|
@ApiResponse({ status: 200, description: 'Got Workspaces successfully!' })
|
||||||
|
@ApiResponse({ status: 404, description: 'Bad Request!' })
|
||||||
|
findByUser(@UserDec() user: ITokenPayload) {
|
||||||
|
return this.workspaceService.findByUser(user.id, user.permissions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsString, IsNotEmpty, IsUUID, IsEnum, MaxLength } from "class-validator";
|
||||||
|
import { TMAttachmentType } from "../../enums/attachment-type.enum";
|
||||||
|
|
||||||
|
export class CreateAttachmentDto {
|
||||||
|
@ApiProperty({ description: "Title of the attachment", example: "Project Requirements Doc" })
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@MaxLength(150)
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "Type of the attachment", enum: TMAttachmentType, example: TMAttachmentType.FILE })
|
||||||
|
@IsEnum(TMAttachmentType)
|
||||||
|
@IsNotEmpty()
|
||||||
|
type: TMAttachmentType;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "File URL or path of the attachment", example: "https://cdn.example.com/files/requirements.pdf" })
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
file: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "ID of the task this attachment belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||||
|
@IsUUID()
|
||||||
|
@IsNotEmpty()
|
||||||
|
taskId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from "@nestjs/swagger";
|
||||||
|
import { CreateAttachmentDto } from "./create-attachment.dto";
|
||||||
|
|
||||||
|
export class UpdateAttachmentDto extends PartialType(CreateAttachmentDto) {}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsString, IsNotEmpty, IsUUID, IsOptional, MaxLength } from "class-validator";
|
||||||
|
|
||||||
|
export class CreateRemarkDto {
|
||||||
|
@ApiProperty({ description: "Title of the remark", example: "This task needs review" })
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@MaxLength(150)
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "Color code for the remark", required: false, example: "#F59E0B" })
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@MaxLength(20)
|
||||||
|
color?: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "ID of the task this remark belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||||
|
@IsUUID()
|
||||||
|
@IsNotEmpty()
|
||||||
|
taskId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from "@nestjs/swagger";
|
||||||
|
import { CreateRemarkDto } from "./create-remark.dto";
|
||||||
|
|
||||||
|
export class UpdateRemarkDto extends PartialType(CreateRemarkDto) {}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsDateString, IsNotEmpty, IsUUID } from "class-validator";
|
||||||
|
|
||||||
|
export class CreateTimeDto {
|
||||||
|
@ApiProperty({ description: "Start time of the entry", example: "2026-07-15T08:00:00.000Z" })
|
||||||
|
@IsDateString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
startedAt: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "End time of the entry", example: "2026-07-15T10:30:00.000Z" })
|
||||||
|
@IsDateString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
endedAt: string;
|
||||||
|
|
||||||
|
@ApiProperty({ description: "ID of the task this time entry belongs to", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
||||||
|
@IsUUID()
|
||||||
|
@IsNotEmpty()
|
||||||
|
taskId: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
import { PartialType } from "@nestjs/swagger";
|
||||||
|
import { CreateTimeDto } from "./create-time.dto";
|
||||||
|
|
||||||
|
export class UpdateTimeDto extends PartialType(CreateTimeDto) {}
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { ApiProperty } from "@nestjs/swagger";
|
|
||||||
import { IsString, IsOptional, IsInt, IsNotEmpty, MaxLength, Min } from "class-validator";
|
|
||||||
|
|
||||||
export class CreateWorkspaceTypeDto {
|
|
||||||
@ApiProperty({ description: "Name of the workspace type", example: "Engineering" })
|
|
||||||
@IsString()
|
|
||||||
@IsNotEmpty()
|
|
||||||
@MaxLength(100)
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@ApiProperty({
|
|
||||||
description: "Description of the workspace type",
|
|
||||||
required: false,
|
|
||||||
example: "Workspace type for engineering related work",
|
|
||||||
})
|
|
||||||
@IsString()
|
|
||||||
@IsOptional()
|
|
||||||
description?: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: "Display order of the workspace type", example: 1 })
|
|
||||||
@IsInt()
|
|
||||||
@IsNotEmpty()
|
|
||||||
@Min(0)
|
|
||||||
order: number;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
import { PartialType } from '@nestjs/swagger';
|
|
||||||
import { CreateWorkspaceTypeDto } from './create-workspace-type.dto';
|
|
||||||
|
|
||||||
export class UpdateWorkspaceTypeDto extends PartialType(CreateWorkspaceTypeDto) {}
|
|
||||||
@@ -8,11 +8,6 @@ export class CreateWorkspaceDto {
|
|||||||
@MaxLength(100)
|
@MaxLength(100)
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@ApiProperty({ description: "ID of the workspace type", example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" })
|
|
||||||
@IsUUID()
|
|
||||||
@IsNotEmpty()
|
|
||||||
workspaceTypeId: string;
|
|
||||||
|
|
||||||
@ApiProperty({ description: "Description of the workspace", required: false, example: "Workspace for the engineering team" })
|
@ApiProperty({ description: "Description of the workspace", required: false, example: "Workspace for the engineering team" })
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { TMTaskPhase } from "./task-phase.entity";
|
|||||||
import { TMRemark } from "./remark.entity";
|
import { TMRemark } from "./remark.entity";
|
||||||
import { TMAttachment } from "./attachment.entity";
|
import { TMAttachment } from "./attachment.entity";
|
||||||
import { TMCheckListItem } from "./check-list-item.entity";
|
import { TMCheckListItem } from "./check-list-item.entity";
|
||||||
|
import { TMTime } from "./time.entity";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
|
||||||
@Entity("tm_tasks")
|
@Entity("tm_tasks")
|
||||||
@@ -23,6 +24,9 @@ export class TMTask extends BaseEntity {
|
|||||||
@Column({ type: "timestamptz", nullable: true })
|
@Column({ type: "timestamptz", nullable: true })
|
||||||
endDate: Date;
|
endDate: Date;
|
||||||
|
|
||||||
|
@Column({type: 'int', default: 1})
|
||||||
|
priority: number;
|
||||||
|
|
||||||
// --- Relations ---
|
// --- Relations ---
|
||||||
|
|
||||||
@ManyToOne(() => TMTaskPhase, (taskPhase) => taskPhase.tasks, {
|
@ManyToOne(() => TMTaskPhase, (taskPhase) => taskPhase.tasks, {
|
||||||
@@ -50,6 +54,11 @@ export class TMTask extends BaseEntity {
|
|||||||
})
|
})
|
||||||
checkListItems: TMCheckListItem[];
|
checkListItems: TMCheckListItem[];
|
||||||
|
|
||||||
|
@OneToMany(() => TMTime, (time) => time.task, {
|
||||||
|
cascade: ["insert", "update"],
|
||||||
|
})
|
||||||
|
times: TMTime[];
|
||||||
|
|
||||||
@ManyToMany(() => User, (user) => user.tasks)
|
@ManyToMany(() => User, (user) => user.tasks)
|
||||||
@JoinTable({
|
@JoinTable({
|
||||||
name: "tm_task_users",
|
name: "tm_task_users",
|
||||||
@@ -57,4 +66,10 @@ export class TMTask extends BaseEntity {
|
|||||||
inverseJoinColumn: { name: "userId", referencedColumnName: "id" },
|
inverseJoinColumn: { name: "userId", referencedColumnName: "id" },
|
||||||
})
|
})
|
||||||
users: User[];
|
users: User[];
|
||||||
|
|
||||||
|
// deriven(calculated) attributes. not database columns
|
||||||
|
attachmentCount?: number;
|
||||||
|
checkListItemCount?: number;
|
||||||
|
completedCheckListItemCount?: number;
|
||||||
|
time?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { Column, Entity, JoinColumn, ManyToOne } from "typeorm";
|
||||||
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
|
import { TMTask } from "./task.entity";
|
||||||
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
|
||||||
|
@Entity("tm_times")
|
||||||
|
export class TMTime extends BaseEntity {
|
||||||
|
@Column({ type: "timestamptz" })
|
||||||
|
startedAt: Date;
|
||||||
|
|
||||||
|
@Column({ type: "timestamptz", nullable: true })
|
||||||
|
endedAt: Date | null;
|
||||||
|
|
||||||
|
@Column({ type: "int", nullable: true })
|
||||||
|
duration: number | null;
|
||||||
|
|
||||||
|
// --- Relations ---
|
||||||
|
|
||||||
|
@ManyToOne(() => User, {
|
||||||
|
nullable: false,
|
||||||
|
onDelete: "RESTRICT",
|
||||||
|
})
|
||||||
|
@JoinColumn({ name: "adminId" })
|
||||||
|
admin: User;
|
||||||
|
|
||||||
|
@Column({ type: "uuid" })
|
||||||
|
adminId: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => TMTask, (task) => task.times, {
|
||||||
|
nullable: false,
|
||||||
|
onDelete: "CASCADE",
|
||||||
|
})
|
||||||
|
@JoinColumn({ name: "taskId" })
|
||||||
|
task: TMTask;
|
||||||
|
|
||||||
|
@Column({ type: "uuid" })
|
||||||
|
taskId: string;
|
||||||
|
}
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { Column, Entity, OneToMany } from "typeorm";
|
|
||||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
|
||||||
import { TMWorkspace } from "./workspace.entity";
|
|
||||||
|
|
||||||
@Entity("tm_workspace_types")
|
|
||||||
export class TMWorkspaceType extends BaseEntity {
|
|
||||||
@Column({ type: "varchar", length: 100, unique: true })
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
@Column({ type: "text", nullable: true })
|
|
||||||
description: string;
|
|
||||||
|
|
||||||
@Column({ type: "int", default: 0 })
|
|
||||||
order: number;
|
|
||||||
|
|
||||||
// --- Relations ---
|
|
||||||
|
|
||||||
@OneToMany(() => TMWorkspace, (workspace) => workspace.workspaceType)
|
|
||||||
workspaces: TMWorkspace[];
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany } from "typeorm";
|
import { Column, Entity, JoinTable, ManyToMany, OneToMany } from "typeorm";
|
||||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
import { TMWorkspaceType } from "./workspace-type.entity";
|
|
||||||
import { TMProject } from "./project.entity";
|
import { TMProject } from "./project.entity";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
|
||||||
@Entity("tm_workspaces")
|
@Entity("tm_workspaces")
|
||||||
export class TMWorkspace extends BaseEntity {
|
export class TMWorkspace extends BaseEntity {
|
||||||
@Column({ type: "varchar", length: 100 })
|
@Column({ type: "varchar", length: 100, unique: true })
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
@Column({ type: "text", nullable: true })
|
@Column({ type: "text", nullable: true })
|
||||||
@@ -20,13 +19,6 @@ export class TMWorkspace extends BaseEntity {
|
|||||||
|
|
||||||
// --- Relations ---
|
// --- Relations ---
|
||||||
|
|
||||||
@ManyToOne(() => TMWorkspaceType, { nullable: false, eager: true })
|
|
||||||
@JoinColumn({ name: "workspaceTypeId" })
|
|
||||||
workspaceType: TMWorkspaceType;
|
|
||||||
|
|
||||||
@Column({ type: "uuid" })
|
|
||||||
workspaceTypeId: string;
|
|
||||||
|
|
||||||
@OneToMany(() => TMProject, (project) => project.workspace, {
|
@OneToMany(() => TMProject, (project) => project.workspace, {
|
||||||
cascade: ["insert", "update"],
|
cascade: ["insert", "update"],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||||
|
import { AttachmentRepository } from "../repositories/attachment.repository";
|
||||||
|
import { TMAttachment } from "../entities/attachment.entity";
|
||||||
|
import { CreateAttachmentDto } from "../dto/attachment/create-attachment.dto";
|
||||||
|
import { UpdateAttachmentDto } from "../dto/attachment/update-attachment.dto";
|
||||||
|
import { attachmentMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { TaskService } from "./task.service";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AttachmentService {
|
||||||
|
constructor(
|
||||||
|
private readonly attachmentRepository: AttachmentRepository,
|
||||||
|
private readonly taskService: TaskService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async findOneOrFail(id: string): Promise<TMAttachment> {
|
||||||
|
const attachment = await this.attachmentRepository.findOne({ where: { id }, relations: { task: true } });
|
||||||
|
if (!attachment) throw new NotFoundException(attachmentMessage.ATTACHMENT_NOT_FOUND);
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(dto: CreateAttachmentDto): Promise<TMAttachment> {
|
||||||
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
|
|
||||||
|
const attachment = this.attachmentRepository.create(dto);
|
||||||
|
return this.attachmentRepository.save(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateAttachmentDto): Promise<TMAttachment> {
|
||||||
|
const attachment = await this.findOneOrFail(id);
|
||||||
|
|
||||||
|
if (dto.taskId) {
|
||||||
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(attachment, dto);
|
||||||
|
return this.attachmentRepository.save(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string): Promise<void> {
|
||||||
|
await this.findOneOrFail(id);
|
||||||
|
await this.attachmentRepository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,53 +1,54 @@
|
|||||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||||
import { CheckListItemRepository } from "../repositories/check-list-item.repository";
|
import { CheckListItemRepository } from '../repositories/check-list-item.repository';
|
||||||
import { TaskRepository } from "../repositories/task.repository";
|
import { TMCheckListItem } from '../entities/check-list-item.entity';
|
||||||
import { TMCheckListItem } from "../entities/check-list-item.entity";
|
import { CreateCheckListItemDto } from '../dto/check-list-item/create-check-list-item.dto';
|
||||||
import { CreateCheckListItemDto } from "../dto/check-list-item/create-check-list-item.dto";
|
import { UpdateCheckListItemDto } from '../dto/check-list-item/update-check-list-item.dto';
|
||||||
import { UpdateCheckListItemDto } from "../dto/check-list-item/update-check-list-item.dto";
|
import { checkListItemMessage } from '../../../common/enums/message.enum';
|
||||||
|
import { TaskService } from './task.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckListItemService {
|
export class CheckListItemService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly checkListItemRepository: CheckListItemRepository,
|
private readonly checkListItemRepository: CheckListItemRepository,
|
||||||
private readonly taskRepository: TaskRepository,
|
private readonly taskService: TaskService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<TMCheckListItem[]> {
|
async findOneOrFail(id: string): Promise<TMCheckListItem> {
|
||||||
return this.checkListItemRepository.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
findByTask(taskId: string): Promise<TMCheckListItem[]> {
|
|
||||||
return this.checkListItemRepository.findByTask(taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async findOne(id: string): Promise<TMCheckListItem> {
|
|
||||||
const checkListItem = await this.checkListItemRepository.findOneById(id);
|
const checkListItem = await this.checkListItemRepository.findOneById(id);
|
||||||
if (!checkListItem) throw new NotFoundException(`CheckListItem #${id} not found`);
|
if (!checkListItem) throw new NotFoundException(checkListItemMessage.CHECKLISTITEM_NOT_FOUND);
|
||||||
return checkListItem;
|
return checkListItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(dto: CreateCheckListItemDto): Promise<TMCheckListItem> {
|
async create(dto: CreateCheckListItemDto): Promise<TMCheckListItem> {
|
||||||
const task = await this.taskRepository.findOneById(dto.taskId);
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
if (!task) throw new NotFoundException(`Task #${dto.taskId} not found`);
|
|
||||||
|
|
||||||
const checkListItem = this.checkListItemRepository.create(dto);
|
const checkListItem = this.checkListItemRepository.create(dto);
|
||||||
return this.checkListItemRepository.save(checkListItem);
|
return this.checkListItemRepository.save(checkListItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, dto: UpdateCheckListItemDto): Promise<TMCheckListItem> {
|
async update(id: string, dto: UpdateCheckListItemDto): Promise<TMCheckListItem> {
|
||||||
const checkListItem = await this.findOne(id);
|
const checkListItem = await this.findOneOrFail(id);
|
||||||
|
|
||||||
if (dto.taskId) {
|
if (dto.taskId) {
|
||||||
const task = await this.taskRepository.findOneById(dto.taskId);
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
if (!task) throw new NotFoundException(`Task #${dto.taskId} not found`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(checkListItem, dto);
|
Object.assign(checkListItem, dto);
|
||||||
return this.checkListItemRepository.save(checkListItem);
|
return this.checkListItemRepository.save(checkListItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<TMCheckListItem> {
|
||||||
await this.findOne(id);
|
const checkListItem = await this.findOneOrFail(id);
|
||||||
await this.checkListItemRepository.delete(id);
|
await this.checkListItemRepository.delete(id);
|
||||||
|
return checkListItem;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
async toggleStatus(id: string) : Promise<TMCheckListItem> {
|
||||||
|
const checkListItem = await this.findOneOrFail(id);
|
||||||
|
const isDone = checkListItem.isDone;
|
||||||
|
checkListItem.isDone = !isDone;
|
||||||
|
await this.checkListItemRepository.save(checkListItem);
|
||||||
|
|
||||||
|
return checkListItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,41 +1,52 @@
|
|||||||
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
|
||||||
import { InjectRepository } from "@nestjs/typeorm";
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { In, Repository } from "typeorm";
|
import { In, Repository } from "typeorm";
|
||||||
import { ProjectRepository } from "../repositories/project.repository";
|
import { ProjectRepository } from "../repositories/project.repository";
|
||||||
import { TMProject } from "../entities/project.entity";
|
import { TMProject } from "../entities/project.entity";
|
||||||
import { CreateProjectDto } from "../dto/project/create-project.dto";
|
import { CreateProjectDto } from "../dto/project/create-project.dto";
|
||||||
import { UpdateProjectDto } from "../dto/project/update-project.dto";
|
import { UpdateProjectDto } from "../dto/project/update-project.dto";
|
||||||
|
import { PaginationDto } from "../../../common/DTO/pagination.dto";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { WorkspaceRepository } from "../repositories/workspace.repository";
|
import { ProjectMessage, WorkSpaceMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { WorkspaceService } from "./workspace.service";
|
||||||
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProjectService {
|
export class ProjectService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly projectRepository: ProjectRepository,
|
private readonly projectRepository: ProjectRepository,
|
||||||
private readonly workspaceRepository: WorkspaceRepository,
|
private readonly workspaceService: WorkspaceService,
|
||||||
@InjectRepository(User)
|
@InjectRepository(User)
|
||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<TMProject[]> {
|
async findOneOrFail(id: string): Promise<TMProject> {
|
||||||
return this.projectRepository.findAll();
|
const project = await this.projectRepository.findOne({
|
||||||
}
|
where: { id },
|
||||||
|
relations: {
|
||||||
findByWorkspace(workspaceId: string): Promise<TMProject[]> {
|
users: true,
|
||||||
return this.projectRepository.findByWorkspace(workspaceId);
|
taskPhases: true
|
||||||
}
|
},
|
||||||
|
select: {
|
||||||
async findOne(id: string): Promise<TMProject> {
|
users: {
|
||||||
const project = await this.projectRepository.findOneById(id);
|
id: true,
|
||||||
if (!project) throw new NotFoundException(`Project #${id} not found`);
|
firstName: true,
|
||||||
|
lastName: true
|
||||||
|
},
|
||||||
|
taskPhases: {
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!project) throw new NotFoundException(ProjectMessage.PROJECT_NOT_FOUND);
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(dto: CreateProjectDto): Promise<TMProject> {
|
async create(dto: CreateProjectDto): Promise<TMProject> {
|
||||||
const { userIds, startDate, ...rest } = dto;
|
const { userIds, startDate, ...rest } = dto;
|
||||||
|
|
||||||
const workspace = await this.workspaceRepository.findOneById(dto.workspaceId);
|
const workspace = await this.workspaceService.findOneOrFail(dto.workspaceId);
|
||||||
if (!workspace) throw new NotFoundException(`Workspace #${dto.workspaceId} not found`);
|
|
||||||
|
|
||||||
const project = this.projectRepository.create({
|
const project = this.projectRepository.create({
|
||||||
...rest,
|
...rest,
|
||||||
@@ -46,7 +57,7 @@ export class ProjectService {
|
|||||||
const workspaceUserIds = workspace.users.map((u) => u.id);
|
const workspaceUserIds = workspace.users.map((u) => u.id);
|
||||||
const invalidUsers = userIds.filter((id) => !workspaceUserIds.includes(id));
|
const invalidUsers = userIds.filter((id) => !workspaceUserIds.includes(id));
|
||||||
if (invalidUsers.length) {
|
if (invalidUsers.length) {
|
||||||
throw new BadRequestException(`Users [${invalidUsers.join(", ")}] are not members of this workspace`);
|
throw new BadRequestException(WorkSpaceMessage.USERS_DONT_BELONG_TO_THIS_WORKSPACE);
|
||||||
}
|
}
|
||||||
project.users = await this.userRepository.findBy({ id: In(userIds) });
|
project.users = await this.userRepository.findBy({ id: In(userIds) });
|
||||||
}
|
}
|
||||||
@@ -55,7 +66,8 @@ export class ProjectService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, dto: UpdateProjectDto): Promise<TMProject> {
|
async update(id: string, dto: UpdateProjectDto): Promise<TMProject> {
|
||||||
const project = await this.findOne(id);
|
const project = await this.findOneOrFail(id);
|
||||||
|
|
||||||
const { userIds, startDate, ...rest } = dto;
|
const { userIds, startDate, ...rest } = dto;
|
||||||
|
|
||||||
Object.assign(project, {
|
Object.assign(project, {
|
||||||
@@ -66,13 +78,12 @@ export class ProjectService {
|
|||||||
if (userIds) {
|
if (userIds) {
|
||||||
if (userIds.length) {
|
if (userIds.length) {
|
||||||
const workspaceId = dto.workspaceId ?? project.workspaceId;
|
const workspaceId = dto.workspaceId ?? project.workspaceId;
|
||||||
const workspace = await this.workspaceRepository.findOneById(workspaceId);
|
const workspace = await this.workspaceService.findOneOrFail(workspaceId);
|
||||||
if (!workspace) throw new NotFoundException(`Workspace #${workspaceId} not found`);
|
|
||||||
|
|
||||||
const workspaceUserIds = workspace.users.map((u) => u.id);
|
const workspaceUserIds = workspace.users.map((u) => u.id);
|
||||||
const invalidUsers = userIds.filter((uid) => !workspaceUserIds.includes(uid));
|
const invalidUsers = userIds.filter((uid) => !workspaceUserIds.includes(uid));
|
||||||
if (invalidUsers.length) {
|
if (invalidUsers.length) {
|
||||||
throw new BadRequestException(`Users [${invalidUsers.join(", ")}] are not members of this workspace`);
|
throw new BadRequestException(WorkSpaceMessage.USERS_DONT_BELONG_TO_THIS_WORKSPACE);
|
||||||
}
|
}
|
||||||
project.users = await this.userRepository.findBy({ id: In(userIds) });
|
project.users = await this.userRepository.findBy({ id: In(userIds) });
|
||||||
} else {
|
} else {
|
||||||
@@ -84,9 +95,74 @@ export class ProjectService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<TMProject> {
|
async remove(id: string): Promise<TMProject> {
|
||||||
const project = await this.findOne(id);
|
const project = await this.projectRepository.findOne({
|
||||||
await this.projectRepository.delete(id);
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
relations: {
|
||||||
|
taskPhases: true,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
taskPhases: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!project) throw new NotFoundException(ProjectMessage.PROJECT_NOT_FOUND);
|
||||||
|
|
||||||
|
const taskPhases = project.taskPhases;
|
||||||
|
if (taskPhases !== undefined && taskPhases.length) {
|
||||||
|
throw new BadRequestException(ProjectMessage.PROJECT_CONTAINS_TASK_PHASES);
|
||||||
|
}
|
||||||
|
await this.projectRepository.delete(id);
|
||||||
return project;
|
return project;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findUserProjectsByWorkspace(
|
||||||
|
userId: string,
|
||||||
|
permissions: PermissionEnum[],
|
||||||
|
wsId: string,
|
||||||
|
pagination: PaginationDto,
|
||||||
|
): Promise<{ projects: TMProject[]; count: number; paginate: true }> {
|
||||||
|
const workspace = await this.workspaceService.findOneOrFail(wsId);
|
||||||
|
|
||||||
|
const page = pagination.page ?? 1;
|
||||||
|
const limit = pagination.limit ?? 10;
|
||||||
|
const skip = (page - 1) * limit;
|
||||||
|
|
||||||
|
const isPermissionIncluded = permissions.includes(PermissionEnum.PROJECT_READ);
|
||||||
|
const isUserMemeberOfWorkspace = workspace.users.some((user) => user.id === userId);
|
||||||
|
|
||||||
|
var res: [TMProject[], number];
|
||||||
|
if (isUserMemeberOfWorkspace && !isPermissionIncluded) {
|
||||||
|
res = await this.projectRepository.findUserProjects(userId, wsId, skip, limit);
|
||||||
|
} else if (isPermissionIncluded) {
|
||||||
|
res = await this.projectRepository.findAndCount({ where: { workspaceId: wsId } });
|
||||||
|
} else {
|
||||||
|
throw new ForbiddenException(WorkSpaceMessage.FORBIDDEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
const [projects, count] = res;
|
||||||
|
|
||||||
|
return { projects, count, paginate: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProjectDetail(projectId: string, userId: string, permissions: PermissionEnum[]): Promise<TMProject | null> {
|
||||||
|
const project = await this.projectRepository.findOne({
|
||||||
|
where: { id: projectId },
|
||||||
|
relations: {
|
||||||
|
users: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!project) throw new NotFoundException(ProjectMessage.PROJECT_NOT_FOUND);
|
||||||
|
|
||||||
|
const isUserMember = project.users.some((user) => user.id === userId);
|
||||||
|
if (!isUserMember && !permissions.includes(PermissionEnum.PROJECT_READ))
|
||||||
|
throw new ForbiddenException(ProjectMessage.NOT_MEMBER_OF_PROJECT);
|
||||||
|
|
||||||
|
const projectDetail = await this.projectRepository.getProjectDetail(projectId);
|
||||||
|
|
||||||
|
return projectDetail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||||
|
import { RemarkRepository } from "../repositories/remark.repository";
|
||||||
|
import { TMRemark } from "../entities/remark.entity";
|
||||||
|
import { CreateRemarkDto } from "../dto/remark/create-remark.dto";
|
||||||
|
import { UpdateRemarkDto } from "../dto/remark/update-remark.dto";
|
||||||
|
import { remarkMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { TaskService } from './task.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RemarkService {
|
||||||
|
constructor(
|
||||||
|
private readonly remarkRepository: RemarkRepository,
|
||||||
|
private readonly taskService: TaskService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async findOneOrFail(id: string): Promise<TMRemark> {
|
||||||
|
const remark = await this.remarkRepository.findOne({ where: { id } });
|
||||||
|
if (!remark) throw new NotFoundException(remarkMessage.REMARK_NOT_FOUND);
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(dto: CreateRemarkDto): Promise<TMRemark> {
|
||||||
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
|
|
||||||
|
const remark = this.remarkRepository.create(dto);
|
||||||
|
return this.remarkRepository.save(remark);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateRemarkDto): Promise<TMRemark> {
|
||||||
|
const remark = await this.findOneOrFail(id);
|
||||||
|
|
||||||
|
if (dto.taskId) {
|
||||||
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(remark, dto);
|
||||||
|
return this.remarkRepository.save(remark);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string): Promise<void> {
|
||||||
|
await this.findOneOrFail(id);
|
||||||
|
await this.remarkRepository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,45 +1,35 @@
|
|||||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
import { Injectable, NotFoundException } from "@nestjs/common";
|
||||||
import { TaskPhaseRepository } from "../repositories/task-phase.repository";
|
import { TaskPhaseRepository } from "../repositories/task-phase.repository";
|
||||||
import { ProjectRepository } from "../repositories/project.repository";
|
|
||||||
import { TMTaskPhase } from "../entities/task-phase.entity";
|
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||||
import { CreateTaskPhaseDto } from "../dto/task-phase/create-task-phase.dto";
|
import { CreateTaskPhaseDto } from "../dto/task-phase/create-task-phase.dto";
|
||||||
import { UpdateTaskPhaseDto } from "../dto/task-phase/update-task-phase.dto";
|
import { UpdateTaskPhaseDto } from "../dto/task-phase/update-task-phase.dto";
|
||||||
|
import { TaskPhaseMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { ProjectService } from "./project.service";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TaskPhaseService {
|
export class TaskPhaseService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly taskPhaseRepository: TaskPhaseRepository,
|
private readonly taskPhaseRepository: TaskPhaseRepository,
|
||||||
private readonly projectRepository: ProjectRepository,
|
private readonly projectService: ProjectService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<TMTaskPhase[]> {
|
async findOneOrFail(id: string): Promise<TMTaskPhase> {
|
||||||
return this.taskPhaseRepository.findAll();
|
const taskPhase = await this.taskPhaseRepository.findOne({where: {id}});
|
||||||
}
|
if (!taskPhase) throw new NotFoundException(TaskPhaseMessage.TASK_PHASE_NOT_FOUND);
|
||||||
|
|
||||||
findByProject(projectId: string): Promise<TMTaskPhase[]> {
|
|
||||||
return this.taskPhaseRepository.findByProject(projectId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async findOne(id: string): Promise<TMTaskPhase> {
|
|
||||||
const taskPhase = await this.taskPhaseRepository.findOneById(id);
|
|
||||||
if (!taskPhase) throw new NotFoundException(`TaskPhase #${id} not found`);
|
|
||||||
return taskPhase;
|
return taskPhase;
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(dto: CreateTaskPhaseDto): Promise<TMTaskPhase> {
|
async create(dto: CreateTaskPhaseDto): Promise<TMTaskPhase> {
|
||||||
const project = await this.projectRepository.findOneById(dto.projectId);
|
await this.projectService.findOneOrFail(dto.projectId);
|
||||||
if (!project) throw new NotFoundException(`Project #${dto.projectId} not found`);
|
|
||||||
|
|
||||||
const taskPhase = this.taskPhaseRepository.create(dto);
|
const taskPhase = this.taskPhaseRepository.create(dto);
|
||||||
return this.taskPhaseRepository.save(taskPhase);
|
return this.taskPhaseRepository.save(taskPhase);
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, dto: UpdateTaskPhaseDto): Promise<TMTaskPhase> {
|
async update(id: string, dto: UpdateTaskPhaseDto): Promise<TMTaskPhase> {
|
||||||
const taskPhase = await this.findOne(id);
|
const taskPhase = await this.findOneOrFail(id);
|
||||||
|
|
||||||
if (dto.projectId) {
|
if (dto.projectId) {
|
||||||
const project = await this.projectRepository.findOneById(dto.projectId);
|
await this.projectService.findOneOrFail(dto.projectId);
|
||||||
if (!project) throw new NotFoundException(`Project #${dto.projectId} not found`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(taskPhase, dto);
|
Object.assign(taskPhase, dto);
|
||||||
@@ -47,7 +37,7 @@ export class TaskPhaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
await this.findOne(id);
|
await this.findOneOrFail(id);
|
||||||
await this.taskPhaseRepository.delete(id);
|
await this.taskPhaseRepository.delete(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
|
import { BadRequestException, ForbiddenException, Injectable, NotFoundException } from "@nestjs/common";
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { In, Repository } from 'typeorm';
|
import { In, Repository } from "typeorm";
|
||||||
import { TaskRepository } from '../repositories/task.repository';
|
import { TaskRepository } from "../repositories/task.repository";
|
||||||
import { TaskPhaseRepository } from '../repositories/task-phase.repository';
|
import { TMTask } from "../entities/task.entity";
|
||||||
import { TMTask } from '../entities/task.entity';
|
import { CreateTaskDto } from "../dto/task/create-task.dto";
|
||||||
import { CreateTaskDto } from '../dto/task/create-task.dto';
|
import { UpdateTaskDto } from "../dto/task/update-task.dto";
|
||||||
import { UpdateTaskDto } from '../dto/task/update-task.dto';
|
import { ChangeTaskPhaseDto } from "../dto/task/change-task-phase.dto";
|
||||||
import { ChangeTaskPhaseDto } from '../dto/task/change-task-phase.dto';
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { User } from '../../users/entities/user.entity';
|
import { TaskMessage, TaskPhaseMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { TaskPhaseRepository } from "../repositories/task-phase.repository";
|
||||||
|
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||||
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
import { encodeCursor } from "../../utils/providers/cursor-pagination.utils";
|
||||||
|
import { CursorDirection, CursorPaginationDto } from "../../../common/DTO/cursor-pagination.dto";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TaskService {
|
export class TaskService {
|
||||||
@@ -18,25 +23,41 @@ export class TaskService {
|
|||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<TMTask[]> {
|
async findOneOrFail(id: string): Promise<TMTask> {
|
||||||
return this.taskRepository.findAll();
|
const task = await this.taskRepository.findOne({
|
||||||
}
|
where: { id },
|
||||||
|
relations: {
|
||||||
findByPhase(taskPhaseId: string): Promise<TMTask[]> {
|
taskPhase: true,
|
||||||
return this.taskRepository.findByPhase(taskPhaseId);
|
users: true,
|
||||||
}
|
},
|
||||||
|
});
|
||||||
async findOne(id: string): Promise<TMTask> {
|
if (!task) throw new NotFoundException(TaskMessage.TASK_NOT_FOUND);
|
||||||
const task = await this.taskRepository.findOneById(id);
|
|
||||||
if (!task) throw new NotFoundException(`Task #${id} not found`);
|
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findTaskPhaseOrFail(taskPhaseId: string): Promise<TMTaskPhase> {
|
||||||
|
const taskPhase = await this.taskPhaseRepository.findOne({
|
||||||
|
where: { id: taskPhaseId },
|
||||||
|
relations: {
|
||||||
|
project: {
|
||||||
|
users: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!taskPhase) throw new NotFoundException(TaskPhaseMessage.TASK_PHASE_NOT_FOUND);
|
||||||
|
|
||||||
|
return taskPhase;
|
||||||
|
}
|
||||||
|
|
||||||
async create(dto: CreateTaskDto): Promise<TMTask> {
|
async create(dto: CreateTaskDto): Promise<TMTask> {
|
||||||
const { userIds, startDate, endDate, ...rest } = dto;
|
const { userIds, startDate, endDate, ...rest } = dto;
|
||||||
|
|
||||||
const taskPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId);
|
const taskPhase = await this.findTaskPhaseOrFail(dto.taskPhaseId);
|
||||||
if (!taskPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`);
|
|
||||||
|
if (userIds?.length) {
|
||||||
|
const isUsersValid = userIds.every((userId) => taskPhase.project.users.some((user) => user.id === userId));
|
||||||
|
if (!isUsersValid) throw new BadRequestException(TaskMessage.USERS_ASSIGNED_TO_TASK_NOT_PROJECT_MEMBER);
|
||||||
|
}
|
||||||
|
|
||||||
const task = this.taskRepository.create({
|
const task = this.taskRepository.create({
|
||||||
...rest,
|
...rest,
|
||||||
@@ -52,12 +73,16 @@ export class TaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, dto: UpdateTaskDto): Promise<TMTask> {
|
async update(id: string, dto: UpdateTaskDto): Promise<TMTask> {
|
||||||
const task = await this.findOne(id);
|
const task = await this.findOneOrFail(id);
|
||||||
const { userIds, startDate, endDate, ...rest } = dto;
|
const { userIds, startDate, endDate, ...rest } = dto;
|
||||||
|
|
||||||
if (dto.taskPhaseId) {
|
if (dto.taskPhaseId) {
|
||||||
const taskPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId);
|
const taskPhase = await this.findTaskPhaseOrFail(dto.taskPhaseId);
|
||||||
if (!taskPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`);
|
|
||||||
|
if (userIds?.length) {
|
||||||
|
const isUsersValid = userIds.every((userId) => taskPhase.project.users.some((user) => user.id === userId));
|
||||||
|
if (!isUsersValid) throw new BadRequestException(TaskMessage.USERS_ASSIGNED_TO_TASK_NOT_PROJECT_MEMBER);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(task, {
|
Object.assign(task, {
|
||||||
@@ -67,24 +92,23 @@ export class TaskService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (userIds) {
|
if (userIds) {
|
||||||
task.users = userIds.length
|
task.users = userIds.length ? await this.userRepository.findBy({ id: In(userIds) }) : [];
|
||||||
? await this.userRepository.findBy({ id: In(userIds) })
|
|
||||||
: [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.taskRepository.save(task);
|
return this.taskRepository.save(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
async changePhase(id: string, dto: ChangeTaskPhaseDto): Promise<TMTask> {
|
async changePhase(id: string,permissions: PermissionEnum[],userId: string, dto: ChangeTaskPhaseDto): Promise<TMTask> {
|
||||||
const task = await this.findOne(id);
|
const task = await this.findOneOrFail(id);
|
||||||
|
|
||||||
const newPhase = await this.taskPhaseRepository.findOneById(dto.taskPhaseId);
|
const isTaskMember = task.users.some((user) => user.id === userId);
|
||||||
if (!newPhase) throw new NotFoundException(`TaskPhase #${dto.taskPhaseId} not found`);
|
const hasPermission = permissions.includes(PermissionEnum.TASK_UPDATE);
|
||||||
|
if (!isTaskMember && !hasPermission) throw new ForbiddenException(TaskMessage.USER_NOT_TASK_MEMBER);
|
||||||
|
|
||||||
|
const newPhase = await this.findTaskPhaseOrFail(dto.taskPhaseId);
|
||||||
|
|
||||||
if (task.taskPhase.projectId !== newPhase.projectId) {
|
if (task.taskPhase.projectId !== newPhase.projectId) {
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(TaskPhaseMessage.TASK_PHASE_NOT_SAME_PROJECT);
|
||||||
`TaskPhase #${dto.taskPhaseId} does not belong to the same project as the current phase`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
task.taskPhaseId = dto.taskPhaseId;
|
task.taskPhaseId = dto.taskPhaseId;
|
||||||
@@ -94,7 +118,79 @@ export class TaskService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async remove(id: string): Promise<void> {
|
async remove(id: string): Promise<void> {
|
||||||
await this.findOne(id);
|
await this.findOneOrFail(id);
|
||||||
await this.taskRepository.delete(id);
|
await this.taskRepository.delete(id);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
async getTaskDetail(userId: string, permissions: PermissionEnum[], taskId: string): Promise<TMTask | null> {
|
||||||
|
const task = await this.findOneOrFail(taskId);
|
||||||
|
|
||||||
|
const isTaskMember = task.users.some((user) => user.id === userId);
|
||||||
|
const hasPermission = permissions.includes(PermissionEnum.TASK_READ);
|
||||||
|
if (!isTaskMember && !hasPermission) throw new ForbiddenException(TaskMessage.USER_NOT_TASK_MEMBER);
|
||||||
|
|
||||||
|
const taskDetail = await this.taskRepository.getTaskDetail(taskId);
|
||||||
|
return taskDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
async findTasksByTaskPhase(
|
||||||
|
taskPhaseId: string,
|
||||||
|
pagination: CursorPaginationDto,
|
||||||
|
): Promise<{
|
||||||
|
data: TMTask[];
|
||||||
|
nextCursor: string | null;
|
||||||
|
previousCursor: string | null;
|
||||||
|
hasNextPage: boolean;
|
||||||
|
hasPreviousPage: boolean;
|
||||||
|
cursorPaginate: true;
|
||||||
|
}> {
|
||||||
|
await this.findTaskPhaseOrFail(taskPhaseId);
|
||||||
|
|
||||||
|
const isBackward = pagination.direction === CursorDirection.PREV;
|
||||||
|
const { items, hasMore } = await this.taskRepository.findTasksByTaskPhase(taskPhaseId, pagination);
|
||||||
|
|
||||||
|
// paging backward always has more ahead (we came from there); paging forward relies on
|
||||||
|
// whether a cursor was even supplied to know whether anything precedes this page
|
||||||
|
const hasNextPage = items.length > 0 && (isBackward ? true : hasMore);
|
||||||
|
const hasPreviousPage = items.length > 0 && (isBackward ? hasMore : !!pagination.cursor);
|
||||||
|
|
||||||
|
const nextCursor = hasNextPage ? encodeCursor(items[items.length - 1]) : null;
|
||||||
|
const previousCursor = hasPreviousPage ? encodeCursor(items[0]) : null;
|
||||||
|
|
||||||
|
return { data: items, nextCursor, previousCursor, hasNextPage, hasPreviousPage, cursorPaginate: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
async changePriority(srcTaskId: string,permissions: PermissionEnum[],userId: string, destTaskId: string): Promise<TMTask> {
|
||||||
|
const srcTask = await this.findOneOrFail(srcTaskId);
|
||||||
|
const desTask = await this.findOneOrFail(destTaskId);
|
||||||
|
|
||||||
|
const isTaskMember = srcTask.users.some((user) => user.id === userId);
|
||||||
|
const hasPermission = permissions.includes(PermissionEnum.TASK_UPDATE);
|
||||||
|
if (!isTaskMember && !hasPermission) throw new ForbiddenException(TaskMessage.USER_NOT_TASK_MEMBER);
|
||||||
|
|
||||||
|
if (srcTask.taskPhaseId !== desTask.taskPhaseId)
|
||||||
|
throw new BadRequestException(TaskMessage.TASKS_NOT_IN_THE_SAME_TASK_PHASE);
|
||||||
|
|
||||||
|
let movingUp: boolean = false;
|
||||||
|
|
||||||
|
if(srcTask.priority < desTask.priority) {
|
||||||
|
movingUp = true;
|
||||||
|
} else if(srcTask.priority < desTask.priority) {
|
||||||
|
movingUp = false;
|
||||||
|
} else {
|
||||||
|
if(srcTask.createdAt > desTask.createdAt) {
|
||||||
|
movingUp = true;
|
||||||
|
}else {
|
||||||
|
movingUp = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const priorityChange: number = movingUp ? 1 : -1;
|
||||||
|
|
||||||
|
srcTask.priority = desTask.priority + priorityChange;
|
||||||
|
|
||||||
|
await this.taskRepository.save(srcTask);
|
||||||
|
|
||||||
|
return srcTask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||||
|
import { IsNull } from "typeorm";
|
||||||
|
import { TimeRepository } from "../repositories/time.repository";
|
||||||
|
import { TMTime } from "../entities/time.entity";
|
||||||
|
import { CreateTimeDto } from "../dto/time/create-time.dto";
|
||||||
|
import { UpdateTimeDto } from "../dto/time/update-time.dto";
|
||||||
|
import { timeMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { TaskService } from "./task.service";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TimeService {
|
||||||
|
constructor(
|
||||||
|
private readonly timeRepository: TimeRepository,
|
||||||
|
private readonly taskService: TaskService,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
private calculateDuration(startedAt: Date, endedAt: Date): number {
|
||||||
|
if (endedAt.getTime() < startedAt.getTime()) {
|
||||||
|
throw new BadRequestException(timeMessage.INVALID_TIME_RANGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.floor((endedAt.getTime() - startedAt.getTime()) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async findRunningTime(adminId: string, taskId: string): Promise<TMTime | null> {
|
||||||
|
return this.timeRepository.findOne({
|
||||||
|
where: { adminId, taskId, endedAt: IsNull() },
|
||||||
|
order: { startedAt: "DESC" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOneOrFail(id: string): Promise<TMTime> {
|
||||||
|
const time = await this.timeRepository.findOne({
|
||||||
|
where: { id },
|
||||||
|
relations: { admin: true, task: true },
|
||||||
|
});
|
||||||
|
if (!time) throw new NotFoundException(timeMessage.TIME_NOT_FOUND);
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
async start(adminId: string, taskId: string): Promise<TMTime> {
|
||||||
|
await this.taskService.findOneOrFail(taskId);
|
||||||
|
|
||||||
|
const runningTime = await this.findRunningTime(adminId, taskId);
|
||||||
|
if (runningTime) throw new BadRequestException(timeMessage.TIME_ALREADY_STARTED);
|
||||||
|
|
||||||
|
const time = this.timeRepository.create({
|
||||||
|
taskId,
|
||||||
|
adminId,
|
||||||
|
startedAt: new Date(),
|
||||||
|
endedAt: null,
|
||||||
|
duration: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.timeRepository.save(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getTaskTimes(adminId: string, taskId: string): Promise<TMTime[]> {
|
||||||
|
return this.timeRepository.find({
|
||||||
|
where: { adminId, taskId },
|
||||||
|
order: { startedAt: "DESC" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async end(adminId: string, taskId: string): Promise<TMTime> {
|
||||||
|
await this.taskService.findOneOrFail(taskId);
|
||||||
|
|
||||||
|
const runningTime = await this.findRunningTime(adminId, taskId);
|
||||||
|
if (!runningTime) throw new BadRequestException(timeMessage.NO_RUNNING_TIME);
|
||||||
|
|
||||||
|
const endedAt = new Date();
|
||||||
|
runningTime.endedAt = endedAt;
|
||||||
|
runningTime.duration = this.calculateDuration(runningTime.startedAt, endedAt);
|
||||||
|
|
||||||
|
return this.timeRepository.save(runningTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(adminId: string, dto: CreateTimeDto): Promise<TMTime> {
|
||||||
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
|
|
||||||
|
const startedAt = new Date(dto.startedAt);
|
||||||
|
const endedAt = new Date(dto.endedAt);
|
||||||
|
|
||||||
|
const time = this.timeRepository.create({
|
||||||
|
taskId: dto.taskId,
|
||||||
|
adminId,
|
||||||
|
startedAt,
|
||||||
|
endedAt,
|
||||||
|
duration: this.calculateDuration(startedAt, endedAt),
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.timeRepository.save(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, dto: UpdateTimeDto): Promise<TMTime> {
|
||||||
|
const time = await this.findOneOrFail(id);
|
||||||
|
|
||||||
|
if (dto.taskId) {
|
||||||
|
await this.taskService.findOneOrFail(dto.taskId);
|
||||||
|
}
|
||||||
|
|
||||||
|
const startedAt = dto.startedAt ? new Date(dto.startedAt) : time.startedAt;
|
||||||
|
const endedAt = dto.endedAt ? new Date(dto.endedAt) : time.endedAt;
|
||||||
|
|
||||||
|
Object.assign(time, {
|
||||||
|
...dto,
|
||||||
|
startedAt,
|
||||||
|
endedAt,
|
||||||
|
duration: endedAt ? this.calculateDuration(startedAt, endedAt) : null,
|
||||||
|
});
|
||||||
|
|
||||||
|
return this.timeRepository.save(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
async remove(id: string): Promise<void> {
|
||||||
|
await this.findOneOrFail(id);
|
||||||
|
await this.timeRepository.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
import { Injectable, NotFoundException, ConflictException } from "@nestjs/common";
|
|
||||||
import { WorkspaceTypeRepository } from "../repositories/workspace-type.repository";
|
|
||||||
import { TMWorkspaceType } from "../entities/workspace-type.entity";
|
|
||||||
import { CreateWorkspaceTypeDto } from "../dto/workspace-type/create-workspace-type.dto";
|
|
||||||
import { UpdateWorkspaceTypeDto } from "../dto/workspace-type/update-workspace-type.dto";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class WorkspaceTypeService {
|
|
||||||
constructor(private readonly workspaceTypeRepository: WorkspaceTypeRepository) {}
|
|
||||||
|
|
||||||
findAll(): Promise<TMWorkspaceType[]> {
|
|
||||||
return this.workspaceTypeRepository.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
async findOne(id: string): Promise<TMWorkspaceType> {
|
|
||||||
const workspaceType = await this.workspaceTypeRepository.findOneById(id);
|
|
||||||
if (!workspaceType) throw new NotFoundException(`WorkspaceType #${id} not found`);
|
|
||||||
return workspaceType;
|
|
||||||
}
|
|
||||||
|
|
||||||
async create(dto: CreateWorkspaceTypeDto): Promise<TMWorkspaceType> {
|
|
||||||
const existing = await this.workspaceTypeRepository.findOneByName(dto.name);
|
|
||||||
if (existing) throw new ConflictException(`WorkspaceType with name "${dto.name}" already exists`);
|
|
||||||
|
|
||||||
const workspaceType = this.workspaceTypeRepository.create(dto);
|
|
||||||
return this.workspaceTypeRepository.save(workspaceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
async update(id: string, dto: UpdateWorkspaceTypeDto): Promise<TMWorkspaceType> {
|
|
||||||
await this.findOne(id);
|
|
||||||
|
|
||||||
if (dto.name) {
|
|
||||||
const existing = await this.workspaceTypeRepository.findOneByName(dto.name);
|
|
||||||
if (existing && existing.id !== id) throw new ConflictException(`WorkspaceType with name "${dto.name}" already exists`);
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.workspaceTypeRepository.update(id, dto);
|
|
||||||
return this.findOne(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async remove(id: string): Promise<TMWorkspaceType> {
|
|
||||||
const workspaceType = await this.findOne(id);
|
|
||||||
await this.workspaceTypeRepository.delete(id);
|
|
||||||
|
|
||||||
return workspaceType;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +1,35 @@
|
|||||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
||||||
import { InjectRepository } from "@nestjs/typeorm";
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { In, Repository } from "typeorm";
|
import { In, Not, Repository } from "typeorm";
|
||||||
import { WorkspaceRepository } from "../repositories/workspace.repository";
|
import { WorkspaceRepository } from "../repositories/workspace.repository";
|
||||||
import { TMWorkspace } from "../entities/workspace.entity";
|
import { TMWorkspace } from "../entities/workspace.entity";
|
||||||
import { CreateWorkspaceDto } from "../dto/workspace/create-workspace.dto";
|
import { CreateWorkspaceDto } from "../dto/workspace/create-workspace.dto";
|
||||||
import { UpdateWorkspaceDto } from "../dto/workspace/update-workspace.dto";
|
import { UpdateWorkspaceDto } from "../dto/workspace/update-workspace.dto";
|
||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { WorkspaceTypeRepository } from "../repositories/workspace-type.repository";
|
import { WorkSpaceMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { PermissionEnum } from "../../users/enums/permission.enum";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceService {
|
export class WorkspaceService {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly workspaceRepository: WorkspaceRepository,
|
private readonly workspaceRepository: WorkspaceRepository,
|
||||||
private readonly workspaceTypeRepository: WorkspaceTypeRepository,
|
|
||||||
@InjectRepository(User)
|
@InjectRepository(User)
|
||||||
private readonly userRepository: Repository<User>,
|
private readonly userRepository: Repository<User>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
findAll(): Promise<TMWorkspace[]> {
|
|
||||||
return this.workspaceRepository.findAll();
|
|
||||||
}
|
|
||||||
|
|
||||||
async findOneOrFail(id: string): Promise<TMWorkspace> {
|
async findOneOrFail(id: string): Promise<TMWorkspace> {
|
||||||
const workspace = await this.workspaceRepository.findOneById(id);
|
const workspace = await this.workspaceRepository.findOneWorkSpace(id);
|
||||||
if (!workspace) throw new NotFoundException(`Workspace #${id} not found`);
|
if (!workspace) throw new NotFoundException(WorkSpaceMessage.WORKSPACE_NOT_FOUND);
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
async create(dto: CreateWorkspaceDto): Promise<TMWorkspace> {
|
async create(dto: CreateWorkspaceDto): Promise<TMWorkspace> {
|
||||||
const { userIds, workspaceTypeId, ...rest } = dto;
|
const { userIds, ...rest } = dto;
|
||||||
|
|
||||||
const workspaceType = await this.workspaceTypeRepository.findOneById(workspaceTypeId);
|
const existingWorkspace = await this.workspaceRepository.findOne({ where: { name: rest.name } });
|
||||||
if (!workspaceType) throw new NotFoundException(`WorkSpaceType #${workspaceTypeId} not found!`);
|
if (existingWorkspace) {
|
||||||
|
throw new BadRequestException(WorkSpaceMessage.WORKSPACE_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
const workspace = this.workspaceRepository.create(rest);
|
const workspace = this.workspaceRepository.create(rest);
|
||||||
|
|
||||||
@@ -44,11 +42,11 @@ export class WorkspaceService {
|
|||||||
|
|
||||||
async update(id: string, dto: UpdateWorkspaceDto): Promise<TMWorkspace> {
|
async update(id: string, dto: UpdateWorkspaceDto): Promise<TMWorkspace> {
|
||||||
const workspace = await this.findOneOrFail(id);
|
const workspace = await this.findOneOrFail(id);
|
||||||
const { userIds, workspaceTypeId, ...rest } = dto;
|
const { userIds, ...rest } = dto;
|
||||||
|
|
||||||
if (workspaceTypeId) {
|
if (rest.name) {
|
||||||
const workspaceType = await this.workspaceTypeRepository.findOneById(workspaceTypeId);
|
const existingWorkSpaceWithTheSameName = await this.workspaceRepository.findOne({ where: { name: rest.name, id: Not(id) } });
|
||||||
if (!workspaceType) throw new NotFoundException(`WorkSpaceType #${workspaceTypeId} not found!`);
|
if (existingWorkSpaceWithTheSameName) throw new BadRequestException(WorkSpaceMessage.WORKSPACE_SAME_NAME_EXISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.assign(workspace, rest);
|
Object.assign(workspace, rest);
|
||||||
@@ -66,4 +64,11 @@ export class WorkspaceService {
|
|||||||
|
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findByUser(userId: string, permissions: PermissionEnum[]): Promise<TMWorkspace[]> {
|
||||||
|
if(permissions.includes(PermissionEnum.WORKSPACE_READ)) {
|
||||||
|
return await this.workspaceRepository.find();
|
||||||
|
}
|
||||||
|
return await this.workspaceRepository.findByUser(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
import { TMAttachment } from '../entities/attachment.entity';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AttachmentRepository extends Repository<TMAttachment>{
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(TMAttachment) attachmentRepository: Repository<TMAttachment>,
|
||||||
|
) {
|
||||||
|
super(attachmentRepository.target, attachmentRepository.manager, attachmentRepository.queryRunner);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,44 +4,10 @@ import { Repository } from 'typeorm';
|
|||||||
import { TMCheckListItem } from '../entities/check-list-item.entity';
|
import { TMCheckListItem } from '../entities/check-list-item.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CheckListItemRepository {
|
export class CheckListItemRepository extends Repository<TMCheckListItem>{
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(TMCheckListItem)
|
@InjectRepository(TMCheckListItem) checkListItemRepository: Repository<TMCheckListItem>,
|
||||||
private readonly repository: Repository<TMCheckListItem>,
|
) {
|
||||||
) {}
|
super(checkListItemRepository.target, checkListItemRepository.manager, checkListItemRepository.queryRunner);
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return this.repository.find({
|
|
||||||
relations: ['task'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findByTask(taskId: string) {
|
|
||||||
return this.repository.find({
|
|
||||||
where: { taskId },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findOneById(id: string) {
|
|
||||||
return this.repository.findOne({
|
|
||||||
where: { id },
|
|
||||||
relations: ['task'],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
create(data: Partial<TMCheckListItem>) {
|
|
||||||
return this.repository.create(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(checkListItem: TMCheckListItem) {
|
|
||||||
return this.repository.save(checkListItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: string, data: Partial<TMCheckListItem>) {
|
|
||||||
return this.repository.update(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: string) {
|
|
||||||
return this.repository.delete(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,45 +4,37 @@ import { Repository } from "typeorm";
|
|||||||
import { TMProject } from "../entities/project.entity";
|
import { TMProject } from "../entities/project.entity";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ProjectRepository {
|
export class ProjectRepository extends Repository<TMProject> {
|
||||||
constructor(
|
constructor(@InjectRepository(TMProject) projectRepository: Repository<TMProject>) {
|
||||||
@InjectRepository(TMProject)
|
super(projectRepository.target, projectRepository.manager, projectRepository.queryRunner);
|
||||||
private readonly repository: Repository<TMProject>,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return this.repository.find({
|
|
||||||
relations: ["workspace", "taskPhases", "users"],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findByWorkspace(workspaceId: string) {
|
async findUserProjects(userId: string, wsId: string, skip?: number, take?: number): Promise<[TMProject[], number]> {
|
||||||
return this.repository.find({
|
return this.createQueryBuilder("project")
|
||||||
where: { workspaceId },
|
.innerJoin("project.workspace", "workspace")
|
||||||
relations: ["taskPhases", "users"],
|
.innerJoin("project.users", "user")
|
||||||
});
|
.where("workspace.id = :wsId", { wsId })
|
||||||
|
.andWhere("user.id = :userId", { userId })
|
||||||
|
.skip(skip ?? 0)
|
||||||
|
.take(take ?? 10)
|
||||||
|
.getManyAndCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
findOneById(id: string) {
|
async getProjectDetail(projectId: string): Promise<TMProject | null> {
|
||||||
return this.repository.findOne({
|
return this.createQueryBuilder("project")
|
||||||
where: { id },
|
.leftJoinAndSelect("project.taskPhases", "taskPhase")
|
||||||
relations: ["workspace", "taskPhases", "users"],
|
.where("project.id = :projectId", { projectId })
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
create(data: Partial<TMProject>) {
|
.select([
|
||||||
return this.repository.create(data);
|
"project.id",
|
||||||
}
|
"project.name",
|
||||||
|
"taskPhase.id",
|
||||||
|
"taskPhase.name",
|
||||||
|
"taskPhase.order",
|
||||||
|
])
|
||||||
|
|
||||||
|
.orderBy("taskPhase.order", "ASC")
|
||||||
|
|
||||||
save(project: TMProject) {
|
.getOne();
|
||||||
return this.repository.save(project);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: string, data: Partial<TMProject>) {
|
|
||||||
return this.repository.update(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: string) {
|
|
||||||
return this.repository.delete(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
|
import { Repository } from "typeorm";
|
||||||
|
import { TMRemark } from "../entities/remark.entity";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class RemarkRepository extends Repository<TMRemark>{
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(TMRemark) remarkRepository: Repository<TMRemark>,
|
||||||
|
) {
|
||||||
|
super(remarkRepository.target, remarkRepository.manager, remarkRepository.queryRunner);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,47 +4,10 @@ import { Repository } from "typeorm";
|
|||||||
import { TMTaskPhase } from "../entities/task-phase.entity";
|
import { TMTaskPhase } from "../entities/task-phase.entity";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TaskPhaseRepository {
|
export class TaskPhaseRepository extends Repository<TMTaskPhase> {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(TMTaskPhase)
|
@InjectRepository(TMTaskPhase) taskPhaseRepository: Repository<TMTaskPhase>,
|
||||||
private readonly repository: Repository<TMTaskPhase>,
|
) {
|
||||||
) {}
|
super(taskPhaseRepository.target, taskPhaseRepository.manager, taskPhaseRepository.queryRunner);
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return this.repository.find({
|
|
||||||
relations: ["project", "tasks"],
|
|
||||||
order: { order: "ASC" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findByProject(projectId: string) {
|
|
||||||
return this.repository.find({
|
|
||||||
where: { projectId },
|
|
||||||
relations: ["tasks"],
|
|
||||||
order: { order: "ASC" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findOneById(id: string) {
|
|
||||||
return this.repository.findOne({
|
|
||||||
where: { id },
|
|
||||||
relations: ["project", "tasks"],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
create(data: Partial<TMTaskPhase>) {
|
|
||||||
return this.repository.create(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(taskPhase: TMTaskPhase) {
|
|
||||||
return this.repository.save(taskPhase);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: string, data: Partial<TMTaskPhase>) {
|
|
||||||
return this.repository.update(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: string) {
|
|
||||||
return this.repository.delete(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,47 +2,144 @@ import { Injectable } from "@nestjs/common";
|
|||||||
import { InjectRepository } from "@nestjs/typeorm";
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { Repository } from "typeorm";
|
import { Repository } from "typeorm";
|
||||||
import { TMTask } from "../entities/task.entity";
|
import { TMTask } from "../entities/task.entity";
|
||||||
|
import { TMTime } from "../entities/time.entity";
|
||||||
|
import { CursorDirection, CursorPaginationDto } from "../../../common/DTO/cursor-pagination.dto";
|
||||||
|
import { decodeCursor } from "../../utils/providers/cursor-pagination.utils";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TaskRepository {
|
export class TaskRepository extends Repository<TMTask> {
|
||||||
constructor(
|
constructor(@InjectRepository(TMTask) taskRepository: Repository<TMTask>) {
|
||||||
@InjectRepository(TMTask)
|
super(taskRepository.target, taskRepository.manager, taskRepository.queryRunner);
|
||||||
private readonly repository: Repository<TMTask>,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return this.repository.find({
|
|
||||||
relations: ["taskPhase", "remarks", "attachments", "checkListItems", "users"],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findByPhase(taskPhaseId: string) {
|
async getTaskDetail(taskId: string): Promise<TMTask | null> {
|
||||||
return this.repository.find({
|
const task = await this.createQueryBuilder("task")
|
||||||
where: { taskPhaseId },
|
.leftJoinAndSelect("task.remarks", "remark")
|
||||||
relations: ["remarks", "attachments", "checkListItems", "users"],
|
.leftJoinAndSelect("task.attachments", "attachment")
|
||||||
});
|
.leftJoinAndSelect("task.checkListItems", "checkListItem")
|
||||||
|
.leftJoinAndSelect("task.users", "user")
|
||||||
|
.leftJoinAndSelect("task.times", "time")
|
||||||
|
.leftJoinAndSelect("time.admin", "timeAdmin")
|
||||||
|
|
||||||
|
.loadRelationCountAndMap("task.checkListItemCount", "task.checkListItems")
|
||||||
|
|
||||||
|
.loadRelationCountAndMap("task.completedCheckListItemCount", "task.checkListItems", "completedCheckListItems", (qb) =>
|
||||||
|
qb.where("completedCheckListItems.isDone = :isDone", { isDone: true }),
|
||||||
|
)
|
||||||
|
|
||||||
|
.select([
|
||||||
|
"task",
|
||||||
|
|
||||||
|
"remark.id",
|
||||||
|
"remark.title",
|
||||||
|
"remark.color",
|
||||||
|
"checkListItem.id",
|
||||||
|
"checkListItem.title",
|
||||||
|
"checkListItem.isDone",
|
||||||
|
"attachment.id",
|
||||||
|
"attachment.title",
|
||||||
|
"attachment.type",
|
||||||
|
"attachment.file",
|
||||||
|
|
||||||
|
"user.id",
|
||||||
|
"user.firstName",
|
||||||
|
"user.lastName",
|
||||||
|
|
||||||
|
"time.id",
|
||||||
|
"time.startedAt",
|
||||||
|
"time.endedAt",
|
||||||
|
"time.duration",
|
||||||
|
"time.adminId",
|
||||||
|
"timeAdmin.id",
|
||||||
|
"timeAdmin.firstName",
|
||||||
|
"timeAdmin.lastName",
|
||||||
|
])
|
||||||
|
.where("task.id = :taskId", { taskId })
|
||||||
|
|
||||||
|
.orderBy("checkListItem.createdAt", "ASC")
|
||||||
|
.addOrderBy("time.createdAt", "ASC")
|
||||||
|
|
||||||
|
.getOne();
|
||||||
|
|
||||||
|
if (task) {
|
||||||
|
task.time = task.times?.reduce((sum, entry) => sum + (entry.duration ?? 0), 0) ?? 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return task;
|
||||||
}
|
}
|
||||||
|
|
||||||
findOneById(id: string) {
|
async findTasksByTaskPhase(taskPhaseId: string, pagination: CursorPaginationDto): Promise<{ items: TMTask[]; hasMore: boolean }> {
|
||||||
return this.repository.findOne({
|
const limit = pagination.limit || 10;
|
||||||
where: { id },
|
const isBackward = pagination.direction === CursorDirection.PREV;
|
||||||
relations: ["taskPhase", "remarks", "attachments", "checkListItems", "users"],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
create(data: Partial<TMTask>) {
|
const createdAtExpr = `date_trunc('milliseconds', task.createdAt)`;
|
||||||
return this.repository.create(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(task: TMTask) {
|
const seekQuery = this.createQueryBuilder("task")
|
||||||
return this.repository.save(task);
|
.select(["task.id", "task.priority", "task.createdAt"])
|
||||||
}
|
.where("task.taskPhaseId = :taskPhaseId", { taskPhaseId })
|
||||||
|
.limit(limit + 1); // fetch one extra to check whether there's a further page
|
||||||
|
|
||||||
update(id: string, data: Partial<TMTask>) {
|
if (isBackward) {
|
||||||
return this.repository.update(id, data);
|
seekQuery.orderBy("task.priority", "ASC").addOrderBy(createdAtExpr, "DESC").addOrderBy("task.id", "DESC");
|
||||||
}
|
} else {
|
||||||
|
seekQuery.orderBy("task.priority", "DESC").addOrderBy(createdAtExpr, "ASC").addOrderBy("task.id", "ASC");
|
||||||
|
}
|
||||||
|
|
||||||
delete(id: string) {
|
if (pagination.cursor) {
|
||||||
return this.repository.delete(id);
|
const { priority: cursorPriority, createdAt: cursorCreatedAt, id: cursorId } = decodeCursor(pagination.cursor);
|
||||||
|
const priorityOp = isBackward ? ">" : "<";
|
||||||
|
const seekOp = isBackward ? "<" : ">";
|
||||||
|
|
||||||
|
seekQuery.andWhere(
|
||||||
|
`(task.priority ${priorityOp} :cursorPriority
|
||||||
|
OR (task.priority = :cursorPriority AND ${createdAtExpr} ${seekOp} :cursorCreatedAt)
|
||||||
|
OR (task.priority = :cursorPriority AND ${createdAtExpr} = :cursorCreatedAt AND task.id ${seekOp} :cursorId))`,
|
||||||
|
{ cursorPriority, cursorCreatedAt, cursorId },
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const seekRows = await seekQuery.getMany();
|
||||||
|
const hasMore = seekRows.length > limit;
|
||||||
|
if (hasMore) seekRows.pop();
|
||||||
|
|
||||||
|
// backward queries fetch in reverse order to seek from the cursor, so flip back to
|
||||||
|
// the normal display order before returning
|
||||||
|
const orderedRows = isBackward ? seekRows.reverse() : seekRows;
|
||||||
|
const ids = orderedRows.map((row) => row.id);
|
||||||
|
|
||||||
|
if (!ids.length) return { items: [], hasMore };
|
||||||
|
|
||||||
|
// Detail query: hydrates exactly the ids picked above with the relations/counts the
|
||||||
|
// response needs. IN (:...ids) doesn't preserve order, so re-order to match seekQuery.
|
||||||
|
const detailRows = await this.createQueryBuilder("task")
|
||||||
|
.leftJoinAndSelect("task.remarks", "remark")
|
||||||
|
.loadRelationCountAndMap("task.attachmentCount", "task.attachments")
|
||||||
|
.loadRelationCountAndMap("task.checkListItemCount", "task.checkListItems")
|
||||||
|
.loadRelationCountAndMap("task.completedCheckListItemCount", "task.checkListItems", "completedCheckListItems", (qb) =>
|
||||||
|
qb.where("completedCheckListItems.isDone = :isDone", { isDone: true }),
|
||||||
|
)
|
||||||
|
.select(["task", "remark.id", "remark.title", "remark.color"])
|
||||||
|
.where("task.id IN (:...ids)", { ids })
|
||||||
|
.getMany();
|
||||||
|
|
||||||
|
const timeSums = await this.manager
|
||||||
|
.createQueryBuilder(TMTime, "time")
|
||||||
|
.select("time.taskId", "taskId")
|
||||||
|
.addSelect("COALESCE(SUM(time.duration), 0)", "totalTime")
|
||||||
|
.where("time.taskId IN (:...ids)", { ids })
|
||||||
|
.groupBy("time.taskId")
|
||||||
|
.getRawMany<{ taskId: string; totalTime: string }>();
|
||||||
|
|
||||||
|
const timeByTaskId = new Map(timeSums.map((row) => [row.taskId, Number(row.totalTime)]));
|
||||||
|
|
||||||
|
const detailById = new Map(
|
||||||
|
detailRows.map((task) => {
|
||||||
|
task.time = timeByTaskId.get(task.id) ?? 0;
|
||||||
|
return [task.id, task];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const items = ids.map((id) => detailById.get(id)).filter((task): task is TMTask => task !== undefined);
|
||||||
|
|
||||||
|
return { items, hasMore };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { Injectable } from "@nestjs/common";
|
||||||
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
|
import { Repository } from "typeorm";
|
||||||
|
import { TMTime } from "../entities/time.entity";
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TimeRepository extends Repository<TMTime> {
|
||||||
|
constructor(@InjectRepository(TMTime) timeRepository: Repository<TMTime>) {
|
||||||
|
super(timeRepository.target, timeRepository.manager, timeRepository.queryRunner);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import { Injectable } from "@nestjs/common";
|
|
||||||
import { InjectRepository } from "@nestjs/typeorm";
|
|
||||||
import { Repository } from "typeorm";
|
|
||||||
import { TMWorkspaceType } from "../entities/workspace-type.entity";
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class WorkspaceTypeRepository {
|
|
||||||
constructor(
|
|
||||||
@InjectRepository(TMWorkspaceType)
|
|
||||||
private readonly repository: Repository<TMWorkspaceType>,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return this.repository.find({
|
|
||||||
order: { order: "ASC" },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findOneById(id: string) {
|
|
||||||
return this.repository.findOne({ where: { id } });
|
|
||||||
}
|
|
||||||
|
|
||||||
findOneByName(name: string) {
|
|
||||||
return this.repository.findOne({ where: { name } });
|
|
||||||
}
|
|
||||||
|
|
||||||
create(data: Partial<TMWorkspaceType>) {
|
|
||||||
return this.repository.create(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
save(workspaceType: TMWorkspaceType) {
|
|
||||||
return this.repository.save(workspaceType);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: string, data: Partial<TMWorkspaceType>) {
|
|
||||||
return this.repository.update(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: string) {
|
|
||||||
return this.repository.delete(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +1,30 @@
|
|||||||
import { Injectable } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
import { InjectRepository } from "@nestjs/typeorm";
|
import { InjectRepository } from "@nestjs/typeorm";
|
||||||
import { Repository } from "typeorm";
|
import { Repository } from 'typeorm';
|
||||||
import { TMWorkspace } from "../entities/workspace.entity";
|
import { TMWorkspace } from '../entities/workspace.entity';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WorkspaceRepository {
|
export class WorkspaceRepository extends Repository<TMWorkspace> {
|
||||||
constructor(
|
constructor(@InjectRepository(TMWorkspace) workspaceRepository: Repository<TMWorkspace>) {
|
||||||
@InjectRepository(TMWorkspace)
|
super(workspaceRepository.target, workspaceRepository.manager, workspaceRepository.queryRunner);
|
||||||
private readonly repository: Repository<TMWorkspace>,
|
|
||||||
) {}
|
|
||||||
|
|
||||||
findAll() {
|
|
||||||
return this.repository.find({
|
|
||||||
relations: ["workspaceType", "projects", "users"],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findOneById(id: string) {
|
async findOneWorkSpace(workspaceId: string): Promise<TMWorkspace | null> {
|
||||||
return this.repository.findOne({
|
return this.createQueryBuilder("workspace")
|
||||||
where: { id },
|
.leftJoinAndSelect('workspace.users', 'user')
|
||||||
});
|
.select([
|
||||||
|
'workspace',
|
||||||
|
'user.id',
|
||||||
|
'user.firstName',
|
||||||
|
'user.lastName'
|
||||||
|
]).where('workspace.id = :workspaceId', {workspaceId})
|
||||||
|
.getOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
create(data: Partial<TMWorkspace>) {
|
async findByUser(userId: string): Promise<TMWorkspace[]> {
|
||||||
return this.repository.create(data);
|
return this.createQueryBuilder("workspace")
|
||||||
}
|
.innerJoin("workspace.users", "users")
|
||||||
|
.where("users.id = :userId", { userId })
|
||||||
save(workspace: TMWorkspace) {
|
.getMany();
|
||||||
return this.repository.save(workspace);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(id: string, data: Partial<TMWorkspace>) {
|
|
||||||
return this.repository.update(id, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(id: string) {
|
|
||||||
return this.repository.delete(id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||||
|
|
||||||
import { TMWorkspaceType } from "./entities/workspace-type.entity";
|
|
||||||
import { TMWorkspace } from "./entities/workspace.entity";
|
import { TMWorkspace } from "./entities/workspace.entity";
|
||||||
import { TMProject } from "./entities/project.entity";
|
import { TMProject } from "./entities/project.entity";
|
||||||
import { TMTaskPhase } from "./entities/task-phase.entity";
|
import { TMTaskPhase } from "./entities/task-phase.entity";
|
||||||
@@ -9,13 +8,11 @@ import { TMTask } from "./entities/task.entity";
|
|||||||
import { TMRemark } from "./entities/remark.entity";
|
import { TMRemark } from "./entities/remark.entity";
|
||||||
import { TMAttachment } from "./entities/attachment.entity";
|
import { TMAttachment } from "./entities/attachment.entity";
|
||||||
import { TMCheckListItem } from "./entities/check-list-item.entity";
|
import { TMCheckListItem } from "./entities/check-list-item.entity";
|
||||||
|
import { TMTime } from "./entities/time.entity";
|
||||||
import { WorkspaceRepository } from "./repositories/workspace.repository";
|
import { WorkspaceRepository } from "./repositories/workspace.repository";
|
||||||
import { WorkspaceController } from "./controllers/workspace.controller";
|
import { WorkspaceController } from "./controllers/workspace.controller";
|
||||||
import { WorkspaceService } from "./providers/workspace.service";
|
import { WorkspaceService } from "./providers/workspace.service";
|
||||||
import { User } from "../users/entities/user.entity";
|
import { User } from "../users/entities/user.entity";
|
||||||
import { WorkspaceTypeService } from "./providers/workspace-type.service";
|
|
||||||
import { WorkspaceTypeRepository } from "./repositories/workspace-type.repository";
|
|
||||||
import { WorkspaceTypeController } from "./controllers/workspace-type.controller";
|
|
||||||
import { ProjectController } from "./controllers/project.controller";
|
import { ProjectController } from "./controllers/project.controller";
|
||||||
import { ProjectRepository } from "./repositories/project.repository";
|
import { ProjectRepository } from "./repositories/project.repository";
|
||||||
import { ProjectService } from "./providers/project.service";
|
import { ProjectService } from "./providers/project.service";
|
||||||
@@ -28,24 +25,33 @@ import { CheckListItemService } from "./providers/check-list-item.service";
|
|||||||
import { TaskPhaseController } from "./controllers/task-phase.controller";
|
import { TaskPhaseController } from "./controllers/task-phase.controller";
|
||||||
import { TaskController } from "./controllers/task.controller";
|
import { TaskController } from "./controllers/task.controller";
|
||||||
import { CheckListItemController } from "./controllers/check-list-item.controller";
|
import { CheckListItemController } from "./controllers/check-list-item.controller";
|
||||||
|
import { RemarkController } from "./controllers/remark.controller";
|
||||||
|
import { RemarkRepository } from "./repositories/remark.repository";
|
||||||
|
import { RemarkService } from "./providers/remark.service";
|
||||||
|
import { AttachmentController } from "./controllers/attachment.controller";
|
||||||
|
import { AttachmentRepository } from "./repositories/attachment.repository";
|
||||||
|
import { AttachmentService } from "./providers/attachment.service";
|
||||||
|
import { TimeController } from "./controllers/time.controller";
|
||||||
|
import { TimeRepository } from "./repositories/time.repository";
|
||||||
|
import { TimeService } from "./providers/time.service";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
TypeOrmModule.forFeature([TMWorkspaceType, TMWorkspace, TMProject, TMTaskPhase, TMTask, TMRemark, TMAttachment, TMCheckListItem, User]),
|
TypeOrmModule.forFeature([TMWorkspace, TMProject, TMTaskPhase, TMTask, TMRemark, TMAttachment, TMCheckListItem, TMTime, User]),
|
||||||
],
|
],
|
||||||
controllers: [
|
controllers: [
|
||||||
WorkspaceController,
|
WorkspaceController,
|
||||||
WorkspaceTypeController,
|
|
||||||
ProjectController,
|
ProjectController,
|
||||||
TaskPhaseController,
|
TaskPhaseController,
|
||||||
TaskController,
|
TaskController,
|
||||||
CheckListItemController,
|
CheckListItemController,
|
||||||
|
RemarkController,
|
||||||
|
AttachmentController,
|
||||||
|
TimeController,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
WorkspaceRepository,
|
WorkspaceRepository,
|
||||||
WorkspaceService,
|
WorkspaceService,
|
||||||
WorkspaceTypeRepository,
|
|
||||||
WorkspaceTypeService,
|
|
||||||
ProjectRepository,
|
ProjectRepository,
|
||||||
ProjectService,
|
ProjectService,
|
||||||
TaskPhaseRepository,
|
TaskPhaseRepository,
|
||||||
@@ -54,20 +60,12 @@ import { CheckListItemController } from "./controllers/check-list-item.controlle
|
|||||||
TaskService,
|
TaskService,
|
||||||
CheckListItemRepository,
|
CheckListItemRepository,
|
||||||
CheckListItemService,
|
CheckListItemService,
|
||||||
],
|
RemarkRepository,
|
||||||
exports: [
|
RemarkService,
|
||||||
WorkspaceRepository,
|
AttachmentRepository,
|
||||||
WorkspaceService,
|
AttachmentService,
|
||||||
WorkspaceTypeRepository,
|
TimeRepository,
|
||||||
WorkspaceTypeService,
|
TimeService,
|
||||||
ProjectRepository,
|
]
|
||||||
ProjectService,
|
|
||||||
TaskPhaseRepository,
|
|
||||||
TaskPhaseService,
|
|
||||||
TaskRepository,
|
|
||||||
TaskService,
|
|
||||||
CheckListItemRepository,
|
|
||||||
CheckListItemService,
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
export class TaskManagerModule {}
|
export class TaskManagerModule {}
|
||||||
|
|||||||
@@ -24,14 +24,14 @@ export class TicketsController {
|
|||||||
//----------------- ticket categories -------------------
|
//----------------- ticket categories -------------------
|
||||||
|
|
||||||
@ApiOperation({ summary: "Create ticket category => admin route" })
|
@ApiOperation({ summary: "Create ticket category => admin route" })
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_CREATE)
|
||||||
@Post("category")
|
@Post("category")
|
||||||
createTicketCategory(@Body() createDto: CreateTicketCategoryDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createTicketCategory(@Body() createDto: CreateTicketCategoryDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.ticketsService.createTicketCategory(createDto, userIpAndHeaders);
|
return this.ticketsService.createTicketCategory(createDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Update ticket category => admin route" })
|
@ApiOperation({ summary: "Update ticket category => admin route" })
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_UPDATE)
|
||||||
@Patch("category/:id")
|
@Patch("category/:id")
|
||||||
updateCategory(
|
updateCategory(
|
||||||
@Param() paramDto: ParamDto,
|
@Param() paramDto: ParamDto,
|
||||||
@@ -49,7 +49,7 @@ export class TicketsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get ticket categories list => admin route" })
|
@ApiOperation({ summary: "Get ticket categories list => admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_READ)
|
||||||
@Get("categories-list")
|
@Get("categories-list")
|
||||||
getCategoriesList(@Query() queryDto: SearchTicketCategoryDto) {
|
getCategoriesList(@Query() queryDto: SearchTicketCategoryDto) {
|
||||||
return this.ticketsService.getCategoriesList(queryDto);
|
return this.ticketsService.getCategoriesList(queryDto);
|
||||||
@@ -58,7 +58,7 @@ export class TicketsController {
|
|||||||
@ApiOperation({ summary: "toggle status of categories => admin route" })
|
@ApiOperation({ summary: "toggle status of categories => admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_UPDATE)
|
||||||
@Post("category/toggle-status/:id")
|
@Post("category/toggle-status/:id")
|
||||||
toggleCategoryStatus(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
toggleCategoryStatus(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.ticketsService.toggleCategoryStatus(paramDto, userIpAndHeaders);
|
return this.ticketsService.toggleCategoryStatus(paramDto, userIpAndHeaders);
|
||||||
@@ -74,7 +74,7 @@ export class TicketsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "create ticket by admin" })
|
@ApiOperation({ summary: "create ticket by admin" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_CREATE)
|
||||||
@Post("admin")
|
@Post("admin")
|
||||||
createTicketByAdmin(@Body() createDto: CreateTicketByAdminDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createTicketByAdmin(@Body() createDto: CreateTicketByAdminDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.ticketsService.createTicketByAdmin(createDto, userIpAndHeaders);
|
return this.ticketsService.createTicketByAdmin(createDto, userIpAndHeaders);
|
||||||
@@ -88,7 +88,7 @@ export class TicketsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Get all tickets ==> admin route" })
|
@ApiOperation({ summary: "Get all tickets ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_READ)
|
||||||
@Get("admin")
|
@Get("admin")
|
||||||
getAllTickets(@Query() queryDto: SearchTicketQueryDto, @UserDec("id") adminId: string) {
|
getAllTickets(@Query() queryDto: SearchTicketQueryDto, @UserDec("id") adminId: string) {
|
||||||
return this.ticketsService.getTicketForAdmin(queryDto, adminId);
|
return this.ticketsService.getTicketForAdmin(queryDto, adminId);
|
||||||
@@ -124,7 +124,7 @@ export class TicketsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "open ticket by admin" })
|
@ApiOperation({ summary: "open ticket by admin" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_UPDATE)
|
||||||
@Post(":id/open")
|
@Post(":id/open")
|
||||||
openTicketByAdmin(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
openTicketByAdmin(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.ticketsService.openTicketByAdmin(paramDto.id, userIpAndHeaders);
|
return this.ticketsService.openTicketByAdmin(paramDto.id, userIpAndHeaders);
|
||||||
@@ -132,7 +132,7 @@ export class TicketsController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "referer ticket ==> admin route" })
|
@ApiOperation({ summary: "referer ticket ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
@PermissionsDec(PermissionEnum.TICKETS)
|
@PermissionsDec(PermissionEnum.TICKETS_UPDATE)
|
||||||
@Post(":id/refer")
|
@Post(":id/refer")
|
||||||
referTicket(@Param() paramDto: ParamDto, @Body() referDto: ReferTicketDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
referTicket(@Param() paramDto: ParamDto, @Body() referDto: ReferTicketDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.ticketsService.referTicket(paramDto.id, referDto, userIpAndHeaders);
|
return this.ticketsService.referTicket(paramDto.id, referDto, userIpAndHeaders);
|
||||||
|
|||||||
@@ -12,6 +12,6 @@ export class SearchAdminQueryDto extends PaginationDto {
|
|||||||
|
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsEnum(PermissionEnum)
|
@IsEnum(PermissionEnum)
|
||||||
@ApiPropertyOptional({ description: "permission", example: PermissionEnum.SERVICES })
|
@ApiPropertyOptional({ description: "permission", example: PermissionEnum.SERVICES_READ })
|
||||||
permission?: PermissionEnum;
|
permission?: PermissionEnum;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
import { PermissionEnum } from "../enums/permission.enum";
|
||||||
|
import { PermissionGroupEnum } from "../enums/permission-group.enum";
|
||||||
|
|
||||||
|
export type PermissionMeta = {
|
||||||
|
title: string;
|
||||||
|
group: PermissionGroupEnum;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const permissionMeta: Record<PermissionEnum, PermissionMeta> = {
|
||||||
|
[PermissionEnum.SERVICES_CREATE]: { title: "ایجاد سرویسها", group: PermissionGroupEnum.SERVICES },
|
||||||
|
[PermissionEnum.SERVICES_READ]: { title: "مشاهده سرویسها", group: PermissionGroupEnum.SERVICES },
|
||||||
|
[PermissionEnum.SERVICES_UPDATE]: { title: "ویرایش سرویسها", group: PermissionGroupEnum.SERVICES },
|
||||||
|
[PermissionEnum.SERVICES_DELETE]: { title: "حذف سرویسها", group: PermissionGroupEnum.SERVICES },
|
||||||
|
|
||||||
|
[PermissionEnum.CUSTOMERS_CREATE]: { title: "ایجاد مشتریان", group: PermissionGroupEnum.CUSTOMERS },
|
||||||
|
[PermissionEnum.CUSTOMERS_READ]: { title: "مشاهده مشتریان", group: PermissionGroupEnum.CUSTOMERS },
|
||||||
|
[PermissionEnum.CUSTOMERS_UPDATE]: { title: "ویرایش مشتریان", group: PermissionGroupEnum.CUSTOMERS },
|
||||||
|
[PermissionEnum.CUSTOMERS_DELETE]: { title: "حذف مشتریان", group: PermissionGroupEnum.CUSTOMERS },
|
||||||
|
|
||||||
|
[PermissionEnum.AGENTS_CREATE]: { title: "ایجاد نمایندگان", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
[PermissionEnum.AGENTS_READ]: { title: "مشاهده نمایندگان", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
[PermissionEnum.AGENTS_UPDATE]: { title: "ویرایش نمایندگان", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
[PermissionEnum.AGENTS_DELETE]: { title: "حذف نمایندگان", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
|
||||||
|
[PermissionEnum.DEVELOPERS_CREATE]: { title: "ایجاد توسعهدهندگان", group: PermissionGroupEnum.USERS },
|
||||||
|
[PermissionEnum.DEVELOPERS_READ]: { title: "مشاهده توسعهدهندگان", group: PermissionGroupEnum.USERS },
|
||||||
|
[PermissionEnum.DEVELOPERS_UPDATE]: { title: "ویرایش توسعهدهندگان", group: PermissionGroupEnum.USERS },
|
||||||
|
[PermissionEnum.DEVELOPERS_DELETE]: { title: "حذف توسعهدهندگان", group: PermissionGroupEnum.USERS },
|
||||||
|
|
||||||
|
[PermissionEnum.INVOICES_CREATE]: { title: "ایجاد صورتحسابها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.INVOICES_READ]: { title: "مشاهده صورتحسابها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.INVOICES_UPDATE]: { title: "ویرایش صورتحسابها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.INVOICES_DELETE]: { title: "حذف صورتحسابها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
|
||||||
|
[PermissionEnum.TRANSACTIONS_CREATE]: { title: "ایجاد تراکنشها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.TRANSACTIONS_READ]: { title: "مشاهده تراکنشها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.TRANSACTIONS_UPDATE]: { title: "ویرایش تراکنشها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.TRANSACTIONS_DELETE]: { title: "حذف تراکنشها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
|
||||||
|
[PermissionEnum.DISCOUNTS_CREATE]: { title: "ایجاد تخفیفها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.DISCOUNTS_READ]: { title: "مشاهده تخفیفها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.DISCOUNTS_UPDATE]: { title: "ویرایش تخفیفها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.DISCOUNTS_DELETE]: { title: "حذف تخفیفها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
|
||||||
|
[PermissionEnum.ADMINS_CREATE]: { title: "ایجاد ادمینها", group: PermissionGroupEnum.USERS },
|
||||||
|
[PermissionEnum.ADMINS_READ]: { title: "مشاهده ادمینها", group: PermissionGroupEnum.USERS },
|
||||||
|
[PermissionEnum.ADMINS_UPDATE]: { title: "ویرایش ادمینها", group: PermissionGroupEnum.USERS },
|
||||||
|
[PermissionEnum.ADMINS_DELETE]: { title: "حذف ادمینها", group: PermissionGroupEnum.USERS },
|
||||||
|
|
||||||
|
[PermissionEnum.TICKETS_CREATE]: { title: "ایجاد تیکتها", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
[PermissionEnum.TICKETS_READ]: { title: "مشاهده تیکتها", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
[PermissionEnum.TICKETS_UPDATE]: { title: "ویرایش تیکتها", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
[PermissionEnum.TICKETS_DELETE]: { title: "حذف تیکتها", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
|
||||||
|
[PermissionEnum.CRITICISMS_CREATE]: { title: "ایجاد انتقادات", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.CRITICISMS_READ]: { title: "مشاهده انتقادات", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.CRITICISMS_UPDATE]: { title: "ویرایش انتقادات", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.CRITICISMS_DELETE]: { title: "حذف انتقادات", group: PermissionGroupEnum.OTHER },
|
||||||
|
|
||||||
|
[PermissionEnum.CONTACTS_US_CREATE]: { title: "ایجاد تماس با ما", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.CONTACTS_US_READ]: { title: "مشاهده تماس با ما", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.CONTACTS_US_UPDATE]: { title: "ویرایش تماس با ما", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.CONTACTS_US_DELETE]: { title: "حذف تماس با ما", group: PermissionGroupEnum.OTHER },
|
||||||
|
|
||||||
|
[PermissionEnum.ADVERTISEMENTS_CREATE]: { title: "ایجاد تبلیغات", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.ADVERTISEMENTS_READ]: { title: "مشاهده تبلیغات", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.ADVERTISEMENTS_UPDATE]: { title: "ویرایش تبلیغات", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.ADVERTISEMENTS_DELETE]: { title: "حذف تبلیغات", group: PermissionGroupEnum.CONTENT },
|
||||||
|
|
||||||
|
[PermissionEnum.ANNOUNCEMENTS_CREATE]: { title: "ایجاد اطلاعیهها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.ANNOUNCEMENTS_READ]: { title: "مشاهده اطلاعیهها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.ANNOUNCEMENTS_UPDATE]: { title: "ویرایش اطلاعیهها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.ANNOUNCEMENTS_DELETE]: { title: "حذف اطلاعیهها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
|
||||||
|
[PermissionEnum.BLOGS_CREATE]: { title: "ایجاد بلاگها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.BLOGS_READ]: { title: "مشاهده بلاگها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.BLOGS_UPDATE]: { title: "ویرایش بلاگها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
[PermissionEnum.BLOGS_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 },
|
||||||
|
[PermissionEnum.LEARNINGS_DELETE]: { title: "حذف آموزشها", group: PermissionGroupEnum.CONTENT },
|
||||||
|
|
||||||
|
[PermissionEnum.SETTINGS_CREATE]: { title: "ایجاد تنظیمات", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.SETTINGS_READ]: { title: "مشاهده تنظیمات", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.SETTINGS_UPDATE]: { title: "ویرایش تنظیمات", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.SETTINGS_DELETE]: { title: "حذف تنظیمات", group: PermissionGroupEnum.OTHER },
|
||||||
|
|
||||||
|
[PermissionEnum.BANK_ACCOUNTS_CREATE]: { title: "ایجاد حسابهای بانکی", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.BANK_ACCOUNTS_READ]: { title: "مشاهده حسابهای بانکی", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.BANK_ACCOUNTS_UPDATE]: { title: "ویرایش حسابهای بانکی", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.BANK_ACCOUNTS_DELETE]: { title: "حذف حسابهای بانکی", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
|
||||||
|
[PermissionEnum.PAYMENTS_CREATE]: { title: "ایجاد پرداختها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.PAYMENTS_READ]: { title: "مشاهده پرداختها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.PAYMENTS_UPDATE]: { title: "ویرایش پرداختها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
[PermissionEnum.PAYMENTS_DELETE]: { title: "حذف پرداختها", group: PermissionGroupEnum.FINANCIAL },
|
||||||
|
|
||||||
|
[PermissionEnum.SUPPORT_PLAN_CREATE]: { title: "ایجاد پلن پشتیبانی", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
[PermissionEnum.SUPPORT_PLAN_READ]: { title: "مشاهده پلن پشتیبانی", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
[PermissionEnum.SUPPORT_PLAN_UPDATE]: { title: "ویرایش پلن پشتیبانی", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
[PermissionEnum.SUPPORT_PLAN_DELETE]: { title: "حذف پلن پشتیبانی", group: PermissionGroupEnum.SUPPORT },
|
||||||
|
|
||||||
|
[PermissionEnum.RESELLER_CREATE]: { title: "ایجاد نمایندگی فروش", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
[PermissionEnum.RESELLER_READ]: { title: "مشاهده نمایندگی فروش", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
[PermissionEnum.RESELLER_UPDATE]: { title: "ویرایش نمایندگی فروش", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
[PermissionEnum.RESELLER_DELETE]: { title: "حذف نمایندگی فروش", group: PermissionGroupEnum.REPRESENTATIVES },
|
||||||
|
|
||||||
|
[PermissionEnum.WORKSPACE_CREATE]: { title: "ایجاد فضای کار", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.WORKSPACE_READ]: { title: "مشاهده فضای کار", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.WORKSPACE_UPDATE]: { title: "ویرایش فضای کار", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.WORKSPACE_DELETE]: { title: "حذف فضای کار", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
|
||||||
|
[PermissionEnum.PROJECT_CREATE]: { title: "ایجاد پروژه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.PROJECT_READ]: { title: "مشاهده پروژه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.PROJECT_UPDATE]: { title: "ویرایش پروژه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.PROJECT_DELETE]: { title: "حذف پروژه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
|
||||||
|
[PermissionEnum.TASK_CREATE]: { title: "ایجاد وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.TASK_READ]: { title: "مشاهده وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.TASK_UPDATE]: { title: "ویرایش وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.TASK_DELETE]: { title: "حذف وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
|
||||||
|
[PermissionEnum.TASK_PHASE_CREATE]: { title: "ایجاد فاز وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.TASK_PHASE_READ]: { title: "مشاهده فاز وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.TASK_PHASE_UPDATE]: { title: "ویرایش فاز وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
[PermissionEnum.TASK_PHASE_DELETE]: { title: "حذف فاز وظیفه", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
|
||||||
|
[PermissionEnum.LOGS]: { title: "لاگها", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.MANAGE_SSO_CLIENTS]: { title: "مدیریت کلاینتهای SSO", group: PermissionGroupEnum.OTHER },
|
||||||
|
[PermissionEnum.DMENU]: { title: "دیمنو", group: PermissionGroupEnum.PRODUCTS },
|
||||||
|
[PermissionEnum.DKALA]: { title: "دیکالا", group: PermissionGroupEnum.PRODUCTS },
|
||||||
|
[PermissionEnum.DPAGE]: { title: "دیپیج", group: PermissionGroupEnum.PRODUCTS },
|
||||||
|
[PermissionEnum.DMAIL]: { title: "دیمیل", group: PermissionGroupEnum.PRODUCTS },
|
||||||
|
// [PermissionEnum.VIEW_ALL_WORKSPACES]: { title: "مشاهده همه فضاهای کار", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
// [PermissionEnum.VIEW_ALL_PROJECTS]: { title: "مشاهده همه پروژهها", group: PermissionGroupEnum.TASK_MANAGER },
|
||||||
|
};
|
||||||
@@ -3,12 +3,19 @@ import { Column, Entity, ManyToMany } from "typeorm";
|
|||||||
import { Role } from "./role.entity";
|
import { Role } from "./role.entity";
|
||||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
import { PermissionEnum } from "../enums/permission.enum";
|
import { PermissionEnum } from "../enums/permission.enum";
|
||||||
|
import { PermissionGroupEnum } from "../enums/permission-group.enum";
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Permission extends BaseEntity {
|
export class Permission extends BaseEntity {
|
||||||
@Column({ type: "enum", enum: PermissionEnum, nullable: false, unique: true })
|
@Column({ type: "enum", enum: PermissionEnum, nullable: false, unique: true })
|
||||||
name: PermissionEnum;
|
name: PermissionEnum;
|
||||||
|
|
||||||
|
@Column({ type: "varchar", length: 150, nullable: false })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Column({ type: "enum", enum: PermissionGroupEnum, nullable: false })
|
||||||
|
group: PermissionGroupEnum;
|
||||||
|
|
||||||
@ManyToMany(() => Role, (role) => role.permissions)
|
@ManyToMany(() => Role, (role) => role.permissions)
|
||||||
roles: Role[];
|
roles: Role[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export enum PermissionGroupEnum {
|
||||||
|
SERVICES = "services",
|
||||||
|
CUSTOMERS = "customers",
|
||||||
|
USERS = "users",
|
||||||
|
FINANCIAL = "financial",
|
||||||
|
CONTENT = "content",
|
||||||
|
SUPPORT = "support",
|
||||||
|
OTHER = "other",
|
||||||
|
PRODUCTS = "products",
|
||||||
|
REPRESENTATIVES = "representatives",
|
||||||
|
TASK_MANAGER = "task_manager",
|
||||||
|
}
|
||||||
@@ -1,28 +1,155 @@
|
|||||||
export enum PermissionEnum {
|
export enum PermissionEnum {
|
||||||
SERVICES = "services",
|
// services
|
||||||
CUSTOMERS = "customers",
|
SERVICES_CREATE = "services_create",
|
||||||
AGENTS = "agents",
|
SERVICES_READ = "services_read",
|
||||||
DEVELOPERS = "developers",
|
SERVICES_UPDATE = "services_update",
|
||||||
INVOICES = "invoices",
|
SERVICES_DELETE = "services_delete",
|
||||||
TRANSACTIONS = "transactions",
|
|
||||||
DISCOUNTS = "discounts",
|
// customers
|
||||||
ADMINS = "admins",
|
CUSTOMERS_CREATE = "customers_create",
|
||||||
TICKETS = "tickets",
|
CUSTOMERS_READ = "customers_read",
|
||||||
CRITICISMS = "criticisms",
|
CUSTOMERS_UPDATE = "customers_update",
|
||||||
CONTACTS_US = "contacts_us",
|
CUSTOMERS_DELETE = "customers_delete",
|
||||||
ADVERTISEMENTS = "advertisements",
|
|
||||||
ANNOUNCEMENTS = "announcements",
|
// agents
|
||||||
BLOGS = "blogs",
|
AGENTS_CREATE = "agents_create",
|
||||||
LEARNINGS = "learnings",
|
AGENTS_READ = "agents_read",
|
||||||
|
AGENTS_UPDATE = "agents_update",
|
||||||
|
AGENTS_DELETE = "agents_delete",
|
||||||
|
|
||||||
|
// developers
|
||||||
|
DEVELOPERS_CREATE = "developers_create",
|
||||||
|
DEVELOPERS_READ = "developers_read",
|
||||||
|
DEVELOPERS_UPDATE = "developers_update",
|
||||||
|
DEVELOPERS_DELETE = "developers_delete",
|
||||||
|
|
||||||
|
// invoices
|
||||||
|
INVOICES_CREATE = "invoices_create",
|
||||||
|
INVOICES_READ = "invoices_read",
|
||||||
|
INVOICES_UPDATE = "invoices_update",
|
||||||
|
INVOICES_DELETE = "invoices_delete",
|
||||||
|
|
||||||
|
// transactions
|
||||||
|
TRANSACTIONS_CREATE = "transactions_create",
|
||||||
|
TRANSACTIONS_READ = "transactions_read",
|
||||||
|
TRANSACTIONS_UPDATE = "transactions_update",
|
||||||
|
TRANSACTIONS_DELETE = "transactions_delete",
|
||||||
|
|
||||||
|
// discounts
|
||||||
|
DISCOUNTS_CREATE = "discounts_create",
|
||||||
|
DISCOUNTS_READ = "discounts_read",
|
||||||
|
DISCOUNTS_UPDATE = "discounts_update",
|
||||||
|
DISCOUNTS_DELETE = "discounts_delete",
|
||||||
|
|
||||||
|
// admins
|
||||||
|
ADMINS_CREATE = "admins_create",
|
||||||
|
ADMINS_READ = "admins_read",
|
||||||
|
ADMINS_UPDATE = "admins_update",
|
||||||
|
ADMINS_DELETE = "admins_delete",
|
||||||
|
|
||||||
|
// tickets
|
||||||
|
TICKETS_CREATE = "tickets_create",
|
||||||
|
TICKETS_READ = "tickets_read",
|
||||||
|
TICKETS_UPDATE = "tickets_update",
|
||||||
|
TICKETS_DELETE = "tickets_delete",
|
||||||
|
|
||||||
|
// criticisms
|
||||||
|
CRITICISMS_CREATE = "criticisms_create",
|
||||||
|
CRITICISMS_READ = "criticisms_read",
|
||||||
|
CRITICISMS_UPDATE = "criticisms_update",
|
||||||
|
CRITICISMS_DELETE = "criticisms_delete",
|
||||||
|
|
||||||
|
// contacts_us
|
||||||
|
CONTACTS_US_CREATE = "contacts_us_create",
|
||||||
|
CONTACTS_US_READ = "contacts_us_read",
|
||||||
|
CONTACTS_US_UPDATE = "contacts_us_update",
|
||||||
|
CONTACTS_US_DELETE = "contacts_us_delete",
|
||||||
|
|
||||||
|
// advertisements
|
||||||
|
ADVERTISEMENTS_CREATE = "advertisements_create",
|
||||||
|
ADVERTISEMENTS_READ = "advertisements_read",
|
||||||
|
ADVERTISEMENTS_UPDATE = "advertisements_update",
|
||||||
|
ADVERTISEMENTS_DELETE = "advertisements_delete",
|
||||||
|
|
||||||
|
// announcements
|
||||||
|
ANNOUNCEMENTS_CREATE = "announcements_create",
|
||||||
|
ANNOUNCEMENTS_READ = "announcements_read",
|
||||||
|
ANNOUNCEMENTS_UPDATE = "announcements_update",
|
||||||
|
ANNOUNCEMENTS_DELETE = "announcements_delete",
|
||||||
|
|
||||||
|
// blogs
|
||||||
|
BLOGS_CREATE = "blogs_create",
|
||||||
|
BLOGS_READ = "blogs_read",
|
||||||
|
BLOGS_UPDATE = "blogs_update",
|
||||||
|
BLOGS_DELETE = "blogs_delete",
|
||||||
|
|
||||||
|
// learnings
|
||||||
|
LEARNINGS_CREATE = "learnings_create",
|
||||||
|
LEARNINGS_READ = "learnings_read",
|
||||||
|
LEARNINGS_UPDATE = "learnings_update",
|
||||||
|
LEARNINGS_DELETE = "learnings_delete",
|
||||||
|
|
||||||
|
// settings
|
||||||
|
SETTINGS_CREATE = "settings_create",
|
||||||
|
SETTINGS_READ = "settings_read",
|
||||||
|
SETTINGS_UPDATE = "settings_update",
|
||||||
|
SETTINGS_DELETE = "settings_delete",
|
||||||
|
|
||||||
|
// bank_accounts
|
||||||
|
BANK_ACCOUNTS_CREATE = "bank_accounts_create",
|
||||||
|
BANK_ACCOUNTS_READ = "bank_accounts_read",
|
||||||
|
BANK_ACCOUNTS_UPDATE = "bank_accounts_update",
|
||||||
|
BANK_ACCOUNTS_DELETE = "bank_accounts_delete",
|
||||||
|
|
||||||
|
// payments
|
||||||
|
PAYMENTS_CREATE = "payments_create",
|
||||||
|
PAYMENTS_READ = "payments_read",
|
||||||
|
PAYMENTS_UPDATE = "payments_update",
|
||||||
|
PAYMENTS_DELETE = "payments_delete",
|
||||||
|
|
||||||
|
// support_plan
|
||||||
|
SUPPORT_PLAN_CREATE = "support_plan_create",
|
||||||
|
SUPPORT_PLAN_READ = "support_plan_read",
|
||||||
|
SUPPORT_PLAN_UPDATE = "support_plan_update",
|
||||||
|
SUPPORT_PLAN_DELETE = "support_plan_delete",
|
||||||
|
|
||||||
|
// reseller
|
||||||
|
RESELLER_CREATE = "reseller_create",
|
||||||
|
RESELLER_READ = "reseller_read",
|
||||||
|
RESELLER_UPDATE = "reseller_update",
|
||||||
|
RESELLER_DELETE = "reseller_delete",
|
||||||
|
|
||||||
|
// workspace
|
||||||
|
WORKSPACE_CREATE = "workspace_create",
|
||||||
|
WORKSPACE_READ = "workspace_read",
|
||||||
|
WORKSPACE_UPDATE = "workspace_update",
|
||||||
|
WORKSPACE_DELETE = "workspace_delete",
|
||||||
|
|
||||||
|
// project
|
||||||
|
PROJECT_CREATE = "project_create",
|
||||||
|
PROJECT_READ = "project_read",
|
||||||
|
PROJECT_UPDATE = "project_update",
|
||||||
|
PROJECT_DELETE = "project_delete",
|
||||||
|
|
||||||
|
// task
|
||||||
|
TASK_CREATE = "task_create",
|
||||||
|
TASK_READ = "task_read",
|
||||||
|
TASK_UPDATE = "task_update",
|
||||||
|
TASK_DELETE = "task_delete",
|
||||||
|
|
||||||
|
// task_phase
|
||||||
|
TASK_PHASE_CREATE = "task_phase_create",
|
||||||
|
TASK_PHASE_READ = "task_phase_read",
|
||||||
|
TASK_PHASE_UPDATE = "task_phase_update",
|
||||||
|
TASK_PHASE_DELETE = "task_phase_delete",
|
||||||
|
|
||||||
|
// single permissions (no CRUD split)
|
||||||
LOGS = "logs",
|
LOGS = "logs",
|
||||||
SETTINGS = "settings",
|
|
||||||
BANK_ACCOUNTS = "bank_accounts",
|
|
||||||
PAYMENTS = "payments",
|
|
||||||
MANAGE_SSO_CLIENTS = "manage_sso_clients",
|
MANAGE_SSO_CLIENTS = "manage_sso_clients",
|
||||||
SUPPORT_PLAN = "support_plan",
|
|
||||||
DMENU = "dmenu",
|
DMENU = "dmenu",
|
||||||
DKALA = "dkala",
|
DKALA = "dkala",
|
||||||
DPAGE = "dpage",
|
DPAGE = "dpage",
|
||||||
DMAIL = 'dmail',
|
DMAIL = "dmail",
|
||||||
RESELLER="reseller"
|
// VIEW_ALL_WORKSPACES = "view_all_workspaces",
|
||||||
|
// VIEW_ALL_PROJECTS = "view_all_projects",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,7 +288,10 @@ export class AdminsService {
|
|||||||
/************************************************************ */
|
/************************************************************ */
|
||||||
|
|
||||||
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, title: true, group: true },
|
||||||
|
order: { group: "ASC", name: "ASC" },
|
||||||
|
});
|
||||||
return {
|
return {
|
||||||
permissions,
|
permissions,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -188,7 +188,7 @@ export class UserRepository extends Repository<User> {
|
|||||||
.leftJoinAndSelect("role.permissions", "permissions")
|
.leftJoinAndSelect("role.permissions", "permissions")
|
||||||
.andWhere("user.deletedAt IS NULL");
|
.andWhere("user.deletedAt IS NULL");
|
||||||
// .where("permissions.name IN (:...adminPermissions)", {
|
// .where("permissions.name IN (:...adminPermissions)", {
|
||||||
// adminPermissions: [PermissionEnum.ADMINS],
|
// adminPermissions: [PermissionEnum.ADMINS_READ],
|
||||||
// });
|
// });
|
||||||
// .addSelect(["permissions.id", "permissions.name"]);
|
// .addSelect(["permissions.id", "permissions.name"]);
|
||||||
|
|
||||||
|
|||||||
@@ -113,21 +113,21 @@ export class UsersController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Create user group ==> admin route" })
|
@ApiOperation({ summary: "Create user group ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_CREATE, PermissionEnum.CUSTOMERS_CREATE)
|
||||||
@Post("user-group")
|
@Post("user-group")
|
||||||
createUserGroup(@Body() createDto: CreateUserGroupDto) {
|
createUserGroup(@Body() createDto: CreateUserGroupDto) {
|
||||||
return this.usersService.createUserGroup(createDto);
|
return this.usersService.createUserGroup(createDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all user group ==> admin route" })
|
@ApiOperation({ summary: "get all user group ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("user-group")
|
@Get("user-group")
|
||||||
UserGroups() {
|
UserGroups() {
|
||||||
return this.usersService.getUserGroups();
|
return this.usersService.getUserGroups();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all users ==> admin route" })
|
@ApiOperation({ summary: "get all users ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get()
|
@Get()
|
||||||
getUsers() {
|
getUsers() {
|
||||||
return this.usersService.findAllUsers();
|
return this.usersService.findAllUsers();
|
||||||
@@ -136,12 +136,14 @@ export class UsersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "Create customer" })
|
@ApiOperation({ summary: "Create customer" })
|
||||||
@HttpCode(HttpStatus.CREATED)
|
@HttpCode(HttpStatus.CREATED)
|
||||||
|
@PermissionsDec(PermissionEnum.CUSTOMERS_CREATE)
|
||||||
@Post("customers")
|
@Post("customers")
|
||||||
createCustomer(@Body() createDto: CreateCustomerDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createCustomer(@Body() createDto: CreateCustomerDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.customersService.createCustomer(createDto, userIpAndHeaders);
|
return this.customersService.createCustomer(createDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Update customer" })
|
@ApiOperation({ summary: "Update customer" })
|
||||||
|
@PermissionsDec(PermissionEnum.CUSTOMERS_UPDATE)
|
||||||
@Patch("customers/:id")
|
@Patch("customers/:id")
|
||||||
updateCustomer(
|
updateCustomer(
|
||||||
@Param() paramDto: ParamDto,
|
@Param() paramDto: ParamDto,
|
||||||
@@ -152,14 +154,14 @@ export class UsersController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get customers ==> admin route" })
|
@ApiOperation({ summary: "get customers ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("customers")
|
@Get("customers")
|
||||||
getCustomers(@Query() queryDto: SearchCustomersDto) {
|
getCustomers(@Query() queryDto: SearchCustomersDto) {
|
||||||
return this.customersService.getCustomers(queryDto);
|
return this.customersService.getCustomers(queryDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get customers by id ==> admin route" })
|
@ApiOperation({ summary: "get customers by id ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("customers/:id")
|
@Get("customers/:id")
|
||||||
getCustomerById(@Param() paramDto: ParamDto) {
|
getCustomerById(@Param() paramDto: ParamDto) {
|
||||||
return this.customersService.getCustomerById(paramDto.id);
|
return this.customersService.getCustomerById(paramDto.id);
|
||||||
@@ -169,35 +171,35 @@ export class UsersController {
|
|||||||
|
|
||||||
@ApiOperation({ summary: "get all admins ==> admin route" })
|
@ApiOperation({ summary: "get all admins ==> admin route" })
|
||||||
@AdminRoute()
|
@AdminRoute()
|
||||||
// @PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
// @PermissionsDec(PermissionEnum.ADMINS_READ, PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("admins")
|
@Get("admins")
|
||||||
getAdmins(@Query() queryDto: SearchAdminQueryDto) {
|
getAdmins(@Query() queryDto: SearchAdminQueryDto) {
|
||||||
return this.adminsService.getAdmins(queryDto);
|
return this.adminsService.getAdmins(queryDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get admin by id ==> admin route" })
|
@ApiOperation({ summary: "get admin by id ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_READ, PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("admins/:id")
|
@Get("admins/:id")
|
||||||
getAdminById(@Param() paramDto: ParamDto) {
|
getAdminById(@Param() paramDto: ParamDto) {
|
||||||
return this.adminsService.getAdminById(paramDto.id);
|
return this.adminsService.getAdminById(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "update admin ==> admin route" })
|
@ApiOperation({ summary: "update admin ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_UPDATE, PermissionEnum.CUSTOMERS_UPDATE)
|
||||||
@Patch("admins/:id")
|
@Patch("admins/:id")
|
||||||
updateAdmin(@Param() paramDto: ParamDto, @Body() updateDto: UpdateAdminDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
updateAdmin(@Param() paramDto: ParamDto, @Body() updateDto: UpdateAdminDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.adminsService.updateAdmin(paramDto.id, updateDto, userIpAndHeaders);
|
return this.adminsService.updateAdmin(paramDto.id, updateDto, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "delete admin ==> admin route" })
|
@ApiOperation({ summary: "delete admin ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_DELETE, PermissionEnum.CUSTOMERS_DELETE)
|
||||||
@Delete("admins/:id")
|
@Delete("admins/:id")
|
||||||
deleteAdmin(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
deleteAdmin(@Param() paramDto: ParamDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.adminsService.deleteAdmin(paramDto.id, userIpAndHeaders);
|
return this.adminsService.deleteAdmin(paramDto.id, userIpAndHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "create admin ==> admin route" })
|
@ApiOperation({ summary: "create admin ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_CREATE, PermissionEnum.CUSTOMERS_CREATE)
|
||||||
@Post("admins")
|
@Post("admins")
|
||||||
createAdmin(@Body() createDto: CreateAdminDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
createAdmin(@Body() createDto: CreateAdminDto, @UserIpAndHeaders() userIpAndHeaders: IUserIpAndHeaders) {
|
||||||
return this.adminsService.createAdmin(createDto, userIpAndHeaders);
|
return this.adminsService.createAdmin(createDto, userIpAndHeaders);
|
||||||
@@ -210,42 +212,42 @@ export class UsersController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all permissions ==> admin route" })
|
@ApiOperation({ summary: "get all permissions ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_READ, PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("permissions")
|
@Get("permissions")
|
||||||
getPermissions() {
|
getPermissions() {
|
||||||
return this.adminsService.getPermissions();
|
return this.adminsService.getPermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get all roles ==> admin route" })
|
@ApiOperation({ summary: "get all roles ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_READ, PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("roles")
|
@Get("roles")
|
||||||
getRoles(@Query() queryDto: SearchRolesQueryDto) {
|
getRoles(@Query() queryDto: SearchRolesQueryDto) {
|
||||||
return this.adminsService.getRoles(queryDto);
|
return this.adminsService.getRoles(queryDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "get role by id ==> admin route" })
|
@ApiOperation({ summary: "get role by id ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_READ, PermissionEnum.CUSTOMERS_READ)
|
||||||
@Get("roles/:id")
|
@Get("roles/:id")
|
||||||
getRoleById(@Param() paramDto: ParamDto) {
|
getRoleById(@Param() paramDto: ParamDto) {
|
||||||
return this.adminsService.getRoleById(paramDto.id);
|
return this.adminsService.getRoleById(paramDto.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "create role ==> admin route" })
|
@ApiOperation({ summary: "create role ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_CREATE, PermissionEnum.CUSTOMERS_CREATE)
|
||||||
@Post("roles")
|
@Post("roles")
|
||||||
createRole(@Body() createDto: CreateRoleDto) {
|
createRole(@Body() createDto: CreateRoleDto) {
|
||||||
return this.adminsService.createRole(createDto);
|
return this.adminsService.createRole(createDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "update role ==> admin route" })
|
@ApiOperation({ summary: "update role ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_UPDATE, PermissionEnum.CUSTOMERS_UPDATE)
|
||||||
@Patch("roles/:id")
|
@Patch("roles/:id")
|
||||||
updateRole(@Param() paramDto: ParamDto, @Body() updateDto: UpdateRoleDto) {
|
updateRole(@Param() paramDto: ParamDto, @Body() updateDto: UpdateRoleDto) {
|
||||||
return this.adminsService.updateRole(paramDto.id, updateDto);
|
return this.adminsService.updateRole(paramDto.id, updateDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "delete role ==> admin route" })
|
@ApiOperation({ summary: "delete role ==> admin route" })
|
||||||
@PermissionsDec(PermissionEnum.ADMINS, PermissionEnum.CUSTOMERS)
|
@PermissionsDec(PermissionEnum.ADMINS_DELETE, PermissionEnum.CUSTOMERS_DELETE)
|
||||||
@Delete("roles/:id")
|
@Delete("roles/:id")
|
||||||
deleteRole(@Param() paramDto: ParamDto) {
|
deleteRole(@Param() paramDto: ParamDto) {
|
||||||
return this.adminsService.deleteRole(paramDto.id);
|
return this.adminsService.deleteRole(paramDto.id);
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { BadRequestException } from "@nestjs/common";
|
||||||
|
|
||||||
|
interface CursorPayload {
|
||||||
|
priority: number;
|
||||||
|
createdAt: Date;
|
||||||
|
id: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodeCursor(cursor: string): CursorPayload {
|
||||||
|
try {
|
||||||
|
const decoded = Buffer.from(cursor, "base64").toString("utf-8");
|
||||||
|
const [priorityStr, timestamp, id] = decoded.split("|");
|
||||||
|
if (!priorityStr || !timestamp || !id) throw new Error("Invalid format");
|
||||||
|
const priority = parseInt(priorityStr, 10);
|
||||||
|
if (isNaN(priority)) throw new Error("Priority not a number");
|
||||||
|
const createdAt = new Date(timestamp);
|
||||||
|
if (isNaN(createdAt.getTime())) throw new Error("Invalid date");
|
||||||
|
return { priority, createdAt, id };
|
||||||
|
} catch {
|
||||||
|
throw new BadRequestException(
|
||||||
|
"Invalid cursor. Expected base64‑encoded string containing priority, ISO date and id (separated by '|').",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function encodeCursor(task: { priority: number; createdAt: Date; id: string }): string {
|
||||||
|
return Buffer.from(`${task.priority}|${task.createdAt.toISOString()}|${task.id}`).toString("base64");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user