Browse Source

setup mongo

Dr-Swopt 2 months ago
parent
commit
d7c7a05248

+ 224 - 1
package-lock.json

@@ -12,14 +12,17 @@
         "@nestjs/common": "^11.1.3",
         "@nestjs/core": "^11.1.3",
         "@nestjs/jwt": "^11.0.0",
+        "@nestjs/mongoose": "^11.0.3",
         "@nestjs/passport": "^11.0.5",
         "@nestjs/platform-express": "^11.1.3",
         "@nestjs/platform-socket.io": "^11.1.3",
         "@nestjs/websockets": "^11.1.3",
         "@simplewebauthn/server": "^13.1.1",
         "bcrypt": "^6.0.0",
+        "dotenv": "^17.2.3",
         "express-list-endpoints": "^7.1.1",
         "express-session": "^1.18.1",
+        "mongoose": "^8.19.1",
         "passport": "^0.7.0",
         "passport-jwt": "^4.0.1",
         "reflect-metadata": "^0.2.2",
@@ -2077,6 +2080,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/@mongodb-js/saslprep": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.3.1.tgz",
+      "integrity": "sha512-6nZrq5kfAz0POWyhljnbWQQJQ5uT8oE2ddX303q1uY0tWsivWKgBDXBBvuFPwOqRRalXJuVO9EjOdVtuhLX0zg==",
+      "license": "MIT",
+      "dependencies": {
+        "sparse-bitfield": "^3.0.3"
+      }
+    },
     "node_modules/@napi-rs/nice": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.0.1.tgz",
@@ -2698,6 +2710,18 @@
         "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0 || ^11.0.0"
       }
     },
+    "node_modules/@nestjs/mongoose": {
+      "version": "11.0.3",
+      "resolved": "https://registry.npmjs.org/@nestjs/mongoose/-/mongoose-11.0.3.tgz",
+      "integrity": "sha512-tg7bbKD4MnNMPaiDLXK/JUyTNQxIn3rNnI+oYU1HorLpNiR2E8vPraWVvfptpIj+zferpT6LkrHMvtqvuIKNPw==",
+      "license": "MIT",
+      "peerDependencies": {
+        "@nestjs/common": "^10.0.0 || ^11.0.0",
+        "@nestjs/core": "^10.0.0 || ^11.0.0",
+        "mongoose": "^7.0.0 || ^8.0.0",
+        "rxjs": "^7.0.0"
+      }
+    },
     "node_modules/@nestjs/passport": {
       "version": "11.0.5",
       "resolved": "https://registry.npmjs.org/@nestjs/passport/-/passport-11.0.5.tgz",
@@ -3802,6 +3826,21 @@
         "@types/superagent": "^8.1.0"
       }
     },
+    "node_modules/@types/webidl-conversions": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz",
+      "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==",
+      "license": "MIT"
+    },
+    "node_modules/@types/whatwg-url": {
+      "version": "11.0.5",
+      "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz",
+      "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@types/webidl-conversions": "*"
+      }
+    },
     "node_modules/@types/yargs": {
       "version": "17.0.33",
       "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz",
@@ -5695,6 +5734,15 @@
         "node-int64": "^0.4.0"
       }
     },
+    "node_modules/bson": {
+      "version": "6.10.4",
+      "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz",
+      "integrity": "sha512-WIsKqkSC0ABoBJuT1LEX+2HEvNmNKKgnTAyd0fL8qzK4SH2i9NXg+t08YtdZp/V9IZ33cxe3iV4yM0qg8lMQng==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=16.20.1"
+      }
+    },
     "node_modules/buffer": {
       "version": "5.7.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
@@ -6456,6 +6504,18 @@
         "node": ">=0.3.1"
       }
     },
+    "node_modules/dotenv": {
+      "version": "17.2.3",
+      "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.3.tgz",
+      "integrity": "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://dotenvx.com"
+      }
+    },
     "node_modules/dunder-proto": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
@@ -9275,6 +9335,15 @@
         "safe-buffer": "^5.0.1"
       }
     },
+    "node_modules/kareem": {
+      "version": "2.6.3",
+      "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
+      "integrity": "sha512-C3iHfuGUXK2u8/ipq9LfjFfXFxAZMQJJq7vLS45r3D9Y2xQ/m4S8zaR4zMLFWh9AsNPXmcFfUDhTEO8UIC/V6Q==",
+      "license": "Apache-2.0",
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
     "node_modules/keyv": {
       "version": "4.5.4",
       "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -9548,6 +9617,12 @@
         "node": ">= 4.0.0"
       }
     },
