Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 126 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"type": "module",
"dependencies": {
"@lucia-auth/adapter-drizzle": "^1.0.3",
"@sendgrid/mail": "^8.1.3",
"ably": "^1.2.50",
"drizzle-orm": "^0.30.1",
"oslo": "^1.1.3",
Expand Down
9 changes: 9 additions & 0 deletions src/lib/db/schema/user.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,12 @@ export const sessionTable = pgTable('sessions', {
mode: 'date'
}).notNull()
});

export const emailVerificationTable = pgTable('email-verification', {
id: text('id').primaryKey(),
userId: text('user_id')
.notNull()
.references(() => userTable.id),
isActive: boolean('is_active').default(true),
createdAt: timestamp('created_at').defaultNow()
});
2 changes: 1 addition & 1 deletion src/lib/server/db.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import {env} from '$env/dynamic/private';
import { env } from '$env/dynamic/private';
import { dev } from '$app/environment';
import { DrizzlePostgreSQLAdapter } from '@lucia-auth/adapter-drizzle';
import * as userSchema from '$lib/db/schema/user.schema';
Expand Down
6 changes: 6 additions & 0 deletions src/lib/server/sendgrid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import sgMail from '@sendgrid/mail';
import { env } from '$env/dynamic/private';

sgMail.setApiKey(env.SENDGRID_API_KEY);

export default sgMail;
Empty file.
23 changes: 23 additions & 0 deletions src/lib/server/utils/send-verification-mail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import sgMail from '$lib/server/sendgrid';
import { env } from '$env/dynamic/private';

type SendVerificationMailProps = {
to: string;
verificationUrl: string;
};

export default async function sendVerificationMail({
to,
verificationUrl
}: SendVerificationMailProps) {
const msg = {
to,
from: env.SENDGRID_FROM_EMAIL_ID,
subject: 'Connect email verification',
text: 'Click the link below to verify your email address',
html: `<a href=${verificationUrl}>Verify Account</a>`
};

const response = await sgMail.send(msg);
return response;
}
Empty file.
Empty file.
42 changes: 42 additions & 0 deletions src/routes/verify-email/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Actions } from './$types';
import { redirect, fail } from '@sveltejs/kit';
import sendVerificationMail from '$lib/server/utils/send-verification-mail';
import { generateId } from 'lucia';
import { emailVerificationTable } from '$lib/db/schema/user.schema';
import { db } from '$lib/server/db';
import { env } from '$env/dynamic/public';
import { dev } from '$app/environment';

export const actions: Actions = {
'send-verfication-mail': async (event) => {
try {
if (!event.locals.user) redirect(302, '/login');

const userId = event.locals.user.id;
const userEmail = event.locals.user.email;

const [verficationEmail] = await db
.insert(emailVerificationTable)
.values({
id: generateId(15),
userId
})
.returning();

if (!verficationEmail) {
throw new Error('Could not create verification email entry in db.');
}

sendVerificationMail({
to: userEmail,
verificationUrl: `${env.PUBLIC_BASE_URL}/verify-email/${verficationEmail.id}`
});
} catch (error) {
let devmsg = error;
if (error instanceof Error) devmsg = error.message;
return fail(500, {
error: `Something went wrong, could not send verfication mail at the moment. Pls try again later. ${dev ? devmsg : null}`
});
}
}
};
41 changes: 41 additions & 0 deletions src/routes/verify-email/[slug]/+page.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { PageServerLoad } from './$types';
import { db } from '$lib/server/db';
import { fail, json } from '@sveltejs/kit';
import { emailVerificationTable } from '$lib/db/schema/user.schema';
import { eq } from 'drizzle-orm';
import { dev } from '$app/environment';

export const load: PageServerLoad = async (event) => {
try {
const mailVerificationId = event.params.slug;

const verification = await db.query.emailVerificationTable.findFirst({
where: (ct, { eq }) => eq(ct.id, mailVerificationId)
});

if (!verification) {
return fail(400, {
error: 'Invalid link'
});
}

if (verification.isActive) {
await db
.update(emailVerificationTable)
.set({ isActive: false })
.where(eq(emailVerificationTable.id, verification.id));
} else {
return fail(400, {
error: 'Verification email link expired.'
});
}

json(200, {
statusText: 'Success'
});
} catch (error) {
return fail(500, {
error: `Something went wrong verifying email address, pls try again later. ${dev ? error : ''}`
});
}
};