v3: added a roles/permissions system, added user management tab on user profile
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 42s
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 42s
This commit is contained in:
@@ -2,6 +2,8 @@ import type { DatabaseSync } from "node:sqlite";
|
||||
import { up as up0001CommentLikes } from "./migrations/0001_comment_likes.ts";
|
||||
import { up as up0002DumpThumbnail } from "./migrations/0002_dump_thumbnail.ts";
|
||||
import { up as up0003DumpBacklinks } from "./migrations/0003_dump_backlinks.ts";
|
||||
import { up as up0004UserRoles } from "./migrations/0004_user_roles.ts";
|
||||
import { up as up0005DropIsAdmin } from "./migrations/0005_drop_is_admin.ts";
|
||||
|
||||
interface Migration {
|
||||
name: string;
|
||||
@@ -15,6 +17,8 @@ const MIGRATIONS: Migration[] = [
|
||||
{ name: "0001_comment_likes", up: up0001CommentLikes },
|
||||
{ name: "0002_dump_thumbnail", up: up0002DumpThumbnail },
|
||||
{ name: "0003_dump_backlinks", up: up0003DumpBacklinks },
|
||||
{ name: "0004_user_roles", up: up0004UserRoles },
|
||||
{ name: "0005_drop_is_admin", up: up0005DropIsAdmin },
|
||||
];
|
||||
|
||||
export function runMigrations(db: DatabaseSync): void {
|
||||
|
||||
22
api/db/migrations/0004_user_roles.ts
Normal file
22
api/db/migrations/0004_user_roles.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
|
||||
// Idempotent: safe to run against a fresh db (already created from schema.sql
|
||||
// with the `role` column) or an existing one that predates it.
|
||||
export function up(db: DatabaseSync): void {
|
||||
const userCols = db.prepare(`PRAGMA table_info(users);`).all() as {
|
||||
name: string;
|
||||
}[];
|
||||
if (!userCols.some((c) => c.name === "role")) {
|
||||
db.exec(
|
||||
`ALTER TABLE users ADD COLUMN role TEXT NOT NULL DEFAULT 'user';`,
|
||||
);
|
||||
}
|
||||
|
||||
// Backfill existing admins to role 'admin'. Guarded because the legacy
|
||||
// is_admin column is absent on fresh databases (and dropped by 0005).
|
||||
if (userCols.some((c) => c.name === "is_admin")) {
|
||||
db.exec(
|
||||
`UPDATE users SET role = 'admin' WHERE is_admin = 1 AND role != 'admin';`,
|
||||
);
|
||||
}
|
||||
}
|
||||
13
api/db/migrations/0005_drop_is_admin.ts
Normal file
13
api/db/migrations/0005_drop_is_admin.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { DatabaseSync } from "node:sqlite";
|
||||
|
||||
// Drops the legacy is_admin column now that `role` is the single source of
|
||||
// truth. Idempotent: skips when the column is already gone (fresh databases
|
||||
// created from schema.sql never had it). Must run after 0004 has backfilled.
|
||||
export function up(db: DatabaseSync): void {
|
||||
const userCols = db.prepare(`PRAGMA table_info(users);`).all() as {
|
||||
name: string;
|
||||
}[];
|
||||
if (userCols.some((c) => c.name === "is_admin")) {
|
||||
db.exec(`ALTER TABLE users DROP COLUMN is_admin;`);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ CREATE TABLE users (
|
||||
id TEXT PRIMARY KEY,
|
||||
username TEXT NOT NULL UNIQUE,
|
||||
password_hash TEXT NOT NULL,
|
||||
is_admin INTEGER NOT NULL DEFAULT 0,
|
||||
role TEXT NOT NULL DEFAULT 'user',
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT,
|
||||
avatar_mime TEXT,
|
||||
|
||||
Reference in New Issue
Block a user