Replace registration stream with code based

This commit is contained in:
Fred Boniface 2024-03-10 20:43:29 +00:00
parent 4dd9ea05d6
commit 80b3c235af
3 changed files with 131 additions and 184 deletions

View File

@ -1,9 +1,9 @@
<script> <script lang="ts">
import Header from '$lib/navigation/header.svelte'; import Header from '$lib/navigation/header.svelte';
import Nav from '$lib/navigation/nav.svelte'; import Nav from '$lib/navigation/nav.svelte';
import Loading from '$lib/navigation/loading.svelte'; import Loading from '$lib/navigation/loading.svelte';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { checkAuth, logout } from '$lib/libauth'; import { checkAuth } from '$lib/libauth';
import LogoutButton from '$lib/navigation/LogoutButton.svelte'; import LogoutButton from '$lib/navigation/LogoutButton.svelte';
import { getApiUrl } from '$lib/scripts/upstream'; import { getApiUrl } from '$lib/scripts/upstream';
@ -13,8 +13,8 @@
let isLoading = true; let isLoading = true;
let inputValue = ''; let inputValue = '';
function handleInput(event) { function handleInput(event: KeyboardEvent) {
inputValue = event.target.value; inputValue = event?.target?.value;
} }
async function request() { async function request() {
@ -57,29 +57,27 @@
{#if isLoading} {#if isLoading}
<Loading /> <Loading />
{:else if state == 'unreg'} {:else if state == 'unreg'}
<p>The staff version of OwlBoard offers several extra features:</p> <p>To register, you will need to enter a work email address to receive a confirmation email</p>
<ul> <p class="bold">Already have a registration code? <a href="/more/reg/submit">enter it here</a></p>
<li>Access the Train Finder</li> <form on:submit={request}>
<li>Access the PIS Finder</li> <input type="text" autocomplete="email" placeholder="Enter work email" bind:value={inputValue} on:input={handleInput} /><br />
<li>More detailed departure boards:</li> <label for="checkbox">
<ul> I have read and accept the terms of the <a href="/more/privacy">Privacy Policy</a><br />
<li>Non-Passenger movements</li> <input id="checkbox" type="checkbox" required />
<li>Hidden platform numbers</li> </label><br />
<li>Display up to 25 services</li> <button type="submit">Submit</button>
</ul> </form><br>
</ul> <p class="bold">What do you get?</p>
<p>To register, you will need to enter a work email address to receive a confirmation email</p> <li>Access to Train details</li>
<form on:submit={request}> <li>Access to PIS Codes</li>
<input type="text" autocomplete="email" placeholder="Enter work email" bind:value={inputValue} on:input={handleInput} /><br /> <li>ECS Movements on departure boards</li>
<label for="checkbox"> <li>Non-Public trains on departure boards</li>
I have read and accept the terms of the <a href="/more/privacy">Privacy Policy</a><br /> <li>Hidden platform numbers on departure boards</li>
<input id="checkbox" type="checkbox" required /> <li>See up to the next 40 trains departing a station over the next two hours</li>
</label><br />
<button type="submit">Submit</button>
</form>
{:else if state == 'sent'} {:else if state == 'sent'}
<p>An email has been sent, click the link in the email to activate your profile.</p> <p>An email has been sent, enter the code in the email to activate your profile.</p>
<p>When you click the link, your authorisation key will be automatically be stored in your browser.</p> <p class="bold"><a href="/more/reg/submit">Ready to enter your code?</a></p>
<p>If you use multiple browsers, you will only be logged in using the browser you open the link with.</p> <p>If you use multiple browsers, you will only be logged in using the browser you open the link with.</p>
<p>You will be able to register again using the same email address</p> <p>You will be able to register again using the same email address</p>
{:else if state == 'unauth'} {:else if state == 'unauth'}
@ -99,15 +97,25 @@
<Nav /> <Nav />
<style> <style>
.bold {
font-weight: 800;
}
.content { .content {
margin-top: 30px; margin-top: 30px;
} }
p { p {
margin: 10px; margin: 10px;
margin-left: 20px;
margin-right: 20px;
} }
ul { li {
text-align: left; text-align: center;
font-size: 14px;
color: white; color: white;
margin-top: 5px;
margin-left: 15px;
margin-right: 15px;
list-style-type: none;
} }
input { input {
height: 40px; height: 40px;

View File

@ -1,111 +0,0 @@
<script lang="ts">
import Header from '$lib/navigation/header.svelte';
import Nav from '$lib/navigation/nav.svelte';
import { getApiUrl } from '$lib/scripts/upstream';
import { uuid } from '$lib/stores/uuid';
const title = 'Submit Registration';
let state = false;
let status: string;
let inputs: { id: string; value: string }[] = [
{ id: '1', value: '' },
{ id: '2', value: '' },
{ id: '3', value: '' },
{ id: '4', value: '' },
{ id: '5', value: '' },
{ id: '6', value: '' }
];
function handleInput(index: number, event: KeyboardEvent): void {
if (event.key === 'Backspace' && index > 0 && inputs[index].value === '') {
const prevInput = document.getElementById(`input-${index}`);
if (prevInput) {
prevInput.focus();
}
} else if (inputs[index].value.length === 1) {
const nextInput = document.getElementById(`input-${index + 2}`);
if (nextInput) {
nextInput.focus();
}
}
}
async function handleSubmit() {
let submitString: string = '';
for (const input of inputs) {
submitString += input.value.toUpperCase()
}
console.log(`Code: ${submitString}`)
const res = await submit(submitString)
if (res == 201) {
status = "okay"
} else if (res == 401) {
status = "fail"
} else {
console.error("Unable to register: ", status)
}
}
async function submit(id: string): Promise<number> {
const url = `${getApiUrl()}/api/v2/user/register`;
const request = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
uuid: id
})
};
const res = await fetch(url, request);
const body = await res.json();
if (body.api_key) {
uuid.set(body.api_key);
return 201;
}
return res.status;
}
</script>
<Header {title} />
{#if state}
{#if status = "okay"}
<p class="title-ish">You are now registered</p>
{:else if status = "fail"}
<p class="title-ish">Your code was not accepted</p>
{/if}
{:else}
<p class="title-ish">Enter your registration code below</p>
<form on:submit={handleSubmit} id="codeInputForm">
{#each inputs as input, index}
<input class="code-in" bind:value={input.value} id={`input-${input.id}`} maxlength="1" autocomplete="off" on:keydown={(event) => handleInput(index, event)} />
{/each}
<br />
<button type="submit">Submit</button>
</form>
{/if}
<Nav />
<style>
.title-ish {
font-size: 20px;
}
.code-in {
margin: 3px;
margin-bottom: 20px;
width: 29px;
height: 39px;
font-size: 30px;
text-align: center;
text-transform: uppercase;
border-radius: 10px;
border: none;
}
#submit {
}
</style>

View File

@ -1,20 +1,56 @@
<script> <script lang="ts">
import Header from '$lib/navigation/header.svelte'; import Header from '$lib/navigation/header.svelte';
import Loading from '$lib/navigation/loading.svelte';
import Nav from '$lib/navigation/nav.svelte'; import Nav from '$lib/navigation/nav.svelte';
import { getApiUrl } from '$lib/scripts/upstream'; import { getApiUrl } from '$lib/scripts/upstream';
import { uuid } from '$lib/stores/uuid.js'; import { uuid } from '$lib/stores/uuid';
import { onMount } from 'svelte';
const title = 'Registration'; const title = 'Submit Registration';
let state = ''; let state = false;
let isLoading = true; let status: string;
async function getUUID() { let inputs: { id: string; value: string }[] = [
return new URLSearchParams(window.location.search).get('key'); { id: '1', value: '' },
{ id: '2', value: '' },
{ id: '3', value: '' },
{ id: '4', value: '' },
{ id: '5', value: '' },
{ id: '6', value: '' }
];
function handleInput(index: number, event: KeyboardEvent): void {
if (event.key === 'Backspace' && index > 0 && inputs[index].value === '') {
const prevInput = document.getElementById(`input-${index}`);
if (prevInput) {
prevInput.focus();
}
} else if (inputs[index].value.length === 1) {
const nextInput = document.getElementById(`input-${index + 2}`);
if (nextInput) {
nextInput.focus();
}
}
} }
async function submit(id) { async function handleSubmit() {
let submitString: string = '';
for (const input of inputs) {
submitString += input.value.toUpperCase();
}
console.log(`Code: ${submitString}`);
const res = await submit(submitString);
console.log(`Registration Status: ${res}`)
if (res == 201) {
status = "okay"
} else if (res == 401) {
status = "fail"
} else {
console.error("Unable to register: ", status)
}
state = true;
}
async function submit(id: string): Promise<number> {
const url = `${getApiUrl()}/api/v2/user/register`; const url = `${getApiUrl()}/api/v2/user/register`;
const request = { const request = {
method: 'POST', method: 'POST',
@ -30,51 +66,65 @@
if (body.api_key) { if (body.api_key) {
uuid.set(body.api_key); uuid.set(body.api_key);
return 201; return 201;
} else {
return res.status;
} }
return res.status;
} }
onMount(async () => {
const id = (await getUUID()) || '';
if (id == '' || !id) {
state = 'none';
isLoading = false;
return;
}
const status = await submit(id);
if (status == 201) {
console.log('Registered Successfully');
state = 'done';
} else if (status == 401) {
console.log('Invalid Key');
state = 'unauth';
} else {
console.log('Error');
state = 'error';
}
isLoading = false;
});
</script> </script>
<Header {title} /> <Header {title} />
{#if isLoading}
<Loading /> {#if state}
{/if} {#if status == "okay"}
{#if state == 'none'} <p class="title-ish">You are now registered</p>
<p>Unable to read your access key.</p> <p>Your secret key will be stored in your browser.</p>
<p>Please click the link in your email again.</p> <p>If you change browsers, change device or clear your browsing data, you may have to register again.</p>
{:else if state == 'unauth'} {:else if status == "fail"}
<p>Your link is not valid, links expire after 30 minutes.</p> <p class="title-ish">Your code was not accepted</p>
<p>You can try to register again.</p> <p>The code expires after 1 hour, you can check the code and enter it again or request a <a href="/more/reg">new code</a>.</p>
{:else if state == 'error'} {/if}
<p>There was an error on our end, please try again later</p> {:else}
{:else if state == 'done'} <p class="title-ish">Enter your registration code below</p>
<p>You are now logged in</p> <form on:submit={handleSubmit} id="codeInputForm">
{#each inputs as input, index}
<input class="code-in" bind:value={input.value} id={`input-${input.id}`} maxlength="1" autocomplete="off" on:keydown={(event) => handleInput(index, event)} />
{/each}
<br />
<button type="submit">Submit</button>
</form>
{/if} {/if}
<Nav /> <Nav />
<style> <style>
.title-ish {
font-size: 20px;
}
.code-in {
margin: 3px;
margin-bottom: 20px;
width: 29px;
height: 39px;
font-size: 30px;
text-align: center;
text-transform: uppercase;
border-radius: 10px;
border: none;
}
button {
border: none;
background-color: var(--island-bg-color);
color: var(--main-text-color);
width: 35%;
min-width: 95px;
max-width: 231px;
height: 30px;
border-radius: 50px;
font-size: 18px;
}
p { p {
margin: 14px; margin-left: 40px;
margin-right: 40px;
} }
</style> </style>