mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-27 07:16:40 +00:00
first pass
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
roles,
|
||||
Transaction,
|
||||
userClients,
|
||||
userOrgRoles,
|
||||
userOrgs
|
||||
} from "@server/db";
|
||||
import { getUniqueClientName } from "@server/db/names";
|
||||
@@ -39,20 +40,36 @@ export async function calculateUserClientsForOrgs(
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all user orgs
|
||||
const allUserOrgs = await transaction
|
||||
// Get all user orgs with all roles (for org list and role-based logic)
|
||||
const userOrgRoleRows = await transaction
|
||||
.select()
|
||||
.from(userOrgs)
|
||||
.innerJoin(roles, eq(roles.roleId, userOrgs.roleId))
|
||||
.innerJoin(
|
||||
userOrgRoles,
|
||||
and(
|
||||
eq(userOrgs.userId, userOrgRoles.userId),
|
||||
eq(userOrgs.orgId, userOrgRoles.orgId)
|
||||
)
|
||||
)
|
||||
.innerJoin(roles, eq(userOrgRoles.roleId, roles.roleId))
|
||||
.where(eq(userOrgs.userId, userId));
|
||||
|
||||
const userOrgIds = allUserOrgs.map(({ userOrgs: uo }) => uo.orgId);
|
||||
const userOrgIds = [...new Set(userOrgRoleRows.map((r) => r.userOrgs.orgId))];
|
||||
const orgIdToRoleRows = new Map<
|
||||
string,
|
||||
(typeof userOrgRoleRows)[0][]
|
||||
>();
|
||||
for (const r of userOrgRoleRows) {
|
||||
const list = orgIdToRoleRows.get(r.userOrgs.orgId) ?? [];
|
||||
list.push(r);
|
||||
orgIdToRoleRows.set(r.userOrgs.orgId, list);
|
||||
}
|
||||
|
||||
// For each OLM, ensure there's a client in each org the user is in
|
||||
for (const olm of userOlms) {
|
||||
for (const userRoleOrg of allUserOrgs) {
|
||||
const { userOrgs: userOrg, roles: role } = userRoleOrg;
|
||||
const orgId = userOrg.orgId;
|
||||
for (const orgId of orgIdToRoleRows.keys()) {
|
||||
const roleRowsForOrg = orgIdToRoleRows.get(orgId)!;
|
||||
const userOrg = roleRowsForOrg[0].userOrgs;
|
||||
|
||||
const [org] = await transaction
|
||||
.select()
|
||||
@@ -196,7 +213,7 @@ export async function calculateUserClientsForOrgs(
|
||||
const requireApproval =
|
||||
build !== "oss" &&
|
||||
isOrgLicensed &&
|
||||
role.requireDeviceApproval;
|
||||
roleRowsForOrg.some((r) => r.roles.requireDeviceApproval);
|
||||
|
||||
const newClientData: InferInsertModel<typeof clients> = {
|
||||
userId,
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
siteResources,
|
||||
sites,
|
||||
Transaction,
|
||||
userOrgRoles,
|
||||
userOrgs,
|
||||
userSiteResources
|
||||
} from "@server/db";
|
||||
@@ -77,10 +78,10 @@ export async function getClientSiteResourceAccess(
|
||||
// get all of the users in these roles
|
||||
const userIdsFromRoles = await trx
|
||||
.select({
|
||||
userId: userOrgs.userId
|
||||
userId: userOrgRoles.userId
|
||||
})
|
||||
.from(userOrgs)
|
||||
.where(inArray(userOrgs.roleId, roleIds))
|
||||
.from(userOrgRoles)
|
||||
.where(inArray(userOrgRoles.roleId, roleIds))
|
||||
.then((rows) => rows.map((row) => row.userId));
|
||||
|
||||
const newAllUserIds = Array.from(
|
||||
@@ -811,12 +812,12 @@ export async function rebuildClientAssociationsFromClient(
|
||||
|
||||
// Role-based access
|
||||
const roleIds = await trx
|
||||
.select({ roleId: userOrgs.roleId })
|
||||
.from(userOrgs)
|
||||
.select({ roleId: userOrgRoles.roleId })
|
||||
.from(userOrgRoles)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgs.userId, client.userId),
|
||||
eq(userOrgs.orgId, client.orgId)
|
||||
eq(userOrgRoles.userId, client.userId),
|
||||
eq(userOrgRoles.orgId, client.orgId)
|
||||
)
|
||||
) // this needs to be locked onto this org or else cross-org access could happen
|
||||
.then((rows) => rows.map((row) => row.roleId));
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
siteResources,
|
||||
sites,
|
||||
Transaction,
|
||||
UserOrg,
|
||||
userOrgRoles,
|
||||
userOrgs,
|
||||
userResources,
|
||||
userSiteResources,
|
||||
@@ -19,9 +19,15 @@ import { FeatureId } from "@server/lib/billing";
|
||||
export async function assignUserToOrg(
|
||||
org: Org,
|
||||
values: typeof userOrgs.$inferInsert,
|
||||
roleId: number,
|
||||
trx: Transaction | typeof db = db
|
||||
) {
|
||||
const [userOrg] = await trx.insert(userOrgs).values(values).returning();
|
||||
await trx.insert(userOrgRoles).values({
|
||||
userId: userOrg.userId,
|
||||
orgId: userOrg.orgId,
|
||||
roleId
|
||||
});
|
||||
|
||||
// calculate if the user is in any other of the orgs before we count it as an add to the billing org
|
||||
if (org.billingOrgId) {
|
||||
@@ -58,6 +64,14 @@ export async function removeUserFromOrg(
|
||||
userId: string,
|
||||
trx: Transaction | typeof db = db
|
||||
) {
|
||||
await trx
|
||||
.delete(userOrgRoles)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgRoles.userId, userId),
|
||||
eq(userOrgRoles.orgId, org.orgId)
|
||||
)
|
||||
);
|
||||
await trx
|
||||
.delete(userOrgs)
|
||||
.where(and(eq(userOrgs.userId, userId), eq(userOrgs.orgId, org.orgId)));
|
||||
|
||||
22
server/lib/userOrgRoles.ts
Normal file
22
server/lib/userOrgRoles.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { db, userOrgRoles } from "@server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
|
||||
/**
|
||||
* Get all role IDs a user has in an organization.
|
||||
* Returns empty array if the user has no roles in the org (callers must treat as no access).
|
||||
*/
|
||||
export async function getUserOrgRoleIds(
|
||||
userId: string,
|
||||
orgId: string
|
||||
): Promise<number[]> {
|
||||
const rows = await db
|
||||
.select({ roleId: userOrgRoles.roleId })
|
||||
.from(userOrgRoles)
|
||||
.where(
|
||||
and(
|
||||
eq(userOrgRoles.userId, userId),
|
||||
eq(userOrgRoles.orgId, orgId)
|
||||
)
|
||||
);
|
||||
return rows.map((r) => r.roleId);
|
||||
}
|
||||
Reference in New Issue
Block a user