+    "node_modules/memory-pager": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
+      "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
+      "license": "MIT"
+    },
     "node_modules/merge-descriptors": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
@@ -9721,6 +9796,106 @@
         "mkdirp": "bin/cmd.js"
       }
     },
+    "node_modules/mongodb": {
+      "version": "6.20.0",
+      "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.20.0.tgz",
+      "integrity": "sha512-Tl6MEIU3K4Rq3TSHd+sZQqRBoGlFsOgNrH5ltAcFBV62Re3Fd+FcaVf8uSEQFOJ51SDowDVttBTONMfoYWrWlQ==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@mongodb-js/saslprep": "^1.3.0",
+        "bson": "^6.10.4",
+        "mongodb-connection-string-url": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=16.20.1"
+      },
+      "peerDependencies": {
+        "@aws-sdk/credential-providers": "^3.188.0",
+        "@mongodb-js/zstd": "^1.1.0 || ^2.0.0",
+        "gcp-metadata": "^5.2.0",
+        "kerberos": "^2.0.1",
+        "mongodb-client-encryption": ">=6.0.0 <7",
+        "snappy": "^7.3.2",
+        "socks": "^2.7.1"
+      },
+      "peerDependenciesMeta": {
+        "@aws-sdk/credential-providers": {
+          "optional": true
+        },
+        "@mongodb-js/zstd": {
+          "optional": true
+        },
+        "gcp-metadata": {
+          "optional": true
+        },
+        "kerberos": {
+          "optional": true
+        },
+        "mongodb-client-encryption": {
+          "optional": true
+        },
+        "snappy": {
+          "optional": true
+        },
+        "socks": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/mongodb-connection-string-url": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.2.tgz",
+      "integrity": "sha512-rMO7CGo/9BFwyZABcKAWL8UJwH/Kc2x0g72uhDWzG48URRax5TCIcJ7Rc3RZqffZzO/Gwff/jyKwCU9TN8gehA==",
+      "license": "Apache-2.0",
+      "dependencies": {
+        "@types/whatwg-url": "^11.0.2",
+        "whatwg-url": "^14.1.0 || ^13.0.0"
+      }
+    },
+    "node_modules/mongoose": {
+      "version": "8.19.1",
+      "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.19.1.tgz",
+      "integrity": "sha512-oB7hGQJn4f8aebqE7mhE54EReb5cxVgpCxQCQj0K/cK3q4J3Tg08nFP6sM52nJ4Hlm8jsDnhVYpqIITZUAhckQ==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "bson": "^6.10.4",
+        "kareem": "2.6.3",
+        "mongodb": "~6.20.0",
+        "mpath": "0.9.0",
+        "mquery": "5.0.0",
+        "ms": "2.1.3",
+        "sift": "17.1.3"
+      },
+      "engines": {
+        "node": ">=16.20.1"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/mongoose"
+      }
+    },
+    "node_modules/mpath": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz",
+      "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/mquery": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz",
+      "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==",
+      "license": "MIT",
+      "dependencies": {
+        "debug": "4.x"
+      },
+      "engines": {
+        "node": ">=14.0.0"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.3",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -10518,7 +10693,6 @@
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
       "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-      "dev": true,
       "license": "MIT",
       "engines": {
         "node": ">=6"
@@ -11119,6 +11293,12 @@
         "url": "https://github.com/sponsors/ljharb"
       }
     },
+    "node_modules/sift": {
+      "version": "17.1.3",
+      "resolved": "https://registry.npmjs.org/sift/-/sift-17.1.3.tgz",
+      "integrity": "sha512-Rtlj66/b0ICeFzYTuNvX/EF1igRbbnGSvEyT79McoZa/DeGhMyC5pWKOEsZKnpkqtSeovd5FL/bjHWC3CIIvCQ==",
+      "license": "MIT"
+    },
     "node_modules/signal-exit": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
@@ -11334,6 +11514,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/sparse-bitfield": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
+      "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==",
+      "license": "MIT",
+      "dependencies": {
+        "memory-pager": "^1.0.2"
+      }
+    },
     "node_modules/sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -11995,6 +12184,18 @@
         "url": "https://github.com/sponsors/Borewit"
       }
     },
