Skip to content

Commit d9b3456

Browse files
DropheartJoshua Gonsalves
andauthored
feat: update drizzle, email login, seedfile changes
* feat: update drizzle & use bun driver * feat: update seed, email login * fix: login route ABC api logic * refactor: some cleanup of abc api interfacing, email * feat: login bar + prettier got opinionated ?? * chore: don't double send email, email text changes * fix: add missing var to env example (abc api base) * chore: update dockerfile to version im currently using * refactor: robust academic year calculations + renamed variables for clarity + log email when not in prod. + rename token table to auth_token WARN: consider state not being init error. * refactor: mailer use API logger * feat: consolidate migrations into one --------- Co-authored-by: Joshua Gonsalves <[email protected]>
1 parent 6fadd96 commit d9b3456

27 files changed

+1041
-332
lines changed

.env.example

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,13 @@ PGUSER=
99
PGPASSWORD=
1010
PGHOST=
1111
PGPORT=
12-
PGDB=
12+
PGDB=
13+
14+
NODEMAILER_HOST=smtp-mail.outlook.com
15+
NODEMAILER_PORT=587
16+
NODEMAILER_USER=
17+
NODEMAILER_PASS=
18+
19+
ABC_API_BASE=https://abc-api.doc.ic.ac.uk
20+
ABC_API_USER=docsoc
21+
ABC_API_PASS=

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM oven/bun:1.1.29
1+
FROM oven/bun:1.2.22
22

33
ARG WEBMASTERS
44
ENV WEBMASTERS $WEBMASTERS

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Although using Nuxt 3, we have opted to use Nuxt 4 in our build. [`app/`](/app/)
1616

