Make feilds optional

This commit is contained in:
Owen
2026-07-07 09:02:25 -04:00
parent 633159fb77
commit 8cceed91cf
+125 -91
View File
@@ -68,9 +68,9 @@ const updateSiteResourceSchema = z
"Fully qualified domain name with optional wildcards, e.g., example.internal, *.example.internal, or host-0?.example.internal", "Fully qualified domain name with optional wildcards, e.g., example.internal, *.example.internal, or host-0?.example.internal",
example: "service.example.internal" example: "service.example.internal"
}), }),
userIds: z.array(z.string()), userIds: z.array(z.string()).optional(),
roleIds: z.array(z.int()), roleIds: z.array(z.int()).optional(),
clientIds: z.array(z.int()), clientIds: z.array(z.int()).optional(),
tcpPortRangeString: portRangeStringSchema, tcpPortRangeString: portRangeStringSchema,
udpPortRangeString: portRangeStringSchema, udpPortRangeString: portRangeStringSchema,
disableIcmp: z.boolean().optional(), disableIcmp: z.boolean().optional(),
@@ -167,6 +167,10 @@ const updateSiteResourceSchema = z
) )
.refine( .refine(
(data) => { (data) => {
// if neither is provided, the existing site associations are left unchanged
if (data.siteIds === undefined && data.siteId === undefined) {
return true;
}
return ( return (
(data.siteIds !== undefined && data.siteIds.length > 0) || (data.siteIds !== undefined && data.siteIds.length > 0) ||
data.siteId !== undefined data.siteId !== undefined
@@ -263,7 +267,7 @@ export async function updateSiteResource(
const { siteResourceId } = parsedParams.data; const { siteResourceId } = parsedParams.data;
const { const {
name, name,
siteIds: siteIdsInput = [], // because it can change siteIds: siteIdsInput,
siteId, siteId,
niceId, niceId,
mode, mode,
@@ -287,9 +291,14 @@ export async function updateSiteResource(
} = parsedBody.data; } = parsedBody.data;
// Backward compatibility: merge deprecated siteId into siteIds array // Backward compatibility: merge deprecated siteId into siteIds array
const siteIds = [...siteIdsInput]; const siteIdsProvided =
if (siteId !== undefined && !siteIds.includes(siteId)) { siteIdsInput !== undefined || siteId !== undefined;
siteIds.push(siteId); let siteIds: number[] | undefined;
if (siteIdsProvided) {
siteIds = [...(siteIdsInput ?? [])];
if (siteId !== undefined && !siteIds.includes(siteId)) {
siteIds.push(siteId);
}
} }
// Check if site resource exists // Check if site resource exists
@@ -356,20 +365,22 @@ export async function updateSiteResource(
} }
// Verify the site exists and belongs to the org // Verify the site exists and belongs to the org
const sitesToAssign = await db if (siteIds !== undefined) {
.select() const sitesToAssign = await db
.from(sites) .select()
.where( .from(sites)
and( .where(
inArray(sites.siteId, siteIds), and(
eq(sites.orgId, existingSiteResource.orgId) inArray(sites.siteId, siteIds),
) eq(sites.orgId, existingSiteResource.orgId)
); )
);
if (sitesToAssign.length !== siteIds.length) { if (sitesToAssign.length !== siteIds.length) {
return next( return next(
createHttpError(HttpCode.NOT_FOUND, "Some site not found") createHttpError(HttpCode.NOT_FOUND, "Some site not found")
); );
}
} }
// Only check if destination is an IP address // Only check if destination is an IP address
@@ -463,7 +474,8 @@ export async function updateSiteResource(
} }
let updatedSiteResource: SiteResource | undefined; let updatedSiteResource: SiteResource | undefined;
let updatedSiteIds: number[] = []; // defaults to the existing sites; only overwritten below if siteIds/siteId was provided
let updatedSiteIds: number[] = [...existingSiteIds];
await db.transaction(async (trx) => { await db.transaction(async (trx) => {
// Update the site resource // Update the site resource
const sshPamSet = const sshPamSet =
@@ -522,81 +534,103 @@ export async function updateSiteResource(
//////////////////// update the associations //////////////////// //////////////////// update the associations ////////////////////
// delete the site - site resources associations if (siteIds !== undefined) {
await trx // delete the site - site resources associations
.delete(siteNetworks)
.where(
eq(siteNetworks.networkId, updatedSiteResource.networkId!)
);
for (const siteId of siteIds) {
await trx.insert(siteNetworks).values({
siteId: siteId,
networkId: updatedSiteResource.networkId!
});
updatedSiteIds.push(siteId);
}
await trx
.delete(clientSiteResources)
.where(eq(clientSiteResources.siteResourceId, siteResourceId));
if (clientIds.length > 0) {
await trx.insert(clientSiteResources).values(
clientIds.map((clientId) => ({
clientId,
siteResourceId
}))
);
}
await trx
.delete(userSiteResources)
.where(eq(userSiteResources.siteResourceId, siteResourceId));
if (userIds.length > 0) {
await trx.insert(userSiteResources).values(
userIds.map((userId) => ({
userId,
siteResourceId
}))
);
}
// Get all admin role IDs for this org to exclude from deletion
const adminRoles = await trx
.select()
.from(roles)
.where(
and(
eq(roles.isAdmin, true),
eq(roles.orgId, updatedSiteResource.orgId)
)
);
const adminRoleIds = adminRoles.map((role) => role.roleId);
if (adminRoleIds.length > 0) {
await trx.delete(roleSiteResources).where(
and(
eq(roleSiteResources.siteResourceId, siteResourceId),
ne(roleSiteResources.roleId, adminRoleIds[0]) // delete all but the admin role
)
);
} else {
await trx await trx
.delete(roleSiteResources) .delete(siteNetworks)
.where( .where(
eq(roleSiteResources.siteResourceId, siteResourceId) eq(
siteNetworks.networkId,
updatedSiteResource.networkId!
)
); );
updatedSiteIds = [];
for (const siteId of siteIds) {
await trx.insert(siteNetworks).values({
siteId: siteId,
networkId: updatedSiteResource.networkId!
});
updatedSiteIds.push(siteId);
}
} }
if (roleIds.length > 0) { if (clientIds !== undefined) {
await trx.insert(roleSiteResources).values( await trx
roleIds.map((roleId) => ({ .delete(clientSiteResources)
roleId, .where(
siteResourceId eq(clientSiteResources.siteResourceId, siteResourceId)
})) );
);
if (clientIds.length > 0) {
await trx.insert(clientSiteResources).values(
clientIds.map((clientId) => ({
clientId,
siteResourceId
}))
);
}
}
if (userIds !== undefined) {
await trx
.delete(userSiteResources)
.where(
eq(userSiteResources.siteResourceId, siteResourceId)
);
if (userIds.length > 0) {
await trx.insert(userSiteResources).values(
userIds.map((userId) => ({
userId,
siteResourceId
}))
);
}
}
if (roleIds !== undefined) {
// Get all admin role IDs for this org to exclude from deletion
const adminRoles = await trx
.select()
.from(roles)
.where(
and(
eq(roles.isAdmin, true),
eq(roles.orgId, updatedSiteResource.orgId)
)
);
const adminRoleIds = adminRoles.map((role) => role.roleId);
if (adminRoleIds.length > 0) {
await trx.delete(roleSiteResources).where(
and(
eq(
roleSiteResources.siteResourceId,
siteResourceId
),
ne(roleSiteResources.roleId, adminRoleIds[0]) // delete all but the admin role
)
);
} else {
await trx
.delete(roleSiteResources)
.where(
eq(
roleSiteResources.siteResourceId,
siteResourceId
)
);
}
if (roleIds.length > 0) {
await trx.insert(roleSiteResources).values(
roleIds.map((roleId) => ({
roleId,
siteResourceId
}))
);
}
} }
logger.info(`Updated site resource ${siteResourceId}`); logger.info(`Updated site resource ${siteResourceId}`);