Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: user, group basic endpoints #36

Closed
wants to merge 12 commits into from
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,9 @@ TBA
- Keep commits and PRs atomic.
- A PR should be a single feature or bug fix.
- A commit should be a single logical change.

### Environment Variables

If you need credentials for the `.env` file, contact the project lead ([Minh](https://github.com/minhxNguyen7/)).

After changes to the .env file, run `pnpm run check` to update SvelteKit's auto-generated environment variable types.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"dependencies": {
"@iconify/json": "^2.2.160",
"@lucia-auth/adapter-prisma": "3.0.2",
"@lucia-auth/oauth": "^3.5.3",
"@prisma/client": "5.6.0",
"lucia": "2.7.4",
"svelty-picker": "^5.2.1",
Expand Down
11 changes: 11 additions & 0 deletions pnpm-lock.yaml

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

Binary file modified prisma/dev.db
Binary file not shown.
146 changes: 46 additions & 100 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,19 @@ datasource db {
// Do not modify anything above this line unless you know what you are doing.

model User {
id String @id @unique @default(cuid())

email String @unique
firstName String
lastName String
verified Boolean @default(false)
receiveEmail Boolean @default(true)
token String? @unique

meetingsHosted Meeting[] @relation("hostId")
groups GroupMembers[]
notifications UserNotifications[]
generalAvailability GeneralAvailability[]
meetingSpecificAvailability MeetingSpecificAvailability[]
meetingParticipants MeetingParticipants[]

createdAt DateTime @default(now())
updatedAt DateTime @updatedAt

auth_session Session[]
key Key[]
id String @id @unique @default(uuid())
username String @unique
email String @unique
token String? @unique

created_at DateTime? @default(now())
groups Group[]
meetings Meeting[]
generalAvailability Availability? @relation(fields: [availabilityId], references: [id])
availabilityId String?
MeetingUserAvailability MeetingUserAvailability[]
Key Key[]
Session Session[]
}

model Key {
Expand All @@ -59,91 +51,45 @@ model Session {
}

model Meeting {
id String @id @default(uuid())
title String
description String?
startTime Int
endTime Int
location String?
hostId String
created_at Int
host User @relation("hostId", fields: [hostId], references: [id])
participants MeetingParticipants[]
groups MeetingGroups[]
agendaItems MeetingAgendaItems[]
MeetingSpecificAvailability MeetingSpecificAvailability[]
id String @id @unique @default(uuid())
title String
description String?
date DateTime
location String?
Invitees User[]
host_id String
group Group? @relation(fields: [groupId], references: [id])
from_time DateTime
to_time DateTime
groupId String?
MeetingUserAvailability MeetingUserAvailability[]
}

model Groups {
id String @id @default(uuid())
model Group {
id String @id @unique @default(uuid())
name String
description String?
created_at Int
members GroupMembers[]
meetings MeetingGroups[]
}

model GroupMembers {
userId String
groupId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
group Groups @relation(fields: [groupId], references: [id], onDelete: Cascade)

@@id([userId, groupId])
}

model MeetingParticipants {
meetingId String
userId String
status String
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)

@@id([meetingId, userId])
}

model MeetingGroups {
meetingId String
groupId String
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
group Groups @relation(fields: [groupId], references: [id], onDelete: Cascade)

@@id([meetingId, groupId])
}

model MeetingAgendaItems {
id String @id @default(uuid())
meetingId String
title String
description String?
duration Int?
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
}

model UserNotifications {
id String @id @default(uuid())
userId String
message String
timestamp Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
created_at DateTime?
members User[]
Meeting Meeting[]
}

model GeneralAvailability {
id String @id @default(uuid())
userId String
dayOfWeek Int
startTime Int
endTime Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
model MeetingUserAvailability {
id String @id @unique @default(uuid())
meeting Meeting @relation(fields: [meetingId], references: [id])
user User? @relation(fields: [userId], references: [id])
Availability Availability? @relation(fields: [availabilityId], references: [id])
meetingId String
userId String?
availabilityId String?
}

model MeetingSpecificAvailability {
id String @id @default(uuid())
userId String
meetingId String
date Int
startTime Int
endTime Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
model Availability {
id String @id @unique @default(cuid())
from_time String
to_time String
from_date String
to_date String
User User[]
MeetingUserAvailability MeetingUserAvailability[]
}
6 changes: 1 addition & 5 deletions src/app.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,7 @@ declare global {
type UserAttributes = {
userId: string;
email: string;
firstName: string;
lastName: string;
// role: string;
verified: boolean;
receiveEmail: boolean;
username: string;
token: string;
};
}
Expand Down
2 changes: 2 additions & 0 deletions src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ export const handle: Handle = async ({ event, resolve }) => {
if (event.locals?.auth) {
const session = await event.locals.auth.validate();
const user = session?.user;

if (user) {
event.locals.user = user;
}

if (event.route.id?.startsWith("/(protected)")) {
if (!user) throw redirect(302, "/auth");
// if (!user.verified) throw redirect(302, "/auth/verify/email");
Expand Down
42 changes: 11 additions & 31 deletions src/lib/components/auth/register.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
export let data;

const registerSchema = userSchema.pick({
firstName: true,
lastName: true,
username: true,
email: true,
password: true,
});
Expand All @@ -26,43 +25,24 @@
<!--<SuperDebug data={$form} />-->
<div class="mt-6">
<label class="label">
<span class="sr-only">First Name</span>
<span class="sr-only">Username</span>
<input
id="firstName"
name="firstName"
id="username"
name="username"
type="text"
placeholder="first name"
autocomplete="given-name"
data-invalid={$errors.firstName}
bind:value={$form.firstName}
placeholder="username"
autocomplete="username"
data-invalid={$errors.username}
bind:value={$form.username}
class="input"
class:input-error={$errors.firstName}
class:input-error={$errors.username}
/>
{#if $errors.firstName}
<small>{$errors.firstName}</small>
{#if $errors.username}
<small>{$errors.username}</small>
{/if}
</label>
</div>

<div class="mt-6">
<label class="label">
<span class="sr-only">Last Name</span>
<input
id="lastName"
name="lastName"
type="text"
placeholder="last name"
autocomplete="family-name"
data-invalid={$errors.lastName}
bind:value={$form.lastName}
class="input"
class:input-error={$errors.lastName}
/>
{#if $errors.lastName}
<small>{$errors.lastName}</small>
{/if}
</label>
</div>
<div class="mt-6">
<label class="label">
<span class="sr-only">Email</span>
Expand Down
10 changes: 3 additions & 7 deletions src/lib/config/zod-schemas.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { z } from "zod";

export const userSchema = z.object({
firstName: z
.string({ required_error: "First Name is required" })
.min(1, { message: "First Name is required" })
.trim(),
lastName: z
.string({ required_error: "Last Name is required" })
.min(1, { message: "Last Name is required" })
username: z
.string({ required_error: "Username is required" })
.min(1, { message: "Username is required" })
.trim(),
email: z
.string({ required_error: "Email is required" })
Expand Down
19 changes: 19 additions & 0 deletions src/lib/server/lucia.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { prisma } from "@lucia-auth/adapter-prisma";
import { google } from "@lucia-auth/oauth/providers";
import { lucia } from "lucia";
import { sveltekit } from "lucia/middleware";

import { dev } from "$app/environment";
import {
GOOGLE_OAUTH_CLIENT_ID,
GOOGLE_OAUTH_CLIENT_SECRET,
GOOGLE_OAUTH_REDIRECT_URI,
} from "$env/static/private";
import { prisma as client } from "$lib/server/prisma";

export const auth = lucia({
Expand All @@ -23,8 +29,21 @@ export const auth = lucia({
verified: data.verified,
receiveEmail: data.receiveEmail,
token: data.token,

googleId: data.google_id,
username: data.username,
};
},
});

export const googleAuth = google(auth, {
clientId: GOOGLE_OAUTH_CLIENT_ID!,
clientSecret: GOOGLE_OAUTH_CLIENT_SECRET!,
redirectUri: GOOGLE_OAUTH_REDIRECT_URI!,
scope: [
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email",
],
});

export type Auth = typeof auth;
11 changes: 10 additions & 1 deletion src/routes/auth/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<div class="mt-48 flex min-h-[100vh] justify-center">
<div class="mx-2 w-[450px] md:mx-16">
{#if data.user}
<p>{data.user.firstName} {data.user.lastName} {data.user.userId}</p>
<p>{data.user.username} {data.user.userId}</p>

<div>
<form use:enhance action="/auth/logout" method="post">
Expand All @@ -24,6 +24,15 @@
</div>
{/if}

<div class="mb-4">
<a
href="/auth/login/google"
class="mx-auto flex w-fit rounded-md bg-blue-500 p-2 font-semibold text-white"
>
Continue with Google
</a>
</div>

<TabGroup justify="justify-center">
<Tab bind:group={tabSet} name="signInTab" value={"signIn"}>Sign In</Tab>
<Tab bind:group={tabSet} name="signUpTab" value={"signUp"}>Sign Up</Tab>
Expand Down
Loading
Loading