Update
This commit is contained in:
+105
-6
@@ -6,10 +6,11 @@ const selectUsersWithGroups = db.prepare(`
|
||||
u.username,
|
||||
u.email,
|
||||
u.is_active,
|
||||
u.avatar_color,
|
||||
u.last_login,
|
||||
u.created_at,
|
||||
u.updated_at,
|
||||
GROUP_CONCAT(g.name, '|||') AS group_names
|
||||
GROUP_CONCAT(g.id || '::' || g.name, '|||') AS group_pairs
|
||||
FROM users u
|
||||
LEFT JOIN user_group_memberships m ON m.user_id = u.id
|
||||
LEFT JOIN user_groups g ON g.id = m.group_id
|
||||
@@ -17,13 +18,54 @@ const selectUsersWithGroups = db.prepare(`
|
||||
ORDER BY u.username COLLATE NOCASE
|
||||
`);
|
||||
|
||||
const normalizeGroupNames = (rawNames) => {
|
||||
if (!rawNames) {
|
||||
const selectUserWithGroupsById = db.prepare(`
|
||||
SELECT
|
||||
u.id,
|
||||
u.username,
|
||||
u.email,
|
||||
u.is_active,
|
||||
u.avatar_color,
|
||||
u.last_login,
|
||||
u.created_at,
|
||||
u.updated_at,
|
||||
GROUP_CONCAT(g.id || '::' || g.name, '|||') AS group_pairs
|
||||
FROM users u
|
||||
LEFT JOIN user_group_memberships m ON m.user_id = u.id
|
||||
LEFT JOIN user_groups g ON g.id = m.group_id
|
||||
WHERE u.id = ?
|
||||
GROUP BY u.id
|
||||
`);
|
||||
|
||||
const deleteMembershipsByUser = db.prepare(`
|
||||
DELETE FROM user_group_memberships
|
||||
WHERE user_id = ?
|
||||
`);
|
||||
|
||||
const insertMembershipForUser = db.prepare(`
|
||||
INSERT OR IGNORE INTO user_group_memberships (user_id, group_id)
|
||||
VALUES (?, ?)
|
||||
`);
|
||||
|
||||
const selectGroupById = db.prepare('SELECT id, name FROM user_groups WHERE id = ?');
|
||||
|
||||
const parseGroupPairs = (rawPairs) => {
|
||||
if (!rawPairs) {
|
||||
return [];
|
||||
}
|
||||
return rawNames
|
||||
return rawPairs
|
||||
.split('|||')
|
||||
.map((name) => String(name || '').trim())
|
||||
.map((entry) => {
|
||||
const [idPart, namePart] = entry.split('::');
|
||||
const groupName = String(namePart || '').trim();
|
||||
if (!groupName) {
|
||||
return null;
|
||||
}
|
||||
const numericId = Number(idPart);
|
||||
return {
|
||||
id: Number.isFinite(numericId) ? numericId : null,
|
||||
name: groupName
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
@@ -32,13 +74,70 @@ const sanitizeUserRecord = (row) => ({
|
||||
username: row.username,
|
||||
email: row.email,
|
||||
isActive: Boolean(row.is_active),
|
||||
avatarColor: row.avatar_color || null,
|
||||
lastLogin: row.last_login || null,
|
||||
createdAt: row.created_at || null,
|
||||
updatedAt: row.updated_at || null,
|
||||
groups: normalizeGroupNames(row.group_names)
|
||||
groups: parseGroupPairs(row.group_pairs)
|
||||
});
|
||||
|
||||
export function listUsers() {
|
||||
const rows = selectUsersWithGroups.all();
|
||||
return rows.map(sanitizeUserRecord);
|
||||
}
|
||||
|
||||
export function getUserById(userId) {
|
||||
const row = selectUserWithGroupsById.get(userId);
|
||||
return row ? sanitizeUserRecord(row) : null;
|
||||
}
|
||||
|
||||
const applyUserGroupAssignments = db.transaction((userId, groupIds) => {
|
||||
deleteMembershipsByUser.run(userId);
|
||||
groupIds.forEach((groupId) => {
|
||||
insertMembershipForUser.run(userId, groupId);
|
||||
});
|
||||
});
|
||||
|
||||
export function updateUserGroups(userId, groupIds) {
|
||||
const numericUserId = Number(userId);
|
||||
if (!Number.isFinite(numericUserId) || numericUserId <= 0) {
|
||||
const error = new Error('INVALID_USER_ID');
|
||||
error.code = 'INVALID_USER_ID';
|
||||
throw error;
|
||||
}
|
||||
|
||||
const existingUser = getUserById(numericUserId);
|
||||
if (!existingUser) {
|
||||
const error = new Error('USER_NOT_FOUND');
|
||||
error.code = 'USER_NOT_FOUND';
|
||||
throw error;
|
||||
}
|
||||
|
||||
const normalizedGroupIds = Array.isArray(groupIds)
|
||||
? Array.from(
|
||||
new Set(
|
||||
groupIds
|
||||
.map((value) => Number(value))
|
||||
.filter((value) => Number.isFinite(value) && value > 0)
|
||||
)
|
||||
)
|
||||
: [];
|
||||
|
||||
const missingGroupIds = [];
|
||||
normalizedGroupIds.forEach((groupId) => {
|
||||
const groupRow = selectGroupById.get(groupId);
|
||||
if (!groupRow) {
|
||||
missingGroupIds.push(groupId);
|
||||
}
|
||||
});
|
||||
|
||||
if (missingGroupIds.length > 0) {
|
||||
const error = new Error('GROUP_NOT_FOUND');
|
||||
error.code = 'GROUP_NOT_FOUND';
|
||||
error.missingGroupIds = missingGroupIds;
|
||||
throw error;
|
||||
}
|
||||
|
||||
applyUserGroupAssignments(numericUserId, normalizedGroupIds);
|
||||
return getUserById(numericUserId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user