From e728303d530691f1da1d1160c8f249729130fef4 Mon Sep 17 00:00:00 2001 From: mahdi rafie Date: Mon, 29 Jun 2026 16:43:17 +0330 Subject: [PATCH] adding entities for taskmanager --- package-lock.json | 53 +++++----------- .../dto/workspace/create-workspace.dto.ts | 25 ++++++++ .../dto/workspace/update-workspace.dto.ts | 4 ++ .../entities/attachment.entity.ts | 33 ++++++++++ .../entities/check-list-item.entity.ts | 24 ++++++++ .../task-manager/entities/project.entity.ts | 36 +++++++++++ .../task-manager/entities/remark.entity.ts | 24 ++++++++ .../entities/task-phase.entity.ts | 33 ++++++++++ .../task-manager/entities/task.entity.ts | 60 +++++++++++++++++++ .../entities/workspace-type.entity.ts | 20 +++++++ .../task-manager/entities/workspace.entity.ts | 42 +++++++++++++ .../enums/attachment-type.enum.ts | 6 ++ .../providers/workspace.service.ts | 41 +++++++++++++ .../repositories/workspace.repository.ts | 41 +++++++++++++ .../task-manager/task-manager.controller.ts | 38 ++++++++++++ .../task-manager/task-manager.module.ts | 51 ++++++++++++++++ src/modules/users/entities/user.entity.ts | 18 ++++-- src/modules/users/users.module.ts | 2 + 18 files changed, 507 insertions(+), 44 deletions(-) create mode 100644 src/modules/task-manager/dto/workspace/create-workspace.dto.ts create mode 100644 src/modules/task-manager/dto/workspace/update-workspace.dto.ts create mode 100644 src/modules/task-manager/entities/attachment.entity.ts create mode 100644 src/modules/task-manager/entities/check-list-item.entity.ts create mode 100644 src/modules/task-manager/entities/project.entity.ts create mode 100644 src/modules/task-manager/entities/remark.entity.ts create mode 100644 src/modules/task-manager/entities/task-phase.entity.ts create mode 100644 src/modules/task-manager/entities/task.entity.ts create mode 100644 src/modules/task-manager/entities/workspace-type.entity.ts create mode 100644 src/modules/task-manager/entities/workspace.entity.ts create mode 100644 src/modules/task-manager/enums/attachment-type.enum.ts create mode 100644 src/modules/task-manager/providers/workspace.service.ts create mode 100644 src/modules/task-manager/repositories/workspace.repository.ts create mode 100644 src/modules/task-manager/task-manager.controller.ts create mode 100644 src/modules/task-manager/task-manager.module.ts diff --git a/package-lock.json b/package-lock.json index b5dab37..1b1b3b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1191,7 +1191,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -2695,7 +2694,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@fastify/accept-negotiator": "^2.0.0", "@fastify/send": "^4.0.0", @@ -4461,7 +4459,6 @@ "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-11.1.8.tgz", "integrity": "sha512-bbsOqwld/GdBfiRNc4nnjyWWENDEicq4SH+R5AuYatvf++vf1x5JIsHB1i1KtfZMD3eRte0D4K9WXuAYil6XAg==", "license": "MIT", - "peer": true, "dependencies": { "file-type": "21.0.0", "iterare": "1.2.1", @@ -4521,7 +4518,6 @@ "integrity": "sha512-7riWfmTmMhCJHZ5ZiaG+crj4t85IPCq/wLRuOUSigBYyFT2JZj0lVHtAdf4Davp9ouNI8GINBDt9h9b5Gz9nTw==", "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@nuxt/opencollective": "0.4.1", "fast-safe-stringify": "2.1.1", @@ -4605,7 +4601,6 @@ "resolved": "https://registry.npmjs.org/@nestjs/platform-fastify/-/platform-fastify-11.1.8.tgz", "integrity": "sha512-4XiiTiTkF9UbVDAuHDyVIzgr43L2sI3vLs9A52ov2lrOJcqyKwTYL/NiCQd4dtUQm1L6M0jOrJhzpYXobX5uMw==", "license": "MIT", - "peer": true, "dependencies": { "@fastify/cors": "11.1.0", "@fastify/formbody": "8.0.2", @@ -4808,7 +4803,6 @@ "resolved": "https://registry.npmjs.org/@nestjs/throttler/-/throttler-6.4.0.tgz", "integrity": "sha512-osL67i0PUuwU5nqSuJjtUJZMkxAnYB4VldgYUMGzvYRJDCqGRFMWbsbzm/CkUtPLRL30I8T74Xgt/OQxnYokiA==", "license": "MIT", - "peer": true, "peerDependencies": { "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", "@nestjs/core": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0", @@ -4916,6 +4910,7 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } @@ -5937,7 +5932,6 @@ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -6107,7 +6101,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.27.tgz", "integrity": "sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -6299,7 +6292,6 @@ "integrity": "sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.4", "@typescript-eslint/types": "8.46.4", @@ -7007,7 +6999,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "devOptional": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -7056,7 +7047,6 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -7483,7 +7473,6 @@ "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", "license": "MIT", - "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -7736,7 +7725,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/bl": { "version": "4.1.0", @@ -7845,7 +7835,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -7933,7 +7922,6 @@ "resolved": "https://registry.npmjs.org/bullmq/-/bullmq-5.63.0.tgz", "integrity": "sha512-HT1iM3Jt4bZeg3Ru/MxrOy2iIItxcl1Pz5Ync1Vrot70jBpVguMxFEiSaDU57BwYwR4iwnObDnzct2lirKkX5A==", "license": "MIT", - "peer": true, "dependencies": { "cron-parser": "^4.9.0", "ioredis": "^5.4.1", @@ -7962,7 +7950,6 @@ "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-6.4.3.tgz", "integrity": "sha512-VV5eq/QQ5rIVix7/aICO4JyvSeEv9eIQuKL5iFwgM2BrcYoE0A/D1mNsAHJAsB0WEbNdBlKkn6Tjz6fKzh/cKQ==", "license": "MIT", - "peer": true, "dependencies": { "keyv": "^5.3.3" } @@ -8152,7 +8139,6 @@ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -8200,15 +8186,13 @@ "version": "0.5.1", "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/class-validator": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz", "integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==", "license": "MIT", - "peer": true, "dependencies": { "@types/validator": "^13.11.8", "libphonenumber-js": "^1.11.1", @@ -8688,7 +8672,6 @@ "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "env-paths": "^2.2.1", "import-fresh": "^3.3.0", @@ -9735,7 +9718,6 @@ "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -9796,7 +9778,6 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", - "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -9898,7 +9879,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -11825,7 +11805,6 @@ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.8.2.tgz", "integrity": "sha512-C6uC+kleiIMmjViJINWk80sOQw5lEzse1ZmvD+S/s8p8CWapftSaC+kocGTx6xrbrJ4WmYQGC08ffHLr6ToR6Q==", "license": "MIT", - "peer": true, "dependencies": { "@ioredis/commands": "1.4.0", "cluster-key-slot": "^1.1.0", @@ -12587,7 +12566,6 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -14131,7 +14109,6 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.5.3.tgz", "integrity": "sha512-h0Un1ieD+HUrzBH6dJXhod3ifSghk5Hw/2Y4/KHBziPlZecrFyE9YOTPU6eOs0V9pYl8gOs86fkr/KN8lUX39A==", "license": "MIT", - "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -16010,7 +15987,6 @@ "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.10.1.tgz", "integrity": "sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==", "license": "MIT-0", - "peer": true, "engines": { "node": ">=6.0.0" } @@ -16720,7 +16696,8 @@ "node_modules/pause": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", - "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==", + "peer": true }, "node_modules/peberminta": { "version": "0.9.0", @@ -16748,7 +16725,6 @@ "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.3.tgz", "integrity": "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==", "license": "MIT", - "peer": true, "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", @@ -17066,7 +17042,6 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -17659,8 +17634,7 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz", "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/reflect.getprototypeof": { "version": "1.0.10", @@ -18030,7 +18004,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -18207,7 +18180,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -19155,6 +19127,7 @@ "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==", "license": "MIT", + "peer": true, "dependencies": { "bintrees": "1.0.2" } @@ -19164,7 +19137,6 @@ "resolved": "https://registry.npmjs.org/telegraf/-/telegraf-4.16.3.tgz", "integrity": "sha512-yjEu2NwkHlXu0OARWoNhJlIjX09dRktiMQFsM678BAH/PEPVwctzL67+tvXqLCRQQvm3SDtki2saGO9hLlz68w==", "license": "MIT", - "peer": true, "dependencies": { "@telegraf/types": "^7.1.0", "abort-controller": "^3.0.0", @@ -19765,7 +19737,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -20021,7 +19992,6 @@ "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.27.tgz", "integrity": "sha512-pNV1bn+1n8qEe8tUNsNdD8ejuPcMAg47u2lUGnbsajiNUr3p2Js1XLKQjBMH0yMRMDfdX8T+fIRejFmIwy9x4A==", "license": "MIT", - "peer": true, "dependencies": { "@sqltools/formatter": "^1.2.5", "ansis": "^3.17.0", @@ -20247,7 +20217,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -20499,6 +20468,7 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", + "peer": true, "engines": { "node": ">= 0.4.0" } @@ -20814,6 +20784,7 @@ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^8.0.0" }, @@ -20832,6 +20803,7 @@ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -20846,6 +20818,7 @@ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "engines": { "node": ">=4.0" } @@ -20856,6 +20829,7 @@ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=0.8.x" } @@ -20866,6 +20840,7 @@ "integrity": "sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/json-schema": "^7.0.9", "ajv": "^8.9.0", diff --git a/src/modules/task-manager/dto/workspace/create-workspace.dto.ts b/src/modules/task-manager/dto/workspace/create-workspace.dto.ts new file mode 100644 index 0000000..ac2ef19 --- /dev/null +++ b/src/modules/task-manager/dto/workspace/create-workspace.dto.ts @@ -0,0 +1,25 @@ +import { IsString, IsOptional, IsBoolean, IsNotEmpty, IsUUID, MaxLength } from "class-validator"; + +export class CreateWorkspaceDto { + @IsString() + @IsNotEmpty() + @MaxLength(100) + name: string; + + @IsString() + @IsOptional() + description?: string; + + @IsString() + @IsNotEmpty() + @MaxLength(20) + color: string; + + @IsBoolean() + @IsOptional() + isActive?: boolean; + + @IsUUID() + @IsNotEmpty() + workspaceTypeId: string; +} diff --git a/src/modules/task-manager/dto/workspace/update-workspace.dto.ts b/src/modules/task-manager/dto/workspace/update-workspace.dto.ts new file mode 100644 index 0000000..8d9eef1 --- /dev/null +++ b/src/modules/task-manager/dto/workspace/update-workspace.dto.ts @@ -0,0 +1,4 @@ +import { PartialType } from "@nestjs/mapped-types"; +import { CreateWorkspaceDto } from "./create-workspace.dto"; + +export class UpdateWorkspaceDto extends PartialType(CreateWorkspaceDto) {} diff --git a/src/modules/task-manager/entities/attachment.entity.ts b/src/modules/task-manager/entities/attachment.entity.ts new file mode 100644 index 0000000..ce2ef05 --- /dev/null +++ b/src/modules/task-manager/entities/attachment.entity.ts @@ -0,0 +1,33 @@ +import { + Column, + Entity, + JoinColumn, + ManyToOne, + } from 'typeorm'; + import { BaseEntity } from '../../../common/entities/base.entity'; + import { TMTask } from './task.entity'; + import { TMAttachmentType } from '../enums/attachment-type.enum'; + + @Entity('tm_attachments') + export class TMAttachment extends BaseEntity { + @Column({ type: 'varchar', length: 150 }) + title: string; + + @Column({ type: 'enum', enum: TMAttachmentType }) + type: TMAttachmentType; + + @Column({ type: 'text' }) + file: string; + + // --- Relations --- + + @ManyToOne(() => TMTask, (task) => task.attachments, { + nullable: false, + onDelete: 'CASCADE', + }) + @JoinColumn({ name: 'taskId' }) + task: TMTask; + + @Column({ type: 'uuid' }) + taskId: string; + } \ No newline at end of file diff --git a/src/modules/task-manager/entities/check-list-item.entity.ts b/src/modules/task-manager/entities/check-list-item.entity.ts new file mode 100644 index 0000000..870b438 --- /dev/null +++ b/src/modules/task-manager/entities/check-list-item.entity.ts @@ -0,0 +1,24 @@ +import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { TMTask } from "./task.entity"; + +@Entity("tm_check_list_items") +export class TMCheckListItem extends BaseEntity { + @Column({ type: "varchar", length: 150 }) + title: string; + + @Column({ type: "boolean", default: false }) + isDone: boolean; + + // --- Relations --- + + @ManyToOne(() => TMTask, (task) => task.checkListItems, { + nullable: false, + onDelete: "CASCADE", + }) + @JoinColumn({ name: "taskId" }) + task: TMTask; + + @Column({ type: "uuid" }) + taskId: string; +} diff --git a/src/modules/task-manager/entities/project.entity.ts b/src/modules/task-manager/entities/project.entity.ts new file mode 100644 index 0000000..a4e761b --- /dev/null +++ b/src/modules/task-manager/entities/project.entity.ts @@ -0,0 +1,36 @@ +import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { TMWorkspace } from "./workspace.entity"; +import { TMTaskPhase } from "./task-phase.entity"; + +@Entity("tm_projects") +export class TMProject extends BaseEntity { + @Column({ type: "varchar", length: 150 }) + name: string; + + @Column({ type: "varchar", length: 150, nullable: true }) + ownerName: string; + + @Column({ type: "text", nullable: true }) + description: string; + + @Column({ type: "timestamptz", nullable: true }) + startDate: Date; + + // --- Relations --- + + @ManyToOne(() => TMWorkspace, (workspace) => workspace.projects, { + nullable: false, + onDelete: "RESTRICT", + }) + @JoinColumn({ name: "workspaceId" }) + workspace: TMWorkspace; + + @Column({ type: "uuid" }) + workspaceId: string; + + @OneToMany(() => TMTaskPhase, (taskPhase) => taskPhase.project, { + cascade: ["insert", "update"], + }) + taskPhases: TMTaskPhase[]; +} diff --git a/src/modules/task-manager/entities/remark.entity.ts b/src/modules/task-manager/entities/remark.entity.ts new file mode 100644 index 0000000..5705a20 --- /dev/null +++ b/src/modules/task-manager/entities/remark.entity.ts @@ -0,0 +1,24 @@ +import { Column, Entity, JoinColumn, ManyToOne } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { TMTask } from "./task.entity"; + +@Entity("tm_remarks") +export class TMRemark extends BaseEntity { + @Column({ type: "varchar", length: 150 }) + title: string; + + @Column({ type: "varchar", length: 20, nullable: true }) + color: string; + + // --- Relations --- + + @ManyToOne(() => TMTask, (task) => task.remarks, { + nullable: false, + onDelete: "CASCADE", + }) + @JoinColumn({ name: "taskId" }) + task: TMTask; + + @Column({ type: "uuid" }) + taskId: string; +} diff --git a/src/modules/task-manager/entities/task-phase.entity.ts b/src/modules/task-manager/entities/task-phase.entity.ts new file mode 100644 index 0000000..644166d --- /dev/null +++ b/src/modules/task-manager/entities/task-phase.entity.ts @@ -0,0 +1,33 @@ +import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { TMProject } from "./project.entity"; +import { TMTask } from "./task.entity"; + +@Entity("tm_task_phases") +export class TMTaskPhase extends BaseEntity { + @Column({ type: "varchar", length: 100 }) + name: string; + + @Column({ type: "int", default: 0 }) + order: number; + + @Column({ type: "varchar", length: 20, nullable: true }) + color: string; + + // --- Relations --- + + @ManyToOne(() => TMProject, (project) => project.taskPhases, { + nullable: false, + onDelete: "CASCADE", + }) + @JoinColumn({ name: "projectId" }) + project: TMProject; + + @Column({ type: "uuid" }) + projectId: string; + + @OneToMany(() => TMTask, (task) => task.taskPhase, { + cascade: ["insert", "update"], + }) + tasks: TMTask[]; +} diff --git a/src/modules/task-manager/entities/task.entity.ts b/src/modules/task-manager/entities/task.entity.ts new file mode 100644 index 0000000..bf18fe2 --- /dev/null +++ b/src/modules/task-manager/entities/task.entity.ts @@ -0,0 +1,60 @@ +import { Column, Entity, JoinColumn, ManyToOne, ManyToMany, OneToMany, JoinTable } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { TMTaskPhase } from "./task-phase.entity"; +import { TMRemark } from "./remark.entity"; +import { TMAttachment } from "./attachment.entity"; +import { TMCheckListItem } from "./check-list-item.entity"; +import { User } from "../../users/entities/user.entity"; + +@Entity("tm_tasks") +export class TMTask extends BaseEntity { + @Column({ type: "varchar", length: 150 }) + title: string; + + @Column({ type: "text", nullable: true }) + description: string; + + @Column({ type: "varchar", length: 20, nullable: true }) + color: string; + + @Column({ type: "timestamptz", nullable: true }) + startDate: Date; + + @Column({ type: "timestamptz", nullable: true }) + endDate: Date; + + // --- Relations --- + + @ManyToOne(() => TMTaskPhase, (taskPhase) => taskPhase.tasks, { + nullable: false, + onDelete: "RESTRICT", + }) + @JoinColumn({ name: "taskPhaseId" }) + taskPhase: TMTaskPhase; + + @Column({ type: "uuid" }) + taskPhaseId: string; + + @OneToMany(() => TMRemark, (remark) => remark.task, { + cascade: ["insert", "update"], + }) + remarks: TMRemark[]; + + @OneToMany(() => TMAttachment, (attachment) => attachment.task, { + cascade: ["insert", "update"], + }) + attachments: TMAttachment[]; + + @OneToMany(() => TMCheckListItem, (checkListItem) => checkListItem.task, { + cascade: ["insert", "update"], + }) + checkListItems: TMCheckListItem[]; + + @ManyToMany(() => User, (user) => user.tasks) + @JoinTable({ + name: "tm_task_users", + joinColumn: { name: "taskId", referencedColumnName: "id" }, + inverseJoinColumn: { name: "userId", referencedColumnName: "id" }, + }) + users: User[]; +} diff --git a/src/modules/task-manager/entities/workspace-type.entity.ts b/src/modules/task-manager/entities/workspace-type.entity.ts new file mode 100644 index 0000000..b840242 --- /dev/null +++ b/src/modules/task-manager/entities/workspace-type.entity.ts @@ -0,0 +1,20 @@ +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[]; +} diff --git a/src/modules/task-manager/entities/workspace.entity.ts b/src/modules/task-manager/entities/workspace.entity.ts new file mode 100644 index 0000000..c63366d --- /dev/null +++ b/src/modules/task-manager/entities/workspace.entity.ts @@ -0,0 +1,42 @@ +import { Column, Entity, JoinColumn, JoinTable, ManyToMany, ManyToOne, OneToMany } from "typeorm"; +import { BaseEntity } from "../../../common/entities/base.entity"; +import { TMWorkspaceType } from "./workspace-type.entity"; +import { TMProject } from "./project.entity"; +import { User } from "../../users/entities/user.entity"; + +@Entity("tm_workspaces") +export class TMWorkspace extends BaseEntity { + @Column({ type: "varchar", length: 100 }) + name: string; + + @Column({ type: "text", nullable: true }) + description: string; + + @Column({ type: "varchar", length: 20 }) + color: string; + + @Column({ type: "boolean", default: true }) + isActive: boolean; + + // --- Relations --- + + @ManyToOne(() => TMWorkspaceType, { nullable: false, eager: true }) + @JoinColumn({ name: "workspaceTypeId" }) + workspaceType: TMWorkspaceType; + + @Column({ type: "uuid" }) + workspaceTypeId: string; + + @OneToMany(() => TMProject, (project) => project.workspace, { + cascade: ["insert", "update"], + }) + projects: TMProject[]; + + @ManyToMany(() => User, (user) => user.workspaces) + @JoinTable({ + name: "tm_workspace_users", + joinColumn: { name: "workspaceId", referencedColumnName: "id" }, + inverseJoinColumn: { name: "userId", referencedColumnName: "id" }, + }) + users: User[]; +} diff --git a/src/modules/task-manager/enums/attachment-type.enum.ts b/src/modules/task-manager/enums/attachment-type.enum.ts new file mode 100644 index 0000000..e442e22 --- /dev/null +++ b/src/modules/task-manager/enums/attachment-type.enum.ts @@ -0,0 +1,6 @@ +export enum TMAttachmentType { + FILE = "file", + LINK = "link", + IMAGE = "image", + VIDEO = "video", +} diff --git a/src/modules/task-manager/providers/workspace.service.ts b/src/modules/task-manager/providers/workspace.service.ts new file mode 100644 index 0000000..259b4f1 --- /dev/null +++ b/src/modules/task-manager/providers/workspace.service.ts @@ -0,0 +1,41 @@ +import { Injectable, NotFoundException } from "@nestjs/common"; +import { CreateWorkspaceDto } from "../dto/workspace/create-workspace.dto"; +import { WorkspaceRepository } from "../repositories/workspace.repository"; +import { UpdateWorkspaceDto } from "../dto/workspace/update-workspace.dto"; + +@Injectable() +export class WorkspaceService { + constructor( + private readonly workspaceRepository: WorkspaceRepository, + ) {} + + findAll() { + return this.workspaceRepository.findAll(); + } + + async findOne(id: string) { + const workspace = await this.workspaceRepository.findOneById(id); + + if (!workspace) { + throw new NotFoundException(`Workspace #${id} not found`); + } + + return workspace; + } + + async create(dto: CreateWorkspaceDto) { + const workspace = this.workspaceRepository.create(dto); + return this.workspaceRepository.save(workspace); + } + + async update(id: string, dto: UpdateWorkspaceDto) { + await this.findOne(id); + await this.workspaceRepository.update(id, dto); + return this.findOne(id); + } + + async remove(id: string) { + await this.findOne(id); + await this.workspaceRepository.delete(id); + } +} \ No newline at end of file diff --git a/src/modules/task-manager/repositories/workspace.repository.ts b/src/modules/task-manager/repositories/workspace.repository.ts new file mode 100644 index 0000000..fd38d40 --- /dev/null +++ b/src/modules/task-manager/repositories/workspace.repository.ts @@ -0,0 +1,41 @@ +import { Injectable } from "@nestjs/common"; +import { InjectRepository } from "@nestjs/typeorm"; +import { Repository } from "typeorm"; +import { TMWorkspace } from "../entities/workspace.entity"; + +@Injectable() +export class WorkspaceRepository { + constructor( + @InjectRepository(TMWorkspace) + private readonly repository: Repository, + ) {} + + findAll() { + return this.repository.find({ + relations: ["workspaceType", "projects", "users"], + }); + } + + findOneById(id: string) { + return this.repository.findOne({ + where: { id }, + relations: ["workspaceType", "projects", "users"], + }); + } + + create(data: Partial) { + return this.repository.create(data); + } + + save(workspace: TMWorkspace) { + return this.repository.save(workspace); + } + + update(id: string, data: Partial) { + return this.repository.update(id, data); + } + + delete(id: string) { + return this.repository.delete(id); + } +} diff --git a/src/modules/task-manager/task-manager.controller.ts b/src/modules/task-manager/task-manager.controller.ts new file mode 100644 index 0000000..1d7f245 --- /dev/null +++ b/src/modules/task-manager/task-manager.controller.ts @@ -0,0 +1,38 @@ +import { Controller, Get, Post, Patch, Delete, Param, Body } from '@nestjs/common'; +import { TMWorkspace } from './entities/workspace.entity'; +import { WorkspaceService } from './providers/workspace.service'; +import { CreateWorkspaceDto } from './dto/workspace/create-workspace.dto'; +import { UpdateWorkspaceDto } from './dto/workspace/update-workspace.dto'; + +@Controller('task-manager') +export class TaskManagerController { + constructor( + private readonly workspaceService: WorkspaceService, + ) {} + // --- Workspace --- + + @Get('workspaces') + findAllWorkspaces(): Promise { + return this.workspaceService.findAll(); + } + + @Get('workspaces/:id') + findOneWorkspace(@Param('id') id: string): Promise { + return this.workspaceService.findOne(id); + } + + @Post('workspaces') + createWorkspace(@Body() body: CreateWorkspaceDto): Promise { + return this.workspaceService.create(body); + } + + @Patch('workspaces/:id') + updateWorkspace(@Param('id') id: string, @Body() body: UpdateWorkspaceDto): Promise { + return this.workspaceService.update(id, body); + } + + @Delete('workspaces/:id') + removeWorkspace(@Param('id') id: string): Promise { + return this.workspaceService.remove(id); + } +} \ No newline at end of file diff --git a/src/modules/task-manager/task-manager.module.ts b/src/modules/task-manager/task-manager.module.ts new file mode 100644 index 0000000..d02d0c4 --- /dev/null +++ b/src/modules/task-manager/task-manager.module.ts @@ -0,0 +1,51 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { TMWorkspaceType } from './entities/workspace-type.entity'; +import { TMWorkspace } from './entities/workspace.entity'; +import { TMProject } from './entities/project.entity'; +import { TMTaskPhase } from './entities/task-phase.entity'; +import { TMTask } from './entities/task.entity'; +import { TMRemark } from './entities/remark.entity'; +import { TMAttachment } from './entities/attachment.entity'; +import { TMCheckListItem } from './entities/check-list-item.entity'; +import { WorkspaceRepository } from './repositories/workspace.repository'; +import { TaskManagerController } from './task-manager.controller'; +import { WorkspaceService } from './providers/workspace.service'; + +// import { WorkspaceTypeService } from './providers/workspace-type.service'; +// import { WorkspaceService } from './providers/workspace.service'; +// import { ProjectService } from './providers/project.service'; +// import { TaskPhaseService } from './providers/task-phase.service'; +// import { TaskService } from './providers/task.service'; + +// import { TaskManagerController } from './task-manager.controller'; + +@Module({ + imports: [ + TypeOrmModule.forFeature([ + TMWorkspaceType, + TMWorkspace, + TMProject, + TMTaskPhase, + TMTask, + TMRemark, + TMAttachment, + TMCheckListItem, + ]), + ], + controllers: [TaskManagerController], + providers: [ + WorkspaceRepository, + WorkspaceService, + // WorkspaceTypeService, + // ProjectService, + // TaskPhaseService, + // TaskService, + ], + exports: [ + WorkspaceService, + WorkspaceRepository + ], +}) +export class TaskManagerModule {} \ No newline at end of file diff --git a/src/modules/users/entities/user.entity.ts b/src/modules/users/entities/user.entity.ts index 2237188..abcd099 100755 --- a/src/modules/users/entities/user.entity.ts +++ b/src/modules/users/entities/user.entity.ts @@ -32,6 +32,8 @@ import { Wallet } from "../../wallets/entities/wallet.entity"; import { FinancialType } from "../enums/financial-type.enum"; import { Reseller } from "../../reseller/entities/reseller.entity"; import { UserBankAccount } from "../../reseller/entities/user-bank-account.entity"; +import { TMWorkspace } from "../../task-manager/entities/workspace.entity"; +import { TMTask } from "../../task-manager/entities/task.entity"; @Entity() export class User extends BaseEntity { @@ -167,14 +169,20 @@ export class User extends BaseEntity { //--------------------------------------- @ManyToOne(() => Reseller, (reseller) => reseller.agents, { nullable: true }) - reseller?: Reseller + reseller?: Reseller; - - @OneToOne(() => Reseller, reseller => reseller.owner, { nullable: true }) - ownedReseller?: Reseller + @OneToOne(() => Reseller, (reseller) => reseller.owner, { nullable: true }) + ownedReseller?: Reseller; //------------------------ @OneToOne(() => UserBankAccount, (account) => account.user, { nullable: true }) - bankAckount: UserBankAccount + bankAckount: UserBankAccount; + + // ----------------------- + @ManyToMany(() => TMWorkspace, (workspace) => workspace.users) + workspaces: TMWorkspace[]; + + @ManyToMany(() => TMTask, (task) => task.users) + tasks: TMTask[]; } diff --git a/src/modules/users/users.module.ts b/src/modules/users/users.module.ts index 1d24e7a..68afdc5 100755 --- a/src/modules/users/users.module.ts +++ b/src/modules/users/users.module.ts @@ -28,6 +28,7 @@ import { AdminsService } from "./providers/admins.service"; import { CustomersService } from "./providers/customers.service"; import { RefreshTokensRepository } from "./repositories/refresh-token.repository"; import { ReferralsModule } from "../referrals/referrals.module"; +import { TaskManagerModule } from "../task-manager/task-manager.module"; @Module({ @@ -38,6 +39,7 @@ import { ReferralsModule } from "../referrals/referrals.module"; AddressModule, ReferralsModule, AccessLogsModule, + TaskManagerModule ], providers: [ UsersService,