Products: images need https addresses; lowering a rating waits for review; library shows creators
CI / test (push) Successful in 50s

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
dhkatzandClaude Opus 5.5 committed 2026-10-29 19:14:12 -07:00
1 parent 51d5bb5ff3
commit d57674d90c
4 files changed
+14 -17

No files matched your search

+1 -1
View File
@@ -704,7 +704,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),
product: productView(l.product, l.creator),
stayOn: l.stayOn,
addedAt: l.addedAt.toISOString(),
})),
+2 -2
View File
@@ -41,8 +41,8 @@ const options: sanitize.IOptions = {
attribs: { ...attribs, rel: "nofollow ugc noopener noreferrer", target: "_blank" },
}),
},
// Images whose address was refused are dropped.
exclusiveFilter: (frame) => frame.tag === "img" && !frame.attribs.src,
// Images need an absolute https address (scheme rules don't apply to relative ones); others are dropped.
exclusiveFilter: (frame) => frame.tag === "img" && !/^https:\/\//i.test(frame.attribs.src ?? ""),
disallowedTagsMode: "discard",
};
+5 -11
View File
@@ -271,16 +271,9 @@ export class Products {
}
if (input.rating !== undefined) {
if (input.rating === "adult") set.rating = "adult";
else if (input.rating === "general" && p.rating === "adult") {
// Lowering is reviewed first (design.md); refused for now unless every revision is general.
const [adultRev] = await this.db
.select({ n: productRevision.number })
.from(productRevision)
.where(and(eq(productRevision.productId, id), eq(productRevision.rating, "adult")))
.limit(1);
if (adultRev) throw new ProductError(400, "invalid", "A product with adult revisions stays adult.");
set.rating = "general";
}
else if (input.rating === "general" && p.rating === "adult")
// Lowering is reviewed by moderators first (design.md); until that exists, it's refused.
throw new ProductError(400, "review_needed", "Lowering a rating needs a moderator's review.");
}
const [updated] = await this.db.update(product).set(set).where(eq(product.id, id)).returning();
return updated!;
@@ -301,9 +294,10 @@ export class Products {
async library(personId: string) {
return this.db
.select({ product, stayOn: library.stayOn, addedAt: library.addedAt })
.select({ product, stayOn: library.stayOn, addedAt: library.addedAt, creator: user.displayUsername })
.from(library)
.innerJoin(product, eq(product.id, library.productId))
.innerJoin(user, eq(user.id, product.creatorId))
.where(eq(library.userId, personId))
.orderBy(desc(library.addedAt));
}