Skip to content

Commit

Permalink
Add all moderator pages to svelte
Browse files Browse the repository at this point in the history
  • Loading branch information
PeterJFB committed Aug 20, 2023
1 parent 4bf4506 commit 22c3028
Show file tree
Hide file tree
Showing 20 changed files with 441 additions and 29 deletions.
3 changes: 0 additions & 3 deletions app/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ router.get('/admin*', checkAdmin, (req, res, next) => {

// Make sure all moderator routes are secure
router.get('/moderator*', checkModerator, (req, res, next) => {
if (env.NODE_ENV !== 'development') {
return res.render('moderatorIndex'); // Remove when migration is finished
}
next();
});

Expand Down
Binary file added src/lib/assets/deactivate.mp3
Binary file not shown.
38 changes: 31 additions & 7 deletions src/lib/utils/callApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,58 @@ const callApi = async <
input: string,
method: RequestInit['method'] = 'GET',
body?: ReqBody,
headers?: RequestInit['headers']
): Promise<{ status: number; body: ResBody }> => {
headers?: RequestInit['headers'],
fetchFunc = fetch
): Promise<
| {
result: 'success';
status: number;
body: ResBody;
}
| {
result: 'failure';
status: number;
body: {
message: string;
name: string;
};
}
> => {
let xsrfToken = get(xsrf);
if (!xsrfToken && method.toUpperCase() !== 'GET') {
await generateXSRFToken();
xsrfToken = get(xsrf);
}

const res = await fetch('/api' + input, {
const res = await fetchFunc('/api' + input, {
headers: {
...headers,
'Content-Type': body ? 'application/json' : undefined,
'content-type': body ? 'application/json' : undefined,
'X-XSRF-TOKEN': xsrfToken,
},
method,
body: body ? JSON.stringify(body) : undefined,
});

let resBody: ResBody;
let resBody: ResBody & { message: string; name: string };
if (res.headers.get('Content-Type')?.includes('application/json')) {
resBody = await res.json();
}
return { status: res.status, body: resBody };

if (res.status < 400) {
return { result: 'success', status: res.status, body: resBody };
} else {
return {
result: 'failure',
status: res.status,
body: resBody,
};
}
};

export const generateXSRFToken = async () => {
const res = await callApi<{ csrfToken: string }>('/auth/token');
if (res.status === 200) {
if (res.result === 'success') {
xsrf.set(res.body.csrfToken);
} else {
console.error('Could not retrieve csrf-token');
Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/cardKeyScanStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,11 @@ export const cardKeyScanStore = writable<{ cardKey: number; time: number }>(
};
}
} catch (e) {
console.error(e);
if (window.navigator.userAgent.includes('Android')) {
alerts.push(e, 'ERROR');
}
window.location.assign('/moderator/serial_error');
console.error(e);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/userApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const changeCard = (user: Record<string, unknown>) => {
};

export const countActiveUsers = () => {
return callApi('/user/count?active=true');
return callApi<{ users: number }>('/user/count?active=true');
};

export const deactivateNonAdminUsers = () => {
Expand Down
17 changes: 5 additions & 12 deletions src/routes/(election)/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,23 @@
let priorities: IAlternative[] = [];
type ErrorCode = {
name: string;
};
type ErrorMessage = {
message: string;
};
const getActiveElection = async (accessCode: string = '') => {
const res = await callApi<PopulatedElection & ErrorCode & ErrorMessage>(
const res = await callApi<PopulatedElection>(
'/election/active?accessCode=' + accessCode
);
if (res.status === 200) {
if (res.result === 'success') {
priorities = [];
electionExists = true;
activeElection = res.body;
errorCode = '';
} else {
errorCode = res.body.name;
if (res.status == 404) {
if (res.status === 404) {
electionExists = false;
activeElection = null;
accessCode = '';
} else if (res.status == 403) {
} else if (res.status === 403) {
electionExists = true;
activeElection = null;
accessCode = '';
Expand All @@ -62,7 +55,7 @@
election,
priorities,
});
if (res.status === 201) {
if (res.result === 'success') {
activeElection = null;
priorities = [];
electionExists = false;
Expand Down
2 changes: 1 addition & 1 deletion src/routes/(election)/retrieve/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
const res = await callApi<typeof vote>('/vote', 'GET', null, {
'Vote-Hash': voteHash,
});
if (res.status === 200) {
if (res.result === 'success') {
vote = res.body;
}
};
Expand Down
4 changes: 2 additions & 2 deletions src/routes/auth/login/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@
Object.fromEntries(new FormData(e.currentTarget))
);
if (res.status == 200) {
if (res.result === 'success') {
window.location.assign('/');
} else if (res.status == 401) {
} else if (res.status === 401) {
feedback = 'authfailed';
} else {
feedback = 'unknownError';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
if (firstCall || !cardKey) return (firstCall = false);
const res = await userApi.toggleUser(cardKey);
if (res.status === 200) {
if (res.result === 'success') {
const lastAlert = alerts.getLastAlert();
if (dingAudio) dingAudio.play();
Expand Down
81 changes: 81 additions & 0 deletions src/routes/moderator/(useCardKey)/change_card/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<script lang="ts">
import { alerts } from '$lib/stores';
import { cardKeyScanStore } from '$lib/utils/cardKeyScanStore';
import userApi from '$lib/utils/userApi';
import type { EventHandler } from 'svelte/elements';
let form: HTMLFormElement;
const handleChangeCard: EventHandler<SubmitEvent, HTMLFormElement> = async (
e
) => {
e.preventDefault();
const res = await userApi.changeCard({
...Object.fromEntries(new FormData(e.currentTarget)),
cardKey: $cardKeyScanStore.cardKey,
});
if (res.result === 'success') {
alerts.push('Det nye kortet er nå registert.', 'SUCCESS');
form.reset();
} else {
switch (res.body.name) {
case 'DuplicateCardError':
alerts.push('Dette kortet er allerede blitt registrert.', 'ERROR');
break;
case 'InvalidRegistrationError':
alerts.push('Ugyldig brukernavn og/eller passord.', 'ERROR');
break;
default:
alerts.push('Noe gikk galt!', 'ERROR');
}
}
};
</script>

<div class="center text-center">
<form
class="form-group"
name="createUserForm"
on:submit|preventDefault={handleChangeCard}
bind:this={form}
>
<div class="form-group">
<label for="card-number">Nytt kortnummer</label><input
class="form-control"
type="text"
name="cardKey"
value={$cardKeyScanStore.cardKey || ''}
placeholder="Vennligst skann kortet"
required
disabled
/>
</div>
<div class="form-group">
<label for="username">Brukernavn</label><input
class="form-control"
type="text"
name="username"
id="username"
required
placeholder="Skriv inn brukernavn"
/>
</div>
<div class="form-group">
<label for="password">Password</label><input
class="form-control"
type="password"
name="password"
id="password"
required
placeholder="Skriv inn passord"
/>
</div>
<button class="btn btn-outline-secondary" id="submit" type="submit"
>Registrer nytt kort</button
>
{#if !$cardKeyScanStore.cardKey}
<p class="text-danger">Kortnummer er påkrevd</p>
{/if}
</form>
</div>
124 changes: 124 additions & 0 deletions src/routes/moderator/(useCardKey)/create_user/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<script lang="ts">
import { alerts } from '$lib/stores';
import { cardKeyScanStore } from '$lib/utils/cardKeyScanStore';
import userApi from '$lib/utils/userApi';
import type { EventHandler } from 'svelte/elements';
let form: HTMLFormElement;
let username: string = '';
let password: string = '';
let confirmPassword: string = '';
$: usernameMinLength = username.length >= 5;
$: usernamePattern = username.match(/^[a-zA-Z0-9]+$/);
$: passwordMinLength = password.length >= 5;
$: passwordMatch = password === confirmPassword;
$: disableSubmit =
!usernameMinLength ||
!usernamePattern ||
!passwordMinLength ||
!passwordMatch ||
!$cardKeyScanStore.cardKey;
const handleCreateUser: EventHandler<SubmitEvent, HTMLFormElement> = async (
e
) => {
e.preventDefault();
const res = await userApi.createUser({
...Object.fromEntries(new FormData(e.currentTarget)),
cardKey: $cardKeyScanStore.cardKey,
});
if (res.result === 'success') {
alerts.push('Bruker registrert!', 'SUCCESS');
form.reset();
} else {
switch (res.body.name) {
case 'DuplicateUsernameError':
alerts.push('Dette brukernavnet er allerede i bruk.', 'ERROR');
break;
case 'DuplicateCardError':
alerts.push('Dette kortet er allerede blitt registrert.', 'ERROR');
break;
default:
alerts.push('Noe gikk galt!', 'ERROR');
}
}
};
</script>

<div class="center text-center">
<form
class="form-group"
on:submit|preventDefault={handleCreateUser}
name="createUserForm"
bind:this={form}
>
<div class="form-group">
<label for="cardKey">Kortnummer</label><input
class="form-control"
type="text"
name="cardKey"
placeholder="Scan kort"
value={$cardKeyScanStore.cardKey}
required
disabled
/>
</div>
{#if !$cardKeyScanStore.cardKey}
<p class="text-danger">Kortnummer er påkrevd</p>
{/if}
<div class="form-group">
<label for="username">Brukernavn</label><input
class="form-control"
type="text"
id="username"
name="username"
bind:value={username}
placeholder="Skriv inn brukernavn"
/>
{#if !usernameMinLength}
<p class="text-danger">Brukernavn må være minst 5 tegn</p>
{/if}
{#if !usernamePattern}
<p class="text-danger">
Brukernavn kan bare inneholde tall eller bokstaver fra A-Z
</p>
{/if}
</div>
<div class="form-group">
<label for="password">Passord</label><input
class="form-control"
type="password"
id="password"
name="password"
bind:value={password}
placeholder="Skriv inn ønsket passord"
/>
{#if !passwordMinLength}
<p class="text-danger">Passord må være minst 6 tegn</p>
{/if}
</div>
<div class="form-group">
<label for="confirmPassword">Bekreft passord</label><input
class="form-control"
type="password"
id="confirmPassword"
name="confirmPassword"
bind:value={confirmPassword}
placeholder="Bekreft passord"
/>
{#if !passwordMatch}
<p class="text-danger">Må være lik passordet</p>
{/if}
</div>
<button
class="btn btn-outline-secondary"
id="submit"
type="submit"
disabled={disableSubmit}>Lag ny bruker</button
>
</form>
</div>

0 comments on commit 22c3028

Please sign in to comment.