Base model refactor (#810)
* Big upgrades * WIP: Stash * Stash, 30 flow errors left * Downgrade mobx * WIP * When I understand the difference between class and instance methods * 💚 * Fixes: File import Model saving edge cases pinning and starring docs Collection editing Upgrade mobx devtools * Notification settings saving works * Disabled settings * Document mailer * Working notifications * Colletion created notification Ensure not notified for own actions * Tidy up * Document updated event only for document creation Add indexes Notification setting on user creation * Commentary * Fixed: Notification setting on signup * Fix document move / duplicate stale data Add BaseModel.refresh method * Fixes: Title in sidebar not updated after editing document * 💚 * Improve / restore error handling Better handle offline errors * 👕
This commit is contained in:
@@ -7,16 +7,12 @@ const services = {};
|
||||
fs
|
||||
.readdirSync(__dirname)
|
||||
.filter(file => file.indexOf('.') !== 0 && file !== path.basename(__filename))
|
||||
.forEach(name => {
|
||||
const servicePath = path.join(__dirname, name);
|
||||
.forEach(fileName => {
|
||||
const servicePath = path.join(__dirname, fileName);
|
||||
const name = servicePath.replace(/\.js$/, '');
|
||||
// $FlowIssue
|
||||
const pkg = require(path.join(servicePath, 'package.json'));
|
||||
// $FlowIssue
|
||||
const hooks = require(servicePath).default;
|
||||
services[pkg.name] = {
|
||||
...pkg,
|
||||
...hooks,
|
||||
};
|
||||
const Service = require(servicePath).default;
|
||||
services[name] = new Service();
|
||||
});
|
||||
|
||||
export default services;
|
||||
|
||||
99
server/services/notifications.js
Normal file
99
server/services/notifications.js
Normal file
@@ -0,0 +1,99 @@
|
||||
// @flow
|
||||
import { Op } from '../sequelize';
|
||||
import type { Event } from '../events';
|
||||
import { Document, Collection, User, NotificationSetting } from '../models';
|
||||
import mailer from '../mailer';
|
||||
|
||||
export default class Notifications {
|
||||
async on(event: Event) {
|
||||
switch (event.name) {
|
||||
case 'documents.publish':
|
||||
case 'documents.update':
|
||||
return this.documentUpdated(event);
|
||||
case 'collections.create':
|
||||
return this.collectionCreated(event);
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
async documentUpdated(event: Event) {
|
||||
const document = await Document.findById(event.model.id);
|
||||
if (!document) return;
|
||||
|
||||
const { collection } = document;
|
||||
if (!collection) return;
|
||||
|
||||
const notificationSettings = await NotificationSetting.findAll({
|
||||
where: {
|
||||
userId: {
|
||||
// $FlowFixMe
|
||||
[Op.ne]: document.lastModifiedById,
|
||||
},
|
||||
teamId: document.teamId,
|
||||
event: event.name,
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
required: true,
|
||||
as: 'user',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const eventName =
|
||||
event.name === 'documents.publish' ? 'published' : 'updated';
|
||||
|
||||
notificationSettings.forEach(setting => {
|
||||
// For document updates we only want to send notifications if
|
||||
// the document creator matches the notification setting.
|
||||
// This could be replaced with ability to "follow" in the future
|
||||
if (
|
||||
event.name === 'documents.update' &&
|
||||
document.createdById !== setting.userId
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
mailer.documentNotification({
|
||||
to: setting.user.email,
|
||||
eventName,
|
||||
document,
|
||||
collection,
|
||||
actor: document.updatedBy,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async collectionCreated(event: Event) {
|
||||
const collection = await Collection.findById(event.model.id);
|
||||
if (!collection) return;
|
||||
|
||||
const notificationSettings = await NotificationSetting.findAll({
|
||||
where: {
|
||||
userId: {
|
||||
// $FlowFixMe
|
||||
[Op.ne]: collection.createdById,
|
||||
},
|
||||
teamId: collection.teamId,
|
||||
event: event.name,
|
||||
},
|
||||
include: [
|
||||
{
|
||||
model: User,
|
||||
required: true,
|
||||
as: 'user',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
notificationSettings.forEach(setting =>
|
||||
mailer.collectionNotification({
|
||||
to: setting.user.email,
|
||||
eventName: 'created',
|
||||
collection,
|
||||
actor: collection.createdBy,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
// @flow
|
||||
import type { Event } from '../../events';
|
||||
import { Document, Integration, Collection } from '../../models';
|
||||
import { presentSlackAttachment } from '../../presenters';
|
||||
import type { Event } from '../events';
|
||||
import { Document, Integration, Collection } from '../models';
|
||||
import { presentSlackAttachment } from '../presenters';
|
||||
|
||||
class Slack {
|
||||
on = async (event: Event) => {
|
||||
export default class Slack {
|
||||
async on(event: Event) {
|
||||
switch (event.name) {
|
||||
case 'documents.publish':
|
||||
case 'documents.update':
|
||||
@@ -13,9 +13,9 @@ class Slack {
|
||||
return this.integrationCreated(event);
|
||||
default:
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
integrationCreated = async (event: Event) => {
|
||||
async integrationCreated(event: Event) {
|
||||
const integration = await Integration.findOne({
|
||||
where: {
|
||||
id: event.model.id,
|
||||
@@ -54,9 +54,9 @@ class Slack {
|
||||
],
|
||||
}),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
documentUpdated = async (event: Event) => {
|
||||
async documentUpdated(event: Event) {
|
||||
const document = await Document.findById(event.model.id);
|
||||
if (!document) return;
|
||||
|
||||
@@ -86,7 +86,5 @@ class Slack {
|
||||
attachments: [presentSlackAttachment(document)],
|
||||
}),
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export default new Slack();
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"name": "slack",
|
||||
"description": "Hook up your Slack to your Outline."
|
||||
}
|
||||
Reference in New Issue
Block a user