diff --git a/database/mongo.js b/database/mongo.js index 887c439..0d7f558 100644 --- a/database/mongo.js +++ b/database/mongo.js @@ -19,6 +19,7 @@ var Connect = async function () { module.exports.SubProjects = client.db(dbName).collection('SubProject'); module.exports.Locations = client.db(dbName).collection('Location'); module.exports.Sections = client.db(dbName).collection('VisualSection'); + module.exports.DynamicSections = client.db(dbName).collection('DynamicVisualSection'); module.exports.Users = client.db(dbName).collection('Users'); module.exports.ProjectDocuments = client.db(dbName).collection('ProjectDocuments'); diff --git a/model/dynamicSectionDAO.js b/model/dynamicSectionDAO.js new file mode 100644 index 0000000..01c94f8 --- /dev/null +++ b/model/dynamicSectionDAO.js @@ -0,0 +1,31 @@ +const ObjectId = require('mongodb').ObjectId; +const mongo = require('../database/mongo'); + +module.exports = { + addSection: async (dynamicSection) => { + return await mongo.DynamicSections.insertOne(dynamicSection); + }, + getAllSections: async () => { + return await mongo.DynamicSections.find({}).limit(50).sort({"_id": -1}).toArray(); + }, + getSectionById: async (id) => { + return await mongo.DynamicSections.findOne({ _id: new ObjectId(id) }); + }, + editSection: async (id, newData) => { + return await mongo.DynamicSections.updateOne({ _id: new ObjectId(id) }, { $set: newData },{upsert:false}); + }, + deleteSection: async (id) => { + return await mongo.DynamicSections.deleteOne({ _id: new ObjectId(id) }); + }, + getSectionByParentId: async (parentId) => { + return await mongo.DynamicSections.find({ parentid: new ObjectId(parentId) }).toArray(); + }, + addImageInSection : async (sectionId, url) => { + await mongo.DynamicSections.updateOne({ _id: new ObjectId(sectionId) }, { $push: { images: url } }); + }, + removeImageInSection : async (sectionId, url) => { + await mongo.DynamicSections.updateOne({ _id: new ObjectId(sectionId) }, { $pull: { images: url } }); + } +} + + diff --git a/routes.js b/routes.js index 65143ee..b68e96f 100644 --- a/routes.js +++ b/routes.js @@ -7,6 +7,7 @@ var projectRouter = require("./routes/project-endpoint"); var subprojectRouter = require("./routes/subproject-endpoint"); var locationRouter = require("./routes/location-endpoint"); var sectionRouter = require("./routes/section-endpoint"); +var dynamicSectionRouter = require("./routes/dynamic-section-endpoint"); var invasivesectionRouter = require("./routes/invasivesection-endpoint"); var conclusiveSectionRouter = require("./routes/conclusivesection-endpoint"); var tenantRouter = require("./routes/tenants-endpoint"); @@ -26,6 +27,7 @@ module.exports = function(app) { app.use("/api/subproject", subprojectRouter); app.use("/api/location", locationRouter); app.use("/api/section", sectionRouter); + app.use("/api/dynamicsection", dynamicSectionRouter); app.use("/api/invasivesection", invasivesectionRouter); app.use("/api/conclusivesection", conclusiveSectionRouter); app.use("/api/tenants", authenticateToken,tenantRouter); diff --git a/routes/dynamic-section-endpoint.js b/routes/dynamic-section-endpoint.js new file mode 100644 index 0000000..ec1ddba --- /dev/null +++ b/routes/dynamic-section-endpoint.js @@ -0,0 +1,258 @@ +"use strict"; +var express = require('express'); +var router = express.Router(); +const ErrorResponse = require('../model/error'); +var ObjectId = require('mongodb').ObjectId; +const newErrorResponse = require('../model/newError'); +const DynamicSectionService = require("../service/dynamicSectionService"); +const dynamicSectionDAO = require('../model/dynamicSectionDAO'); + +require("dotenv").config(); + +router.route('/add') +.post(async function (req,res){ +try{ +var errResponse; +// Get user input + +const { name,additionalconsiderations, + additionalconsiderationshtml,furtherinvasivereviewrequired,images,createdby,parentid,parenttype,unitUnavailable, companyIdentifier } = req.body; + +// Validate user input +if (!(name&&parentid)) { + errResponse = new ErrorResponse(400,"Name and parentid is required",""); + res.status(400).json(errResponse); + return; +} +var creationtime= (new Date(Date.now())).toISOString(); +var newSection = { + "additionalconsiderations":additionalconsiderations, + "additionalconsiderationshtml":additionalconsiderationshtml? additionalconsiderationshtml: "", + "createdat":creationtime, + "createdby":createdby, + "editedat":creationtime, + "lasteditedby":createdby, + "furtherinvasivereviewrequired":furtherinvasivereviewrequired.toLowerCase()==='true', + "name":name, + "parentid": new ObjectId(parentid), + "parenttype":parenttype, + "images":images, + "unitUnavailable": unitUnavailable, + "companyIdentifier": companyIdentifier +} +var result = await DynamicSectionService.addSection(newSection); +if (result.reason) { + return res.status(result.code).json(result); +} +if (result) { + //console.debug(result); + return res.status(201).json(result); +} +} +catch (exception) { +errResponse = new newErrorResponse(500, false, exception); +return res.status(500).json(errResponse); +} +}); + + +router.route('/:id') +.get(async function(req,res){ + try{ + var errResponse; + const sectionId = req.params.id; + var result = await DynamicSectionService.getSectionById(sectionId); + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } + } + catch (exception) { + errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } +}) + +router.route('/:id') +.put(async function(req,res){ + try{ + var errResponse; + const sectionId = req.params.id; + const newData = req.body; + if(newData.parentid){ + newData.parentid = new ObjectId(newData.parentid); + } + + if(newData.furtherinvasivereviewrequired){ + newData.furtherinvasivereviewrequired = newData.furtherinvasivereviewrequired.toLowerCase()==='true' + } + + var result = await DynamicSectionService.editSetion(sectionId,newData); + + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } + } + catch (exception) { + errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } +}) +.delete(async function(req,res){ + try{ + var errResponse; + const sectionId = req.params.id; + var result = await DynamicSectionService.deleteSectionPermanently(sectionId); + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } + } + catch (exception) { + errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } +}); + +router.route('/:id/addimage') +.post(async function(req,res){ + try { + var errResponse; + const sectionId = req.params.id; + const {url} = req.body; + var result = await DynamicSectionService.addImageInSection(sectionId,url); + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } + } + catch (exception) { + errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } +}); + +router.route('/:id/removeimage') +.post(async function(req,res){ + try { + var errResponse; + const sectionId = req.params.id; + const {url} = req.body + var result = await DynamicSectionService.removeImageFromSection(sectionId,url); + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } + } + catch (exception) { + errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } +}); + +router.route('/getSectionById') + .post(async function(req, res) { + try { + const sectionId = req.body.sectionid; // Use req.body instead of req.params + const userName = req.body.username; // Use req.body instead of req.params + + const result = await DynamicSectionService.getSectionById(sectionId); + + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } + } + catch (exception) { + const errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } + }); + +router.route('/getSectionsByParentId') +.post(async function(req,res){ +try{ + var errResponse; + const parentId = req.body.parentid; + const username = req.body.username; + var result = await DynamicSectionService.getSectionsByParentId(parentId); + if (result.reason) { + return res.status(result.code).json(result); + } + if (result) { + //console.debug(result); + return res.status(201).json(result); + } +} +catch (exception) { + errResponse = new newErrorResponse(500, false, exception); + return res.status(500).json(errResponse); +} +}) + +router.route('/moveSection') +.post(async function(req, res){ + try{ + const sectionId = req.body.sectionId; + const newParentId = req.body.newParentId; + + if (!(sectionId && newParentId)) { + const errResponse = new ErrorResponse(400,"Invalid move operation",""); + res.status(400).json(errResponse); + return; + } + + //Get the section object by id + const result = await dynamicSectionDAO.getSectionById(sectionId); + if (!result) { + return res.status(result).json(result); + } + + const section = result; + //Remove the section from the original parent + const isSectionRemoved = await DynamicSectionService.deleteSectionPermanently(sectionId); + if (isSectionRemoved.reason) { + return res.status(isSectionRemoved.code).json(isSectionRemoved); + } + if (isSectionRemoved) { + //update the section parent id with new parent id + section.parentid = new ObjectId(newParentId); + //add the section to the new parent + const isSectionAdded = await DynamicSectionService.addSection(section); + + if (isSectionAdded.reason) { + return res.status(isSectionAdded.code).json(isSectionAdded); + } + if (isSectionAdded) { + return res.status(201).json(isSectionAdded); + } + } + + } + catch (exception){ + console.log(exception); + const errResponse = new ErrorResponse(500, false, exception); + return res.status(500).json(errResponse); + } +}) + +module.exports = router ; diff --git a/service/dynamicSectionService.js b/service/dynamicSectionService.js new file mode 100644 index 0000000..625666f --- /dev/null +++ b/service/dynamicSectionService.js @@ -0,0 +1,246 @@ +"use strict"; +const LocationDAO = require("../model/locationDAO.js"); +const SectionDAO = require("../model/dynamicSectionDAO.js"); +const InvasiveSectionService = require("./invasiveSectionService.js"); +const ConclusiveSectionService = require("./conclusiveSectionService.js"); +const InvasiveUtil = require("./invasiveUtil.js"); +const ProjectDAO = require("../model/projectDAO.js"); +const updateParentHelper = require("./updateParentHelper.js"); +const RatingMapping = require("../model/ratingMapping.js"); + + +const addSection = async (section) => { + try { + const result = await SectionDAO.addSection(section); + if (result.insertedId) { + await updateParentHelper.addDynamicSectionMetadataInParent(result.insertedId, section); + + //if section is invasive ,it will mark entire parent hierarchy as invasive + await InvasiveUtil.markDynamicSectionInvasive(result.insertedId); + return { + success: true, + id: result.insertedId, + }; + } + return { + code: 500, + success: false, + reason: "Insertion failed", + }; + } catch (error) { + return handleError(error); + } +}; + +var getSectionById = async function (sectionId) { + try { + const result = await SectionDAO.getSectionById(sectionId); + if (result) { + transformDynamicSectionData(result); + return { + success: true, + section: result, + }; + } + return { + code: 401, + success: false, + reason: "No Section found with the given ID", + }; + } catch (error) { + return handleError(error); + } +}; + +var deleteSectionPermanently = async function (sectionId) { + try { + //Delete Invasive Sections + const invasiveSectionResult = + await InvasiveSectionService.getInvasiveSectionByParentId(sectionId); + if (invasiveSectionResult.sections) { + for (let invasiveSection of invasiveSectionResult.sections) { + await InvasiveSectionService.deleteInvasiveSectionPermanently( + invasiveSection._id + ); + } + } + + //Delete Conclusive Sections + const conclusiveSectionResult = + await ConclusiveSectionService.deleteConclusiveSectionPermanently( + sectionId + ); + if (conclusiveSectionResult.sections) { + for (let conclusiveSection of conclusiveSectionResult.sections) { + await ConclusiveSectionService.deleteConclusiveSectionPermanently( + conclusiveSection._id + ); + } + } + + const section = await SectionDAO.getSectionById(sectionId); + const result = await SectionDAO.deleteSection(sectionId); + + + //Mark parent as non-invasive if its all child are non invasive + + if(section.parenttype == "project") + { + await InvasiveUtil.markDynamicProjectNonInvasive(section.parentid); + } + else{ + await InvasiveUtil.markDynamicLocationNonInvasive(section.parentid); + } + //Update Parent for the section + await updateParentHelper.removeDynamicSectionMetadataFromParent(sectionId, section); + + + + if (result.deletedCount === 1) { + return { + success: true, + id: sectionId, + }; + } + return { + code: 401, + success: false, + reason: "No Section found with the given ID", + }; + } catch (error) { + return handleError(error); + } +}; + +var getSectionsByParentId = async function (parentId) { + try { + const result = await SectionDAO.getSectionByParentId(parentId); + if (result) { + for (let section of result) { + transformDynamicSectionData(section); + } + return { + success: true, + sections: result, + }; + } + return { + code: 401, + success: false, + reason: "No Location found with the given parent ID", + }; + } catch (error) { + return handleError(error); + } +}; + +const editSetion = async (sectionId, section) => { + try { + const result = await SectionDAO.editSection(sectionId, section); + if (result.modifiedCount === 1) { + const sectionFromDB = await SectionDAO.getSectionById(sectionId); + + await updateParentHelper.addUpdateDynamicSectionMetadataInParent( + sectionId, + sectionFromDB + ); + //if section is invasive ,it will mark entire parent hierarchy as invasive + if (sectionFromDB.furtherinvasivereviewrequired) { + await InvasiveUtil.markSectionInvasive(sectionId); + } else { + if (sectionFromDB.parenttype == "project") { + await InvasiveUtil.markDynamicProjectNonInvasive(section.parentid); + } + else { + await InvasiveUtil.markDynamicLocationNonInvasive(section.parentid); + } + } + return { + success: true, + }; + } + return { + code: 401, + success: false, + reason: "No Section found with the given ID", + }; + } catch (error) { + return handleError(error); + } +}; + +const addImageInSection = async (sectionId, imageUrl) => { + try { + const result = await SectionDAO.addImageInSection(sectionId, imageUrl); + if (result.modifiedCount === 1) { + return { + success: true, + }; + } + return { + code: 401, + success: false, + reason: "No Section found with the given ID", + }; + } catch (error) { + return handleError(error); + } +}; + + +const removeImageFromSection = async (sectionId, imageUrl) => { + try { + const result = await SectionDAO.removeImageInSection(sectionId, imageUrl); + if (result.modifiedCount === 1) { + return { + success: true, + }; + } + return { + code: 401, + success: false, + reason: "No Section found with the given ID", + }; + } catch (error) { + return handleError(error); + } +}; + +const handleError = (error) => { + console.error("An error occurred:", error); + return { + code: 500, + success: false, + reason: `An error occurred: ${error.message}`, + }; +}; + +var transformDynamicSectionData = function(section) { + section.furtherinvasivereviewrequired = capitalizeWords(convertBooleanToString((section.furtherinvasivereviewrequired))); +}; + +var capitalizeWords = function (word) { + if (word) { + var finalWord = word[0].toUpperCase() + word.slice(1); + return finalWord; + } + return word; +}; + +var convertBooleanToString = function (word) { + if (typeof word !== 'boolean') { + return; // this will return undefined by default + } + return word ? "Yes" : "No"; +}; + + +module.exports = { + addSection, + getSectionById, + deleteSectionPermanently, + getSectionsByParentId, + editSetion, + addImageInSection, + removeImageFromSection +}; \ No newline at end of file diff --git a/service/invasiveUtil.js b/service/invasiveUtil.js index fc08235..dafe7b6 100644 --- a/service/invasiveUtil.js +++ b/service/invasiveUtil.js @@ -1,4 +1,5 @@ const SectionDAO = require("../model/sectionDAO"); +const DynamicSectionDAO = require("../model/dynamicSectionDAO"); const LocationDAO = require("../model/locationDAO"); const SubProjectDAO = require("../model/subProjectDAO"); const ProjectDAO = require("../model/projectDAO"); @@ -25,6 +26,27 @@ const markSectionInvasive = async (sectionId) => { } }; +// Marks a dynamicSection as invasive if the condition is met +const markDynamicSectionInvasive = async (sectionId) => { + try { + const section = await DynamicSectionDAO.getSectionById(sectionId); + if (section) { + if (section.furtherinvasivereviewrequired) { + + if(section.parenttype == "project") + { + await markProjectInvasive(section.parentid); + } + else{ + await markLocationInvasive(section.parentid); + } + } + } + } catch (err) { + console.error("Error in markSectionInvasive:", err); + } +}; + // Marks a location as invasive if the condition is met const markLocationInvasive = async (locationId) => { try { @@ -107,6 +129,21 @@ const markSectionNonInvasive = async (sectionId) => { } }; +const markDynamicSectionNonInvasive = async (sectionId) => { + try { + const section = await DynamicSectionDAO.getSectionById(sectionId); + if (section) { + if (section.furtherinvasivereviewrequired) return; + const location = await LocationDAO.getLocationById(section.parentid); + if (location) { + await markDynamicLocationNonInvasive(section.parentid); + } + } + } catch (err) { + console.error("Error in markSectionNonInvasive:", err); + } +}; + const markLocationNonInvasive = async (locationid) => { try { const sections = await SectionDAO.getSectionByParentId(locationid); @@ -141,6 +178,40 @@ const markLocationNonInvasive = async (locationid) => { } }; +const markDynamicLocationNonInvasive = async (locationid) => { + try { + const sections = await DynamicSectionDAO.getSectionByParentId(locationid); + if (sections) { + for (const section of sections) { + if (section.furtherinvasivereviewrequired) { + return; + } + } + const location = await LocationDAO.getLocationById(locationid); + + + + if (location) { + location.isInvasive = false; + await LocationDAO.editLocation(locationid, location); + + + // await updateParentHelper.removeLocationFromParent(locationid, location); + // await updateParentHelper.addLocationMetadataInParent(locationid, location); + await updateParentHelper.addUpdateLocationMetadataInParent(locationid, location); + + if (location.parenttype == "subproject") { + await markDynamicSubProjectNonInvasive(location.parentid); + } else if (location.parenttype == "project") { + await markDynamicProjectNonInvasive(location.parentid); + } + } + } + } catch (err) { + console.error("Error in markSectionNonInvasive:", err); + } +}; + const markSubProjectNonInvasive = async (subProjectId) => { try { const locations = await LocationDAO.getLocationByParentId(subProjectId); @@ -169,6 +240,34 @@ const markSubProjectNonInvasive = async (subProjectId) => { } }; +const markDynamicSubProjectNonInvasive = async (subProjectId) => { + try { + const locations = await LocationDAO.getLocationByParentId(subProjectId); + if (locations) { + for (const location of locations) { + if (location.isInvasive) { + return; + } + } + + const subProject = await SubProjectDAO.findSubProjectById(subProjectId); + if (subProject) { + subProject.isInvasive = false; + await SubProjectDAO.editSubProject(subProjectId, subProject); + + // await updateParentHelper.removeSubprojectMetaDataInProject(subProjectId, subProject); + // await updateParentHelper.addSubprojectMetaDataInProject(subProjectId, subProject); + await updateParentHelper.addUpdateSubProjectMetadataInProject(subProjectId, subProject); + if (subProject.parenttype == "project") { + await markDynamicProjectNonInvasive(subProject.parentid); + } + } + } + } catch (err) { + console.error("Error in markSubProjectNonInvasive:", err); + } +}; + const markProjectNonInvasive = async (projectId) => { try { const project = await ProjectDAO.getProjectById(projectId); @@ -214,13 +313,63 @@ const markProjectNonInvasive = async (projectId) => { } }; +const markDynamicProjectNonInvasive = async (projectId) => { + try { + const project = await ProjectDAO.getProjectById(projectId); + + if (project) { + if (project.projecttype == "singlelevel") { + const sections = await DynamicSectionDAO.getSectionByParentId(projectId); + if (sections) { + for (const section of sections) { + if (section.furtherinvasivereviewrequired) { + return; + } + } + } + } else { + const locations = await LocationDAO.getLocationByParentId(projectId); + if (locations) { + for (const location of locations) { + if (location.isInvasive) { + return; + } + } + } + + const subProjects = await SubProjectDAO.findSubProjectsByParentId( + projectId + ); + + if (subProjects) { + for (const subProject of subProjects) { + if (subProject.isInvasive) { + return; + } + } + } + } + + project.isInvasive = false; + await ProjectDAO.editProject(projectId, project); + } + } catch (err) { + console.error("Error in markProjectNonInvasive:", err); + } +}; + module.exports = { markSectionInvasive, + markDynamicSectionInvasive, markLocationInvasive, markSubProjectInvasive, markProjectInvasive, markLocationNonInvasive, + markDynamicLocationNonInvasive, markProjectNonInvasive, + markDynamicProjectNonInvasive, markSubProjectNonInvasive, + markDynamicSubProjectNonInvasive, markSectionNonInvasive, + markDynamicSectionNonInvasive, }; \ No newline at end of file diff --git a/service/updateParentHelper.js b/service/updateParentHelper.js index 476bcc9..d944691 100644 --- a/service/updateParentHelper.js +++ b/service/updateParentHelper.js @@ -174,6 +174,88 @@ const addUpdateSectionMetadataInParent = async (sectionId,section)=>{ ); } }; + +const addDynamicSectionMetadataInParent = async (sectionId, section) => { + const sectionDataInParent = { + name: section.name, + coverUrl: section.images ? section.images[0] : "", + furtherinvasivereviewrequired: section.furtherinvasivereviewrequired, + isInvasive: section.furtherinvasivereviewrequired, + isuploading: false, + count: section.images ? section.images.length : 0, + sequenceNo: section.sequenceNo !== undefined ? section.sequenceNo : null, + }; + + if (section.parenttype == "project") { + await ProjectDAO.addChildInSingleLevelProject( + section.parentid, + sectionId, + sectionDataInParent + ); + console.log( + `Added section with id ${sectionId} in Project id ${section.parentid} for Single Level Project successfully` + ); + } else { + await LocationDAO.addLocationChild( + section.parentid, + sectionId, + sectionDataInParent + ); + console.log( + `Added section with id ${sectionId} in location id ${section.parentid} successfully` + ); + } +}; + +const removeDynamicSectionMetadataFromParent = async (sectionId, section) => { + if (section.parenttype == "project") { + await ProjectDAO.removeChildFromSingleLevelProject( + section.parentid, + sectionId + ); + console.log( + `Removed section with id ${sectionId} from Project id ${section.parentid} for Single Level Project successfully` + ); + } else { + await LocationDAO.removeLocationChild(section.parentid, sectionId); + console.log( + `Removed section with id ${sectionId} from location id ${section.parentid} successfully` + ); + } +}; +const addUpdateDynamicSectionMetadataInParent = async (sectionId,section)=>{ + const sectionDataInParent = { + _id:ObjectId(sectionId), + name: section.name, + coverUrl: section.images ? section.images[0] : "", + furtherinvasivereviewrequired: section.furtherinvasivereviewrequired, + isInvasive: section.furtherinvasivereviewrequired, + isuploading: false, + count: section.images.length, + sequenceNo: section.sequenceNo !== undefined ? section.sequenceNo : null, + }; + + if (section.parenttype == "project") { + await ProjectDAO.addUpdateChildInSingleLevelProject ( + section.parentid, + sectionId, + sectionDataInParent + ); + console.log( + `Added section with id ${sectionId} in Project id ${section.parentid} for Single Level Project successfully` + ); + } else { + await LocationDAO.addUpdateLocationChild( + section.parentid, + sectionId, + sectionDataInParent + ); + console.log( + `Added section with id ${sectionId} in location id ${section.parentid} successfully` + ); + } +}; + const addSubprojectMetaDataInProject = async (subProjectId, subProject) => { const subProjectDataInParent = { name: subProject.name, @@ -241,9 +323,11 @@ module.exports = { removeLocationFromParent, addSectionMetadataInParent, removeSectionMetadataFromParent, + addDynamicSectionMetadataInParent, + removeDynamicSectionMetadataFromParent, addSubprojectMetaDataInProject, removeSubprojectMetaDataInProject, addUpdateLocationMetadataInParent, - addUpdateSectionMetadataInParent, + addUpdateDynamicSectionMetadataInParent, addUpdateSubProjectMetadataInProject }; \ No newline at end of file