sc-idp/lib/groups.js
2026-06-01 16:40:54 -05:00

79 lines
2.2 KiB
JavaScript

// Group membership model: the single source of truth for the OIDC `groups` claim
// (and, in a later phase, LDAP groups). A user's effective groups = their
// Saltcorn role exposed as a group (role:<name>) UNION their custom group
// memberships (group:<name>), so a role and a custom group with the same name
// never collide.
const db = require("@saltcorn/data/db");
const { TABLE_GROUPS, TABLE_GROUP_MEMBERS } = require("./constants");
const ROLE_PREFIX = "role:";
const GROUP_PREFIX = "group:";
const listGroups = async () => {
return await db.select(TABLE_GROUPS, {}, { orderBy: "name" });
};
const createGroup = async (name, description) => {
return await db.insert(TABLE_GROUPS, {
name: name,
description: description || null,
created_at: new Date().toISOString()
});
};
const deleteGroup = async (id) => {
await db.deleteWhere(TABLE_GROUP_MEMBERS, { group_id: id });
await db.deleteWhere(TABLE_GROUPS, { id: id });
};
const membersOf = async (groupId) => {
return await db.select(TABLE_GROUP_MEMBERS, { group_id: groupId });
};
const addMember = async (groupId, userId) => {
const existing = await db.selectMaybeOne(TABLE_GROUP_MEMBERS, { group_id: groupId, user_id: userId });
if (existing) {
return;
}
await db.insert(TABLE_GROUP_MEMBERS, { group_id: groupId, user_id: userId }, { noid: true });
};
const removeMember = async (groupId, userId) => {
await db.deleteWhere(TABLE_GROUP_MEMBERS, { group_id: groupId, user_id: userId });
};
const effectiveGroups = async (user) => {
const out = [];
const role = await db.selectMaybeOne("_sc_roles", { id: user.role_id });
if (role && role.role) {
out.push(ROLE_PREFIX + role.role);
}
const members = await db.select(TABLE_GROUP_MEMBERS, { user_id: user.id });
for (const member of members) {
const group = await db.selectMaybeOne(TABLE_GROUPS, { id: member.group_id });
if (group && group.name) {
out.push(GROUP_PREFIX + group.name);
}
}
return out;
};
module.exports = {
listGroups,
createGroup,
deleteGroup,
membersOf,
addMember,
removeMember,
effectiveGroups
};