mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
Fix: Allow workspace Viewers with collection Admin membership to edit templates
Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>
This commit is contained in:
@@ -57,7 +57,7 @@ describe("policies/team", () => {
|
||||
const permissions = new Map<UserRole, boolean>([
|
||||
[UserRole.Admin, true],
|
||||
[UserRole.Member, true],
|
||||
[UserRole.Viewer, false],
|
||||
[UserRole.Viewer, true],
|
||||
[UserRole.Guest, false],
|
||||
]);
|
||||
for (const [role, permission] of permissions.entries()) {
|
||||
|
||||
@@ -15,7 +15,6 @@ allow(User, "readTemplate", Team, (actor, team) =>
|
||||
and(
|
||||
//
|
||||
!actor.isGuest,
|
||||
!actor.isViewer,
|
||||
isTeamModel(actor, team)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import {
|
||||
buildAdmin,
|
||||
buildUser,
|
||||
buildViewer,
|
||||
buildTemplate,
|
||||
buildCollection,
|
||||
} from "@server/test/factories";
|
||||
import { UserMembership } from "@server/models";
|
||||
import { CollectionPermission } from "@shared/types";
|
||||
import { getTestServer } from "@server/test/support";
|
||||
|
||||
const server = getTestServer();
|
||||
@@ -159,6 +162,62 @@ describe("#templates.update", () => {
|
||||
expect(body.data.data).toEqual(data);
|
||||
});
|
||||
|
||||
it("should allow workspace viewer with collection admin membership to update template", async () => {
|
||||
const viewer = await buildViewer();
|
||||
const collection = await buildCollection({
|
||||
teamId: viewer.teamId,
|
||||
permission: null,
|
||||
});
|
||||
|
||||
await UserMembership.create({
|
||||
createdById: viewer.id,
|
||||
collectionId: collection.id,
|
||||
userId: viewer.id,
|
||||
permission: CollectionPermission.Admin,
|
||||
});
|
||||
|
||||
const template = await buildTemplate({
|
||||
teamId: viewer.teamId,
|
||||
collectionId: collection.id,
|
||||
});
|
||||
|
||||
const res = await server.post("/api/templates.update", {
|
||||
body: {
|
||||
token: viewer.getJwtToken(),
|
||||
id: template.id,
|
||||
title: "Updated by collection manager",
|
||||
},
|
||||
});
|
||||
|
||||
const body = await res.json();
|
||||
expect(res.status).toEqual(200);
|
||||
expect(body.data.title).toEqual("Updated by collection manager");
|
||||
expect(body.policies[0].abilities.update).toEqual(true);
|
||||
});
|
||||
|
||||
it("should not allow workspace viewer without collection admin to update template", async () => {
|
||||
const viewer = await buildViewer();
|
||||
const collection = await buildCollection({
|
||||
teamId: viewer.teamId,
|
||||
permission: CollectionPermission.ReadWrite,
|
||||
});
|
||||
|
||||
const template = await buildTemplate({
|
||||
teamId: viewer.teamId,
|
||||
collectionId: collection.id,
|
||||
});
|
||||
|
||||
const res = await server.post("/api/templates.update", {
|
||||
body: {
|
||||
token: viewer.getJwtToken(),
|
||||
id: template.id,
|
||||
title: "Should fail",
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.status).toEqual(403);
|
||||
});
|
||||
|
||||
it("should allow admin to move template to another accessible collection", async () => {
|
||||
const admin = await buildAdmin();
|
||||
const template = await buildTemplate({
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
import { UserMembership } from "@server/models";
|
||||
import {
|
||||
buildViewer,
|
||||
buildCollection,
|
||||
} from "@server/test/factories";
|
||||
import { CollectionPermission } from "@shared/types";
|
||||
import { getTestServer } from "@server/test/support";
|
||||
|
||||
const server = getTestServer();
|
||||
|
||||
describe("viewer with collection admin can edit templates", () => {
|
||||
it("should return update:true policy after viewer creates a template in their managed collection", async () => {
|
||||
// Create a workspace viewer
|
||||
const viewer = await buildViewer();
|
||||
|
||||
// Create a collection with permission: null (private/restricted)
|
||||
const collection = await buildCollection({
|
||||
teamId: viewer.teamId,
|
||||
permission: null,
|
||||
});
|
||||
|
||||
// Give the viewer Admin (Manager) collection membership
|
||||
await UserMembership.create({
|
||||
createdById: viewer.id,
|
||||
collectionId: collection.id,
|
||||
userId: viewer.id,
|
||||
permission: CollectionPermission.Admin,
|
||||
});
|
||||
|
||||
// Create a template via the API (as the viewer)
|
||||
const createRes = await server.post("/api/templates.create", {
|
||||
body: {
|
||||
token: viewer.getJwtToken(),
|
||||
collectionId: collection.id,
|
||||
title: "My Template",
|
||||
},
|
||||
});
|
||||
|
||||
const createBody = await createRes.json();
|
||||
console.log("Create Status:", createRes.status);
|
||||
console.log("Create Policies:", JSON.stringify(createBody.policies, null, 2));
|
||||
|
||||
expect(createRes.status).toEqual(200);
|
||||
|
||||
const templateId = createBody.data.id;
|
||||
const policy = createBody.policies?.find((p: {id: string}) => p.id === templateId);
|
||||
console.log("Template policy after create:", JSON.stringify(policy, null, 2));
|
||||
|
||||
// The template should be editable by the creator (viewer + collection manager)
|
||||
expect(policy?.abilities?.update).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should allow viewer to create a template via templates.create if they have collection admin", async () => {
|
||||
const viewer = await buildViewer();
|
||||
|
||||
const collection = await buildCollection({
|
||||
teamId: viewer.teamId,
|
||||
permission: null,
|
||||
});
|
||||
|
||||
await UserMembership.create({
|
||||
createdById: viewer.id,
|
||||
collectionId: collection.id,
|
||||
userId: viewer.id,
|
||||
permission: CollectionPermission.Admin,
|
||||
});
|
||||
|
||||
const createRes = await server.post("/api/templates.create", {
|
||||
body: {
|
||||
token: viewer.getJwtToken(),
|
||||
collectionId: collection.id,
|
||||
title: "Viewer Template",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Status:", createRes.status);
|
||||
expect(createRes.status).toEqual(200);
|
||||
});
|
||||
|
||||
it("should NOT allow viewer to create a template without collection admin", async () => {
|
||||
const viewer = await buildViewer();
|
||||
|
||||
const collection = await buildCollection({
|
||||
teamId: viewer.teamId,
|
||||
permission: CollectionPermission.ReadWrite, // public collection
|
||||
});
|
||||
|
||||
const createRes = await server.post("/api/templates.create", {
|
||||
body: {
|
||||
token: viewer.getJwtToken(),
|
||||
collectionId: collection.id,
|
||||
title: "Viewer Template",
|
||||
},
|
||||
});
|
||||
|
||||
console.log("Status:", createRes.status);
|
||||
expect(createRes.status).toEqual(403);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user