105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
import { avatarUrl } from '$lib/avatar';
|
|
import { parseLoadoutDraft } from '$lib/builder/loadout';
|
|
import { summarizeLoadout } from '$lib/builder/loadout-summary';
|
|
import { getDatabase } from '$lib/server/database';
|
|
import { loadSharedBuildSummaryCatalog } from '$lib/server/shared-build-summary';
|
|
|
|
export type SharedBuildAccessPolicy =
|
|
{ kind: 'viewer-page'; viewerId: string | null } | { kind: 'public-preview' };
|
|
type BuildVisibility = 'public' | 'unlisted' | 'private';
|
|
|
|
export async function loadSharedBuildProjection(
|
|
slug: string,
|
|
access: SharedBuildAccessPolicy,
|
|
) {
|
|
const database = await getDatabase();
|
|
const build = await (
|
|
await database.prepare(`
|
|
SELECT builds.*,COALESCE(user_profiles.display_name,users.username,'Deleted Agent') AS author,
|
|
user_profiles.public_slug,
|
|
COALESCE(user_profiles.is_public,1) AS profile_is_public,deleted_accounts.user_id AS deleted_user_id,
|
|
user_avatars.source AS avatar_source,user_avatars.value AS avatar_value,
|
|
user_avatars.updated_at AS avatar_updated_at
|
|
FROM builds
|
|
JOIN users ON users.id=builds.owner_id
|
|
LEFT JOIN user_profiles ON user_profiles.user_id=users.id
|
|
LEFT JOIN deleted_accounts ON deleted_accounts.user_id=users.id
|
|
LEFT JOIN user_avatars ON user_avatars.user_id=users.id
|
|
WHERE builds.slug=?
|
|
`)
|
|
).get(slug);
|
|
|
|
if (!build) return null;
|
|
|
|
const ownerId = String(build.owner_id);
|
|
const visibility = String(build.visibility) as BuildVisibility;
|
|
const viewerId = access.kind === 'viewer-page' ? access.viewerId : null;
|
|
const accessible =
|
|
access.kind === 'public-preview'
|
|
? visibility === 'public' || visibility === 'unlisted'
|
|
: visibility === 'public' ||
|
|
visibility === 'unlisted' ||
|
|
(visibility === 'private' && ownerId === viewerId);
|
|
if (!accessible) return null;
|
|
|
|
let loadout;
|
|
try {
|
|
loadout = parseLoadoutDraft(JSON.parse(String(build.loadout_json)));
|
|
} catch {
|
|
return null;
|
|
}
|
|
if (!loadout) return null;
|
|
|
|
const [gear, weapons, chips, protocols, brands, summaryCatalog] =
|
|
await Promise.all([
|
|
(
|
|
await database.prepare(
|
|
'SELECT id,name,slot,tier,base_armor_min FROM gear',
|
|
)
|
|
).all(),
|
|
(
|
|
await database.prepare(
|
|
'SELECT id,name,category,is_exotic,rpm,magazine,reload_speed,damage_type,exotic_talent_id FROM weapons',
|
|
)
|
|
).all(),
|
|
(await database.prepare('SELECT id,name FROM skill_chip_sets')).all(),
|
|
(
|
|
await database.prepare('SELECT id,name,quality FROM os_protocols')
|
|
).all(),
|
|
(await database.prepare('SELECT id,name FROM brand_sets')).all(),
|
|
loadSharedBuildSummaryCatalog(database),
|
|
]);
|
|
const summary = summarizeLoadout(loadout, summaryCatalog);
|
|
|
|
return {
|
|
build: {
|
|
id: String(build.id),
|
|
title: String(build.title),
|
|
slug: String(build.slug),
|
|
visibility,
|
|
author: String(build.author),
|
|
ownerId,
|
|
authorPublicSlug: build.public_slug ? String(build.public_slug) : null,
|
|
profileAvailable:
|
|
Boolean(build.profile_is_public) && !build.deleted_user_id,
|
|
authorAvatarUrl: avatarUrl(
|
|
build.avatar_source,
|
|
build.avatar_value,
|
|
ownerId,
|
|
build.avatar_updated_at,
|
|
),
|
|
owner: ownerId === viewerId,
|
|
updatedAt: String(build.updated_at),
|
|
},
|
|
loadout,
|
|
gear,
|
|
weapons,
|
|
chips,
|
|
protocols,
|
|
brands,
|
|
summary,
|
|
attributes: summaryCatalog.attributes,
|
|
talents: summaryCatalog.talents,
|
|
};
|
|
}
|