146 lines
5.6 KiB
TypeScript
146 lines
5.6 KiB
TypeScript
import { query } from '../config/database.js';
|
|
|
|
export const syncUser = async (data: { externalId: string, email: string, name: string, organizationId?: string, clerkRole?: string }) => {
|
|
const { externalId, email, name, organizationId, clerkRole } = data;
|
|
|
|
let result = await query(
|
|
`INSERT INTO gpi.users (clerk_id, email, name, role, updated_at)
|
|
VALUES ($1, $2, $3, 'guest', NOW())
|
|
ON CONFLICT (clerk_id) DO UPDATE SET email = EXCLUDED.email, name = EXCLUDED.name, updated_at = NOW()
|
|
RETURNING *`,
|
|
[externalId, email, name]
|
|
);
|
|
|
|
let user = result.rows[0];
|
|
|
|
if (organizationId) {
|
|
let appRole = 'guest';
|
|
if (clerkRole === 'org:admin') appRole = 'admin';
|
|
else if (clerkRole === 'org:member') appRole = 'user';
|
|
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length > 0) {
|
|
const orgUuid = orgResult.rows[0].id;
|
|
|
|
await query(
|
|
`INSERT INTO gpi.user_organizations (user_id, organization_id, role, updated_at)
|
|
VALUES ($1, $2, $3, NOW())
|
|
ON CONFLICT (user_id, organization_id) DO NOTHING`,
|
|
[user.id, orgUuid, appRole]
|
|
);
|
|
|
|
const memberResult = await query(
|
|
'SELECT role, is_banned FROM gpi.user_organizations WHERE user_id = $1 AND organization_id = $2',
|
|
[user.id, orgUuid]
|
|
);
|
|
|
|
return {
|
|
...user,
|
|
organizationRole: memberResult.rows[0].role,
|
|
organizationBanned: memberResult.rows[0].is_banned
|
|
};
|
|
}
|
|
}
|
|
|
|
return user;
|
|
};
|
|
|
|
export const getCurrentUser = async (externalId: string, organizationId?: string) => {
|
|
const userResult = await query('SELECT * FROM gpi.users WHERE clerk_id = $1 OR logto_id = $1', [externalId]);
|
|
if (userResult.rows.length === 0) return null;
|
|
const user = userResult.rows[0];
|
|
|
|
if (organizationId) {
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length > 0) {
|
|
const orgUuid = orgResult.rows[0].id;
|
|
const memberResult = await query(
|
|
'SELECT role, is_banned FROM gpi.user_organizations WHERE user_id = $1 AND organization_id = $2',
|
|
[user.id, orgUuid]
|
|
);
|
|
if (memberResult.rows.length > 0) {
|
|
return {
|
|
...user,
|
|
role: memberResult.rows[0].role,
|
|
isBanned: memberResult.rows[0].is_banned,
|
|
organizationId
|
|
};
|
|
}
|
|
}
|
|
}
|
|
return user;
|
|
};
|
|
|
|
export const getAllUsersInOrg = async (organizationId: string) => {
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length === 0) return [];
|
|
const orgUuid = orgResult.rows[0].id;
|
|
|
|
const results = await query(
|
|
`SELECT u.*, uo.role as organization_role, uo.is_banned as organization_banned, uo.id as member_id
|
|
FROM gpi.users u
|
|
JOIN gpi.user_organizations uo ON u.id = uo.user_id
|
|
WHERE uo.organization_id = $1
|
|
ORDER BY uo.created_at DESC`,
|
|
[orgUuid]
|
|
);
|
|
return results.rows;
|
|
};
|
|
|
|
export const updateUserRole = async (userIdOrMemberId: string, organizationId: string, role: string) => {
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length === 0) return null;
|
|
const orgUuid = orgResult.rows[0].id;
|
|
|
|
// Try update by member_id or user_id
|
|
const result = await query(
|
|
'UPDATE gpi.user_organizations SET role = $1, updated_at = NOW() WHERE (id = $2 OR user_id = $2) AND organization_id = $3 RETURNING *',
|
|
[role, userIdOrMemberId, orgUuid]
|
|
);
|
|
return result.rows[0];
|
|
};
|
|
|
|
export const toggleBanUser = async (userIdOrMemberId: string, organizationId: string, isBanned: boolean) => {
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length === 0) return null;
|
|
const orgUuid = orgResult.rows[0].id;
|
|
|
|
const result = await query(
|
|
'UPDATE gpi.user_organizations SET is_banned = $1, updated_at = NOW() WHERE (id = $2 OR user_id = $2) AND organization_id = $3 RETURNING *',
|
|
[isBanned, userIdOrMemberId, orgUuid]
|
|
);
|
|
return result.rows[0];
|
|
};
|
|
|
|
export const heartbeat = async (userId: string) => {
|
|
await query('UPDATE gpi.users SET last_seen_at = NOW() WHERE id = $1', [userId]);
|
|
};
|
|
|
|
export const getActiveUsers = async (organizationId: string, excludeUserId?: string) => {
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length === 0) return [];
|
|
const orgUuid = orgResult.rows[0].id;
|
|
|
|
const twoMinutesAgo = new Date(Date.now() - 2 * 60 * 1000);
|
|
const result = await query(
|
|
`SELECT u.id, u.name, u.email, u.last_seen_at, u.clerk_id as "externalId"
|
|
FROM gpi.users u
|
|
JOIN gpi.user_organizations uo ON u.id = uo.user_id
|
|
WHERE uo.organization_id = $1 AND u.last_seen_at >= $2 AND u.id != $3`,
|
|
[orgUuid, twoMinutesAgo, excludeUserId || '00000000-0000-0000-0000-000000000000']
|
|
);
|
|
return result.rows;
|
|
};
|
|
|
|
export const deleteUserFromOrg = async (userIdOrMemberId: string, organizationId: string) => {
|
|
const orgResult = await query('SELECT id FROM gpi.organizations WHERE clerk_id = $1 OR logto_id = $1', [organizationId]);
|
|
if (orgResult.rows.length === 0) return false;
|
|
const orgUuid = orgResult.rows[0].id;
|
|
|
|
const result = await query(
|
|
'DELETE FROM gpi.user_organizations WHERE (id = $1 OR user_id = $1) AND organization_id = $2',
|
|
[userIdOrMemberId, orgUuid]
|
|
);
|
|
return result.rowCount > 0;
|
|
};
|