diff --git a/controllers/v1/projectsController.js b/controllers/v1/projectsController.js new file mode 100644 index 00000000..a976ebae --- /dev/null +++ b/controllers/v1/projectsController.js @@ -0,0 +1,25 @@ +/** + * name : projectsController.js + * author : Saish Borkar + * created-date : 26-nov-2024 + * Description : Projects controller + */ + + + +/** + * Projects + * @class +*/ +module.exports = class Projects extends Abstract { + + constructor() { + super(projectsSchema); + } + + static get name() { + return "projects"; + } + + +} diff --git a/migrations/updateUserProfilesFromProjects/copyUserDataFromProjectsToObservations.js b/migrations/updateUserProfilesFromProjects/copyUserDataFromProjectsToObservations.js new file mode 100644 index 00000000..a0befbc6 --- /dev/null +++ b/migrations/updateUserProfilesFromProjects/copyUserDataFromProjectsToObservations.js @@ -0,0 +1,119 @@ +/** + * name : copyUserDataFromProjectsToObservations.js + * author : Saish Borkar + * created-date : 26-nov-2024 + * Description : Migration script for updating userProfile in observation & observationSubmission based on project information + */ + +const path = require("path"); +const fs = require("fs"); +const _ = require("lodash"); +const { MongoClient } = require("mongodb"); + +const rootPath = path.join(__dirname, "../../"); +require("dotenv").config({ path: rootPath + "/.env" }); + +const mongoUrl = process.env.MONGODB_URL; +const dbName = mongoUrl.split("/").pop(); +const url = mongoUrl.split(dbName)[0]; + +(async () => { + const connection = await MongoClient.connect(url, { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + const db = connection.db(dbName); + + try { + console.log('Migration started...') + let observationIdsUpdated = []; + // Get all observations with referenceFrom "project" + const observationDocuments = await db + .collection("observations") + .find({ referenceFrom: "project" }) + .project({ "_id": 1,"project":1}) + .toArray(); + + if (!observationDocuments.length) { + console.log("No observations found to process."); + connection.close(); + return; + } + + const chunkedObservations = _.chunk(observationDocuments, 10); + const totalChunkLength = chunkedObservations.length; + let iteration = 1; + for (const chunk of chunkedObservations) { + console.log(`processing chunk of ${iteration++}/${totalChunkLength}`) + const projectIds = chunk.map((obs) => obs.project._id); + + // Fetch relevant projects + const projectRecords = await db + .collection("projects") + .find({ _id: { $in: projectIds } }) + .project({"_id":1,"userRoleInformation":1,"userProfile":1}) + .toArray(); + + for (const project of projectRecords) { + + const targetObservationIds = chunk + .filter((obs) => { + return obs.project._id.equals(project._id); + }) + .map((obs) => obs._id); + + let setObject = {}; + + if ( + project.userRoleInformation && + project.userRoleInformation.role && + project.userRoleInformation.state + ) { + setObject.userRoleInformation = project.userRoleInformation; + } + + if ( + project.userProfile && + project.userProfile.id + ) { + setObject.userProfile = project.userProfile; + } + + + if (Object.keys(setObject).length === 0) { + continue; + } + + // Update observations + const updatedObservations = await db + .collection("observations") + .updateMany( + { _id: { $in: targetObservationIds } }, + { + $set: setObject + } + ); + + // Update observationSubmissions + const updatedObservationSubmissions = await db + .collection("observationSubmissions") + .updateMany( + { observationId: { $in: targetObservationIds } }, + { + $set: setObject + } + ); + + observationIdsUpdated.push(...targetObservationIds) + + } + } + + require('fs').writeFileSync('observationIdsUpdated'+Date.now()+'.json',JSON.stringify(observationIdsUpdated)) + console.log("Migration completed successfully."); + } catch (error) { + console.error("Migration failed:", error); + } finally { + connection.close(); + } +})(); diff --git a/models/projects.js b/models/projects.js new file mode 100644 index 00000000..21df83c7 --- /dev/null +++ b/models/projects.js @@ -0,0 +1,183 @@ +/** + * name : projects.js. + * author : Saish Borkar + * created-date : 26-NOV-2024. + * Description : Schema for projects. + */ + +module.exports = { + name: "projects", + schema: { + title : { + type : String, + index: true + }, + description : { + type : String, + index: true + }, + taskReport : { + type : Object, + default : {} + }, + metaInformation : { + type : Object, + default : {} + }, + userId : { + type : String, + default : "SYSTEM", + index: true + }, + userRole : { + type : String, + default : "", + index: true + }, + status : { + type : String, + default : "started", + index: true + }, + lastDownloadedAt : Date, + syncedAt : Date, + isDeleted : { + type : Boolean, + default : false, + index: true + }, + categories : { + type : Array, + default : [] + }, + createdBy : { + type : String, + default : "SYSTEM", + index: true + }, + tasks : { + type : Array, + default : [] + }, + entityInformation : { + type : Object, + default : {} + }, + programInformation : { + type : Object, + default : {} + }, + solutionInformation : { + type : Object, + default : {} + }, + updatedBy : { + type : String, + default : "SYSTEM" + }, + projectTemplateId : { + type : "ObjectId", + index: true + }, + projectTemplateExternalId : { + type : String, + index: true + }, + startDate: Date, + endDate: Date, + learningResources : { + type : Array, + default : [] + }, + entityId : { + type : String, + index : true + }, + programId : { + type : "ObjectId", + index : true + }, + programExternalId : { + type : String, + index : true + }, + solutionId : { + type : "ObjectId", + index : true + }, + solutionExternalId : { + type : String, + index : true + }, + isAPrivateProgram : { + type : Boolean, + index : true + }, + appInformation : Object, + userRoleInformation : Object, + hasAcceptedTAndC : { + type : Boolean, + default : false + }, + referenceFrom : { + type : String, + index : true + }, + submissions : Object, + link : { + type : String, + index : true + }, + taskSequence : { + type : Array, + default : [] + }, + completedDate: Date, + recommendedFor : { + type : Array, + default : [] + }, + attachments : { + type : Array, + default : [] + }, + remarks : String, + userProfile : Object, + certificate : { + templateId : "ObjectId", + osid : { + type : String, + index : true, + unique : true + }, + transactionId : { + type : String, + index : true, + unique : true + }, + templateUrl : String, + status : String, + eligible : Boolean, + message : String, + issuedOn : Date, + criteria : Object, + reIssuedAt : Date, + transactionIdCreatedAt : Date, + originalTransactionInformation :{ + transactionId : String, + osid : String + } + + } + }, + compoundIndex: [ + { + "name" :{ userId: 1, solutionId: 1 }, + "indexType" : { unique: true, partialFilterExpression: { solutionId: { $exists: true }}} + } + ] + + + +}; + diff --git a/module/observations/helper.js b/module/observations/helper.js index 543e09a4..1baed668 100644 --- a/module/observations/helper.js +++ b/module/observations/helper.js @@ -217,7 +217,7 @@ module.exports = class ObservationsHelper { static createObservation(data,userId,solution,userRoleInformation="",userProfileInformation = {}) { return new Promise(async (resolve, reject) => { try { - + if (data.entities) { let entitiesToAdd = await entitiesHelper.validateEntities(data.entities, solution.entityType); @@ -246,6 +246,24 @@ module.exports = class ObservationsHelper { userProfileInformation = updatedUserProfile.data; } } + + try { + if( data.project ){ + let projectDocument = await database.models.projects.findOne({ + _id: ObjectId(data.project._id), + }); + + if (projectDocument) { + userRoleInformation = projectDocument.userRoleInformation; + userProfileInformation = projectDocument.userProfile; + } + } + + } catch (err) { + + } + + let observationData = await database.models.observations.create(