+    "node_modules/tr46": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz",
+      "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==",
+      "license": "MIT",
+      "dependencies": {
+        "punycode": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/tree-kill": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
@@ -12542,6 +12743,15 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
+    "node_modules/webidl-conversions": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+      "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/webpack": {
       "version": "5.99.9",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.99.9.tgz",
@@ -12734,6 +12944,19 @@
         "url": "https://opencollective.com/webpack"
       }
     },
+    "node_modules/whatwg-url": {
+      "version": "14.2.0",
+      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz",
+      "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==",
+      "license": "MIT",
+      "dependencies": {
+        "tr46": "^5.1.0",
+        "webidl-conversions": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=18"
+      }
+    },
     "node_modules/which": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

+ 3 - 0
package.json

@@ -23,14 +23,17 @@
     "@nestjs/common": "^11.1.3",
     "@nestjs/core": "^11.1.3",
     "@nestjs/jwt": "^11.0.0",
+    "@nestjs/mongoose": "^11.0.3",
     "@nestjs/passport": "^11.0.5",
     "@nestjs/platform-express": "^11.1.3",
     "@nestjs/platform-socket.io": "^11.1.3",
     "@nestjs/websockets": "^11.1.3",
     "@simplewebauthn/server": "^13.1.1",
     "bcrypt": "^6.0.0",
+    "dotenv": "^17.2.3",
     "express-list-endpoints": "^7.1.1",
     "express-session": "^1.18.1",
+    "mongoose": "^8.19.1",
     "passport": "^0.7.0",
     "passport-jwt": "^4.0.1",
     "reflect-metadata": "^0.2.2",

+ 11 - 1
src/app.module.ts

@@ -5,9 +5,19 @@ import { AttendanceModule } from './attendance/attendance.module';
 import { PaymentModule } from './payment/payment.module';
 import { PlantationTreeModule } from './plantation/plantation-tree.module';
 import { AppService } from './app.service';
+import { MongooseModule } from '@nestjs/mongoose';
+import { mongooseConfig } from './config/mongoose.config';
 
 @Module({
-  imports: [AuthModule, AttendanceModule, PaymentModule, PlantationTreeModule],
+  imports: [
+    MongooseModule.forRootAsync({
+      useFactory: () => mongooseConfig,
+    }),
+    AuthModule,
+    AttendanceModule,
+    PaymentModule,
+    PlantationTreeModule
+  ],
   controllers: [AppController],
   providers: [AppService],
 })

+ 1 - 1
src/auth/auth.controller.ts

@@ -3,7 +3,7 @@ import { JwtService } from '@nestjs/jwt';
 import { AuthenticatorTransportFuture } from '@simplewebauthn/server';
 import { isoBase64URL } from '@simplewebauthn/server/helpers';
 import { JwtAuthGuard } from 'src/common/guards/jwt-auth.guard';
-import { serverConfig } from 'src/config';
+import { serverConfig } from 'src/config/config';
 import { UsersService } from 'src/users/user.service';
 import { WebauthnService } from 'src/auth/webauthn.service';
 import { LoginPayload, User } from 'src/interface/interface';

+ 1 - 1
src/auth/webauthn.service.ts

