Finish fine-grained ACL across remaining admin pages and actions.
Replace leftover requireStaff gates with module PERMS, drop hardcoded room rank thresholds, and expand contract tests so admin mutations cannot regress to dashboard-only checks. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
3c8a8ff888
commit
0e89d03940
63 files changed
+420
-163
No files matched your search
@@ -2,6 +2,8 @@ import { Award } from "lucide-react";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -16,6 +18,11 @@ type Achievement = {
|
||||
};
|
||||
|
||||
export default async function AdminAchievements() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.CATALOG_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.achievements");
|
||||
|
||||
let achievements: Achievement[];
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Megaphone } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { deleteAd, updateAd } from "@/actions/admin-ads";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -11,6 +12,11 @@ export default async function EditAd({
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
let ad: Awaited<ReturnType<typeof prisma.websiteAds.findUnique>> = null;
|
||||
try {
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
import { Megaphone } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { createAd } from "@/actions/admin-ads";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function NewAd() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_EDIT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
export default function NewAd() {
|
||||
return (
|
||||
<main>
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
|
||||
@@ -3,10 +3,17 @@ import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminAds() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.ads");
|
||||
let ads: Awaited<ReturnType<typeof prisma.websiteAds.findMany>>;
|
||||
try {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { sendHotelAlert } from "@/actions/admin-alerts";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -54,6 +56,11 @@ function Badge({ label, color }: { label: string; color: string }) {
|
||||
}
|
||||
|
||||
export default async function AdminAlerts() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.NOTIFICATIONS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.alerts");
|
||||
|
||||
let alerts: Awaited<ReturnType<typeof prisma.alertLogs.findMany>>;
|
||||
|
||||
@@ -4,6 +4,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { dismissApplication } from "@/actions/admin-applications";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -20,6 +22,11 @@ function formatDate(d: Date | null): string {
|
||||
}
|
||||
|
||||
export default async function AdminApplications() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.USERS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.applications");
|
||||
let applications: ApplicationRow[];
|
||||
try {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { uploadBadge } from "@/actions/admin-badge-upload";
|
||||
import { giveBadge } from "@/actions/admin-badges";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -13,6 +15,11 @@ export default async function AdminBadges({
|
||||
}: {
|
||||
searchParams: Promise<{ uploaded?: string; error?: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.CATALOG_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.badges");
|
||||
const { uploaded, error } = await searchParams;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -40,6 +41,11 @@ export default async function AdminCalendarCampaign({
|
||||
}: {
|
||||
params: Promise<{ id: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.calendar");
|
||||
|
||||
const { id } = await params;
|
||||
|
||||
@@ -3,6 +3,8 @@ import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -22,6 +24,11 @@ function fmtDate(ts: number): string {
|
||||
}
|
||||
|
||||
export default async function AdminCalendar() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.calendar");
|
||||
|
||||
let campaigns: Campaign[] = [];
|
||||
|
||||
@@ -5,10 +5,17 @@ import {
|
||||
updateEmailTemplate,
|
||||
} from "@/actions/admin-email-templates";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminEmailTemplates() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.emailTemplates");
|
||||
|
||||
let templates: Awaited<ReturnType<typeof prisma.emailTemplates.findMany>> =
|
||||
|
||||
@@ -2,10 +2,17 @@ import { Image } from "lucide-react";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { FaviconForm } from "./favicon-form";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminFaviconPage() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.favicon");
|
||||
|
||||
let faviconUrl: string | null = null;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { HelpCircle } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { notFound } from "next/navigation";
|
||||
import { notFound, redirect } from "next/navigation";
|
||||
import { deleteHelpQuestion, updateHelpQuestion } from "@/actions/admin-help";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -13,6 +14,11 @@ export default async function EditHelpQuestion({
|
||||
params: Promise<{ id: string }>;
|
||||
searchParams: Promise<{ error?: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const { id } = await params;
|
||||
const { error } = await searchParams;
|
||||
let entry: Awaited<
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
import { HelpCircle } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { createHelpQuestion } from "@/actions/admin-help";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function NewHelpQuestion({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: Promise<{ error?: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_EDIT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const { error } = await searchParams;
|
||||
|
||||
return (
|
||||
|
||||
@@ -3,10 +3,17 @@ import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminHelpQuestions() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.helpCenter");
|
||||
let entries: Awaited<
|
||||
ReturnType<typeof prisma.websiteHelpCenterCategories.findMany>
|
||||
|
||||
@@ -5,6 +5,8 @@ import {
|
||||
upsertPermission,
|
||||
} from "@/actions/admin-housekeeping";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -13,6 +15,11 @@ export default async function AdminHousekeeping({
|
||||
}: {
|
||||
searchParams: Promise<{ q?: string; mode?: "manage" | "import" }>;
|
||||
}) {
|
||||
const { session, permissions: acl } = await getAdminContext();
|
||||
if (!canAccess(acl, PERMS.SETTINGS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.housekeeping");
|
||||
|
||||
const sp = await searchParams;
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
} from "@/actions/admin-ip";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -23,6 +25,11 @@ function formatDate(d: Date | null): string {
|
||||
}
|
||||
|
||||
export default async function AdminIp() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.ip");
|
||||
let whitelist: IpRow[] = [];
|
||||
let blacklist: IpRow[] = [];
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { buildStaffActivityWhere } from "@/lib/admin/log-filters";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -23,6 +25,11 @@ export default async function AdminStaffActivities({
|
||||
authorization?: string;
|
||||
}>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.LOGS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.logs");
|
||||
|
||||
const sp = await searchParams;
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { saveMaintenance } from "@/actions/admin-maintenance";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -13,6 +15,11 @@ const KEYS = [
|
||||
] as const;
|
||||
|
||||
export default async function AdminMaintenance() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.maintenance");
|
||||
|
||||
let rows: { key: string; value: string }[] = [];
|
||||
|
||||
@@ -2,8 +2,15 @@ import { Image } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { AdminMediaGrid } from "@/components/admin/media-grid";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export default async function AdminMediaPage() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.media");
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,6 +2,8 @@ import { Navigation } from "lucide-react";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -40,6 +42,11 @@ function YesNo({ on }: { on: boolean }) {
|
||||
}
|
||||
|
||||
export default async function AdminNavigation() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.navigation");
|
||||
let flatcats: Flatcat[] = [];
|
||||
try {
|
||||
|
||||
@@ -3,10 +3,17 @@ import { getTranslations } from "next-intl/server";
|
||||
import { deletePhoto } from "@/actions/admin-photos";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function AdminPhotos() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.photos");
|
||||
let photos: Awaited<ReturnType<typeof prisma.cameraWeb.findMany>> = [];
|
||||
try {
|
||||
|
||||
@@ -8,12 +8,19 @@ import {
|
||||
} from "@/actions/admin-rare-values";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const CURRENCY_TYPES = ["diamonds", "credits", "duckets", "points"];
|
||||
|
||||
export default async function AdminRareValues() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.rareValues");
|
||||
|
||||
let categories: Awaited<
|
||||
|
||||
@@ -84,7 +84,7 @@ export default async function RoomFurniPage({
|
||||
ownerUsername: room.owner?.username ?? room.ownerName,
|
||||
}}
|
||||
items={rows}
|
||||
canEdit={session.user.rank >= 4}
|
||||
canEdit={canAccess(permissions, PERMS.ROOMS_EDIT, session.user.rank)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -15,10 +15,7 @@ export default async function RoomEditPage({
|
||||
}) {
|
||||
const { id } = await params;
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (
|
||||
!canAccess(permissions, PERMS.ROOMS_VIEW, session.user.rank) ||
|
||||
session.user.rank < 4
|
||||
) {
|
||||
if (!canAccess(permissions, PERMS.ROOMS_EDIT, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
|
||||
@@ -30,9 +30,7 @@ export default async function RoomsPage({
|
||||
searchParams,
|
||||
);
|
||||
|
||||
const canEdit =
|
||||
canAccess(result.permissions, PERMS.ROOMS_VIEW, result.rank) &&
|
||||
result.rank >= 4;
|
||||
const canEdit = canAccess(result.permissions, PERMS.ROOMS_EDIT, result.rank);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
|
||||
@@ -29,7 +29,7 @@ export default async function RoomShowPage({
|
||||
redirect("/admin");
|
||||
|
||||
const room = await loadRoom(id);
|
||||
const canEdit = session.user.rank >= 4;
|
||||
const canEdit = canAccess(permissions, PERMS.ROOMS_EDIT, session.user.rank);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
|
||||
@@ -2,6 +2,8 @@ import { CreditCard } from "lucide-react";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -17,6 +19,11 @@ function fmt(ts: number): string {
|
||||
}
|
||||
|
||||
export default async function AdminSubscriptions() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.subscriptions");
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { createTag, deleteTag, updateTag } from "@/actions/admin-tags";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -18,6 +20,11 @@ function formatDate(d: Date | null): string {
|
||||
}
|
||||
|
||||
export default async function AdminTagsPage() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.tags");
|
||||
let tags: Tag[] = [];
|
||||
let usage = new Map<string, number>();
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { createTeam, deleteTeam } from "@/actions/admin-teams";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -16,6 +18,11 @@ type TeamRow = {
|
||||
};
|
||||
|
||||
export default async function AdminTeams() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.USERS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.teams");
|
||||
let teams: TeamRow[] = [];
|
||||
try {
|
||||
|
||||
@@ -2,8 +2,9 @@ import { ArrowLeftRight } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { requireStaff } from "@/lib/admin/guard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -47,7 +48,10 @@ export default async function AdminTransactions({
|
||||
}: {
|
||||
searchParams: Promise<{ page?: string }>;
|
||||
}) {
|
||||
await requireStaff();
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.transactions");
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { createVoucher, deleteVoucher } from "@/actions/admin-vouchers";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
@@ -22,6 +24,11 @@ function fmtDate(d: Date | null): string {
|
||||
}
|
||||
|
||||
export default async function AdminVouchers() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SHOP_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.vouchers");
|
||||
const now = Date.now();
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ import { getTranslations } from "next-intl/server";
|
||||
import { saveVpn } from "@/actions/admin-vpn";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { siteSettings } from "@/lib/services/site-settings";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
export const metadata = { title: "VPN" };
|
||||
@@ -19,6 +21,11 @@ export default async function AdminVpn({
|
||||
}: {
|
||||
searchParams: Promise<{ saved?: string }>;
|
||||
}) {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const sp = await searchParams;
|
||||
const t = await getTranslations("pages.admin.vpn");
|
||||
|
||||
|
||||
@@ -8,12 +8,19 @@ import {
|
||||
} from "@/actions/admin-writeable-boxes";
|
||||
import { StatusCard } from "@/components/admin/dashboard";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export const metadata = { title: "Writeable boxes" };
|
||||
|
||||
export default async function AdminWriteableBoxes() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.PAGES_VIEW, session.user.rank)) {
|
||||
redirect("/admin");
|
||||
}
|
||||
|
||||
const t = await getTranslations("pages.admin.writeableBoxes");
|
||||
const boxes = await prisma.websiteWriteableBoxes
|
||||
.findMany({
|
||||
|
||||
Reference in new issue
Block a user