PronounsPage/shared/profile.ts
2025-09-21 00:11:00 +02:00

161 lines
4.0 KiB
TypeScript

import type { CustomEvent } from './calendar/helpers.ts';
import type { Opinion } from './opinions.ts';
import type { User } from './user.ts';
import type { VoiceKey } from '#shared/pronunciation/voices.ts';
import type { LocaleCode } from '~~/locale/locales.ts';
export interface UserWithProfiles {
id: string;
username: string;
email: string;
avatarSource: string | null;
bannedReason: string | null;
bannedTerms: string | null;
bannedBy: string | null;
team: string;
profiles: Record<string, Profile>;
personally: string | null;
}
export interface Profile {
id: string;
names: NameOpinion[];
pronouns: ValueOpinion[];
description: string;
age?: number | null;
/**
* @format date
*/
birthday: string | null;
timezone: Timezone | null;
links: string[];
linksMetadata: Record<string, LinkMetadata>;
verifiedLinks: Record<string, string>;
flags: string[];
customFlags: CustomFlag[];
words: WordCategory[];
teamName: string | null;
footerName: string | null;
footerAreas: string[];
credentials: string[];
credentialsLevel: number | null;
credentialsName: string | null;
card: string | null;
cardDark: string | null;
opinions: Record<string, Opinion & { description: string }>;
circle: RelatedPerson[];
sensitive: string[];
markdown: boolean;
events: string[];
customEvents: CustomEvent[];
visibility: ProfileVisibility;
access: boolean;
/**
* @format ulid
*/
lastUpdate: string | null;
}
export interface ValueOpinion {
value: string;
opinion: string;
}
export interface NameOpinion extends ValueOpinion {
pronunciation: string;
voice: VoiceKey | null;
}
export interface Timezone {
tz: string;
area: boolean;
loc: boolean;
}
export interface LinkMetadata {
favicon: string | null;
relMe: string[];
nodeinfo: unknown | null;
}
export interface WordCategory {
header: string | null;
values: ValueOpinion[];
}
export interface CustomFlag {
value: string;
name: string;
description: string | null;
alt: string | null;
link: string | null;
}
export interface RelatedPerson {
avatar: string;
circleMutual: boolean;
locale: LocaleCode;
relationship: string;
username: string;
}
export interface ProfileV1 extends Omit<Profile, 'names' | 'pronouns' | 'words' | 'customFlags'> {
names: Record<string, number>;
pronouns: Record<string, number>;
words: Record<string, number>[];
customFlags: Record<string, string>;
}
export interface SaveProfilePayload extends Omit<Profile, 'linksMetadata' | 'verifiedLinks' | 'opinions'
| 'card' | 'cardDark' | 'lastUpdate' | 'id' | 'access'> {
username: string;
opinions: OpinionFormValue[];
propagate: string[];
}
export interface OpinionFormValue {
key: string;
icon: string;
description: string;
colour: string;
style: string;
}
export enum ProfileVisibility {
Public = 0,
InternalBots = 1,
Internal = 2,
}
const denyAccessToProfile = (profile: Partial<Profile>): Partial<Profile> => {
return Object.fromEntries(Object.entries(profile).map(([key, value]) => {
if (key === 'access') {
return ['access', false];
}
if (['opinions', 'pronouns', 'visibility'].includes(key)) {
return [key, value];
}
return [key, undefined];
}));
};
export const applyProfileVisibilityRules = (visitor: User | null, profile: Partial<Profile>, allowBots: boolean): Partial<Profile> => {
if (visitor) {
return profile;
}
switch (profile.visibility) {
case ProfileVisibility.Internal:
return denyAccessToProfile(profile);
case ProfileVisibility.InternalBots:
return allowBots
? profile
: denyAccessToProfile(profile);
case ProfileVisibility.Public:
return profile;
default:
throw new Error(`Unknown visibility value: ${profile.visibility}`);
}
};