Added web and email notifications. Tests. Fire page

This commit is contained in:
vjrj 2018-01-16 16:19:29 +01:00
parent df05b33e82
commit 3bf21c8caf
32 changed files with 696 additions and 88 deletions

View file

@ -2,6 +2,7 @@
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import firesCommonSchema from '../Common/FiresSchema';
const ActiveFires = new Mongo.Collection('activefires', { idGeneration: 'MONGO' });
@ -17,6 +18,13 @@ ActiveFires.deny({
remove: () => true
});
ActiveFires.schema = new SimpleSchema(firesCommonSchema);
ActiveFires.attachSchema(ActiveFires.schema);
export default ActiveFires;
/* Sample:
* {
* "_id" : ObjectId("5a208d7579095a1adba48191"),
@ -46,19 +54,3 @@ ActiveFires.deny({
* "createdAt" : ISODate("2017-11-30T08:07:33.720Z")
* }
* */
ActiveFires.schema = new SimpleSchema({
lat: Number,
lon: Number,
scan: Number,
type: String,
acq_date: String,
acq_time: String,
when: Date,
createdAt: Date,
updatedAt: Date
});
ActiveFires.attachSchema(ActiveFires.schema);
export default ActiveFires;

View file

@ -0,0 +1,29 @@
/* eslint-disable import/no-absolute-path */
import { defaultCreatedAt, defaultUpdateAt } from '/imports/api/Utility/Utils.js';
import LocationSchema from '/imports/api/Utility/LocationSchema.js';
const firesCommonSchema = {
ourid: LocationSchema,
lat: Number,
lon: Number,
scan: Number,
type: String,
when: Date,
track: { type: Number, optional: true },
acq_date: { type: String, optional: true },
acq_time: { type: String, optional: true },
satellite: { type: String, optional: true },
confidence: { type: Number, optional: true },
version: { type: String, optional: true },
frp: { type: Number, optional: true },
daynight: { type: String, optional: true },
brightness: { type: Number, optional: true },
bright_t31: { type: Number, optional: true },
bright_ti4: { type: Number, optional: true },
bright_ti5: { type: Number, optional: true },
createdAt: defaultCreatedAt,
updatedAt: defaultUpdateAt
};
export default firesCommonSchema;

View file

@ -0,0 +1,25 @@
/* eslint-disable consistent-return */
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import firesCommonSchema from '../Common/FiresSchema';
const Fires = new Mongo.Collection('fires', { idGeneration: 'MONGO' });
Fires.allow({
insert: () => false,
update: () => false,
remove: () => false
});
Fires.deny({
insert: () => true,
update: () => true,
remove: () => true
});
Fires.schema = new SimpleSchema(firesCommonSchema);
Fires.attachSchema(Fires.schema);
export default Fires;

View file

@ -0,0 +1,22 @@
/* eslint-disable import/no-absolute-path */
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import rateLimit from '/imports/modules/rate-limit';
import urlEnc from '/imports/modules/url-encode';
Meteor.methods({
'fire.decrypt': async function fireDecode(fireEnc) {
check(fireEnc, String);
const unsealed = await urlEnc.decrypt(fireEnc);
return unsealed;
}
});
rateLimit({
methods: [
'fire.decode'
],
limit: 5,
timeRange: 1000
});

View file

@ -0,0 +1,37 @@
/* eslint-disable import/no-absolute-path */
/* eslint-disable prefer-arrow-callback */
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import urlEnc from '/imports/modules/url-encode';
import { Promise } from 'meteor/promise';
import FiresCollection from '../Fires';
function findFire(unsealed) {
const fire = FiresCollection.find({ ourid: { type: 'Point', coordinates: [unsealed.lon, unsealed.lat] } });
return fire;
}
Meteor.publish('fireFromHash', function fireFromHash(fireEnc) {
check(fireEnc, String);
try {
// console.log(fireEnc);
const unsealed = Promise.await(urlEnc.decrypt(fireEnc));
const w = unsealed.when;
// console.log(w);
unsealed.when = new Date(w);
// console.log(unsealed);
FiresCollection.schema.validate(unsealed);
const fire = findFire(unsealed);
if (fire.count() === 0) {
const result = FiresCollection.upsert({ ourid: unsealed.ourid }, { $set: unsealed }, { multi: false, upsert: true });
console.log(JSON.stringify(result));
}
return findFire(unsealed);
/* console.log(`fires: ${fire.count()}`);
* return fire; */
} catch (e) {
console.error(e);
throw new Meteor.Error('500', e);
}
});

View file

