feat(auth): add Discord OAuth sign-in and user timezones
Add persistent user and session storage, protected profile requests, and React sign-in controls. Capture and preserve each user's timezone, and load development and production configuration before migrations and server startup.
This commit is contained in:
22
drizzle/0000_discord_auth.sql
Normal file
22
drizzle/0000_discord_auth.sql
Normal file
@@ -0,0 +1,22 @@
|
||||
CREATE TABLE `sessions` (
|
||||
`token_hash` text PRIMARY KEY NOT NULL,
|
||||
`user_id` text NOT NULL,
|
||||
`created_at` integer NOT NULL,
|
||||
`expires_at` integer NOT NULL,
|
||||
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE INDEX `sessions_user_id_idx` ON `sessions` (`user_id`);--> statement-breakpoint
|
||||
CREATE INDEX `sessions_expires_at_idx` ON `sessions` (`expires_at`);--> statement-breakpoint
|
||||
CREATE TABLE `users` (
|
||||
`id` text PRIMARY KEY NOT NULL,
|
||||
`discord_id` text NOT NULL,
|
||||
`username` text NOT NULL,
|
||||
`global_name` text,
|
||||
`avatar_hash` text,
|
||||
`timezone` text DEFAULT 'UTC' NOT NULL,
|
||||
`created_at` integer NOT NULL,
|
||||
`updated_at` integer NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX `users_discord_id_unique` ON `users` (`discord_id`);
|
||||
160
drizzle/meta/0000_snapshot.json
Normal file
160
drizzle/meta/0000_snapshot.json
Normal file
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"version": "6",
|
||||
"dialect": "sqlite",
|
||||
"id": "1d46cf45-94a2-434f-b5d7-bc0346cc1fdd",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"tables": {
|
||||
"sessions": {
|
||||
"name": "sessions",
|
||||
"columns": {
|
||||
"token_hash": {
|
||||
"name": "token_hash",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"expires_at": {
|
||||
"name": "expires_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"sessions_user_id_idx": {
|
||||
"name": "sessions_user_id_idx",
|
||||
"columns": [
|
||||
"user_id"
|
||||
],
|
||||
"isUnique": false
|
||||
},
|
||||
"sessions_expires_at_idx": {
|
||||
"name": "sessions_expires_at_idx",
|
||||
"columns": [
|
||||
"expires_at"
|
||||
],
|
||||
"isUnique": false
|
||||
}
|
||||
},
|
||||
"foreignKeys": {
|
||||
"sessions_user_id_users_id_fk": {
|
||||
"name": "sessions_user_id_users_id_fk",
|
||||
"tableFrom": "sessions",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"onDelete": "cascade",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
},
|
||||
"users": {
|
||||
"name": "users",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"discord_id": {
|
||||
"name": "discord_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"username": {
|
||||
"name": "username",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"global_name": {
|
||||
"name": "global_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"avatar_hash": {
|
||||
"name": "avatar_hash",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"autoincrement": false
|
||||
},
|
||||
"timezone": {
|
||||
"name": "timezone",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false,
|
||||
"default": "'UTC'"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"autoincrement": false
|
||||
}
|
||||
},
|
||||
"indexes": {
|
||||
"users_discord_id_unique": {
|
||||
"name": "users_discord_id_unique",
|
||||
"columns": [
|
||||
"discord_id"
|
||||
],
|
||||
"isUnique": true
|
||||
}
|
||||
},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"checkConstraints": {}
|
||||
}
|
||||
},
|
||||
"views": {},
|
||||
"enums": {},
|
||||
"_meta": {
|
||||
"schemas": {},
|
||||
"tables": {},
|
||||
"columns": {}
|
||||
},
|
||||
"internal": {
|
||||
"indexes": {}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,13 @@
|
||||
{"version":"7","dialect":"sqlite","entries":[]}
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "sqlite",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "6",
|
||||
"when": 1788501609255,
|
||||
"tag": "0000_discord_auth",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user