diff --git a/server/routes/api/accessRequests/accessRequests.test.ts b/server/routes/api/accessRequests/accessRequests.test.ts index 1173295911..2fed31a0ff 100644 --- a/server/routes/api/accessRequests/accessRequests.test.ts +++ b/server/routes/api/accessRequests/accessRequests.test.ts @@ -1,4 +1,4 @@ -import { DocumentPermission } from "@shared/types"; +import { CollectionPermission, DocumentPermission } from "@shared/types"; import { AccessRequest, UserMembership } from "@server/models"; import { AccessRequestStatus } from "@server/models/AccessRequest"; import { @@ -313,6 +313,54 @@ describe("#accessRequests.approve", () => { expect(membership?.permission).toEqual(DocumentPermission.ReadWrite); }); + it("should allow a document manager who is not a workspace admin to approve", async () => { + const team = await buildTeam(); + const requester = await buildUser({ teamId: team.id }); + const manager = await buildUser({ teamId: team.id }); + const collection = await buildCollection({ + teamId: team.id, + userId: manager.id, + permission: null, + }); + const document = await buildDocument({ + teamId: team.id, + createdById: manager.id, + collectionId: collection.id, + }); + + await UserMembership.create({ + userId: manager.id, + collectionId: collection.id, + createdById: manager.id, + permission: CollectionPermission.Admin, + }); + + const accessRequest = await AccessRequest.create({ + documentId: document.id, + userId: requester.id, + teamId: team.id, + status: AccessRequestStatus.Pending, + }); + + const res = await server.post("/api/accessRequests.approve", manager, { + body: { + id: accessRequest.id, + permission: DocumentPermission.Read, + }, + }); + + expect(res.status).toEqual(200); + + const membership = await UserMembership.findOne({ + where: { + userId: requester.id, + documentId: document.id, + }, + }); + expect(membership).toBeTruthy(); + expect(membership?.permission).toEqual(DocumentPermission.Read); + }); + it("should not allow non-managers to approve requests", async () => { const team = await buildTeam(); const requester = await buildUser({ teamId: team.id }); @@ -461,6 +509,46 @@ describe("#accessRequests.dismiss", () => { expect(membership).toBeNull(); }); + it("should allow a document manager who is not a workspace admin to dismiss", async () => { + const team = await buildTeam(); + const requester = await buildUser({ teamId: team.id }); + const manager = await buildUser({ teamId: team.id }); + const collection = await buildCollection({ + teamId: team.id, + userId: manager.id, + permission: null, + }); + const document = await buildDocument({ + teamId: team.id, + createdById: manager.id, + collectionId: collection.id, + }); + + await UserMembership.create({ + userId: manager.id, + collectionId: collection.id, + createdById: manager.id, + permission: CollectionPermission.Admin, + }); + + const accessRequest = await AccessRequest.create({ + documentId: document.id, + userId: requester.id, + teamId: team.id, + }); + + const res = await server.post("/api/accessRequests.dismiss", manager, { + body: { + id: accessRequest.id, + }, + }); + const body = await res.json(); + + expect(res.status).toEqual(200); + expect(body.data.status).toEqual(AccessRequestStatus.Dismissed); + expect(body.data.responderId).toEqual(manager.id); + }); + it("should not allow non-managers to dismiss requests", async () => { const team = await buildTeam(); const requester = await buildUser({ teamId: team.id }); diff --git a/server/routes/api/accessRequests/accessRequests.ts b/server/routes/api/accessRequests/accessRequests.ts index ffc8af0cac..e6dd152d8a 100644 --- a/server/routes/api/accessRequests/accessRequests.ts +++ b/server/routes/api/accessRequests/accessRequests.ts @@ -101,8 +101,6 @@ router.post( transaction, lock: { level: transaction.LOCK.UPDATE, of: AccessRequest }, }); - authorize(user, "update", accessRequest); - authorize(user, "read", accessRequest.user); if (accessRequest.status !== AccessRequestStatus.Pending) { throw InvalidRequestError("Access request has already been responded to"); @@ -111,8 +109,10 @@ router.post( const document = await Document.findByPk(accessRequest.documentId, { userId: user.id, transaction, + rejectOnEmpty: true, }); - authorize(user, "share", document); + authorize(user, "manageUsers", document); + authorize(user, "read", accessRequest.user); const membership = await UserMembership.findOne({ where: { @@ -157,14 +157,14 @@ router.post( transaction, lock: { level: transaction.LOCK.UPDATE, of: AccessRequest }, }); - authorize(user, "update", accessRequest); - authorize(user, "read", accessRequest.user); const document = await Document.findByPk(accessRequest.documentId, { userId: user.id, transaction, + rejectOnEmpty: true, }); - authorize(user, "share", document); + authorize(user, "manageUsers", document); + authorize(user, "read", accessRequest.user); if (accessRequest.status === AccessRequestStatus.Pending) { await accessRequest.dismiss(ctx);