diff --git a/docker-compose.yml b/docker-compose.yml index 4a58128..223872d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,6 +7,8 @@ services: - DATABASE_URL=postgres://adventurelog:PO24VjITwGgk@db:5432/adventurelog # ORIGIN is only necessary when not using a reverse proxy or hosting that includes https - ORIGIN=http://localhost:3000 + - SKIP_DB_WAIT=false + # Only necessary for externaly hosted databases such as NeonDB depends_on: - db volumes: diff --git a/migrations/0003_easy_iron_monger.sql b/migrations/0003_easy_iron_monger.sql new file mode 100644 index 0000000..8d6046e --- /dev/null +++ b/migrations/0003_easy_iron_monger.sql @@ -0,0 +1,3 @@ +ALTER TABLE "user" ADD COLUMN "signup_date" timestamp with time zone NOT NULL;--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "last_login" timestamp with time zone;--> statement-breakpoint +ALTER TABLE "user" ADD COLUMN "role" text NOT NULL; \ No newline at end of file diff --git a/migrations/meta/0003_snapshot.json b/migrations/meta/0003_snapshot.json new file mode 100644 index 0000000..dc62400 --- /dev/null +++ b/migrations/meta/0003_snapshot.json @@ -0,0 +1,409 @@ +{ + "id": "72cc9a9a-a12e-4ca2-b644-b704673af4d7", + "prevId": "91692e84-91ec-4411-ad9d-7b8b14f67dda", + "version": "5", + "dialect": "pg", + "tables": { + "featuredAdventures": { + "name": "featuredAdventures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "featuredAdventures_name_unique": { + "name": "featuredAdventures_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "sharedAdventures": { + "name": "sharedAdventures", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "data": { + "name": "data", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "date": { + "name": "date", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hashed_password": { + "name": "hashed_password", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "signup_date": { + "name": "signup_date", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "last_login": { + "name": "last_login", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "userVisitedAdventures": { + "name": "userVisitedAdventures", + "schema": "", + "columns": { + "adventure_id": { + "name": "adventure_id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "adventure_name": { + "name": "adventure_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "location": { + "name": "location", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "visited_date": { + "name": "visited_date", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "userVisitedAdventures_user_id_user_id_fk": { + "name": "userVisitedAdventures_user_id_user_id_fk", + "tableFrom": "userVisitedAdventures", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "userVisitedWorldTravel": { + "name": "userVisitedWorldTravel", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "region_id": { + "name": "region_id", + "type": "varchar", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "userVisitedWorldTravel_country_code_worldTravelCountries_country_code_fk": { + "name": "userVisitedWorldTravel_country_code_worldTravelCountries_country_code_fk", + "tableFrom": "userVisitedWorldTravel", + "tableTo": "worldTravelCountries", + "columnsFrom": [ + "country_code" + ], + "columnsTo": [ + "country_code" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "userVisitedWorldTravel_user_id_user_id_fk": { + "name": "userVisitedWorldTravel_user_id_user_id_fk", + "tableFrom": "userVisitedWorldTravel", + "tableTo": "user", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "userVisitedWorldTravel_region_id_worldTravelCountryRegions_id_fk": { + "name": "userVisitedWorldTravel_region_id_worldTravelCountryRegions_id_fk", + "tableFrom": "userVisitedWorldTravel", + "tableTo": "worldTravelCountryRegions", + "columnsFrom": [ + "region_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "worldTravelCountries": { + "name": "worldTravelCountries", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "serial", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "continent": { + "name": "continent", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "worldTravelCountries_country_code_unique": { + "name": "worldTravelCountries_country_code_unique", + "nullsNotDistinct": false, + "columns": [ + "country_code" + ] + } + } + }, + "worldTravelCountryRegions": { + "name": "worldTravelCountryRegions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "varchar", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "info": { + "name": "info", + "type": "json", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "worldTravelCountryRegions_country_code_worldTravelCountries_country_code_fk": { + "name": "worldTravelCountryRegions_country_code_worldTravelCountries_country_code_fk", + "tableFrom": "worldTravelCountryRegions", + "tableTo": "worldTravelCountries", + "columnsFrom": [ + "country_code" + ], + "columnsTo": [ + "country_code" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index 12ecd45..a1f987e 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1713125110816, "tag": "0002_far_mephistopheles", "breakpoints": true + }, + { + "idx": 3, + "version": "5", + "when": 1713402092365, + "tag": "0003_easy_iron_monger", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts index 303f47f..f600f11 100644 --- a/src/lib/db/schema.ts +++ b/src/lib/db/schema.ts @@ -28,6 +28,15 @@ export const userTable = pgTable("user", { last_name: text("last_name").notNull(), icon: text("icon"), hashed_password: varchar("hashed_password").notNull(), + signup_date: timestamp("signup_date", { + withTimezone: true, + mode: "date", + }).notNull(), + last_login: timestamp("last_login", { + withTimezone: true, + mode: "date", + }), + role: text("role").notNull(), }); // export type SelectUser = typeof userTable.$inferSelect; diff --git a/src/lib/server/auth.ts b/src/lib/server/auth.ts index 8a1b9d9..34c1d0a 100644 --- a/src/lib/server/auth.ts +++ b/src/lib/server/auth.ts @@ -20,6 +20,9 @@ export const lucia = new Lucia(adapter, { first_name: attributes.first_name, last_name: attributes.last_name, icon: attributes.icon, + signup_date: attributes.signup_date, + last_login: attributes.last_login, + role: attributes.role, }; }, }); @@ -38,4 +41,7 @@ export interface DatabaseUser { last_name: string; icon: string; hashed_password: string; + signup_date: Date; + last_login: Date; + role: string; } diff --git a/src/routes/login/+page.server.ts b/src/routes/login/+page.server.ts index 5d67d1a..f3a1563 100644 --- a/src/routes/login/+page.server.ts +++ b/src/routes/login/+page.server.ts @@ -47,7 +47,7 @@ export const actions: Actions = { }); } - const existingUser = await db + const existingUser:any = await db .select() .from(userTable) .where(eq(userTable.username, username)) @@ -70,6 +70,14 @@ export const actions: Actions = { }); } + await db + .update(userTable) + .set({ + last_login: new Date(), + }) + .where(eq(userTable.id, existingUser.id)) + .execute(); + const session = await lucia.createSession(existingUser.id, {}); const sessionCookie = lucia.createSessionCookie(session.id); event.cookies.set(sessionCookie.name, sessionCookie.value, { diff --git a/src/routes/settings/+page.svelte b/src/routes/settings/+page.svelte index d4ef414..9d2ce7b 100644 --- a/src/routes/settings/+page.svelte +++ b/src/routes/settings/+page.svelte @@ -7,6 +7,8 @@ let last_name = data.user?.last_name; let user_id = data.user?.id; let icon = data.user?.icon; + let signup_date = data.user?.signup_date; + let role = data.user?.role;