Skip to content

Commit

Permalink
Merge pull request #4584 from NCI-Agency/AB-1003-1004-make-minAttendi…
Browse files Browse the repository at this point in the history
…ngAuthors-and-primaryAttendees-configurable

Make attending authors and primary attendees configurable
  • Loading branch information
midmarch authored Jan 10, 2024
2 parents 8ee284b + 62b1bf8 commit d2f0ad5
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 66 deletions.
12 changes: 8 additions & 4 deletions anet-dictionary.yml
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,14 @@ fields:
label: Location
placeholder: Search for the engagement location…
filter: [POINT_LOCATION, VIRTUAL_LOCATION]
reportPeople:
optionalAttendingAuthor: false
optionalPrimaryAdvisor: false
optionalPrimaryPrincipal: true
attendeeGroups:
- label: Linguists
filter:
orgUuid: 70193ee9-05b4-4aac-80b5-75609825db9f
customFields:
relatedReport:
type: anet_object
Expand Down Expand Up @@ -508,10 +516,6 @@ fields:
typeError: Qty must be a number
label: Qty
visibleWhen: $[?(@ && @.multipleButtons && (@.multipleButtons.indexOf('assist') != -1 || @.multipleButtons.indexOf('other') != -1))]
attendeeGroups:
- label: Linguists
filter:
orgUuid: 70193ee9-05b4-4aac-80b5-75609825db9f

person:
status:
Expand Down
79 changes: 45 additions & 34 deletions client/src/models/Report.js
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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 (
Expand All @@ -426,8 +434,11 @@ export default class Report extends Model {
}

static checkAttendingAuthor(reportPeople) {
if (!reportPeople?.some(rp => rp.author && rp.attendee)) {
return "You must provide at least 1 attending author"
const optionalAttendingAuthor =
Settings.fields.report.reportPeople?.optionalAttendingAuthor
const attendingAuthor = reportPeople?.some(rp => rp.author && rp.attendee)
if (!attendingAuthor && !optionalAttendingAuthor) {
return "You must provide at least 1 attending author(s)"
}
}

Expand Down
3 changes: 2 additions & 1 deletion client/src/pages/reports/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,8 @@ const ReportForm = ({
}

// Add attendee groups defined in the dictionary
const attendeeGroups = Settings.fields.report.attendeeGroups ?? []
const attendeeGroups =
Settings.fields.report.reportPeople?.attendeeGroups ?? []
attendeeGroups.forEach(({ label, filter: queryVars }) => {
reportPeopleFilters[label] = { label, queryVars }
})
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/mil/dds/anet/resources/ReportResource.java
Original file line number Diff line number Diff line change
Expand Up @@ -398,15 +398,26 @@ public int submitReport(@GraphQLRootContext Map<String, Object> 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());
}
Expand Down
53 changes: 34 additions & 19 deletions src/main/resources/anet-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -642,29 +642,44 @@ properties:
type: string
enum:
[VIRTUAL_LOCATION, PHYSICAL_LOCATION, GEOGRAPHICAL_AREA, POINT_LOCATION, ADVISOR_LOCATION, PRINCIPAL_LOCATION]
reportPeople:
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
attendeeGroups:
type: array
uniqueItems: true
items:
type: object
additionalProperties: false
title: Attendee-group
required: [label, filter]
properties:
label:
type: string
title: The label of the attendee group
filter:
type: object
title: Attendee group filters
properties:
orgUuid:
type: string
title: UUID of organisation membership to form
customFields:
type: object
additionalProperties:
"$ref": "#/$defs/customField"
attendeeGroups:
type: array
uniqueItems: true
items:
type: object
additionalProperties: false
title: Attendee-group
required: [label, filter]
properties:
label:
type: string
title: The label of the attendee group
filter:
type: object
title: Attendee group filters
properties:
orgUuid:
type: string
title: UUID of organisation membership to form

person:
type: object
Expand Down
12 changes: 8 additions & 4 deletions testDictionaries/no-custom-fields.yml
Original file line number Diff line number Diff line change
Expand Up @@ -363,10 +363,14 @@ fields:
label: Location
placeholder: Search for the engagement location…
filter: [POINT_LOCATION, VIRTUAL_LOCATION]
attendeeGroups:
- label: Linguists
filter:
orgUuid: 70193ee9-05b4-4aac-80b5-75609825db9f
reportPeople:
optionalAttendingAuthor: false
optionalPrimaryAdvisor: false
optionalPrimaryPrincipal: true
attendeeGroups:
- label: Linguists
filter:
orgUuid: 70193ee9-05b4-4aac-80b5-75609825db9f

person:
status:
Expand Down

0 comments on commit d2f0ad5

Please sign in to comment.