fix: restore complete admin feature dependencies

This commit is contained in:
Simo committed 2026-07-11 21:15:54 +02:00
1 parent 5b4228261a
commit 0cd753c735
115 files changed
+18565 -4930

No files matched your search

@@ -264,7 +264,7 @@ export function CatalogTranslateTab({
<Database className="h-3 w-3" /> items_base (name)
</span>
<span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
<ShoppingCart className="h-3 w-3" /> catalog_name (auto)
<ShoppingCart className="h-3 w-3" /> catalogName (auto)
</span>
<span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
<FileJson className="h-3 w-3" /> FurnitureData.json (name + desc)
+2 -2
View File
@@ -22,14 +22,14 @@ export default async function CatalogEditPage({
const pageId = parseInt(id, 10)
if (Number.isNaN(pageId)) notFound()
const catalogPage = await prisma.catalogPage.findUnique({
const catalogPage = await prisma.catalogPages.findUnique({
where: { id: pageId },
})
if (!catalogPage) notFound()
const [children, itemsData, ancestors] = await Promise.all([
prisma.catalogPage.findMany({
prisma.catalogPages.findMany({
where: { parentId: pageId },
orderBy: { orderNum: 'asc' },
select: { id: true, caption: true, enabled: true },
@@ -19,40 +19,40 @@ export default async function BcPageDetailPage({
const canEdit = canAccess(permissions, PERMS.CATALOG_EDIT, session.user.rank)
const bcPage = await prisma.catalog_pages_bc.findUnique({ where: { id } })
const bcPage = await prisma.catalogPagesBc.findUnique({ where: { id } })
if (!bcPage) notFound()
const bcItems = await prisma.catalog_items_bc.findMany({
where: { page_id: id },
orderBy: { order_number: 'asc' },
const bcItems = await prisma.catalogItemsBc.findMany({
where: { pageId: id },
orderBy: { orderNumber: 'asc' },
})
return (
<BcPageDetail
page={{
id: bcPage.id,
parentId: bcPage.parent_id,
parentId: bcPage.parentId,
caption: bcPage.caption,
pageLayout: bcPage.page_layout,
iconColor: bcPage.icon_color,
iconImage: bcPage.icon_image,
orderNum: bcPage.order_num,
pageLayout: bcPage.pageLayout,
iconColor: bcPage.iconColor,
iconImage: bcPage.iconImage,
orderNum: bcPage.orderNum,
visible: bcPage.visible,
enabled: bcPage.enabled,
pageHeadline: bcPage.page_headline,
pageTeaser: bcPage.page_teaser,
pageSpecial: bcPage.page_special ?? '',
pageText1: bcPage.page_text1 ?? '',
pageText2: bcPage.page_text2 ?? '',
pageTextDetails: bcPage.page_text_details ?? '',
pageTextTeaser: bcPage.page_text_teaser ?? '',
pageHeadline: bcPage.pageHeadline,
pageTeaser: bcPage.pageTeaser,
pageSpecial: bcPage.pageSpecial ?? '',
pageText1: bcPage.pageText1 ?? '',
pageText2: bcPage.pageText2 ?? '',
pageTextDetails: bcPage.pageTextDetails ?? '',
pageTextTeaser: bcPage.pageTextTeaser ?? '',
}}
items={bcItems.map((i) => ({
id: i.id,
pageId: i.page_id,
itemIds: i.item_ids,
catalogName: i.catalog_name,
orderNumber: i.order_number,
pageId: i.pageId,
itemIds: i.itemIds,
catalogName: i.catalogName,
orderNumber: i.orderNumber,
extradata: i.extradata,
}))}
canEdit={canEdit}
+55 -55
View File
@@ -51,46 +51,46 @@ export default async function CatalogPagesPage({
if (catalogType === 'bc') {
const [totalBcPages, totalBcItems, enabledBcPages] = await Promise.all([
prisma.catalog_pages_bc.count(),
prisma.catalog_items_bc.count(),
prisma.catalog_pages_bc.count({ where: { enabled: '1' } }),
prisma.catalogPagesBc.count(),
prisma.catalogItemsBc.count(),
prisma.catalogPagesBc.count({ where: { enabled: '1' } }),
])
// ── BC tree view ──────────────────────────────────────────────
let bcRootPages: TreeNodeShape[] = []
if (viewMode === 'tree') {
const bcRootRaw = await prisma.catalog_pages_bc.findMany({
where: { OR: [{ parent_id: -1 }, { parent_id: 0 }] },
orderBy: { order_num: 'asc' },
const bcRootRaw = await prisma.catalogPagesBc.findMany({
where: { OR: [{ parentId: -1 }, { parentId: 0 }] },
orderBy: { orderNum: 'asc' },
})
const bcRootIds = bcRootRaw.map((p) => p.id)
const [bcChildCounts, bcItemCounts] = await Promise.all([
bcRootIds.length > 0
? prisma.catalog_pages_bc.groupBy({
by: ['parent_id'],
where: { parent_id: { in: bcRootIds } },
? prisma.catalogPagesBc.groupBy({
by: ['parentId'],
where: { parentId: { in: bcRootIds } },
_count: true,
})
: [],
bcRootIds.length > 0
? prisma.catalog_items_bc.groupBy({
by: ['page_id'],
where: { page_id: { in: bcRootIds } },
? prisma.catalogItemsBc.groupBy({
by: ['pageId'],
where: { pageId: { in: bcRootIds } },
_count: true,
})
: [],
])
const bcChildMap = Object.fromEntries(bcChildCounts.map((c) => [c.parent_id, c._count]))
const bcItemMap = Object.fromEntries(bcItemCounts.map((c) => [c.page_id, c._count]))
const bcChildMap = Object.fromEntries(bcChildCounts.map((c) => [c.parentId, c._count]))
const bcItemMap = Object.fromEntries(bcItemCounts.map((c) => [c.pageId, c._count]))
bcRootPages = bcRootRaw.map((p) => ({
id: p.id,
caption: p.caption,
parentId: p.parent_id,
parentId: p.parentId,
enabled: String(p.enabled),
visible: String(p.visible),
iconImage: p.icon_image,
iconColor: p.icon_color,
pageLayout: p.page_layout,
iconImage: p.iconImage,
iconColor: p.iconColor,
pageLayout: p.pageLayout,
childCount: bcChildMap[p.id] ?? 0,
itemCount: bcItemMap[p.id] ?? 0,
}))
@@ -122,68 +122,68 @@ export default async function CatalogPagesPage({
const pattern = { contains: search }
where.OR = [{ caption: pattern }]
}
if (hasParent) where.parent_id = parentId
if (hasParent) where.parentId = parentId
// Prisma sort key is snake_case for BC model. Translate known keys.
const sortKeyMap: Record<string, string> = {
parentId: 'parent_id',
pageLayout: 'page_layout',
orderNum: 'order_num',
parentId: 'parentId',
pageLayout: 'pageLayout',
orderNum: 'orderNum',
}
const sortKey = sort ? (sortKeyMap[sort] ?? sort) : 'order_num'
const sortKey = sort ? (sortKeyMap[sort] ?? sort) : 'orderNum'
const orderBy = { [sortKey]: sort ? order : 'asc' }
const [pages, total] = await Promise.all([
prisma.catalog_pages_bc.findMany({
prisma.catalogPagesBc.findMany({
where,
orderBy,
skip: (page - 1) * perPage,
take: perPage,
}),
prisma.catalog_pages_bc.count({ where }),
prisma.catalogPagesBc.count({ where }),
])
bcPagination = calcPagination(total, page, perPage)
const pageIds = pages.map((p) => p.id)
const parentIds = [...new Set(pages.map((p) => p.parent_id).filter((id) => id > 0))]
const parentIds = [...new Set(pages.map((p) => p.parentId).filter((id) => id > 0))]
const [childCounts, itemCounts, parentPages] = await Promise.all([
pageIds.length > 0
? prisma.catalog_pages_bc.groupBy({
by: ['parent_id'],
where: { parent_id: { in: pageIds } },
? prisma.catalogPagesBc.groupBy({
by: ['parentId'],
where: { parentId: { in: pageIds } },
_count: true,
})
: [],
pageIds.length > 0
? prisma.catalog_items_bc.groupBy({
by: ['page_id'],
where: { page_id: { in: pageIds } },
? prisma.catalogItemsBc.groupBy({
by: ['pageId'],
where: { pageId: { in: pageIds } },
_count: true,
})
: [],
parentIds.length > 0
? prisma.catalog_pages_bc.findMany({
? prisma.catalogPagesBc.findMany({
where: { id: { in: parentIds } },
select: { id: true, caption: true },
})
: [],
])
const childCountMap = Object.fromEntries(childCounts.map((c) => [c.parent_id, c._count]))
const itemCountMap = Object.fromEntries(itemCounts.map((c) => [c.page_id, c._count]))
const childCountMap = Object.fromEntries(childCounts.map((c) => [c.parentId, c._count]))
const itemCountMap = Object.fromEntries(itemCounts.map((c) => [c.pageId, c._count]))
const parentNameMap = Object.fromEntries(parentPages.map((p) => [p.id, p.caption]))
bcRows = pages.map((p) => ({
id: p.id,
caption: p.caption,
parentId: p.parent_id,
parentId: p.parentId,
parentCaption:
p.parent_id === -1 ? 'Root' : (parentNameMap[p.parent_id] ?? `#${p.parent_id}`),
pageLayout: String(p.page_layout),
p.parentId === -1 ? 'Root' : (parentNameMap[p.parentId] ?? `#${p.parentId}`),
pageLayout: String(p.pageLayout),
enabled: String(p.enabled),
visible: String(p.visible),
minRank: 0, // BC pages have no min rank column
orderNum: p.order_num,
orderNum: p.orderNum,
itemCount: itemCountMap[p.id] ?? 0,
childCount: childCountMap[p.id] ?? 0,
}))
@@ -220,29 +220,29 @@ export default async function CatalogPagesPage({
// Global stats (lightweight counts)
const [totalPages, totalItems, enabledPages] = await Promise.all([
prisma.catalogPage.count(),
prisma.catalogItem.count(),
prisma.catalogPage.count({ where: { enabled: '1' } }),
prisma.catalogPages.count(),
prisma.catalogItems.count(),
prisma.catalogPages.count({ where: { enabled: '1' } }),
])
// ── Tree view data ──────────────────────────────────────────────
let rootPages: TreeNodeShape[] = []
if (viewMode === 'tree') {
const rootPagesRaw = await prisma.catalogPage.findMany({
const rootPagesRaw = await prisma.catalogPages.findMany({
where: { parentId: -1 },
orderBy: { orderNum: 'asc' },
})
const rootIds = rootPagesRaw.map((p) => p.id)
const [rootChildCounts, rootItemCounts] = await Promise.all([
rootIds.length > 0
? prisma.catalogPage.groupBy({
? prisma.catalogPages.groupBy({
by: ['parentId'],
where: { parentId: { in: rootIds } },
_count: true,
})
: [],
rootIds.length > 0
? prisma.catalogItem.groupBy({
? prisma.catalogItems.groupBy({
by: ['pageId'],
where: { pageId: { in: rootIds } },
_count: true,
@@ -289,15 +289,15 @@ export default async function CatalogPagesPage({
const hasParent = parentId !== undefined && !Number.isNaN(parentId)
if (search) {
const searchPattern = `%${search}%`
const parentClause = hasParent ? Prisma.sql`AND cp.parent_id = ${parentId}` : Prisma.empty
const parentClause = hasParent ? Prisma.sql`AND cp.parentId = ${parentId}` : Prisma.empty
const matchedIds = await prisma.$queryRaw<{ id: number }[]>(Prisma.sql`
SELECT DISTINCT cp.id FROM catalog_pages cp
LEFT JOIN catalog_items ci ON ci.page_id = cp.id
LEFT JOIN items_base ib ON FIND_IN_SET(ib.id, REPLACE(ci.item_ids, ';', ','))
LEFT JOIN catalog_items ci ON ci.pageId = cp.id
LEFT JOIN items_base ib ON FIND_IN_SET(ib.id, REPLACE(ci.itemIds, ';', ','))
WHERE (cp.caption LIKE ${searchPattern}
OR cp.page_layout LIKE ${searchPattern}
OR ci.catalog_name LIKE ${searchPattern}
OR cp.pageLayout LIKE ${searchPattern}
OR ci.catalogName LIKE ${searchPattern}
OR ib.public_name LIKE ${searchPattern}
OR ib.item_name LIKE ${searchPattern})
${parentClause}
@@ -310,13 +310,13 @@ export default async function CatalogPagesPage({
const orderBy = sort ? { [sort]: order } : { orderNum: 'asc' as const }
const [pages, total] = await Promise.all([
prisma.catalogPage.findMany({
prisma.catalogPages.findMany({
where,
orderBy,
skip: (page - 1) * perPage,
take: perPage,
}),
prisma.catalogPage.count({ where }),
prisma.catalogPages.count({ where }),
])
pagination = calcPagination(total, page, perPage)
@@ -326,21 +326,21 @@ export default async function CatalogPagesPage({
const parentIds = [...new Set(pages.map((p) => p.parentId).filter((id) => id > 0))]
const [childCounts, itemCounts, parentPages] = await Promise.all([
pageIds.length > 0
? prisma.catalogPage.groupBy({
? prisma.catalogPages.groupBy({
by: ['parentId'],
where: { parentId: { in: pageIds } },
_count: true,
})
: [],
pageIds.length > 0
? prisma.catalogItem.groupBy({
? prisma.catalogItems.groupBy({
by: ['pageId'],
where: { pageId: { in: pageIds } },
_count: true,
})
: [],
parentIds.length > 0
? prisma.catalogPage.findMany({
? prisma.catalogPages.findMany({
where: { id: { in: parentIds } },
select: { id: true, caption: true },
})
@@ -379,7 +379,7 @@ function FurniGrid({ source }: FurniGridProps) {
setError(data.error || 'Failed to load')
return
}
setItems(data.items || [])
setItems(data.item || [])
setMeta(data.meta || null)
setStats(data.stats || null)
setSelected(new Set())
@@ -150,7 +150,7 @@ function LibsView() {
setError(data.error || 'Failed to load')
return
}
setItems(data.items || [])
setItems(data.item || [])
setTotal(data.meta?.total || 0)
setSelected(new Set())
} catch {
@@ -498,7 +498,7 @@ function SetsView() {
setError(data.error || 'Failed to load')
return
}
setItems(data.items || [])
setItems(data.item || [])
setTotal(data.meta?.total || 0)
setSelected(new Set())
} catch {
@@ -310,7 +310,7 @@ export function ImportFurniClient() {
setError(data.error || 'Failed to load')
return
}
const loadedItems = data.items || []
const loadedItems = data.item || []
setItems(loadedItems)
setMeta(data.meta || null)
setSelected(new Set())
@@ -167,7 +167,10 @@ export function RankEditClient({
}
function saveRank() {
run(() => saveRankAction({ id: initialRank.id, fields: { ...general, ...perms } }), {
const fields = Object.fromEntries(
Object.entries({ ...general, ...perms }).map(([key, value]) => [key, String(value)]),
)
run(() => saveRankAction({ id: initialRank.id, fields }), {
successMessage: 'Rank saved',
})
}
+5 -5
View File
@@ -17,13 +17,13 @@ export default async function RoomFurniPage({
const room = await loadRoom(id)
// Load items in this room. items.item_id → items_base.id
const items = await prisma.item.findMany({
const items = await prisma.items.findMany({
where: { roomId: room.id },
orderBy: { id: 'desc' },
})
// Resolve item bases
const baseIds = Array.from(new Set(items.map((i) => i.itemId)))
const baseIds = Array.from(new Set(items.map((i) => i.itemId).filter((id): id is number => id !== null)))
const bases = baseIds.length
? await prisma.itemsBase.findMany({
where: { id: { in: baseIds } },
@@ -43,10 +43,10 @@ export default async function RoomFurniPage({
const userMap = new Map(users.map((u) => [u.id, u.username]))
const rows = items.map((i) => {
const base = baseMap.get(i.itemId)
const base = i.itemId === null ? undefined : baseMap.get(i.itemId)
return {
id: i.id,
baseId: i.itemId,
baseId: i.itemId ?? 0,
name: base?.publicName || base?.itemName || `#${i.itemId}`,
itemName: base?.itemName ?? '',
type: base?.type ?? '?',
@@ -74,7 +74,7 @@ export default async function RoomFurniPage({
room={{
id: room.id,
name: room.name,
ownerUsername: room.owner?.username ?? room.owner_name,
ownerUsername: room.owner?.username ?? room.ownerName,
}}
items={rows}
canEdit={session.user.rank >= 4}
+8 -3
View File
@@ -5,11 +5,16 @@ export async function loadRoom(id: string) {
const roomId = parseInt(id, 10)
if (Number.isNaN(roomId)) notFound()
const room = await prisma.room.findUnique({
const room = await prisma.rooms.findUnique({
where: { id: roomId },
include: { owner: { select: { id: true, username: true, look: true } } },
})
if (!room) notFound()
return room
const owner = room.ownerId > 0
? await prisma.user.findUnique({
where: { id: room.ownerId },
select: { id: true, username: true, look: true },
})
: null
return { ...room, owner }
}
+2 -2
View File
@@ -42,7 +42,7 @@ export default async function RoomEditPage({
</Badge>
</h1>
<p className="text-sm text-muted-foreground">
Owner: {room.owner.username} &middot; {room.users}/{room.usersMax} users
Owner: {room.owner?.username ?? room.ownerName} &middot; {room.users}/{room.usersMax} users
</p>
</div>
</div>
@@ -61,7 +61,7 @@ export default async function RoomEditPage({
state: room.state,
usersMax: room.usersMax,
users: room.users,
ownerName: room.owner.username,
ownerName: room.owner?.username ?? room.ownerName,
}}
/>
</div>
+7 -6
View File
@@ -49,12 +49,13 @@ export default async function RoomShowPage({
<Users className="h-4 w-4 text-muted-foreground" />
<span className="font-medium">{room.users}</span> / {room.usersMax} users
</span>
<Link
href={`/admin/users/show/${room.owner.id}`}
className="text-primary hover:underline"
>
Owner: {room.owner.username}
</Link>
{room.owner ? (
<Link href={`/admin/users/show/${room.owner.id}`} className="text-primary hover:underline">
Owner: {room.owner.username}
</Link>
) : (
<span>Owner: {room.ownerName}</span>
)}
</div>
</div>
<div className="flex gap-2">
+3 -2
View File
@@ -26,7 +26,7 @@ export default async function SoundsPage() {
track: true,
},
}),
prisma.catalogItem.groupBy({
prisma.catalogItems.groupBy({
by: ['songId'],
where: { songId: { gt: 0 } },
_count: { _all: true },
@@ -55,7 +55,8 @@ export default async function SoundsPage() {
})
// Normalize: ensure trailing slash so ${base}${code}.mp3 yields a valid URL.
const baseUrl = baseUrlSetting.endsWith('/') ? baseUrlSetting : `${baseUrlSetting}/`
const configuredBaseUrl = baseUrlSetting ?? '/sounds/'
const baseUrl = configuredBaseUrl.endsWith('/') ? configuredBaseUrl : `${configuredBaseUrl}/`
return (
<div className="space-y-6">
+1 -1
View File
@@ -67,7 +67,7 @@ export default async function AdminTicketDetailPage({
username: ticket.creator.username,
look: ticket.creator.look,
rank: ticket.creator.rank,
mail: ticket.creator.mail,
mail: ticket.creator.mail ?? '',
ipRegister: ticket.creator.ipRegister,
accountCreated: ticket.creator.accountCreated,
},
+8 -8
View File
@@ -1,6 +1,6 @@
import { ExternalLink, Server } from 'lucide-react'
import Link from 'next/link'
import { EmulatorSettingsForm } from '@/app/[locale]/admin/settings/emulator/emulator-settings-form'
import { EmulatorSettingsForm } from '@/components/admin/emulator-settings-form'
import { Button } from '@/components/ui/button'
import type { Prisma } from '@/generated/prisma/client'
import { calcPagination } from '@/lib/admin-helpers'
@@ -31,32 +31,32 @@ export default async function EmulatorTranslationsPage({
const perPage = Math.min(Math.max(parseInt(sp.perPage || '50', 10), 10), 200)
const page = Math.max(parseInt(sp.page || '1', 10), 1)
const patternFilters: Prisma.EmulatorSettingWhereInput[] = TRANSLATION_KEY_PATTERNS.map((p) => ({
const patternFilters: Prisma.EmulatorSettingsWhereInput[] = TRANSLATION_KEY_PATTERNS.map((p) => ({
key: { contains: p.replace(/%/g, '') },
}))
const baseFilter: Prisma.EmulatorSettingWhereInput = { OR: patternFilters }
const baseFilter: Prisma.EmulatorSettingsWhereInput = { OR: patternFilters }
const conditions: Prisma.EmulatorSettingWhereInput[] = [baseFilter]
const conditions: Prisma.EmulatorSettingsWhereInput[] = [baseFilter]
if (group) conditions.push({ key: { startsWith: `${group}.` } })
if (search) {
conditions.push({
OR: [{ key: { contains: search } }, { value: { contains: search } }],
})
}
const where: Prisma.EmulatorSettingWhereInput = { AND: conditions }
const where: Prisma.EmulatorSettingsWhereInput = { AND: conditions }
const [settings, total, allKeys] = await Promise.all([
prisma.emulatorSetting.findMany({
prisma.emulatorSettings.findMany({
where,
orderBy: { key: 'asc' },
skip: (page - 1) * perPage,
take: perPage,
}),
prisma.emulatorSetting.count({ where }),
prisma.emulatorSettings.count({ where }),
// Group chips reflect the WHOLE translation-pattern subset (so they don't
// disappear when you click one); we ignore the group/search filters here.
prisma.emulatorSetting.findMany({
prisma.emulatorSettings.findMany({
where: baseFilter,
select: { key: true },
}),
+55 -59
View File
@@ -1,73 +1,69 @@
import { notFound } from 'next/navigation'
import { prisma } from '@/lib/prisma'
import { notFound } from "next/navigation";
import { prisma } from "@/lib/prisma";
export async function loadUserById(id: string) {
const numericId = parseInt(id, 10)
const isNumeric = !Number.isNaN(numericId) && String(numericId) === id
const numericId = Number(id);
const isNumeric = Number.isSafeInteger(numericId) && numericId > 0 && String(numericId) === id;
const user = await prisma.user.findUnique({ where: isNumeric ? { id: numericId } : { username: id } });
if (!user) notFound();
const user = await prisma.user.findUnique({
where: isNumeric ? { id: numericId } : { username: id },
include: {
permission: true,
settings: true,
currencies: true,
badges: true,
bansReceived: {
include: { staff: { select: { username: true } } },
orderBy: { id: 'desc' },
take: 5,
},
},
})
const [currencies, badges, bansReceived, permissionRows, roomCount, tradeCount, userRooms, chatLogs, commandLogs] =
await Promise.all([
prisma.usersCurrency.findMany({ where: { userId: user.id } }),
prisma.usersBadges.findMany({ where: { userId: user.id }, orderBy: { slotId: "asc" } }),
prisma.$queryRaw<Array<{ id: number; banReason: string; type: string; timestamp: number; banExpire: number; staffName: string }>>`
SELECT b.id, b.ban_reason AS banReason, b.type, b.timestamp, b.ban_expire AS banExpire,
COALESCE(s.username, 'Unknown') AS staffName
FROM bans b LEFT JOIN users s ON s.id = b.user_staff_id
WHERE b.user_id = ${user.id} ORDER BY b.id DESC LIMIT 5`,
prisma.$queryRaw<Array<{ rankName: string }>>`
SELECT COALESCE(rank_name, CONCAT('Rank ', id)) AS rankName FROM permissions WHERE id = ${user.rank} LIMIT 1`,
prisma.rooms.count({ where: { ownerId: user.id } }),
prisma.roomTradeLog.count({ where: { OR: [{ userOneId: user.id }, { userTwoId: user.id }] } }),
prisma.rooms.findMany({
where: { ownerId: user.id },
orderBy: { users: "desc" },
take: 20,
select: { id: true, name: true, state: true, users: true, usersMax: true },
}),
prisma.$queryRaw<Array<{ id: number; roomId: number; timestamp: number; message: string }>>`
SELECT ROW_NUMBER() OVER (ORDER BY timestamp DESC) AS id, room_id AS roomId, timestamp, message
FROM chatlogs_room WHERE user_from_id = ${user.id} ORDER BY timestamp DESC LIMIT 20`,
prisma.$queryRaw<Array<{ id: number; timestamp: number; command: string; params: string; succes: string }>>`
SELECT ROW_NUMBER() OVER (ORDER BY timestamp DESC) AS id, timestamp, command, params, succes
FROM commandlogs WHERE user_id = ${user.id} ORDER BY timestamp DESC LIMIT 10`,
]);
if (!user) notFound()
const diamonds = user.currencies.find((c) => c.type === 5)?.amount ?? 0
const duckets = user.currencies.find((c) => c.type === 0)?.amount ?? 0
const [roomCount, chatCount, tradeCount, userRooms, chatLogs, commandLogs] = await Promise.all([
prisma.room.count({ where: { ownerId: user.id } }),
prisma.chatLog.count({ where: { userId: user.id } }),
prisma.trade.count({
where: { OR: [{ userOneId: user.id }, { userTwoId: user.id }] },
}),
prisma.room.findMany({
where: { ownerId: user.id },
orderBy: { users: 'desc' },
take: 20,
select: { id: true, name: true, state: true, users: true, usersMax: true },
}),
prisma.chatLog.findMany({
where: { userId: user.id },
orderBy: { id: 'desc' },
take: 20,
select: { id: true, roomId: true, timestamp: true, message: true },
}),
prisma.commandLog.findMany({
where: { userId: user.id },
orderBy: { id: 'desc' },
take: 10,
select: { id: true, timestamp: true, command: true, params: true, succes: true },
}),
])
const isOnline = user.online === '1'
const activeBan = user.bansReceived.find((b) => {
const now = Math.floor(Date.now() / 1000)
return b.banExpire === 0 || b.banExpire > now
})
const diamonds = currencies.find((currency) => currency.type === 5)?.amount ?? 0;
const duckets = currencies.find((currency) => currency.type === 0)?.amount ?? 0;
const now = Math.floor(Date.now() / 1000);
const activeBan = bansReceived.find((ban) => ban.banExpire === 0 || ban.banExpire > now);
const decoratedUser = {
...user,
mail: user.mail ?? "",
gender: String(user.gender),
machine_id: user.machineId,
twoFactorConfirmed: user.twoFactorConfirmedAt ? 1 : 0,
permission: { rankName: permissionRows[0]?.rankName ?? `Rank ${user.rank}` },
currencies,
badges,
bansReceived: bansReceived.map((ban) => ({
...ban,
staff: { username: ban.staffName },
})),
};
return {
user,
user: decoratedUser,
diamonds,
duckets,
roomCount,
chatCount,
chatCount: chatLogs.length,
tradeCount,
userRooms,
chatLogs,
commandLogs: commandLogs.map((l) => ({ ...l, succes: String(l.succes) })),
isOnline,
commandLogs,
isOnline: user.online === "1",
activeBan,
}
};
}