Skip to content

Commit

Permalink
feat: log activity for team create and edit
Browse files Browse the repository at this point in the history
  • Loading branch information
maninder-singh committed Mar 3, 2021
1 parent 5f7ffb0 commit 4978f75
Show file tree
Hide file tree
Showing 17 changed files with 311 additions and 6 deletions.
15 changes: 15 additions & 0 deletions app/activity/handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Hapi from '@hapi/hapi';
import * as Resource from './resource';

// groups/{groupId}/activities

// activities?{}

export const get = {
description: 'get all activities or team activities',
tags: ['api'],
handler: async (request: Hapi.Request) => {
const { team } = request.query;
return Resource.get(team);
}
};
16 changes: 16 additions & 0 deletions app/activity/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Hapi from '@hapi/hapi';
import * as Handler from './handler';

export const plugin = {
name: 'activity',
dependencies: 'postgres',
register(server: Hapi.Server) {
server.route([
{
method: 'GET',
path: '/api/activities',
options: Handler.get
}
]);
}
};
24 changes: 24 additions & 0 deletions app/activity/resource.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Activity } from '../../model/activity';

export const get = async (team = '') => {
let criteria: any = {
order: {
createdAt: 'DESC'
}
};

if (team.length !== 0) {
// fetch activities based on team
criteria = Object.assign(criteria, {
where: {
team
}
});
}

return Activity.find(criteria);
};

export const create = async (payload: any) => {
return await Activity.save({ ...payload });
};
16 changes: 16 additions & 0 deletions app/activity/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Joi from 'joi';
import Config from '../../config/config';

const validationOptions = Config.get('/validationOptions');

export const ActivityPayload = Joi.object()
.label('ActivityPayload')
.keys({
id: Joi.string().required(),
title: Joi.string().required(),
team: Joi.string().required(),
details: Joi.array().items(Joi.object().optional()),
createdAt: Joi.date().iso().required(),
createdBy: Joi.string().required()
})
.options(validationOptions);
3 changes: 3 additions & 0 deletions config/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ internals.manifest = {
{
plugin: '../app/role/index'
},
{
plugin: '../app/activity/index'
},
{
plugin: '../plugin/proxy'
},
Expand Down
19 changes: 19 additions & 0 deletions factory/activity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Faker from 'faker';
import { define } from 'typeorm-seeding';
import { Activity } from '../model/activity';
// import { User } from '../model/user';

define(Activity, (faker: typeof Faker) => {
const activity = new Activity();
activity.id = faker.random.uuid();
activity.title = faker.random.words(3).toString();
activity.model = 'User';
activity.document = {};
activity.documentId = faker.random.uuid();
activity.diffs = [{}];
// const user = new User();
// user.id = faker.random.uuid();
// user.displayname = faker.random.word();
// activity.createdBy = user;
return activity;
});
7 changes: 6 additions & 1 deletion lib/casbin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import {
JsonFilteredEnforcer
} from './JsonFilteredEnforcer';

const Config = require('../../config/config');

const baseDir = Config.get('/typeormDir').dir;

const { newWatcher } = CasbinPgWatcher;

class CasbinSingleton {
Expand Down Expand Up @@ -51,7 +55,8 @@ class CasbinSingleton {
if (!this.policyAdapter) {
this.policyAdapter = await TypeORMAdapter.newAdapter({
type: 'postgres',
url: dbConnectionUrl
url: dbConnectionUrl,
subscribers: [`${baseDir}/subscriber/*{.ts,.js}`]
});
}

Expand Down
58 changes: 58 additions & 0 deletions model/activity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
Entity,
Column,
CreateDateColumn,
BaseEntity,
PrimaryGeneratedColumn
} from 'typeorm';

import Constants from '../utils/constant';

// eslint-disable-next-line import/no-cycle
// import { User } from './user';

@Entity(Constants.MODEL.Activity)
export class Activity extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;

@Column({
type: 'varchar',
nullable: false
})
title: string;

@Column({
type: 'varchar',
nullable: false
})
model: string;

@Column({
type: 'varchar',
nullable: false
})
documentId: string;

@Column({
type: 'jsonb',
nullable: false
})
document: Record<string, string>;

@Column({
type: 'jsonb',
nullable: true
})
diffs: Record<string, string>[];

@CreateDateColumn()
createdAt: string;

// @Column({
// type: 'varchar',
// nullable: false
// })
// @ManyToOne(() => User, (user) => user.activities)
// createdBy: User;
}
3 changes: 2 additions & 1 deletion model/group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
BaseEntity,
PrimaryGeneratedColumn
} from 'typeorm';
import Constants from '../utils/constant';

@Entity('groups')
@Entity(Constants.MODEL.Group)
export class Group extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
Expand Down
3 changes: 2 additions & 1 deletion model/role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {
BaseEntity,
PrimaryGeneratedColumn
} from 'typeorm';
import Constants from '../utils/constant';

@Entity('roles')
@Entity(Constants.MODEL.Role)
export class Role extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
Expand Down
9 changes: 8 additions & 1 deletion model/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ import {
PrimaryGeneratedColumn
} from 'typeorm';

