From 6310a7a971f58a548de2e2934d522afbb8231d40 Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Sat, 6 Apr 2019 21:02:39 +0200 Subject: [PATCH] Updated Project calculation for hours and progress. --- server/calculations/todo.js | 1 + server/models/project.js | 94 ++++++++++++++-- server/models/todo.js | 183 +++++++++++++++++++++++++++++-- server/router/projects_router.js | 47 +++++--- server/router/todos_router.js | 39 ++++--- server/tools/general.js | 14 ++- 6 files changed, 317 insertions(+), 61 deletions(-) create mode 100644 server/calculations/todo.js diff --git a/server/calculations/todo.js b/server/calculations/todo.js new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/server/calculations/todo.js @@ -0,0 +1 @@ + diff --git a/server/models/project.js b/server/models/project.js index 045d480..7e82790 100644 --- a/server/models/project.js +++ b/server/models/project.js @@ -29,9 +29,11 @@ var ProjectSchema = new mongoose.Schema({ }, hoursplanned: { type: Number, + default: 0 }, hoursworked: { type: Number, + default: 0 }, id_parent: { type: String, @@ -64,6 +66,7 @@ var ProjectSchema = new mongoose.Schema({ }, progressCalc: { type: Number, + default: 0 }, modified: { type: Boolean, @@ -93,15 +96,37 @@ ProjectSchema.methods.toJSON = function () { }; -ProjectSchema.statics.findByUserIdAndCat = function (userId, category) { +ProjectSchema.statics.findByUserIdAndIdParent = function (userId, id_parent) { var Project = this; - return Project.find({ - 'userId': userId, - 'category': category, - }); + if (userId === '') { + return Project.find({ + 'id_parent': id_parent, + }); + } else { + return Project.find({ + 'userId': userId, + 'id_parent': id_parent, + }); + } }; +ProjectSchema.statics.findProjectByUserId = function (userId, idproj) { + var Project = this; + + if (userId === '') { + return Project.findOne({ + '_id': idproj, + }); + } else { + return Project.findOne({ + 'userId': userId, + '_id': idproj, + }); + } +}; + + ProjectSchema.statics.findAllByUserId = function (userId) { var Project = this; @@ -113,13 +138,28 @@ ProjectSchema.statics.findAllByUserId = function (userId) { }; -ProjectSchema.statics.getArrCategoryInTable = function (userId) { +ProjectSchema.statics.getArrIdParentInTable = function (userId) { var Project = this; - return Project.find({ 'userId': userId }).distinct("category") - .then(arrcategory => { - return arrcategory - }) + return Project.find({ 'userId': userId }).distinct("id_parent") + +}; + +ProjectSchema.statics.getIdParentByIdProj = function (idProj) { + var Project = this; + + console.log('INIT getIdParentByIdProj', idProj); + + return Project.findOne({ '_id': idProj }).then(rec => { + if (!!rec) { + console.log('getIdParentByIdProj', rec.id_parent); + return rec.id_parent; + } else { + return ''; + } + }).catch(e => { + return ''; + }) }; @@ -134,6 +174,40 @@ ProjectSchema.statics.getAllProjects = async function (userId) { }; +ProjectSchema.statics.updateCalc = async function (userId, idproj, objdatacalc, recIn) { + + + return new Promise((resolve, reject) => { + if (!!recIn) { + return resolve(recIn); + } else { + return resolve(Project.findProjectByUserId(userId, idproj)) + } + }).then((myproj) => { + if (!!myproj) { + // console.log('myproj', myproj); + + objdatacalc.setValuesToRecord(myproj); + + console.log('updateCalc', myproj._id, objdatacalc); + + myproj.save() + .then(() => { + // console.log('salvato proj!'); + }) + .catch(err => { + console.log("Error updateCalc", err.message); + }); + } + return true; + }).catch(e => { + console.log('Error: ', e); + return false; + }); + +}; + + ProjectSchema.pre('save', function (next) { // var Project = this; diff --git a/server/models/todo.js b/server/models/todo.js index 5a1285a..ee3cbd6 100644 --- a/server/models/todo.js +++ b/server/models/todo.js @@ -4,6 +4,8 @@ const _ = require('lodash'); const tools = require('../tools/general'); +var { Project } = require('./project'); + mongoose.Promise = global.Promise; mongoose.level = "F"; @@ -40,6 +42,9 @@ var TodoSchema = new mongoose.Schema({ modify_at: { type: Date }, + start_date: { + type: Date, + }, completed_at: { type: Date }, @@ -56,6 +61,18 @@ var TodoSchema = new mongoose.Schema({ progress: { type: Number, }, + phase: { + type: Number, + }, + assigned_to_userId: { + type: String, + }, + hoursplanned: { + type: Number, + }, + hoursworked: { + type: Number, + }, modified: { type: Boolean, }, @@ -71,13 +88,19 @@ TodoSchema.methods.toJSON = function () { }; -TodoSchema.statics.findByUserIdAndCat = function (userId, category) { +TodoSchema.statics.findByUserIdAndIdParent = function (userId, category) { var Todo = this; - return Todo.find({ - 'userId': userId, - 'category': category, - }); + if (userId === '') { + return Todo.find({ + 'category': category, + }); + } else { + return Todo.find({ + 'userId': userId, + 'category': category, + }); + } }; TodoSchema.statics.findAllByUserIdAndCat = function (userId, category = '') { @@ -87,7 +110,8 @@ TodoSchema.statics.findAllByUserIdAndCat = function (userId, category = '') { return Todo.find({ 'userId': userId, }).then(ris => { - return tools.mapSort(ris) + //return tools.mapSort(ris) + return ris }) } else { @@ -98,7 +122,7 @@ TodoSchema.statics.findAllByUserIdAndCat = function (userId, category = '') { } }; -TodoSchema.statics.getArrCategoryInTable = function (userId) { +TodoSchema.statics.getArrIdParentInTable = function (userId) { var Todo = this; return Todo.find({ 'userId': userId }).distinct("category") @@ -112,16 +136,16 @@ TodoSchema.statics.getAllTodo = async function (userId) { var Todo = this; const arralltodo = await Todo.findAllByUserIdAndCat(userId); - // console.log('arralltodo', ); + // console.log('arralltodo', arralltodo); let obj = []; - obj.arrcategories = await Todo.getArrCategoryInTable(userId); + obj.arrcategories = await Todo.getArrIdParentInTable(userId); const arrtodos = []; if (obj.arrcategories.length > 0) { for (let mycat in obj.arrcategories) { - arrtodos.push(arralltodo.filter(item => item.category === obj.arrcategories[mycat])) + arrtodos.push(tools.mapSort(arralltodo.filter(item => item.category === obj.arrcategories[mycat]))) } } @@ -133,6 +157,144 @@ TodoSchema.statics.getAllTodo = async function (userId) { }; +class CalcTodo { + constructor() { + this.mydata = { + hoursworked: 0, + hoursplanned: 0, + progressCalc: 0, + numitem: 0 + } + } + + addData(datain) { + if (!!datain) { + this.mydata.hoursworked += datain.hoursworked; + this.mydata.hoursplanned += datain.hoursplanned; + if (!!datain.progressCalc) + this.mydata.progressCalc += datain.progressCalc; + else if (!!datain.progress) + this.mydata.progressCalc += datain.progress; + + this.mydata.numitem++; + } + } + + endDataCalc() { + if (this.mydata.numitem > 0) { + this.mydata.progressCalc = Math.round(this.mydata.progressCalc / this.mydata.numitem); + } + } + + setValuesToRecord(objout) { + objout.hoursworked = this.mydata.hoursworked; + objout.hoursplanned = this.mydata.hoursplanned; + objout.progressCalc = this.mydata.progressCalc; + } + + getData() { + // return tools.jsonCopy(this.mydata); + return { ...this.mydata } + } +} + + +TodoSchema.statics.calculateTreeTodo = async function (userId, idproj, calcalsoUpper, masterproj, nocalcDown) { + console.log('calculateTreeTodo', idproj); + + let objdata = new CalcTodo(); + + let promiseChain = Promise.resolve(); + + return await Project.findByUserIdAndIdParent(userId, idproj) + .then(arrsubproj => { + console.log('arrsubproj', 'userId', userId, 'idproj', idproj, arrsubproj.length); + + if (!nocalcDown) { + // 1) Calculate the SubProjects of this project Main + for (const subproj of arrsubproj) { + if (!calcalsoUpper) { // not include the first Project because it was already calculated before + promiseChain = promiseChain.then(() => { + return Todo.calculateTreeTodo(userId, subproj._id, calcalsoUpper, masterproj, true) + .then((subobjdata) => { + objdata.addData(subobjdata); + }); + }); + } else { + promiseChain = promiseChain.then(() => { + objdata.addData(subproj); + }); + } + } + } + + return promiseChain; + }) + .then(() => { + console.log('objdata', objdata); + // 2) Calculate the Todos of this project + return Todo.calculateTodoHoursAndProgress(userId, idproj); + }) + .then((objdatatodos) => { + objdata.addData(objdatatodos); + + // End Calculate + objdata.endDataCalc(); + + // Update into the DB: + return Project.updateCalc(userId, idproj, objdata, null) + .then(() => { + return objdata.getData(); + }); + }) + .then((ris) => { + if (calcalsoUpper) { + return Project.getIdParentByIdProj(idproj) + .then(idparent => { + console.log('idparent', idparent); + if (!!idparent) { + // Calculate also the upper Projects ! + return new Promise((resolve, reject) => { + Todo.calculateTreeTodo(userId, idparent, true, masterproj, true); + resolve(ris) + }); + } else { + return new Promise((resolve, reject) => { + resolve() + }); + } + }); + } else { + return new Promise((resolve, reject) => { + resolve() + }); + } + }) +}; + + +TodoSchema.statics.calculateTodoHoursAndProgress = async function (userId, idproj) { + var Todo = this; + + let objdata = new CalcTodo(); + + return await Todo.findByUserIdAndIdParent(userId, idproj) + .then(arrtodo => { + for (let itemtodo of arrtodo) { + objdata.addData(itemtodo); + } + + objdata.endDataCalc(); + + return objdata.getData(); + }) + .catch(e => { + console.log('Error: ', e); + return null; + }); + +}; + TodoSchema.pre('save', function (next) { // var todo = this; @@ -142,7 +304,6 @@ TodoSchema.pre('save', function (next) { }); - var Todo = mongoose.model('Todos', TodoSchema); module.exports = { Todo }; diff --git a/server/router/projects_router.js b/server/router/projects_router.js index 931a2cf..7cec53d 100644 --- a/server/router/projects_router.js +++ b/server/router/projects_router.js @@ -10,6 +10,7 @@ var { authenticate } = require('../middleware/authenticate'); // var mongoose = require('mongoose'); var { Project } = require('../models/project'); +const { Todo } = require('./../models/todo'); const _ = require('lodash'); @@ -65,7 +66,6 @@ router.post('/', authenticate, (req, res) => { }); - router.patch('/:id', authenticate, (req, res) => { var id = req.params.id; var body = _.pick(req.body, tools.allfieldProject()); @@ -118,16 +118,21 @@ router.get('/:userId', authenticate, (req, res) => { // Extract all the projects of the userId only // Project.findAllByUserIdAndCat(userId, category).then((projects) => { - Project.getAllProjects(userId).then((objprojects) => { + return Project.getAllProjects(userId).then((objprojects) => { tools.mylog('projects', objprojects.arrproj.length); - objout = calcProjects(objprojects); + return objprojects - res.send({ projects: objout }); + }).then((objprojects) => { + // tools.mylog('objprojects', objprojects); - tools.mylog('objout', objout); - - // res.send({ projects: objprojects.arrproj, categories: objprojects.arrcategories }); + // if (tools.EXECUTE_CALCPROJ) { + // return calcProjects('', objprojects).then(objout => { + // res.send({ projects: objprojects.arrproj }); + // }); + // } else { + res.send({ projects: objprojects.arrproj }); + // } }).catch((e) => { console.log(e); res.status(400).send(e); @@ -135,20 +140,28 @@ router.get('/:userId', authenticate, (req, res) => { }); -function calcProjects(obj) { +// USATO SOLO LE PRIME VOLTE! O A RICHIESTA! +async function calcProjects(userId, obj) { - let myarr = tools.jsonCopy(obj.arrproj); + // let myarr = tools.jsonCopy(obj.arrproj); + let myarr = [...obj.arrproj]; - for (const indrec in myarr) { - // Calculate the Progression of the Project + if (myarr.length > 0) { + let promiseChain = Promise.resolve(); - // Find the todos for this project - - // sum the progression - - myarr[indrec].progressCalc = Math.round(Math.random() * 100); + for (const rec of myarr) { + promiseChain = promiseChain.then(() => { + // Find the todos for this project + // Calculate the Progression of the Project // sum the progression + return Todo.calculateTreeTodo(userId, rec._id, false, rec._id, false) + }) + } + return promiseChain + } else { + return new Promise((resolve, reject) => { + resolve() + }) } - return myarr } diff --git a/server/router/todos_router.js b/server/router/todos_router.js index bbeee37..c0c5bd3 100644 --- a/server/router/todos_router.js +++ b/server/router/todos_router.js @@ -5,6 +5,8 @@ const tools = require('../tools/general'); var server_constants = require('../tools/server_constants'); +var { Project } = require('../models/project'); + var { authenticate } = require('../middleware/authenticate'); var mongoose = require('mongoose'); @@ -66,12 +68,11 @@ router.post('/', authenticate, (req, res) => { }); - router.patch('/:id', authenticate, (req, res) => { var id = req.params.id; var body = _.pick(req.body, tools.allfieldTodo()); - tools.mylogshow('PATCH TODO: ', id) + tools.mylogshow('PATCH TODO: ', id); if (!ObjectID.isValid(id)) { tools.mylog('ERROR: id not VALID', id); @@ -79,26 +80,31 @@ router.patch('/:id', authenticate, (req, res) => { } + Todo.findByIdAndUpdate(id, { $set: body }, { new: true }) + .then((todo) => { + if (!todo) { + tools.mylogshow(' TODO NOT FOUND !: id:', id, 'body: ', body); + return res.status(404).send(); + } - Todo.findByIdAndUpdate(id, { $set: body }, { new: true }).then((todo) => { - if (!todo) { - tools.mylogshow(' TODO NOT FOUND !: id:', id, 'body: ', body); - return res.status(404).send(); - } + let level = 0; + return Todo.calculateTreeTodo(todo.userId, todo.category, true, todo.category, false) + .then(objdatacalc => { + tools.mylogshow(' TODO TO MODIFY: ', todo.descr, todo.expiring_at); - tools.mylogshow(' TODO TO MODIFY: ', todo.descr, todo.expiring_at); + if (todo.userId !== String(req.user._id)) { + // I'm trying to write something not mine! + return res.status(404).send({ code: server_constants.RIS_CODE_TODO_CREATING_NOTMYUSER }); + } - if (todo.userId !== String(req.user._id)) { - // I'm trying to write something not mine! - return res.status(404).send({ code: server_constants.RIS_CODE_TODO_CREATING_NOTMYUSER }); - } + todo.modified = false; - todo.modified = false; + tools.mylog('PATCH ', todo.descr, todo._id); - tools.mylog('PATCH ', todo.descr, todo._id); + res.send({ todo, objdatacalc }); + }); - res.send({ todo }); - }).catch((e) => { + }).catch((e) => { tools.mylogserr('Error patch TODO: ', e); res.status(400).send(); }) @@ -121,7 +127,6 @@ router.get('/:userId', authenticate, (req, res) => { } // Extract all the todos of the userId only - // Todo.findAllByUserIdAndCat(userId, category).then((todos) => { Todo.getAllTodo(userId).then((objtodos) => { tools.mylog('todos', objtodos.arrtodos.length); diff --git a/server/tools/general.js b/server/tools/general.js index 95ee017..04a9290 100644 --- a/server/tools/general.js +++ b/server/tools/general.js @@ -20,10 +20,12 @@ if (process.env.GCM_API_KEY !== "") webpush.setGCMAPIKey(process.env.GCM_API_KEY); webpush.setVapidDetails(subject, publicVapidKey, privateVapidKey); -console.log('setVapidDetails... config...'); +// console.log('setVapidDetails... config...'); module.exports = { + FIRST_PROJ: '__PROJECTS', + EXECUTE_CALCPROJ: true, getHostname: function () { return os.hostname() }, @@ -50,7 +52,7 @@ module.exports = { allfieldTodo: function () { return ['userId', 'pos', 'category', 'descr', 'priority', 'status', 'created_at', 'modify_at', - 'completed_at', 'expiring_at', 'enableExpiring', 'id_prev', 'progress', 'modified'] + 'completed_at', 'expiring_at', 'enableExpiring', 'id_prev', 'progress', 'modified', 'phase', 'assigned_to_userId', 'hoursplanned', 'hoursworked', 'start_date'] }, allfieldTodoWithId: function () { @@ -146,16 +148,16 @@ module.exports = { }; console.log('************ INVIO WEBPUSH.SENDNOTIFICATION N° ', conta, '/', trovati, 'A', subscription.browser); - console.log('vapidDetails', pushOptions.vapidDetails); + // console.log('vapidDetails', pushOptions.vapidDetails); payload.title = process.env.URLBASE_APP1 + ' Msg n° ' + conta + '/' + trovati; // payload.message += subscription.browser ; const pushPayload = JSON.stringify(payload); - console.log('A1) SUBS: pushSubscription', pushSubscription); - console.log('A2) OPZIONI: pushOptions', pushOptions); - console.log('A3) MSG_TO_SEND: pushPayload', pushPayload); + // console.log('A1) SUBS: pushSubscription', pushSubscription); + // console.log('A2) OPZIONI: pushOptions', pushOptions); + // console.log('A3) MSG_TO_SEND: pushPayload', pushPayload); webpush.sendNotification( pushSubscription,