diff --git a/anet-dictionary.yml b/anet-dictionary.yml index 9011375fdf..d09cf11f51 100644 --- a/anet-dictionary.yml +++ b/anet-dictionary.yml @@ -381,6 +381,8 @@ fields: filter: [POINT_LOCATION, VIRTUAL_LOCATION] reportPeople: optionalAttendingAuthor: false + optionalPrimaryAdvisor: false + optionalPrimaryPrincipal: true customFields: relatedReport: type: anet_object diff --git a/client/src/models/Report.js b/client/src/models/Report.js index 3634780b10..be1a3b9b6c 100644 --- a/client/src/models/Report.js +++ b/client/src/models/Report.js @@ -162,20 +162,10 @@ export default class Report extends Model { .array() .nullable() .when("cancelled", ([cancelled], schema) => + // Only do validation warning when engagement not cancelled cancelled - ? schema.nullable() - : schema // Only do validation warning when engagement not cancelled - .test( - "primary-advisor", - "primary advisor error", - (reportPeople, testContext) => { - const message = Report.checkPrimaryAttendee( - reportPeople, - Person.ROLE.ADVISOR - ) - return message ? testContext.createError({ message }) : true - } - ) + ? schema + : Report.testPrimaryAttendees(schema, false) .test( "no-author", "no author error", @@ -281,20 +271,8 @@ export default class Report extends Model { .array() .nullable() .when("cancelled", ([cancelled], schema) => - cancelled - ? schema.nullable() - : schema // Only do validation warning when engagement not cancelled - .test( - "primary-principal", - "primary principal error", - (reportPeople, testContext) => { - const message = Report.checkPrimaryAttendee( - reportPeople, - Person.ROLE.PRINCIPAL - ) - return message ? testContext.createError({ message }) : true - } - ) + // Only do validation warning when engagement not cancelled + cancelled ? schema : Report.testPrimaryAttendees(schema, true) ), reportSensitiveInformation: yup.object().nullable().default({}), authorizationGroups: yup @@ -317,6 +295,36 @@ export default class Report extends Model { ) }) + static testPrimaryAttendees(schema, asWarning) { + return schema + .test( + "primary-advisor", + "primary advisor error", + (reportPeople, testContext) => { + const message = Report.checkPrimaryAttendee( + reportPeople, + Person.ROLE.ADVISOR, + Settings.fields.report.reportPeople?.optionalPrimaryAdvisor, + asWarning + ) + return message ? testContext.createError({ message }) : true + } + ) + .test( + "primary-principal", + "primary principal error", + (reportPeople, testContext) => { + const message = Report.checkPrimaryAttendee( + reportPeople, + Person.ROLE.PRINCIPAL, + Settings.fields.report.reportPeople?.optionalPrimaryPrincipal, + asWarning + ) + return message ? testContext.createError({ message }) : true + } + ) + } + static autocompleteQuery = "uuid, intent, authors { uuid, name, rank, role }" constructor(props) { @@ -404,13 +412,13 @@ export default class Report extends Model { return this.intent || "None" } - static checkPrimaryAttendee(reportPeople, role) { + static checkPrimaryAttendee(reportPeople, role, optional, asWarning) { const primaryAttendee = Report.getPrimaryAttendee(reportPeople, role) const roleName = Person.humanNameOfRole(role) - if (!primaryAttendee && role === Person.ROLE.ADVISOR) { - return `You must provide the primary ${roleName} for the Engagement` - } else if (!primaryAttendee && role === Person.ROLE.PRINCIPAL) { - return `No primary ${roleName} has been provided for the Engagement` + if (!primaryAttendee) { + if ((optional && asWarning) || (!optional && !asWarning)) { + return `No primary ${roleName} has been provided for the Engagement` + } } else if (primaryAttendee.status !== Model.STATUS.ACTIVE) { return `The primary ${roleName} - ${primaryAttendee.name} - needs to have an active profile` } else if ( diff --git a/src/main/java/mil/dds/anet/resources/ReportResource.java b/src/main/java/mil/dds/anet/resources/ReportResource.java index baf449c13d..de32db2f27 100644 --- a/src/main/java/mil/dds/anet/resources/ReportResource.java +++ b/src/main/java/mil/dds/anet/resources/ReportResource.java @@ -398,15 +398,26 @@ public int submitReport(@GraphQLRootContext Map context, if (r.getAdvisorOrgUuid() == null) { final ReportPerson advisor = r.loadPrimaryAdvisor(engine.getContext()).join(); + final Boolean optionalPrimaryAdvisor = + (Boolean) config.getDictionaryEntry("fields.report.reportPeople.optionalPrimaryAdvisor"); if (advisor == null) { - throw new WebApplicationException("Report missing primary advisor", Status.BAD_REQUEST); + if (!Boolean.TRUE.equals(optionalPrimaryAdvisor)) { + throw new WebApplicationException("Report missing primary advisor", Status.BAD_REQUEST); + } + } else { + r.setAdvisorOrg( + engine.getOrganizationForPerson(engine.getContext(), advisor.getUuid()).join()); } - r.setAdvisorOrg( - engine.getOrganizationForPerson(engine.getContext(), advisor.getUuid()).join()); } if (r.getPrincipalOrgUuid() == null) { final ReportPerson principal = r.loadPrimaryPrincipal(engine.getContext()).join(); - if (principal != null) { + final Boolean optionalPrimaryPrincipal = (Boolean) config + .getDictionaryEntry("fields.report.reportPeople.optionalPrimaryPrincipal"); + if (principal == null) { + if (!Boolean.TRUE.equals(optionalPrimaryPrincipal)) { + throw new WebApplicationException("Report missing primary principal", Status.BAD_REQUEST); + } + } else { r.setPrincipalOrg( engine.getOrganizationForPerson(engine.getContext(), principal.getUuid()).join()); } diff --git a/src/main/resources/anet-schema.yml b/src/main/resources/anet-schema.yml index 9dc754c4bd..18cf183ca7 100644 --- a/src/main/resources/anet-schema.yml +++ b/src/main/resources/anet-schema.yml @@ -641,12 +641,20 @@ properties: enum: [VIRTUAL_LOCATION, PHYSICAL_LOCATION, GEOGRAPHICAL_AREA, POINT_LOCATION, ADVISOR_LOCATION, PRINCIPAL_LOCATION] reportPeople: - required: [optionalAttendingAuthor] + required: [optionalAttendingAuthor, optionalPrimaryAdvisor, optionalPrimaryPrincipal] properties: optionalAttendingAuthor: type: boolean default: false description: Defines if having an attending author for a report is optional + optionalPrimaryAdvisor: + type: boolean + default: false + description: Defines if having a primary advisor for a report is optional + optionalPrimaryPrincipal: + type: boolean + default: false + description: Defines if having a primary principal for a report is optional customFields: type: object additionalProperties: diff --git a/testDictionaries/no-custom-fields.yml b/testDictionaries/no-custom-fields.yml index 6660e28558..06e7cb2799 100644 --- a/testDictionaries/no-custom-fields.yml +++ b/testDictionaries/no-custom-fields.yml @@ -365,6 +365,8 @@ fields: filter: [POINT_LOCATION, VIRTUAL_LOCATION] reportPeople: optionalAttendingAuthor: false + optionalPrimaryAdvisor: false + optionalPrimaryPrincipal: true attendeeGroups: - label: Linguists filter: