diff --git a/Foxnouns.Frontend/src/lib/api/models/moderation.ts b/Foxnouns.Frontend/src/lib/api/models/moderation.ts
index 47aa3c8..852358e 100644
--- a/Foxnouns.Frontend/src/lib/api/models/moderation.ts
+++ b/Foxnouns.Frontend/src/lib/api/models/moderation.ts
@@ -1,5 +1,5 @@
import type { Member } from "./member";
-import type { PartialMember, PartialUser, User } from "./user";
+import type { AuthMethod, PartialMember, PartialUser, User } from "./user";
export type CreateReportRequest = {
reason: ReportReason;
@@ -70,3 +70,13 @@ export type PartialReport = {
context: string | null;
target_type: "USER" | "MEMBER";
};
+
+export type QueriedUser = {
+ user: User;
+ member_list_hidden: boolean;
+ last_active: string;
+ last_sid_reroll: string;
+ suspended: boolean;
+ deleted: boolean;
+ auth_methods?: AuthMethod[];
+};
diff --git a/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte b/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte
index 692146a..f1c7964 100644
--- a/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte
+++ b/Foxnouns.Frontend/src/lib/components/settings/AuthMethodRow.svelte
@@ -2,8 +2,8 @@
import { t } from "$lib/i18n";
import type { AuthMethod } from "$api/models";
- type Props = { method: AuthMethod; canRemove: boolean };
- let { method, canRemove }: Props = $props();
+ type Props = { method: AuthMethod; canRemove: boolean; showType?: boolean };
+ let { method, canRemove, showType }: Props = $props();
let name = $derived(
method.type === "EMAIL" ? method.remote_id : (method.remote_username ?? method.remote_id),
@@ -14,6 +14,9 @@
+ {#if showType}
+ {method.type}
:
+ {/if}
{name}
{#if showId}({method.remote_id}){/if}
diff --git a/Foxnouns.Frontend/src/routes/admin/+layout.svelte b/Foxnouns.Frontend/src/routes/admin/+layout.svelte
index 0c0b247..c40279e 100644
--- a/Foxnouns.Frontend/src/routes/admin/+layout.svelte
+++ b/Foxnouns.Frontend/src/routes/admin/+layout.svelte
@@ -41,6 +41,13 @@
>
Audit log
+
+ Lookup
+
diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/lookup/+page.server.ts
new file mode 100644
index 0000000..90a284e
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/admin/lookup/+page.server.ts
@@ -0,0 +1,27 @@
+import { apiRequest } from "$api";
+import { redirect } from "@sveltejs/kit";
+
+export const actions = {
+ default: async ({ request, fetch, cookies }) => {
+ const body = await request.formData();
+ const query = body.get("query") as string;
+ const fuzzy = body.get("fuzzy") === "yes";
+
+ const users = await apiRequest
>(
+ "POST",
+ "/moderation/lookup",
+ {
+ fetch,
+ cookies,
+ body: {
+ query,
+ fuzzy,
+ },
+ },
+ );
+
+ if (!fuzzy && users.length > 0) redirect(303, `/admin/lookup/${users[0].id}`);
+
+ return { users };
+ },
+};
diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/+page.svelte b/Foxnouns.Frontend/src/routes/admin/lookup/+page.svelte
new file mode 100644
index 0000000..b3c8a8d
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/admin/lookup/+page.svelte
@@ -0,0 +1,33 @@
+
+
+
+ Look up a user • pronouns.cc
+
+
+Look up a user
+
+
+
+
diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.server.ts b/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.server.ts
new file mode 100644
index 0000000..130ae90
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.server.ts
@@ -0,0 +1,11 @@
+import { apiRequest } from "$api";
+import type { QueriedUser } from "$api/models/moderation";
+
+export const load = async ({ params, fetch, cookies }) => {
+ const user = await apiRequest("GET", `/moderation/lookup/${params.id}`, {
+ fetch,
+ cookies,
+ });
+
+ return { user };
+};
diff --git a/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.svelte b/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.svelte
new file mode 100644
index 0000000..e3cf389
--- /dev/null
+++ b/Foxnouns.Frontend/src/routes/admin/lookup/[id]/+page.svelte
@@ -0,0 +1,63 @@
+
+
+
+ Looking up @{data.user.user.username} • pronouns.cc
+
+
+Basic profile
+
+
+
+
+
+Extra information
+
+
+
+
+ Created at |
+ {createdAt.toLocaleString(DateTime.DATETIME_MED)} |
+
+
+ Last active |
+ {lastActive.toLocaleString(DateTime.DATETIME_MED)} |
+
+
+ Last SID reroll |
+ {lastSidReroll.toLocaleString(DateTime.DATETIME_MED)} |
+
+
+
+
+{#if authMethods}
+ Authentication methods
+
+ {#each authMethods as method (method.id)}
+
+ {/each}
+
+{/if}