feat: Improved viewers popover (#2106)

* refactoring popover

* feat: DocumentViews popover

* i18n

* fix: tab focus warnings

* test: Add tests around users.info changes

* snapshots
This commit is contained in:
Tom Moor
2021-05-05 19:35:23 -07:00
committed by GitHub
parent e984a3dcdb
commit 896ee5c20d
18 changed files with 388 additions and 191 deletions

View File

@ -23,6 +23,7 @@ Object {
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"suspend": true,
"update": false,
},
@ -74,39 +75,7 @@ Object {
"demote": true,
"promote": true,
"read": true,
"suspend": true,
"update": false,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.demote should demote an admin to viewer 1`] = `
Object {
"data": Object {
"avatarUrl": "https://tiley.herokuapp.com/avatar/111d68d06e2d317b5a59c2c6c5bad808/U.png",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": false,
"isViewer": true,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
},
"ok": true,
"policies": Array [
Object {
"abilities": Object {
"activate": true,
"delete": true,
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"suspend": true,
"update": false,
},
@ -140,6 +109,41 @@ Object {
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"suspend": true,
"update": false,
},
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
},
],
"status": 200,
}
`;
exports[`#users.demote should demote an admin to viewer 1`] = `
Object {
"data": Object {
"avatarUrl": "https://tiley.herokuapp.com/avatar/111d68d06e2d317b5a59c2c6c5bad808/U.png",
"createdAt": "2018-01-02T00:00:00.000Z",
"email": "user1@example.com",
"id": "46fde1d4-0050-428f-9f0b-0bf77f4bdf61",
"isAdmin": false,
"isSuspended": false,
"isViewer": true,
"language": "en_US",
"lastActiveAt": null,
"name": "User 1",
},
"ok": true,
"policies": Array [
Object {
"abilities": Object {
"activate": true,
"delete": true,
"demote": true,
"promote": true,
"read": true,
"readDetails": true,
"suspend": true,
"update": false,
},
@ -191,6 +195,7 @@ Object {
"demote": true,
"promote": false,
"read": true,
"readDetails": true,
"suspend": true,
"update": false,
},
@ -251,6 +256,7 @@ Object {
"demote": false,
"promote": false,
"read": true,
"readDetails": true,
"suspend": true,
"update": false,
},

View File

@ -10,7 +10,7 @@ import { presentUser, presentPolicies } from "../presenters";
import { Op } from "../sequelize";
import pagination from "./middlewares/pagination";
const { authorize } = policy;
const { can, authorize } = policy;
const router = new Router();
router.post("users.list", auth(), pagination(), async (ctx) => {
@ -23,10 +23,10 @@ router.post("users.list", auth(), pagination(), async (ctx) => {
if (direction !== "ASC") direction = "DESC";
ctx.assertSort(sort, User);
const user = ctx.state.user;
const actor = ctx.state.user;
let where = {
teamId: user.teamId,
teamId: actor.teamId,
};
if (!includeSuspended) {
@ -56,10 +56,10 @@ router.post("users.list", auth(), pagination(), async (ctx) => {
ctx.body = {
pagination: ctx.state.pagination,
data: users.map((listUser) =>
presentUser(listUser, { includeDetails: user.isAdmin })
data: users.map((user) =>
presentUser(user, { includeDetails: can(actor, "readDetails", user) })
),
policies: presentPolicies(user, users),
policies: presentPolicies(actor, users),
};
});
@ -75,11 +75,17 @@ router.post("users.count", auth(), async (ctx) => {
});
router.post("users.info", auth(), async (ctx) => {
const { user } = ctx.state;
const { id } = ctx.body;
const actor = ctx.state.user;
const user = id ? await User.findByPk(id) : actor;
authorize(actor, "read", user);
const includeDetails = can(actor, "readDetails", user);
ctx.body = {
data: presentUser(user),
policies: presentPolicies(user, [user]),
data: presentUser(user, { includeDetails }),
policies: presentPolicies(actor, [user]),
};
});
@ -128,8 +134,10 @@ router.post("users.promote", auth(), async (ctx) => {
ip: ctx.request.ip,
});
const includeDetails = can(actor, "readDetails", user);
ctx.body = {
data: presentUser(user, { includeDetails: true }),
data: presentUser(user, { includeDetails }),
policies: presentPolicies(actor, [user]),
};
});
@ -159,8 +167,10 @@ router.post("users.demote", auth(), async (ctx) => {
ip: ctx.request.ip,
});
const includeDetails = can(actor, "readDetails", user);
ctx.body = {
data: presentUser(user, { includeDetails: true }),
data: presentUser(user, { includeDetails }),
policies: presentPolicies(actor, [user]),
};
});
@ -179,8 +189,10 @@ router.post("users.suspend", auth(), async (ctx) => {
ip: ctx.request.ip,
});
const includeDetails = can(actor, "readDetails", user);
ctx.body = {
data: presentUser(user, { includeDetails: true }),
data: presentUser(user, { includeDetails }),
policies: presentPolicies(actor, [user]),
};
});
@ -205,8 +217,10 @@ router.post("users.activate", auth(), async (ctx) => {
ip: ctx.request.ip,
});
const includeDetails = can(actor, "readDetails", user);
ctx.body = {
data: presentUser(user, { includeDetails: true }),
data: presentUser(user, { includeDetails }),
policies: presentPolicies(actor, [user]),
};
});

View File

@ -87,7 +87,7 @@ describe("#users.list", () => {
});
describe("#users.info", () => {
it("should return known user", async () => {
it("should return current user with no id", async () => {
const user = await buildUser();
const res = await server.post("/api/users.info", {
body: { token: user.getJwtToken() },
@ -97,6 +97,33 @@ describe("#users.info", () => {
expect(res.status).toEqual(200);
expect(body.data.id).toEqual(user.id);
expect(body.data.name).toEqual(user.name);
expect(body.data.email).toEqual(user.email);
});
it("should return user with permission", async () => {
const user = await buildUser();
const another = await buildUser({ teamId: user.teamId });
const res = await server.post("/api/users.info", {
body: { token: user.getJwtToken(), id: another.id },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.id).toEqual(another.id);
expect(body.data.name).toEqual(another.name);
// no emails of other users
expect(body.data.email).toEqual(undefined);
});
it("should now return user without permission", async () => {
const user = await buildUser();
const another = await buildUser();
const res = await server.post("/api/users.info", {
body: { token: user.getJwtToken(), id: another.id },
});
expect(res.status).toEqual(403);
});
it("should require authentication", async () => {