Skip to content

Commit

Permalink
Encapsulated @wordplay.dev domain checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
amyjko committed Oct 27, 2023
1 parent 5738c44 commit b204cef
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 36 deletions.
11 changes: 2 additions & 9 deletions src/components/app/CreatorView.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import type { Creator } from '@db/CreatorDatabase';
import { locales } from '@db/Database';
import { CreatorUsernameEmailDomain } from '../../db/CreatorDatabase';
export let creator: Creator | null;
export let anonymize = true;
Expand All @@ -11,15 +10,9 @@
>{#if creator}<span
class="name"
style:animation-delay={`${Math.random() * 1000}ms`}
>{creator.name ?? '😃'}</span
>{creator.getName() ?? '😃'}</span
>{/if}{creator
? creator.email === null
? ''
: anonymize
? `${creator.email.split('@')[0].substring(0, 4)}...`
: creator.email.endsWith(CreatorUsernameEmailDomain)
? creator.email.replace(CreatorUsernameEmailDomain, '')
: creator.email
? creator.getUsername(anonymize)
: $locales.get((l) => l.ui.page.login.anonymous)}</div
>

Expand Down
9 changes: 2 additions & 7 deletions src/components/settings/Settings.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import Dialog from '../widgets/Dialog.svelte';
import CreatorView from '../app/CreatorView.svelte';
import Beta from '../../routes/Beta.svelte';
import { Creator } from '../../db/CreatorDatabase';
let user = getUser();
Expand Down Expand Up @@ -68,13 +69,7 @@
<Link to="/login">
<CreatorView
anonymize={false}
creator={$user
? {
email: $user.email,
uid: $user.uid,
name: $user.displayName ?? null,
}
: null}
creator={$user ? Creator.from($user) : null}
/>
</Link>
<LanguageChooser />
Expand Down
77 changes: 68 additions & 9 deletions src/db/CreatorDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,71 @@ import { httpsCallable } from 'firebase/functions';
import type { Database } from './Database';
import { functions } from './firebase';
import type { UserIdentifier } from 'firebase-admin/auth';
import type { User } from 'firebase/auth';

export const CreatorCollection = 'creators';
export const CreatorUsernameEmailDomain = '@wordplay.dev';

/** The type for a record returned by our cloud functions */
export type Creator = {
export type CreatorSchema = {
uid: string;
name: string | null;
email: string | null;
};

export class Creator {
/** This is the domain we append to work around the lack of Firebase support for raw usernames. */
static CreatorUsernameEmailDomain = '@wordplay.dev';
readonly data: CreatorSchema;
constructor(data: CreatorSchema) {
this.data = data;
}

static from(user: User) {
return new Creator({
uid: user.uid,
name: user.displayName,
email: user.email,
});
}

static usernameEmail(username: string) {
return `${username}${Creator.CreatorUsernameEmailDomain}`;
}

static isUsername(email: string) {
return email.endsWith(Creator.CreatorUsernameEmailDomain);
}

getName() {
return this.data.name;
}

getEmail() {
return this.data.email;
}

isUsername() {
return (
this.data.email &&
this.data.email.endsWith(Creator.CreatorUsernameEmailDomain)
);
}

getUsername(anonymous: boolean) {
return this.data.email === null
? '—'
: anonymous
? `${this.data.email.split('@')[0].substring(0, 4)}...`
: this.isUsername()
? this.data.email.replace(Creator.CreatorUsernameEmailDomain, '')
: this.data.email;
}

getUID() {
return this.data.uid;
}
}

export default class CreatorDatabase {
/** The main database that manages this gallery database */
readonly database: Database;
Expand All @@ -28,6 +82,10 @@ export default class CreatorDatabase {
this.database = database;
}

static getUsernameEmail(username: string) {
return Creator.usernameEmail(username);
}

async getCreators(
ids: string[],
detail: 'email' | 'uid'
Expand All @@ -50,7 +108,7 @@ export default class CreatorDatabase {
if (functions === undefined) return creators;

// Get missing info.
const getCreators = httpsCallable<UserIdentifier[], Creator[]>(
const getCreators = httpsCallable<UserIdentifier[], CreatorSchema[]>(
functions,
'getCreators'
);
Expand All @@ -59,14 +117,15 @@ export default class CreatorDatabase {
await getCreators(
missing.map((id) => (email ? { email: id } : { uid: id }))
)
).data as Creator[];
).data as CreatorSchema[];

// Add the missing creators
for (const creator of missingCreators) {
if (creator.email) this.creatorsByEmail.set(creator.email, creator);
this.creatorsByUID.set(creator.uid, creator);
for (const schema of missingCreators) {
const creator = new Creator(schema);
if (schema.email) this.creatorsByEmail.set(schema.email, creator);
this.creatorsByUID.set(schema.uid, creator);
missing = missing.filter(
(id) => id !== (email ? creator.email : creator.uid)
(id) => id !== (email ? schema.email : schema.uid)
);
creators.push(creator);
}
Expand Down Expand Up @@ -96,7 +155,7 @@ export default class CreatorDatabase {
await this.getCreators([email], 'email');

// Then return what we've got.
return this.creatorsByEmail.get(email)?.uid ?? null;
return this.creatorsByEmail.get(email)?.getUID() ?? null;
}

async getCreator(uid: string): Promise<Creator | null> {
Expand Down
4 changes: 2 additions & 2 deletions src/routes/login/Login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import Mode from '../../components/widgets/Mode.svelte';
import Subheader from '../../components/app/Subheader.svelte';
import MarkupHtmlView from '../../components/concepts/MarkupHTMLView.svelte';
import { CreatorUsernameEmailDomain } from '../../db/CreatorDatabase';
import CreatorDatabase from '../../db/CreatorDatabase';
let user = getUser();
let success: boolean | undefined = undefined;
Expand All @@ -37,7 +37,7 @@
let password = '';
let reveal = false;
$: emailUsername = `${username}${CreatorUsernameEmailDomain}`;
$: emailUsername = CreatorDatabase.getUsernameEmail(username);
/** True if we tried to log in and there's no account. */
let noAccount = false;
Expand Down
19 changes: 10 additions & 9 deletions src/routes/login/Profile.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
import Feedback from '../../components/app/Feedback.svelte';
import { isModerator } from '../../models/Moderation';
import { getLoginErrorDescription } from './login';
import { CreatorUsernameEmailDomain } from '../../db/CreatorDatabase';
import { Creator } from '../../db/CreatorDatabase';
export let user: User;
$: username = user.email?.endsWith(CreatorUsernameEmailDomain);
$: creator = Creator.from(user);
let newEmail: string;
Expand Down Expand Up @@ -78,16 +78,16 @@
}
function readyToDeleteAccount(email: string) {
const finalEmail = username
? `${email}${CreatorUsernameEmailDomain}`
const finalEmail = creator.isUsername()
? Creator.usernameEmail(email)
: email;
return validEmail(finalEmail) && finalEmail === user.email;
}
</script>

<Header
><span style:font-family="Noto Color Emoji">{user.displayName ?? '😃'}</span
>{user.email?.replace(CreatorUsernameEmailDomain, '')}</Header
>{creator.getUsername(false)}</Header
>

<div class="actions">
Expand Down Expand Up @@ -119,7 +119,7 @@
></p
>
</div>
{#if user && !username}
{#if !creator.isUsername()}
<div class="action">
<p>{$locales.get((l) => l.ui.page.login.prompt.change)}</p>
<form on:submit={update}>
Expand All @@ -134,6 +134,7 @@
editable={!changeSubmitted}
/><Button
submit
background
tip={$locales.get((l) => l.ui.page.login.button.update)}
active={validEmail(newEmail)}
action={() => undefined}>&gt;</Button
Expand Down Expand Up @@ -176,17 +177,17 @@
>
<TextField
description={$locales.get((l) =>
username
creator.isUsername()
? l.ui.page.login.field.username.description
: l.ui.page.login.field.email.description
)}
placeholder={$locales.get((l) =>
username
creator.isUsername()
? l.ui.page.login.field.username.placeholder
: l.ui.page.login.field.email.placeholder
)}
fill={true}
kind={username ? undefined : 'email'}
kind={creator.isUsername() ? undefined : 'email'}
bind:text={confirmEmail}
/>
<Button
Expand Down

0 comments on commit b204cef

Please sign in to comment.