@ -0,0 +1,39 @@
/* eslint-disable consistent-return */
/* eslint-disable import/no-absolute-path */
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import { defaultCreatedAt, defaultUpdateAt } from '/imports/api/Utility/Utils.js';
import LocationSchema from '/imports/api/Utility/LocationSchema.js';
const Notifications = new Mongo.Collection('notifications', { idGeneration: 'MONGO' });
Notifications.allow({
insert: () => false,
update: () => false,
remove: () => false
});
Notifications.deny({
insert: () => true,
update: () => true,
remove: () => true
});
Notifications.schema = new SimpleSchema({
userId: String,
content: String,
geo: LocationSchema,
type: String,
webNotified: { type: Boolean, optional: true },
webNotifiedAt: { type: Date, optional: true },
emailNotified: { type: Boolean, optional: true },
emailNotifiedAt: { type: Date, optional: true },
when: Date,
createdAt: defaultCreatedAt,
updatedAt: defaultUpdateAt
});
Notifications.attachSchema(Notifications.schema);
export default Notifications;

View file

@ -0,0 +1,25 @@
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import Notifications from './Notifications';
import rateLimit from '../../modules/rate-limit';
Meteor.methods({
'notifications.sent': function notificationsUpdate(notifId) {
check(notifId, Meteor.Collection.ObjectID);
try {
Notifications.update(notifId, { $set: { webNotified: true, webNotifiedAt: new Date() } });
return notifId;
} catch (exception) {
throw new Meteor.Error('500', exception);
}
}
});
rateLimit({
methods: [
'notifications.sent'
],
limit: 5,
timeRange: 1000
});

View file

@ -0,0 +1,10 @@
/* eslint-disable prefer-arrow-callback */
import { Meteor } from 'meteor/meteor';
import Notifications from '../Notifications';
Meteor.publish('mynotifications', function notifications() {
const notif = Notifications.find({ userId: this.userId, type: 'web', webNotified: null });
console.log(`Notifications for user ${this.userId}: ${notif.count()}`);
return notif;
});

View file

@ -4,6 +4,7 @@
import { Mongo } from 'meteor/mongo';
import SimpleSchema from 'simpl-schema';
import { defaultCreatedAt, defaultUpdateAt } from '/imports/api/Utility/Utils.js';
import LocationSchema from '/imports/api/Utility/LocationSchema.js';
const Subscriptions = new Mongo.Collection('subscriptions', { idGeneration: 'MONGO' });
@ -39,36 +40,6 @@ Subscriptions.deny({
* }
* */
// https://stackoverflow.com/questions/24492333/meteor-simple-schema-for-mongo-geo-location-data
// https://github.com/aldeed/meteor-simple-schema/issues/606
const LocationSchema = new SimpleSchema({
type: {
type: String,
allowedValues: ['Point']
},
coordinates: {
type: Array,
minCount: 2,
maxCount: 2,
custom: function custom() {
if (!(this.value[0] >= -90 && this.value[0] <= 90)) {
return 'lngOutOfRange';
}
if (!(this.value[1] >= -180 && this.value[1] <= 180)) {
return 'latOutOfRange';
}
return true;
}
},
'coordinates.$': {
type: Number
}
});
LocationSchema.messageBox.messages({
lonOutOfRange: '[label] longitude should be between -90 and 90',
latOutOfRange: '[label] latitude should be between -180 and 180'
});
Subscriptions.schema = new SimpleSchema({
location: Object,

View file

@ -16,10 +16,10 @@ export default (options, user) => {
templateVars: {
applicationName,
firstName,
welcomeUrl: Meteor.absoluteUrl('documents'), // e.g., returns http://localhost:3000/documents
},
welcomeUrl: Meteor.absoluteUrl('subscriptions') // e.g., returns http://localhost:3000/documents
}
})
.catch((error) => {
throw new Meteor.Error('500', `${error}`);
});
.catch((error) => {
throw new Meteor.Error('500', `${error}`);
});
};

View file

@ -0,0 +1,34 @@
import SimpleSchema from 'simpl-schema';
// https://stackoverflow.com/questions/24492333/meteor-simple-schema-for-mongo-geo-location-data
// https://github.com/aldeed/meteor-simple-schema/issues/606
const LocationSchema = new SimpleSchema({
type: {
type: String,
allowedValues: ['Point']
},
coordinates: {
type: Array,
minCount: 2,
maxCount: 2,
custom: function custom() {
if (!(this.value[0] >= -90 && this.value[0] <= 90)) {
return 'lngOutOfRange';
}
if (!(this.value[1] >= -180 && this.value[1] <= 180)) {
return 'latOutOfRange';
}
return true;
}
},
'coordinates.$': {
type: Number
}
});
LocationSchema.messageBox.messages({
lonOutOfRange: '[label] longitude should be between -90 and 90',
latOutOfRange: '[label] latitude should be between -180 and 180'
});
export default LocationSchema;