@tiledesk/tiledesk-server
Version:
The Tiledesk server module
584 lines (429 loc) • 16.5 kB
JavaScript
var express = require('express');
var router = express.Router();
var Lead = require("../models/lead");
var LeadConstants = require("../models/leadConstants");
var winston = require('../config/winston');
var leadService = require("../services/leadService");
csv = require('csv-express');
csv.separator = ';';
const leadEvent = require('../event/leadEvent');
var Segment = require("../models/segment");
var Segment2MongoConverter = require("../utils/segment2mongoConverter");
router.post('/', function (req, res) {
winston.debug(req.body);
winston.debug("req.user", req.user);
leadService.createWitId(req.body.lead_id, req.body.fullname, req.body.email, req.projectid, req.user.id, req.body.attributes).then(function(savedLead) {
res.json(savedLead);
})
});
router.put('/:leadid', function (req, res) {
winston.debug(req.body);
var update = {};
if (req.body.fullname!=undefined) {
update.fullname = req.body.fullname;
}
if (req.body.email!=undefined) {
update.email = req.body.email;
}
if (req.body.attributes!=undefined) {
update.attributes = req.body.attributes;
}
if (req.body.status!=undefined) {
update.status = req.body.status;
}
if (req.body.phone!=undefined) {
update.phone = req.body.phone;
}
if (req.body.company!=undefined) {
update.company = req.body.company;
}
if (req.body.note!=undefined) {
update.note = req.body.note;
}
if (req.body.streetAddress!=undefined) {
update.streetAddress = req.body.streetAddress;
}
if (req.body.city!=undefined) {
update.city = req.body.city;
}
if (req.body.region!=undefined) {
update.region = req.body.region;
}
if (req.body.zipcode!=undefined) {
update.zipcode = req.body.zipcode;
}
if (req.body.country!=undefined) {
update.country = req.body.country;
}
if (req.body.tags) {
update.tags = req.body.tags;
}
Lead.findByIdAndUpdate(req.params.leadid, update, { new: true, upsert: true }, function (err, updatedLead) {
if (err) {
winston.error('--- > ERROR ', err);
return res.status(500).send({ success: false, msg: 'Error updating object.' });
}
leadEvent.emit('lead.update', updatedLead);
if (req.body.fullname!=undefined) {
leadEvent.emit('lead.fullname.update', updatedLead);
}
if (req.body.email!=undefined) {
leadEvent.emit('lead.email.update', updatedLead);
}
if (req.body.email!=undefined || req.body.fullname!=undefined) {
leadEvent.emit('lead.fullname.email.update', updatedLead);
}
res.json(updatedLead);
});
});
router.put('/:leadid/tag', async (req, res) => {
let lead_id = req.params.leadid;
let tags_list = req.body;
winston.debug("(Lead) /tag tags_list: ", tags_list)
if (tags_list.length == 0) {
winston.warn("(Lead) /tag no tag specified")
return res.status(400).send({ success: false, message: "No tag specified" })
}
let lead = await Lead.findById(lead_id).catch((err) => {
winston.error("(Lead) /tag error getting lead ", err);
return res.status(500).send({ success: false, error: "Error getting lead with id " + lead_id});
})
if (!lead) {
winston.warn("(Lead) /tag lead not found with lead_id " + lead_id);
return res.status(404).send({ success: false, error: "Lead not found with id " + lead_id });
}
let current_tags = lead.tags;
tags_list.forEach(t => {
// Check if tag already exists in the lead. If true, skip the adding.
if (!current_tags.includes(t)) {
current_tags.push(t)
}
})
let update = {
tags: current_tags
}
Lead.findByIdAndUpdate(lead_id, update, { new: true }, (err, updatedLead) => {
if (err) {
winston.error("(Lead) /tag error finding and update lead ", err);
return res.status(500).send({ success: false, error: "Error updating lead with id " + lead_id })
}
if (!updatedLead) {
winston.warn("(Lead) /tag The lead was deleted while adding tags for lead " + lead_id);
return res.status(404).send({ success: false, error: "The lead was deleted while adding tags for lead " + lead_id })
}
winston.debug("(Lead) /tag Lead updated successfully ", updatedLead);
leadEvent.emit('lead.update', updatedLead);
res.status(200).send(updatedLead)
})
})
router.patch('/:leadid/attributes', function (req, res) {
var data = req.body;
// TODO use service method
Lead.findById(req.params.leadid, function (err, lead) {
if (err) {
winston.error('--- > ERROR ', err);
return res.status(500).send({ success: false, msg: 'Error updating object.' });
}
if (!lead) {
return res.status(404).send({ success: false, msg: 'Object not found.' });
}
if (!lead.attributes) {
winston.debug("empty attributes")
lead.attributes = {};
}
winston.debug(" lead attributes", lead.attributes)
Object.keys(data).forEach(function(key) {
var val = data[key];
winston.debug("data attributes "+key+" " +val)
lead.attributes[key] = val;
});
winston.debug(" lead attributes", lead.attributes)
// https://stackoverflow.com/questions/24054552/mongoose-not-saving-nested-object
lead.markModified('attributes');
//cacheinvalidation
lead.save(function (err, savedLead) {
if (err) {
winston.error("error saving lead attributes",err)
return res.status(500).send({ success: false, msg: 'Error getting object.' });
}
winston.verbose(" saved lead attributes",savedLead.toObject())
leadEvent.emit('lead.update', savedLead);
res.json(savedLead);
});
});
});
//.post and .patch for /properties are equals
router.post('/:leadid/properties', function (req, res) {
var data = req.body;
// TODO use service method
Lead.findById(req.params.leadid, function (err, lead) {
if (err) {
winston.error('--- > ERROR ', err);
return res.status(500).send({ success: false, msg: 'Error updating object.' });
}
if (!lead) {
return res.status(404).send({ success: false, msg: 'Object not found.' });
}
if (!lead.properties) {
winston.debug("empty properties")
lead.properties = {};
}
winston.debug(" lead properties", lead.properties)
Object.keys(data).forEach(function(key) {
var val = data[key];
winston.debug("data attributes "+key+" " +val)
lead.properties[key] = val;
});
winston.debug(" lead properties", lead.properties)
// https://stackoverflow.com/questions/24054552/mongoose-not-saving-nested-object
lead.markModified('properties');
//cacheinvalidation
lead.save(function (err, savedLead) {
if (err) {
winston.error("error saving lead properties",err)
return res.status(500).send({ success: false, msg: 'Error getting object.' });
}
winston.verbose(" saved lead properties",savedLead.toObject())
leadEvent.emit('lead.update', savedLead);
res.json(savedLead);
});
});
});
router.patch('/:leadid/properties', function (req, res) {
var data = req.body;
// TODO use service method
Lead.findById(req.params.leadid, function (err, lead) {
if (err) {
winston.error('--- > ERROR ', err);
return res.status(500).send({ success: false, msg: 'Error updating object.' });
}
if (!lead) {
return res.status(404).send({ success: false, msg: 'Object not found.' });
}
if (!lead.properties) {
winston.debug("empty properties")
lead.properties = {};
}
winston.debug(" lead properties", lead.properties)
Object.keys(data).forEach(function(key) {
var val = data[key];
winston.debug("data attributes "+key+" " +val)
lead.properties[key] = val;
});
winston.debug(" lead properties", lead.properties)
// https://stackoverflow.com/questions/24054552/mongoose-not-saving-nested-object
lead.markModified('properties');
//cacheinvalidation
lead.save(function (err, savedLead) {
if (err) {
winston.error("error saving lead properties",err)
return res.status(500).send({ success: false, msg: 'Error getting object.' });
}
winston.verbose(" saved lead properties",savedLead.toObject())
leadEvent.emit('lead.update', savedLead);
res.json(savedLead);
});
});
});
// router.put('/:leadid', function (req, res) {
// winston.debug(req.body);
// var update = {};
// // trasforma in patch altrimenti nn va
// update.fullname = req.body.fullname;
// update.email = req.body.email;
// update.attributes = req.body.attributes;
// update.status = req.body.status;
// Lead.findByIdAndUpdate(req.params.leadid, update, { new: true, upsert: true }, function (err, updatedLead) {
// if (err) {
// winston.error('--- > ERROR ', err);
// return res.status(500).send({ success: false, msg: 'Error updating object.' });
// }
// leadEvent.emit('lead.update', updatedLead);
// res.json(updatedLead);
// });
// });
router.delete('/:leadid/tag/:tag', async (req, res) => {
let lead_id = req.params.leadid;
let tag = req.params.tag;
Lead.findByIdAndUpdate(lead_id, { $pull: { tags: tag }}, { new: true}).then((updatedLead) => {
if (!updatedLead) {
winston.warn("(Lead) /removetag lead not found with id " + lead_id);
return res.status(404).send({ success: false, error: "Lead not found with id " + lead_id })
}
winston.debug("(Lead) /removetag updatedLead: ", updatedLead)
res.status(200).send(updatedLead)
}).catch((err) => {
winston.error("(Lead) /removetag error updating lead: ", err);
res.status(500).send({ success: false, error: err });
})
})
router.delete('/:leadid', function (req, res) {
winston.debug(req.body);
Lead.findByIdAndUpdate(req.params.leadid, {status: LeadConstants.DELETED}, { new: true, upsert: true }, function (err, updatedLead) {
if (err) {
winston.error('--- > ERROR ', err);
return res.status(500).send({ success: false, msg: 'Error updating object.' });
}
leadEvent.emit('lead.delete', updatedLead);
res.json(updatedLead);
});
});
router.delete('/:leadid/physical', function (req, res) {
winston.debug(req.body);
var projectuser = req.projectuser;
if (projectuser.role != "owner" ) {
return res.status(403).send({ success: false, msg: 'Unauthorized.' });
}
// TODO use findByIdAndRemove otherwise lead don't contains label object
Lead.remove({ _id: req.params.leadid }, function (err, lead) {
if (err) {
winston.error('--- > ERROR ', err);
return res.status(500).send({ success: false, msg: 'Error deleting object.' });
}
leadEvent.emit('lead.delete', lead);
res.json(lead);
});
});
// DOWNLOAD leads AS CSV
router.get('/csv', function (req, res, next) {
var limit = 100000; // Number of leads per page
var page = 0;
if (req.query.page) {
page = req.query.page;
}
var skip = page * limit;
winston.debug('LEAD ROUTE - SKIP PAGE ', skip);
var query = { "id_project": req.projectid, "status": {$lt: LeadConstants.DELETED}};
if (req.query.full_text) {
winston.debug('LEAD ROUTE req.query.fulltext', req.query.full_text);
query.$text = { "$search": req.query.full_text };
}
if (req.query.email) {
winston.debug('LEAD ROUTE req.query.email', req.query.email);
query.email = req.query.email;
}
var direction = -1; //-1 descending , 1 ascending
if (req.query.direction) {
direction = req.query.direction;
}
winston.debug("direction", direction);
var sortField = "createdAt";
if (req.query.sort) {
sortField = req.query.sort;
}
winston.debug("sortField", sortField);
var sortQuery = {};
sortQuery[sortField] = direction;
winston.debug("sort query", sortQuery);
// TODO ORDER BY SCORE
// return Faq.find(query, {score: { $meta: "textScore" } })
// .sort( { score: { $meta: "textScore" } } ) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
// Lead.find({ "id_project": req.projectid }, function (err, leads, next) {
return Lead.find(query, '-attributes -__v').
skip(skip).limit(limit).
sort(sortQuery).lean().
exec(function (err, leads) {
if (err) {
winston.error('LEAD ROUTE - EXPORT CONTACT TO CSV ERR ', err)
return next(err);
}
winston.verbose('LEAD ROUTE - EXPORT CONTACT TO CSV LEADS', leads)
return res.csv(leads, true);
});
});
router.get('/:leadid', function (req, res) {
winston.debug(req.body);
Lead.findById(req.params.leadid, function (err, lead) {
if (err) {
return res.status(500).send({ success: false, msg: 'Error getting object.' });
}
if (!lead) {
return res.status(404).send({ success: false, msg: 'Object not found.' });
}
res.json(lead);
});
});
router.get('/', async(req, res) => {
var limit = 40; // Number of request per page
if (req.query.limit) {
limit = parseInt(req.query.limit);
winston.debug('LEAD ROUTE - limit: '+limit);
}
var page = 0;
if (req.query.page) {
page = req.query.page;
}
var skip = page * limit;
winston.debug('LEAD ROUTE - SKIP PAGE ', skip);
var query = {};
if (req.query.segment) {
let segment = await Segment.findOne({id_project: req.projectid, _id: req.query.segment }).exec();
if (!segment) {
return res.status(404).send({ success: false, msg: 'Error segment not found' });
}
Segment2MongoConverter.convert(query, segment);
}
if (req.query.full_text) {
winston.debug('LEAD ROUTE req.query.fulltext', req.query.full_text);
query.$text = { "$search": req.query.full_text };
}
if (req.query.email) {
winston.debug('LEAD ROUTE req.query.email', req.query.email);
query.email = req.query.email;
}
if (req.query.with_email) { //for internal request and zapier to retrieve only lead with an email
winston.debug('LEAD ROUTE req.query.withemail', req.query.withemail);
query.email = { "$exists": true };
}
if (req.query.with_fullname) { //or internal request to retrieve only lead with an email
winston.debug('LEAD ROUTE req.query.withfullname', req.query.with_fullname);
query.fullname = { "$exists": true };
}
// aggiungi filtro per data
if (req.query.tags) {
winston.debug('req.query.tags', req.query.tags);
query["tags"] = req.query.tags;
}
// last query modifier
query["id_project"] = req.projectid;
query["status"] = LeadConstants.NORMAL;
if (req.query.status) {
query.status = req.query.status;
}
winston.debug("query", query);
var direction = -1; //-1 descending , 1 ascending
if (req.query.direction) {
direction = req.query.direction;
}
var sortField = "createdAt";
if (req.query.sort) {
sortField = req.query.sort;
}
var sortQuery = {};
sortQuery[sortField] = direction;
winston.debug("sort query", sortQuery);
// TODO ORDER BY SCORE
// return Faq.find(query, {score: { $meta: "textScore" } })
// .sort( { score: { $meta: "textScore" } } ) //https://docs.mongodb.com/manual/reference/operator/query/text/#sort-by-text-search-score
// aggiungi filtro per data marco
return Lead.find(query).
skip(skip).limit(limit).
sort(sortQuery).
exec(function (err, leads) {
if (err) {
winston.error('LEAD ROUTE - REQUEST FIND ERR ', err)
return (err);
}
// blocked to 1000 TODO increases it
// collection.count is deprecated, and will be removed in a future version. Use Collection.countDocuments or Collection.estimatedDocumentCount instead
return Lead.countDocuments(query, function (err, totalRowCount) {
var objectToReturn = {
perPage: limit,
count: totalRowCount,
leads: leads
};
return res.json(objectToReturn);
});
});
});
module.exports = router;