feat: add short IDs + link shortener

This commit is contained in:
Sam 2023-06-03 03:06:26 +02:00
parent 7c94c088e0
commit 10dc59d3d4
Signed by: sam
GPG key ID: B4EF20DDE721CAA1
18 changed files with 510 additions and 31 deletions

View file

@ -30,6 +30,7 @@
type Pronoun,
} from "$lib/api/entities";
import { PUBLIC_BASE_URL } from "$env/static/public";
import { env } from "$env/dynamic/public";
import { apiFetchClient } from "$lib/api/fetch";
import ErrorAlert from "$lib/components/ErrorAlert.svelte";
import { goto } from "$app/navigation";
@ -41,6 +42,7 @@
import defaultPreferences from "$lib/api/default_preferences";
import { addToast } from "$lib/toast";
import ProfileFlag from "./ProfileFlag.svelte";
import IconButton from "$lib/components/IconButton.svelte";
export let data: PageData;
@ -117,6 +119,12 @@
addToast({ body: "Copied the link to your clipboard!", duration: 2000 });
};
const copyShortURL = async () => {
const url = `${env.PUBLIC_SHORT_BASE}/${data.sid}`;
await navigator.clipboard.writeText(url);
addToast({ body: "Copied the short link to your clipboard!", duration: 2000 });
};
onMount(async () => {
if ($userStore && $userStore.id === data.id) {
console.log("User is current user, fetching members");
@ -231,6 +239,15 @@
<Button color="secondary" outline on:click={copyURL}>
<Icon name="clipboard" /> Copy link
</Button>
{#if env.PUBLIC_SHORT_BASE}
<IconButton
outline
icon="link-45deg"
tooltip="Copy short link"
color="secondary"
click={copyShortURL}
/>
{/if}
{#if $userStore && $userStore.id !== data.id}
<ReportButton subject="user" reportUrl="/users/{data.id}/reports" />
{/if}

View file

@ -13,6 +13,7 @@
type Pronoun,
} from "$lib/api/entities";
import { PUBLIC_BASE_URL } from "$env/static/public";
import { env } from "$env/dynamic/public";
import { userStore } from "$lib/store";
import { renderMarkdown } from "$lib/utils";
import ReportButton from "../ReportButton.svelte";
@ -21,6 +22,7 @@
import defaultPreferences from "$lib/api/default_preferences";
import { addToast } from "$lib/toast";
import ProfileFlag from "../ProfileFlag.svelte";
import IconButton from "$lib/components/IconButton.svelte";
export let data: PageData;
@ -51,6 +53,12 @@
await navigator.clipboard.writeText(url);
addToast({ body: "Copied the link to your clipboard!", duration: 2000 });
};
const copyShortURL = async () => {
const url = `${env.PUBLIC_SHORT_BASE}/${data.sid}`;
await navigator.clipboard.writeText(url);
addToast({ body: "Copied the short link to your clipboard!", duration: 2000 });
};
</script>
<div class="container">
@ -153,6 +161,15 @@
<Button color="secondary" outline on:click={copyURL}>
<Icon name="clipboard" /> Copy link
</Button>
{#if env.PUBLIC_SHORT_BASE}
<IconButton
outline
icon="link-45deg"
tooltip="Copy short link"
color="secondary"
click={copyShortURL}
/>
{/if}
{#if $userStore && $userStore.id !== data.user.id}
<ReportButton subject="member" reportUrl="/members/{data.id}/reports" />
{/if}

View file

@ -28,8 +28,10 @@
CardHeader,
Alert,
} from "sveltestrap";
import { DateTime } from "luxon";
import { encode } from "base64-arraybuffer";
import prettyBytes from "pretty-bytes";
import { env } from "$env/dynamic/public";
import { apiFetchClient, fastFetchClient } from "$lib/api/fetch";
import IconButton from "$lib/components/IconButton.svelte";
import EditableField from "../../EditableField.svelte";
@ -373,6 +375,28 @@
let deleteName = "";
let deleteError: APIError | null = null;
const now = DateTime.now().toLocal();
let canRerollSid: boolean;
$: canRerollSid =
now.diff(DateTime.fromISO(data.user.last_sid_reroll).toLocal(), "hours").hours >= 1;
const rerollSid = async () => {
try {
const resp = await apiFetchClient<Member>(`/members/${data.member.id}/reroll`);
addToast({ header: "Success", body: "Rerolled short ID!" });
error = null;
data.member.sid = resp.sid;
} catch (e) {
error = e as APIError;
}
};
const copyShortURL = async () => {
const url = `${env.PUBLIC_SHORT_BASE}/${data.member.sid}`;
await navigator.clipboard.writeText(url);
addToast({ body: "Copied the short link to your clipboard!", duration: 2000 });
};
interface SnapshotData {
bio: string;
name: string;
@ -407,19 +431,19 @@
newLink,
}),
restore: (value) => {
bio = value.bio
name = value.name
display_name = value.display_name
links = value.links
names = value.names
pronouns = value.pronouns
fields = value.fields
flags = value.flags
unlisted = value.unlisted
avatar = value.avatar
newName = value.newName
newPronouns = value.newPronouns
newLink = value.newLink
bio = value.bio;
name = value.name;
display_name = value.display_name;
links = value.links;
names = value.names;
pronouns = value.pronouns;
fields = value.fields;
flags = value.flags;
unlisted = value.unlisted;
avatar = value.avatar;
newName = value.newName;
newPronouns = value.newPronouns;
newLink = value.newLink;
},
};
</script>
@ -755,6 +779,30 @@
</strong>
</p>
</div>
{#if env.PUBLIC_SHORT_BASE}
<div class="col-md">
<p>
Current short ID: <code>{data.member.sid}</code>
<ButtonGroup class="mb-1">
<Button color="secondary" disabled={!canRerollSid} on:click={() => rerollSid()}
>Reroll short ID</Button
>
<IconButton
icon="link-45deg"
tooltip="Copy short link"
color="secondary"
click={copyShortURL}
/>
</ButtonGroup>
<br />
<span class="text-muted">
<Icon name="info-circle-fill" aria-hidden />
This ID is used in <code>prns.cc</code> links. You can reroll one short ID every hour (shared
between your main profile and all members) by pressing the button above.
</span>
</p>
</div>
{/if}
</div>
</TabPane>
</TabContent>

View file

@ -28,7 +28,9 @@
TabPane,
} from "sveltestrap";
import { encode } from "base64-arraybuffer";
import { DateTime } from "luxon";
import { apiFetchClient } from "$lib/api/fetch";
import { env } from "$env/dynamic/public";
import IconButton from "$lib/components/IconButton.svelte";
import EditableField from "../EditableField.svelte";
import EditableName from "../EditableName.svelte";
@ -379,6 +381,28 @@
}
};
const now = DateTime.now().toLocal();
let canRerollSid: boolean;
$: canRerollSid =
now.diff(DateTime.fromISO(data.user.last_sid_reroll).toLocal(), "hours").hours >= 1;
const rerollSid = async () => {
try {
const resp = await apiFetchClient<MeUser>("/users/@me/reroll");
addToast({ header: "Success", body: "Rerolled short ID!" });
error = null;
data.user.sid = resp.sid;
} catch (e) {
error = e as APIError;
}
};
const copyShortURL = async () => {
const url = `${env.PUBLIC_SHORT_BASE}/${data.user.sid}`;
await navigator.clipboard.writeText(url);
addToast({ body: "Copied the short link to your clipboard!", duration: 2000 });
};
interface SnapshotData {
bio: string;
display_name: string;
@ -721,6 +745,29 @@
will be used.
</p>
</FormGroup>
{#if env.PUBLIC_SHORT_BASE}
<hr />
<p>
Current short ID: <code>{data.user.sid}</code>
<ButtonGroup class="mb-1">
<Button color="secondary" disabled={!canRerollSid} on:click={() => rerollSid()}
>Reroll short ID</Button
>
<IconButton
icon="link-45deg"
tooltip="Copy short link"
color="secondary"
click={copyShortURL}
/>
</ButtonGroup>
<br />
<span class="text-muted">
<Icon name="info-circle-fill" aria-hidden />
This ID is used in <code>prns.cc</code> links. You can reroll one short ID every hour (shared
between your main profile and all members) by pressing the button above.
</span>
</p>
{/if}
</div>
<div class="col-md">
<div class="form-check">