Introduce granular role-based permissions with SuperAdmin env override, admin roles UI, and permission-gated API routes. Fix admin user Nostr metadata by batching relay profile fetches, normalizing npub pubkeys to hex, and adding reusable NostrAvatar/useNostrProfile components. Co-authored-by: Cursor <cursoragent@cursor.com>
84 lines
2.8 KiB
SQL
84 lines
2.8 KiB
SQL
-- Roles and permissions system.
|
|
-- Makes User.role nullable (null means Guest), backfills legacy uppercase roles
|
|
-- to the new lowercase enum, adds the RolePermission table, and seeds default
|
|
-- permission sets. Safe and idempotent to run on a live database.
|
|
|
|
-- RedefineTables: make User.role nullable and drop its default, converting values.
|
|
PRAGMA defer_foreign_keys=ON;
|
|
PRAGMA foreign_keys=OFF;
|
|
CREATE TABLE "new_User" (
|
|
"id" TEXT NOT NULL PRIMARY KEY,
|
|
"pubkey" TEXT NOT NULL,
|
|
"role" TEXT,
|
|
"displayName" TEXT,
|
|
"username" TEXT,
|
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
"updatedAt" DATETIME NOT NULL
|
|
);
|
|
INSERT INTO "new_User" ("id", "pubkey", "role", "displayName", "username", "createdAt", "updatedAt")
|
|
SELECT
|
|
"id",
|
|
"pubkey",
|
|
CASE
|
|
WHEN "role" = 'ADMIN' THEN 'admin'
|
|
WHEN "role" = 'MODERATOR' THEN 'moderator'
|
|
WHEN "role" = 'WRITER' THEN 'writer'
|
|
WHEN "role" IN ('admin', 'moderator', 'writer') THEN "role"
|
|
ELSE NULL
|
|
END,
|
|
"displayName",
|
|
"username",
|
|
"createdAt",
|
|
"updatedAt"
|
|
FROM "User";
|
|
DROP TABLE "User";
|
|
ALTER TABLE "new_User" RENAME TO "User";
|
|
CREATE UNIQUE INDEX "User_pubkey_key" ON "User"("pubkey");
|
|
CREATE UNIQUE INDEX "User_username_key" ON "User"("username");
|
|
PRAGMA foreign_keys=ON;
|
|
PRAGMA defer_foreign_keys=OFF;
|
|
|
|
-- CreateTable
|
|
CREATE TABLE IF NOT EXISTS "RolePermission" (
|
|
"role" TEXT NOT NULL,
|
|
"permission" TEXT NOT NULL,
|
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
PRIMARY KEY ("role", "permission")
|
|
);
|
|
|
|
-- Seed default permission sets. INSERT OR IGNORE keeps this idempotent and never
|
|
-- clobbers permissions an operator has already customized at runtime.
|
|
INSERT OR IGNORE INTO "RolePermission" ("role", "permission") VALUES
|
|
('admin', 'events.create'),
|
|
('admin', 'events.edit'),
|
|
('admin', 'events.delete'),
|
|
('admin', 'organizers.manage'),
|
|
('admin', 'gallery.upload'),
|
|
('admin', 'gallery.delete'),
|
|
('admin', 'blog.draft'),
|
|
('admin', 'blog.publish'),
|
|
('admin', 'blog.delete'),
|
|
('admin', 'faq.manage'),
|
|
('admin', 'submissions.review'),
|
|
('admin', 'board.manage'),
|
|
('admin', 'moderation.act'),
|
|
('admin', 'categories.manage'),
|
|
('admin', 'users.assign_role'),
|
|
('admin', 'nip05.assign'),
|
|
('admin', 'relays.manage'),
|
|
('admin', 'settings.edit'),
|
|
('admin', 'nostr_tools.use'),
|
|
('moderator', 'events.create'),
|
|
('moderator', 'events.edit'),
|
|
('moderator', 'events.delete'),
|
|
('moderator', 'submissions.review'),
|
|
('moderator', 'moderation.act'),
|
|
('moderator', 'gallery.upload'),
|
|
('moderator', 'board.manage'),
|
|
('moderator', 'categories.manage'),
|
|
('moderator', 'faq.manage'),
|
|
('writer', 'blog.draft'),
|
|
('writer', 'gallery.upload'),
|
|
('writer', 'events.create');
|