From 172d28a828039e211d7a87d076aea98aebdb54fd Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Mon, 24 Feb 2025 00:46:37 -0500 Subject: [PATCH 1/2] gracefully log invalid jwt token and return null users instead of an internal server error --- dev/src/collections/LocalUsers.ts | 10 + dev/src/migrations/20250224_052431.json | 568 ++++++++++++++++++++++++ dev/src/migrations/20250224_052431.ts | 180 ++++++++ dev/src/migrations/index.ts | 6 + dev/src/payload-types.ts | 102 ++++- dev/src/payload.config.ts | 3 +- src/auth-strategy.ts | 147 +++--- 7 files changed, 929 insertions(+), 87 deletions(-) create mode 100644 dev/src/collections/LocalUsers.ts create mode 100644 dev/src/migrations/20250224_052431.json create mode 100644 dev/src/migrations/20250224_052431.ts diff --git a/dev/src/collections/LocalUsers.ts b/dev/src/collections/LocalUsers.ts new file mode 100644 index 0000000..d2efb40 --- /dev/null +++ b/dev/src/collections/LocalUsers.ts @@ -0,0 +1,10 @@ +import { CollectionConfig } from "payload"; + +const Users: CollectionConfig = { + slug: "local-users", + auth: true, + admin: { useAsTitle: "email" }, + fields: [{ name: "email", type: "email", required: true }], +}; + +export default Users; diff --git a/dev/src/migrations/20250224_052431.json b/dev/src/migrations/20250224_052431.json new file mode 100644 index 0000000..4645c73 --- /dev/null +++ b/dev/src/migrations/20250224_052431.json @@ -0,0 +1,568 @@ +{ + "version": "6", + "dialect": "sqlite", + "tables": { + "local_users": { + "name": "local_users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reset_password_token": { + "name": "reset_password_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reset_password_expiration": { + "name": "reset_password_expiration", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "salt": { + "name": "salt", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "login_attempts": { + "name": "login_attempts", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "lock_until": { + "name": "lock_until", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "local_users_updated_at_idx": { + "name": "local_users_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "local_users_created_at_idx": { + "name": "local_users_created_at_idx", + "columns": ["created_at"], + "isUnique": false + }, + "local_users_email_idx": { + "name": "local_users_email_idx", + "columns": ["email"], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users": { + "name": "users", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sub": { + "name": "sub", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "users_sub_idx": { + "name": "users_sub_idx", + "columns": ["sub"], + "isUnique": false + }, + "users_updated_at_idx": { + "name": "users_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "users_created_at_idx": { + "name": "users_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_locked_documents": { + "name": "payload_locked_documents", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "global_slug": { + "name": "global_slug", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "payload_locked_documents_global_slug_idx": { + "name": "payload_locked_documents_global_slug_idx", + "columns": ["global_slug"], + "isUnique": false + }, + "payload_locked_documents_updated_at_idx": { + "name": "payload_locked_documents_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "payload_locked_documents_created_at_idx": { + "name": "payload_locked_documents_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_locked_documents_rels": { + "name": "payload_locked_documents_rels", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "local_users_id": { + "name": "local_users_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "users_id": { + "name": "users_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "payload_locked_documents_rels_order_idx": { + "name": "payload_locked_documents_rels_order_idx", + "columns": ["order"], + "isUnique": false + }, + "payload_locked_documents_rels_parent_idx": { + "name": "payload_locked_documents_rels_parent_idx", + "columns": ["parent_id"], + "isUnique": false + }, + "payload_locked_documents_rels_path_idx": { + "name": "payload_locked_documents_rels_path_idx", + "columns": ["path"], + "isUnique": false + }, + "payload_locked_documents_rels_local_users_id_idx": { + "name": "payload_locked_documents_rels_local_users_id_idx", + "columns": ["local_users_id"], + "isUnique": false + }, + "payload_locked_documents_rels_users_id_idx": { + "name": "payload_locked_documents_rels_users_id_idx", + "columns": ["users_id"], + "isUnique": false + } + }, + "foreignKeys": { + "payload_locked_documents_rels_parent_fk": { + "name": "payload_locked_documents_rels_parent_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "payload_locked_documents", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_local_users_fk": { + "name": "payload_locked_documents_rels_local_users_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "local_users", + "columnsFrom": ["local_users_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_locked_documents_rels_users_fk": { + "name": "payload_locked_documents_rels_users_fk", + "tableFrom": "payload_locked_documents_rels", + "tableTo": "users", + "columnsFrom": ["users_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_preferences": { + "name": "payload_preferences", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "payload_preferences_key_idx": { + "name": "payload_preferences_key_idx", + "columns": ["key"], + "isUnique": false + }, + "payload_preferences_updated_at_idx": { + "name": "payload_preferences_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "payload_preferences_created_at_idx": { + "name": "payload_preferences_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_preferences_rels": { + "name": "payload_preferences_rels", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "order": { + "name": "order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "parent_id": { + "name": "parent_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "local_users_id": { + "name": "local_users_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "users_id": { + "name": "users_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "payload_preferences_rels_order_idx": { + "name": "payload_preferences_rels_order_idx", + "columns": ["order"], + "isUnique": false + }, + "payload_preferences_rels_parent_idx": { + "name": "payload_preferences_rels_parent_idx", + "columns": ["parent_id"], + "isUnique": false + }, + "payload_preferences_rels_path_idx": { + "name": "payload_preferences_rels_path_idx", + "columns": ["path"], + "isUnique": false + }, + "payload_preferences_rels_local_users_id_idx": { + "name": "payload_preferences_rels_local_users_id_idx", + "columns": ["local_users_id"], + "isUnique": false + }, + "payload_preferences_rels_users_id_idx": { + "name": "payload_preferences_rels_users_id_idx", + "columns": ["users_id"], + "isUnique": false + } + }, + "foreignKeys": { + "payload_preferences_rels_parent_fk": { + "name": "payload_preferences_rels_parent_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "payload_preferences", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_preferences_rels_local_users_fk": { + "name": "payload_preferences_rels_local_users_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "local_users", + "columnsFrom": ["local_users_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "payload_preferences_rels_users_fk": { + "name": "payload_preferences_rels_users_fk", + "tableFrom": "payload_preferences_rels", + "tableTo": "users", + "columnsFrom": ["users_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "payload_migrations": { + "name": "payload_migrations", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "batch": { + "name": "batch", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" + } + }, + "indexes": { + "payload_migrations_updated_at_idx": { + "name": "payload_migrations_updated_at_idx", + "columns": ["updated_at"], + "isUnique": false + }, + "payload_migrations_created_at_idx": { + "name": "payload_migrations_created_at_idx", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + }, + "id": "504b6ae6-0d42-48c8-8510-2756b0122bc1", + "prevId": "00000000-0000-0000-0000-000000000000" +} diff --git a/dev/src/migrations/20250224_052431.ts b/dev/src/migrations/20250224_052431.ts new file mode 100644 index 0000000..0ccd024 --- /dev/null +++ b/dev/src/migrations/20250224_052431.ts @@ -0,0 +1,180 @@ +import { MigrateDownArgs, MigrateUpArgs, sql } from "@payloadcms/db-sqlite"; + +export async function up({ db, payload, req }: MigrateUpArgs): Promise { + await db.run(sql`CREATE TABLE \`local_users\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`email\` text NOT NULL, + \`reset_password_token\` text, + \`reset_password_expiration\` text, + \`salt\` text, + \`hash\` text, + \`login_attempts\` numeric DEFAULT 0, + \`lock_until\` text + ); + `); + await db.run( + sql`CREATE INDEX \`local_users_updated_at_idx\` ON \`local_users\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`local_users_created_at_idx\` ON \`local_users\` (\`created_at\`);`, + ); + await db.run( + sql`CREATE UNIQUE INDEX \`local_users_email_idx\` ON \`local_users\` (\`email\`);`, + ); + await db.run(sql`PRAGMA foreign_keys=OFF;`); + await db.run(sql`CREATE TABLE \`__new_payload_locked_documents_rels\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order\` integer, + \`parent_id\` integer NOT NULL, + \`path\` text NOT NULL, + \`local_users_id\` integer, + \`users_id\` integer, + FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`local_users_id\`) REFERENCES \`local_users\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade + ); + `); + await db.run( + sql`INSERT INTO \`__new_payload_locked_documents_rels\`("id", "order", "parent_id", "path", "local_users_id", "users_id") SELECT "id", "order", "parent_id", "path", "local_users_id", "users_id" FROM \`payload_locked_documents_rels\`;`, + ); + await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`); + await db.run( + sql`ALTER TABLE \`__new_payload_locked_documents_rels\` RENAME TO \`payload_locked_documents_rels\`;`, + ); + await db.run(sql`PRAGMA foreign_keys=ON;`); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_local_users_id_idx\` ON \`payload_locked_documents_rels\` (\`local_users_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_users_id_idx\` ON \`payload_locked_documents_rels\` (\`users_id\`);`, + ); + await db.run(sql`CREATE TABLE \`__new_payload_preferences_rels\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`order\` integer, + \`parent_id\` integer NOT NULL, + \`path\` text NOT NULL, + \`local_users_id\` integer, + \`users_id\` integer, + FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_preferences\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`local_users_id\`) REFERENCES \`local_users\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade + ); + `); + await db.run( + sql`INSERT INTO \`__new_payload_preferences_rels\`("id", "order", "parent_id", "path", "local_users_id", "users_id") SELECT "id", "order", "parent_id", "path", "local_users_id", "users_id" FROM \`payload_preferences_rels\`;`, + ); + await db.run(sql`DROP TABLE \`payload_preferences_rels\`;`); + await db.run( + sql`ALTER TABLE \`__new_payload_preferences_rels\` RENAME TO \`payload_preferences_rels\`;`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_order_idx\` ON \`payload_preferences_rels\` (\`order\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_parent_idx\` ON \`payload_preferences_rels\` (\`parent_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_path_idx\` ON \`payload_preferences_rels\` (\`path\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_local_users_id_idx\` ON \`payload_preferences_rels\` (\`local_users_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_users_id_idx\` ON \`payload_preferences_rels\` (\`users_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`users_updated_at_idx\` ON \`users\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_updated_at_idx\` ON \`payload_locked_documents\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_updated_at_idx\` ON \`payload_preferences\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_migrations_updated_at_idx\` ON \`payload_migrations\` (\`updated_at\`);`, + ); +} + +export async function down({ + db, + payload, + req, +}: MigrateDownArgs): Promise { + await db.run(sql`DROP TABLE \`local_users\`;`); + await db.run(sql`PRAGMA foreign_keys=OFF;`); + await db.run(sql`CREATE TABLE \`__new_payload_locked_documents_rels\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`order\` integer, + \`parent_id\` integer NOT NULL, + \`path\` text NOT NULL, + \`users_id\` integer, + FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade + ); + `); + await db.run( + sql`INSERT INTO \`__new_payload_locked_documents_rels\`("id", "order", "parent_id", "path", "users_id") SELECT "id", "order", "parent_id", "path", "users_id" FROM \`payload_locked_documents_rels\`;`, + ); + await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`); + await db.run( + sql`ALTER TABLE \`__new_payload_locked_documents_rels\` RENAME TO \`payload_locked_documents_rels\`;`, + ); + await db.run(sql`PRAGMA foreign_keys=ON;`); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`, + ); + await db.run(sql`CREATE TABLE \`__new_payload_preferences_rels\` ( + \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, + \`order\` integer, + \`parent_id\` integer NOT NULL, + \`path\` text NOT NULL, + \`users_id\` integer, + FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_preferences\`(\`id\`) ON UPDATE no action ON DELETE cascade, + FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade + ); + `); + await db.run( + sql`INSERT INTO \`__new_payload_preferences_rels\`("id", "order", "parent_id", "path", "users_id") SELECT "id", "order", "parent_id", "path", "users_id" FROM \`payload_preferences_rels\`;`, + ); + await db.run(sql`DROP TABLE \`payload_preferences_rels\`;`); + await db.run( + sql`ALTER TABLE \`__new_payload_preferences_rels\` RENAME TO \`payload_preferences_rels\`;`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_order_idx\` ON \`payload_preferences_rels\` (\`order\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_parent_idx\` ON \`payload_preferences_rels\` (\`parent_id\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_rels_path_idx\` ON \`payload_preferences_rels\` (\`path\`);`, + ); + await db.run(sql`DROP INDEX IF EXISTS \`users_updated_at_idx\`;`); + await db.run( + sql`DROP INDEX IF EXISTS \`payload_locked_documents_updated_at_idx\`;`, + ); + await db.run( + sql`DROP INDEX IF EXISTS \`payload_preferences_updated_at_idx\`;`, + ); + await db.run( + sql`DROP INDEX IF EXISTS \`payload_migrations_updated_at_idx\`;`, + ); +} diff --git a/dev/src/migrations/index.ts b/dev/src/migrations/index.ts index a94db8a..5b4b976 100644 --- a/dev/src/migrations/index.ts +++ b/dev/src/migrations/index.ts @@ -1,4 +1,5 @@ import * as migration_20241017_034629 from "./20241017_034629"; +import * as migration_20250224_052431 from "./20250224_052431"; export const migrations = [ { @@ -6,4 +7,9 @@ export const migrations = [ down: migration_20241017_034629.down, name: "20241017_034629", }, + { + up: migration_20250224_052431.up, + down: migration_20250224_052431.down, + name: "20250224_052431", + }, ]; diff --git a/dev/src/payload-types.ts b/dev/src/payload-types.ts index fa1a9a7..5ece452 100644 --- a/dev/src/payload-types.ts +++ b/dev/src/payload-types.ts @@ -62,10 +62,12 @@ export type SupportedTimezones = export interface Config { auth: { + 'local-users': LocalUserAuthOperations; users: UserAuthOperations; }; blocks: {}; collections: { + 'local-users': LocalUser; users: User; 'payload-locked-documents': PayloadLockedDocument; 'payload-preferences': PayloadPreference; @@ -73,6 +75,7 @@ export interface Config { }; collectionsJoins: {}; collectionsSelect: { + 'local-users': LocalUsersSelect | LocalUsersSelect; users: UsersSelect | UsersSelect; 'payload-locked-documents': PayloadLockedDocumentsSelect | PayloadLockedDocumentsSelect; 'payload-preferences': PayloadPreferencesSelect | PayloadPreferencesSelect; @@ -84,14 +87,36 @@ export interface Config { globals: {}; globalsSelect: {}; locale: null; - user: User & { - collection: 'users'; - }; + user: + | (LocalUser & { + collection: 'local-users'; + }) + | (User & { + collection: 'users'; + }); jobs: { tasks: unknown; workflows: unknown; }; } +export interface LocalUserAuthOperations { + forgotPassword: { + email: string; + password: string; + }; + login: { + email: string; + password: string; + }; + registerFirstUser: { + email: string; + password: string; + }; + unlock: { + email: string; + password: string; + }; +} export interface UserAuthOperations { forgotPassword: { email: string; @@ -110,6 +135,23 @@ export interface UserAuthOperations { password: string; }; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "local-users". + */ +export interface LocalUser { + id: number; + updatedAt: string; + createdAt: string; + email: string; + resetPasswordToken?: string | null; + resetPasswordExpiration?: string | null; + salt?: string | null; + hash?: string | null; + loginAttempts?: number | null; + lockUntil?: string | null; + password?: string | null; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users". @@ -127,15 +169,25 @@ export interface User { */ export interface PayloadLockedDocument { id: number; - document?: { - relationTo: 'users'; - value: number | User; - } | null; + document?: + | ({ + relationTo: 'local-users'; + value: number | LocalUser; + } | null) + | ({ + relationTo: 'users'; + value: number | User; + } | null); globalSlug?: string | null; - user: { - relationTo: 'users'; - value: number | User; - }; + user: + | { + relationTo: 'local-users'; + value: number | LocalUser; + } + | { + relationTo: 'users'; + value: number | User; + }; updatedAt: string; createdAt: string; } @@ -145,10 +197,15 @@ export interface PayloadLockedDocument { */ export interface PayloadPreference { id: number; - user: { - relationTo: 'users'; - value: number | User; - }; + user: + | { + relationTo: 'local-users'; + value: number | LocalUser; + } + | { + relationTo: 'users'; + value: number | User; + }; key?: string | null; value?: | { @@ -173,6 +230,21 @@ export interface PayloadMigration { updatedAt: string; createdAt: string; } +/** + * This interface was referenced by `Config`'s JSON-Schema + * via the `definition` "local-users_select". + */ +export interface LocalUsersSelect { + updatedAt?: T; + createdAt?: T; + email?: T; + resetPasswordToken?: T; + resetPasswordExpiration?: T; + salt?: T; + hash?: T; + loginAttempts?: T; + lockUntil?: T; +} /** * This interface was referenced by `Config`'s JSON-Schema * via the `definition` "users_select". diff --git a/dev/src/payload.config.ts b/dev/src/payload.config.ts index 0613e10..3cbdea4 100644 --- a/dev/src/payload.config.ts +++ b/dev/src/payload.config.ts @@ -6,6 +6,7 @@ import sharp from "sharp"; import { fileURLToPath } from "url"; import { googleOAuth } from "../../examples/google"; import { zitadelOAuth } from "../../examples/zitadel"; +import LocalUsers from "./collections/LocalUsers"; import Users from "./collections/Users"; import { migrations } from "./migrations"; @@ -32,7 +33,7 @@ export default buildConfig({ prodMigrations: migrations, }), editor: lexicalEditor({}), - collections: [Users], + collections: [Users, LocalUsers], typescript: { outputFile: path.resolve(dirname, "payload-types.ts") }, plugins: [googleOAuth, zitadelOAuth], sharp, diff --git a/src/auth-strategy.ts b/src/auth-strategy.ts index db92829..6927f37 100644 --- a/src/auth-strategy.ts +++ b/src/auth-strategy.ts @@ -16,87 +16,92 @@ export const createAuthStrategy = ( const authStrategy: AuthStrategy = { name: pluginOptions.strategyName, authenticate: async ({ headers, payload }): Promise => { - const cookie = parseCookies(headers); - const token = cookie.get(`${payload.config.cookiePrefix}-token`); - if (!token) return { user: null }; - - let jwtUser: JWTPayload | null = null; try { - const secret = crypto - .createHash("sha256") - .update(payload.config.secret) - .digest("hex") - .slice(0, 32); - - const { payload: verifiedPayload } = await jwtVerify( - token, - new TextEncoder().encode(secret), - { algorithms: ["HS256"] }, - ); - jwtUser = verifiedPayload; - } catch (e: any) { - // Handle token expiration - if (e.code === "ERR_JWT_EXPIRED") return { user: null }; - throw e; - } - if (!jwtUser) return { user: null }; + const cookie = parseCookies(headers); + const token = cookie.get(`${payload.config.cookiePrefix}-token`); + if (!token) return { user: null }; - // Find the user by email from the verified jwt token - // coerce userCollection to CollectionSlug because it is already checked - // in `modify-auth-collection.ts` that it is a valud collection slug - const userCollection = ((typeof jwtUser.collection === "string" && - jwtUser.collection) || - pluginOptions.authCollection || - "users") as CollectionSlug; - let user: User | null = null; + let jwtUser: JWTPayload | null = null; + try { + const secret = crypto + .createHash("sha256") + .update(payload.config.secret) + .digest("hex") + .slice(0, 32); - if (pluginOptions.useEmailAsIdentity) { - if (typeof jwtUser.email !== "string") { - payload.logger.warn( - "Using email as identity but no email is found in jwt token", + const { payload: verifiedPayload } = await jwtVerify( + token, + new TextEncoder().encode(secret), + { algorithms: ["HS256"] }, ); - return { user: null }; + jwtUser = verifiedPayload; + } catch (e: any) { + // Handle token expiration + if (e.code === "ERR_JWT_EXPIRED") return { user: null }; + throw e; } - const usersQuery = await payload.find({ - collection: userCollection, - where: { email: { equals: jwtUser.email } }, - }); - if (usersQuery.docs.length === 0) { - // coerce to User because `userCollection` is a valid auth collection, checked by `modify-auth-collection.ts` already - user = (await payload.create({ + if (!jwtUser) return { user: null }; + + // Find the user by email from the verified jwt token + // coerce userCollection to CollectionSlug because it is already checked + // in `modify-auth-collection.ts` that it is a valud collection slug + const userCollection = ((typeof jwtUser.collection === "string" && + jwtUser.collection) || + pluginOptions.authCollection || + "users") as CollectionSlug; + let user: User | null = null; + + if (pluginOptions.useEmailAsIdentity) { + if (typeof jwtUser.email !== "string") { + payload.logger.warn( + "Using email as identity but no email is found in jwt token", + ); + return { user: null }; + } + const usersQuery = await payload.find({ collection: userCollection, - data: jwtUser as any, - })) as unknown as User; + where: { email: { equals: jwtUser.email } }, + }); + if (usersQuery.docs.length === 0) { + // coerce to User because `userCollection` is a valid auth collection, checked by `modify-auth-collection.ts` already + user = (await payload.create({ + collection: userCollection, + data: jwtUser as any, + })) as unknown as User; + } else { + // coerce to User because payload warns that some collection may not have property `collection` - i.e. `PayloadMigration; + user = usersQuery.docs[0] as unknown as User; + } } else { - // coerce to User because payload warns that some collection may not have property `collection` - i.e. `PayloadMigration; - user = usersQuery.docs[0] as unknown as User; - } - } else { - if (typeof jwtUser[subFieldName] !== "string") { - payload.logger.warn( - `No ${subFieldName} found in jwt token. Make sure the jwt token contains the ${subFieldName} field`, - ); - return { user: null }; - } - const usersQuery = await payload.find({ - collection: userCollection, - where: { [subFieldName]: { equals: jwtUser[subFieldName] } }, - }); - if (usersQuery.docs.length === 0) { - // coerce to User because payload warns that some collection may not have property `collection` - i.e. `PayloadMigration; - user = (await payload.create({ + if (typeof jwtUser[subFieldName] !== "string") { + payload.logger.warn( + `No ${subFieldName} found in jwt token. Make sure the jwt token contains the ${subFieldName} field`, + ); + return { user: null }; + } + const usersQuery = await payload.find({ collection: userCollection, - data: jwtUser as any, - })) as unknown as User; - } else { - // coerce to User because payload warns that some collection may not have property `collection` - i.e. `PayloadMigration; - user = usersQuery.docs[0] as unknown as User; + where: { [subFieldName]: { equals: jwtUser[subFieldName] } }, + }); + if (usersQuery.docs.length === 0) { + // coerce to User because payload warns that some collection may not have property `collection` - i.e. `PayloadMigration; + user = (await payload.create({ + collection: userCollection, + data: jwtUser as any, + })) as unknown as User; + } else { + // coerce to User because payload warns that some collection may not have property `collection` - i.e. `PayloadMigration; + user = usersQuery.docs[0] as unknown as User; + } } - } - user.collection = userCollection; + user.collection = userCollection; - // Return the user object - return { user }; + // Return the user object + return { user }; + } catch (e) { + payload.logger.error(e); + return { user: null }; + } }, }; return authStrategy; From 2148358d8d71cb3ee769c2f879d1ef4cef1e14e5 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Mon, 24 Feb 2025 01:26:00 -0500 Subject: [PATCH 2/2] fix migration test, there should always be 1 migration since test starts with an empty database --- dev/src/migrations/20241017_034629.json | 390 ------------------ dev/src/migrations/20241017_034629.ts | 106 ----- ...50224_052431.json => 20250224_061957.json} | 2 +- ...{20250224_052431.ts => 20250224_061957.ts} | 150 +++---- dev/src/migrations/index.ts | 14 +- package.json | 2 +- 6 files changed, 69 insertions(+), 595 deletions(-) delete mode 100644 dev/src/migrations/20241017_034629.json delete mode 100644 dev/src/migrations/20241017_034629.ts rename dev/src/migrations/{20250224_052431.json => 20250224_061957.json} (99%) rename dev/src/migrations/{20250224_052431.ts => 20250224_061957.ts} (52%) diff --git a/dev/src/migrations/20241017_034629.json b/dev/src/migrations/20241017_034629.json deleted file mode 100644 index 292a237..0000000 --- a/dev/src/migrations/20241017_034629.json +++ /dev/null @@ -1,390 +0,0 @@ -{ - "version": "6", - "dialect": "sqlite", - "tables": { - "users": { - "name": "users", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "email": { - "name": "email", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "sub": { - "name": "sub", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - } - }, - "indexes": { - "users_sub_idx": { - "name": "users_sub_idx", - "columns": ["sub"], - "isUnique": false - }, - "users_created_at_idx": { - "name": "users_created_at_idx", - "columns": ["created_at"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "payload_locked_documents": { - "name": "payload_locked_documents", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "global_slug": { - "name": "global_slug", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - } - }, - "indexes": { - "payload_locked_documents_global_slug_idx": { - "name": "payload_locked_documents_global_slug_idx", - "columns": ["global_slug"], - "isUnique": false - }, - "payload_locked_documents_created_at_idx": { - "name": "payload_locked_documents_created_at_idx", - "columns": ["created_at"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "payload_locked_documents_rels": { - "name": "payload_locked_documents_rels", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "users_id": { - "name": "users_id", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "payload_locked_documents_rels_order_idx": { - "name": "payload_locked_documents_rels_order_idx", - "columns": ["order"], - "isUnique": false - }, - "payload_locked_documents_rels_parent_idx": { - "name": "payload_locked_documents_rels_parent_idx", - "columns": ["parent_id"], - "isUnique": false - }, - "payload_locked_documents_rels_path_idx": { - "name": "payload_locked_documents_rels_path_idx", - "columns": ["path"], - "isUnique": false - } - }, - "foreignKeys": { - "payload_locked_documents_rels_parent_fk": { - "name": "payload_locked_documents_rels_parent_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "payload_locked_documents", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_locked_documents_rels_users_fk": { - "name": "payload_locked_documents_rels_users_fk", - "tableFrom": "payload_locked_documents_rels", - "tableTo": "users", - "columnsFrom": ["users_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "payload_preferences": { - "name": "payload_preferences", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "key": { - "name": "key", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "value": { - "name": "value", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - } - }, - "indexes": { - "payload_preferences_key_idx": { - "name": "payload_preferences_key_idx", - "columns": ["key"], - "isUnique": false - }, - "payload_preferences_created_at_idx": { - "name": "payload_preferences_created_at_idx", - "columns": ["created_at"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "payload_preferences_rels": { - "name": "payload_preferences_rels", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": true - }, - "order": { - "name": "order", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "parent_id": { - "name": "parent_id", - "type": "integer", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "path": { - "name": "path", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false - }, - "users_id": { - "name": "users_id", - "type": "integer", - "primaryKey": false, - "notNull": false, - "autoincrement": false - } - }, - "indexes": { - "payload_preferences_rels_order_idx": { - "name": "payload_preferences_rels_order_idx", - "columns": ["order"], - "isUnique": false - }, - "payload_preferences_rels_parent_idx": { - "name": "payload_preferences_rels_parent_idx", - "columns": ["parent_id"], - "isUnique": false - }, - "payload_preferences_rels_path_idx": { - "name": "payload_preferences_rels_path_idx", - "columns": ["path"], - "isUnique": false - } - }, - "foreignKeys": { - "payload_preferences_rels_parent_fk": { - "name": "payload_preferences_rels_parent_fk", - "tableFrom": "payload_preferences_rels", - "tableTo": "payload_preferences", - "columnsFrom": ["parent_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - }, - "payload_preferences_rels_users_fk": { - "name": "payload_preferences_rels_users_fk", - "tableFrom": "payload_preferences_rels", - "tableTo": "users", - "columnsFrom": ["users_id"], - "columnsTo": ["id"], - "onDelete": "cascade", - "onUpdate": "no action" - } - }, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - }, - "payload_migrations": { - "name": "payload_migrations", - "columns": { - "id": { - "name": "id", - "type": "integer", - "primaryKey": true, - "notNull": true, - "autoincrement": false - }, - "name": { - "name": "name", - "type": "text", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "batch": { - "name": "batch", - "type": "numeric", - "primaryKey": false, - "notNull": false, - "autoincrement": false - }, - "updated_at": { - "name": "updated_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - }, - "created_at": { - "name": "created_at", - "type": "text", - "primaryKey": false, - "notNull": true, - "autoincrement": false, - "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))" - } - }, - "indexes": { - "payload_migrations_created_at_idx": { - "name": "payload_migrations_created_at_idx", - "columns": ["created_at"], - "isUnique": false - } - }, - "foreignKeys": {}, - "compositePrimaryKeys": {}, - "uniqueConstraints": {} - } - }, - "enums": {}, - "_meta": { - "tables": {}, - "columns": {} - }, - "internal": { - "indexes": {} - }, - "id": "cedd7049-0d47-4c51-8734-2c3d70ac3c4d", - "prevId": "00000000-0000-0000-0000-000000000000" -} diff --git a/dev/src/migrations/20241017_034629.ts b/dev/src/migrations/20241017_034629.ts deleted file mode 100644 index a1c5cb9..0000000 --- a/dev/src/migrations/20241017_034629.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { MigrateDownArgs, MigrateUpArgs, sql } from "@payloadcms/db-sqlite"; - -export async function up({ payload, req }: MigrateUpArgs): Promise { - await payload.db.drizzle.run(sql`CREATE TABLE \`users\` ( - \`id\` integer PRIMARY KEY NOT NULL, - \`email\` text NOT NULL, - \`sub\` text, - \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, - \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL - ); - `); - await payload.db.drizzle.run(sql`CREATE TABLE \`payload_locked_documents\` ( - \`id\` integer PRIMARY KEY NOT NULL, - \`global_slug\` text, - \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, - \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL - ); - `); - await payload.db.drizzle - .run(sql`CREATE TABLE \`payload_locked_documents_rels\` ( - \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - \`order\` integer, - \`parent_id\` integer NOT NULL, - \`path\` text NOT NULL, - \`users_id\` integer, - FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade - ); - `); - await payload.db.drizzle.run(sql`CREATE TABLE \`payload_preferences\` ( - \`id\` integer PRIMARY KEY NOT NULL, - \`key\` text, - \`value\` text, - \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, - \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL - ); - `); - await payload.db.drizzle.run(sql`CREATE TABLE \`payload_preferences_rels\` ( - \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - \`order\` integer, - \`parent_id\` integer NOT NULL, - \`path\` text NOT NULL, - \`users_id\` integer, - FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_preferences\`(\`id\`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade - ); - `); - await payload.db.drizzle.run(sql`CREATE TABLE \`payload_migrations\` ( - \`id\` integer PRIMARY KEY NOT NULL, - \`name\` text, - \`batch\` numeric, - \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, - \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL - ); - `); - await payload.db.drizzle.run( - sql`CREATE INDEX \`users_sub_idx\` ON \`users\` (\`sub\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`users_created_at_idx\` ON \`users\` (\`created_at\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_locked_documents_global_slug_idx\` ON \`payload_locked_documents\` (\`global_slug\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_locked_documents_created_at_idx\` ON \`payload_locked_documents\` (\`created_at\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_preferences_key_idx\` ON \`payload_preferences\` (\`key\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_preferences_created_at_idx\` ON \`payload_preferences\` (\`created_at\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_preferences_rels_order_idx\` ON \`payload_preferences_rels\` (\`order\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_preferences_rels_parent_idx\` ON \`payload_preferences_rels\` (\`parent_id\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_preferences_rels_path_idx\` ON \`payload_preferences_rels\` (\`path\`);`, - ); - await payload.db.drizzle.run( - sql`CREATE INDEX \`payload_migrations_created_at_idx\` ON \`payload_migrations\` (\`created_at\`);`, - ); -} - -export async function down({ payload, req }: MigrateDownArgs): Promise { - await payload.db.drizzle.run(sql`DROP TABLE \`users\`;`); - await payload.db.drizzle.run(sql`DROP TABLE \`payload_locked_documents\`;`); - await payload.db.drizzle.run( - sql`DROP TABLE \`payload_locked_documents_rels\`;`, - ); - await payload.db.drizzle.run(sql`DROP TABLE \`payload_preferences\`;`); - await payload.db.drizzle.run(sql`DROP TABLE \`payload_preferences_rels\`;`); - await payload.db.drizzle.run(sql`DROP TABLE \`payload_migrations\`;`); -} diff --git a/dev/src/migrations/20250224_052431.json b/dev/src/migrations/20250224_061957.json similarity index 99% rename from dev/src/migrations/20250224_052431.json rename to dev/src/migrations/20250224_061957.json index 4645c73..e2f6966 100644 --- a/dev/src/migrations/20250224_052431.json +++ b/dev/src/migrations/20250224_061957.json @@ -563,6 +563,6 @@ "internal": { "indexes": {} }, - "id": "504b6ae6-0d42-48c8-8510-2756b0122bc1", + "id": "0653c2d0-b1b7-43ca-85ed-c2d2ca48aef3", "prevId": "00000000-0000-0000-0000-000000000000" } diff --git a/dev/src/migrations/20250224_052431.ts b/dev/src/migrations/20250224_061957.ts similarity index 52% rename from dev/src/migrations/20250224_052431.ts rename to dev/src/migrations/20250224_061957.ts index 0ccd024..fcf4dc4 100644 --- a/dev/src/migrations/20250224_052431.ts +++ b/dev/src/migrations/20250224_061957.ts @@ -23,8 +23,38 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { await db.run( sql`CREATE UNIQUE INDEX \`local_users_email_idx\` ON \`local_users\` (\`email\`);`, ); - await db.run(sql`PRAGMA foreign_keys=OFF;`); - await db.run(sql`CREATE TABLE \`__new_payload_locked_documents_rels\` ( + await db.run(sql`CREATE TABLE \`users\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`email\` text NOT NULL, + \`sub\` text, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL + ); + `); + await db.run(sql`CREATE INDEX \`users_sub_idx\` ON \`users\` (\`sub\`);`); + await db.run( + sql`CREATE INDEX \`users_updated_at_idx\` ON \`users\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`users_created_at_idx\` ON \`users\` (\`created_at\`);`, + ); + await db.run(sql`CREATE TABLE \`payload_locked_documents\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`global_slug\` text, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL + ); + `); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_global_slug_idx\` ON \`payload_locked_documents\` (\`global_slug\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_updated_at_idx\` ON \`payload_locked_documents\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_locked_documents_created_at_idx\` ON \`payload_locked_documents\` (\`created_at\`);`, + ); + await db.run(sql`CREATE TABLE \`payload_locked_documents_rels\` ( \`id\` integer PRIMARY KEY NOT NULL, \`order\` integer, \`parent_id\` integer NOT NULL, @@ -36,14 +66,6 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade ); `); - await db.run( - sql`INSERT INTO \`__new_payload_locked_documents_rels\`("id", "order", "parent_id", "path", "local_users_id", "users_id") SELECT "id", "order", "parent_id", "path", "local_users_id", "users_id" FROM \`payload_locked_documents_rels\`;`, - ); - await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`); - await db.run( - sql`ALTER TABLE \`__new_payload_locked_documents_rels\` RENAME TO \`payload_locked_documents_rels\`;`, - ); - await db.run(sql`PRAGMA foreign_keys=ON;`); await db.run( sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`, ); @@ -59,7 +81,24 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { await db.run( sql`CREATE INDEX \`payload_locked_documents_rels_users_id_idx\` ON \`payload_locked_documents_rels\` (\`users_id\`);`, ); - await db.run(sql`CREATE TABLE \`__new_payload_preferences_rels\` ( + await db.run(sql`CREATE TABLE \`payload_preferences\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`key\` text, + \`value\` text, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL + ); + `); + await db.run( + sql`CREATE INDEX \`payload_preferences_key_idx\` ON \`payload_preferences\` (\`key\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_updated_at_idx\` ON \`payload_preferences\` (\`updated_at\`);`, + ); + await db.run( + sql`CREATE INDEX \`payload_preferences_created_at_idx\` ON \`payload_preferences\` (\`created_at\`);`, + ); + await db.run(sql`CREATE TABLE \`payload_preferences_rels\` ( \`id\` integer PRIMARY KEY NOT NULL, \`order\` integer, \`parent_id\` integer NOT NULL, @@ -71,13 +110,6 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade ); `); - await db.run( - sql`INSERT INTO \`__new_payload_preferences_rels\`("id", "order", "parent_id", "path", "local_users_id", "users_id") SELECT "id", "order", "parent_id", "path", "local_users_id", "users_id" FROM \`payload_preferences_rels\`;`, - ); - await db.run(sql`DROP TABLE \`payload_preferences_rels\`;`); - await db.run( - sql`ALTER TABLE \`__new_payload_preferences_rels\` RENAME TO \`payload_preferences_rels\`;`, - ); await db.run( sql`CREATE INDEX \`payload_preferences_rels_order_idx\` ON \`payload_preferences_rels\` (\`order\`);`, ); @@ -93,17 +125,19 @@ export async function up({ db, payload, req }: MigrateUpArgs): Promise { await db.run( sql`CREATE INDEX \`payload_preferences_rels_users_id_idx\` ON \`payload_preferences_rels\` (\`users_id\`);`, ); - await db.run( - sql`CREATE INDEX \`users_updated_at_idx\` ON \`users\` (\`updated_at\`);`, - ); - await db.run( - sql`CREATE INDEX \`payload_locked_documents_updated_at_idx\` ON \`payload_locked_documents\` (\`updated_at\`);`, + await db.run(sql`CREATE TABLE \`payload_migrations\` ( + \`id\` integer PRIMARY KEY NOT NULL, + \`name\` text, + \`batch\` numeric, + \`updated_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL, + \`created_at\` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL ); + `); await db.run( - sql`CREATE INDEX \`payload_preferences_updated_at_idx\` ON \`payload_preferences\` (\`updated_at\`);`, + sql`CREATE INDEX \`payload_migrations_updated_at_idx\` ON \`payload_migrations\` (\`updated_at\`);`, ); await db.run( - sql`CREATE INDEX \`payload_migrations_updated_at_idx\` ON \`payload_migrations\` (\`updated_at\`);`, + sql`CREATE INDEX \`payload_migrations_created_at_idx\` ON \`payload_migrations\` (\`created_at\`);`, ); } @@ -113,68 +147,10 @@ export async function down({ req, }: MigrateDownArgs): Promise { await db.run(sql`DROP TABLE \`local_users\`;`); - await db.run(sql`PRAGMA foreign_keys=OFF;`); - await db.run(sql`CREATE TABLE \`__new_payload_locked_documents_rels\` ( - \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - \`order\` integer, - \`parent_id\` integer NOT NULL, - \`path\` text NOT NULL, - \`users_id\` integer, - FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_locked_documents\`(\`id\`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade - ); - `); - await db.run( - sql`INSERT INTO \`__new_payload_locked_documents_rels\`("id", "order", "parent_id", "path", "users_id") SELECT "id", "order", "parent_id", "path", "users_id" FROM \`payload_locked_documents_rels\`;`, - ); + await db.run(sql`DROP TABLE \`users\`;`); + await db.run(sql`DROP TABLE \`payload_locked_documents\`;`); await db.run(sql`DROP TABLE \`payload_locked_documents_rels\`;`); - await db.run( - sql`ALTER TABLE \`__new_payload_locked_documents_rels\` RENAME TO \`payload_locked_documents_rels\`;`, - ); - await db.run(sql`PRAGMA foreign_keys=ON;`); - await db.run( - sql`CREATE INDEX \`payload_locked_documents_rels_order_idx\` ON \`payload_locked_documents_rels\` (\`order\`);`, - ); - await db.run( - sql`CREATE INDEX \`payload_locked_documents_rels_parent_idx\` ON \`payload_locked_documents_rels\` (\`parent_id\`);`, - ); - await db.run( - sql`CREATE INDEX \`payload_locked_documents_rels_path_idx\` ON \`payload_locked_documents_rels\` (\`path\`);`, - ); - await db.run(sql`CREATE TABLE \`__new_payload_preferences_rels\` ( - \`id\` integer PRIMARY KEY AUTOINCREMENT NOT NULL, - \`order\` integer, - \`parent_id\` integer NOT NULL, - \`path\` text NOT NULL, - \`users_id\` integer, - FOREIGN KEY (\`parent_id\`) REFERENCES \`payload_preferences\`(\`id\`) ON UPDATE no action ON DELETE cascade, - FOREIGN KEY (\`users_id\`) REFERENCES \`users\`(\`id\`) ON UPDATE no action ON DELETE cascade - ); - `); - await db.run( - sql`INSERT INTO \`__new_payload_preferences_rels\`("id", "order", "parent_id", "path", "users_id") SELECT "id", "order", "parent_id", "path", "users_id" FROM \`payload_preferences_rels\`;`, - ); + await db.run(sql`DROP TABLE \`payload_preferences\`;`); await db.run(sql`DROP TABLE \`payload_preferences_rels\`;`); - await db.run( - sql`ALTER TABLE \`__new_payload_preferences_rels\` RENAME TO \`payload_preferences_rels\`;`, - ); - await db.run( - sql`CREATE INDEX \`payload_preferences_rels_order_idx\` ON \`payload_preferences_rels\` (\`order\`);`, - ); - await db.run( - sql`CREATE INDEX \`payload_preferences_rels_parent_idx\` ON \`payload_preferences_rels\` (\`parent_id\`);`, - ); - await db.run( - sql`CREATE INDEX \`payload_preferences_rels_path_idx\` ON \`payload_preferences_rels\` (\`path\`);`, - ); - await db.run(sql`DROP INDEX IF EXISTS \`users_updated_at_idx\`;`); - await db.run( - sql`DROP INDEX IF EXISTS \`payload_locked_documents_updated_at_idx\`;`, - ); - await db.run( - sql`DROP INDEX IF EXISTS \`payload_preferences_updated_at_idx\`;`, - ); - await db.run( - sql`DROP INDEX IF EXISTS \`payload_migrations_updated_at_idx\`;`, - ); + await db.run(sql`DROP TABLE \`payload_migrations\`;`); } diff --git a/dev/src/migrations/index.ts b/dev/src/migrations/index.ts index 5b4b976..ca8a1ac 100644 --- a/dev/src/migrations/index.ts +++ b/dev/src/migrations/index.ts @@ -1,15 +1,9 @@ -import * as migration_20241017_034629 from "./20241017_034629"; -import * as migration_20250224_052431 from "./20250224_052431"; +import * as migration_20250224_061957 from './20250224_061957'; export const migrations = [ { - up: migration_20241017_034629.up, - down: migration_20241017_034629.down, - name: "20241017_034629", - }, - { - up: migration_20250224_052431.up, - down: migration_20250224_052431.down, - name: "20250224_052431", + up: migration_20250224_061957.up, + down: migration_20250224_061957.down, + name: '20250224_061957' }, ]; diff --git a/package.json b/package.json index 873535e..619b2d5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "payload-oauth2", - "version": "1.0.12", + "version": "1.0.13", "type": "module", "homepage:": "https://github.com/WilsonLe/payload-oauth2", "repository": "https://github.com/WilsonLe/payload-oauth2",