2017-12-14 20:12:14 +02:00
|
|
|
const Note = require('lib/models/Note.js');
|
2017-11-28 00:50:46 +02:00
|
|
|
const Alarm = require('lib/models/Alarm.js');
|
|
|
|
|
|
|
|
class AlarmService {
|
|
|
|
static setDriver(v) {
|
|
|
|
this.driver_ = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static driver() {
|
|
|
|
if (!this.driver_) throw new Error('AlarmService driver not set!');
|
|
|
|
return this.driver_;
|
|
|
|
}
|
|
|
|
|
|
|
|
static setLogger(v) {
|
|
|
|
this.logger_ = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static logger() {
|
|
|
|
return this.logger_;
|
|
|
|
}
|
|
|
|
|
2017-11-28 22:17:34 +02:00
|
|
|
static setInAppNotificationHandler(v) {
|
|
|
|
this.inAppNotificationHandler_ = v;
|
|
|
|
if (this.driver_.setInAppNotificationHandler) this.driver_.setInAppNotificationHandler(v);
|
|
|
|
}
|
|
|
|
|
2017-11-28 02:22:38 +02:00
|
|
|
static async garbageCollect() {
|
|
|
|
this.logger().info('Garbage collecting alarms...');
|
|
|
|
|
|
|
|
// Delete alarms that have already been triggered
|
|
|
|
await Alarm.deleteExpiredAlarms();
|
|
|
|
|
|
|
|
// Delete alarms that correspond to non-existent notes
|
|
|
|
const alarmIds = await Alarm.alarmIdsWithoutNotes();
|
|
|
|
for (let i = 0; i < alarmIds.length; i++) {
|
|
|
|
this.logger().info('Clearing notification for non-existing note. Alarm ' + alarmIds[i]);
|
|
|
|
await this.driver().clearNotification(alarmIds[i]);
|
|
|
|
}
|
|
|
|
await Alarm.batchDelete(alarmIds);
|
|
|
|
}
|
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
// When passing a note, make sure it has all the required properties
|
2017-11-28 02:22:38 +02:00
|
|
|
// (better to pass a complete note or else just the ID)
|
|
|
|
static async updateNoteNotification(noteOrId, isDeleted = false) {
|
2018-12-08 01:42:29 +02:00
|
|
|
try {
|
|
|
|
let note = null;
|
|
|
|
let noteId = null;
|
|
|
|
|
|
|
|
if (typeof noteOrId === 'object') {
|
|
|
|
note = noteOrId;
|
|
|
|
noteId = note.id;
|
|
|
|
} else {
|
|
|
|
note = await Note.load(noteOrId);
|
|
|
|
noteId = note ? note.id : null;
|
|
|
|
}
|
2017-11-28 02:22:38 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
if (!note && !isDeleted) return;
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
const driver = this.driver();
|
2017-11-28 02:22:38 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
let alarm = noteId ? await Alarm.byNoteId(noteId) : null;
|
|
|
|
let clearAlarm = false;
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
if (isDeleted || !Note.needAlarm(note) || (alarm && alarm.trigger_time !== note.todo_due)) {
|
2018-12-08 01:42:29 +02:00
|
|
|
clearAlarm = !!alarm;
|
|
|
|
}
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
if (!clearAlarm && alarm) {
|
|
|
|
// Alarm already exists and set at the right time
|
2017-11-28 02:22:38 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
// For persistent notifications (those that stay active after the app has been closed, like on mobile), if we have
|
|
|
|
// an alarm object we can be sure that the notification has already been set, so there's nothing to do.
|
|
|
|
// For non-persistent notifications however we need to check that the notification has been set because, for example,
|
|
|
|
// if the app has just started the notifications need to be set again. so we do this below.
|
|
|
|
if (!driver.hasPersistentNotifications() && !driver.notificationIsSet(alarm.id)) {
|
|
|
|
const notification = await Alarm.makeNotification(alarm, note);
|
|
|
|
this.logger().info('Scheduling (non-persistent) notification for note ' + note.id, notification);
|
|
|
|
driver.scheduleNotification(notification);
|
|
|
|
}
|
2017-11-28 02:22:38 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
return;
|
|
|
|
}
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
if (clearAlarm) {
|
|
|
|
this.logger().info('Clearing notification for note ' + noteId);
|
|
|
|
await driver.clearNotification(alarm.id);
|
|
|
|
await Alarm.delete(alarm.id);
|
|
|
|
}
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
if (isDeleted || !Note.needAlarm(note)) return;
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
await Alarm.save({
|
|
|
|
note_id: note.id,
|
|
|
|
trigger_time: note.todo_due,
|
|
|
|
});
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
// Reload alarm to get its ID
|
|
|
|
alarm = await Alarm.byNoteId(note.id);
|
2017-11-28 00:50:46 +02:00
|
|
|
|
2018-12-08 01:42:29 +02:00
|
|
|
const notification = await Alarm.makeNotification(alarm, note);
|
|
|
|
this.logger().info('Scheduling notification for note ' + note.id, notification);
|
|
|
|
await driver.scheduleNotification(notification);
|
|
|
|
} catch (error) {
|
|
|
|
this.logger().error('Could not update notification', error);
|
|
|
|
}
|
2017-11-28 02:22:38 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static async updateAllNotifications() {
|
2018-06-09 21:00:26 +02:00
|
|
|
this.logger().info('Updating all notifications...');
|
2017-11-28 02:22:38 +02:00
|
|
|
|
|
|
|
await this.garbageCollect();
|
|
|
|
|
|
|
|
const dueNotes = await Note.dueNotes();
|
|
|
|
for (let i = 0; i < dueNotes.length; i++) {
|
|
|
|
await this.updateNoteNotification(dueNotes[i]);
|
|
|
|
}
|
2017-11-28 00:50:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-29 15:43:53 +02:00
|
|
|
module.exports = AlarmService;
|