feat(housekeeping): deliver system vertical
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
import "server-only";
|
||||
|
||||
import { PERMS } from "@/lib/permission-slugs";
|
||||
import { authorizeHousekeeping } from "../../../foundation/authorization";
|
||||
import {
|
||||
anyCapability,
|
||||
fail,
|
||||
type HousekeepingQuery,
|
||||
ok,
|
||||
} from "../../../foundation/contracts";
|
||||
|
||||
export interface SystemSettingRow {
|
||||
readonly key: string;
|
||||
readonly value: string;
|
||||
readonly comment?: string | null;
|
||||
}
|
||||
|
||||
export interface SystemEmulatorTextResult {
|
||||
readonly rows: readonly SystemSettingRow[];
|
||||
readonly total: number;
|
||||
}
|
||||
|
||||
export interface SystemConfigurationAdapters {
|
||||
loadWebsiteSettings(): Promise<readonly SystemSettingRow[]>;
|
||||
loadEmulatorSettings(): Promise<readonly SystemSettingRow[]>;
|
||||
loadEmulatorTexts(): Promise<SystemEmulatorTextResult>;
|
||||
}
|
||||
|
||||
export type SystemConfigurationQueryInput =
|
||||
| { readonly routeId: "system.configuration.settings" }
|
||||
| { readonly routeId: "system.configuration.emulator" };
|
||||
|
||||
export type SystemConfigurationQueryData =
|
||||
| {
|
||||
readonly kind: "settings";
|
||||
readonly settings: readonly SystemSettingRow[];
|
||||
readonly partialDependencies: readonly string[];
|
||||
}
|
||||
| {
|
||||
readonly kind: "emulator";
|
||||
readonly settings: readonly SystemSettingRow[];
|
||||
readonly texts: readonly SystemSettingRow[];
|
||||
readonly textsTotal: number;
|
||||
readonly partialDependencies: readonly string[];
|
||||
};
|
||||
|
||||
const configurationCapability = anyCapability(PERMS.SETTINGS_VIEW);
|
||||
|
||||
function unavailable(correlationId: string) {
|
||||
return fail(
|
||||
"DEPENDENCY_UNAVAILABLE",
|
||||
"errors.housekeeping.dependencyUnavailable",
|
||||
correlationId,
|
||||
);
|
||||
}
|
||||
|
||||
export function createSystemConfigurationQuery(
|
||||
adapters: SystemConfigurationAdapters,
|
||||
): HousekeepingQuery<
|
||||
SystemConfigurationQueryInput,
|
||||
SystemConfigurationQueryData
|
||||
> {
|
||||
return {
|
||||
id: "system.configuration.query",
|
||||
owner: "system",
|
||||
capability: configurationCapability,
|
||||
async run(context, input) {
|
||||
const authorization = authorizeHousekeeping(
|
||||
context,
|
||||
configurationCapability,
|
||||
);
|
||||
if (!authorization.ok) return authorization;
|
||||
const correlationId = authorization.correlationId;
|
||||
|
||||
if (input.routeId === "system.configuration.settings") {
|
||||
try {
|
||||
return ok(
|
||||
{
|
||||
kind: "settings" as const,
|
||||
settings: await adapters.loadWebsiteSettings(),
|
||||
partialDependencies: [],
|
||||
},
|
||||
correlationId,
|
||||
);
|
||||
} catch {
|
||||
return unavailable(correlationId);
|
||||
}
|
||||
}
|
||||
|
||||
const [settingsResult, textsResult] = await Promise.allSettled([
|
||||
adapters.loadEmulatorSettings(),
|
||||
adapters.loadEmulatorTexts(),
|
||||
]);
|
||||
if (
|
||||
settingsResult.status === "rejected" &&
|
||||
textsResult.status === "rejected"
|
||||
) {
|
||||
return unavailable(correlationId);
|
||||
}
|
||||
|
||||
const partialDependencies: string[] = [];
|
||||
if (settingsResult.status === "rejected") {
|
||||
partialDependencies.push("emulator-settings");
|
||||
}
|
||||
if (textsResult.status === "rejected") {
|
||||
partialDependencies.push("emulator-texts");
|
||||
}
|
||||
const textData =
|
||||
textsResult.status === "fulfilled"
|
||||
? textsResult.value
|
||||
: { rows: [], total: 0 };
|
||||
|
||||
return ok(
|
||||
{
|
||||
kind: "emulator",
|
||||
settings:
|
||||
settingsResult.status === "fulfilled" ? settingsResult.value : [],
|
||||
texts: textData.rows,
|
||||
textsTotal: textData.total,
|
||||
partialDependencies,
|
||||
},
|
||||
correlationId,
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export const systemConfigurationAdapters: SystemConfigurationAdapters = {
|
||||
async loadWebsiteSettings() {
|
||||
const [{ asc }, { db, WebsiteSetting }] = await Promise.all([
|
||||
import("drizzle-orm"),
|
||||
import("@/lib/db"),
|
||||
]);
|
||||
return db
|
||||
.select({
|
||||
key: WebsiteSetting.key,
|
||||
value: WebsiteSetting.value,
|
||||
comment: WebsiteSetting.comment,
|
||||
})
|
||||
.from(WebsiteSetting)
|
||||
.orderBy(asc(WebsiteSetting.key));
|
||||
},
|
||||
async loadEmulatorSettings() {
|
||||
const [{ asc }, { db, EmulatorSettings }] = await Promise.all([
|
||||
import("drizzle-orm"),
|
||||
import("@/lib/db"),
|
||||
]);
|
||||
return db
|
||||
.select({ key: EmulatorSettings.key, value: EmulatorSettings.value })
|
||||
.from(EmulatorSettings)
|
||||
.orderBy(asc(EmulatorSettings.key));
|
||||
},
|
||||
async loadEmulatorTexts() {
|
||||
const [{ asc, count }, { db, EmulatorTexts }] = await Promise.all([
|
||||
import("drizzle-orm"),
|
||||
import("@/lib/db"),
|
||||
]);
|
||||
const [rows, totals] = await Promise.all([
|
||||
db
|
||||
.select({ key: EmulatorTexts.key, value: EmulatorTexts.value })
|
||||
.from(EmulatorTexts)
|
||||
.orderBy(asc(EmulatorTexts.key))
|
||||
.limit(300),
|
||||
db.select({ total: count() }).from(EmulatorTexts),
|
||||
]);
|
||||
return { rows, total: Number(totals[0]?.total ?? 0) };
|
||||
},
|
||||
};
|
||||
|
||||
export const systemConfigurationQuery = createSystemConfigurationQuery(
|
||||
systemConfigurationAdapters,
|
||||
);
|
||||
Reference in New Issue
Block a user