feat: Implement section access validation for agent filtering and refine filterable field retrieval to include only fields from global or assigned sections.
This commit is contained in:
@@ -236,41 +236,67 @@ export class AgentsService {
|
||||
const filterSlugs = Object.keys(parsedFilters);
|
||||
|
||||
if (filterSlugs.length > 0) {
|
||||
// Get field IDs for the filter slugs
|
||||
// Get field IDs for the filter slugs, including section info for assignment validation
|
||||
const fields = await this.prisma.profileField.findMany({
|
||||
where: { slug: { in: filterSlugs } },
|
||||
select: { id: true, slug: true },
|
||||
select: {
|
||||
id: true,
|
||||
slug: true,
|
||||
sectionId: true,
|
||||
section: {
|
||||
select: {
|
||||
isGlobal: true,
|
||||
agentTypeSections: {
|
||||
select: { agentTypeId: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const slugToFieldId = new Map(fields.map((f) => [f.slug, f.id]));
|
||||
const slugToField = new Map(fields.map((f) => [f.slug, f]));
|
||||
|
||||
// For each filter, find agents that have ANY of the selected values
|
||||
// Use AND logic between different fields
|
||||
const filterConditions: string[][] = [];
|
||||
|
||||
for (const [slug, selectedValues] of Object.entries(parsedFilters)) {
|
||||
const fieldId = slugToFieldId.get(slug);
|
||||
if (!fieldId || !selectedValues || selectedValues.length === 0) continue;
|
||||
const field = slugToField.get(slug);
|
||||
if (!field || !selectedValues || selectedValues.length === 0) continue;
|
||||
|
||||
// Build set of agent type IDs that have access to this field's section
|
||||
const isGlobal = field.section.isGlobal;
|
||||
const allowedAgentTypeIds = new Set(
|
||||
field.section.agentTypeSections.map((ats) => ats.agentTypeId),
|
||||
);
|
||||
|
||||
// Find agentProfileIds where jsonValue contains ANY of the selected values
|
||||
const matchingValues = await this.prisma.agentProfileFieldValue.findMany({
|
||||
where: {
|
||||
fieldId,
|
||||
// jsonValue contains any of the selected values (for MULTI_SELECT, CHECKBOX_GROUP)
|
||||
// We need to check if the jsonValue array contains any of the selected values
|
||||
},
|
||||
where: { fieldId: field.id },
|
||||
select: {
|
||||
agentProfileId: true,
|
||||
jsonValue: true,
|
||||
agentProfile: {
|
||||
select: { agentTypeId: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
// Filter in memory - check if jsonValue array contains any selected value
|
||||
// Filter in memory:
|
||||
// 1. Check if jsonValue array contains any selected value
|
||||
// 2. Check if the agent's type has access to this field's section
|
||||
const matchingAgentIds = matchingValues
|
||||
.filter((fv) => {
|
||||
const jsonVal = fv.jsonValue as string[] | null;
|
||||
if (!jsonVal || !Array.isArray(jsonVal)) return false;
|
||||
return selectedValues.some((sv) => jsonVal.includes(sv));
|
||||
if (!selectedValues.some((sv) => jsonVal.includes(sv))) return false;
|
||||
|
||||
// Validate that this agent's type has access to the field's section
|
||||
const agentTypeId = fv.agentProfile.agentTypeId;
|
||||
if (!isGlobal && (!agentTypeId || !allowedAgentTypeIds.has(agentTypeId))) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map((fv) => fv.agentProfileId);
|
||||
|
||||
|
||||
@@ -235,6 +235,7 @@ export class ProfileFieldsService {
|
||||
/**
|
||||
* Get all filterable fields (public endpoint for search filters)
|
||||
* Returns fields with CHECKBOX_GROUP, SELECT, MULTI_SELECT types that have options
|
||||
* Only includes fields from sections that are global or assigned to at least one agent type
|
||||
* De-duplicates by both slug AND name to handle duplicate fields with different slugs
|
||||
*/
|
||||
async getFilterableFields() {
|
||||
@@ -245,6 +246,14 @@ export class ProfileFieldsService {
|
||||
isActive: true,
|
||||
fieldType: { in: filterableTypes },
|
||||
options: { not: Prisma.JsonNull },
|
||||
// Only include fields from sections that are global or assigned to at least one agent type
|
||||
section: {
|
||||
isActive: true,
|
||||
OR: [
|
||||
{ isGlobal: true },
|
||||
{ agentTypeSections: { some: {} } },
|
||||
],
|
||||
},
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
|
||||
Reference in New Issue
Block a user