1717
Visit [Microsoft Entra admin center](https://entra.microsoft.com/) -> App registrations -> \[your mums and dads app]. Copy your tenant ID and client ID into `.env`, and generate a client secret from 'Certificates & secrets' to copy into `.env`.
1818

19-
Fill out the rest of the `.env` file - note that webmasters is comma seperated and restricts admin routes. JWT_SECRET should be a randomly generated long string with no dollar signs, or else Docker gets mad.
19+
Fill out the rest of the `.env` file - note that webmasters is comma seperated and restricts admin routes. JWT_SECRET should be a randomly generated long string with no dollar signs, or else Docker gets mad. ABC API credentials are those used to log in to Scientia. Nodemailer credentials are those used to authenticate with Microsoft.
2020

2121
Next, build the docker images.
2222

@@ -36,6 +36,8 @@ docker compose start postgres
3636
docker compose up postgres
3737
```
3838

39+
If you haven't, you will also need to push the database schema.
40+
3941
Finally, run the website.
4042

4143
```bash

app/components/EmailPrompt.vue

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<template>
2+
<div>
3+
<div @click="focus = !focus">
4+
<slot />
5+
</div>
6+
<div
7+
v-if="focus"
8+
class="absolute -ml-52 mt-2 flex items-center justify-center">
9+
<div class="rounded-lg bg-white p-6 shadow-lg">
10+
<h2 class="mb-4 text-lg font-bold">Enter your shortcode email</h2>
11+
<input
12+
@keyup.enter="sendLoginEmail"
13+
:pattern="shortcodeEmailRegex.source"
14+
v-model="email"
15+
type="email"
16+
placeholder="[email protected]"
17+
class="mb-4 w-full rounded border p-2 invalid:border-red-500" />
18+
<div class="flex justify-end gap-2">
19+
<button
20+
@click="focus = false"
21+
class="rounded bg-gray-300 px-4 py-2 hover:bg-gray-400">
22+
Cancel
23+
</button>
24+
<button
25+
@click="sendLoginEmail"
26+
class="rounded bg-blue-500 px-4 py-2 text-white hover:bg-blue-600">
27+
{{ loading ? 'Loading...' : 'Submit' }}
28+
</button>
29+
</div>
30+
</div>
31+
</div>
32+
</div>
33+
</template>
34+
35+
<script lang="ts" setup>
36+
import { shortcodeEmailRegex } from '~~/hono/types';
37+
38+
const focus = ref(false);
39+
const loading = ref(false);
40+
const email = ref('');
41+
42+
const sendLoginEmail = async () => {
43+
if (loading.value) return;
44+
if (!shortcodeEmailRegex.test(email.value)) {
45+
return alert('Please use your Imperial shortcode email.');
46+
}
47+
48+
loading.value = true;
49+
const res = await fetch('/api/auth/login', {
50+
method: 'POST',
51+
body: JSON.stringify({ email: email.value }),
52+
headers: { 'Content-Type': 'application/json' }
53+
});
54+
loading.value = false;
55+
56+
if (res.ok) {
57+
alert('Login email sent! Please check your inbox.');
58+
focus.value = false;
59+
email.value = '';
60+
} else {
61+
alert('Failed to send login email. Please try again.');
62+
}
63+
};
64+
</script>

app/components/navigation/Bar.vue

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,17 @@ const { currentUser } = useAuth();
1111
</NavigationLink>
1212
<ul class="flex items-center gap-3">
1313
<li v-if="currentUser === null">
14-
<a
14+
<!-- <a
1515
class="cursor-pointer font-bold text-white hover:text-white hover:no-underline md:text-xl"
1616
href="/api/auth/signIn">
1717
Log In
18-
</a>
18+
</a> -->
19+
<EmailPrompt>
20+
<p
21+
class="cursor-pointer font-bold text-white hover:text-white hover:no-underline md:text-xl">
22+
Log In
23+
</p>
24+
</EmailPrompt>
1925
</li>
2026
<li v-if="currentUser !== null">
2127
<NavigationLink to="/portal">

app/middleware/requireAdmin.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ export default defineNuxtRouteMiddleware((to, from) => {
33
const { currentUser } = useAuth();
44
// I am aware that the client might be able to Do Things, but that's okay
55
// as if they have access to the admin page, everything is closed server-side anyways.
6-
const admins = process.env.WEBMASTERS!.split(',')
7-
6+
const admins = process.env.WEBMASTERS!.split(',');
87

98
if (!admins.includes(currentUser.value?.shortcode || '')) {
109
return createError({

app/pages/admin.vue

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,12 @@ definePageMeta({
9898
{{ statsData.registered_freshers }}
9999
</p>
100100
<p>
101-
<b>Minimum to reasonably expect (all parents + all kids):</b> {{ statsData.families * 2 + statsData.registered_freshers }}
101+
<b>Minimum to reasonably expect (all parents + all kids):</b>
102+
{{ statsData.families * 2 + statsData.registered_freshers }}
102103
</p>
103104
<p>
104-
<b>Maximum to unreasonably expect (all freshers + all parents)</b> {{ statsData.families * 2 + statsData.all_freshers }}
105+
<b>Maximum to unreasonably expect (all freshers + all parents)</b>
106+
{{ statsData.families * 2 + statsData.all_freshers }}
105107
</p>
106108
</div>
107109
</div>

app/pages/finish-email.vue

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<script setup lang="ts">
2+
const route = useRoute();
3+
4+
const { token } = route.query;
5+
6+
const { status, error } = await useFetch('/api/auth/callback-email', {
7+
method: 'POST',
8+
body: { token },
9+
server: false
10+
});
11+
12+
watch(status, () => {
13+
if (status.value == 'success') navigateTo('/portal');
14+
});
15+
</script>
16+
17+
<template>
18+
<div>
19+
<Card v-if="status == 'pending' || status == 'idle'">
20+
<CardTitle>We're signing you in...</CardTitle>
21+
</Card>
22+
<Card v-else-if="status == 'error'">
23+
<CardText>{{ error }}</CardText>
24+
</Card>
25+
<Card v-else-if="status == 'success'">
26+
<CardTitle>You are being redirected</CardTitle>
27+
<CardText>
28+
Please click
29+
<NuxtLink to="/portal">this link</NuxtLink>
30+
if not automatically redirected.
31+
</CardText>
32+
</Card>
33+
</div>
34+
</template>

app/pages/finish-oauth.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const body = !msError
1818
error_description: msErrorDesc
1919
};
2020
21-
const { status, error } = await useFetch('/api/auth/callback', {
21+
const { status, error } = await useFetch('/api/auth/callback-oauth', {
2222
method: 'POST',
2323
body: body,
2424
server: false

app/utils/types.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ declare const stateOptions = [
2121
declare type State = (typeof stateOptions)[number];
2222

2323
declare type IFamily = {
24-
id: number,
25-
parents: IStudent[],
26-
kids: IStudent[]
27-
}
24+
id: number;
25+
parents: IStudent[];
26+
kids: IStudent[];
27+
};

0 commit comments

Comments
 (0)