fix: resolve TypeScript and lint issues
CI / check (push) Successful in 26s
CI / release (push) Skipped
CI / deploy (push) Successful in 58s

- Fix proxy routes to use resolveImagerBase instead of removed resolveUpstreamBase
- Fix avatarImageUrl type signature to use AvatarOptions
- Run biome formatter
This commit is contained in:
openhands committed 2026-08-09 19:42:02 +02:00
1 parent fc7e6ca248
commit 7a2c0fd4d4
19 files changed
+86 -164

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
import { eq } from "drizzle-orm";
import { WebsiteSetting } from "@/db/schema";
import { db } from "./src/lib/db";
async function main() {
const result = await db
.select()
.from(WebsiteSetting)
.where(eq(WebsiteSetting.key, "habbo_imaging_url"));
console.log("Current:", result);
if (result[0]?.value !== "/imaging") {
await db
.update(WebsiteSetting)
.set({ value: "/imaging" })
.where(eq(WebsiteSetting.key, "habbo_imaging_url"));
console.log("Updated to /imaging");
} else {
console.log("Already correct");
}
process.exit(0);
}
main().catch((e) => {
console.error(e);
process.exit(1);
});
+15 -22
View File
@@ -8,7 +8,6 @@ import { ContentCard, EmptyState, OnlineBadge } from "@/components/public/ui";
import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth";
import { db, MessengerFriendships, User } from "@/lib/db"; import { db, MessengerFriendships, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { siteSettings } from "@/lib/services/site-settings";
export const metadata = { title: "Friends" }; export const metadata = { title: "Friends" };
@@ -66,26 +65,20 @@ export default async function FriendsPage({
), ),
); );
const [friends, imagerBase] = await Promise.all([ const friends = friendIds.length
friendIds.length ? await db
? db .select({
.select({ id: User.id,
id: User.id, username: User.username,
username: User.username, look: User.look,
look: User.look, motto: User.motto,
motto: User.motto, online: User.online,
online: User.online, })
}) .from(User)
.from(User) .where(inArray(User.id, friendIds))
.where(inArray(User.id, friendIds)) .orderBy(asc(User.username))
.orderBy(asc(User.username)) .catch(() => [])
.catch(() => []) : [];
: Promise.resolve([]),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
]);
const errorMessage = const errorMessage =
error === "not_found" error === "not_found"
@@ -125,7 +118,7 @@ export default async function FriendsPage({
) : ( ) : (
<div className="card-grid sm-2 lg-3" style={{ padding: "1rem" }}> <div className="card-grid sm-2 lg-3" style={{ padding: "1rem" }}>
{friends.map((friend) => { {friends.map((friend) => {
const avatar = avatarImageUrl(imagerBase ?? "", friend.look, { const avatar = avatarImageUrl(friend.look, {
size: "s", size: "s",
headOnly: true, headOnly: true,
}); });
+1 -7
View File
@@ -6,7 +6,6 @@ import { ContentCard, EmptyState, StatBlock } from "@/components/public/ui";
import { db, Guilds, GuildsMembers, User } from "@/lib/db"; import { db, Guilds, GuildsMembers, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { formatDate } from "@/lib/format-date"; import { formatDate } from "@/lib/format-date";
import { siteSettings } from "@/lib/services/site-settings";
type GuildView = { type GuildView = {
id: number; id: number;
@@ -98,11 +97,6 @@ export default async function GuildPage({
users = []; users = [];
} }
const imagerBase = await siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
);
const usersById = new Map(users.map((u) => [u.id, u])); const usersById = new Map(users.map((u) => [u.id, u]));
const sinceById = new Map(memberRows.map((m) => [m.userId, m.memberSince])); const sinceById = new Map(memberRows.map((m) => [m.userId, m.memberSince]));
@@ -211,7 +205,7 @@ export default async function GuildPage({
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
<img <img
className="avatar" className="avatar"
src={avatarImageUrl(imagerBase ?? "", m.look, { size: "l" })} src={avatarImageUrl(m.look, { size: "l" })}
alt={`${m.username} avatar`} alt={`${m.username} avatar`}
width={50} width={50}
height={75} height={75}
+9 -16
View File
@@ -4,7 +4,6 @@ import { getTranslations } from "next-intl/server";
import { ContentCard, EmptyState, RankBadge } from "@/components/public/ui"; import { ContentCard, EmptyState, RankBadge } from "@/components/public/ui";
import { db, User, UsersCurrency, UsersSettings } from "@/lib/db"; import { db, User, UsersCurrency, UsersSettings } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { siteSettings } from "@/lib/services/site-settings";
export const metadata = { title: "Leaderboard" }; export const metadata = { title: "Leaderboard" };
@@ -158,20 +157,14 @@ export default async function LeaderboardPage({
: "credits"; : "credits";
const activeTab = TABS.find((tab) => tab.key === active) ?? TABS[0]; const activeTab = TABS.find((tab) => tab.key === active) ?? TABS[0];
const [rows, imagerBase] = await Promise.all([ const rows = await (active === "credits"
active === "credits" ? loadCreditsRows()
? loadCreditsRows() : active === "diamonds" || active === "duckets"
: active === "diamonds" || active === "duckets" ? // eslint-disable-next-line security/detect-object-injection -- active validated as "diamonds"|"duckets" in this branch
? // eslint-disable-next-line security/detect-object-injection -- active validated as "diamonds"|"duckets" in this branch loadCurrencyRows(CURRENCY_TYPE[active])
loadCurrencyRows(CURRENCY_TYPE[active]) : loadSettingsRows(
: loadSettingsRows( SETTINGS_FIELD[active as keyof typeof SETTINGS_FIELD],
SETTINGS_FIELD[active as keyof typeof SETTINGS_FIELD], ));
),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
]);
const valueOnly = const valueOnly =
active === "achievement" || active === "achievement" ||
@@ -213,7 +206,7 @@ export default async function LeaderboardPage({
</thead> </thead>
<tbody> <tbody>
{rows.map((row, i) => { {rows.map((row, i) => {
const avatar = avatarImageUrl(imagerBase ?? "", row.look, { const avatar = avatarImageUrl(row.look, {
size: "s", size: "s",
headOnly: true, headOnly: true,
}); });
+3 -9
View File
@@ -18,17 +18,11 @@ import { siteSettings } from "@/lib/services/site-settings";
export default async function LoginPage() { export default async function LoginPage() {
const t = await getTranslations("pages.login"); const t = await getTranslations("pages.login");
const th = await getTranslations("header"); const th = await getTranslations("header");
const [hotelName, imagerRaw, cfg, logo] = await Promise.all([ const [hotelName, cfg, logo] = await Promise.all([
resolveHotelName(), resolveHotelName(),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
captchaConfig(), captchaConfig(),
siteSettings.get("radio_social_discord", ""),
siteSettings.get("cms_logo", ""), siteSettings.get("cms_logo", ""),
]); ]);
const imager = imagerRaw ?? "https://www.habbo.com/habbo-imaging/avatarimage";
const nonce = (await headers()).get("x-nonce") ?? undefined; const nonce = (await headers()).get("x-nonce") ?? undefined;
const [online, recentUsers, latestUsers] = await Promise.all([ const [online, recentUsers, latestUsers] = await Promise.all([
@@ -234,7 +228,7 @@ export default async function LoginPage() {
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
size: "s", size: "s",
@@ -305,7 +299,7 @@ export default async function LoginPage() {
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
size: "s", size: "s",
+3 -10
View File
@@ -19,8 +19,8 @@ import {
WebsiteLoginLogs, WebsiteLoginLogs,
WebsiteSetting, WebsiteSetting,
} from "@/lib/db"; } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format";
import { resolveHotelName } from "@/lib/hotel-name"; import { resolveHotelName } from "@/lib/hotel-name";
import { getAvatarUrl } from "@/lib/imager";
import { siteSettings } from "@/lib/services/site-settings"; import { siteSettings } from "@/lib/services/site-settings";
import CopyReferralButton from "./CopyReferralButton"; import CopyReferralButton from "./CopyReferralButton";
@@ -83,7 +83,6 @@ export default async function MePage({
const [ const [
userRows, userRows,
imagerBase,
hotelName, hotelName,
neededRows, neededRows,
amountRows, amountRows,
@@ -111,10 +110,6 @@ export default async function MePage({
.from(User) .from(User)
.where(eq(User.id, userId)) .where(eq(User.id, userId))
.limit(1), .limit(1),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
resolveHotelName(), resolveHotelName(),
db db
.select({ value: WebsiteSetting.value }) .select({ value: WebsiteSetting.value })
@@ -273,9 +268,7 @@ export default async function MePage({
: "Never"; : "Never";
const referralLink = `/register?ref=${encodeURIComponent(user.username)}`; const referralLink = `/register?ref=${encodeURIComponent(user.username)}`;
const imager = const avatarFull = getAvatarUrl(user.look, {
imagerBase ?? "https://www.habbo.com/habbo-imaging/avatarimage";
const avatarFull = avatarImageUrl(imager, user.look, {
size: "l", size: "l",
direction: 2, direction: 2,
}); });
@@ -505,7 +498,7 @@ export default async function MePage({
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, friend.look, { src={getAvatarUrl(friend.look, {
size: "s", size: "s",
headOnly: true, headOnly: true,
})} })}
+3 -10
View File
@@ -19,7 +19,6 @@ import {
} from "@/lib/db"; } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { formatDate } from "@/lib/format-date"; import { formatDate } from "@/lib/format-date";
import { siteSettings } from "@/lib/services/site-settings";
type SearchParams = Promise<{ type SearchParams = Promise<{
accepted?: string; accepted?: string;
@@ -65,10 +64,9 @@ export default async function MessagesPage({
sendedOn: number; sendedOn: number;
}[] = []; }[] = [];
let friendships: { userOneId: number; userTwoId: number }[] = []; let friendships: { userOneId: number; userTwoId: number }[] = [];
let imagerBase = "https://www.habbo.com/habbo-imaging/avatarimage";
try { try {
const [reqRows, msgRows, friendRows, base] = await Promise.all([ const [reqRows, msgRows, friendRows] = await Promise.all([
db db
.select({ .select({
id: MessengerFriendrequests.id, id: MessengerFriendrequests.id,
@@ -101,15 +99,10 @@ export default async function MessagesPage({
eq(MessengerFriendships.userTwoId, userId), eq(MessengerFriendships.userTwoId, userId),
), ),
), ),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
]); ]);
requests = reqRows; requests = reqRows;
messages = msgRows; messages = msgRows;
friendships = friendRows; friendships = friendRows;
if (base) imagerBase = base;
} catch { } catch {
requests = []; requests = [];
messages = []; messages = [];
@@ -277,7 +270,7 @@ export default async function MessagesPage({
<div className="grid" style={{ padding: "1rem", gap: "0.75rem" }}> <div className="grid" style={{ padding: "1rem", gap: "0.75rem" }}>
{requests.map((req) => { {requests.map((req) => {
const from = userById.get(req.userFromId); const from = userById.get(req.userFromId);
const avatar = avatarImageUrl(imagerBase, from?.look ?? "", { const avatar = avatarImageUrl(from?.look ?? "", {
size: "s", size: "s",
headOnly: true, headOnly: true,
}); });
@@ -367,7 +360,7 @@ export default async function MessagesPage({
<div className="grid" style={{ padding: "1rem", gap: "0.75rem" }}> <div className="grid" style={{ padding: "1rem", gap: "0.75rem" }}>
{messages.map((msg) => { {messages.map((msg) => {
const from = userById.get(msg.userFromId); const from = userById.get(msg.userFromId);
const avatar = avatarImageUrl(imagerBase, from?.look ?? "", { const avatar = avatarImageUrl(from?.look ?? "", {
size: "s", size: "s",
headOnly: true, headOnly: true,
}); });
+3 -10
View File
@@ -22,15 +22,10 @@ import { captchaConfig } from "@/lib/services/captcha";
import { siteSettings } from "@/lib/services/site-settings"; import { siteSettings } from "@/lib/services/site-settings";
async function getHotelData() { async function getHotelData() {
const [hotelName, imagerRaw, logo] = await Promise.all([ const [hotelName, logo] = await Promise.all([
resolveHotelName(), resolveHotelName(),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
siteSettings.get("cms_logo", ""), siteSettings.get("cms_logo", ""),
]); ]);
const imager = imagerRaw ?? "https://www.habbo.com/habbo-imaging/avatarimage";
const [ const [
online, online,
@@ -88,7 +83,6 @@ async function getHotelData() {
return { return {
hotelName, hotelName,
imager,
online, online,
users, users,
rooms, rooms,
@@ -108,7 +102,6 @@ export default async function Home() {
const th = await getTranslations("header"); const th = await getTranslations("header");
const { const {
hotelName, hotelName,
imager,
online, online,
users, users,
rooms, rooms,
@@ -486,7 +479,7 @@ export default async function Home() {
> >
<div className="relative overflow-visible"> <div className="relative overflow-visible">
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 3, direction: 3,
})} })}
@@ -664,7 +657,7 @@ export default async function Home() {
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
size: "s", size: "s",
+2 -9
View File
@@ -4,7 +4,6 @@ import { getTranslations } from "next-intl/server";
import { ContentCard, EmptyState, RankBadge } from "@/components/public/ui"; import { ContentCard, EmptyState, RankBadge } from "@/components/public/ui";
import { db } from "@/lib/db"; import { db } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { siteSettings } from "@/lib/services/site-settings";
type LeaderRow = { type LeaderRow = {
username: string; username: string;
@@ -36,13 +35,7 @@ async function loadRows(): Promise<
export default async function RadioLeaderboardPage() { export default async function RadioLeaderboardPage() {
const t = await getTranslations("pages.radioLeaderboard"); const t = await getTranslations("pages.radioLeaderboard");
const [rows, imagerBase] = await Promise.all([ const rows = await loadRows();
loadRows(),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
]);
return ( return (
<main style={{ display: "grid", gap: "1.5rem" }}> <main style={{ display: "grid", gap: "1.5rem" }}>
@@ -63,7 +56,7 @@ export default async function RadioLeaderboardPage() {
</thead> </thead>
<tbody> <tbody>
{rows.map((row, i) => { {rows.map((row, i) => {
const avatar = avatarImageUrl(imagerBase ?? "", row.look, { const avatar = avatarImageUrl(row.look, {
size: "s", size: "s",
headOnly: true, headOnly: true,
}); });
+2 -7
View File
@@ -7,7 +7,6 @@ import { auth } from "@/lib/auth";
import { db, RadioShouts, User } from "@/lib/db"; import { db, RadioShouts, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { formatDate } from "@/lib/format-date"; import { formatDate } from "@/lib/format-date";
import { siteSettings } from "@/lib/services/site-settings";
type SearchParams = Promise<{ posted?: string; error?: string }>; type SearchParams = Promise<{ posted?: string; error?: string }>;
@@ -35,17 +34,13 @@ export default async function RadioShoutsPage({
const t = await getTranslations("pages.radioShouts"); const t = await getTranslations("pages.radioShouts");
const { posted, error } = await searchParams; const { posted, error } = await searchParams;
const [shouts, imagerBase, session] = await Promise.all([ const [shouts, session] = await Promise.all([
db db
.select() .select()
.from(RadioShouts) .from(RadioShouts)
.orderBy(desc(RadioShouts.createdAt)) .orderBy(desc(RadioShouts.createdAt))
.limit(50) .limit(50)
.catch(() => []), .catch(() => []),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
auth(), auth(),
]); ]);
@@ -141,7 +136,7 @@ export default async function RadioShoutsPage({
{shouts.map((s) => { {shouts.map((s) => {
const author = authorById.get(Number(s.userId)); const author = authorById.get(Number(s.userId));
const authorAvatar = author const authorAvatar = author
? avatarImageUrl(imagerBase ?? "", author.look, { ? avatarImageUrl(author.look, {
size: "s", size: "s",
headOnly: true, headOnly: true,
}) })
+1 -7
View File
@@ -10,7 +10,6 @@ import {
} from "@/components/public/ui"; } from "@/components/public/ui";
import { db, User } from "@/lib/db"; import { db, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { siteSettings } from "@/lib/services/site-settings";
export const metadata = { title: "Rankings" }; export const metadata = { title: "Rankings" };
@@ -41,11 +40,6 @@ export default async function RankingsPage() {
users = []; users = [];
} }
const imagerBase = await siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
);
return ( return (
<main style={{ display: "grid", gap: "1.5rem" }}> <main style={{ display: "grid", gap: "1.5rem" }}>
<ContentCard icon="🏆" title={t("title")} subtitle={t("subtitle")} /> <ContentCard icon="🏆" title={t("title")} subtitle={t("subtitle")} />
@@ -56,7 +50,7 @@ export default async function RankingsPage() {
) : ( ) : (
<div className="card-grid sm-2 lg-3" style={{ padding: "1rem" }}> <div className="card-grid sm-2 lg-3" style={{ padding: "1rem" }}>
{users.map((u, i) => { {users.map((u, i) => {
const avatar = avatarImageUrl(imagerBase ?? "", u.look, { const avatar = avatarImageUrl(u.look, {
size: "m", size: "m",
}); });
return ( return (
+3 -9
View File
@@ -18,17 +18,11 @@ import { siteSettings } from "@/lib/services/site-settings";
export default async function RegisterPage() { export default async function RegisterPage() {
const th = await getTranslations("header"); const th = await getTranslations("header");
const tpr = await getTranslations("pages.register"); const tpr = await getTranslations("pages.register");
const [hotelName, imagerRaw, cfg, logo] = await Promise.all([ const [hotelName, cfg, logo] = await Promise.all([
resolveHotelName(), resolveHotelName(),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
captchaConfig(), captchaConfig(),
siteSettings.get("radio_social_discord", ""),
siteSettings.get("cms_logo", ""), siteSettings.get("cms_logo", ""),
]); ]);
const imager = imagerRaw ?? "https://www.habbo.com/habbo-imaging/avatarimage";
const nonce = (await headers()).get("x-nonce") ?? undefined; const nonce = (await headers()).get("x-nonce") ?? undefined;
const [online, recentUsers, latestUsers] = await Promise.all([ const [online, recentUsers, latestUsers] = await Promise.all([
@@ -231,7 +225,7 @@ export default async function RegisterPage() {
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
size: "s", size: "s",
@@ -302,7 +296,7 @@ export default async function RegisterPage() {
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
})} })}
+1 -8
View File
@@ -4,7 +4,6 @@ import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { db, Rooms, User } from "@/lib/db"; import { db, Rooms, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { siteSettings } from "@/lib/services/site-settings";
export const metadata: Metadata = { title: "Search" }; export const metadata: Metadata = { title: "Search" };
@@ -18,12 +17,6 @@ export default async function SearchPage({
const { q } = await searchParams; const { q } = await searchParams;
const query = q?.trim(); const query = q?.trim();
const imager =
(await siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
)) ?? "";
if (!query) { if (!query) {
return ( return (
<div <div
@@ -142,7 +135,7 @@ export default async function SearchPage({
}} }}
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
})} })}
+1 -10
View File
@@ -8,7 +8,6 @@ import { Reveal } from "@/components/motion-reveal";
import { auth } from "@/lib/auth"; import { auth } from "@/lib/auth";
import { db, User } from "@/lib/db"; import { db, User } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { siteSettings } from "@/lib/services/site-settings";
export default async function SettingsPage() { export default async function SettingsPage() {
const t = await getTranslations("pages.settings"); const t = await getTranslations("pages.settings");
@@ -41,15 +40,7 @@ export default async function SettingsPage() {
if (!user) redirect("/login"); if (!user) redirect("/login");
let imagerBase = "https://www.habbo.com/habbo-imaging/avatarimage"; const avatar = avatarImageUrl(user.look, { size: "l" });
try {
imagerBase =
(await siteSettings.get("habbo_imaging_url", imagerBase)) ?? imagerBase;
} catch {
/* fall back to default */
}
const avatar = avatarImageUrl(imagerBase, user.look, { size: "l" });
return ( return (
<div className="flex flex-col gap-6 pb-14"> <div className="flex flex-col gap-6 pb-14">
+4 -9
View File
@@ -26,7 +26,6 @@ import {
} from "@/lib/db"; } from "@/lib/db";
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { formatDate } from "@/lib/format-date"; import { formatDate } from "@/lib/format-date";
import { siteSettings } from "@/lib/services/site-settings";
type SearchParams = Promise<{ type SearchParams = Promise<{
friend?: string; friend?: string;
@@ -87,7 +86,7 @@ export default async function ProfilePage({
const { username } = await params; const { username } = await params;
const { friend, guestbook: guestbookStatus, error } = await searchParams; const { friend, guestbook: guestbookStatus, error } = await searchParams;
const [userRows, imagerBase, session] = await Promise.all([ const [userRows, session] = await Promise.all([
db db
.select({ .select({
id: User.id, id: User.id,
@@ -102,17 +101,13 @@ export default async function ProfilePage({
.from(User) .from(User)
.where(eq(User.username, username)) .where(eq(User.username, username))
.limit(1), .limit(1),
siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
),
auth(), auth(),
]); ]);
const user = userRows[0] ?? null; const user = userRows[0] ?? null;
if (!user) notFound(); if (!user) notFound();
const avatar = avatarImageUrl(imagerBase ?? "", user.look, { size: "l" }); const avatar = avatarImageUrl(user.look, { size: "l" });
const registered = formatDate(new Date(user.accountCreated * 1000), "date"); const registered = formatDate(new Date(user.accountCreated * 1000), "date");
const meId = Number(session?.user?.id); const meId = Number(session?.user?.id);
const isLoggedIn = Number.isInteger(meId) && meId > 0; const isLoggedIn = Number.isInteger(meId) && meId > 0;
@@ -484,7 +479,7 @@ export default async function ProfilePage({
> >
{/* eslint-disable-next-line @next/next/no-img-element */} {/* eslint-disable-next-line @next/next/no-img-element */}
<img <img
src={avatarImageUrl(imagerBase ?? "", f.look, { src={avatarImageUrl(f.look, {
size: "m", size: "m",
headOnly: true, headOnly: true,
})} })}
@@ -686,7 +681,7 @@ export default async function ProfilePage({
{guestbook.map((g) => { {guestbook.map((g) => {
const author = authorById.get(g.userId); const author = authorById.get(g.userId);
const authorAvatar = author const authorAvatar = author
? avatarImageUrl(imagerBase ?? "", author.look, { ? avatarImageUrl(author.look, {
size: "s", size: "s",
headOnly: true, headOnly: true,
}) })
+2 -2
View File
@@ -1,5 +1,5 @@
import { type NextRequest, NextResponse } from "next/server"; import { type NextRequest, NextResponse } from "next/server";
import { resolveUpstreamBase } from "@/lib/imager"; import { resolveImagerBase } from "@/lib/imager";
const FIGURE_RE = /^([a-z]{2}-\d+)(\.[a-z]{2}-\d+)*$/i; const FIGURE_RE = /^([a-z]{2}-\d+)(\.[a-z]{2}-\d+)*$/i;
const FIGURE_MAX_LEN = 512; const FIGURE_MAX_LEN = 512;
@@ -66,7 +66,7 @@ export async function GET(request: NextRequest) {
const imgFormat = searchParams.get("img_format"); const imgFormat = searchParams.get("img_format");
if (imgFormat) params.set("img_format", imgFormat); if (imgFormat) params.set("img_format", imgFormat);
const upstream = resolveUpstreamBase(); const upstream = resolveImagerBase();
const upstreamUrl = `${upstream}?${params.toString()}`; const upstreamUrl = `${upstream}?${params.toString()}`;
try { try {
+2 -2
View File
@@ -1,5 +1,5 @@
import { type NextRequest, NextResponse } from "next/server"; import { type NextRequest, NextResponse } from "next/server";
import { resolveUpstreamBase } from "@/lib/imager"; import { resolveImagerBase } from "@/lib/imager";
const FIGURE_RE = /^([a-z]{2}-\d+)(\.[a-z]{2}-\d+)*$/i; const FIGURE_RE = /^([a-z]{2}-\d+)(\.[a-z]{2}-\d+)*$/i;
const FIGURE_MAX_LEN = 512; const FIGURE_MAX_LEN = 512;
@@ -66,7 +66,7 @@ export async function GET(request: NextRequest) {
const imgFormat = searchParams.get("img_format"); const imgFormat = searchParams.get("img_format");
if (imgFormat) params.set("img_format", imgFormat); if (imgFormat) params.set("img_format", imgFormat);
const upstream = resolveUpstreamBase(); const upstream = resolveImagerBase();
const upstreamUrl = `${upstream}?${params.toString()}`; const upstreamUrl = `${upstream}?${params.toString()}`;
try { try {
+2 -8
View File
@@ -16,7 +16,6 @@ import {
import { avatarImageUrl } from "@/lib/format"; import { avatarImageUrl } from "@/lib/format";
import { resolveHotelName } from "@/lib/hotel-name"; import { resolveHotelName } from "@/lib/hotel-name";
import { canAccess, getApiAdminContext, PERMS } from "@/lib/permissions"; import { canAccess, getApiAdminContext, PERMS } from "@/lib/permissions";
import { siteSettings } from "@/lib/services/site-settings";
function Currency({ function Currency({
icon, icon,
@@ -78,12 +77,7 @@ export async function TopHeader({ session }: { session: Session | null }) {
} }
} catch {} } catch {}
const imager = const avatar = avatarImageUrl(look, { headOnly: true, direction: 2 });
(await siteSettings.get(
"habbo_imaging_url",
"https://www.habbo.com/habbo-imaging/avatarimage",
)) ?? "";
const avatar = avatarImageUrl(imager, look, { headOnly: true, direction: 2 });
let showAdmin = false; let showAdmin = false;
let showMod = false; let showMod = false;
const ctx = await getApiAdminContext(); const ctx = await getApiAdminContext();
@@ -394,7 +388,7 @@ export async function TopHeader({ session }: { session: Session | null }) {
className="flex items-center gap-2 rounded-lg px-2 py-1 text-xs transition-colors hover:bg-white/10" className="flex items-center gap-2 rounded-lg px-2 py-1 text-xs transition-colors hover:bg-white/10"
> >
<Image <Image
src={avatarImageUrl(imager, u.look, { src={avatarImageUrl(u.look, {
headOnly: true, headOnly: true,
direction: 2, direction: 2,
size: "s", size: "s",
+2 -9
View File
@@ -1,16 +1,9 @@
import { getNewFormatFigure } from "@/lib/figure-convert"; import { getNewFormatFigure } from "@/lib/figure-convert";
import { getAvatarUrl } from "@/lib/imager"; import { getAvatarUrl } from "@/lib/imager";
import type { AvatarOptions } from "@/types/admin";
/** Build a Habbo avatar-imager URL for a figure string. */ /** Build a Habbo avatar-imager URL for a figure string. */
export function avatarImageUrl( export function avatarImageUrl(look: string, opts: AvatarOptions = {}): string {
look: string,
opts: {
size?: "s" | "m" | "l";
headOnly?: boolean;
direction?: number;
headDirection?: number;
} = {},
): string {
const figure = getNewFormatFigure(look); const figure = getNewFormatFigure(look);
return getAvatarUrl(figure, opts); return getAvatarUrl(figure, opts);
} }