diff --git a/imports/modules/server/notificationsProcess.js b/imports/modules/server/notificationsProcess.js
new file mode 100644
index 0000000..300f925
--- /dev/null
+++ b/imports/modules/server/notificationsProcess.js
@@ -0,0 +1,137 @@
+/* eslint-disable import/no-absolute-path */
+
+import { Meteor } from 'meteor/meteor';
+import Notifications from '/imports/api/Notifications/Notifications';
+import i18n from 'i18next';
+import moment from 'moment';
+import { dateLongFormat } from '/imports/api/Common/dates';
+// import sendMail from '/imports/startup/server/email';
+import sendEmail, { subjectTruncate } from '/imports/modules/server/send-email';
+import { isMailServerMaster } from '/imports/startup/server/email';
+// import { hr } from '/imports/startup/server/email';
+import getEmailOf from '/imports/modules/get-email-of-user';
+import image from 'google-maps-image-api-url';
+import gcm from 'node-gcm';
+import { trim } from '/imports/ui/components/NotificationsObserver/util.js';
+
+let validFcmSender = true;
+
+if (!(Meteor.settings.private.fcmApiToken && Meteor.settings.private.fcmApiToken.length > 0)) {
+ console.warn('Missing settings.private.fcmApiToken key, mobile notifications will not work');
+ validFcmSender = false;
+}
+
+const fcmSender = new gcm.Sender(Meteor.settings.private.fcmApiToken);
+
+// https://www.npmjs.com/package/google-maps-image-api-url
+// https://stackoverflow.com/questions/24355007/is-there-no-way-to-embed-a-google-map-into-an-html-email
+// https://developers.google.com/maps/documentation/static-maps/intro
+function imgUrl(lat, lng) {
+ return image({
+ key: Meteor.settings.gmaps.key,
+ type: 'staticmap',
+ center: `${lat},${lng}`,
+ size: '640x480',
+ zoom: 16,
+ maptype: 'hybrid',
+ language: 'es',
+ markers: `icon: ${Meteor.settings.private.fireIconUrl}|${lat},${lng}`
+ });
+}
+
+/*
+ function imgEl(lat, lng) {
+ return `
`;
+ } */
+
+const processNotif = (notif) => {
+ if (isMailServerMaster && notif.type === 'mobile' && !notif.notified) {
+ const user = Meteor.users.findOne({ _id: notif.userId });
+ moment.locale(user.lang);
+ // duplicate code below
+ const body = `${trim(notif.content)}`;
+
+ // https://firebase.google.com/docs/cloud-messaging/concept-options
+ const msg = new gcm.Message();
+
+ msg.addNotification({
+ title: i18n.t('Alerta de fuego'),
+ body,
+ click_action: 'FLUTTER_NOTIFICATION_CLICK',
+ tag: notif._id, // prevent duplication of fire notifications
+ sound: 'default', // Indicates sound to be played. Supports only default currently.
+ icon: 'launch_image' // 'ic_launcher'
+ });
+
+ msg.addData('id', notif._id._str);
+ msg.addData('description', body);
+ msg.addData('lat', notif.geo.coordinates[1]);
+ msg.addData('lon', notif.geo.coordinates[0]);
+ msg.addData('when', notif.when);
+ msg.addData('subsId', notif.subsId._str);
+ msg.addData('sealed', notif.sealed);
+
+ const registrationTokens = [];
+ if (!user.fireBaseToken) {
+ console.warn('This mobile user doesn\'t have a firebase registration token');
+ } else {
+ registrationTokens.push(user.fireBaseToken);
+ // FIXME: better join users
+ if (validFcmSender) {
+ fcmSender.send(msg, { registrationTokens }, Meteor.bindEnvironment(function processResult(err, response) {
+ if (err) {
+ console.error(`FCM error: ${err}`);
+ // FIXME send to sentry
+ } else {
+ // console.log(`FCM response: ${response}`);
+ Notifications.update(notif._id, { $set: { notified: true, notifiedAt: new Date() } });
+ }
+ }));
+ }
+ }
+ } else if (notif.type === 'web' && !notif.emailNotified) {
+ const user = Meteor.users.findOne({ _id: notif.userId });
+ const { firstName, emailAddress } = getEmailOf(user);
+
+ if (emailAddress) {
+ const img = imgUrl(notif.geo.coordinates[1], notif.geo.coordinates[0]);
+ // const url = imgUrl(notif.geo.coordinates[1], notif.geo.coordinates[0]);
+ const fireUrl = `${Meteor.absoluteUrl('fire/')}${notif.sealed}`;
+ // const fireHtmlUrl = `${i18n.t('Más información sobre este fuego')}`;
+ // TODO get _id of fire
+ // const fireTextUrl = `${i18n.t('Más información sobre este fuego')}:\n${fireUrl}`;
+ // FIXME use our map as url and static map as img
+ moment.locale(user.lang);
+ // moment user tz ?
+ const message = `${trim(notif.content)} (${i18n.t('fireDetectedAt', { when: dateLongFormat(notif.when) })}).`;
+
+ // TODO Comunes Address
+
+ const emailOpts = {
+ to: emailAddress,
+ // userName: firstName,
+ // sendAt: new Date(),
+ subject: subjectTruncate.apply(message),
+ // text: `${message}\n\n${fireTextUrl}\n\n`,
+ // template: '
{{appName}}
{{{html}}}',
+ lang: user.lang,
+ template: 'new-fire',
+ templateVars: {
+ applicationName: i18n.t('AppName'),
+ firstName,
+ message,
+ fireUrl,
+ img,
+ subsUrl: Meteor.absoluteUrl('subscriptions')
+ }
+ };
+ sendEmail(emailOpts).catch((error) => {
+ throw new Meteor.Error('500', `${error}`);
+ });
+ // sendMail(emailOpts, true);
+ Notifications.update(notif._id, { $set: { emailNotified: true, emailNotifiedAt: new Date() } });
+ }
+ }
+};
+
+export default processNotif;
diff --git a/imports/startup/server/cron.js b/imports/startup/server/cron.js
index 9b0fa77..cb9d755 100644
--- a/imports/startup/server/cron.js
+++ b/imports/startup/server/cron.js
@@ -4,6 +4,8 @@
import { Meteor } from 'meteor/meteor';
import { tweetIberiaFires, tweetEuropeFires } from '/imports/api/ActiveFires/server/tweetFiresInZone';
import { isMailServerMaster, sendEmailsFromQueue } from '/imports/startup/server/email';
+import Notifications from '/imports/api/Notifications/Notifications';
+import processNotif from '/imports/modules/server/notificationsProcess.js';
// https://github.com/thesaucecode/meteor-synced-cron/
@@ -44,7 +46,7 @@ Meteor.startup(() => {
timezone: 'Europe/Madrid',
schedule: (parser) => {
// http://bunkat.github.io/later/
- const sched = parser.text('every 1 min');
+ const sched = parser.text('every 10 min');
if (sched.error !== -1) {
console.error(`Mail cron 'when' field parsed with errors: ${sched.error}`);
}
@@ -52,6 +54,24 @@ Meteor.startup(() => {
},
job: () => sendEmailsFromQueue()
});
+
+ SyncedCron.add({
+ name: 'Process pending notif',
+ timezone: 'Europe/Madrid',
+ schedule: (parser) => {
+ // http://bunkat.github.io/later/
+ const sched = parser.text('every 15 min');
+ if (sched.error !== -1) {
+ console.error(`Mail cron 'when' field parsed with errors: ${sched.error}`);
+ }
+ return sched;
+ },
+ job: () => {
+ Notifications.find({ nofitied: null }).forEach((notif) => {
+ processNotif(notif);
+ });
+ }
+ });
}
const esEn = Meteor.settings.private.twitter.es.enabled;
diff --git a/imports/startup/server/notificationsObserver.js b/imports/startup/server/notificationsObserver.js
index 0065e15..70be8e0 100644
--- a/imports/startup/server/notificationsObserver.js
+++ b/imports/startup/server/notificationsObserver.js
@@ -1,145 +1,19 @@
/* eslint-disable import/no-absolute-path */
-import i18n from 'i18next';
import { Meteor } from 'meteor/meteor';
-import moment from 'moment';
-import { dateLongFormat } from '/imports/api/Common/dates';
import Notifications from '/imports/api/Notifications/Notifications';
-// import sendMail from '/imports/startup/server/email';
-import sendEmail, { subjectTruncate } from '/imports/modules/server/send-email';
+import processNotif from '/imports/modules/server/notificationsProcess.js';
import { isMailServerMaster } from '/imports/startup/server/email';
-// import { hr } from '/imports/startup/server/email';
-import getEmailOf from '/imports/modules/get-email-of-user';
-import image from 'google-maps-image-api-url';
-import gcm from 'node-gcm';
-import { trim } from '/imports/ui/components/NotificationsObserver/util.js';
Meteor.startup(() => {
- let validFcmSender = true;
-
- if (!(Meteor.settings.private.fcmApiToken && Meteor.settings.private.fcmApiToken.length > 0)) {
- console.warn('Missing settings.private.fcmApiToken key, mobile notifications will not work');
- validFcmSender = false;
- }
-
- const fcmSender = new gcm.Sender(Meteor.settings.private.fcmApiToken);
-
- // https://www.npmjs.com/package/google-maps-image-api-url
- // https://stackoverflow.com/questions/24355007/is-there-no-way-to-embed-a-google-map-into-an-html-email
- // https://developers.google.com/maps/documentation/static-maps/intro
- function imgUrl(lat, lng) {
- return image({
- key: Meteor.settings.gmaps.key,
- type: 'staticmap',
- center: `${lat},${lng}`,
- size: '640x480',
- zoom: 16,
- maptype: 'hybrid',
- language: 'es',
- markers: `icon: ${Meteor.settings.private.fireIconUrl}|${lat},${lng}`
+ if (isMailServerMaster) {
+ Notifications.find().observe({
+ added: function notifAdded(notif) {
+ processNotif(notif);
+ },
+ changed: function notifChanged(updatedNotif) { // , oldNotif) {
+ processNotif(updatedNotif);
+ }
});
}
-
- /*
- function imgEl(lat, lng) {
- return `
`;
- } */
-
- function process(notif) {
- if (isMailServerMaster && notif.type === 'mobile' && !notif.notified) {
- const user = Meteor.users.findOne({ _id: notif.userId });
- moment.locale(user.lang);
- // duplicate code below
- const body = `${trim(notif.content)}`;
-
- // https://firebase.google.com/docs/cloud-messaging/concept-options
- const msg = new gcm.Message();
-
- msg.addNotification({
- title: i18n.t('Alerta de fuego'),
- body,
- click_action: 'FLUTTER_NOTIFICATION_CLICK',
- tag: notif._id, // prevent duplication of fire notifications
- sound: 'default', // Indicates sound to be played. Supports only default currently.
- icon: 'launch_image' // 'ic_launcher'
- });
-
- msg.addData('id', notif._id._str);
- msg.addData('description', body);
- msg.addData('lat', notif.geo.coordinates[1]);
- msg.addData('lon', notif.geo.coordinates[0]);
- msg.addData('when', notif.when);
- msg.addData('subsId', notif.subsId._str);
- msg.addData('sealed', notif.sealed);
-
- const registrationTokens = [];
- if (!user.fireBaseToken) {
- console.warn('This mobile user doesn\'t have a firebase registration token');
- } else {
- registrationTokens.push(user.fireBaseToken);
- // FIXME: better join users
- if (validFcmSender) {
- fcmSender.send(msg, { registrationTokens }, Meteor.bindEnvironment(function processResult(err, response) {
- if (err) {
- console.error(`FCM error: ${err}`);
- } else {
- // console.log(`FCM response: ${response}`);
- Notifications.update(notif._id, { $set: { notified: true, notifiedAt: new Date() } });
- }
- }));
- }
- }
- } else if (notif.type === 'web' && !notif.emailNotified) {
- const user = Meteor.users.findOne({ _id: notif.userId });
- const { firstName, emailAddress } = getEmailOf(user);
-
- if (emailAddress) {
- const img = imgUrl(notif.geo.coordinates[1], notif.geo.coordinates[0]);
- // const url = imgUrl(notif.geo.coordinates[1], notif.geo.coordinates[0]);
- const fireUrl = `${Meteor.absoluteUrl('fire/')}${notif.sealed}`;
- // const fireHtmlUrl = `${i18n.t('Más información sobre este fuego')}`;
- // TODO get _id of fire
- // const fireTextUrl = `${i18n.t('Más información sobre este fuego')}:\n${fireUrl}`;
- // FIXME use our map as url and static map as img
- moment.locale(user.lang);
- // moment user tz ?
- const message = `${trim(notif.content)} (${i18n.t('fireDetectedAt', { when: dateLongFormat(notif.when) })}).`;
-
- // TODO Comunes Address
-
- const emailOpts = {
- to: emailAddress,
- // userName: firstName,
- // sendAt: new Date(),
- subject: subjectTruncate.apply(message),
- // text: `${message}\n\n${fireTextUrl}\n\n`,
- // template: '{{appName}}
{{{html}}}',
- lang: user.lang,
- template: 'new-fire',
- templateVars: {
- applicationName: i18n.t('AppName'),
- firstName,
- message,
- fireUrl,
- img,
- subsUrl: Meteor.absoluteUrl('subscriptions')
- }
- };
- sendEmail(emailOpts).catch((error) => {
- throw new Meteor.Error('500', `${error}`);
- });
- // sendMail(emailOpts, true);
- Notifications.update(notif._id, { $set: { emailNotified: true, emailNotifiedAt: new Date() } });
- }
- }
- }
-
- Notifications.find().observe({
- added: function notifAdded(notif) {
- process(notif);
- },
- changed: function notifChanged(updatedNotif, oldNotif) {
- process(updatedNotif);
- }
- });
});