2026-04-17 13:48:59 -04:00
|
|
|
import { NextRequest, NextResponse } from "next/server";
|
|
|
|
|
import { prisma } from "@/lib/db";
|
Normalize role-based permissions across API and UI
Centralizes role/permission enforcement so each role (owner, admin, editor,
reviewer, viewer) behaves consistently in the API and UI.
- Extend src/lib/permissions.ts with an expanded action map (cards.reprocess,
cards.assign, uploads.create, integrations.manage, etc.) plus helper
predicates (isAdminRole, canEditContent).
- Add requireApiAuthWithPermission(action) to src/lib/api-auth.ts with a
narrowed OrgSession return type and PermissionError -> 403 handling.
- Replace hand-rolled role checks in card, org, integration, form-template,
settings, upload, and location routes with the shared helpers so 403s are
uniform and derived from one permission map.
- Close the editor UI gap: the dashboard upload button, row-level mark
reviewed/reprocess/delete, and card detail edit/reprocess/export/assign
now flow from can(role, action) instead of ad-hoc isAdmin checks.
- Gate /settings/* at the middleware layer for non-admins and hide the
Settings entry in the sidebar and top-bar menu when the role cannot
access it.
- Use isAdminRole() in the team members settings page for consistency.
Made-with: Cursor
2026-04-23 13:17:35 -04:00
|
|
|
import { requireApiAuthWithPermission, handleApiError } from "@/lib/api-auth";
|
2026-04-17 13:48:59 -04:00
|
|
|
|
|
|
|
|
const VALID_ROLES = ["viewer", "reviewer", "editor", "admin"];
|
|
|
|
|
|
|
|
|
|
export async function PATCH(
|
|
|
|
|
req: NextRequest,
|
|
|
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
|
|
|
) {
|
|
|
|
|
try {
|
Normalize role-based permissions across API and UI
Centralizes role/permission enforcement so each role (owner, admin, editor,
reviewer, viewer) behaves consistently in the API and UI.
- Extend src/lib/permissions.ts with an expanded action map (cards.reprocess,
cards.assign, uploads.create, integrations.manage, etc.) plus helper
predicates (isAdminRole, canEditContent).
- Add requireApiAuthWithPermission(action) to src/lib/api-auth.ts with a
narrowed OrgSession return type and PermissionError -> 403 handling.
- Replace hand-rolled role checks in card, org, integration, form-template,
settings, upload, and location routes with the shared helpers so 403s are
uniform and derived from one permission map.
- Close the editor UI gap: the dashboard upload button, row-level mark
reviewed/reprocess/delete, and card detail edit/reprocess/export/assign
now flow from can(role, action) instead of ad-hoc isAdmin checks.
- Gate /settings/* at the middleware layer for non-admins and hide the
Settings entry in the sidebar and top-bar menu when the role cannot
access it.
- Use isAdminRole() in the team members settings page for consistency.
Made-with: Cursor
2026-04-23 13:17:35 -04:00
|
|
|
const session = await requireApiAuthWithPermission("users.invite");
|
2026-04-17 13:48:59 -04:00
|
|
|
const { id } = await params;
|
|
|
|
|
const { role } = await req.json();
|
|
|
|
|
|
|
|
|
|
if (!role || !VALID_ROLES.includes(role)) {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: `Role must be one of: ${VALID_ROLES.join(", ")}` },
|
|
|
|
|
{ status: 400 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const target = await prisma.orgMember.findFirst({
|
|
|
|
|
where: { id, organizationId: session.user.orgId },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!target) {
|
|
|
|
|
return NextResponse.json({ error: "Member not found" }, { status: 404 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target.role === "owner") {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: "Cannot change the owner's role" },
|
|
|
|
|
{ status: 403 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target.userId === session.user.id) {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: "You cannot change your own role" },
|
|
|
|
|
{ status: 403 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const updated = await prisma.orgMember.update({
|
|
|
|
|
where: { id },
|
|
|
|
|
data: { role },
|
|
|
|
|
include: { user: { select: { id: true, email: true, displayName: true } } },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return NextResponse.json({ member: updated });
|
|
|
|
|
} catch (error) {
|
Normalize role-based permissions across API and UI
Centralizes role/permission enforcement so each role (owner, admin, editor,
reviewer, viewer) behaves consistently in the API and UI.
- Extend src/lib/permissions.ts with an expanded action map (cards.reprocess,
cards.assign, uploads.create, integrations.manage, etc.) plus helper
predicates (isAdminRole, canEditContent).
- Add requireApiAuthWithPermission(action) to src/lib/api-auth.ts with a
narrowed OrgSession return type and PermissionError -> 403 handling.
- Replace hand-rolled role checks in card, org, integration, form-template,
settings, upload, and location routes with the shared helpers so 403s are
uniform and derived from one permission map.
- Close the editor UI gap: the dashboard upload button, row-level mark
reviewed/reprocess/delete, and card detail edit/reprocess/export/assign
now flow from can(role, action) instead of ad-hoc isAdmin checks.
- Gate /settings/* at the middleware layer for non-admins and hide the
Settings entry in the sidebar and top-bar menu when the role cannot
access it.
- Use isAdminRole() in the team members settings page for consistency.
Made-with: Cursor
2026-04-23 13:17:35 -04:00
|
|
|
return handleApiError(error);
|
2026-04-17 13:48:59 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export async function DELETE(
|
|
|
|
|
_req: NextRequest,
|
|
|
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
|
|
|
) {
|
|
|
|
|
try {
|
Normalize role-based permissions across API and UI
Centralizes role/permission enforcement so each role (owner, admin, editor,
reviewer, viewer) behaves consistently in the API and UI.
- Extend src/lib/permissions.ts with an expanded action map (cards.reprocess,
cards.assign, uploads.create, integrations.manage, etc.) plus helper
predicates (isAdminRole, canEditContent).
- Add requireApiAuthWithPermission(action) to src/lib/api-auth.ts with a
narrowed OrgSession return type and PermissionError -> 403 handling.
- Replace hand-rolled role checks in card, org, integration, form-template,
settings, upload, and location routes with the shared helpers so 403s are
uniform and derived from one permission map.
- Close the editor UI gap: the dashboard upload button, row-level mark
reviewed/reprocess/delete, and card detail edit/reprocess/export/assign
now flow from can(role, action) instead of ad-hoc isAdmin checks.
- Gate /settings/* at the middleware layer for non-admins and hide the
Settings entry in the sidebar and top-bar menu when the role cannot
access it.
- Use isAdminRole() in the team members settings page for consistency.
Made-with: Cursor
2026-04-23 13:17:35 -04:00
|
|
|
const session = await requireApiAuthWithPermission("users.invite");
|
2026-04-17 13:48:59 -04:00
|
|
|
const { id } = await params;
|
|
|
|
|
|
|
|
|
|
const target = await prisma.orgMember.findFirst({
|
|
|
|
|
where: { id, organizationId: session.user.orgId },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!target) {
|
|
|
|
|
return NextResponse.json({ error: "Member not found" }, { status: 404 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target.role === "owner") {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: "Cannot remove the organization owner" },
|
|
|
|
|
{ status: 403 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (target.userId === session.user.id) {
|
|
|
|
|
return NextResponse.json(
|
|
|
|
|
{ error: "You cannot remove yourself" },
|
|
|
|
|
{ status: 403 }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await prisma.$transaction([
|
|
|
|
|
prisma.orgMember.delete({ where: { id } }),
|
|
|
|
|
prisma.user.updateMany({
|
|
|
|
|
where: { id: target.userId, activeOrgId: session.user.orgId },
|
|
|
|
|
data: { activeOrgId: null },
|
|
|
|
|
}),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return NextResponse.json({ success: true });
|
|
|
|
|
} catch (error) {
|
Normalize role-based permissions across API and UI
Centralizes role/permission enforcement so each role (owner, admin, editor,
reviewer, viewer) behaves consistently in the API and UI.
- Extend src/lib/permissions.ts with an expanded action map (cards.reprocess,
cards.assign, uploads.create, integrations.manage, etc.) plus helper
predicates (isAdminRole, canEditContent).
- Add requireApiAuthWithPermission(action) to src/lib/api-auth.ts with a
narrowed OrgSession return type and PermissionError -> 403 handling.
- Replace hand-rolled role checks in card, org, integration, form-template,
settings, upload, and location routes with the shared helpers so 403s are
uniform and derived from one permission map.
- Close the editor UI gap: the dashboard upload button, row-level mark
reviewed/reprocess/delete, and card detail edit/reprocess/export/assign
now flow from can(role, action) instead of ad-hoc isAdmin checks.
- Gate /settings/* at the middleware layer for non-admins and hide the
Settings entry in the sidebar and top-bar menu when the role cannot
access it.
- Use isAdminRole() in the team members settings page for consistency.
Made-with: Cursor
2026-04-23 13:17:35 -04:00
|
|
|
return handleApiError(error);
|
2026-04-17 13:48:59 -04:00
|
|
|
}
|
|
|
|
|
}
|