feat: Add parameters for filtering events (#1863)

* feat: Add parameters for filtering events

* test
This commit is contained in:
Tom Moor 2021-02-04 20:20:56 -08:00 committed by GitHub
parent 37fa13d841
commit e23474fa1c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 152 additions and 14 deletions

View File

@ -2,7 +2,7 @@
import Router from "koa-router";
import Sequelize from "sequelize";
import auth from "../middlewares/authentication";
import { Event, Team, User } from "../models";
import { Event, Team, User, Collection } from "../models";
import policy from "../policies";
import { presentEvent } from "../presenters";
import pagination from "./middlewares/pagination";
@ -12,30 +12,62 @@ const { authorize } = policy;
const router = new Router();
router.post("events.list", auth(), pagination(), async (ctx) => {
let { sort = "createdAt", direction, auditLog = false } = ctx.body;
if (direction !== "ASC") direction = "DESC";
const user = ctx.state.user;
const collectionIds = await user.collectionIds({ paranoid: false });
let {
sort = "createdAt",
actorId,
collectionId,
direction,
name,
auditLog = false,
} = ctx.body;
if (direction !== "ASC") direction = "DESC";
let where = {
name: Event.ACTIVITY_EVENTS,
teamId: user.teamId,
[Op.or]: [
{ collectionId: collectionIds },
{
collectionId: {
[Op.eq]: null,
},
},
],
};
if (actorId) {
ctx.assertUuid(actorId, "actorId must be a UUID");
where = {
...where,
actorId,
};
}
if (collectionId) {
ctx.assertUuid(collectionId, "collection must be a UUID");
where = { ...where, collectionId };
const collection = await Collection.scope({
method: ["withMembership", user.id],
}).findByPk(collectionId);
authorize(user, "read", collection);
} else {
const collectionIds = await user.collectionIds({ paranoid: false });
where = {
...where,
[Op.or]: [
{ collectionId: collectionIds },
{
collectionId: {
[Op.eq]: null,
},
},
],
};
}
if (auditLog) {
authorize(user, "auditLog", Team);
where.name = Event.AUDIT_EVENTS;
}
if (name && where.name.includes(name)) {
where.name = name;
}
const events = await Event.findAll({
where,
order: [[sort, direction]],

View File

@ -13,7 +13,7 @@ describe("#events.list", () => {
it("should only return activity events", async () => {
const { user, admin, document, collection } = await seed();
// private event
// audit event
await buildEvent({
name: "users.promote",
teamId: user.teamId,
@ -29,6 +29,7 @@ describe("#events.list", () => {
teamId: user.teamId,
actorId: admin.id,
});
const res = await server.post("/api/events.list", {
body: { token: user.getJwtToken() },
});
@ -39,6 +40,100 @@ describe("#events.list", () => {
expect(body.data[0].id).toEqual(event.id);
});
it("should return audit events", async () => {
const { user, admin, document, collection } = await seed();
// audit event
const auditEvent = await buildEvent({
name: "users.promote",
teamId: user.teamId,
actorId: admin.id,
userId: user.id,
});
// event viewable in activity stream
const event = await buildEvent({
name: "documents.publish",
collectionId: collection.id,
documentId: document.id,
teamId: user.teamId,
actorId: admin.id,
});
const res = await server.post("/api/events.list", {
body: { token: admin.getJwtToken(), auditLog: true },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(2);
expect(body.data[0].id).toEqual(event.id);
expect(body.data[1].id).toEqual(auditEvent.id);
});
it("should allow filtering by actorId", async () => {
const { user, admin, document, collection } = await seed();
// audit event
const auditEvent = await buildEvent({
name: "users.promote",
teamId: user.teamId,
actorId: admin.id,
userId: user.id,
});
// event viewable in activity stream
await buildEvent({
name: "documents.publish",
collectionId: collection.id,
documentId: document.id,
teamId: user.teamId,
actorId: user.id,
});
const res = await server.post("/api/events.list", {
body: { token: admin.getJwtToken(), auditLog: true, actorId: admin.id },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(1);
expect(body.data[0].id).toEqual(auditEvent.id);
});
it("should allow filtering by event name", async () => {
const { user, admin, document, collection } = await seed();
// audit event
await buildEvent({
name: "users.promote",
teamId: user.teamId,
actorId: admin.id,
userId: user.id,
});
// event viewable in activity stream
const event = await buildEvent({
name: "documents.publish",
collectionId: collection.id,
documentId: document.id,
teamId: user.teamId,
actorId: user.id,
});
const res = await server.post("/api/events.list", {
body: {
token: user.getJwtToken(),
name: "documents.publish",
},
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.length).toEqual(1);
expect(body.data[0].id).toEqual(event.id);
});
it("should return events with deleted actors", async () => {
const { user, admin, document, collection } = await seed();
@ -64,6 +159,15 @@ describe("#events.list", () => {
expect(body.data[0].id).toEqual(event.id);
});
it("should require authorization for audit events", async () => {
const { user } = await seed();
const res = await server.post("/api/events.list", {
body: { token: user.getJwtToken(), auditLog: true },
});
expect(res.status).toEqual(403);
});
it("should require authentication", async () => {
const res = await server.post("/api/events.list");
const body = await res.json();

View File

@ -62,6 +62,7 @@ Event.ACTIVITY_EVENTS = [
"documents.unarchive",
"documents.pin",
"documents.unpin",
"documents.move",
"documents.delete",
"documents.restore",
"users.create",
@ -86,6 +87,7 @@ Event.AUDIT_EVENTS = [
"documents.unpin",
"documents.move",
"documents.delete",
"documents.restore",
"groups.create",
"groups.update",
"groups.delete",