@Entity('users')
// eslint-disable-next-line import/no-cycle
// import { Activity } from './activity';
import Constants from '../utils/constant';

@Entity(Constants.MODEL.User)
export class User extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
Expand All @@ -30,6 +34,9 @@ export class User extends BaseEntity {
})
metadata: Record<string, any>;

// @OneToMany(() => Activity, (activity) => activity.createdBy)
// activities: Activity[];

@CreateDateColumn()
createdAt: string;

Expand Down
6 changes: 4 additions & 2 deletions ormconfig.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { SnakeNamingStrategy } = require('typeorm-naming-strategies');
const Config = require('./config/config');
const {SnakeNamingStrategy} = require('typeorm-naming-strategies');

const baseDir = Config.get('/typeormDir').dir;

module.exports = {
Expand All @@ -10,8 +11,9 @@ module.exports = {
entities: [`${baseDir}/model/*{.ts,.js}`],
migrations: [`${baseDir}/migration/*{.ts,.js}`],
factories: [`${baseDir}/factory/*{.ts,.js}`],
subscribers: [`${baseDir}/subscriber/*{.ts,.js}`],
cli: {
migrationsDir: 'migration'
},
namingStrategy:new SnakeNamingStrategy()
namingStrategy: new SnakeNamingStrategy()
};
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"casbin": "^5.2.2",
"casbin-pg-watcher": "^0.1.1",
"confidence": "^5.0.0",
"deep-diff": "^1.0.2",
"faker": "^5.1.0",
"hapi-swagger": "^14.0.0",
"joi": "^17.3.0",
Expand Down
112 changes: 112 additions & 0 deletions subscriber/model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import {
EntitySubscriberInterface,
EventSubscriber,
InsertEvent,
UpdateEvent
} from 'typeorm';
import { delta } from '../utils/deep-diff';
import Constants from '../utils/constant';
import { create } from '../app/activity/resource';

const excludeFields = ['id', 'createdAt', 'updatedAt'];
const actions = {
CREATE: 'create',
EDIT: 'edit'
};

const getTitle = (event: any, type: string) => {
let title = '';
switch (type) {
case actions.CREATE:
if (event.metadata.tableName === Constants.MODEL.Group) {
title = `Created ${event.entity?.displayname} Team `;
} else if (event.metadata.tableName === Constants.MODEL.CasbinRule) {
title = `Created ${event.entity?.ptype} Casbin Rule `;
}
break;
case actions.EDIT:
if (event.metadata.tableName === Constants.MODEL.Group) {
title = `Edited ${event.entity?.displayname}`;
} else if (event.metadata.tableName === Constants.MODEL.CasbinRule) {
title = `Edited ${event.entity?.ptype} Casbin Rule `;
}
break;
default:
title = '';
}

return title;
};

const getDiff = (event: any, type: string) => {
switch (type) {
case actions.CREATE:
return delta({}, event.entity, {
exclude: excludeFields
});
case actions.EDIT:
return delta(event.databaseEntity, event.entity, {
exclude: excludeFields
});
default:
return [];
}
};

const storeActivityPayload = async (event: any, type: string) => {
// console.log(
// 'storeActivityPayload event -> ',
// event.entity,
// event.databaseEntity,
// event.metadata.tableName
// );
if (
event.metadata.tableName === Constants.MODEL.Activity ||
event.metadata.tableName === Constants.MODEL.Role ||
event.metadata.tableName === Constants.MODEL.User
) {
return;
}
const title = getTitle(event, type);
await create({
document: event.entity,
title,
documentId: event.entity.id,
model: event.metadata.tableName,
diffs: getDiff(event, type)
});
};

@EventSubscriber()
export class ModelSubscriber implements EntitySubscriberInterface {
afterInsert = async (event: InsertEvent<any>) => {
await storeActivityPayload(event, actions.CREATE);
};

afterUpdate = async (event: UpdateEvent<any>) => {
await storeActivityPayload(event, actions.EDIT);
};

/**
* Called before entity removal.
*/
// beforeRemove = async (event: RemoveEvent<any>) => {
// console.log(
// `BEFORE ENTITY WITH metadata.tableName ${JSON.stringify(
// event.metadata.tableName
// )} REMOVED: `,
// event.entity
// );
// };

/**
* Called after entity removal.
*/
// afterRemove = async (event: RemoveEvent<any>) => {
// Object.keys(event.queryRunner.data).forEach((key) => {
// console.log(`key => ${key} and value => ${event.queryRunner.data[key]}`);
// });
//
// console.log(`AFTER ENTITY WITH queryRunner REMOVED: `, event.entity);
// };
}
9 changes: 9 additions & 0 deletions utils/constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default {
MODEL: {
Activity: 'activities',
Group: 'groups',
Role: 'roles',
User: 'users',
CasbinRule: 'casbin_rule'
}
};
11 changes: 11 additions & 0 deletions utils/deep-diff.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { diff } = require('deep-diff');

export const delta = (
previous = {},
current = {},
options?: { exclude: string[] }
) => {
return diff(previous, current).filter((i: any) =>
(options?.exclude || []).every((x: any) => i.path.indexOf(x) === -1)
);
};
Loading

0 comments on commit 4978f75

Please sign in to comment.