183 lines
4.7 KiB
TypeScript
183 lines
4.7 KiB
TypeScript
import { Prisma, Site } from "@toolctrl/db/prisma-browser";
|
|
import { db, dbRead } from "~/utils/db.server";
|
|
|
|
export async function getSite({ id, tenantId }: { id: string; tenantId: string }) {
|
|
// Read-only site detail used by admin views and public renderers — replica-safe.
|
|
return dbRead.site.findFirst({
|
|
where: { id, tenantId },
|
|
include: { tenant: true, createdByUser: true },
|
|
});
|
|
}
|
|
|
|
// Get site by type and siteId (for API authentication)
|
|
export async function getSiteByTypeAndSiteId(type: string, siteId: string) {
|
|
return db.site.findUnique({
|
|
where: { type_siteId: { type, siteId } },
|
|
include: { tenant: true },
|
|
});
|
|
}
|
|
|
|
export async function getSiteNameByTypeAndSiteId(type: string, siteId: string) {
|
|
// Read-only public lookup (used by rendering, not auth). Replica-safe.
|
|
return dbRead.site.findUnique({
|
|
where: { type_siteId: { type, siteId } },
|
|
include: { tenant: { select: { name: true, slug: true } } },
|
|
// select: {
|
|
// id: true,
|
|
// tenantId: true,
|
|
// name: true,
|
|
// siteId: true,
|
|
// isActive: true,
|
|
// branding: true,
|
|
// copy: true,
|
|
// },
|
|
});
|
|
}
|
|
|
|
// Get all sites for a tenant
|
|
export async function getSitesByTenantId(tenantId: string) {
|
|
// Tenant site listing for admin/public rendering — read-only.
|
|
return dbRead.site.findMany({
|
|
where: { tenantId },
|
|
orderBy: { createdAt: "desc" },
|
|
include: { createdByUser: { select: { email: true, firstName: true, lastName: true } } },
|
|
});
|
|
}
|
|
|
|
// Get sites by type for a tenant
|
|
export async function getSitesByTenantIdAndType(tenantId: string, type: string) {
|
|
// Tenant site listing filtered by type — read-only.
|
|
return dbRead.site.findMany({
|
|
where: { tenantId, type },
|
|
orderBy: { createdAt: "desc" },
|
|
});
|
|
}
|
|
|
|
// Check if siteId is available for a type
|
|
export async function isSiteIdAvailable(type: string, siteId: string): Promise<boolean> {
|
|
const existing = await db.site.findUnique({
|
|
where: { type_siteId: { type, siteId } },
|
|
select: { id: true },
|
|
});
|
|
return !existing;
|
|
}
|
|
|
|
// Create a new site
|
|
export async function createSite(data: {
|
|
tenantId: string;
|
|
type: string;
|
|
siteId: string;
|
|
name: string;
|
|
serverName: string;
|
|
serverHost: string;
|
|
isActive: boolean;
|
|
serverResolution: string;
|
|
createdByUserId?: string;
|
|
branding?: string;
|
|
copy?: string;
|
|
}) {
|
|
return db.site.create({
|
|
data: {
|
|
tenantId: data.tenantId,
|
|
type: data.type,
|
|
siteId: data.siteId,
|
|
name: data.name,
|
|
serverName: data.serverName,
|
|
serverHost: data.serverHost,
|
|
serverResolution: data.serverResolution,
|
|
isActive: data.isActive,
|
|
createdByUserId: data.createdByUserId,
|
|
branding: data.branding ?? "{}",
|
|
copy: data.copy ?? "{}",
|
|
},
|
|
include: { tenant: true },
|
|
});
|
|
}
|
|
|
|
export async function updateSite(
|
|
scope: { id: string; tenantId: string },
|
|
data: {
|
|
name?: string;
|
|
siteId?: string;
|
|
isActive?: boolean;
|
|
branding?: string;
|
|
copy?: string;
|
|
}
|
|
) {
|
|
const result = await db.site.updateMany({
|
|
where: scope,
|
|
data,
|
|
});
|
|
if (result.count !== 1) {
|
|
throw new Error("Site not found for tenant scope.");
|
|
}
|
|
return db.site.findFirstOrThrow({
|
|
where: scope,
|
|
});
|
|
}
|
|
|
|
export async function deleteSite(scope: { id: string; tenantId: string }) {
|
|
const item = await db.site.findFirst({ where: scope });
|
|
if (!item) {
|
|
throw new Error("Site not found for tenant scope.");
|
|
}
|
|
const result = await db.site.deleteMany({ where: scope });
|
|
if (result.count !== 1) {
|
|
throw new Error("Site not found for tenant scope.");
|
|
}
|
|
return item;
|
|
}
|
|
|
|
// Get sites with pagination
|
|
export async function getSitesWithPagination({
|
|
tenantId,
|
|
type,
|
|
pagination,
|
|
filters,
|
|
}: {
|
|
tenantId: string;
|
|
type?: string;
|
|
pagination?: { page: number; pageSize: number };
|
|
filters?: { q?: string };
|
|
}) {
|
|
let where: Prisma.SiteWhereInput = { tenantId };
|
|
|
|
if (type) {
|
|
where.type = type;
|
|
}
|
|
|
|
if (filters?.q) {
|
|
where = {
|
|
...where,
|
|
OR: [{ name: { contains: filters.q, mode: "insensitive" } }, { siteId: { contains: filters.q, mode: "insensitive" } }],
|
|
};
|
|
}
|
|
|
|
// Paginated listing for admin grid — read-only, replica-safe.
|
|
const items = await dbRead.site.findMany({
|
|
take: pagination?.pageSize,
|
|
skip: pagination ? pagination.pageSize * (pagination.page - 1) : undefined,
|
|
where,
|
|
orderBy: { createdAt: "desc" },
|
|
include: {
|
|
createdByUser: { select: { email: true, firstName: true, lastName: true } },
|
|
},
|
|
});
|
|
|
|
if (!pagination) {
|
|
return { items };
|
|
}
|
|
|
|
const totalItems = await dbRead.site.count({ where });
|
|
|
|
return {
|
|
items,
|
|
pagination: {
|
|
page: pagination.page,
|
|
pageSize: pagination.pageSize,
|
|
totalItems,
|
|
totalPages: Math.ceil(totalItems / pagination.pageSize),
|
|
},
|
|
};
|
|
}
|