Pannello Utente

Aggiornamento Yarn
- Notifiche (1)
This commit is contained in:
Paolo Arena
2022-07-10 01:25:19 +02:00
parent c8324f0de4
commit ba99b72e69
10 changed files with 383 additions and 43 deletions

107
src/server/models/sendnotif.js Executable file
View File

@@ -0,0 +1,107 @@
const mongoose = require('mongoose').set('debug', false)
const Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.level = "F";
const { ObjectID } = require('mongodb');
// Resolving error Unknown modifier: $pushAll
mongoose.plugin(schema => {
schema.options.usePushEach = true
});
const sendNotifSchema = new Schema({
idapp: {
type: String,
},
type: {
type: Number,
},
sender: { // mittente
type: String,
},
dest: {
type: String,
},
descr: {
type: String,
},
datenotif: {
type: Date,
},
status: {
type: Number,
},
read: {
type: Boolean,
default: false
},
deleted: {
type: Boolean,
default: false
},
});
sendNotifSchema.statics.findAllNotifByUsernameIdAndIdApp = function (username, lastdataread, idapp) {
const SendNotif = this;
return SendNotif.find({
$and: [
{ idapp },
{ 'dest': username },
{ 'datenotif': {$gt: new Date(lastdataread)} },
]
}).then((arrnotif) => {
console.log('arrnotif', arrnotif.length);
return arrnotif
}).catch((err) => {
console.error('err', err);
});
};
sendNotifSchema.statics.findLastGroupByUserIdAndIdApp = function (username, idapp) {
const SendNotif = this;
return SendNotif.aggregate([
{
$match: {
idapp,
dest: username,
}
},
{
$group:
{
_id: "$dest",
descr: { $last: "$message" },
datenotif: { $last: "$datenotif" },
read: { $last: "$read" }
}
},
{
$sort: { datenotif: -1 }
},
])
.then((arrnotif) => {
// Remove duplicate
// Exclude my chat
const myarr = arrnotif.filter((ris) => ris._id !== username);
// console.table(myarr);
return myarr
}).catch((err) => {
console.error(err);
});
};
const SendNotif = mongoose.model('SendNotif', sendNotifSchema);
module.exports = { SendNotif: SendNotif };

View File

