fix: Adapt SQL queries to actual Outline database schema

- Users: Use role enum instead of isAdmin/isViewer/isSuspended booleans
- Users: Remove non-existent username column
- Groups: Fix group_users table (no deletedAt, composite PK)
- Attachments: Remove url and deletedAt columns, use hard delete

All 10/10 core queries now pass validation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 13:32:41 +00:00
parent 42fc0c6d6d
commit 6f5d17516b
4 changed files with 65 additions and 61 deletions

View File

@@ -56,13 +56,13 @@ const listUsers: BaseTool<UserArgs> = {
// Add role/status filters
switch (filter) {
case 'admins':
whereConditions.push('u."isAdmin" = true');
whereConditions.push("u.role = 'admin'");
break;
case 'members':
whereConditions.push('u."isAdmin" = false AND u."isViewer" = false');
whereConditions.push("u.role = 'member'");
break;
case 'suspended':
whereConditions.push('u."isSuspended" = true');
whereConditions.push('u."suspendedAt" IS NOT NULL');
break;
case 'invited':
whereConditions.push('u."lastSignedInAt" IS NULL');
@@ -76,16 +76,13 @@ const listUsers: BaseTool<UserArgs> = {
SELECT
u.id,
u.email,
u.username,
u.name,
u."avatarUrl",
u.language,
u.preferences,
u."notificationSettings",
u.timezone,
u."isAdmin",
u."isViewer",
u."isSuspended",
u.role,
u."lastActiveAt",
u."lastSignedInAt",
u."suspendedAt",
@@ -94,7 +91,7 @@ const listUsers: BaseTool<UserArgs> = {
u."createdAt",
u."updatedAt",
t.name as "teamName",
(SELECT COUNT(*) FROM users WHERE ${whereConditions.join(' AND ')}) as total
(SELECT COUNT(*) FROM users u2 WHERE u2."deletedAt" IS NULL) as total
FROM users u
LEFT JOIN teams t ON u."teamId" = t.id
${whereClause}
@@ -152,16 +149,13 @@ const getUser: BaseTool<GetUserArgs> = {
SELECT
u.id,
u.email,
u.username,
u.name,
u."avatarUrl",
u.language,
u.preferences,
u."notificationSettings",
u.timezone,
u."isAdmin",
u."isViewer",
u."isSuspended",
u.role,
u."lastActiveAt",
u."lastSignedInAt",
u."suspendedAt",
@@ -254,22 +248,19 @@ const createUser: BaseTool<CreateUserArgs> = {
}
const teamId = teamResult.rows[0].id;
const isAdmin = role === 'admin';
const isViewer = role === 'viewer';
const result = await pgClient.query(
`
INSERT INTO users (
id, email, name, "teamId", "isAdmin", "isViewer",
id, email, name, "teamId", role,
"createdAt", "updatedAt"
)
VALUES (
gen_random_uuid(), $1, $2, $3, $4, $5,
gen_random_uuid(), $1, $2, $3, $4,
NOW(), NOW()
)
RETURNING *
`,
[email, name, teamId, isAdmin, isViewer]
[email, name, teamId, role]
);
return {
@@ -458,9 +449,9 @@ const suspendUser: BaseTool<GetUserArgs> = {
const result = await pgClient.query(
`
UPDATE users
SET "isSuspended" = true, "suspendedAt" = NOW()
SET "suspendedAt" = NOW()
WHERE id = $1 AND "deletedAt" IS NULL
RETURNING id, email, name, "isSuspended", "suspendedAt"
RETURNING id, email, name, "suspendedAt"
`,
[args.id]
);
@@ -511,9 +502,9 @@ const activateUser: BaseTool<GetUserArgs> = {
const result = await pgClient.query(
`
UPDATE users
SET "isSuspended" = false, "suspendedAt" = NULL, "suspendedById" = NULL
SET "suspendedAt" = NULL, "suspendedById" = NULL
WHERE id = $1 AND "deletedAt" IS NULL
RETURNING id, email, name, "isSuspended"
RETURNING id, email, name, "suspendedAt"
`,
[args.id]
);
@@ -564,9 +555,9 @@ const promoteUser: BaseTool<GetUserArgs> = {
const result = await pgClient.query(
`
UPDATE users
SET "isAdmin" = true, "isViewer" = false, "updatedAt" = NOW()
SET role = 'admin', "updatedAt" = NOW()
WHERE id = $1 AND "deletedAt" IS NULL
RETURNING id, email, name, "isAdmin", "isViewer"
RETURNING id, email, name, role
`,
[args.id]
);
@@ -617,9 +608,9 @@ const demoteUser: BaseTool<GetUserArgs> = {
const result = await pgClient.query(
`
UPDATE users
SET "isAdmin" = false, "updatedAt" = NOW()
SET role = 'member', "updatedAt" = NOW()
WHERE id = $1 AND "deletedAt" IS NULL
RETURNING id, email, name, "isAdmin", "isViewer"
RETURNING id, email, name, role
`,
[args.id]
);