feat: Events / audit log (#1008)
* feat: Record events in DB * feat: events API * First pass, hacky activity feed * WIP * Reset dashboard * feat: audit log UI feat: store ip address * chore: Document events.list api * fix: command specs * await event create * fix: backlinks service * tidy * fix: Hide audit log menu item if not admin
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
// @flow
|
||||
import { DataTypes, sequelize } from '../sequelize';
|
||||
import events from '../events';
|
||||
|
||||
const Event = sequelize.define('event', {
|
||||
id: {
|
||||
@@ -8,6 +9,7 @@ const Event = sequelize.define('event', {
|
||||
primaryKey: true,
|
||||
},
|
||||
name: DataTypes.STRING,
|
||||
ip: DataTypes.STRING,
|
||||
data: DataTypes.JSONB,
|
||||
});
|
||||
|
||||
@@ -16,6 +18,10 @@ Event.associate = models => {
|
||||
as: 'user',
|
||||
foreignKey: 'userId',
|
||||
});
|
||||
Event.belongsTo(models.User, {
|
||||
as: 'actor',
|
||||
foreignKey: 'actorId',
|
||||
});
|
||||
Event.belongsTo(models.Collection, {
|
||||
as: 'collection',
|
||||
foreignKey: 'collectionId',
|
||||
@@ -30,4 +36,52 @@ Event.associate = models => {
|
||||
});
|
||||
};
|
||||
|
||||
Event.beforeCreate(event => {
|
||||
if (event.ip) {
|
||||
// cleanup IPV6 representations of IPV4 addresses
|
||||
event.ip = event.ip.replace(/^::ffff:/, '');
|
||||
}
|
||||
});
|
||||
|
||||
Event.afterCreate(event => {
|
||||
events.add(event);
|
||||
});
|
||||
|
||||
Event.ACTIVITY_EVENTS = [
|
||||
'users.create',
|
||||
'documents.publish',
|
||||
'documents.archive',
|
||||
'documents.unarchive',
|
||||
'documents.pin',
|
||||
'documents.unpin',
|
||||
'documents.delete',
|
||||
'collections.create',
|
||||
'collections.delete',
|
||||
];
|
||||
|
||||
Event.AUDIT_EVENTS = [
|
||||
'users.create',
|
||||
'users.promote',
|
||||
'users.demote',
|
||||
'users.invite',
|
||||
'users.suspend',
|
||||
'users.activate',
|
||||
'users.delete',
|
||||
'documents.publish',
|
||||
'documents.update',
|
||||
'documents.archive',
|
||||
'documents.unarchive',
|
||||
'documents.pin',
|
||||
'documents.unpin',
|
||||
'documents.move',
|
||||
'documents.delete',
|
||||
'shares.create',
|
||||
'shares.revoke',
|
||||
'collections.create',
|
||||
'collections.update',
|
||||
'collections.add_user',
|
||||
'collections.remove_user',
|
||||
'collections.delete',
|
||||
];
|
||||
|
||||
export default Event;
|
||||
|
||||
@@ -172,22 +172,24 @@ User.afterCreate(async user => {
|
||||
// By default when a user signs up we subscribe them to email notifications
|
||||
// when documents they created are edited by other team members and onboarding
|
||||
User.afterCreate(async (user, options) => {
|
||||
await NotificationSetting.findOrCreate({
|
||||
where: {
|
||||
userId: user.id,
|
||||
teamId: user.teamId,
|
||||
event: 'documents.update',
|
||||
},
|
||||
transaction: options.transaction,
|
||||
});
|
||||
await NotificationSetting.findOrCreate({
|
||||
where: {
|
||||
userId: user.id,
|
||||
teamId: user.teamId,
|
||||
event: 'emails.onboarding',
|
||||
},
|
||||
transaction: options.transaction,
|
||||
});
|
||||
await Promise.all([
|
||||
NotificationSetting.findOrCreate({
|
||||
where: {
|
||||
userId: user.id,
|
||||
teamId: user.teamId,
|
||||
event: 'documents.update',
|
||||
},
|
||||
transaction: options.transaction,
|
||||
}),
|
||||
NotificationSetting.findOrCreate({
|
||||
where: {
|
||||
userId: user.id,
|
||||
teamId: user.teamId,
|
||||
event: 'emails.onboarding',
|
||||
},
|
||||
transaction: options.transaction,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
export default User;
|
||||
|
||||
Reference in New Issue
Block a user