Add create account functionality
This commit is contained in:
parent
598b9fd7d6
commit
8ef4636635
8 changed files with 145 additions and 12 deletions
|
@ -60,6 +60,7 @@ button {
|
||||||
|
|
||||||
fieldset {
|
fieldset {
|
||||||
padding-inline: 0.5rem;
|
padding-inline: 0.5rem;
|
||||||
|
width: fit-content;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
|
@ -70,7 +71,7 @@ label>* {
|
||||||
margin-inline-start: 0.5rem;
|
margin-inline-start: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
p + p {
|
:is(p, form, fieldset, pre) + :is(p, form, fieldset, pre) {
|
||||||
margin-block-start: 0.5rem;
|
margin-block-start: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,11 @@
|
||||||
</nav>
|
</nav>
|
||||||
<div class="account">
|
<div class="account">
|
||||||
<template v-if="session?.account">
|
<template v-if="session?.account">
|
||||||
{{ session.account.name || "anonymous" }}
|
{{ session.account.name }}
|
||||||
(s:{{ session.id }} a:{{ session.account.id }}{{ session.push ? " push" : null }})
|
(s:{{ session.id }} a:{{ session.account.id }}{{ session.push ? " push" : null }})
|
||||||
{{ session.account.type }}
|
{{ session.account.type }}
|
||||||
<NuxtLink to="/account/settings">Settings</NuxtLink>
|
<NuxtLink to="/account/settings">Settings</NuxtLink>
|
||||||
<LogOutButton />
|
<LogOutButton v-if="session.account.type !== 'anonymous'"/>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<NuxtLink to="/login">Log In</NuxtLink>
|
<NuxtLink to="/login">Log In</NuxtLink>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
<template>
|
<template>
|
||||||
<main>
|
<main>
|
||||||
<h1>Account Settings</h1>
|
<h1>Account Settings</h1>
|
||||||
<p>Name: {{ session?.account.name }}</p>
|
<p v-if="session?.account.type !== 'anonymous'">
|
||||||
|
Name: {{ session?.account.name }}
|
||||||
|
</p>
|
||||||
<p>Access: {{ session?.account.type }}</p>
|
<p>Access: {{ session?.account.type }}</p>
|
||||||
<p>
|
<p>
|
||||||
<PushNotification />
|
<PushNotification />
|
||||||
|
@ -37,9 +39,3 @@ async function deleteAccount() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
fieldset {
|
|
||||||
width: fit-content;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -5,6 +5,25 @@
|
||||||
<input v-model="name" type="text" placeholder="Name" required>
|
<input v-model="name" type="text" placeholder="Name" required>
|
||||||
<button type="submit">Log In</button>
|
<button type="submit">Log In</button>
|
||||||
</form>
|
</form>
|
||||||
|
<h2 id="create-account">Create Account</h2>
|
||||||
|
<p>If you don't have an account you may create one</p>
|
||||||
|
<form @submit.prevent="createAccount">
|
||||||
|
<fieldset>
|
||||||
|
<legend>Regular Account</legend>
|
||||||
|
<label>
|
||||||
|
Name:
|
||||||
|
<input v-model="createName" type="text" placeholder="Name" required />
|
||||||
|
</label>
|
||||||
|
<button type="submit">Create account</button>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
<p>
|
||||||
|
If you do not wish to deal with logins you may create an anonymous account tied to this device.
|
||||||
|
</p>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Anonymous Account</legend>
|
||||||
|
<button type="button" @click="createAnonymousAccount">Create anonymous account</button>
|
||||||
|
</fieldset>
|
||||||
<pre><code>{{ result }}</code></pre>
|
<pre><code>{{ result }}</code></pre>
|
||||||
<pre><code>Session: {{ session }}</code></pre>
|
<pre><code>Session: {{ session }}</code></pre>
|
||||||
</main>
|
</main>
|
||||||
|
@ -36,4 +55,41 @@ async function logIn() {
|
||||||
result.value = `Server replied: ${err.statusCode} ${err.statusMessage}`;
|
result.value = `Server replied: ${err.statusCode} ${err.statusMessage}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createName = ref("");
|
||||||
|
async function createAccount() {
|
||||||
|
try {
|
||||||
|
const res = await $fetch.raw("/api/account", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
body: new URLSearchParams({ name: createName.value })
|
||||||
|
});
|
||||||
|
result.value = `Server replied: ${res.status} ${res.statusText}`;
|
||||||
|
await sessionRefresh();
|
||||||
|
|
||||||
|
} catch (err: any) {
|
||||||
|
console.log(err);
|
||||||
|
console.log(err.data);
|
||||||
|
result.value = `Server replied: ${err.statusCode} ${err.statusMessage}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function createAnonymousAccount() {
|
||||||
|
try {
|
||||||
|
const res = await $fetch.raw("/api/account", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
result.value = `Server replied: ${res.status} ${res.statusText}`;
|
||||||
|
await sessionRefresh();
|
||||||
|
|
||||||
|
} catch (err: any) {
|
||||||
|
console.log(err);
|
||||||
|
console.log(err.data);
|
||||||
|
result.value = `Server replied: ${err.statusCode} ${err.statusMessage}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -5,9 +5,10 @@
|
||||||
Study carefully, we only hold these events once a year.
|
Study carefully, we only hold these events once a year.
|
||||||
</p>
|
</p>
|
||||||
<p v-if="!session">
|
<p v-if="!session">
|
||||||
<NuxtLink to="/login">Login</NuxtLink> to get notified about updates to the schedule.
|
<NuxtLink to="/login">Login</NuxtLink> or <NuxtLink to="/login#create-account">Create an account</NuxtLink>
|
||||||
|
to get notified about updates to the schedule.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p v-else>
|
||||||
Check out your <NuxtLink to="/account/settings">Account Setting</NuxtLink> to set up notifications for changes to schedule.
|
Check out your <NuxtLink to="/account/settings">Account Setting</NuxtLink> to set up notifications for changes to schedule.
|
||||||
</p>
|
</p>
|
||||||
<h2>Schedule</h2>
|
<h2>Schedule</h2>
|
||||||
|
|
53
server/api/account.post.ts
Normal file
53
server/api/account.post.ts
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
import { readAccounts, writeAccounts, nextAccountId } from "~/server/database";
|
||||||
|
import { Account } from "~/shared/types/account";
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
let session = await getAccountSession(event);
|
||||||
|
if (session) {
|
||||||
|
throw createError({
|
||||||
|
status: 409,
|
||||||
|
message: "Cannot create account while having an active session."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = await readFormData(event);
|
||||||
|
const name = formData.get("name");
|
||||||
|
|
||||||
|
const accounts = await readAccounts();
|
||||||
|
let account: Account;
|
||||||
|
if (typeof name === "string") {
|
||||||
|
if (name === "") {
|
||||||
|
throw createError({
|
||||||
|
status: 400,
|
||||||
|
message: "Name cannot be blank",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (accounts.some(account => account.name && account.name.toLowerCase() === name.toLowerCase())) {
|
||||||
|
throw createError({
|
||||||
|
status: 409,
|
||||||
|
message: "User already exists",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
account = {
|
||||||
|
id: await nextAccountId(),
|
||||||
|
type: "regular",
|
||||||
|
name,
|
||||||
|
};
|
||||||
|
|
||||||
|
} else if (name === null) {
|
||||||
|
account = {
|
||||||
|
id: await nextAccountId(),
|
||||||
|
type: "anonymous",
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw createError({
|
||||||
|
status: 400,
|
||||||
|
message: "Invalid name",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
accounts.push(account);
|
||||||
|
await writeAccounts(accounts);
|
||||||
|
await setAccountSession(event, account.id);
|
||||||
|
})
|
|
@ -1,3 +1,19 @@
|
||||||
|
import { readAccounts } from "~/server/database";
|
||||||
|
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
|
const session = await getAccountSession(event);
|
||||||
|
if (session) {
|
||||||
|
const accounts = await readAccounts();
|
||||||
|
const account = accounts.find(
|
||||||
|
account => account.id === session.accountId
|
||||||
|
);
|
||||||
|
if (account && account.type === "anonymous") {
|
||||||
|
throw createError({
|
||||||
|
status: 409,
|
||||||
|
message: "Cannot log out of an anonymous account",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await clearAccountSession(event);
|
await clearAccountSession(event);
|
||||||
})
|
})
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { generateDemoSchedule, generateDemoAccounts } from "./generate-demo-sche
|
||||||
const schedulePath = "data/schedule.json";
|
const schedulePath = "data/schedule.json";
|
||||||
const subscriptionsPath = "data/subscriptions.json";
|
const subscriptionsPath = "data/subscriptions.json";
|
||||||
const accountsPath = "data/accounts.json";
|
const accountsPath = "data/accounts.json";
|
||||||
|
const nextAccountIdPath = "data/next-account-id.json";
|
||||||
const sessionsPath = "data/sessions.json";
|
const sessionsPath = "data/sessions.json";
|
||||||
const nextSessionIdPath = "data/next-session-id.json";
|
const nextSessionIdPath = "data/next-session-id.json";
|
||||||
|
|
||||||
|
@ -45,6 +46,15 @@ export async function writeSubscriptions(subscriptions: Subscription[]) {
|
||||||
await writeFile(subscriptionsPath, JSON.stringify(subscriptions, undefined, "\t") + "\n", "utf-8");
|
await writeFile(subscriptionsPath, JSON.stringify(subscriptions, undefined, "\t") + "\n", "utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function nextAccountId() {
|
||||||
|
let nextId = await readJson(nextAccountIdPath, 0);
|
||||||
|
if (nextId === 0) {
|
||||||
|
nextId = Math.max(...(await readAccounts()).map(account => account.id), -1) + 1;
|
||||||
|
}
|
||||||
|
await writeFile(nextAccountIdPath, String(nextId + 1), "utf-8");
|
||||||
|
return nextId;
|
||||||
|
}
|
||||||
|
|
||||||
export async function readAccounts() {
|
export async function readAccounts() {
|
||||||
return await readJson(accountsPath, generateDemoAccounts);
|
return await readJson(accountsPath, generateDemoAccounts);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue