Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,7 @@ export class CreateService extends BaseService {
],
})

if (isNil(organization)) {
throw new Error("External group contact is missing its associated external organization")
}
if (isNil(organization)) return null

const { name } = organization
return [name]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import {
externalOrganizationFactory,
informationSharingAgreementFactory,
userFactory,
} from "@/tests/factories"

import CreateService from "@/services/information-sharing-agreements/archive-items/create-service"

describe("api/src/services/information-sharing-agreements/archive-items/create-service.ts", () => {
describe("CreateService", () => {
describe("#perform", () => {
test("when external group contact has an associated external organization, sets yukonFirstNations from it", async () => {
// Arrange
const currentUser = await userFactory.create()
const externalOrganization = await externalOrganizationFactory.create({
name: "Test External Organization",
})
const externalGroupContact = await userFactory.create({
isExternal: true,
externalOrganizationId: externalOrganization.id,
})
const informationSharingAgreement = await informationSharingAgreementFactory.create({
title: "Test Agreement",
purpose: "Test purpose",
externalGroupContactId: externalGroupContact.id,
})

// Act
const archiveItem = await CreateService.perform(
informationSharingAgreement,
{ confidentialityReceipt: true },
currentUser
)

// Assert
expect(archiveItem.yukonFirstNations).toEqual(["Test External Organization"])
})

test("when external group contact is missing its associated external organization, creates the archive item without yukonFirstNations", async () => {
// Arrange
const currentUser = await userFactory.create()
const externalOrganization = await externalOrganizationFactory.create()
const externalGroupContact = await userFactory.create({
isExternal: true,
externalOrganizationId: externalOrganization.id,
})
const informationSharingAgreement = await informationSharingAgreementFactory.create({
title: "Test Agreement",
purpose: "Test purpose",
externalGroupContactId: externalGroupContact.id,
})
await externalOrganization.destroy()

// Act
const archiveItem = await CreateService.perform(
informationSharingAgreement,
{ confidentialityReceipt: true },
currentUser
)

// Assert
expect(archiveItem.yukonFirstNations).toEqual([])
})

test("when confidentiality receipt is not true, throws an informative error", async () => {
// Arrange
const currentUser = await userFactory.create()
const informationSharingAgreement = await informationSharingAgreementFactory.create({
title: "Test Agreement",
purpose: "Test purpose",
})

// Act & Assert
await expect(
CreateService.perform(informationSharingAgreement, {}, currentUser)
).rejects.toThrow("Confidentiality receipt is required, and must be true")
})
})
})
})
15 changes: 15 additions & 0 deletions web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ Vue 3 + Vuetify 3 + TypeScript + Vite + Pinia.

---

## Knowledge Item and ISA Navigation

An information sharing agreement (ISA) and a knowledge item are separate domain records linked through the `InformationSharingAgreementArchiveItem` association. The relationship is many-to-many; neither `informationSharingAgreementId` nor `archiveItemId` identifies the association by itself.

Use the ISA-scoped routes for navigation from an ISA:

- `/sharing-agreements/:informationSharingAgreementId/knowledge-items` lists every linked knowledge item.
- `/sharing-agreements/:informationSharingAgreementId/knowledge-items/:informationSharingAgreementArchiveItemId` opens one linked item.

The detail route validates that the association belongs to the ISA in the URL before rendering the underlying knowledge item. Do not select the first association or expose an archive-item ID as the canonical ISA link.

### Model Naming Transition

The domain model is still named `InformationSharingAgreement`. This PR shortens only the user-facing route prefix to `sharing-agreements`; model, API, and route-name identifiers remain unchanged. A later model rename must migrate those identifiers deliberately rather than mixing it into this URL change.

## Open In Editor

When the frontend runs in Docker, Vue Devtools cannot launch your host editor directly from inside the container. This project handles that by:
Expand Down
Loading
Loading