|
1 | | -import { Injectable, NotFoundException } from '@nestjs/common'; |
| 1 | +import { |
| 2 | + BadRequestException, |
| 3 | + Injectable, |
| 4 | + NotFoundException, |
| 5 | +} from '@nestjs/common'; |
2 | 6 | import { db, Prisma } from '@db'; |
3 | 7 | import { CreateControlDto } from './dto/create-control.dto'; |
4 | 8 |
|
@@ -193,6 +197,115 @@ export class ControlsService { |
193 | 197 | return control; |
194 | 198 | } |
195 | 199 |
|
| 200 | + private async ensureControl(controlId: string, organizationId: string) { |
| 201 | + const control = await db.control.findUnique({ |
| 202 | + where: { id: controlId, organizationId }, |
| 203 | + select: { id: true }, |
| 204 | + }); |
| 205 | + if (!control) { |
| 206 | + throw new NotFoundException('Control not found'); |
| 207 | + } |
| 208 | + return control; |
| 209 | + } |
| 210 | + |
| 211 | + async linkPolicies( |
| 212 | + controlId: string, |
| 213 | + organizationId: string, |
| 214 | + policyIds: string[], |
| 215 | + ) { |
| 216 | + await this.ensureControl(controlId, organizationId); |
| 217 | + |
| 218 | + const policies = await db.policy.findMany({ |
| 219 | + where: { id: { in: policyIds }, organizationId }, |
| 220 | + select: { id: true }, |
| 221 | + }); |
| 222 | + if (policies.length === 0) { |
| 223 | + throw new BadRequestException('No valid policies to link'); |
| 224 | + } |
| 225 | + |
| 226 | + await db.control.update({ |
| 227 | + where: { id: controlId }, |
| 228 | + data: { policies: { connect: policies.map((p) => ({ id: p.id })) } }, |
| 229 | + }); |
| 230 | + |
| 231 | + return { count: policies.length }; |
| 232 | + } |
| 233 | + |
| 234 | + async linkTasks( |
| 235 | + controlId: string, |
| 236 | + organizationId: string, |
| 237 | + taskIds: string[], |
| 238 | + ) { |
| 239 | + await this.ensureControl(controlId, organizationId); |
| 240 | + |
| 241 | + const tasks = await db.task.findMany({ |
| 242 | + where: { id: { in: taskIds }, organizationId }, |
| 243 | + select: { id: true }, |
| 244 | + }); |
| 245 | + if (tasks.length === 0) { |
| 246 | + throw new BadRequestException('No valid tasks to link'); |
| 247 | + } |
| 248 | + |
| 249 | + await db.control.update({ |
| 250 | + where: { id: controlId }, |
| 251 | + data: { tasks: { connect: tasks.map((t) => ({ id: t.id })) } }, |
| 252 | + }); |
| 253 | + |
| 254 | + return { count: tasks.length }; |
| 255 | + } |
| 256 | + |
| 257 | + async linkRequirements( |
| 258 | + controlId: string, |
| 259 | + organizationId: string, |
| 260 | + mappings: { requirementId: string; frameworkInstanceId: string }[], |
| 261 | + ) { |
| 262 | + await this.ensureControl(controlId, organizationId); |
| 263 | + |
| 264 | + const frameworkInstanceIds = Array.from( |
| 265 | + new Set(mappings.map((m) => m.frameworkInstanceId)), |
| 266 | + ); |
| 267 | + const instances = await db.frameworkInstance.findMany({ |
| 268 | + where: { id: { in: frameworkInstanceIds }, organizationId }, |
| 269 | + select: { id: true, frameworkId: true }, |
| 270 | + }); |
| 271 | + const instanceByfId = new Map(instances.map((i) => [i.id, i.frameworkId])); |
| 272 | + |
| 273 | + const requirementIds = Array.from( |
| 274 | + new Set(mappings.map((m) => m.requirementId)), |
| 275 | + ); |
| 276 | + const requirements = await db.frameworkEditorRequirement.findMany({ |
| 277 | + where: { |
| 278 | + id: { in: requirementIds }, |
| 279 | + OR: [{ organizationId: null }, { organizationId }], |
| 280 | + }, |
| 281 | + select: { id: true, frameworkId: true }, |
| 282 | + }); |
| 283 | + const reqFrameworkById = new Map( |
| 284 | + requirements.map((r) => [r.id, r.frameworkId]), |
| 285 | + ); |
| 286 | + |
| 287 | + const validMappings = mappings.filter((m) => { |
| 288 | + const instanceFwId = instanceByfId.get(m.frameworkInstanceId); |
| 289 | + const reqFwId = reqFrameworkById.get(m.requirementId); |
| 290 | + return Boolean(instanceFwId) && instanceFwId === reqFwId; |
| 291 | + }); |
| 292 | + |
| 293 | + if (validMappings.length === 0) { |
| 294 | + throw new BadRequestException('No valid requirements to link'); |
| 295 | + } |
| 296 | + |
| 297 | + await db.requirementMap.createMany({ |
| 298 | + data: validMappings.map((m) => ({ |
| 299 | + controlId, |
| 300 | + requirementId: m.requirementId, |
| 301 | + frameworkInstanceId: m.frameworkInstanceId, |
| 302 | + })), |
| 303 | + skipDuplicates: true, |
| 304 | + }); |
| 305 | + |
| 306 | + return { count: validMappings.length }; |
| 307 | + } |
| 308 | + |
196 | 309 | async delete(controlId: string, organizationId: string) { |
197 | 310 | const control = await db.control.findUnique({ |
198 | 311 | where: { |
|
0 commit comments