From f7fa0c4909e6065afbe613f132b1adaa19f48d8f Mon Sep 17 00:00:00 2001 From: Paolo Arena Date: Thu, 21 Nov 2019 00:18:40 +0100 Subject: [PATCH] - Create Newsletter Page: MailingList (without the class style, using Gulp tasks)#94 --- ecosystem.config.js | 2 +- emails/newsletter/it/html.pug | 141 ++++++++++++++++ emails/newsletter/it/subject.pug | 1 + emails/one/one.template.pug | 27 ++++ gulpfile.js | 73 +++++++++ package.json | 17 +- server/tools/shared_vuejs.ts | 1 - {server => src/server}/calculations/todo.js | 0 {server => src/server}/classes/queryclass.js | 0 {server => src/server}/config/config.js | 0 {server => src/server}/db/mongoose.js | 0 {server => src/server}/locales/en.json | 0 {server => src/server}/locales/es.json | 0 {server => src/server}/locales/it.json | 0 .../server}/middleware/authenticate.js | 0 {server => src/server}/models/booking.js | 0 {server => src/server}/models/cfgserver.js | 0 {server => src/server}/models/contribtype.js | 0 {server => src/server}/models/discipline.js | 0 src/server/models/mailinglist.js | 59 +++++++ {server => src/server}/models/myevent.js | 18 +++ src/server/models/newstosent.js | 114 +++++++++++++ {server => src/server}/models/operator.js | 4 - {server => src/server}/models/permission.js | 0 {server => src/server}/models/project.js | 0 {server => src/server}/models/sendmsg.js | 0 {server => src/server}/models/settings.js | 0 {server => src/server}/models/subscribers.js | 0 {server => src/server}/models/todo.js | 0 {server => src/server}/models/user.js | 7 +- {server => src/server}/models/where.js | 0 {server => src/server}/mysql/mysql_func.js | 0 {server => src/server}/reg/registration.js | 0 {server => src/server}/router/admin_router.js | 0 {server => src/server}/router/api/actions.js | 0 .../server}/router/booking_router.js | 0 {server => src/server}/router/email_router.js | 0 {server => src/server}/router/index_router.js | 16 +- .../server}/router/myevent_router.js | 0 .../server}/router/newsletter_router.js | 28 +++- .../server}/router/projects_router.js | 2 +- {server => src/server}/router/push_router.js | 0 .../server}/router/sendmsg_router.js | 0 .../server}/router/subscribe_router.js | 0 {server => src/server}/router/todos_router.js | 0 {server => src/server}/router/users_router.js | 0 {server => src/server}/sendemail.js | 153 ++++++++++++++++-- {server => src/server}/server.js | 38 ++--- {server => src/server}/tests/seed/seed.js | 4 +- {server => src/server}/tests/server.test.js | 6 +- {server => src/server}/tools/general.js | 12 +- .../server}/tools/server_constants.js | 1 + {server => src/server}/tools/shared_nodejs.js | 2 +- .../server}/views/integrated-mailchimp.html | 0 54 files changed, 675 insertions(+), 51 deletions(-) create mode 100644 emails/newsletter/it/html.pug create mode 100644 emails/newsletter/it/subject.pug create mode 100644 emails/one/one.template.pug create mode 100644 gulpfile.js delete mode 120000 server/tools/shared_vuejs.ts rename {server => src/server}/calculations/todo.js (100%) rename {server => src/server}/classes/queryclass.js (100%) rename {server => src/server}/config/config.js (100%) rename {server => src/server}/db/mongoose.js (100%) rename {server => src/server}/locales/en.json (100%) rename {server => src/server}/locales/es.json (100%) rename {server => src/server}/locales/it.json (100%) rename {server => src/server}/middleware/authenticate.js (100%) rename {server => src/server}/models/booking.js (100%) rename {server => src/server}/models/cfgserver.js (100%) rename {server => src/server}/models/contribtype.js (100%) rename {server => src/server}/models/discipline.js (100%) create mode 100644 src/server/models/mailinglist.js rename {server => src/server}/models/myevent.js (88%) create mode 100644 src/server/models/newstosent.js rename {server => src/server}/models/operator.js (95%) rename {server => src/server}/models/permission.js (100%) rename {server => src/server}/models/project.js (100%) rename {server => src/server}/models/sendmsg.js (100%) rename {server => src/server}/models/settings.js (100%) rename {server => src/server}/models/subscribers.js (100%) rename {server => src/server}/models/todo.js (100%) rename {server => src/server}/models/user.js (97%) rename {server => src/server}/models/where.js (100%) rename {server => src/server}/mysql/mysql_func.js (100%) rename {server => src/server}/reg/registration.js (100%) rename {server => src/server}/router/admin_router.js (100%) rename {server => src/server}/router/api/actions.js (100%) rename {server => src/server}/router/booking_router.js (100%) rename {server => src/server}/router/email_router.js (100%) rename {server => src/server}/router/index_router.js (95%) rename {server => src/server}/router/myevent_router.js (100%) rename {server => src/server}/router/newsletter_router.js (77%) rename {server => src/server}/router/projects_router.js (99%) rename {server => src/server}/router/push_router.js (100%) rename {server => src/server}/router/sendmsg_router.js (100%) rename {server => src/server}/router/subscribe_router.js (100%) rename {server => src/server}/router/todos_router.js (100%) rename {server => src/server}/router/users_router.js (100%) rename {server => src/server}/sendemail.js (62%) rename {server => src/server}/server.js (91%) rename {server => src/server}/tests/seed/seed.js (97%) rename {server => src/server}/tests/server.test.js (99%) rename {server => src/server}/tools/general.js (97%) rename {server => src/server}/tools/server_constants.js (97%) rename {server => src/server}/tools/shared_nodejs.js (90%) rename {server => src/server}/views/integrated-mailchimp.html (100%) diff --git a/ecosystem.config.js b/ecosystem.config.js index 3510bf1..3f6e936 100644 --- a/ecosystem.config.js +++ b/ecosystem.config.js @@ -2,7 +2,7 @@ module.exports = { apps : [ { name: "FreePlanetServerSide", - script: "./server/server.js", + script: "./src/server/server.js", ignore_watch : ["node_modules"], watch: true, env: { diff --git a/emails/newsletter/it/html.pug b/emails/newsletter/it/html.pug new file mode 100644 index 0000000..6b1b470 --- /dev/null +++ b/emails/newsletter/it/html.pug @@ -0,0 +1,141 @@ +-function prettyDate(dateString){ + //if it's already a date object and not a string you don't need this line: + -var date = new Date(dateString); + -var d = date.getDate(); + -var monthNames = [ "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic" ]; + -var m = monthNames[date.getMonth()]; + -var y = date.getFullYear(); + -return d+' '+m+' '+y; +-} + +- var urlweb = 'http://www.prova.it' +- var urlevent = 'http://www.evento.it' +- var urlunsibscribe = '' +- var urltwitter = '' +- var urlfb = '' +- var imgtwitter = 'https://associazioneshen.it/statics/images/logo.png' +- var imgfb = 'https://associazioneshen.it/statics/images/logo.png' +- var baseurl = 'https://associazioneshen.it/' +- var baseimg = baseurl + 'statics/' +doctype html +html + head + title One | Email template! + + //- import css/scss stylesheets + //- these file names will be replace by gulp with proper css file paths + link(rel="stylesheet", href="../sass/basic.scss") + link(rel="stylesheet", href="../sass/one/styles.scss") + + //- embdedded css allowed, but not sass + style. + .red { + background-color: #E84C50; + } + + .full-width { + width: 100%; + } + body(yahoofix) + span(id='body_style', style='display:block') + table(class="preheader", cellpadding="0", cellspacing="0", width="100%") + tr + td.preheaderContent + p Preloader + td.webversion + p non vedi le immagini?  + a(href=urlweb) Apri la pagina qui + + table(class="topHeader", cellpadding="0", cellspacing="0", width="100%") + tr + td + table(cellpadding="0", cellspacing="0", width="300", align="center", summary="") + tr + td.logoContainer + a(href=urlweb, title='logo') + img.logo(src="https://associazioneshen.it/statics/images/logo.png") + + + table(cellpadding="0", cellspacing="0", width="640", align="center") + tr + td(class="whitespace", height="10") + p   + tr + td(class="emailContainer", valign="top") + + each event in arrevents + - var urlevent = baseurl + 'event/' + event.typol + '/' + event._id + - var imgev = event.img_small + - var mydate = prettyDate(event.dateTimeStart) + unless (imgev) + - var imgev = event.img + + table(cellpadding="0", cellspacing="0", width="100%", summary="", border="0", align="center") + tr + td(class="column sectionArticleImage", valign="top") + img(src=baseimg + imgev, alt="", width="150") + td(class="column", valign="top") + + table(cellpadding="0", cellspacing="0", summary="", border="0") + tr + td(class="sectionContentTitle", valign="top") + p #{event.title} + tr + td(class="sectionContentSubTitle", valign="top") + p(style='color:blue;') #{mydate} + tr + td(class="sectionContent", valign="top") + p!= event.details + tr + td(class="buttonContainer") + table(width="50%", cellpadding="0", cellspacing="0", summary="", border="0") + tr + td(class="button") + a(href=urlevent, title='Evento') Apri l'Evento + + tr + td(class="whitespace", height="20") + p   + tr + td(class="whitespace", height="20") + p   + + // Social Media + table.socialMedia(cellpadding="0", cellspacing="0", width="100%", summary="", border="0", align="center") + tr + td(class="whitespace", height="20") + p   + tr + td + table(width="120", cellpadding="0", cellspacing="0", summary="", border="0", align="center") + tr + td(width="32", align="center") + a(href=urltwitter, title='Twitter') + img(src=imgtwitter, alt="Twitter", width="29") + td(width="32", align="center") + a(href=urlfb, title='Facebook') + img(src=imgfb, alt="Facebook", width="29") + + tr + td(class="whitespace", height="20") + p   + + // Footer + table.footer(cellpadding="0", cellspacing="0", width="100%", summary="", border="0", align="center") + tr + td(class="whitespace", height="10") + p   + tr + td.whitespace + table(width="50%", cellpadding="0", cellspacing="0", summary="", border="0") + tr + td(class="footNotes", align="center") + a(href=urlunsibscribe, title='Disiscriviti') Disiscriviti + td(class="footNotes", align="center") + a(href="#", title='Lorem') Lorem + td(class="footNotes", align="center") + a(href="#", title='Dolor') Lorem + + tr + td(class="whitespace", height="10") + p   diff --git a/emails/newsletter/it/subject.pug b/emails/newsletter/it/subject.pug new file mode 100644 index 0000000..874fa23 --- /dev/null +++ b/emails/newsletter/it/subject.pug @@ -0,0 +1 @@ +=`Newsletter ` diff --git a/emails/one/one.template.pug b/emails/one/one.template.pug new file mode 100644 index 0000000..53c1d43 --- /dev/null +++ b/emails/one/one.template.pug @@ -0,0 +1,27 @@ +doctype html +html + head + title One | Email template! + + //- import css/scss stylesheets + //- these file names will be replace by gulp with proper css file paths + link(rel="stylesheet", href="../../sass/basic.scss") + link(rel="stylesheet", href="../../sass/one/styles.scss") + + //- embdedded css allowed, but not sass + style. + .red{ + background-color: #E84C50; + } + .full-width{ + width: 100%; + } + body + table.table(cellpadding="0", cellspacing="0") + tr + td.red + h3(style="color: white;") Gulp & Pug is awesome + tr + td + a(href="/") + img.full-width(src="https://media.giphy.com/media/6o9Q2WehOHWI1QGO08/giphy.gif") diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..c90227f --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,73 @@ +const gulp = require('gulp'); +const pug = require('gulp-pug'); +const sass = require('gulp-sass'); +const replace = require('gulp-replace'); +const inlineCss = require('gulp-inline-css'); +const rename = require('gulp-rename'); +const browserSync = require('browser-sync').create(); + +// browserSync base directory +// this will be the base directory of files for web preview +// since we are building `index.pug` templates (located in src/emails) to `dist` folder. +const baseDir = "./dist"; + +// compile sass to css +gulp.task('compileSass', function () { + return gulp + // import all email .scss files from src/scss folder + // ** means any sub or deep-sub files or foders + .src('./sass/**/*.scss') + + // on error, do not break the process + .pipe(sass().on('error', sass.logError)) + + // output to `src/css` folder + .pipe(gulp.dest('./css')); +}); + +// build complete HTML email template +// compile sass (compileSass task) before running build +gulp.task('build', gulp.series('compileSass', function () { + return gulp + // import all email template (name ending with .template.pug) files from src/emails folder + .src('emails/**/*.template.pug') + + // replace `.scss` file paths from template with compiled file paths + .pipe(replace(new RegExp('\/sass\/(.+)\.scss', 'ig'), '/css/$1.css')) + + // compile using Pug + .pipe(pug()) + + // inline CSS + .pipe(inlineCss()) + + // do not generate sub-folders inside dist folder + .pipe(rename({dirname: ''})) + + // put compiled HTML email templates inside dist folder + .pipe(gulp.dest('dist')) +})); + +// browserSync task to launch preview server +gulp.task('browserSync', function () { + return browserSync.init({ + reloadDelay: 2000, // reload after 2s, compilation is finished (hopefully) + port: 3002, + server: { baseDir: baseDir } + }); +}); + +// task to reload browserSync +gulp.task('reloadBrowserSync', function () { + return browserSync.reload(); +}); + +// watch source files for changes +// run `build` task when anything inside `src` folder changes (except .css) +// and reload browserSync +gulp.task('watch', gulp.series('build', 'browserSync', function () { + return gulp.watch([ + 'emails/**/*', + '!emails/**/*.css', + ], ['build', 'reloadBrowserSync']); +})); diff --git a/package.json b/package.json index 0dbcda9..ad3803c 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,11 @@ "description": "freeplanet serverside", "main": "server.js", "scripts": { - "start": "nodemon server/server.js", - "test": "export NODE_ENV=development || SET NODE_ENV=development && mocha server/**/*.test.js", - "start:prod": "NODE_ENV=production node server/server.js", + "start": "nodemon src/server/server.js", + "build": "gulp build", + "watch": "gulp watch", + "test": "export NODE_ENV=development || SET NODE_ENV=development && mocha src/server/**/*.test.js", + "start:prod": "NODE_ENV=production node src/server/server.js", "test-watch": "nodemon --exec 'npm test'" }, "engines": { @@ -31,17 +33,26 @@ "mongodb": "^2.2.5", "mongoose": "^4.13.19", "mysql": "^2.17.1", + "node-cron": "^2.0.3", "node-pre-gyp": "^0.11.0", "nodemailer": "^4.6.8", "preview-email": "0.0.8", "pug": "^2.0.4", + "save": "^2.4.0", "url-parse": "^1.4.7", "validator": "^5.6.0", "web-push": "^3.4.0", "xoauth2": "^1.2.0" }, "devDependencies": { + "browser-sync": "^2.26.7", "expect": "^1.20.2", + "gulp": "^4.0.2", + "gulp-inline-css": "^3.4.0", + "gulp-pug": "^4.0.1", + "gulp-rename": "^1.4.0", + "gulp-replace": "^1.0.0", + "gulp-sass": "^4.0.2", "mocha": "^6.2.1", "nodemon": "^1.19.4", "supertest": "^2.0.0" diff --git a/server/tools/shared_vuejs.ts b/server/tools/shared_vuejs.ts deleted file mode 120000 index 8c4a7ad..0000000 --- a/server/tools/shared_vuejs.ts +++ /dev/null @@ -1 +0,0 @@ -../../../freeplanet/src/common/shared_vuejs.ts \ No newline at end of file diff --git a/server/calculations/todo.js b/src/server/calculations/todo.js similarity index 100% rename from server/calculations/todo.js rename to src/server/calculations/todo.js diff --git a/server/classes/queryclass.js b/src/server/classes/queryclass.js similarity index 100% rename from server/classes/queryclass.js rename to src/server/classes/queryclass.js diff --git a/server/config/config.js b/src/server/config/config.js similarity index 100% rename from server/config/config.js rename to src/server/config/config.js diff --git a/server/db/mongoose.js b/src/server/db/mongoose.js similarity index 100% rename from server/db/mongoose.js rename to src/server/db/mongoose.js diff --git a/server/locales/en.json b/src/server/locales/en.json similarity index 100% rename from server/locales/en.json rename to src/server/locales/en.json diff --git a/server/locales/es.json b/src/server/locales/es.json similarity index 100% rename from server/locales/es.json rename to src/server/locales/es.json diff --git a/server/locales/it.json b/src/server/locales/it.json similarity index 100% rename from server/locales/it.json rename to src/server/locales/it.json diff --git a/server/middleware/authenticate.js b/src/server/middleware/authenticate.js similarity index 100% rename from server/middleware/authenticate.js rename to src/server/middleware/authenticate.js diff --git a/server/models/booking.js b/src/server/models/booking.js similarity index 100% rename from server/models/booking.js rename to src/server/models/booking.js diff --git a/server/models/cfgserver.js b/src/server/models/cfgserver.js similarity index 100% rename from server/models/cfgserver.js rename to src/server/models/cfgserver.js diff --git a/server/models/contribtype.js b/src/server/models/contribtype.js similarity index 100% rename from server/models/contribtype.js rename to src/server/models/contribtype.js diff --git a/server/models/discipline.js b/src/server/models/discipline.js similarity index 100% rename from server/models/discipline.js rename to src/server/models/discipline.js diff --git a/src/server/models/mailinglist.js b/src/server/models/mailinglist.js new file mode 100644 index 0000000..bf64c9b --- /dev/null +++ b/src/server/models/mailinglist.js @@ -0,0 +1,59 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const tools = require('../tools/general'); + +mongoose.Promise = global.Promise; +mongoose.level = "F"; + + +// Resolving error Unknown modifier: $pushAll +mongoose.plugin(schema => { + schema.options.usePushEach = true +}); + +const MailingListSchema = new Schema({ + idapp: { + type: String, + }, + email: { + type: String, + trim: true, + }, + name: { + type: String, + trim: true, + }, + surname: { + type: String, + trim: true, + }, + lastid_newstosent: { + type: String + } +}); + +MailingListSchema.statics.getFieldsForSearch = function () { + return ['name', 'surname', 'email'] +}; + +MailingListSchema.statics.executeQueryTable = function (idapp, params) { + params.fieldsearch = this.getFieldsForSearch(); + return tools.executeQueryTable(this, idapp, params); +}; + +MailingListSchema.statics.findAllIdApp = function (idapp) { + const MailingList = this; + + const myfind = { idapp }; + + // Extract only the Teacher where in the users table the field permissions is set 'Teacher' bit. + + return MailingList.find(myfind, (err, arrrec) => { + return arrrec + }); +}; + +const MailingList = mongoose.model('MailingList', MailingListSchema); + +module.exports = { MailingList }; diff --git a/server/models/myevent.js b/src/server/models/myevent.js similarity index 88% rename from server/models/myevent.js rename to src/server/models/myevent.js index ddcc4de..95e1de1 100644 --- a/server/models/myevent.js +++ b/src/server/models/myevent.js @@ -113,6 +113,24 @@ MyEventSchema.statics.findAllIdApp = function (idapp) { }; +MyEventSchema.statics.getLastEvents = function (idapp) { + const Event = this; + + const lastn = 3; + + const query = [ + { $match: { idapp } }, + { $sort: { dateTimeStart: 1 } } + ]; + + return Event + .aggregate(query) + .then((arrrec) => { + return arrrec.slice(-lastn) + }) + +}; + MyEventSchema.statics.getFieldsForSearch = function () { return ['short_tit', 'title', 'teacher', 'details'] diff --git a/src/server/models/newstosent.js b/src/server/models/newstosent.js new file mode 100644 index 0000000..f09579a --- /dev/null +++ b/src/server/models/newstosent.js @@ -0,0 +1,114 @@ +const mongoose = require('mongoose'); +const Schema = mongoose.Schema; + +const tools = require('../tools/general'); + +mongoose.Promise = global.Promise; +mongoose.level = "F"; + + +// Resolving error Unknown modifier: $pushAll +mongoose.plugin(schema => { + schema.options.usePushEach = true +}); + +const NewstosentSchema = new Schema({ + idapp: { + type: String, + }, + label: { + type: String, + }, + activate: { + type: Boolean, + default: false + }, + numemail_tot: { + type: Number, + default: 0 + }, + numemail_sent: { + type: Number, + default: 0 + }, + datetoSent: { + type: Date + }, + datestartJob: { + type: Date + }, + datefinishJob: { + type: Date + }, + lastemailsent_Job: { + type: Date + }, + starting_job: { + type: Boolean, + default: false + }, + finish_job: { + type: Boolean, + default: false + }, + error_job: { + type: String, + } +}); + +NewstosentSchema.statics.getFieldsForSearch = function () { + return ['name', 'surname', 'email'] +}; + +NewstosentSchema.statics.executeQueryTable = function (idapp, params) { + params.fieldsearch = this.getFieldsForSearch(); + return tools.executeQueryTable(this, idapp, params); +}; + +NewstosentSchema.statics.findNewsletter_To_Send = function (idapp) { + const Newstosent = this; + + return Newstosent.findOne({ + datetoSent: { $gte: tools.IncDateNow(-1000 * 60 * 60) }, + activate: true, + starting_job: false, + finish_job: false, + idapp + }).then((rec) => { + return (rec) ? rec._doc : null; + }); +}; + +NewstosentSchema.statics.findNewsletterPending_To_Send = function (idapp) { + const Newstosent = this; + + // Resend the Email after N hours no other email sent. + const numhours = 8; + + return Newstosent.findOne({ + datestartJob: { $lt: tools.IncDateNow(0) }, + activate: true, + starting_job: true, + finish_job: false, + lastemailsent_Job: { $gte: tools.IncDateNow(-1000 * 60 * 60 * numhours) }, + idapp + }).then((rec) => { + return (rec) ? rec._doc : null; + }); +}; + +NewstosentSchema.statics.findAllIdApp = function (idapp) { + const Newstosent = this; + + const myfind = { idapp }; + + // Extract only the Teacher where in the users table the field permissions is set 'Teacher' bit. + + return Newstosent.find(myfind, (err, arrrec) => { + return arrrec + }); +}; + +const Newstosent = mongoose.model('Newstosent', NewstosentSchema); + +module.exports = { Newstosent }; diff --git a/server/models/operator.js b/src/server/models/operator.js similarity index 95% rename from server/models/operator.js rename to src/server/models/operator.js index 3dcd4c1..99b4a1e 100644 --- a/server/models/operator.js +++ b/src/server/models/operator.js @@ -73,10 +73,6 @@ const OperatorSchema = new Schema({ }, }); -OperatorSchema.statics.getFieldsForSearch = function () { - return ['name', 'surname', 'email', 'cell'] -}; - OperatorSchema.statics.getEmailByUsername = async function (idapp, username) { const Operator = this; diff --git a/server/models/permission.js b/src/server/models/permission.js similarity index 100% rename from server/models/permission.js rename to src/server/models/permission.js diff --git a/server/models/project.js b/src/server/models/project.js similarity index 100% rename from server/models/project.js rename to src/server/models/project.js diff --git a/server/models/sendmsg.js b/src/server/models/sendmsg.js similarity index 100% rename from server/models/sendmsg.js rename to src/server/models/sendmsg.js diff --git a/server/models/settings.js b/src/server/models/settings.js similarity index 100% rename from server/models/settings.js rename to src/server/models/settings.js diff --git a/server/models/subscribers.js b/src/server/models/subscribers.js similarity index 100% rename from server/models/subscribers.js rename to src/server/models/subscribers.js diff --git a/server/models/todo.js b/src/server/models/todo.js similarity index 100% rename from server/models/todo.js rename to src/server/models/todo.js diff --git a/server/models/user.js b/src/server/models/user.js similarity index 97% rename from server/models/user.js rename to src/server/models/user.js index 79a4ab6..e6dbd9d 100644 --- a/server/models/user.js +++ b/src/server/models/user.js @@ -108,6 +108,9 @@ var UserSchema = new mongoose.Schema({ lasttimeonline: { type: Date }, + news_on: { + type: Boolean + }, profile: { img: { type: String @@ -280,7 +283,7 @@ UserSchema.statics.findByLinkTokenforgot = function (idapp, email, tokenforgot) return User.findOne({ 'email': email, 'tokenforgot': tokenforgot, - 'date_tokenforgot': { $gte: new Date(ISODate().getTime() - 1000 * 60 * 60 * 4) }, // 4 ore fa! + 'date_tokenforgot': { $gte: tools.IncDateNow(-1000 * 60 * 60 * 4) }, // 4 ore fa! 'idapp': idapp, }); }; @@ -363,7 +366,7 @@ UserSchema.statics.getUsersListByParams = function (params) { return User.find( { $match: filterMatchBefore }, { 'idapp': idapp }, - { username: 1, name: 1, surname: 1, verified_email: 1, perm: 1, email: 1, date_reg: 1, img: 1, lasttimeonline: 1 }) + { username: 1, name: 1, surname: 1, verified_email: 1, perm: 1, email: 1, date_reg: 1, img: 1, lasttimeonline: 1, news_on: 1 }) }; diff --git a/server/models/where.js b/src/server/models/where.js similarity index 100% rename from server/models/where.js rename to src/server/models/where.js diff --git a/server/mysql/mysql_func.js b/src/server/mysql/mysql_func.js similarity index 100% rename from server/mysql/mysql_func.js rename to src/server/mysql/mysql_func.js diff --git a/server/reg/registration.js b/src/server/reg/registration.js similarity index 100% rename from server/reg/registration.js rename to src/server/reg/registration.js diff --git a/server/router/admin_router.js b/src/server/router/admin_router.js similarity index 100% rename from server/router/admin_router.js rename to src/server/router/admin_router.js diff --git a/server/router/api/actions.js b/src/server/router/api/actions.js similarity index 100% rename from server/router/api/actions.js rename to src/server/router/api/actions.js diff --git a/server/router/booking_router.js b/src/server/router/booking_router.js similarity index 100% rename from server/router/booking_router.js rename to src/server/router/booking_router.js diff --git a/server/router/email_router.js b/src/server/router/email_router.js similarity index 100% rename from server/router/email_router.js rename to src/server/router/email_router.js diff --git a/server/router/index_router.js b/src/server/router/index_router.js similarity index 95% rename from server/router/index_router.js rename to src/server/router/index_router.js index c8e7f61..0e07e56 100644 --- a/server/router/index_router.js +++ b/src/server/router/index_router.js @@ -17,6 +17,8 @@ const { Where } = require('../models/where'); const { MyEvent } = require('../models/myevent'); const { Contribtype } = require('../models/contribtype'); const { Discipline } = require('../models/discipline'); +const { Newstosent } = require('../models/newstosent'); +const { MailingList } = require('../models/mailinglist'); const { Settings } = require('../models/settings'); const { SendMsg } = require('../models/sendmsg'); const { Permission } = require('../models/permission'); @@ -146,10 +148,14 @@ function getTableByTableName(tablename) { mytable = Contribtype; else if (tablename === 'disciplines') mytable = Discipline; + else if (tablename === 'newstosent') + mytable = Newstosent; else if (tablename === 'settings') mytable = Settings; else if (tablename === 'permissions') mytable = Permission; + else if (tablename === 'mailinglist') + mytable = MailingList; return mytable } @@ -346,8 +352,14 @@ router.get('/loadsite/:userId/:idapp/:sall', authenticate_noerror, (req, res) => const settings = Settings.findAllIdApp(idapp); const permissions = Permission.findAllIdApp(); + let newstosent = Promise.resolve([]); + let mailinglist = Promise.resolve([]); + if (sall){ + newstosent = Newstosent.findAllIdApp(idapp); + mailinglist = MailingList.findAllIdApp(idapp); + } - return Promise.all([bookedevent, eventlist, operators, wheres, contribtype, settings, permissions, disciplines]) + return Promise.all([bookedevent, eventlist, operators, wheres, contribtype, settings, permissions, disciplines, newstosent, mailinglist]) .then((arrdata) => { // console.table(arrdata); res.send({ @@ -359,6 +371,8 @@ router.get('/loadsite/:userId/:idapp/:sall', authenticate_noerror, (req, res) => settings: arrdata[5], permissions: arrdata[6], disciplines: arrdata[7], + newstosent: arrdata[8], + mailinglist: arrdata[9], }); }) .catch((e) => { diff --git a/server/router/myevent_router.js b/src/server/router/myevent_router.js similarity index 100% rename from server/router/myevent_router.js rename to src/server/router/myevent_router.js diff --git a/server/router/newsletter_router.js b/src/server/router/newsletter_router.js similarity index 77% rename from server/router/newsletter_router.js rename to src/server/router/newsletter_router.js index 85342d7..4bcc408 100644 --- a/server/router/newsletter_router.js +++ b/src/server/router/newsletter_router.js @@ -6,6 +6,11 @@ const request = require('superagent'); const sendemail = require('../sendemail'); +const { User } = require('../models/user'); + +const tools = require('../tools/general'); +const { authenticate } = require('../middleware/authenticate'); + const newsletter = [ { name: 'Paolo', @@ -52,7 +57,7 @@ router.post('/', (req, res) => { surname: req.body.lastName, }; - sendemail.sendEmail_Newsletter(locale, user, idapp); + sendemail.sendEmail_Notif_Added_to_Newsletter(locale, user, idapp); request .post('https://' + newsletter[idwebsite].mailchimpInstance + '.api.mailchimp.com/3.0/lists/' + newsletter[idwebsite].listUniqueId + '/members/') @@ -81,4 +86,23 @@ router.post('/', (req, res) => { }); -module.exports = router; +router.post('/testemail', authenticate, async (req, res) => { + + if (!User.isAdmin(req.user)) { + // If without permissions, exit + return res.status(404).send({ code: server_constants.RIS_CODE_ERR_UNAUTHORIZED, msg: '' }); + } + + idapp = req.body.idapp; + lang = req.body.locale; + + const ris = await sendemail.testemail(idapp, lang); + + if (ris) + return res.send({ code: server_constants.RIS_CODE_OK, msg: '' }); + else + return res.send({ code: server_constants.RIS_CODE_EMAIL_NOT_SENT, msg: '' }); + +}); + + module.exports = router; diff --git a/server/router/projects_router.js b/src/server/router/projects_router.js similarity index 99% rename from server/router/projects_router.js rename to src/server/router/projects_router.js index 8d9a36d..8a32a30 100644 --- a/server/router/projects_router.js +++ b/src/server/router/projects_router.js @@ -10,7 +10,7 @@ const { authenticate } = require('../middleware/authenticate'); // var mongoose = require('mongoose'); const { Project } = require('../models/project'); -const { Todo } = require('./../models/todo'); +const { Todo } = require('../models/todo'); const _ = require('lodash'); diff --git a/server/router/push_router.js b/src/server/router/push_router.js similarity index 100% rename from server/router/push_router.js rename to src/server/router/push_router.js diff --git a/server/router/sendmsg_router.js b/src/server/router/sendmsg_router.js similarity index 100% rename from server/router/sendmsg_router.js rename to src/server/router/sendmsg_router.js diff --git a/server/router/subscribe_router.js b/src/server/router/subscribe_router.js similarity index 100% rename from server/router/subscribe_router.js rename to src/server/router/subscribe_router.js diff --git a/server/router/todos_router.js b/src/server/router/todos_router.js similarity index 100% rename from server/router/todos_router.js rename to src/server/router/todos_router.js diff --git a/server/router/users_router.js b/src/server/router/users_router.js similarity index 100% rename from server/router/users_router.js rename to src/server/router/users_router.js diff --git a/server/sendemail.js b/src/server/sendemail.js similarity index 62% rename from server/sendemail.js rename to src/server/sendemail.js index 2daf634..e4f65dd 100644 --- a/server/sendemail.js +++ b/src/server/sendemail.js @@ -6,11 +6,16 @@ const Email = require('email-templates'); var i18n = require("i18n"); +const { ObjectID } = require('mongodb'); const { Settings } = require('./models/settings'); const previewEmail = require('preview-email'); const nodemailer = require("nodemailer"); +const { MyEvent } = require('./models/myevent'); +const { MailingList } = require('./models/mailinglist'); +const { Newstosent } = require('./models/newstosent'); + const transport_preview = nodemailer.createTransport({ jsonTransport: true }); @@ -184,17 +189,17 @@ module.exports = { let texthtml = ''; if (recbooking.modified) { texthtml = 'modifybooking'; - }else { + } else { texthtml = 'makebooking'; } - this.sendEmail_base('booking/'+texthtml+'/' + lang, emailto, mylocalsconf, tools.getreplyToEmailByIdApp(idapp)); + this.sendEmail_base('booking/' + texthtml + '/' + lang, emailto, mylocalsconf, tools.getreplyToEmailByIdApp(idapp)); // Send Email also to the Admin - this.sendEmail_base('admin/'+texthtml+'/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf, ''); + this.sendEmail_base('admin/' + texthtml + '/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf, ''); if (tools.isManagAndAdminDifferent(idapp)) { - this.sendEmail_base('admin/'+texthtml+'/' + lang, tools.getManagerEmailByIdApp(idapp), mylocalsconf, ''); + this.sendEmail_base('admin/' + texthtml + '/' + lang, tools.getManagerEmailByIdApp(idapp), mylocalsconf, ''); } })); @@ -257,7 +262,7 @@ module.exports = { // Send Email also to the Admin // this.sendEmail_base('admin/sendmsg/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf); }, - sendEmail_Newsletter: function (lang, user, idapp) { + sendEmail_Notif_Added_to_Newsletter: function (lang, user, idapp) { console.log('idapp', idapp, tools.getNomeAppByIdApp(idapp)); @@ -269,14 +274,142 @@ module.exports = { emailto: user.email, }; - // Send to the Admin an Email - this.sendEmail_base('admin/added_to_newsletter/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf, ''); + // Add to the database - if (tools.isManagAndAdminDifferent(idapp)) { - this.sendEmail_base('admin/added_to_newsletter/' + lang, tools.getManagerEmailByIdApp(idapp), mylocalsconf, ''); + myperson = new MailingList({ name: mylocalsconf.name, surname: mylocalsconf.surname, email: mylocalsconf.emailto }); + myperson._id = new ObjectID(); + myperson.idapp = idapp; + + // Add new record to the DB MailingList + return myperson.save().then((res) => { + + // Send to the Admin an Email + this.sendEmail_base('admin/added_to_newsletter/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf, ''); + + if (tools.isManagAndAdminDifferent(idapp)) { + this.sendEmail_base('admin/added_to_newsletter/' + lang, tools.getManagerEmailByIdApp(idapp), mylocalsconf, ''); + } + + }); + }, + + sendEmail_Newsletter_Events: async function (lang, idapp, id_newstosent) { + + console.log('INIZIO - sendEmail_Newsletter_Events', tools.getNomeAppByIdApp(idapp)); + + //++Todo Extract List Email to send + const userstosend = await MailingList.findAllIdApp(idapp); + + const myarrevents = await MyEvent.getLastEvents(idapp); + mylocalsconf = { + locale: lang, + nomeapp: tools.getNomeAppByIdApp(idapp), + arrevents: myarrevents + }; + + const mynewsrec = await Newstosent.findOne({ _id: id_newstosent }); + + mynewsrec.numemail_tot = userstosend.length; + + for (const user of userstosend) { + + mylocalsconf.name = user.name; + mylocalsconf.surname = user.surname; + mylocalsconf.emailto = user.email; + + // If has already sent, don't send it again! + if (user.lastid_newstosent !== id_newstosent.toString()) { + // Send Email to the User + console.log('-> Invio Email (', mynewsrec.numemail_sent, '/', mynewsrec.numemail_tot, ')'); + const esito = this.sendEmail_base('newsletter/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf, ''); + + //Put the result in the database, to check if is sent or not. + const updateml = await MailingList.findOneAndUpdate({ + idapp, + email: user.email + }, { $set: { lastid_newstosent: ObjectID(id_newstosent) } }, { new: false }); + + + mynewsrec.lastemailsent_Job = new Date(); + mynewsrec.numemail_sent += 1; + + const recsaved = await mynewsrec.save(); + + //Delay for send email... + await tools.snooze(process.env.DELAY_SENDEMAIL); + + if (mynewsrec.numemail_sent === mynewsrec.numemail_tot) { + mynewsrec.datefinishJob = new Date(); + mynewsrec.finish_job = true; + await mynewsrec.save().then((ris) => { + console.log('****', tools.getNomeAppByIdApp(idapp), mynewsrec.numemail_sent, 'Email inviate'); + }); + } + } + } + + console.log('FINE (esco da funz) - sendEmail_Newsletter_Events', tools.getNomeAppByIdApp(idapp)); + + }, + + checkifSentNewsletter: async function (idapp) { + // Check if is the time to send the Newsletter + + return Newstosent.findNewsletter_To_Send(idapp) + .then((rec) => { + if (rec) + this.sendNewsletter(rec); + }); + } + , + + checkifPendingNewsletter: async function (idapp) { + // Check if is the time to send the Newsletter + // Only newsletter pending en 8 hour last email sent. + + return Newstosent.findNewsletterPending_To_Send(idapp) + .then((rec) => { // + this.sendNewsletter(rec) + }); + }, + + sendNewsletter: async function (rec) { + + // Start the job + myjobnews = await Newstosent.findOne({ _id: rec._id }); + if (!!myjobnews) { + myjobnews.starting_job = true; + myjobnews.datestartJob = new Date(); + + myjobnews.save() + .then((ris) => { + + this.sendEmail_Newsletter_Events("it", '2', rec._id); + }) + .catch((e) => { + console.error(e); + }); } }, + testemail: async function (idapp, lang) { -}; + const myarrevents = await MyEvent.getLastEvents(idapp); + mylocalsconf = { + locale: lang, + nomeapp: tools.getNomeAppByIdApp(idapp), + arrevents: myarrevents, + name: 'Paolo', + surname: 'Arena', + emailto: "pa.oloarena77@gmail.com", + }; + console.log('-> Invio Email TEST a', mylocalsconf.emailto); + return this.sendEmail_base('newsletter/' + lang, tools.getAdminEmailByIdApp(idapp), mylocalsconf, ''); + + } + + + +} +; diff --git a/server/server.js b/src/server/server.js similarity index 91% rename from server/server.js rename to src/server/server.js index 4caaa19..d344cf0 100644 --- a/server/server.js +++ b/src/server/server.js @@ -14,6 +14,7 @@ const path = require('path'); const sendemail = require('./sendemail'); +const cron = require('node-cron'); i18n = require("i18n"); @@ -33,6 +34,8 @@ require('./models/subscribers'); require('./models/cfgserver'); require('./models/booking'); require('./models/sendmsg'); +require('./models/mailinglist'); +require('./models/newstosent'); const mysql_func = require('./mysql/mysql_func'); @@ -49,6 +52,8 @@ const projects_router = require('./router/projects_router'); const users_router = require('./router/users_router'); const admin_router = require('./router/admin_router'); +const { MyEvent } = require('./models/myevent'); + require('./db/mongoose'); console.log("DB: " + process.env.DATABASE); @@ -148,15 +153,15 @@ if ((process.env.NODE_ENV === 'production') || (process.env.NODE_ENV === 'test') } if (process.env.PROD !== 1) { - testmsgwebpush(); - testemail(); + // testmsgwebpush(); + // sendemail.testemail('2', 'it'); } // ----------------- MAILCHIMP ----- const querystring = require('querystring'); const mailchimpClientId = 'xxxxxxxxxxxxxxxx'; -app.get('/mailchimp/auth/authorize', function(req, res) { +app.get('/mailchimp/auth/authorize', function (req, res) { res.redirect('https://login.mailchimp.com/oauth2/authorize?' + querystring.stringify({ 'response_type': 'code', @@ -194,22 +199,12 @@ function startserv() { } -function testemail() { - /*const user = { - username: 'paoloar77', - name: 'Paolo', - surname: 'Arena', - email: "paolo.arena77@gmail.com", - };*/ - const user = { - username: 'cricri_test', - name: 'Cristina', - surname: 'Barattoni', - email: "Info@cristinabarattoni.it", - }; - - // sendemail.sendEmail_Registration("it", user.email, user, '2', "http://link_solo_di_prova.com"); +function mycron() { + for (const app of MYAPPS) { + sendemail.checkifPendingNewsletter(app.idapp); + sendemail.checkifSentNewsletter(app.idapp); + } } function testmsgwebpush() { @@ -232,9 +227,14 @@ function testmsgwebpush() { }); - } +// Cron every 5 minutes +cron.schedule('*/5 * * * *', () => { + console.log('Running Cron Job'); + mycron(); +}); + //app.listen(port, () => { // console.log(`Server started at port ${port}`); //}); diff --git a/server/tests/seed/seed.js b/src/server/tests/seed/seed.js similarity index 97% rename from server/tests/seed/seed.js rename to src/server/tests/seed/seed.js index 25b43e0..6bef9df 100644 --- a/server/tests/seed/seed.js +++ b/src/server/tests/seed/seed.js @@ -1,8 +1,8 @@ const { ObjectID } = require('mongodb'); const jwt = require('jsonwebtoken'); -const { Todo } = require('./../../models/todo'); -const { User } = require('./../../models/user'); +const { Todo } = require('../../models/todo'); +const { User } = require('../../models/user'); var bcrypt = require('bcryptjs'); diff --git a/server/tests/server.test.js b/src/server/tests/server.test.js similarity index 99% rename from server/tests/server.test.js rename to src/server/tests/server.test.js index d67daf2..59ba1e9 100644 --- a/server/tests/server.test.js +++ b/src/server/tests/server.test.js @@ -2,9 +2,9 @@ const expect = require('expect'); const request = require('supertest'); const { ObjectID } = require('mongodb'); -const { app } = require('./../server'); -const { Todo } = require('./../models/todo'); -const { User } = require('./../models/user'); +const { app } = require('../server'); +const { Todo } = require('../models/todo'); +const { User } = require('../models/user'); const { todos, populateTodos, users, populateUsers, userjson, mypwdcrypted, mypwdchiaro, date_login } = require('./seed/seed'); const tools = require('../tools/general'); diff --git a/server/tools/general.js b/src/server/tools/general.js similarity index 97% rename from server/tools/general.js rename to src/server/tools/general.js index de5ba2c..8c25179 100644 --- a/server/tools/general.js +++ b/src/server/tools/general.js @@ -11,7 +11,7 @@ const { ObjectID } = require('mongodb'); const mongoose = require('mongoose'); const Subscription = mongoose.model('subscribers'); -const server_constants = require('../tools/server_constants'); +const server_constants = require('./server_constants'); // SETTINGS WebPush Configuration const webpush = require('web-push'); @@ -480,4 +480,14 @@ module.exports = { return myval }, + snooze(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); + }, + + IncDateNow(secs) { + let mydate = new Date(new Date().getTime() + secs); + // console.log('mydate', mydate); + return mydate + } + }; diff --git a/server/tools/server_constants.js b/src/server/tools/server_constants.js similarity index 97% rename from server/tools/server_constants.js rename to src/server/tools/server_constants.js index 64847fe..3c0e90d 100644 --- a/server/tools/server_constants.js +++ b/src/server/tools/server_constants.js @@ -6,6 +6,7 @@ module.exports = Object.freeze({ RIS_CODE_EMAIL_ALREADY_VERIFIED: -5, RIS_CODE_EMAIL_VERIFIED: 1, + RIS_CODE_EMAIL_NOT_SENT: -40, RIS_CODE_ERR_UNAUTHORIZED: -30, RIS_CODE_LOGIN_ERR_GENERIC: -20, RIS_CODE_LOGIN_ERR: -10, diff --git a/server/tools/shared_nodejs.js b/src/server/tools/shared_nodejs.js similarity index 90% rename from server/tools/shared_nodejs.js rename to src/server/tools/shared_nodejs.js index 7285c3b..62cdf68 100644 --- a/server/tools/shared_nodejs.js +++ b/src/server/tools/shared_nodejs.js @@ -12,7 +12,7 @@ module.exports = { }, fieldsUserToChange() { - return ['_id', 'username', 'email', 'cell', 'name', 'surname', 'perm', 'date_reg', 'verified_email', 'img', 'ipaddr', 'lasttimeonline', 'profile'] + return ['_id', 'username', 'email', 'cell', 'name', 'surname', 'perm', 'date_reg', 'verified_email', 'img', 'ipaddr', 'lasttimeonline', 'profile', 'news_on'] } }; diff --git a/server/views/integrated-mailchimp.html b/src/server/views/integrated-mailchimp.html similarity index 100% rename from server/views/integrated-mailchimp.html rename to src/server/views/integrated-mailchimp.html