Revisions with an IMVU parent store its public info (image, category path, gender) from IMVU's product API, looked up after registering and in a periodic pass. Product views gain parent, image and categories; GET /products takes category and limit. The website shows the image on cards and product pages. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
d57674d90c
commit
6668b55117
15 files changed
+2026
-29
No files matched your search
+21
-8
@@ -2,7 +2,7 @@
|
||||
// origin (Next.js rewrites /api to here), so session cookies are first-party; T5DE's proxy calls it with a bearer
|
||||
// token.
|
||||
import { Elysia, t } from "elysia";
|
||||
import { and, desc, eq, ilike, inArray, ne, or, sql, count, schema, type Database } from "@t5de/db";
|
||||
import { and, desc, eq, ilike, inArray, ne, or, sql, count, schema, type Database, type ParentInfo } from "@t5de/db";
|
||||
import type { Auth } from "./auth";
|
||||
import { AgeError, AgeService } from "./age";
|
||||
import { imvuAgeProvider, imvuResult } from "./age/imvu";
|
||||
@@ -76,7 +76,7 @@ class Limiter {
|
||||
export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms: roomsService, apiURL }: Deps) {
|
||||
const age = ageService ?? new AgeService(db, [imvuAgeProvider(imvu)]);
|
||||
const signer = new Signer(db, apiURL ?? "http://localhost:4101");
|
||||
const products = new Products(db, signer);
|
||||
const products = new Products(db, signer, imvu);
|
||||
const rooms = roomsService ?? new Rooms(db, imvu);
|
||||
const realtime =
|
||||
rt ??
|
||||
@@ -178,10 +178,12 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
}
|
||||
};
|
||||
|
||||
/** `latest`: the latest revision's parent and its info (the image and categories are the parent's). */
|
||||
const productView = (
|
||||
p: typeof schema.product.$inferSelect,
|
||||
creator?: string | null,
|
||||
creatorUsername?: string | null,
|
||||
latest?: { parent: number | null; parentInfo: ParentInfo | null } | null,
|
||||
) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
@@ -190,6 +192,9 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
latest: p.latest,
|
||||
creator: creator ?? creatorUsername ?? "",
|
||||
creatorUsername: creatorUsername ?? "",
|
||||
parent: latest?.parent ?? 0,
|
||||
image: latest?.parentInfo?.image ?? null,
|
||||
categories: latest?.parentInfo?.categories ?? [],
|
||||
createdAt: p.createdAt.toISOString(),
|
||||
updatedAt: p.updatedAt.toISOString(),
|
||||
});
|
||||
@@ -616,10 +621,17 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
"/products",
|
||||
async ({ person, query }) => {
|
||||
const adult = await personAdult(person);
|
||||
const rows = await products.list({ q: query.q, creator: query.creator, adult });
|
||||
return { products: rows.map((r) => productView(r.product, r.creator, r.creatorUsername)) };
|
||||
const rows = await products.list({ ...query, adult });
|
||||
return { products: rows.map((r) => productView(r.product, r.creator, r.creatorUsername, r)) };
|
||||
},
|
||||
{
|
||||
query: t.Object({
|
||||
q: t.Optional(t.String({ maxLength: 100 })),
|
||||
creator: t.Optional(t.String({ maxLength: 64 })),
|
||||
category: t.Optional(t.Numeric({ minimum: 1, maximum: 2_147_483_647, multipleOf: 1 })),
|
||||
limit: t.Optional(t.Numeric({ minimum: 1, maximum: 200, multipleOf: 1 })),
|
||||
}),
|
||||
},
|
||||
{ query: t.Object({ q: t.Optional(t.String({ maxLength: 100 })), creator: t.Optional(t.String({ maxLength: 64 })) }) },
|
||||
)
|
||||
.get(
|
||||
"/products/:id",
|
||||
@@ -627,8 +639,9 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
const adult = await personAdult(person);
|
||||
const p = await productCall(() => products.get(params.id, adult));
|
||||
const lib = person ? await products.inLibrary(person.id, params.id) : undefined;
|
||||
const latest = p.revisions.find((r) => r.number === p.product.latest);
|
||||
return {
|
||||
product: productView(p.product, p.creator, p.creatorUsername),
|
||||
product: productView(p.product, p.creator, p.creatorUsername, latest),
|
||||
revisions: p.revisions.map((r) => ({
|
||||
number: r.number,
|
||||
rating: r.rating,
|
||||
@@ -651,7 +664,7 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
async ({ me, params, body }) => {
|
||||
const p = await productCall(() => products.update(me.id, params.id, body));
|
||||
await audited(me.id, "product.edit", p.id, { fields: Object.keys(body) });
|
||||
return { product: productView(p) };
|
||||
return { product: productView(p, undefined, undefined, await products.latestParent(p)) };
|
||||
},
|
||||
{
|
||||
signedIn: true,
|
||||
@@ -704,7 +717,7 @@ export function createApp({ db, auth, imvu, realtime: rt, age: ageService, rooms
|
||||
"/library",
|
||||
async ({ me }) => ({
|
||||
library: (await products.library(me.id)).map((l) => ({
|
||||
product: productView(l.product, l.creator),
|
||||
product: productView(l.product, l.creator, undefined, l),
|
||||
stayOn: l.stayOn,
|
||||
addedAt: l.addedAt.toISOString(),
|
||||
})),
|
||||
|
||||
Reference in new issue
Block a user