feat: customisable workspace role permissions (#345)
* feat: setup schema for workspace roles * chore: regen migration * feat: add publicId to workspace roles * feat: setup default permissions * feat: add repo funcs * feat: setup basic router interactions * feat: add card permissions * feat: assert permissions for lists * feat: assert board permissions * feat: assert permission for remaining routes * feat: add permissions page to settings * feat: enable updating member roles * feat: order members by role and createdAt * feat: allow editing individual permissions * feat: reset role defaults * feat: clear all permission overrides * feat: allow users to delete entities they have created * feat: set roleId when inviting new members * feat: disable UI elements if user does not have permissions * feat: allow admins to assign the admin role to other users * feat: allow delete:list as default * refactor: centre permissions modal * chore: translations
This commit is contained in:
@@ -10,7 +10,7 @@ import * as workspaceRepo from "@kan/db/repository/workspace.repo";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure, publicProcedure } from "../trpc";
|
||||
import { mergeActivities } from "../utils/activities";
|
||||
import { assertUserInWorkspace } from "../utils/auth";
|
||||
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
|
||||
import { generateDownloadUrl } from "../utils/s3";
|
||||
|
||||
export const cardRouter = createTRPCRouter({
|
||||
@@ -57,13 +57,7 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, list.workspaceId);
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
await assertPermission(ctx.db, userId, list.workspaceId, "card:create");
|
||||
|
||||
const newCard = await cardRepo.create(ctx.db, {
|
||||
title: input.title,
|
||||
@@ -199,7 +193,7 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertPermission(ctx.db, userId, card.workspaceId, "comment:create");
|
||||
|
||||
const newComment = await cardCommentRepo.create(ctx.db, {
|
||||
comment: input.comment,
|
||||
@@ -262,8 +256,6 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
|
||||
const existingComment = await cardCommentRepo.getByPublicId(
|
||||
ctx.db,
|
||||
input.commentPublicId,
|
||||
@@ -275,11 +267,13 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
if (existingComment.createdBy !== userId)
|
||||
throw new TRPCError({
|
||||
message: `You do not have permission to update this comment`,
|
||||
code: "FORBIDDEN",
|
||||
});
|
||||
await assertCanEdit(
|
||||
ctx.db,
|
||||
userId,
|
||||
card.workspaceId,
|
||||
"comment:edit",
|
||||
existingComment.createdBy,
|
||||
);
|
||||
|
||||
const updatedComment = await cardCommentRepo.update(ctx.db, {
|
||||
id: existingComment.id,
|
||||
@@ -340,8 +334,6 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
|
||||
const existingComment = await cardCommentRepo.getByPublicId(
|
||||
ctx.db,
|
||||
input.commentPublicId,
|
||||
@@ -353,6 +345,14 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertCanDelete(
|
||||
ctx.db,
|
||||
userId,
|
||||
card.workspaceId,
|
||||
"comment:delete",
|
||||
existingComment.createdBy,
|
||||
);
|
||||
|
||||
const deletedComment = await cardCommentRepo.softDelete(ctx.db, {
|
||||
commentId: existingComment.id,
|
||||
deletedAt: new Date(),
|
||||
@@ -412,7 +412,7 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertPermission(ctx.db, userId, card.workspaceId, "card:edit");
|
||||
|
||||
const label = await labelRepo.getByPublicId(ctx.db, input.labelPublicId);
|
||||
|
||||
@@ -504,7 +504,7 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertPermission(ctx.db, userId, card.workspaceId, "card:edit");
|
||||
|
||||
const member = await workspaceRepo.getMemberByPublicId(
|
||||
ctx.db,
|
||||
@@ -616,7 +616,7 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertPermission(ctx.db, userId, card.workspaceId, "card:view");
|
||||
}
|
||||
|
||||
const result = await cardRepo.getWithListAndMembersByPublicId(
|
||||
@@ -725,7 +725,7 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertPermission(ctx.db, userId, card.workspaceId, "card:view");
|
||||
}
|
||||
|
||||
const cursor = input.cursor ? new Date(input.cursor) : undefined;
|
||||
@@ -788,7 +788,13 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertCanEdit(
|
||||
ctx.db,
|
||||
userId,
|
||||
card.workspaceId,
|
||||
"card:edit",
|
||||
card.createdBy,
|
||||
);
|
||||
|
||||
const existingCard = await cardRepo.getByPublicId(
|
||||
ctx.db,
|
||||
@@ -958,7 +964,13 @@ export const cardRouter = createTRPCRouter({
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
await assertCanDelete(
|
||||
ctx.db,
|
||||
userId,
|
||||
card.workspaceId,
|
||||
"card:delete",
|
||||
card.createdBy,
|
||||
);
|
||||
|
||||
const deletedAt = new Date();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user