mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-24 17:52:33 +00:00
✨ handle private resources filtering by labels
This commit is contained in:
@@ -1,4 +1,14 @@
|
|||||||
import { db, DB_TYPE, SiteResource, siteNetworks, siteResources, sites } from "@server/db";
|
import {
|
||||||
|
db,
|
||||||
|
DB_TYPE,
|
||||||
|
Label,
|
||||||
|
SiteResource,
|
||||||
|
siteNetworks,
|
||||||
|
siteResourceLabels,
|
||||||
|
siteResources,
|
||||||
|
sites,
|
||||||
|
labels
|
||||||
|
} from "@server/db";
|
||||||
import response from "@server/lib/response";
|
import response from "@server/lib/response";
|
||||||
import logger from "@server/logger";
|
import logger from "@server/logger";
|
||||||
import { OpenAPITags, registry } from "@server/openApi";
|
import { OpenAPITags, registry } from "@server/openApi";
|
||||||
@@ -9,6 +19,8 @@ import { NextFunction, Request, Response } from "express";
|
|||||||
import createHttpError from "http-errors";
|
import createHttpError from "http-errors";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { fromError } from "zod-validation-error";
|
import { fromError } from "zod-validation-error";
|
||||||
|
import { isLicensedOrSubscribed } from "#dynamic/lib/isLicencedOrSubscribed";
|
||||||
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
|
|
||||||
const listAllSiteResourcesByOrgParamsSchema = z.strictObject({
|
const listAllSiteResourcesByOrgParamsSchema = z.strictObject({
|
||||||
orgId: z.string()
|
orgId: z.string()
|
||||||
@@ -69,12 +81,7 @@ const listAllSiteResourcesByOrgQuerySchema = z.object({
|
|||||||
default: "asc",
|
default: "asc",
|
||||||
description: "Sort order"
|
description: "Sort order"
|
||||||
}),
|
}),
|
||||||
siteId: z.coerce
|
siteId: z.coerce.number<string>().int().positive().optional().openapi({
|
||||||
.number<string>()
|
|
||||||
.int()
|
|
||||||
.positive()
|
|
||||||
.optional()
|
|
||||||
.openapi({
|
|
||||||
type: "integer",
|
type: "integer",
|
||||||
description:
|
description:
|
||||||
"When set, only site resources associated with this site (via network) are returned"
|
"When set, only site resources associated with this site (via network) are returned"
|
||||||
@@ -88,6 +95,7 @@ export type ListAllSiteResourcesByOrgResponse = PaginatedResponse<{
|
|||||||
siteNames: string[];
|
siteNames: string[];
|
||||||
siteNiceIds: string[];
|
siteNiceIds: string[];
|
||||||
siteAddresses: (string | null)[];
|
siteAddresses: (string | null)[];
|
||||||
|
labels?: Array<Pick<Label, "labelId" | "name" | "color">>;
|
||||||
})[];
|
})[];
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
@@ -234,6 +242,11 @@ export async function listAllSiteResourcesByOrg(
|
|||||||
const { page, pageSize, query, mode, sort_by, order, siteId } =
|
const { page, pageSize, query, mode, sort_by, order, siteId } =
|
||||||
parsedQuery.data;
|
parsedQuery.data;
|
||||||
|
|
||||||
|
const isLabelFeatureEnabled = await isLicensedOrSubscribed(
|
||||||
|
orgId,
|
||||||
|
tierMatrix.labels
|
||||||
|
);
|
||||||
|
|
||||||
const conditions = [and(eq(siteResources.orgId, orgId))];
|
const conditions = [and(eq(siteResources.orgId, orgId))];
|
||||||
|
|
||||||
if (siteId != null) {
|
if (siteId != null) {
|
||||||
@@ -258,39 +271,39 @@ export async function listAllSiteResourcesByOrg(
|
|||||||
inArray(siteResources.siteResourceId, resourcesForSite)
|
inArray(siteResources.siteResourceId, resourcesForSite)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode) {
|
||||||
|
conditions.push(eq(siteResources.mode, mode));
|
||||||
|
}
|
||||||
|
|
||||||
if (query) {
|
if (query) {
|
||||||
conditions.push(
|
const q = "%" + query.toLowerCase() + "%";
|
||||||
or(
|
const queryList = [
|
||||||
like(
|
like(sql`LOWER(${siteResources.name})`, q),
|
||||||
sql`LOWER(${siteResources.name})`,
|
like(sql`LOWER(${siteResources.niceId})`, q),
|
||||||
"%" + query.toLowerCase() + "%"
|
like(sql`LOWER(${siteResources.destination})`, q),
|
||||||
),
|
like(sql`LOWER(${siteResources.alias})`, q),
|
||||||
like(
|
like(sql`LOWER(${siteResources.aliasAddress})`, q),
|
||||||
sql`LOWER(${siteResources.niceId})`,
|
like(sql`LOWER(${sites.name})`, q)
|
||||||
"%" + query.toLowerCase() + "%"
|
];
|
||||||
),
|
|
||||||
like(
|
if (isLabelFeatureEnabled) {
|
||||||
sql`LOWER(${siteResources.destination})`,
|
queryList.push(
|
||||||
"%" + query.toLowerCase() + "%"
|
inArray(
|
||||||
),
|
siteResources.siteResourceId,
|
||||||
like(
|
db
|
||||||
sql`LOWER(${siteResources.alias})`,
|
.select({ id: siteResourceLabels.siteResourceId })
|
||||||
"%" + query.toLowerCase() + "%"
|
.from(siteResourceLabels)
|
||||||
),
|
.innerJoin(
|
||||||
like(
|
labels,
|
||||||
sql`LOWER(${siteResources.aliasAddress})`,
|
eq(labels.labelId, siteResourceLabels.labelId)
|
||||||
"%" + query.toLowerCase() + "%"
|
|
||||||
),
|
|
||||||
like(
|
|
||||||
sql`LOWER(${sites.name})`,
|
|
||||||
"%" + query.toLowerCase() + "%"
|
|
||||||
)
|
)
|
||||||
|
.where(like(sql`LOWER(${labels.name})`, q))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode) {
|
conditions.push(or(...queryList));
|
||||||
conditions.push(eq(siteResources.mode, mode));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const baseQuery = querySiteResourcesBase().where(and(...conditions));
|
const baseQuery = querySiteResourcesBase().where(and(...conditions));
|
||||||
@@ -315,11 +328,51 @@ export async function listAllSiteResourcesByOrg(
|
|||||||
countQuery
|
countQuery
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const siteResourcesList = siteResourcesRaw.map(transformSiteResourceRow);
|
const siteResourcesList = siteResourcesRaw.map(
|
||||||
|
transformSiteResourceRow
|
||||||
|
);
|
||||||
|
|
||||||
|
const siteResourceIdList = siteResourcesList.map(
|
||||||
|
(r) => r.siteResourceId
|
||||||
|
);
|
||||||
|
|
||||||
|
let labelsForSiteResources: Array<{
|
||||||
|
labelId: number;
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
siteResourceId: number;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
|
if (isLabelFeatureEnabled && siteResourceIdList.length > 0) {
|
||||||
|
labelsForSiteResources = await db
|
||||||
|
.select({
|
||||||
|
labelId: labels.labelId,
|
||||||
|
name: labels.name,
|
||||||
|
color: labels.color,
|
||||||
|
siteResourceId: siteResourceLabels.siteResourceId
|
||||||
|
})
|
||||||
|
.from(labels)
|
||||||
|
.innerJoin(
|
||||||
|
siteResourceLabels,
|
||||||
|
eq(siteResourceLabels.labelId, labels.labelId)
|
||||||
|
)
|
||||||
|
.where(
|
||||||
|
inArray(
|
||||||
|
siteResourceLabels.siteResourceId,
|
||||||
|
siteResourceIdList
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.orderBy(asc(siteResourceLabels.siteResourceLabelId));
|
||||||
|
}
|
||||||
|
|
||||||
return response<ListAllSiteResourcesByOrgResponse>(res, {
|
return response<ListAllSiteResourcesByOrgResponse>(res, {
|
||||||
data: {
|
data: {
|
||||||
siteResources: siteResourcesList,
|
siteResources: siteResourcesList.map((r) => ({
|
||||||
|
...r,
|
||||||
|
labels: labelsForSiteResources.filter(
|
||||||
|
(l) => l.siteResourceId === r.siteResourceId
|
||||||
|
)
|
||||||
|
})),
|
||||||
pagination: {
|
pagination: {
|
||||||
total: totalCount,
|
total: totalCount,
|
||||||
pageSize,
|
pageSize,
|
||||||
|
|||||||
Reference in New Issue
Block a user