Backend: - Add acl.ts with requireAuth/requireRole/requireOwnerOrAdmin helpers - Gate premium videos from unauthenticated users in videos query/resolver - Fix updateVideoPlay to verify ownership before updating - Add admin mutations: adminListUsers, adminUpdateUser, adminDeleteUser - Add admin mutations: createVideo, updateVideo, deleteVideo, setVideoModels, adminListVideos - Add admin mutations: createArticle, updateArticle, deleteArticle, adminListArticles - Add deleteComment mutation (owner or admin only) - Add AdminUserListType to GraphQL types - Fix featured filter on articles query Frontend: - Install marked for markdown rendering - Add /admin/* section with sidebar layout and admin-only guard - Admin users page: paginated table with search, role filter, inline role change, delete - Admin videos pages: list, create form, edit form with file upload and model assignment - Admin articles pages: list, create form, edit form with split-pane markdown editor - Add admin nav link in header (desktop + mobile) for admin users - Render article content through marked in magazine detail page - Add all admin GraphQL service functions to services.ts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
21 lines
654 B
TypeScript
21 lines
654 B
TypeScript
import { GraphQLError } from "graphql";
|
|
import type { Context } from "../graphql/builder";
|
|
|
|
type UserRole = "viewer" | "model" | "admin";
|
|
|
|
export function requireAuth(ctx: Context): void {
|
|
if (!ctx.currentUser) throw new GraphQLError("Unauthorized");
|
|
}
|
|
|
|
export function requireRole(ctx: Context, ...roles: UserRole[]): void {
|
|
requireAuth(ctx);
|
|
if (!roles.includes(ctx.currentUser!.role)) throw new GraphQLError("Forbidden");
|
|
}
|
|
|
|
export function requireOwnerOrAdmin(ctx: Context, ownerId: string): void {
|
|
requireAuth(ctx);
|
|
if (ctx.currentUser!.id !== ownerId && ctx.currentUser!.role !== "admin") {
|
|
throw new GraphQLError("Forbidden");
|
|
}
|
|
}
|