@@ -11,7 +11,7 @@ import {
 import { Injectable, Logger } from '@nestjs/common';
 import { isoUint8Array } from '@simplewebauthn/server/helpers';
 import { isoBase64URL } from '@simplewebauthn/server/helpers';
-import { serverConfig } from 'src/config';
+import { serverConfig } from 'src/config/config';
 
 @Injectable()
 export class WebauthnService {

+ 37 - 0
src/common/schemas/plantation.node.schema.ts

@@ -0,0 +1,37 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document, Types } from 'mongoose';
+import { Worker, WorkerSchema } from './worker.schema';
+
+export type PlantationNodeDocument = PlantationNode & Document;
+
+@Schema()
+export class PlantationNode {
+  @Prop({ required: true, unique: true })
+  id: string;
+
+  @Prop({ required: true })
+  name: string;
+
+  @Prop()
+  location?: string;
+
+  @Prop()
+  plantedDate?: Date;
+
+  @Prop({ enum: ['ROOT','SITE','ZONE','BLOCK','TREE'], default: 'BLOCK' })
+  type: string;
+
+  @Prop({ enum: ['ACTIVE','INACTIVE','MAINTENANCE'], default: 'ACTIVE' })
+  status: string;
+
+  @Prop({ default: '' })
+  notes?: string;
+
+  @Prop({ type: [WorkerSchema], default: [] })
+  workers: Worker[];
+
+  @Prop({ type: [Types.ObjectId], ref: 'PlantationNode', default: [] })
+  childrenNode: PlantationNode[];
+}
+
+export const PlantationNodeSchema = SchemaFactory.createForClass(PlantationNode);

+ 24 - 0
src/common/schemas/task.schema.ts

@@ -0,0 +1,24 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+
+export type TaskDocument = Task & Document;
+
+@Schema()
+export class Task {
+  @Prop({ required: true })
+  id: string;
+
+  @Prop({ required: true })
+  description: string;
+
+  @Prop({ required: true })
+  date: Date;
+
+  @Prop({ required: true, enum: ['PENDING','WIP','DONE'] })
+  status: string;
+
+  @Prop({ enum: ['LOW','MEDIUM','HIGH'], default: 'MEDIUM' })
+  priority?: string;
+}
+
+export const TaskSchema = SchemaFactory.createForClass(Task);

+ 34 - 0
src/common/schemas/worker.schema.ts

@@ -0,0 +1,34 @@
+import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
+import { Document } from 'mongoose';
+import { Task, TaskSchema } from './task.schema';
+
+export type WorkerDocument = Worker & Document;
+
+@Schema()
+export class Worker {
+  @Prop({ required: true, unique: true })
+  id: string;
+
+  @Prop({ required: true })
+  name: string;
+
+  @Prop({ required: true })
+  DOB: Date;
+
+  @Prop({ required: true })
+  age: number;
+
+  @Prop({ required: true })
+  nationality: string;
+
+  @Prop({ required: true, unique: true })
+  personCode: string;
+
+  @Prop()
+  role?: string;
+
+  @Prop({ type: [TaskSchema], default: [] })
+  assignedTasks?: Task[];
+}
+
+export const WorkerSchema = SchemaFactory.createForClass(Worker);

+ 0 - 0
src/config.ts → src/config/config.ts


+ 8 - 0
src/config/mongoose.config.ts

@@ -0,0 +1,8 @@
+import { MongooseModuleOptions } from '@nestjs/mongoose';
+import * as dotenv from 'dotenv';
+
+dotenv.config();
+
+export const mongooseConfig: MongooseModuleOptions = {
+    uri: process.env.MONGO_URI,
+};

+ 1 - 1
src/main.ts

@@ -1,6 +1,6 @@
 import { NestFactory } from '@nestjs/core';
 import { AppModule } from './app.module';
-import { serverConfig } from './config';
+import { serverConfig } from './config/config';
 import { join } from 'path';
 import * as fs from 'fs';
 import { NestExpressApplication } from '@nestjs/platform-express';

+ 36 - 0
src/plantation/plantation-tree-mongo.service.ts

@@ -0,0 +1,36 @@
+import { Injectable } from "@nestjs/common";
+import { InjectModel } from "@nestjs/mongoose";
+import { Model } from "mongoose";
+import { PlantationNode, PlantationNodeDocument } from "src/common/schemas/plantation.node.schema";
+import { Task } from "./plantation-node-data.interface";
+
+@Injectable()
+export class PlantationTreeMongoService {
+  constructor(
+    @InjectModel(PlantationNode.name) private nodeModel: Model<PlantationNodeDocument>,
+  ) {}
+
+  async createNode(nodeData: Partial<PlantationNode>): Promise<PlantationNode> {
+    const node = new this.nodeModel(nodeData);
+    return node.save();
+  }
+
+  async findNodeById(id: string) {
+    return this.nodeModel.findOne({ id }).populate('childrenNode').exec();
+  }
+
+  async addWorker(nodeId: string, worker: Worker) {
+    return this.nodeModel.findOneAndUpdate(
+      { id: nodeId },
+      { $addToSet: { workers: worker } },
+      { new: true }
+    );
+  }
+
+  async assignTaskToWorker(workerId: string, task: Task) {
+    return this.nodeModel.updateMany(
+      { 'workers.id': workerId },
+      { $push: { 'workers.$.assignedTasks': task } },
+    );
+  }
+}