feat: Add parameters for filtering events (#1863)
* feat: Add parameters for filtering events * test
This commit is contained in:
@ -2,7 +2,7 @@
|
|||||||
import Router from "koa-router";
|
import Router from "koa-router";
|
||||||
import Sequelize from "sequelize";
|
import Sequelize from "sequelize";
|
||||||
import auth from "../middlewares/authentication";
|
import auth from "../middlewares/authentication";
|
||||||
import { Event, Team, User } from "../models";
|
import { Event, Team, User, Collection } from "../models";
|
||||||
import policy from "../policies";
|
import policy from "../policies";
|
||||||
import { presentEvent } from "../presenters";
|
import { presentEvent } from "../presenters";
|
||||||
import pagination from "./middlewares/pagination";
|
import pagination from "./middlewares/pagination";
|
||||||
@ -12,30 +12,62 @@ const { authorize } = policy;
|
|||||||
const router = new Router();
|
const router = new Router();
|
||||||
|
|
||||||
router.post("events.list", auth(), pagination(), async (ctx) => {
|
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 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 = {
|
let where = {
|
||||||
name: Event.ACTIVITY_EVENTS,
|
name: Event.ACTIVITY_EVENTS,
|
||||||
teamId: user.teamId,
|
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) {
|
if (auditLog) {
|
||||||
authorize(user, "auditLog", Team);
|
authorize(user, "auditLog", Team);
|
||||||
where.name = Event.AUDIT_EVENTS;
|
where.name = Event.AUDIT_EVENTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (name && where.name.includes(name)) {
|
||||||
|
where.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
const events = await Event.findAll({
|
const events = await Event.findAll({
|
||||||
where,
|
where,
|
||||||
order: [[sort, direction]],
|
order: [[sort, direction]],
|
||||||
|
@ -13,7 +13,7 @@ describe("#events.list", () => {
|
|||||||
it("should only return activity events", async () => {
|
it("should only return activity events", async () => {
|
||||||
const { user, admin, document, collection } = await seed();
|
const { user, admin, document, collection } = await seed();
|
||||||
|
|
||||||
// private event
|
// audit event
|
||||||
await buildEvent({
|
await buildEvent({
|
||||||
name: "users.promote",
|
name: "users.promote",
|
||||||
teamId: user.teamId,
|
teamId: user.teamId,
|
||||||
@ -29,6 +29,7 @@ describe("#events.list", () => {
|
|||||||
teamId: user.teamId,
|
teamId: user.teamId,
|
||||||
actorId: admin.id,
|
actorId: admin.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = await server.post("/api/events.list", {
|
const res = await server.post("/api/events.list", {
|
||||||
body: { token: user.getJwtToken() },
|
body: { token: user.getJwtToken() },
|
||||||
});
|
});
|
||||||
@ -39,6 +40,100 @@ describe("#events.list", () => {
|
|||||||
expect(body.data[0].id).toEqual(event.id);
|
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 () => {
|
it("should return events with deleted actors", async () => {
|
||||||
const { user, admin, document, collection } = await seed();
|
const { user, admin, document, collection } = await seed();
|
||||||
|
|
||||||
@ -64,6 +159,15 @@ describe("#events.list", () => {
|
|||||||
expect(body.data[0].id).toEqual(event.id);
|
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 () => {
|
it("should require authentication", async () => {
|
||||||
const res = await server.post("/api/events.list");
|
const res = await server.post("/api/events.list");
|
||||||
const body = await res.json();
|
const body = await res.json();
|
||||||
|
@ -62,6 +62,7 @@ Event.ACTIVITY_EVENTS = [
|
|||||||
"documents.unarchive",
|
"documents.unarchive",
|
||||||
"documents.pin",
|
"documents.pin",
|
||||||
"documents.unpin",
|
"documents.unpin",
|
||||||
|
"documents.move",
|
||||||
"documents.delete",
|
"documents.delete",
|
||||||
"documents.restore",
|
"documents.restore",
|
||||||
"users.create",
|
"users.create",
|
||||||
@ -86,6 +87,7 @@ Event.AUDIT_EVENTS = [
|
|||||||
"documents.unpin",
|
"documents.unpin",
|
||||||
"documents.move",
|
"documents.move",
|
||||||
"documents.delete",
|
"documents.delete",
|
||||||
|
"documents.restore",
|
||||||
"groups.create",
|
"groups.create",
|
||||||
"groups.update",
|
"groups.update",
|
||||||
"groups.delete",
|
"groups.delete",
|
||||||
|
Reference in New Issue
Block a user