@@ -8,7 +8,6 @@ module.exports = {
{_id: 6, descr: 'Benessere'}, {_id: 6, descr: 'Benessere'},
{_id: 7, descr: 'Per la Casa'}, {_id: 7, descr: 'Per la Casa'},
{_id: 8, descr: 'Intrattenimento'}, {_id: 8, descr: 'Intrattenimento'},
{_id: 9, descr: 'Ospitalità'},
{_id: 10, descr: 'Per la Persona'}, {_id: 10, descr: 'Per la Persona'},
{_id: 11, descr: 'Progetti di Gruppo'}, {_id: 11, descr: 'Progetti di Gruppo'},
{_id: 12, descr: 'Salute'}, {_id: 12, descr: 'Salute'},

View File

@@ -63,12 +63,6 @@ module.exports = {
{_id: 61, idSector: [8], descr: 'Film making'}, {_id: 61, idSector: [8], descr: 'Film making'},
{_id: 62, idSector: [8], descr: 'Sport'}, {_id: 62, idSector: [8], descr: 'Sport'},
{_id: 63, idSector: [8], descr: 'Arte'}, {_id: 63, idSector: [8], descr: 'Arte'},
{_id: 64, idSector: [9], descr: 'Offresi Ospitalità'},
{_id: 65, idSector: [9], descr: 'Affitto casa'},
{_id: 66, idSector: [9], descr: 'Affittacamere'},
{_id: 67, idSector: [9], descr: 'Affitto mini appartamento'},
{_id: 68, idSector: [9], descr: 'Bed & Breakfast'},
{_id: 69, idSector: [9], descr: 'Scambio Casa'},
{_id: 70, idSector: [10], descr: 'Parrucchiere'}, {_id: 70, idSector: [10], descr: 'Parrucchiere'},
{_id: 71, idSector: [10], descr: 'Estetista'}, {_id: 71, idSector: [10], descr: 'Estetista'},
{_id: 72, idSector: [10], descr: 'Omeopatia'}, {_id: 72, idSector: [10], descr: 'Omeopatia'},

View File

@@ -55,6 +55,7 @@ const {CalZoom} = require('../models/calzoom');
const {Gallery} = require('../models/gallery'); const {Gallery} = require('../models/gallery');
const {Settings} = require('../models/settings'); const {Settings} = require('../models/settings');
const {SendMsg} = require('../models/sendmsg'); const {SendMsg} = require('../models/sendmsg');
const {SendNotif} = require('../models/sendnotif');
const {Permission} = require('../models/permission'); const {Permission} = require('../models/permission');
const Producer = require('../models/producer'); const Producer = require('../models/producer');
const Cart = require('../models/cart'); const Cart = require('../models/cart');
@@ -138,7 +139,6 @@ router.post(process.env.LINK_REQUEST_NEWPASSWORD, async (req, res) => {
'POST ' + process.env.LINK_REQUEST_NEWPASSWORD + ' idapp= ' + idapp + 'POST ' + process.env.LINK_REQUEST_NEWPASSWORD + ' idapp= ' + idapp +
' email = ' + email); ' email = ' + email);
try { try {
const ris = await User.createNewRequestPwd(idapp, email); const ris = await User.createNewRequestPwd(idapp, email);
if (ris) { if (ris) {
@@ -148,7 +148,7 @@ router.post(process.env.LINK_REQUEST_NEWPASSWORD, async (req, res) => {
return res.status(200). return res.status(200).
send({code: server_constants.RIS_CODE_EMAIL_NOT_EXIST, msg: ''}); send({code: server_constants.RIS_CODE_EMAIL_NOT_EXIST, msg: ''});
} }
} catch(e) { } catch (e) {
console.log(process.env.LINK_REQUEST_NEWPASSWORD, e.message); console.log(process.env.LINK_REQUEST_NEWPASSWORD, e.message);
res.status(400).send(); res.status(400).send();
res.send({code: server_constants.RIS_CODE_ERR, msg: e}); res.send({code: server_constants.RIS_CODE_ERR, msg: e});
@@ -304,11 +304,11 @@ router.post('/settable', authenticate, async (req, res) => {
// Controlla se esiste già con lo stesso nome // Controlla se esiste già con lo stesso nome
let alreadyexist = await MyGroup.findOne({idapp, groupname: mydata.groupname}); let alreadyexist = await MyGroup.findOne({idapp, groupname: mydata.groupname});
if (alreadyexist) { if (alreadyexist) {
return res.send({code: server_constants.RIS_CODE_REC_ALREADY_EXIST_CODE }); return res.send({code: server_constants.RIS_CODE_REC_ALREADY_EXIST_CODE});
} }
alreadyexist = await MyGroup.findOne({idapp, title: mydata.title}); alreadyexist = await MyGroup.findOne({idapp, title: mydata.title});
if (alreadyexist) { if (alreadyexist) {
return res.send({code: server_constants.RIS_CODE_REC_ALREADY_EXIST_NAME }); return res.send({code: server_constants.RIS_CODE_REC_ALREADY_EXIST_NAME});
} }
} }
@@ -444,6 +444,57 @@ router.post('/gettable', authenticate, (req, res) => {
}); });
router.post('/getexp', authenticate, (req, res) => {
const params = req.body;
let idapp = req.user.idapp;
const myUser = globalTables.getTableByTableName('users');
// console.log('mytable', mytable);
if (!myUser || params.filtersearch2 !== 'fdsgas1') {
return res.status(400).send({});
}
if ((!User.isAdmin(req.user.perm) && !User.isManager(req.user.perm) &&
!User.isTutor(req.user.perm))) {
// If without permissions, exit
return res.status(404).
send({code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: ''});
}
try {
if (params.table === 'exp') {
return myUser.find({
idapp,
$or: [
{deleted: {$exists: false}},
{deleted: {$exists: true, $eq: false}}],
},
{
username: 1,
email: 1,
'profile.teleg_id': 1,
'verified_by_aportador': 1,
'profile.username_telegram': 1,
'profile.firstname_telegram': 1,
'profile.lastname_telegram': 1,
}).then(ris => {
return res.send({data: ris});
}).catch((e) => {
console.error('getexp: ' + e.message);
res.status(400).send(e);
});
}
} catch (e) {
console.error(`ERROR getexp ${params.table}: `, e.message, 'params',
params);
res.status(500).send(e);
}
});
router.post('/pickup', authenticate, (req, res) => { router.post('/pickup', authenticate, (req, res) => {
const params = req.body; const params = req.body;
let idapp = req.user.idapp; let idapp = req.user.idapp;
@@ -1249,8 +1300,8 @@ router.get(process.env.LINK_CHECK_UPDATES, authenticate, async (req, res) => {
// const sall = '0'; // const sall = '0';
// msgs = SendMsg.findAllByUserIdAndIdApp(userId, req.user.username, req.user.idapp); // msgs = SendMsg.findAllByUserIdAndIdApp(userId, req.user.username, req.user.idapp);
let last_msgs = SendMsg.findLastGroupByUserIdAndIdApp(userId, let last_msgs = SendMsg.findLastGroupByUserIdAndIdApp(userId, req.user.username, idapp);
req.user.username, idapp); let last_notifs = SendNotif.findLastGroupByUserIdAndIdApp(userId, req.user.username, idapp);
let usersList = null; let usersList = null;
@@ -1265,12 +1316,13 @@ router.get(process.env.LINK_CHECK_UPDATES, authenticate, async (req, res) => {
} }
} }
return Promise.all([usersList, last_msgs]).then((arrdata) => { return Promise.all([usersList, last_msgs, last_notifs]).then((arrdata) => {
// console.table(arrdata); // console.table(arrdata);
return res.send({ return res.send({
CfgServer: arrcfgrec, CfgServer: arrcfgrec,
usersList: arrdata[0], usersList: arrdata[0],
last_msgs: arrdata[1], last_msgs: arrdata[1],
last_notifs: arrdata[2],
}); });
}); });
@@ -1413,43 +1465,41 @@ function uploadFile(req, res, version) {
// SMALL // SMALL
// questa opzione 'failOnError' serve per risolvere l'errore (Error: VipsJpeg: Invalid SOS parameters for sequential JPEG // questa opzione 'failOnError' serve per risolvere l'errore (Error: VipsJpeg: Invalid SOS parameters for sequential JPEG
sharp(newname, { failOnError: false }). sharp(newname, {failOnError: false}).
resize(64, 64). resize(64, 64).
withMetadata(). withMetadata().
toFile(resized_img_small); toFile(resized_img_small);
// MEDIUM // MEDIUM
let resized_img = tools.extractFilePath(newname) + '/' + server_constants.PREFIX_IMG + tools.extractFileName(newname); let resized_img = tools.extractFilePath(newname) + '/' + server_constants.PREFIX_IMG + tools.extractFileName(newname);
sharp(newname, { failOnError: false }). sharp(newname, {failOnError: false}).
resize( { resize({
width: 512, width: 512,
height: 512, height: 512,
fit: sharp.fit.cover, fit: sharp.fit.cover,
position: sharp.strategy.entropy position: sharp.strategy.entropy,
}) }).withMetadata().toFile(resized_img, function(err) {
.withMetadata()
.toFile(resized_img, function(err) {
// console.log('3) Ridimensionata Immagine ' + newname, 'in', resized_img); // console.log('3) Ridimensionata Immagine ' + newname, 'in', resized_img);
if (tools.isFileExists(resized_img)) { if (tools.isFileExists(resized_img)) {
// console.log('4) Cancella l \'immagine grande originale:', newname); // console.log('4) Cancella l \'immagine grande originale:', newname);
// DELETE THE ORIGINAL BIG // DELETE THE ORIGINAL BIG
tools.delete(newname, false, () => {}); tools.delete(newname, false, () => {});
// console.log('5) Rinomina l\'immagine Media da', resized_img, 'a:', newname);
// RENAME THE MEDIUM IN THE ORIGINAL NAME
tools.move(resized_img, newname, (err) => {
if (err)
console.error('err', err);
else
console.log('move', newname);
});
}
// console.log('5) Rinomina l\'immagine Media da', resized_img, 'a:', newname);
// RENAME THE MEDIUM IN THE ORIGINAL NAME
tools.move(resized_img, newname, (err) => {
if (err) if (err)
console.error('Error Upload: ', err); console.error('err', err);
else
console.log('move', newname);
}); });
}
if (err)
console.error('Error Upload: ', err);
});
} catch (e) { } catch (e) {
console.error('Error Upload(2) ', e); console.error('Error Upload(2) ', e);
} }

View File

@@ -0,0 +1,113 @@
const express = require('express');
const router = express.Router();
const tools = require('../tools/general');
const server_constants = require('../tools/server_constants');
const { authenticate } = require('../middleware/authenticate');
const { User } = require('../models/user');
const { Operator } = require('../models/operator');
const { SendNotif } = require('../models/sendnotif');
const { ObjectID } = require('mongodb');
const sendemail = require('../sendemail');
const shared_consts = require('../tools/shared_nodejs');
const _ = require('lodash');
async function sendNotif(res, idapp, user, recnotif) {
// Controlla nelle impostazioni che tipo di Notifica visualizzare
if (tools.isBitActive(recnotif.options, shared_consts.MessageOptions.Notify_ByPushNotification)) {
if (this.checkifSendPushNotification) {
console.log('SEND PUSH NOTIFICATION ')
//++Todo: tools.sendNotificationToUser
}
}
// Read from the operator table first
let emaildest = await Operator.getEmailByUsername(recnotif.dest.idapp, recnotif.dest.username);
if (!emaildest)
emaildest = await User.getEmailByUsername(recnotif.dest.idapp, recnotif.dest.username);
console.log('emaildest', emaildest);
// Send Msg by EMAIL
if (emaildest && tools.isBitActive(recnotif.options, shared_consts.MessageOptions.Notify_ByEmail))
await sendemail.sendEmail_Msg(res, user.lang, emaildest, user, idapp, recnotif);
return true
}
router.post('/', authenticate, (req, res) => {
tools.mylog('INIZIO - SendNotif');
// tools.mylog('req.body', req.body);
const body = _.pick(req.body, tools.allfieldSendNotif());
tools.mylog('crea SendNotif');
const myrecnotif = new SendNotif(body);
const check = tools.checkUserOk(myrecnotif.sender, req.user.username, res);
if (check.exit) return check.ret;
// console.log('fieldtochange', fieldtochange);
myrecnotif._id = new ObjectID();
return myrecnotif.save()
.then((writeresult) => {
let idobj = writeresult._id;
myrecnotif._id = idobj;
return SendNotif.findById(idobj)
.then(async (recnotif) => {
// Add this field because I don't want to add into the database
return await sendNotif(res, body.idapp, req.user, recnotif).then((ris) => {
return res.send({ code: server_constants.RIS_CODE_OK, notif: '', id: recnotif._id });
})
});
}).catch((e) => {
console.log(e.message);
// res.status(400).send(e);
return res.send({ code: server_constants.RIS_CODE_ERR, notif: '' });
})
});
router.get('/:username/:lastdataread/:idapp', authenticate, (req, res) => {
tools.mylog('GET NotifS : ', req.params);
const username = req.params.username;
const lastdataread = req.params.lastdataread;
const idapp = req.params.idapp;
// var category = req.params.category;
if (req.user.idapp !== idapp) {
// I'm trying to get something not mine!
return res.status(404).send({ code: server_constants.RIS_CODE_NOT_MY_USERNAME });
}
// Extract all the todos of the userId only
return SendNotif.findAllNotifByUsernameIdAndIdApp(username, lastdataread, idapp).then((arrnotif) => {
// const wait = new Promise((resolve, reject) => {
// setTimeout(() => {
res.send({ arrnotif });
// }, 2000);
// });
}).catch((e) => {
console.log(e.message);
res.status(400).send(e);
});
});
module.exports = router;

View File

@@ -403,6 +403,36 @@ router.post('/profile', authenticate, (req, res) => {
}); });
router.post('/panel', authenticate, async (req, res) => {
const username = req.body['username'];
idapp = req.body.idapp;
locale = req.body.locale;
if (!User.isAdmin(req.user.perm) && !User.isManager(req.user.perm)) {
// If without permissions, exit
return res.status(404).
send({code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: ''});
}
try {
const myuser = await User.findOne({idapp, username},
{username: 1, email: 1, verified_by_aportador: 1, aportador_solidario: 1,
lasttimeonline: 1,
deleted: 1,
profile: 1}).lean();
if (!!myuser) {
res.send(myuser);
} else {
tools.mylog('ERRORE IN panel: ' + e.message);
res.status(400).send();
}
} catch (e) {
tools.mylogserr('Error profile: ', e);
res.status(400).send();
}
});
router.post('/login', (req, res) => { router.post('/login', (req, res) => {
var body = _.pick(req.body, var body = _.pick(req.body,
['username', 'password', 'idapp', 'keyappid', 'lang']); ['username', 'password', 'idapp', 'keyappid', 'lang']);

View File

@@ -84,6 +84,7 @@ myLoad().then(ris => {
require('./models/subscribers'); require('./models/subscribers');
require('./models/booking'); require('./models/booking');
require('./models/sendmsg'); require('./models/sendmsg');
require('./models/sendnotif');
require('./models/mailinglist'); require('./models/mailinglist');
require('./models/newstosent'); require('./models/newstosent');
require('./models/mypage'); require('./models/mypage');
@@ -99,6 +100,7 @@ myLoad().then(ris => {
const myevent_router = require('./router/myevent_router'); const myevent_router = require('./router/myevent_router');
const subscribe_router = require('./router/subscribe_router'); const subscribe_router = require('./router/subscribe_router');
const sendmsg_router = require('./router/sendmsg_router'); const sendmsg_router = require('./router/sendmsg_router');
const sendnotif_router = require('./router/sendnotif_router');
const email_router = require('./router/email_router'); const email_router = require('./router/email_router');
const todos_router = require('./router/todos_router'); const todos_router = require('./router/todos_router');
const test_router = require('./router/test_router'); const test_router = require('./router/test_router');
@@ -148,6 +150,7 @@ myLoad().then(ris => {
app.use('/', index_router); app.use('/', index_router);
app.use('/subscribe', subscribe_router); app.use('/subscribe', subscribe_router);
app.use('/sendmsg', sendmsg_router); app.use('/sendmsg', sendmsg_router);
app.use('/sendnotif', sendnotif_router);
app.use('/push', push_router); app.use('/push', push_router);
app.use('/news', newsletter_router); app.use('/news', newsletter_router);
app.use('/booking', booking_router); app.use('/booking', booking_router);
@@ -534,6 +537,10 @@ async function faitest() {
// tools.execScript("ls -la"); // tools.execScript("ls -la");
} }
if (false) {
prova = tools.removeAtChar('@prova');
}
if (false) { if (false) {
const prova = tools.getConfSiteOptionEnabledByIdApp('13', shared_consts.ConfSite.Notif_Reg_Push_Admin); const prova = tools.getConfSiteOptionEnabledByIdApp('13', shared_consts.ConfSite.Notif_Reg_Push_Admin);
console.log('prova', prova); console.log('prova', prova);

View File

@@ -477,7 +477,7 @@ const txt = {
emoji.get('dizzy'), emoji.get('dizzy'),
MSG_ASK_USERNAME_BO: 'Scrivete nel messaggio l\'username (SENZA SPAZI) o la email con cui vi siete registrati sul sito di %s:', MSG_ASK_USERNAME_BO: 'Scrivete nel messaggio l\'username (SENZA SPAZI) o la email con cui vi siete registrati sul sito di %s:',
MSG_ASK_USERNAME_INVITANTE: 'Incolla (o scrivi) l\'username di chi ti ha invitato su %s (non inserire spazi)', MSG_ASK_USERNAME_INVITANTE: 'Incolla (o scrivi) l\'username di chi ti ha invitato su %s (non inserire spazi)',
MSG_ERRORE_INVITANTE_NOT_FOUND: 'L\'username dell\'invitante appena digitato non sembra essere corretto!', MSG_ERRORE_INVITANTE_NOT_FOUND: 'L\'username dell\'invitante appena digitato non sembra essere corretto! Ti ricordo che dev\'essere l\'username con cui si è registrato su RISO',
MSG_ERRORE_USERNAME: 'Attenzione! Devi inserire solo lo username (40 caratteri massimo)', MSG_ERRORE_USERNAME: 'Attenzione! Devi inserire solo lo username (40 caratteri massimo)',
MSG_ERRORE_USERNAME_NOT_FOUND: 'Per Completare la Verifica Telegram BOT, dovete ora scrivere qui sotto nel messaggio l\'Username (senza spazi) OPPURE la email con cui vi siete registrati sul sito', MSG_ERRORE_USERNAME_NOT_FOUND: 'Per Completare la Verifica Telegram BOT, dovete ora scrivere qui sotto nel messaggio l\'Username (senza spazi) OPPURE la email con cui vi siete registrati sul sito',
MSG_ERRORE_USERNAME_ANNULLA: 'Inserimento Annullato. Riprovare', MSG_ERRORE_USERNAME_ANNULLA: 'Inserimento Annullato. Riprovare',
@@ -2548,6 +2548,7 @@ class Telegram {
let aportador_solidario = rec.aportador_solidario; let aportador_solidario = rec.aportador_solidario;
if (!aportador_solidario) { if (!aportador_solidario) {
aportador_solidario = msg.text.toString().trim().toLowerCase(); aportador_solidario = msg.text.toString().trim().toLowerCase();
tools.removeAtChar(aportador_solidario);
const user = await User.getUserShortDataByUsername(this.idapp, aportador_solidario); const user = await User.getUserShortDataByUsername(this.idapp, aportador_solidario);
if (user) if (user)
rec.aportador_solidario = user.username; rec.aportador_solidario = user.username;

View File

@@ -569,6 +569,20 @@ module.exports = {
'options']; 'options'];
}, },
allfieldSendNotif: function() {
return [
'type',
'userId',
'sender',
'dest',
'descr',
'datenotif',
'read',
'deleted',
'idapp',
'status'];
},
allfieldTodo: function() { allfieldTodo: function() {
return [ return [
'userId', 'userId',
@@ -2912,4 +2926,12 @@ module.exports = {
}); });
}, },
removeAtChar(mystr) {
if (mystr && mystr[0] === '@'){
return mystr = mystr.substring(1);
}
return mystr;
},
}; };

View File

@@ -127,7 +127,7 @@ module.exports = {
'mygoods', 'mygoods',
'mygroups', 'mygroups',
'circuits', 'circuits',
'movements'], 'movements'],
TABLES_USER_ID: ['mygroups', 'myskills', 'mybachecas', 'myhosps', 'mygoods'], TABLES_USER_ID: ['mygroups', 'myskills', 'mybachecas', 'myhosps', 'mygoods'],
TABLES_UPDATE_LASTMODIFIED: ['myskills', 'mybachecas', 'myhosps', 'mygoods', 'bots'], TABLES_UPDATE_LASTMODIFIED: ['myskills', 'mybachecas', 'myhosps', 'mygoods', 'bots'],
@@ -254,7 +254,6 @@ module.exports = {
CANCELED: 10, CANCELED: 10,
}, },
ConfSite: { ConfSite: {
Notif_Reg_Bot_ToManagers: 1, Notif_Reg_Bot_ToManagers: 1,
Notif_Reg_Push_Admin: 2, Notif_Reg_Push_Admin: 2,
@@ -262,12 +261,12 @@ module.exports = {
}, },
MsgTeleg: { MsgTeleg: {
SHARE_MSGREG: 1 SHARE_MSGREG: 1,
}, },
TypeMsgTemplate: { TypeMsgTemplate: {
MSG_BENVENUTO: 2010, MSG_BENVENUTO: 2010,
MS_SHARE_LINK: 2000 MS_SHARE_LINK: 2000,
}, },
TypeSend: { TypeSend: {
@@ -275,6 +274,25 @@ module.exports = {
TELEGRAM: 2, TELEGRAM: 2,
}, },
// Tipi di Notifiche:
Notif: {
UPDATE_APP: 1,
NEW_GOOD_MY_PROVINCE: 12,
NEW_GOOD_MY_COMUNE: 13,
NEW_SERVICE_MY_PROVINCE: 14,
NEW_SERVICE_MY_COMUNE: 15,
NEW_HOSP_MY_PROVINCE: 16,
NEW_HOSP_MY_COMUNE: 17,
REQ_NEW_FRIEND: 20,
ACCEPTED_NEW_FRIEND_REQ: 21,
RIS_RECEIVED: 50,
RIS_SENT_CONFIRMED: 51,
RIS_SENT_REFUSED: 52,
},
fieldsUserToChange() { fieldsUserToChange() {
return [ return [
'_id', '_id',
@@ -302,5 +320,4 @@ module.exports = {
'qualified']; 'qualified'];
}, },
}; };