refactor(db): drop operators.telegram_user_id (not used since v1.0)
The Telegram bot phase ended in Plan 3 — the operator now signs in via username + password. Migration 0011 drops the legacy column + its unique index. seed.ts no longer reads SEED_OPERATOR_TELEGRAM_ID; docker-compose.base.yml swaps the env to SEED_OPERATOR_USERNAME (default 'admin'); .env.development follows. Settings page shows 'Username' instead of 'Operator ID'. Auth-and-prod-hardening plan doc updated to drop the synthetic telegram_user_id from the create-user CLI script and createUserAction insert. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a37b36196d
commit
46c0315559
@ -4,7 +4,7 @@ SESSIONS_DIR=/data/sessions
|
|||||||
MEDIA_DIR=/data/media
|
MEDIA_DIR=/data/media
|
||||||
BOT_HEALTH_PORT=8081
|
BOT_HEALTH_PORT=8081
|
||||||
BOT_LOG_LEVEL=debug
|
BOT_LOG_LEVEL=debug
|
||||||
SEED_OPERATOR_TELEGRAM_ID=818380985
|
SEED_OPERATOR_USERNAME=admin
|
||||||
SEED_OPERATOR_NAME="yiekheng (dev)"
|
SEED_OPERATOR_NAME="yiekheng (dev)"
|
||||||
WEB_PORT=9000
|
WEB_PORT=9000
|
||||||
AUTH_SECRET=86f656580a58f03b6ccb43d257e0e801ecd5356e042e8886b3c7c569e29ff13c
|
AUTH_SECRET=86f656580a58f03b6ccb43d257e0e801ecd5356e042e8886b3c7c569e29ff13c
|
||||||
|
|||||||
@ -16,7 +16,7 @@ export default async function SettingsPage() {
|
|||||||
<CardContent className="space-y-3 text-sm">
|
<CardContent className="space-y-3 text-sm">
|
||||||
<Row label="Display name" value={op.displayName} />
|
<Row label="Display name" value={op.displayName} />
|
||||||
<Separator />
|
<Separator />
|
||||||
<Row label="Operator ID" value={String(op.telegramUserId)} mono />
|
<Row label="Username" value={op.username} mono />
|
||||||
<Separator />
|
<Separator />
|
||||||
<Row label="Default timezone" value={op.defaultTimezone} mono />
|
<Row label="Default timezone" value={op.defaultTimezone} mono />
|
||||||
<Separator />
|
<Separator />
|
||||||
|
|||||||
@ -19,7 +19,7 @@ services:
|
|||||||
MEDIA_DIR: ${MEDIA_DIR:-/data/media}
|
MEDIA_DIR: ${MEDIA_DIR:-/data/media}
|
||||||
BOT_HEALTH_PORT: ${BOT_HEALTH_PORT:-8081}
|
BOT_HEALTH_PORT: ${BOT_HEALTH_PORT:-8081}
|
||||||
BOT_LOG_LEVEL: ${BOT_LOG_LEVEL:-info}
|
BOT_LOG_LEVEL: ${BOT_LOG_LEVEL:-info}
|
||||||
SEED_OPERATOR_TELEGRAM_ID: ${SEED_OPERATOR_TELEGRAM_ID:-0}
|
SEED_OPERATOR_USERNAME: ${SEED_OPERATOR_USERNAME:-admin}
|
||||||
SEED_OPERATOR_NAME: ${SEED_OPERATOR_NAME:-Operator}
|
SEED_OPERATOR_NAME: ${SEED_OPERATOR_NAME:-Operator}
|
||||||
networks:
|
networks:
|
||||||
- cmbot
|
- cmbot
|
||||||
|
|||||||
@ -65,7 +65,6 @@ export const operators = pgTable(
|
|||||||
"operators",
|
"operators",
|
||||||
{
|
{
|
||||||
id: uuid("id").primaryKey().defaultRandom(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
telegramUserId: bigint("telegram_user_id", { mode: "number" }).notNull(),
|
|
||||||
username: text("username").notNull(),
|
username: text("username").notNull(),
|
||||||
passwordHash: text("password_hash"),
|
passwordHash: text("password_hash"),
|
||||||
displayName: text("display_name").notNull(),
|
displayName: text("display_name").notNull(),
|
||||||
@ -74,7 +73,6 @@ export const operators = pgTable(
|
|||||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||||
},
|
},
|
||||||
(t) => ({
|
(t) => ({
|
||||||
telegramUserIdUnique: uniqueIndex("operators_telegram_user_id_uq").on(t.telegramUserId),
|
|
||||||
usernameUnique: uniqueIndex("operators_username_uq").on(sql`lower(${t.username})`),
|
usernameUnique: uniqueIndex("operators_username_uq").on(sql`lower(${t.username})`),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -1693,7 +1691,6 @@ export async function createUserAction(input: {
|
|||||||
displayName: u,
|
displayName: u,
|
||||||
role: input.role,
|
role: input.role,
|
||||||
defaultTimezone: "Asia/Kuala_Lumpur",
|
defaultTimezone: "Asia/Kuala_Lumpur",
|
||||||
telegramUserId: Date.now(),
|
|
||||||
})
|
})
|
||||||
.returning({ id: operators.id });
|
.returning({ id: operators.id });
|
||||||
revalidatePath("/settings/users");
|
revalidatePath("/settings/users");
|
||||||
@ -2186,8 +2183,8 @@ async function main() {
|
|||||||
const hash = await bcrypt.hash(password, 12);
|
const hash = await bcrypt.hash(password, 12);
|
||||||
const { db, pool } = createClient(url);
|
const { db, pool } = createClient(url);
|
||||||
await db.execute(
|
await db.execute(
|
||||||
sql`INSERT INTO operators (username, password_hash, display_name, role, telegram_user_id, default_timezone)
|
sql`INSERT INTO operators (username, password_hash, display_name, role, default_timezone)
|
||||||
VALUES (${username}, ${hash}, ${username}, ${role}, ${Date.now()}, 'Asia/Kuala_Lumpur')`,
|
VALUES (${username}, ${hash}, ${username}, ${role}, 'Asia/Kuala_Lumpur')`,
|
||||||
);
|
);
|
||||||
await pool.end();
|
await pool.end();
|
||||||
console.log(`Created ${role} ${username}.`);
|
console.log(`Created ${role} ${username}.`);
|
||||||
|
|||||||
2
packages/db/migrations/0011_premium_grandmaster.sql
Normal file
2
packages/db/migrations/0011_premium_grandmaster.sql
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
DROP INDEX IF EXISTS "operators_telegram_user_id_uq";--> statement-breakpoint
|
||||||
|
ALTER TABLE "operators" DROP COLUMN IF EXISTS "telegram_user_id";
|
||||||
1050
packages/db/migrations/meta/0011_snapshot.json
Normal file
1050
packages/db/migrations/meta/0011_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -78,6 +78,13 @@
|
|||||||
"when": 1778405570914,
|
"when": 1778405570914,
|
||||||
"tag": "0010_fancy_wolf_cub",
|
"tag": "0010_fancy_wolf_cub",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 11,
|
||||||
|
"version": "7",
|
||||||
|
"when": 1778405817706,
|
||||||
|
"tag": "0011_premium_grandmaster",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -17,7 +17,6 @@ export const operators = pgTable(
|
|||||||
"operators",
|
"operators",
|
||||||
{
|
{
|
||||||
id: uuid("id").primaryKey().defaultRandom(),
|
id: uuid("id").primaryKey().defaultRandom(),
|
||||||
telegramUserId: bigint("telegram_user_id", { mode: "number" }).notNull(),
|
|
||||||
username: text("username").notNull(),
|
username: text("username").notNull(),
|
||||||
passwordHash: text("password_hash"),
|
passwordHash: text("password_hash"),
|
||||||
displayName: text("display_name").notNull(),
|
displayName: text("display_name").notNull(),
|
||||||
@ -26,7 +25,6 @@ export const operators = pgTable(
|
|||||||
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
createdAt: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
|
||||||
},
|
},
|
||||||
(t) => ({
|
(t) => ({
|
||||||
telegramUserIdUnique: uniqueIndex("operators_telegram_user_id_uq").on(t.telegramUserId),
|
|
||||||
usernameUnique: uniqueIndex("operators_username_uq").on(sql`lower(${t.username})`),
|
usernameUnique: uniqueIndex("operators_username_uq").on(sql`lower(${t.username})`),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,30 +1,25 @@
|
|||||||
import { createClient, operators } from "./index.js";
|
import { createClient, operators } from "./index.js";
|
||||||
|
|
||||||
const databaseUrl = process.env.DATABASE_URL;
|
const databaseUrl = process.env.DATABASE_URL;
|
||||||
const operatorTelegramId = process.env.SEED_OPERATOR_TELEGRAM_ID;
|
const username = process.env.SEED_OPERATOR_USERNAME ?? "admin";
|
||||||
const operatorName = process.env.SEED_OPERATOR_NAME ?? "Operator";
|
const operatorName = process.env.SEED_OPERATOR_NAME ?? "Operator";
|
||||||
|
|
||||||
if (!databaseUrl) {
|
if (!databaseUrl) {
|
||||||
console.error("DATABASE_URL not set");
|
console.error("DATABASE_URL not set");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
if (!operatorTelegramId || operatorTelegramId === "0") {
|
|
||||||
console.error("SEED_OPERATOR_TELEGRAM_ID not set");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { db, pool } = createClient(databaseUrl);
|
const { db, pool } = createClient(databaseUrl);
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.insert(operators)
|
.insert(operators)
|
||||||
.values({
|
.values({
|
||||||
telegramUserId: Number(operatorTelegramId),
|
username,
|
||||||
username: process.env.SEED_OPERATOR_USERNAME ?? "admin",
|
|
||||||
displayName: operatorName,
|
displayName: operatorName,
|
||||||
role: "admin",
|
role: "admin",
|
||||||
defaultTimezone: "Asia/Kuala_Lumpur",
|
defaultTimezone: "Asia/Kuala_Lumpur",
|
||||||
})
|
})
|
||||||
.onConflictDoNothing();
|
.onConflictDoNothing();
|
||||||
|
|
||||||
console.log(`Seeded operator with telegram_user_id=${operatorTelegramId}`);
|
console.log(`Seeded operator '${username}'. Set a password via scripts/set-password.sh ${username}`);
|
||||||
await pool.end();
|
await pool.end();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user