update error and response handling
This commit is contained in:
@@ -61,3 +61,7 @@ context/
|
||||
memory-bank/
|
||||
workflows/
|
||||
AI_CONTEXT.md
|
||||
memory-bank/activeContext.md
|
||||
memory-bank/change-log.md
|
||||
memory-bank/refactor-plan-actions-index.md
|
||||
memory-bank/progress.md
|
||||
|
||||
@@ -1,712 +0,0 @@
|
||||
# Active Context — PEDW FrontEnd
|
||||
|
||||
## Current development focus (from recent commits)
|
||||
|
||||
- API contract consistency rollout (TASK22102), starting with helper-based response normalization in selected email/admin handlers.
|
||||
- TASK22109 email API contract parity and phase21 contract coverage expansion.
|
||||
- Search/case navigation correctness, especially breadcrumb and back-link behavior.
|
||||
- My Portal "view all" and DNS application path handling.
|
||||
- Welsh/English email behavior for specific notification templates.
|
||||
- PDF output formatting and hyperlink behavior.
|
||||
|
||||
## TASK22109 completion status (2026-03-18)
|
||||
|
||||
- Branch: `TASK22109-email-api-contracts`
|
||||
- Commits:
|
||||
- `6610e5c` — email API contract cleanup + initial phase21 email coverage
|
||||
- `d17f3a1` — expanded email contract coverage and logging hygiene
|
||||
- `e9cf1cf` — mini-slice tidy + notify negative-path tests
|
||||
- Scope completed:
|
||||
- email handler cleanup/hardening in:
|
||||
- `pages/api/email/getevents.js`
|
||||
- `pages/api/email/getdocuments.js`
|
||||
- `pages/api/email/getall.js`
|
||||
- `pages/api/email/getmailinglist.js`
|
||||
- `pages/api/email/getcaseref.js`
|
||||
- `pages/api/email/notify.js`
|
||||
- expanded phase21 contract tests:
|
||||
- `tests/phase21/email-handler-contract.test.cjs`
|
||||
- `tests/phase21/api-contract-slice1.test.cjs`
|
||||
- `tests/phase21/_shared.cjs`
|
||||
- Validation snapshot:
|
||||
- `node tests/phase21/api-contract-slice1.test.cjs` -> pass
|
||||
- helper 4/4
|
||||
- file-handler 11/11
|
||||
- email-handler 12/12
|
||||
- `npm run lint` -> warnings only (pre-existing)
|
||||
|
||||
## TASK22168 endpoint slice status (2026-03-19)
|
||||
|
||||
- Branch: `TASK22168-endpoint-account-contract-consistency`
|
||||
- Scope completed (next coherent low-risk `pages/api/endpoint/**` slice):
|
||||
- `pages/api/endpoint/getaccounts_api.js`
|
||||
- `pages/api/endpoint/getemailaccountcheck_api.js`
|
||||
- `pages/api/endpoint/getpreferredlanguage_api.js`
|
||||
- `tests/phase21/endpoint-handler-contract.test.cjs`
|
||||
- `tests/phase21/api-contract-slice1.test.cjs` (runner extended)
|
||||
- Pattern applied (aligned with TASK22109):
|
||||
1. removed dead/noisy code in selected handlers (unused imports + noisy/commented debug remnants),
|
||||
2. standardized structured negative-path envelopes for missing required input and catch/failure paths,
|
||||
3. preserved success response behavior (`data` pass-through),
|
||||
4. added focused phase21 endpoint contract tests:
|
||||
- missing required input
|
||||
- catch/failure path
|
||||
- one success contract parity assertion.
|
||||
- Validation snapshot:
|
||||
- `node tests/phase21/api-contract-slice1.test.cjs` -> pass
|
||||
- helper 4/4
|
||||
- file-handler 11/11
|
||||
- email-handler 12/12
|
||||
- endpoint-handler 7/7
|
||||
- `npm run lint` -> warnings only (pre-existing react-hooks warnings)
|
||||
|
||||
- Risk/rollback snapshot:
|
||||
- risk: broader endpoint touch in one bundle could drift contracts
|
||||
- mitigation: success payloads preserved as upstream `data`; phase21 endpoint tests expanded to 18/18
|
||||
- rollback: revert `getlogin_api`, `getportallogin_api`, `getportalloginproxy_api`, `getpersonalaccount_api`, and phase21 endpoint test updates, then rerun phase21 + lint
|
||||
|
||||
## Suggested next work package
|
||||
|
||||
- Continue API contract consistency in `pages/api/endpoint/**` with the same pattern used in TASK22109:
|
||||
1. remove noisy logging/commented dead traces in selected endpoints,
|
||||
2. add/standardize structured negative-path responses where contract drift exists,
|
||||
3. add focused phase21 endpoint contract tests for missing required input + catch-path failures.
|
||||
|
||||
## Recently changed areas (high signal)
|
||||
|
||||
- `components/breadcrumbs.js`
|
||||
- `components/case/summary.js`
|
||||
- `components/search/searchresults.js`
|
||||
- `components/search/addresssearchresults.js`
|
||||
- `components/myportal/viewall.js`
|
||||
- `pages/myportal/case/[ticketnumber].js`
|
||||
- `pages/api/email/notify.js`
|
||||
- `actions/index.js`
|
||||
- `actions/core/env.js`
|
||||
- `actions/core/logger.js`
|
||||
- `actions/core/hash.js`
|
||||
- `actions/core/token.js`
|
||||
- `actions/core/headers.js`
|
||||
- `actions/services/legacyActionsService.js`
|
||||
- `i18n.js`
|
||||
|
||||
## Active concerns
|
||||
|
||||
- Breadcrumb and route-state logic is complex and query-dependent (`va`, `adv`, `ads`, `key`), so regressions are easy.
|
||||
- Locale-specific route and label behavior is still a high-risk area due to rewrite + component logic coupling.
|
||||
- Sensitive logging remains present in auth/email/actions paths and should be reduced/redacted over time.
|
||||
- Hash validation on some file endpoints appears inconsistent (some checks active, some commented), requiring careful change discipline.
|
||||
|
||||
## Refactor status update (2026-03-12)
|
||||
|
||||
- Priority 1 refactor (Phase 1) is in place:
|
||||
- `actions/index.js` now acts as a compatibility barrel.
|
||||
- Core helper concerns were extracted into `actions/core/*`.
|
||||
- Existing API/file/domain wrappers were moved into `actions/services/legacyActionsService.js` with backward-compatible exports retained via the barrel.
|
||||
- No intentional behavior changes were introduced in this phase; focus was structural risk reduction.
|
||||
- Priority 1 refactor (Phase 2) is now in place:
|
||||
- Domain service grouping modules added under `actions/services/*`.
|
||||
- `actions/services/index.js` now provides grouped service barrel exports.
|
||||
- `actions/index.js` now re-exports from `./services` and `./core/*` while preserving existing public action names.
|
||||
- `legacyActionsService` remains as a compatibility backing module and should be slimmed in later increments as consumers move to direct service imports.
|
||||
|
||||
## Refactor status update (Priority 1 execution pass — 2026-03-12)
|
||||
|
||||
- Completed an additional Priority 1 consumer-migration pass focused on high-use portal/form helpers.
|
||||
- Updated these files to use focused service/core imports instead of broad `actions` barrel imports:
|
||||
- `components/case/representation/representationElements.js`
|
||||
- `components/elements/index.js`
|
||||
- `components/utils/index.js`
|
||||
- `lib/newappeal/loadNewAppealPage.js`
|
||||
- `lib/myportal/loadMyPortalAppealPage.js`
|
||||
- `components/myportal/topthree.js`
|
||||
- `components/myportal/topthree_reps.js`
|
||||
- `components/myportal/awaitingsubmissionfromblob.js`
|
||||
- Compatibility model remains in place via `actions/index.js`; migration is incremental and non-breaking by design.
|
||||
|
||||
## Refactor status update (Priority 1 execution pass — viewall/search/unsubscribe)
|
||||
|
||||
- Completed another focused import migration pass to reduce broad `actions` barrel coupling in user-facing high-use areas:
|
||||
- `components/myportal/viewall.js`
|
||||
- `components/search/addresssearchresults.js`
|
||||
- `pages/unsubscribe/[watchlistid].js`
|
||||
- `pages/unsubscribeall/[watchlistid].js`
|
||||
- These files now use explicit imports from `actions/services/*` and `actions/core/*` modules.
|
||||
- Remaining non-comment broad `actions` imports are now primarily in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers.
|
||||
|
||||
## Refactor status update (Priority 1 execution pass — endpoint/file proxies)
|
||||
|
||||
- Completed focused import migration for selected endpoint and file proxy handlers:
|
||||
- `pages/api/endpoint/getmylpacases_api.js`
|
||||
- `pages/api/endpoint/getbasicdnssearchpaged_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchpaged_api.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/createappealcompletemessageproxy_api.js`
|
||||
- Replaced broad `../../../actions` imports with focused `actions/core/*` and service-module imports.
|
||||
- Eliminated duplicated local hash helper in `getmylpacases_api.js` by reusing shared `actions/core/hash`.
|
||||
- Current broad-import scan indicates only comment-only legacy references remain.
|
||||
|
||||
## Delivery handover status (2026-03-13)
|
||||
|
||||
- Current import-migration wave has been checked in and completed through PR.
|
||||
- This branch is now treated as the completed migration baseline.
|
||||
- Next implementation chunk should start on a **new branch** and target decomposition of `actions/services/legacyActionsService.js`.
|
||||
- Immediate focus for next branch:
|
||||
1. extract low-risk reference/search wrappers into direct service/client modules,
|
||||
2. migrate portal/document internals in small parity-checked batches,
|
||||
3. slim compatibility layer once parity is proven.
|
||||
|
||||
## Phase 5 kickoff status (2026-03-13)
|
||||
|
||||
- Branch in progress: `TASK21997-phase5-legacyactions-split`.
|
||||
- First decomposition slice completed:
|
||||
- search wrappers extracted to `actions/services/searchDirectService.js`
|
||||
- reference-data wrappers extracted to `actions/services/referenceDataDirectService.js`
|
||||
- `searchService` and `referenceDataService` now route through these direct modules.
|
||||
- `legacyActionsService` remains in place for non-migrated domains (portal/document/account/case/admin/notify/integration) pending next slices.
|
||||
|
||||
## Phase 5 status update (2026-03-13 — document slice)
|
||||
|
||||
- Added `actions/services/documentDirectService.js` and migrated `documentService.js` to route through it.
|
||||
- `legacyActionsService` now remains for:
|
||||
- portal, account, case, admin, notify, integration domains.
|
||||
- Search/reference/document grouped services now point at dedicated direct modules.
|
||||
|
||||
## Phase 5 completion status (2026-03-13)
|
||||
|
||||
- Grouped services now route through focused direct modules for all domains:
|
||||
- search, reference-data, document, portal, account, case, admin, integration, notify.
|
||||
- `actions/services/legacyActionsService.js` has been removed.
|
||||
- Current architecture baseline:
|
||||
- `actions/index.js` -> compatibility barrel re-exporting `actions/services` + core modules
|
||||
- `actions/services/*Service.js` -> grouped public service boundaries
|
||||
- `actions/services/*DirectService.js` -> implementation modules per domain
|
||||
- Validation checkpoints completed:
|
||||
- zero `legacyActionsService` imports in `actions/services/*.js`
|
||||
- lint passes with warnings only
|
||||
- build succeeds
|
||||
|
||||
## Phase 6 hardening status (2026-03-13 — in progress)
|
||||
|
||||
- Working branch: `TASK21998-phase6-postphase5-hardening` (created from `SIPS-Development`).
|
||||
- Main hardening actions completed so far:
|
||||
- Added focused parity test harness:
|
||||
- `tests/phase6/service-parity.test.cjs`
|
||||
- verifies grouped service import/export parity and `actions/services/index.js` re-export stability.
|
||||
- Added shared error-path helper:
|
||||
- `actions/services/httpServiceUtils.js`
|
||||
- consolidates repeated `consoleLogger + error.response` and `ErrResponse` generation patterns.
|
||||
- Applied safe duplication reduction in:
|
||||
- `searchDirectService.js`
|
||||
- `referenceDataDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- Logging cleanup for sensitive/noisy service paths (removed debug `console.log` usage) in:
|
||||
- `searchDirectService.js`
|
||||
- `documentDirectService.js`
|
||||
- `portalDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
|
||||
### Current validation evidence
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `npm run lint` -> warnings only
|
||||
- Targeted local smoke snapshots:
|
||||
- `GET /advancedsearch` and `GET /cy/advancedsearch` -> 200
|
||||
- `GET /case` and `GET /cy/case` -> 200
|
||||
- `GET /myportal` and `GET /cy/myportal` -> 307 redirect to `/auth/signin` (unauthenticated negative path)
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400 (negative path)
|
||||
- `POST /api/email/notify` with empty payload -> 400 (negative path)
|
||||
|
||||
### Active caveat
|
||||
|
||||
- `GET /searchresults` and `GET /cy/searchresults` return 500 in current local dev run due pre-existing SSR serialization issue:
|
||||
- `initialState.search.searchString` is undefined in `getServerSideProps` payload.
|
||||
- captured in `/tmp/phase6-dev.log`.
|
||||
|
||||
## Phase 7 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK21988a-phase7-postphase6-hardening`
|
||||
- Pre-existing search results SSR serialization issue now addressed:
|
||||
- `pages/searchresults.js`
|
||||
- changed `setSearch(query.q)` to `setSearch(query?.q || "")` in `getServerSideProps`.
|
||||
- local smoke result: both `/searchresults` and `/cy/searchresults` return 200 in this run.
|
||||
- Behavioural test expansion delivered for remaining service domains:
|
||||
- `tests/phase7/service-behaviour.test.cjs`
|
||||
- covers document, portal, account, notify, integration.
|
||||
|
||||
### Phase 7 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `npm run lint` -> warnings only (existing react-hooks dependency warnings; no new lint errors)
|
||||
|
||||
### Phase 7 smoke/negative-path snapshot
|
||||
|
||||
- Dev server auto-bound to `localhost:3001` (3000 already in use).
|
||||
- `GET /searchresults`, `GET /cy/searchresults` -> 200
|
||||
- `GET /case`, `GET /cy/case` -> 200
|
||||
- `GET /myportal`, `GET /cy/myportal` -> 307 redirect to `/auth/signin`
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> 400
|
||||
- `POST /api/email/notify` with `{}` -> 400
|
||||
|
||||
### Testing strategy decision (captured)
|
||||
|
||||
- Current phase includes **both**:
|
||||
1. migration/parity guard tests,
|
||||
2. focused behavioural unit tests for critical response/error contracts.
|
||||
- Broader behavioural coverage remains a follow-on expansion item after this focused baseline.
|
||||
|
||||
## Phase 8 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK22017-phase8-hardening-slice`
|
||||
- Sensitive API hardening slice completed across:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- Hash/integrity posture updates:
|
||||
- re-enabled hash validation on previously bypassed/commented file handlers
|
||||
- added standardized early 400 handling for missing/invalid hash and missing key params
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed noisy direct `console.log` usage in `createappealcompletemessage_api`
|
||||
- routed error paths through `consoleLogger` in updated sensitive flow
|
||||
- Required consumer parity updates applied:
|
||||
- `actions/services/documentDirectService.js`
|
||||
- now appends hash for `deleteblobcase` and `deleteblobrep` calls
|
||||
- `actions/services/portalDirectService.js`
|
||||
- now appends hash for `createappealcompletemessage_api` call using existing hash path contract
|
||||
|
||||
### Phase 8 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 8 manual HTTP snapshot
|
||||
|
||||
- Dev server on `http://localhost:3001`.
|
||||
- Negative-path checks for invalid/missing hash (and missing required params where relevant) return **400** across all 4 target handlers.
|
||||
- Valid-hash spot-check for `getportallogin_api` reached hash-validated path but still returned **400** due local upstream relay/CRM dependency behavior.
|
||||
|
||||
## Phase 9 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/createrepcompletemessage_api.js`
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- Hash/integrity posture updates:
|
||||
- re-enabled/enforced hash checks in handlers where hash validation was bypassed/commented
|
||||
- standardized early 400 handling for missing/invalid hash and missing key query/body values
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed noisy `console.log` traces from sensitive upload/rep-complete message paths
|
||||
- retained centralized error logging via `consoleLogger` where present
|
||||
- Required caller parity updates applied:
|
||||
- `actions/services/portalDirectService.js`
|
||||
- `sendRepCompleteMessage` now appends hash
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `uploadFiles`, `uploadRepFiles`, `uploadSingleFile` now append hash
|
||||
|
||||
### Phase 9 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 9 manual HTTP snapshot
|
||||
|
||||
- Negative-path checks for missing/invalid hash and invalid/missing key params on all 4 phase-9 handlers return **400** on local server (`localhost:3000`).
|
||||
- Valid-hash happy-path spot-check completed using `.env.local` hash key:
|
||||
- `POST /api/file/uploadsinglefile?hash=<valid>` -> **200**
|
||||
|
||||
## Phase 10 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/getawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query inputs and hash
|
||||
- standardized early hash-mismatch 400 behaviour in all 4 handlers
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed old commented debug traces in touched handlers
|
||||
- Caller parity:
|
||||
- no additional service-layer updates required in this slice; existing direct services already append hash for these APIs.
|
||||
|
||||
### Phase 10 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 10 manual HTTP snapshot
|
||||
|
||||
- Missing-hash negative-path checks for all 4 handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `getbloblist` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 11 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query inputs and hash
|
||||
- standardized early hash-mismatch 400 behaviour in all touched handlers
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed old commented debug traces in touched handlers
|
||||
- Caller parity:
|
||||
- no additional service-layer updates required in this slice.
|
||||
|
||||
### Phase 11 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 11 manual HTTP snapshot
|
||||
|
||||
- Missing/invalid-hash negative-path checks for selected handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `getbloblist` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 12 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/downloadblob.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query inputs
|
||||
- standardized early hash-mismatch 400 behaviour in `downloadblob`
|
||||
- preserved response-shape contracts and function signatures
|
||||
|
||||
### Phase 12 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 12 manual HTTP snapshot
|
||||
|
||||
- Missing/invalid-input negative-path checks for selected handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `downloadblob` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 13 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Additional sensitive API hardening slice completed across:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createcaseinvolvement_api.js`
|
||||
- `pages/api/file/createrepinvolvement_api.js`
|
||||
- Hash/integrity posture updates:
|
||||
- explicit early 400 guards for missing/empty required query/body inputs
|
||||
- standardized early hash-mismatch 400 behaviour in delete-blob handlers
|
||||
- preserved response-shape contracts and function signatures
|
||||
- Logging discipline updates:
|
||||
- removed noisy direct body/query logging from involvement handlers
|
||||
|
||||
### Phase 13 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7)
|
||||
- `npm run lint` -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
### Phase 13 manual HTTP snapshot
|
||||
|
||||
- Missing/invalid-input negative-path checks for selected handlers return **400** (`localhost:3000`).
|
||||
- Valid-hash spot-check result:
|
||||
- `deleteblobcase` returned **500** with valid hash in local environment (consistent with downstream/local dependency constraints; hash gate passed).
|
||||
|
||||
## Phase 14 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Addressed browser runtime error in authenticated new-appeal journey:
|
||||
- `TypeError` in `hashAPIPath` caused by client-side code attempting to parse server-only `HASHKEY`.
|
||||
- Implemented server-side hash signing bridge for browser callers:
|
||||
- new endpoint `pages/api/endpoint/gethash_api.js`
|
||||
- session-gated (`getSession`), allow-listed supported API prefixes, returns `{ hash }`.
|
||||
- Updated direct service callers to use signer endpoint instead of direct client hash computation:
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- Maintained contract compatibility for target file APIs and existing response shapes.
|
||||
|
||||
### Phase 14 validation evidence snapshot
|
||||
|
||||
- phase6 parity/behaviour tests -> pass
|
||||
- phase7/8/9/10/11/12/13 behaviour tests -> pass
|
||||
- phase14 behaviour tests -> pass (4/4)
|
||||
- lint -> warnings only (pre-existing hook dependency warnings)
|
||||
|
||||
## Phase 14 closeout follow-up status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Browser-safe hash signing expanded for portal login flow:
|
||||
- `actions/services/accountDirectService.js`
|
||||
- `getPortalLogin` now requests signed hash from `/api/endpoint/gethash_api`
|
||||
- server fallback retained for non-browser contexts when `HASHKEY` is present
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- allow-list now includes `/api/endpoint/getportallogin_api`
|
||||
- Contract alignment + runtime fix updates:
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- removed hard requirement for `casefolderID` to match actual route contract (`container + hash`)
|
||||
- `components/elements/index.js`
|
||||
- restored missing `updateLinks` import required by Quill-related runtime path
|
||||
|
||||
### Follow-up validation evidence
|
||||
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- full previously-run phase6–phase14 suite remains passing
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` set)
|
||||
|
||||
### Active risk posture after follow-up
|
||||
|
||||
- Signer endpoint scope remains controlled by strict allow-list (single new path added).
|
||||
- Response-shape contract stability preserved for touched handlers/services.
|
||||
- Remaining risk is primarily external dependency behavior on valid-hash happy paths in local environments (relay/storage), not hash-bypass behavior.
|
||||
|
||||
## Phase 15 hardening status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK22028-phase15-hardening-slice`
|
||||
- Delivered consistency-only hardening across 4 additional sensitive file handlers:
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- Hardening posture updates:
|
||||
- standardized explicit early 400 on missing hash where validation was already required
|
||||
- standardized early hash-mismatch return path style in `setupcontainer`
|
||||
- preserved response-shape/signature contracts (no intended contract changes)
|
||||
- Added focused phase-15 tests:
|
||||
- `tests/phase15/service-behaviour.test.cjs`
|
||||
- negative-path checks for missing/invalid hash across all selected handlers
|
||||
- required-input negative-path checks where applicable
|
||||
- one valid-hash mocked happy-path check (`setupcontainer` response shape)
|
||||
|
||||
### Phase 15 validation evidence snapshot
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> pass
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> pass (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> pass (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> pass (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> pass (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `node tests/phase15/service-behaviour.test.cjs` -> pass (5/5)
|
||||
- `npm run lint` -> warnings only (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
### Phase 15 manual HTTP snapshot
|
||||
|
||||
- Dev server run on `http://localhost:3002`.
|
||||
- Missing/invalid hash negative-path checks for selected handlers -> **400**.
|
||||
- Missing required params where applicable -> **400**.
|
||||
- Valid-hash spot-check:
|
||||
- `GET /api/file/setupcontainer?ident=c1&hash=<valid>` -> **200**.
|
||||
|
||||
## Phase 16 hardening status (2026-03-13)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22028-phase15-hardening-slice`
|
||||
- Added a consistency-only file-proxy hardening slice across:
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- Changes focused on:
|
||||
- standardized required-input guards via `hasValue`
|
||||
- removed unused imports/dead constants from touched proxy handlers
|
||||
- preserved existing response contracts and status semantics
|
||||
- Added focused test pack:
|
||||
- `tests/phase16/service-behaviour.test.cjs`
|
||||
|
||||
### Phase 16 validation evidence snapshot
|
||||
|
||||
- phase6 parity + phase6–phase15 behavioural suites: pass
|
||||
- phase16 behavioural suite: pass (4/4)
|
||||
- lint: warnings only (pre-existing)
|
||||
|
||||
## Follow-up status (2026-03-13)
|
||||
|
||||
- Applied targeted signer allow-list fix for browser delete-awaiting-submission path.
|
||||
- Updated `pages/api/endpoint/gethash_api.js` allow-list with:
|
||||
- `/api/file/deleteblobcase`
|
||||
- Added focused behavioural test:
|
||||
- `tests/phase14/service-behaviour.test.cjs` now includes allow-list coverage for deleteblobcase path.
|
||||
|
||||
## Follow-up status (2026-03-13 — additional delete flows)
|
||||
|
||||
- Expanded signer allow-list for additional browser delete paths:
|
||||
- `/api/endpoint/deletemyrepresentations_api`
|
||||
- `/api/endpoint/deletewatchedcases_api`
|
||||
- `/api/file/deleteblobrep`
|
||||
- Migrated affected direct-service delete calls to signer-based hash retrieval:
|
||||
- `portalDirectService.deleteWatchedCases`
|
||||
- `portalDirectService.deleteMyRepresentations`
|
||||
- `documentDirectService.deleteAwaitingSubmissionsFromBlob`
|
||||
- `documentDirectService.deleteMyRepresentationsFromBlob`
|
||||
|
||||
## Follow-up status (2026-03-13 — myportal + i18n alignment)
|
||||
|
||||
- Updated myportal representation delete call sites to pass `caseRef`:
|
||||
- `components/myportal/topthree_reps.js`
|
||||
- `components/myportal/viewall.js`
|
||||
- Applied small view-all presentation cleanup and watched-case refresh filtering adjustment.
|
||||
- Added missing `myportal` namespace mapping in `i18n.js` for `/newappeal/[appealtypes]`.
|
||||
|
||||
## Phase 17 closeout status (2026-03-13)
|
||||
|
||||
- Working branch created from `origin/SIPS-Development`:
|
||||
- `TASK22057-phase17-hardening-closeout`
|
||||
- Completed remaining closeout hardening slice for sensitive file handlers:
|
||||
- `pages/api/file/generatepdf.js`
|
||||
- `pages/api/file/generateappealpdf.js`
|
||||
- `pages/api/file/createappealcompletemessageproxy_api.js`
|
||||
- Applied consistency-only updates:
|
||||
- standardized missing/invalid hash 400 negative paths in selected PDF handlers
|
||||
- standardized required-input 400 guards where route contract requires it
|
||||
- removed noisy direct logs from touched sensitive handlers
|
||||
- preserved existing response shapes/signatures
|
||||
- Added focused behavioural coverage:
|
||||
- `tests/phase17/service-behaviour.test.cjs` (6/6 passing)
|
||||
- includes missing/invalid hash negative-path checks and valid-input proxy happy-path contract check
|
||||
- Broader consistency scan note:
|
||||
- no additional broad hash/400 consistency gaps were identified in `pages/api/endpoint/**` in this pass.
|
||||
|
||||
## Phase 18 additional consolidation slices (2026-03-14)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22057-phase17-hardening-closeout`
|
||||
- Completed all three requested additional slices:
|
||||
1. endpoint logging/input hygiene
|
||||
2. file hash-guard flow consistency
|
||||
3. create/update input-guard + logging hygiene
|
||||
- Touched handlers:
|
||||
- `pages/api/endpoint/deletewatchedcases_api.js`
|
||||
- `pages/api/endpoint/getaccounts_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchpaged_api.js`
|
||||
- `pages/api/endpoint/getappealpdfdocuments_api.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/createcase_api.js`
|
||||
- `pages/api/file/updatecase_api.js`
|
||||
- `pages/api/file/editRepJson.js`
|
||||
- Outcome:
|
||||
- consistent early 400 guard behavior for missing/invalid required inputs/hash in selected handlers
|
||||
- noisy direct logs removed in touched sensitive flows
|
||||
- no response-shape/signature contract changes intended
|
||||
- Added focused test pack:
|
||||
- `tests/phase18/service-behaviour.test.cjs` (8/8 pass)
|
||||
|
||||
## Phase 19 endpoint consistency slice (2026-03-14)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22057-phase17-hardening-closeout`
|
||||
- Applied a small consistency-only slice across:
|
||||
- `pages/api/endpoint/createwatchedcases_api.js`
|
||||
- `pages/api/endpoint/getappealtypes_api.js`
|
||||
- `pages/api/endpoint/getdnslist_api.js`
|
||||
- Scope:
|
||||
- standardized missing/malformed required `@odata.bind` handling in `createwatchedcases_api` with early 400
|
||||
- removed noisy query logging in appeal-types and dns-list endpoint handlers
|
||||
- preserved response shapes/signatures
|
||||
- Added focused test file:
|
||||
- `tests/phase19/service-behaviour.test.cjs` (5/5 pass)
|
||||
|
||||
## Phase 20 endpoint consistency slice (2026-03-14)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22057-phase17-hardening-closeout`
|
||||
- Applied a small consistency-only slice across:
|
||||
- `pages/api/endpoint/getbasicdnssearch_api.js`
|
||||
- `pages/api/endpoint/getbasicdnsurlsearch_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchdetailspaged_api.js`
|
||||
- Scope:
|
||||
- removed noisy query logging in `getbasicdnssearch_api`
|
||||
- added early 400 for missing/empty `searchString` in `getbasicdnsurlsearch_api`
|
||||
- added early 400 for missing required params in `getbasicsearchdetailspaged_api`
|
||||
- preserved response shapes/signatures
|
||||
- Added focused test file:
|
||||
- `tests/phase20/service-behaviour.test.cjs` (5/5 pass)
|
||||
|
||||
## Likely next steps
|
||||
|
||||
1. Stabilize and simplify breadcrumb/back-link decision logic with focused regression checks.
|
||||
2. Standardize hash-check enforcement patterns across file and endpoint APIs.
|
||||
3. Reduce verbose logging in sensitive flows (auth/email/file/account).
|
||||
4. Expand automated tests for navigation and representation eligibility edge-cases (currently minimal `tests/`).
|
||||
|
||||
See `memory-bank/refactor-backlog.md` for the prioritized refactor plan and sequencing.
|
||||
Priority 1 detailed execution plan is documented in `memory-bank/refactor-plan-actions-index.md`.
|
||||
|
||||
## Areas currently important for contributors
|
||||
|
||||
- `components/breadcrumbs.js`
|
||||
- `components/case/summary.js`
|
||||
- `pages/api/endpoint/**`
|
||||
- `pages/api/file/**`
|
||||
- `pages/api/auth/[...nextauth].js`
|
||||
- `pages/api/email/notify.js`
|
||||
- `next.config.js`, `i18n.js`, `locales/**`
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,955 +0,0 @@
|
||||
# Progress — PEDW FrontEnd
|
||||
|
||||
## Completed / evidenced milestones
|
||||
|
||||
- Bilingual routing structure is established with extensive Welsh rewrites and locale namespace mapping.
|
||||
- Next-auth + Prisma SQL Server persistence is integrated for user/session lifecycle.
|
||||
- Broad API surface exists for search, case, portal, admin, and file/document operations.
|
||||
- CRM/relay hash pattern is implemented across many endpoint handlers.
|
||||
- Recent shipped updates focused on:
|
||||
- search/case back-navigation and breadcrumb behavior,
|
||||
- DNS/view-all navigation logic,
|
||||
- preferred-language handling for notify template selection,
|
||||
- PDF formatting/hyperlink fixes,
|
||||
- upload validation character updates.
|
||||
|
||||
## Work in progress signals
|
||||
|
||||
- Ongoing iterative fixes in breadcrumb/case-summary flows suggest navigation consistency is still being tuned.
|
||||
- Mixed proxy/non-proxy endpoint implementations continue to evolve in parallel.
|
||||
- Priority 1 refactor plan execution started for `actions/index.js` split (Phase 1 foundation complete).
|
||||
|
||||
## Planned / partially implemented (inferred from code state)
|
||||
|
||||
- Partial migration or coexistence of deployment/runtime patterns (Next runtime plus custom server artifacts).
|
||||
- Continued refinement of document/email workflow behavior (template/language and formatting quality).
|
||||
- Prioritized structural refactor backlog documented in `memory-bank/refactor-backlog.md`.
|
||||
|
||||
## Known technical debt
|
||||
|
||||
- `actions/services/legacyActionsService.js` still holds broad domain wrappers after Phase 1 extraction (core helpers now separated).
|
||||
- Significant duplication of token/hash/relay logic across endpoint files.
|
||||
- Inconsistent security/hash guard enforcement in some file routes.
|
||||
- Sparse automated test coverage (`tests/` currently empty).
|
||||
- Verbose logging in sensitive flows (auth/email/actions/file) increases privacy risk.
|
||||
|
||||
## Latest update (2026-03-12)
|
||||
|
||||
- Branch `0000-update-actions-monolith` created from development branch for Priority 1 refactor implementation.
|
||||
- `actions/index.js` reduced to a compatibility barrel.
|
||||
- New core helper modules added under `actions/core/`:
|
||||
- `env.js`
|
||||
- `logger.js`
|
||||
- `hash.js`
|
||||
- `token.js`
|
||||
- `headers.js`
|
||||
- Existing action wrappers moved to `actions/services/legacyActionsService.js` and continue to be exported via the barrel for compatibility.
|
||||
- `actions/clients/` scaffolded for upcoming client extraction phase.
|
||||
- Phase 2 service grouping completed with dedicated service files and `actions/services/index.js` barrel.
|
||||
- Export parity check confirms grouped service modules cover all legacy exported action names.
|
||||
- Phase 3 migration started by moving selected high-churn consumers and representative endpoint handlers to direct `actions/services/*` and `actions/core/*` imports.
|
||||
- Phase 4 hardening baseline added with new guard helpers and redacted logging, adopted in selected notify/login/contact API handlers.
|
||||
- Additional Priority 1 consumer migration pass completed for high-use portal/form/representation helpers:
|
||||
- Updated direct service/core imports in:
|
||||
- `components/admin/tabs/documents.js`
|
||||
- `components/admin/tabs/storage.js`
|
||||
- `components/admin/utils/serverside.js`
|
||||
- `components/case/documents.js`
|
||||
- `components/case/representation/representationComplete.js`
|
||||
- `components/case/representation/representationElements.js`
|
||||
- `components/elements/index.js`
|
||||
- `components/myportal/awaitingsubmissionfromblob.js`
|
||||
- `components/myportal/topthree.js`
|
||||
- `components/myportal/topthree_reps.js`
|
||||
- `components/utils/index.js`
|
||||
- `lib/myportal/loadMyPortalAppealPage.js`
|
||||
- `lib/newappeal/loadNewAppealPage.js`
|
||||
- Additional Priority 1 consumer migration pass completed for view-all/search/unsubscribe flows:
|
||||
- Updated direct service/core imports in:
|
||||
- `components/myportal/viewall.js`
|
||||
- `components/search/addresssearchresults.js`
|
||||
- `pages/unsubscribe/[watchlistid].js`
|
||||
- `pages/unsubscribeall/[watchlistid].js`
|
||||
- Broad `actions` barrel import count reduced again; remaining non-comment usages are now concentrated in selected `pages/api/endpoint/*` and `pages/api/file/*` handlers.
|
||||
- Additional Priority 1 endpoint/file proxy migration chunk completed:
|
||||
- Updated imports in:
|
||||
- `pages/api/endpoint/getmylpacases_api.js`
|
||||
- `pages/api/endpoint/getbasicdnssearchpaged_api.js`
|
||||
- `pages/api/endpoint/getsearchdocumentdetailspaged_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchpaged_api.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/createappealcompletemessageproxy_api.js`
|
||||
- Migrated from broad `../../../actions` imports to focused `actions/core/*` + service imports.
|
||||
- Removed duplicated local hash helper in `getmylpacases_api.js` and reused `actions/core/hash`.
|
||||
- Broad `actions` import scan now reports only comment-only references (no active broad imports in `.js` files).
|
||||
- Lint check re-run outcome unchanged: `next lint` fails due legacy/unsupported ESLint options in repo tooling config (not introduced by this refactor pass).
|
||||
|
||||
## Handover update (2026-03-13)
|
||||
|
||||
- Priority 1 import-migration wave has been checked in and completed via pull request.
|
||||
- Recent migration commits captured in this wave:
|
||||
- `f0202bb`
|
||||
- `fa98535`
|
||||
- `bef8f25`
|
||||
- Active broad `.../actions` imports are now eliminated from live `.js` code paths.
|
||||
- Next refactor phase will begin on a **new branch** and focus on splitting `actions/services/legacyActionsService.js` into smaller direct implementation modules.
|
||||
- Recommended decomposition order for the new branch:
|
||||
1. reference/search extraction
|
||||
2. portal/document extraction
|
||||
3. compatibility layer slimming + dead wrapper removal
|
||||
|
||||
## Latest update (2026-03-13 — Phase 5 kickoff)
|
||||
|
||||
- New branch created from `SIPS-Development`: `TASK21997-phase5-legacyactions-split`.
|
||||
- Completed first Phase 5 decomposition slice from `legacyActionsService`:
|
||||
- Added `actions/services/searchDirectService.js`
|
||||
- Added `actions/services/referenceDataDirectService.js`
|
||||
- Updated `actions/services/searchService.js` to source from `searchDirectService`
|
||||
- Updated `actions/services/referenceDataService.js` to source from `referenceDataDirectService`
|
||||
- Compatibility approach preserved: public grouped service exports and function signatures remain unchanged for callers.
|
||||
- Validation status unchanged:
|
||||
- `npm run lint` still fails due pre-existing Next/ESLint option incompatibility in repo tooling configuration.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 5 document slice)
|
||||
|
||||
- Continued on branch `TASK21997-phase5-legacyactions-split`.
|
||||
- Completed second decomposition slice from `legacyActionsService`:
|
||||
- Added `actions/services/documentDirectService.js`
|
||||
- Updated `actions/services/documentService.js` to source from `documentDirectService`
|
||||
- Compatibility approach preserved:
|
||||
- grouped service export names/signatures unchanged for consumers.
|
||||
- Verification:
|
||||
- service import scan now shows remaining legacy-backed grouped modules are:
|
||||
- `portalService`, `accountService`, `caseService`, `adminService`, `notifyService`, `integrationService`
|
||||
- `npm run lint` passes with warnings only (no blocking errors).
|
||||
|
||||
## Latest update (2026-03-13 — Phase 5 completion)
|
||||
|
||||
- Continued decomposition and completed all remaining slices on `TASK21997-phase5-legacyactions-split`:
|
||||
- portal direct extraction
|
||||
- account + case direct extraction
|
||||
- admin + integration + notify direct extraction
|
||||
- legacy cleanup/removal
|
||||
- New direct modules now in place:
|
||||
- `portalDirectService.js`
|
||||
- `accountDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- `integrationDirectService.js`
|
||||
- `notifyDirectService.js`
|
||||
- `actions/services/legacyActionsService.js` removed after import parity checks.
|
||||
- Validation evidence:
|
||||
- `actions/services` import scan: zero `./legacyActionsService` references
|
||||
- `npm run lint`: warnings only, no blocking errors
|
||||
- `npm run build`: successful production build
|
||||
|
||||
## Latest update (2026-03-13 — Phase 6 post-Phase-5 hardening, in progress)
|
||||
|
||||
- Branch created from `SIPS-Development`: `TASK21998-phase6-postphase5-hardening`.
|
||||
- Added focused parity checks for grouped/direct service stability and service index barrel stability:
|
||||
- `tests/phase6/service-parity.test.cjs`
|
||||
- validates grouped service import/export parity across:
|
||||
- search, referenceData, document, portal, account, case, admin, integration, notify
|
||||
- validates `actions/services/index.js` export list stability/order.
|
||||
- Added shared service error helper:
|
||||
- `actions/services/httpServiceUtils.js`
|
||||
- centralizes common `consoleLogger + return error.response` and `ErrResponse` shape patterns.
|
||||
- Applied low-risk duplication reduction in direct services (no signature/shape changes intended):
|
||||
- `searchDirectService.js`
|
||||
- `referenceDataDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
- Logging cleanup/redaction-oriented hardening (sensitive-flow noisy logs removed):
|
||||
- removed debug `console.log` statements from:
|
||||
- `searchDirectService.js`
|
||||
- `documentDirectService.js`
|
||||
- `portalDirectService.js`
|
||||
- `caseDirectService.js`
|
||||
- `adminDirectService.js`
|
||||
|
||||
### Validation snapshot (Phase 6)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `npm run lint` -> **warnings only** (same pre-existing warnings)
|
||||
|
||||
### Decision captured (Phase 6)
|
||||
|
||||
- Agreed approach: keep parity guard tests **and** add focused behavioural unit tests in the current refactor stream (instead of deferring all behavioural checks to long-term roadmap).
|
||||
- Implemented now:
|
||||
- `tests/phase6/service-behaviour.test.cjs`
|
||||
- mocked-axios behavioural checks for critical success/error contracts across search/reference/case/admin direct services.
|
||||
- Wider behavioural expansion remains on roadmap for additional domains/functions.
|
||||
|
||||
### Targeted smoke snapshot (local dev server)
|
||||
|
||||
- Search flow:
|
||||
- `GET /searchresults` (EN/CY) -> **500** in local env due existing serialization issue (`initialState.search.searchString` undefined in SSR payload), observed in `/tmp/phase6-dev.log`.
|
||||
- `GET /advancedsearch` and `GET /cy/advancedsearch` -> **200**
|
||||
- Case flow:
|
||||
- `GET /case` and `GET /cy/case` -> **200**
|
||||
- My Portal flow (negative-path):
|
||||
- `GET /myportal` and `GET /cy/myportal` -> **307** redirect to `/auth/signin` (expected unauthenticated behavior)
|
||||
- Document flow (negative-path):
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> **400**
|
||||
- Notify flow (negative-path):
|
||||
- `POST /api/email/notify` with `{}` -> **400**
|
||||
|
||||
## Latest update (2026-03-13 — Phase 8 hardening slice)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with work item prefix:
|
||||
- `TASK22017-phase8-hardening-slice`
|
||||
- Hardened four sensitive API handlers with minimal reversible guards:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- Scope delivered:
|
||||
- re-enabled/enforced hash checks where bypassed/commented
|
||||
- standardized early 400 negative paths for missing/invalid required query inputs
|
||||
- reduced noisy sensitive-path logging and routed errors through `consoleLogger`
|
||||
- preserved function signatures and existing response-shape contracts
|
||||
- Consumer parity updates (required to preserve behaviour after hash enforcement):
|
||||
- `actions/services/documentDirectService.js`
|
||||
- append hash for delete-blob-case/delete-blob-rep calls
|
||||
- `actions/services/portalDirectService.js`
|
||||
- append hash for create-appeal-complete-message call (hash path preserved to existing API contract)
|
||||
- Added focused tests:
|
||||
- `tests/phase8/service-behaviour.test.cjs`
|
||||
- covers negative paths for all 4 handlers (missing/invalid hash and missing key params as applicable)
|
||||
- includes one happy-path check for `getportallogin_api` with valid hash via mocked dependencies
|
||||
|
||||
### Validation snapshot (Phase 8)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks dependency warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 8)
|
||||
|
||||
- Local dev server on `http://localhost:3001`.
|
||||
- Negative-path checks:
|
||||
- `GET /api/file/deleteblobcase?...` missing hash -> **400**
|
||||
- `GET /api/file/deleteblobcase?...&hash=bad` -> **400**
|
||||
- `GET /api/file/deleteblobrep?...` missing hash -> **400**
|
||||
- `GET /api/file/deleteblobrep?...&hash=bad` -> **400**
|
||||
- `GET /api/file/deleteblobrep?...` missing `repfile` -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?...` missing hash -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?...&hash=bad` -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?...` missing `tempcaseref` -> **400**
|
||||
- `GET /api/endpoint/getportallogin_api?...` missing hash -> **400**
|
||||
- `GET /api/endpoint/getportallogin_api?...&hash=bad` -> **400**
|
||||
- `GET /api/endpoint/getportallogin_api?...` missing `emailAddress` -> **400**
|
||||
- Valid-hash spot-check:
|
||||
- `GET /api/endpoint/getportallogin_api?...&hash=<valid>` reached handler with valid hash but returned **400** from upstream relay/CRM call in local environment (expected environmental dependency risk, not hash-guard bypass).
|
||||
|
||||
## Latest update (2026-03-13 — Phase 9 hardening slice)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with work item prefix:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive file handlers with minimal reversible changes:
|
||||
- `pages/api/file/createrepcompletemessage_api.js`
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- Scope delivered:
|
||||
- re-enabled/enforced hash validation where bypassed/commented
|
||||
- added/standardized early 400 negative paths for missing/invalid hash and missing key parameters
|
||||
- reduced noisy logging in sensitive file-upload/message paths
|
||||
- preserved handler signatures and external response-shape contracts
|
||||
- Consumer parity updates:
|
||||
- `actions/services/portalDirectService.js`
|
||||
- append hash for `createrepcompletemessage_api` call
|
||||
- `actions/services/documentDirectService.js`
|
||||
- append hash for `upload` and `uploadsinglefile` calls
|
||||
- Added focused tests:
|
||||
- `tests/phase9/service-behaviour.test.cjs`
|
||||
- covers negative paths across all 4 phase-9 handlers
|
||||
|
||||
### Validation snapshot (Phase 9)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 9)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/createrepcompletemessage_api?...` missing hash -> **400**
|
||||
- `GET /api/file/createrepcompletemessage_api?...&hash=bad` -> **400**
|
||||
- `POST /api/file/upload` missing hash -> **400**
|
||||
- `POST /api/file/upload?hash=bad` -> **400**
|
||||
- `POST /api/file/uploadsinglefile` missing hash -> **400**
|
||||
- `POST /api/file/uploadsinglefile?hash=bad` -> **400**
|
||||
- `GET /api/file/setupcontainer?ident=...` missing hash -> **400**
|
||||
- `GET /api/file/setupcontainer?ident=...&hash=bad` -> **400**
|
||||
- `GET /api/file/setupcontainer?hash=bad` (missing ident) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- Completed using `.env.local` runtime key: `POST /api/file/uploadsinglefile?hash=<valid>` -> **200**
|
||||
|
||||
### Rollback plan (Phase 9)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Revert direct-service hash append changes in `documentDirectService` and `portalDirectService`.
|
||||
3. Remove `tests/phase9/service-behaviour.test.cjs` if full slice rollback required.
|
||||
4. Re-run phase6/7/8/9 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 10 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive file handlers with minimal reversible changes:
|
||||
- `pages/api/file/getawaitingsubmissionfromblob.js`
|
||||
- `pages/api/file/getprogressobjblob.js`
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required inputs (`container`, `casefolderID` where applicable, `hash`)
|
||||
- standardized hash-mismatch negative-path checks to early return 400
|
||||
- removed legacy/noisy commented debug blocks from touched handlers
|
||||
- preserved existing handler signatures and response-shape contracts
|
||||
- Caller parity impact:
|
||||
- no new caller changes required in this slice because direct-service consumers already append hash for these APIs.
|
||||
- Added focused tests:
|
||||
- `tests/phase10/service-behaviour.test.cjs`
|
||||
- covers negative paths for all 4 selected phase-10 handlers
|
||||
- includes one valid-hash contract-preserving happy-path check (`getbloblist` via mocked dependencies)
|
||||
|
||||
### Validation snapshot (Phase 10)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 10)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/getawaitingsubmissionfromblob?container=test` (missing hash) -> **400**
|
||||
- `GET /api/file/getprogressobjblob?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/getrepsblob?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 10)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Remove `tests/phase10/service-behaviour.test.cjs` if full phase-10 rollback required.
|
||||
3. Re-run phase6/7/8/9/10 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 11 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened three additional sensitive file handlers with minimal reversible changes:
|
||||
- `pages/api/file/getbloblist.js`
|
||||
- `pages/api/file/deleteblob.js`
|
||||
- `pages/api/file/deleteawaitingsubmissionfromblob.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required query inputs (`container`, `casefolderID`, `blobname`, `hash` as applicable)
|
||||
- standardized hash-mismatch negative-path checks to early return 400
|
||||
- removed legacy/noisy commented debug traces in touched handlers
|
||||
- preserved existing handler signatures and response-shape contracts
|
||||
- Caller parity impact:
|
||||
- no new caller changes required in this slice; direct-service consumers already pass expected query/hash data.
|
||||
- Added focused tests:
|
||||
- `tests/phase11/service-behaviour.test.cjs`
|
||||
- covers negative paths for selected phase-11 handlers
|
||||
- includes one valid-hash contract-preserving happy-path check (`getbloblist` via mocked dependencies)
|
||||
|
||||
### Validation snapshot (Phase 11)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 11)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteawaitingsubmissionfromblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteblob?container=test&casefolderID=case-1&hash=bad` (missing blobname/invalid hash) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/getbloblist?container=test&casefolderID=case-1&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 11)
|
||||
|
||||
1. Revert the three hardened API handlers.
|
||||
2. Remove `tests/phase11/service-behaviour.test.cjs` if full phase-11 rollback required.
|
||||
3. Re-run phase6/7/8/9/10/11 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 12 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive handlers with minimal reversible changes:
|
||||
- `pages/api/file/downloadblob.js`
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required query inputs (`container`, `casefolderID`, `blobname`, `hash` as applicable)
|
||||
- standardized hash-mismatch negative-path checks for `downloadblob`
|
||||
- preserved existing function signatures and response-shape contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase12/service-behaviour.test.cjs`
|
||||
- covers negative paths for selected phase-12 handlers
|
||||
- includes one valid-hash contract-preserving happy-path check (`downloadblob` via mocked dependencies)
|
||||
|
||||
### Validation snapshot (Phase 12)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 12)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf` (missing hash) -> **400**
|
||||
- `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf&hash=bad` -> **400**
|
||||
- `GET /api/file/getbloblistproxy?casefolderID=case-1` (missing container) -> **400**
|
||||
- `GET /api/file/getrepsblobproxy` (missing container) -> **400**
|
||||
- `GET /api/file/getawaitingsubmissionfromblobproxy` (missing container) -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/downloadblob?container=test&casefolderID=case-1&blobname=file.pdf&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 12)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Remove `tests/phase12/service-behaviour.test.cjs` if full phase-12 rollback required.
|
||||
3. Re-run phase6/7/8/9/10/11/12 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 13 hardening slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Hardened four additional sensitive handlers with minimal reversible changes:
|
||||
- `pages/api/file/deleteblobcase.js`
|
||||
- `pages/api/file/deleteblobrep.js`
|
||||
- `pages/api/file/createcaseinvolvement_api.js`
|
||||
- `pages/api/file/createrepinvolvement_api.js`
|
||||
- Scope delivered:
|
||||
- added explicit early 400 handling for missing/empty required query/body inputs (`hash`, `contactid`, `incidentid` as applicable)
|
||||
- standardized hash-mismatch negative-path checks for delete-blob handlers
|
||||
- removed noisy body/query logging in involvement handlers
|
||||
- preserved existing function signatures and response-shape contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase13/service-behaviour.test.cjs`
|
||||
- covers negative paths for selected phase-13 handlers
|
||||
- includes valid-hash/valid-body contract-preserving happy-path checks via mocked dependencies
|
||||
|
||||
### Validation snapshot (Phase 13)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `npm run lint` -> **warnings only** (pre-existing react-hooks warnings; no new lint errors)
|
||||
|
||||
### Manual HTTP checks (Phase 13)
|
||||
|
||||
- Negative-path checks on `localhost:3000`:
|
||||
- `GET /api/file/deleteblobcase?container=test&casefolderID=case-1` (missing hash) -> **400**
|
||||
- `GET /api/file/deleteblobcase?container=test&casefolderID=case-1&hash=bad` -> **400**
|
||||
- `GET /api/file/deleteblobrep?container=test&casefolderID=case-1&repfile=r.pdf` (missing hash) -> **400**
|
||||
- `POST /api/file/createcaseinvolvement_api` with `{}` -> **400**
|
||||
- `POST /api/file/createrepinvolvement_api` with `{}` -> **400**
|
||||
- Valid-hash happy-path spot-check:
|
||||
- `GET /api/file/deleteblobcase?container=test&casefolderID=case-1&hash=<valid>` -> **500**
|
||||
- expected due local storage/upstream dependency constraints, while confirming hash gate is no longer the failing check.
|
||||
|
||||
### Rollback plan (Phase 13)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Remove `tests/phase13/service-behaviour.test.cjs` if full phase-13 rollback required.
|
||||
3. Re-run phase6/7/8/9/10/11/12/13 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 14 client-hash signing fix)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Fixed authenticated user-journey runtime error during new appeal flow where client-side hashing tried to use server-only `HASHKEY`.
|
||||
- Added authenticated server-side hash signer endpoint:
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- requires session (`getSession`), allow-lists supported API paths, returns `{ hash }`.
|
||||
- Updated direct services to request hash from server signer for browser calls, with server-side fallback only when `HASHKEY` exists:
|
||||
- `actions/services/documentDirectService.js`
|
||||
- `actions/services/portalDirectService.js`
|
||||
- Preserved existing API contracts and response shapes in file handlers.
|
||||
- Added focused tests:
|
||||
- `tests/phase14/service-behaviour.test.cjs`
|
||||
- covers signer endpoint negative paths + authenticated happy path.
|
||||
|
||||
### Validation snapshot (Phase 14)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings)
|
||||
|
||||
### Rollback plan (Phase 14)
|
||||
|
||||
1. Revert `pages/api/endpoint/gethash_api.js`.
|
||||
2. Revert direct-service hash signer usage in `documentDirectService.js` and `portalDirectService.js`.
|
||||
3. Remove `tests/phase14/service-behaviour.test.cjs` if rolling back full phase-14 slice.
|
||||
4. Re-run phase6–phase14 tests + lint.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 14 closeout follow-up)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22019-phase-9-hardening`
|
||||
- Completed follow-up hardening and contract-alignment after runtime verification:
|
||||
- `actions/services/accountDirectService.js`
|
||||
- `getPortalLogin` now uses authenticated signer endpoint (`/api/endpoint/gethash_api`) for browser-safe hash generation
|
||||
- retains server-only fallback to local `hashAPIPath` when `HASHKEY` is available
|
||||
- `pages/api/endpoint/gethash_api.js`
|
||||
- allow-list expanded for `/api/endpoint/getportallogin_api`
|
||||
- `pages/api/file/getrepsblob.js`
|
||||
- removed enforced `casefolderID` guard and argument pass-through to align with route contract (`/api/file/getrepsblob?container=...`)
|
||||
- `components/elements/index.js`
|
||||
- added missing `updateLinks` import from `components/utils` to resolve Quill runtime error
|
||||
- Tests updated:
|
||||
- `tests/phase7/service-behaviour.test.cjs`
|
||||
- updated `getPortalLogin` expectations for signer endpoint behavior
|
||||
- `tests/phase14/service-behaviour.test.cjs`
|
||||
- added allow-list coverage for signer path `/api/endpoint/getportallogin_api`
|
||||
|
||||
### Validation snapshot (Phase 14 follow-up)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings)
|
||||
|
||||
### Risks + mitigations (follow-up)
|
||||
|
||||
- Risk: signer endpoint over-expansion could broaden hash issuance.
|
||||
- Mitigation: strict allow-list retained; only required `getportallogin_api` path added.
|
||||
- Risk: tightened/changed guards could break existing caller contracts.
|
||||
- Mitigation: `getrepsblob` guard aligned back to actual route contract; response shape unchanged.
|
||||
- Risk: UI runtime dependency regressions during hardening verification.
|
||||
- Mitigation: missing `updateLinks` import restored with minimal diff.
|
||||
|
||||
### Rollback plan (follow-up)
|
||||
|
||||
1. Revert signer-path migration commit `6094874` (or files: `accountDirectService.js`, `gethash_api.js`, `tests/phase7`, `tests/phase14`).
|
||||
2. Revert contract/import alignment commit `b8fa514` (or files: `getrepsblob.js`, `components/elements/index.js`).
|
||||
3. Re-run phase6–phase14 tests and lint to confirm rollback parity.
|
||||
|
||||
### Rollback plan (Phase 8)
|
||||
|
||||
1. Revert the four hardened API handlers.
|
||||
2. Revert direct-service hash append changes in `documentDirectService` and `portalDirectService`.
|
||||
3. Remove `tests/phase8/service-behaviour.test.cjs` if full slice rollback required.
|
||||
4. Re-run phase6/7 baseline tests + lint after rollback.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 15 hardening slice)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with confirmed work item prefix:
|
||||
- `TASK22028-phase15-hardening-slice`
|
||||
- Delivered a small consistency-only hardening slice across 4 additional sensitive file handlers:
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- Scope delivered:
|
||||
- standardized explicit early 400 handling for missing hash in handlers where hash validation was present but missing-hash guard was inconsistent
|
||||
- standardized guard style in `setupcontainer` to early-return on hash mismatch (same status/contract)
|
||||
- standardized missing required hash handling in `createappealcompletemessage_api`
|
||||
- preserved response shapes and signatures (no contract changes)
|
||||
- Added focused phase-15 tests:
|
||||
- `tests/phase15/service-behaviour.test.cjs`
|
||||
- negative-path coverage for missing hash across all 4 handlers
|
||||
- additional required-input checks where applicable
|
||||
- one valid-hash happy-path contract check (`setupcontainer` -> 200 with existing response shape)
|
||||
|
||||
### Validation snapshot (Phase 15)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
## Latest update (2026-03-14 — Phase 19 endpoint consistency slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22057-phase17-hardening-closeout`
|
||||
- Delivered a small additional consistency-only endpoint slice across:
|
||||
- `pages/api/endpoint/createwatchedcases_api.js`
|
||||
- `pages/api/endpoint/getappealtypes_api.js`
|
||||
- `pages/api/endpoint/getdnslist_api.js`
|
||||
- Scope delivered:
|
||||
- added required early 400 handling for malformed/missing `@odata.bind` values in `createwatchedcases_api`
|
||||
- removed noisy query logging in `getappealtypes_api` and `getdnslist_api`
|
||||
- preserved response-shape/signature contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase19/service-behaviour.test.cjs` (5/5 passing)
|
||||
|
||||
### Validation snapshot (Phase 19)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (9/9)
|
||||
- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase16/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase17/service-behaviour.test.cjs` -> **pass** (6/6)
|
||||
- `node tests/phase18/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase19/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
## Latest update (2026-03-14 — Phase 20 endpoint consistency slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22057-phase17-hardening-closeout`
|
||||
- Delivered a small additional consistency-only endpoint slice across:
|
||||
- `pages/api/endpoint/getbasicdnssearch_api.js`
|
||||
- `pages/api/endpoint/getbasicdnsurlsearch_api.js`
|
||||
- `pages/api/endpoint/getbasicsearchdetailspaged_api.js`
|
||||
- Scope delivered:
|
||||
- removed noisy query logging in `getbasicdnssearch_api`
|
||||
- standardized missing/empty `searchString` handling in `getbasicdnsurlsearch_api` with early 400
|
||||
- standardized missing required input handling in `getbasicsearchdetailspaged_api` (`appealTypeName`, `primaryIdAttribute`, `incidentID`) with early 400
|
||||
- preserved response-shape/signature contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase20/service-behaviour.test.cjs` (5/5 passing)
|
||||
|
||||
### Validation snapshot (Phase 20)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (9/9)
|
||||
- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase16/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase17/service-behaviour.test.cjs` -> **pass** (6/6)
|
||||
- `node tests/phase18/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase19/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase20/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
### Manual HTTP snapshot (Phase 15)
|
||||
|
||||
- Dev server run on `http://localhost:3002`.
|
||||
- Negative-path checks:
|
||||
- `POST /api/file/upload` missing hash -> **400**
|
||||
- `POST /api/file/upload?hash=wrong` -> **400**
|
||||
- `POST /api/file/uploadsinglefile` missing hash -> **400**
|
||||
- `POST /api/file/uploadsinglefile?hash=wrong` -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?container=c1&tempcaseref=t1` missing hash -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?container=c1&tempcaseref=t1&hash=wrong` -> **400**
|
||||
- `GET /api/file/createappealcompletemessage_api?container=c1` missing required params/hash -> **400**
|
||||
- `GET /api/file/setupcontainer?ident=c1` missing hash -> **400**
|
||||
- `GET /api/file/setupcontainer?ident=c1&hash=wrong` -> **400**
|
||||
- `GET /api/file/setupcontainer?hash=<valid>` missing required `ident` -> **400**
|
||||
- Valid-hash spot-check:
|
||||
- `GET /api/file/setupcontainer?ident=c1&hash=<valid>` -> **200**
|
||||
|
||||
### Rollback plan (Phase 15)
|
||||
|
||||
1. Revert these files:
|
||||
- `pages/api/file/upload.js`
|
||||
- `pages/api/file/uploadsinglefile.js`
|
||||
- `pages/api/file/createappealcompletemessage_api.js`
|
||||
- `pages/api/file/setupcontainer.js`
|
||||
- `tests/phase15/service-behaviour.test.cjs`
|
||||
2. Re-run phase6–phase15 tests and lint to confirm parity.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 16 file-proxy consistency slice)
|
||||
|
||||
- Continued on branch:
|
||||
- `TASK22028-phase15-hardening-slice`
|
||||
- Delivered a small consistency-only hardening slice across 3 sensitive file proxy handlers:
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- Scope delivered:
|
||||
- removed unused imports/constants in touched handlers to reduce noisy/unsafe dead code
|
||||
- standardized required input checks using shared local `hasValue` pattern
|
||||
- preserved response shape/signature/status behavior contracts
|
||||
- Added focused tests:
|
||||
- `tests/phase16/service-behaviour.test.cjs`
|
||||
- negative-path checks for missing required container/casefolder inputs
|
||||
- one valid-input happy-path contract check for `getbloblistproxy` (200 + passthrough shape)
|
||||
|
||||
### Validation snapshot (Phase 16)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `node tests/phase8/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase9/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase10/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase11/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase12/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `node tests/phase13/service-behaviour.test.cjs` -> **pass** (7/7)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase15/service-behaviour.test.cjs` -> **pass** (5/5)
|
||||
- `node tests/phase16/service-behaviour.test.cjs` -> **pass** (4/4)
|
||||
- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
## Latest update (2026-03-19 — TASK22168 endpoint account contract consistency slice)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with required work item prefix:
|
||||
- `TASK22168-endpoint-account-contract-consistency`
|
||||
- Delivered next coherent low-risk `pages/api/endpoint/**` slice after TASK22109 across:
|
||||
- `pages/api/endpoint/getaccounts_api.js`
|
||||
- `pages/api/endpoint/getemailaccountcheck_api.js`
|
||||
- `pages/api/endpoint/getpreferredlanguage_api.js`
|
||||
- Scope delivered:
|
||||
- removed dead/noisy code in touched handlers (unused imports and commented debug remnants)
|
||||
- standardized structured negative-path handling for:
|
||||
- missing required `emailAddress`
|
||||
- catch/failure paths
|
||||
- preserved success response contracts by returning unchanged upstream `data`
|
||||
- Added focused phase21 endpoint contract coverage:
|
||||
- `tests/phase21/endpoint-handler-contract.test.cjs`
|
||||
- extended `tests/phase21/api-contract-slice1.test.cjs` runner
|
||||
|
||||
### Validation snapshot (TASK22168)
|
||||
|
||||
- `node tests/phase21/api-contract-slice1.test.cjs` -> **pass**
|
||||
- helper: 4/4
|
||||
- file-handler: 11/11
|
||||
- email-handler: 12/12
|
||||
- endpoint-handler: 7/7
|
||||
- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
### Risks + mitigations (TASK22168)
|
||||
|
||||
- Risk: endpoint contract drift in success payloads.
|
||||
- Mitigation: success responses kept as upstream `data` payload via `respondSuccess`.
|
||||
- Risk: over-broad behavior change in account/login adjacent APIs.
|
||||
- Mitigation: scoped to 3 low-risk handlers only; no auth/session/security flow changes.
|
||||
- Risk: regression in negative-path status/shape expectations.
|
||||
- Mitigation: added explicit phase21 missing-input and catch-path assertions for each touched endpoint.
|
||||
|
||||
### Rollback plan (TASK22168)
|
||||
|
||||
1. Revert endpoint files:
|
||||
- `pages/api/endpoint/getaccounts_api.js`
|
||||
- `pages/api/endpoint/getemailaccountcheck_api.js`
|
||||
- `pages/api/endpoint/getpreferredlanguage_api.js`
|
||||
2. Revert phase21 test updates:
|
||||
- `tests/phase21/endpoint-handler-contract.test.cjs`
|
||||
- `tests/phase21/api-contract-slice1.test.cjs`
|
||||
3. Re-run:
|
||||
- `node tests/phase21/api-contract-slice1.test.cjs`
|
||||
- `npm run lint`
|
||||
|
||||
## Latest update (2026-03-19 — TASK22168 Bundle C extension on same branch)
|
||||
|
||||
- Continued same branch with user-approved larger bundle:
|
||||
- `TASK22168-endpoint-account-contract-consistency`
|
||||
- Added contract-consistency coverage for login/portal/account-adjacent endpoints:
|
||||
- `pages/api/endpoint/getlogin_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- `pages/api/endpoint/getportalloginproxy_api.js`
|
||||
- `pages/api/endpoint/getpersonalaccount_api.js`
|
||||
- Scope delivered:
|
||||
- removed dead imports/commented debug/noisy logging remnants
|
||||
- standardized structured 400 errors for required-input negative paths and catch/failure paths
|
||||
- preserved success payload contracts via `respondSuccess` pass-through
|
||||
- Phase21 endpoint suite expanded in:
|
||||
- `tests/phase21/endpoint-handler-contract.test.cjs`
|
||||
- test count grew from 7 to 18 for endpoint handler coverage
|
||||
|
||||
### Validation snapshot (TASK22168 Bundle C)
|
||||
|
||||
- `node tests/phase21/api-contract-slice1.test.cjs` -> **pass**
|
||||
- helper: 4/4
|
||||
- file-handler: 11/11
|
||||
- email-handler: 12/12
|
||||
- endpoint-handler: 18/18
|
||||
- `npm run lint` -> **warnings only** (pre-existing `react-hooks/exhaustive-deps` warnings)
|
||||
|
||||
### Risks + mitigations (TASK22168 Bundle C)
|
||||
|
||||
- Risk: contract drift from broad endpoint touch surface.
|
||||
- Mitigation: constrained to login/account adjacency group only and preserved success pass-through behavior.
|
||||
- Risk: hash-path behavior regression in `getportallogin_api`.
|
||||
- Mitigation: explicit tests for missing hash, invalid hash, and catch path.
|
||||
- Risk: inconsistent required-input behavior across adjacent handlers.
|
||||
- Mitigation: standardized explicit required-input envelopes in all four newly touched handlers.
|
||||
|
||||
### Rollback plan (TASK22168 Bundle C)
|
||||
|
||||
1. Revert endpoint files:
|
||||
- `pages/api/endpoint/getlogin_api.js`
|
||||
- `pages/api/endpoint/getportallogin_api.js`
|
||||
- `pages/api/endpoint/getportalloginproxy_api.js`
|
||||
- `pages/api/endpoint/getpersonalaccount_api.js`
|
||||
2. Revert endpoint contract test updates:
|
||||
- `tests/phase21/endpoint-handler-contract.test.cjs`
|
||||
3. Re-run:
|
||||
- `node tests/phase21/api-contract-slice1.test.cjs`
|
||||
- `npm run lint`
|
||||
|
||||
### Manual HTTP checks (Phase 16)
|
||||
|
||||
- Dev server on `http://localhost:3002`.
|
||||
- Negative-path checks:
|
||||
- `/api/file/getbloblistproxy?casefolderID=case-1` -> **400**
|
||||
- `/api/file/getbloblistproxy?container=c1` -> **400**
|
||||
- `/api/file/getrepsblobproxy` -> **400**
|
||||
- `/api/file/getawaitingsubmissionfromblobproxy` -> **400**
|
||||
- Feasible valid-input spot-check:
|
||||
- `/api/file/getbloblistproxy?container=c1&casefolderID=case-1` -> **400** (expected downstream/local dependency behavior; input guard passed)
|
||||
|
||||
### Rollback plan (Phase 16)
|
||||
|
||||
1. Revert commit `c196edb` or files:
|
||||
- `pages/api/file/getbloblistproxy.js`
|
||||
- `pages/api/file/getrepsblobproxy.js`
|
||||
- `pages/api/file/getawaitingsubmissionfromblobproxy.js`
|
||||
- `tests/phase16/service-behaviour.test.cjs`
|
||||
2. Re-run phase6–phase16 tests and lint.
|
||||
|
||||
## Latest update (2026-03-13 — signer allow-list follow-up)
|
||||
|
||||
- Branch: `TASK22028-phase15-hardening-slice`
|
||||
- Fix applied:
|
||||
- added `/api/file/deleteblobcase` to signer endpoint allow-list in `pages/api/endpoint/gethash_api.js`
|
||||
- Test update:
|
||||
- extended `tests/phase14/service-behaviour.test.cjs` with deleteblobcase allow-list coverage
|
||||
|
||||
### Validation snapshot (follow-up)
|
||||
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (6/6)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `npm run lint` -> **warnings only** (pre-existing)
|
||||
|
||||
## Latest update (2026-03-13 — signer delete-flow follow-up)
|
||||
|
||||
- Branch: `TASK22028-phase15-hardening-slice`
|
||||
- Extended signer allow-list and browser signer usage for additional delete flows:
|
||||
- `deleteWatchedCases`
|
||||
- `deleteMyRepresentations`
|
||||
- `deleteAwaitingSubmissionsFromBlob`
|
||||
- `deleteMyRepresentationsFromBlob`
|
||||
|
||||
### Validation snapshot (delete-flow follow-up)
|
||||
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12)
|
||||
- `node tests/phase14/service-behaviour.test.cjs` -> **pass** (9/9)
|
||||
- `npm run lint` -> **warnings only** (pre-existing)
|
||||
|
||||
## Latest update (2026-03-13 — myportal + i18n follow-up)
|
||||
|
||||
- Branch: `TASK22028-phase15-hardening-slice`
|
||||
- Delivered follow-up fixes:
|
||||
- myportal representation delete calls now use `caseRef` in top-three and view-all flows
|
||||
- missing `myportal` namespace added for `/newappeal/[appealtypes]` in `i18n.js`
|
||||
|
||||
### Validation snapshot (myportal + i18n follow-up)
|
||||
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (12/12)
|
||||
- `npm run lint` -> **warnings only** (pre-existing)
|
||||
|
||||
## Outstanding risks / gaps
|
||||
|
||||
- Navigation regressions across EN/CY + route query combinations.
|
||||
- Drift between rewrite config and component-level locale path logic.
|
||||
- Deployment ambiguity due to multiple CI/CD artifacts (Azure pipeline, Jenkins, Docker) with unclear active source of truth.
|
||||
- Security posture variability where hash checks are bypassed/commented in selected handlers.
|
||||
|
||||
## Latest update (2026-03-13 — Phase 7 post-Phase-6 hardening)
|
||||
|
||||
- New branch created from `origin/SIPS-Development` with required work item prefix:
|
||||
- `TASK21988a-phase7-postphase6-hardening`
|
||||
- Fixed known pre-existing SSR serialization issue on search results route:
|
||||
- `pages/searchresults.js`
|
||||
- updated SSR dispatch fallback from `setSearch(query.q)` to `setSearch(query?.q || "")`
|
||||
- result: `/searchresults` and `/cy/searchresults` now return 200 in local smoke checks (no 500 observed in this run).
|
||||
- Added expanded behavioural coverage for remaining direct-service domains:
|
||||
- new test file: `tests/phase7/service-behaviour.test.cjs`
|
||||
- includes document, portal, account, notify, integration behavioural checks
|
||||
- includes negative-path assertions for relay/hash/token-sensitive behaviors where feasible:
|
||||
- hashed URL append checks (`hashAPIPath`)
|
||||
- error handling contracts (undefined/error string/rethrow depending on existing function contract)
|
||||
|
||||
### Validation snapshot (Phase 7)
|
||||
|
||||
- `node tests/phase6/service-parity.test.cjs` -> **pass**
|
||||
- `node tests/phase6/service-behaviour.test.cjs` -> **pass** (8/8)
|
||||
- `node tests/phase7/service-behaviour.test.cjs` -> **pass** (10/10)
|
||||
- `npm run lint` -> **warnings only** (pre-existing hook dependency warnings; no new lint errors)
|
||||
|
||||
### Targeted smoke snapshot (local dev server)
|
||||
|
||||
- Note: dev server auto-started on `http://localhost:3001` because port `3000` was in use.
|
||||
- Search flow:
|
||||
- `GET /searchresults` and `GET /cy/searchresults` -> **200**
|
||||
- Case flow:
|
||||
- `GET /case` and `GET /cy/case` -> **200**
|
||||
- My Portal flow (negative-path):
|
||||
- `GET /myportal` and `GET /cy/myportal` -> **307** redirect to `/auth/signin`
|
||||
- Document flow (negative-path):
|
||||
- `GET /api/file/getbloblistproxy?container=test&casefolderID=test` -> **400**
|
||||
- Notify flow (negative-path):
|
||||
- `POST /api/email/notify` with `{}` -> **400**
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,40 +11,51 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var token = await getToken();
|
||||
var queryUrl = "contacts";
|
||||
var data = JSON.stringify(req.body);
|
||||
|
||||
var config = {
|
||||
method: "post",
|
||||
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json",
|
||||
"Prefer": 'odata.include-annotations="*",return=representation',
|
||||
"Authorization": "Bearer " + token.access_token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: data
|
||||
};
|
||||
|
||||
return axios(config)
|
||||
.then(({ data }) => {
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
if (!req.body || Object.keys(req.body).length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "ACCOUNT_PAYLOAD_REQUIRED",
|
||||
message: "Account payload is required"
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await getToken();
|
||||
const queryUrl = "contacts";
|
||||
const data = JSON.stringify(req.body);
|
||||
|
||||
const config = {
|
||||
method: "post",
|
||||
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
Accept: "application/json",
|
||||
Prefer: 'odata.include-annotations="*",return=representation',
|
||||
Authorization: "Bearer " + token.access_token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data
|
||||
};
|
||||
|
||||
const response = await axios(config);
|
||||
return respondSuccess(res, response.data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "ACCOUNT_CREATE_FAILED",
|
||||
message: "Failed to create account"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,149 +22,149 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import _ from "lodash";
|
||||
import { azureHeadersPaged } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var searchString = req.query.searchstring;
|
||||
var token = await getToken();
|
||||
const encodedSearchString = req.query.searchstring;
|
||||
|
||||
searchString = _.isEmpty(searchString)
|
||||
? searchString
|
||||
: JSON.parse(decodeURI(searchString));
|
||||
if (
|
||||
typeof encodedSearchString !== "string" ||
|
||||
encodedSearchString.trim().length === 0
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "SEARCH_STRING_REQUIRED",
|
||||
message: "searchstring is required"
|
||||
});
|
||||
}
|
||||
|
||||
var queryString = "";
|
||||
let searchString;
|
||||
try {
|
||||
searchString = JSON.parse(decodeURI(encodedSearchString));
|
||||
} catch (error) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INVALID_SEARCH_STRING",
|
||||
message: "searchstring must be valid JSON"
|
||||
});
|
||||
}
|
||||
|
||||
if (
|
||||
!searchString ||
|
||||
typeof searchString !== "object" ||
|
||||
Object.keys(searchString).length === 0
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "SEARCH_STRING_REQUIRED",
|
||||
message: "searchstring is required"
|
||||
});
|
||||
}
|
||||
|
||||
const toEscapedString = (value) => String(value).replace(/\'/g, "''");
|
||||
let queryString = "";
|
||||
|
||||
queryString +=
|
||||
_.has(searchString, "q") && searchString.q != null
|
||||
searchString.q != null
|
||||
? "(contains(title, '" +
|
||||
searchString.q.replace(/\'/g, "''") +
|
||||
toEscapedString(searchString.q) +
|
||||
"') or contains(ticketnumber,'" +
|
||||
searchString.q.replace(/\'/g, "''") +
|
||||
toEscapedString(searchString.q) +
|
||||
"')) and"
|
||||
: "";
|
||||
|
||||
queryString +=
|
||||
_.has(searchString, "lpaRef") && searchString.lpaRef != null
|
||||
searchString.lpaRef != null
|
||||
? "(contains(pinswg_lpareference, '" +
|
||||
searchString.lpaRef.replace(/\'/g, "''") +
|
||||
toEscapedString(searchString.lpaRef) +
|
||||
"')) and"
|
||||
: "";
|
||||
|
||||
queryString +=
|
||||
(_.has(searchString, "lpa") || _.has(searchString, "LPA")) &&
|
||||
(searchString.lpa != null || searchString.LPA != null) &&
|
||||
searchString.lpa != null
|
||||
? " _pinswg_associatedlpa_value eq " + searchString.lpa + " and"
|
||||
: "";
|
||||
|
||||
queryString +=
|
||||
_.has(searchString, "apt") && searchString.apt != null
|
||||
searchString.apt != null
|
||||
? " pinswg_appealcasetype eq " + searchString.apt + " and"
|
||||
: "";
|
||||
|
||||
queryString +=
|
||||
_.has(searchString, "statuscode") && searchString.statuscode != null
|
||||
searchString.statuscode != null
|
||||
? " statuscode eq " + searchString.statuscode + " and"
|
||||
: "";
|
||||
|
||||
//console.log(queryString);
|
||||
|
||||
var queryUrl =
|
||||
const queryUrl =
|
||||
"incidents?$select=pinswg_environmentalstatementlocation,pinswg_caseaddress,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title,_primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$filter=" +
|
||||
queryString +
|
||||
" pinswg_appealcasetype ne null and pinswg_publishtoweb eq true&$orderby=createdon desc&$count=true";
|
||||
|
||||
//console.log(queryString, "\n", queryUrl);
|
||||
try {
|
||||
const token = await getToken();
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPaged(token.access_token)
|
||||
);
|
||||
|
||||
var apiResponse = _.isEmpty(searchString)
|
||||
? res.status(400).json()
|
||||
: axios
|
||||
.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPaged(token.access_token)
|
||||
)
|
||||
.then(async ({ data }) => {
|
||||
var dataStr;
|
||||
_.has(data, "@odata.nextLink") == true &&
|
||||
((dataStr = JSON.stringify(data["@odata.nextLink"])),
|
||||
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
|
||||
if (Object.prototype.hasOwnProperty.call(data, "@odata.nextLink")) {
|
||||
const dataStr = JSON.stringify(data["@odata.nextLink"]);
|
||||
data["@odata.nextLink"] = dataStr.split("/v8.2/")[1];
|
||||
}
|
||||
|
||||
if (_.has(searchString, "projecttype")) {
|
||||
await updateValueArray(data, token);
|
||||
if (searchString.projecttype != null) {
|
||||
for (let i = 0; i < data.value.length; i++) {
|
||||
const item = data.value[i];
|
||||
|
||||
async function updateValueArray(data, token) {
|
||||
for (let i = 0; i < data.value.length; i++) {
|
||||
const item = data.value[i];
|
||||
try {
|
||||
const projectTypeQuery =
|
||||
"pinswg_sipses?$filter=_pinswg_sipscase_value eq " +
|
||||
item.incidentid +
|
||||
" and _pinswg_projecttype_value eq " +
|
||||
searchString.projecttype +
|
||||
"&$select=_pinswg_projecttype_value";
|
||||
|
||||
try {
|
||||
// Axios call using the `incidentid` to fetch additional data
|
||||
const response = await axios.get(
|
||||
WEBAPI_URL +
|
||||
"pinswg_sipses?$filter=_pinswg_sipscase_value eq " +
|
||||
item.incidentid +
|
||||
" and _pinswg_projecttype_value eq " +
|
||||
searchString.projecttype +
|
||||
"&$select=_pinswg_projecttype_value" +
|
||||
hashAPIPath(
|
||||
"pinswg_sipses?$filter=_pinswg_sipscase_value eq " +
|
||||
item.incidentid +
|
||||
" and _pinswg_projecttype_value eq " +
|
||||
searchString.projecttype +
|
||||
"&$select=_pinswg_projecttype_value"
|
||||
),
|
||||
azureHeadersPaged(token.access_token)
|
||||
);
|
||||
const response = await axios.get(
|
||||
WEBAPI_URL +
|
||||
projectTypeQuery +
|
||||
hashAPIPath(projectTypeQuery),
|
||||
azureHeadersPaged(token.access_token)
|
||||
);
|
||||
|
||||
// Assuming the response contains the additional data you want to add
|
||||
// console.log(response.data.value[0]);
|
||||
console.log(response.data.value);
|
||||
if (
|
||||
response.data.value.length > 0 &&
|
||||
response.data.value[0]._pinswg_projecttype_value != null
|
||||
) {
|
||||
Object.assign(item, response.data.value[0]);
|
||||
}
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
response.data.value.length > 0 &&
|
||||
response.data.value[0]
|
||||
._pinswg_projecttype_value != null
|
||||
) {
|
||||
Object.assign(
|
||||
item,
|
||||
response.data.value[0]
|
||||
); // Update item with new data
|
||||
} else {
|
||||
console.log(
|
||||
`No project type found for incident ID ${item.incidentid}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Error fetching data for incident ID ${item.incidentid}:`,
|
||||
error
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
data.value = data.value.filter(
|
||||
(item) => item._pinswg_projecttype_value != null
|
||||
);
|
||||
|
||||
data.value = data.value.filter(
|
||||
(item) => item._pinswg_projecttype_value != null
|
||||
);
|
||||
data["@odata.count"] = data.value.length;
|
||||
}
|
||||
|
||||
data["@odata.count"] = data.value.length;
|
||||
|
||||
// console.log(newDataObj);
|
||||
}
|
||||
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
});
|
||||
|
||||
return apiResponse;
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "ADVANCED_SEARCH_FETCH_FAILED",
|
||||
message: "Failed to fetch advanced search results"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,39 +11,53 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { azureHeaders } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var loggedInUserId = req.query.loggedInUserId;
|
||||
var token = await getToken();
|
||||
const loggedInUserId = req.query.loggedInUserId;
|
||||
|
||||
var queryUrl =
|
||||
"incidents?$select=pinswg_environmentalstatementlocation,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantlastname,pinswg_appellantfirstname,pinswg_appellantagent,pinswg_agentfirstname,pinswg_agentlastname,pinswg_agentcompanyname&$expand=primarycontactid($select=fullname)&$filter=_customerid_value eq " +
|
||||
loggedInUserId +
|
||||
" and pinswg_appealcasetype ne null&$orderby=createdon desc&$count=true";
|
||||
if (
|
||||
typeof loggedInUserId !== "string" ||
|
||||
loggedInUserId.trim().length === 0
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "LOGGED_IN_USER_ID_REQUIRED",
|
||||
message: "loggedInUserId is required"
|
||||
});
|
||||
}
|
||||
|
||||
//console.log(WEBAPI_URL + queryUrl + hashAPIPath(queryUrl));
|
||||
return axios
|
||||
.get(
|
||||
try {
|
||||
const token = await getToken();
|
||||
const queryUrl =
|
||||
"incidents?$select=pinswg_environmentalstatementlocation,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantlastname,pinswg_appellantfirstname,pinswg_appellantagent,pinswg_agentfirstname,pinswg_agentlastname,pinswg_agentcompanyname&$expand=primarycontactid($select=fullname)&$filter=_customerid_value eq " +
|
||||
loggedInUserId +
|
||||
" and pinswg_appealcasetype ne null&$orderby=createdon desc&$count=true";
|
||||
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeaders(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
data.value.forEach(function (element) {
|
||||
element.pinswg_title = element.title;
|
||||
});
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
);
|
||||
|
||||
data.value.forEach(function (element) {
|
||||
element.pinswg_title = element.title;
|
||||
});
|
||||
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "AWAITING_SUBMISSION_PROXY_FETCH_FAILED",
|
||||
message: "Failed to fetch awaiting submission proxy details"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,65 +16,61 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import _ from "lodash";
|
||||
import { azureHeadersPaged } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var searchString = req.query.searchString;
|
||||
var token = await getToken();
|
||||
const searchString = req.query.searchString;
|
||||
|
||||
searchString = searchString.replace(/\'/g, "''");
|
||||
if (typeof searchString !== "string" || searchString.trim().length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "SEARCH_STRING_REQUIRED",
|
||||
message: "searchString is required"
|
||||
});
|
||||
}
|
||||
|
||||
var queryUrl =
|
||||
"incidents?$select=pinswg_environmentalstatementlocation,pinswg_caseaddress,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$filter=(contains(title, '" +
|
||||
searchString +
|
||||
"') or contains(ticketnumber, '" +
|
||||
searchString +
|
||||
"') or contains(pinswg_lpareference, '" +
|
||||
searchString +
|
||||
"')) and pinswg_appealcasetype ne null " +
|
||||
(process.env.SHOWSIPS !== "true"
|
||||
? "and pinswg_appealcasetype ne 846040002 "
|
||||
: "") +
|
||||
"and pinswg_publishtoweb eq true&$orderby=createdon desc&$count=true";
|
||||
try {
|
||||
const token = await getToken();
|
||||
const escapedSearchString = searchString.replace(/\'/g, "''");
|
||||
|
||||
console.log(
|
||||
"\n==========================================\n",
|
||||
"\nBasic search ",
|
||||
"\nSearch String: " + searchString,
|
||||
"\n\nQuery url: " + queryUrl,
|
||||
"\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
"\n==========================================\n"
|
||||
);
|
||||
const queryUrl =
|
||||
"incidents?$select=pinswg_environmentalstatementlocation,pinswg_caseaddress,modifiedon,description,numberofchildincidents,_accountid_value,_customerid_value,_pinswg_associatedlpa_value,_ownerid_value,pinswg_appealcasetype,statuscode,ticketnumber,title, _primarycontactid_value,pinswg_lpareference,pinswg_appellantagent,pinswg_appellantfirstname,pinswg_appellantlastname&$expand=primarycontactid($select=fullname)&$filter=(contains(title, '" +
|
||||
escapedSearchString +
|
||||
"') or contains(ticketnumber, '" +
|
||||
escapedSearchString +
|
||||
"') or contains(pinswg_lpareference, '" +
|
||||
escapedSearchString +
|
||||
"')) and pinswg_appealcasetype ne null " +
|
||||
(process.env.SHOWSIPS !== "true"
|
||||
? "and pinswg_appealcasetype ne 846040002 "
|
||||
: "") +
|
||||
"and pinswg_publishtoweb eq true&$orderby=createdon desc&$count=true";
|
||||
|
||||
var apiResponse = _.isEmpty(req.query)
|
||||
? res.status(400).json()
|
||||
: searchString.length > 0
|
||||
? axios
|
||||
.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPaged(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
var dataStr;
|
||||
_.has(data, "@odata.nextLink") == true &&
|
||||
((dataStr = JSON.stringify(data["@odata.nextLink"])),
|
||||
(data["@odata.nextLink"] = dataStr.split("/v8.2/")[1]));
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
})
|
||||
: res.status(400).json();
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPaged(token.access_token)
|
||||
);
|
||||
|
||||
return apiResponse;
|
||||
if (Object.prototype.hasOwnProperty.call(data, "@odata.nextLink")) {
|
||||
const dataStr = JSON.stringify(data["@odata.nextLink"]);
|
||||
data["@odata.nextLink"] = dataStr.split("/v8.2/")[1];
|
||||
}
|
||||
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "BASIC_SEARCH_FETCH_FAILED",
|
||||
message: "Failed to fetch basic search results"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,48 +16,47 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import _ from "lodash";
|
||||
import { azureHeadersPaged } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var searchString = req.query.id;
|
||||
var token = await getToken();
|
||||
const caseId = req.query.id;
|
||||
|
||||
var queryUrl = `tasks?$select=_regardingobjectid_value,subject,description,createdon,statuscode,scheduledend,scheduledstart&$count=true&$filter=_regardingobjectid_value eq ${searchString} and contains(subject, 'Banner') and statuscode ne 5&$orderby=createdon desc`;
|
||||
if (typeof caseId !== "string" || caseId.trim().length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "CASE_ID_REQUIRED",
|
||||
message: "id is required"
|
||||
});
|
||||
}
|
||||
|
||||
console.log(
|
||||
"\n==========================================\n",
|
||||
"\nCase messages ",
|
||||
"\nSearch String: " + searchString,
|
||||
"\n\nQuery url: " + queryUrl,
|
||||
"\n\nRelay link: " + WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
"\n==========================================\n"
|
||||
);
|
||||
try {
|
||||
const token = await getToken();
|
||||
|
||||
var apiResponse = _.isEmpty(req.query)
|
||||
? res.status(400).json()
|
||||
: searchString.length > 0
|
||||
? axios
|
||||
.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPaged(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
})
|
||||
: res.status(400).json();
|
||||
const queryUrl =
|
||||
"tasks?$select=_regardingobjectid_value,subject,description,createdon,statuscode,scheduledend,scheduledstart&$count=true&$filter=_regardingobjectid_value eq " +
|
||||
caseId +
|
||||
" and contains(subject, 'Banner') and statuscode ne 5&$orderby=createdon desc";
|
||||
|
||||
return apiResponse;
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeadersPaged(token.access_token)
|
||||
);
|
||||
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "CASE_MESSAGE_FETCH_FAILED",
|
||||
message: "Failed to fetch case messages"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,35 +18,50 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { azureHeaders } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var loggedInUserId = req.query.loggedInUserId;
|
||||
var token = await getToken();
|
||||
const loggedInUserId = req.query.loggedInUserId;
|
||||
|
||||
var queryUrl =
|
||||
"pinswg_representationses?$filter= _pinswg_contact_value eq " +
|
||||
loggedInUserId +
|
||||
"&$count=true&$orderby=createdon desc";
|
||||
if (
|
||||
typeof loggedInUserId !== "string" ||
|
||||
loggedInUserId.trim().length === 0
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "LOGGED_IN_USER_ID_REQUIRED",
|
||||
message: "loggedInUserId is required"
|
||||
});
|
||||
}
|
||||
|
||||
return axios
|
||||
.get(
|
||||
try {
|
||||
const token = await getToken();
|
||||
|
||||
const queryUrl =
|
||||
"pinswg_representationses?$filter= _pinswg_contact_value eq " +
|
||||
loggedInUserId +
|
||||
"&$count=true&$orderby=createdon desc";
|
||||
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeaders(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
);
|
||||
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "MY_REPRESENTATIONS_PROXY_FETCH_FAILED",
|
||||
message: "Failed to fetch my representations proxy details"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,35 +18,47 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { azureHeaders } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var incidentID = req.query.incidentID;
|
||||
var token = await getToken();
|
||||
const incidentID = req.query.incidentID;
|
||||
|
||||
var queryUrl =
|
||||
"pinswg_representationses?$filter= _pinswg_case_value eq " +
|
||||
incidentID +
|
||||
"&$count=true&$orderby=createdon desc";
|
||||
if (typeof incidentID !== "string" || incidentID.trim().length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "INCIDENT_ID_REQUIRED",
|
||||
message: "incidentID is required"
|
||||
});
|
||||
}
|
||||
|
||||
return axios
|
||||
.get(
|
||||
try {
|
||||
const token = await getToken();
|
||||
|
||||
const queryUrl =
|
||||
"pinswg_representationses?$filter= _pinswg_case_value eq " +
|
||||
incidentID +
|
||||
"&$count=true&$orderby=createdon desc";
|
||||
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeaders(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
);
|
||||
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "REPRESENTATIONS_PROXY_FETCH_FAILED",
|
||||
message: "Failed to fetch representations proxy details"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,69 +18,75 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { azureHeaders } from "../../../actions/core/headers";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
const BASE_URL = process.env.API_ROOT || `http://localhost:${port}`;
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var loggedInUserId = req.query.loggedInUserId;
|
||||
var token = await getToken();
|
||||
const loggedInUserId = req.query.loggedInUserId;
|
||||
|
||||
// var queryUrl =
|
||||
// "pinswg_watchlists?$filter= _pinswg_contact_value eq " +
|
||||
// loggedInUserId +
|
||||
// "&$select=pinswg_emailnotifications,modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)";
|
||||
if (
|
||||
typeof loggedInUserId !== "string" ||
|
||||
loggedInUserId.trim().length === 0
|
||||
) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "LOGGED_IN_USER_ID_REQUIRED",
|
||||
message: "loggedInUserId is required"
|
||||
});
|
||||
}
|
||||
|
||||
var queryUrl =
|
||||
"pinswg_watchlists?$filter= _pinswg_contact_value eq " +
|
||||
loggedInUserId +
|
||||
"&$select=modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)";
|
||||
try {
|
||||
const token = await getToken();
|
||||
const queryUrl =
|
||||
"pinswg_watchlists?$filter= _pinswg_contact_value eq " +
|
||||
loggedInUserId +
|
||||
"&$select=modifiedon,pinswg_appealcasetype,pinswg_watchlistid,_pinswg_watchedcase_value,statuscode,pinswg_representationsubmitted,pinswg_representationtype&$count=true&$orderby=createdon desc&$expand=pinswg_WatchedCase($select=pinswg_AssociatedLPA)";
|
||||
|
||||
return axios
|
||||
.get(
|
||||
const { data } = await axios.get(
|
||||
WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
azureHeaders(token.access_token)
|
||||
)
|
||||
.then(({ data }) => {
|
||||
data.value.forEach(function (element) {
|
||||
element.ticketnumber = element.pinswg_WatchedCase.ticketnumber;
|
||||
element.pinswg_title =
|
||||
element[
|
||||
"_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue"
|
||||
];
|
||||
);
|
||||
|
||||
data.value.forEach(function (element) {
|
||||
element.ticketnumber = element.pinswg_WatchedCase.ticketnumber;
|
||||
element.pinswg_title =
|
||||
element[
|
||||
"_pinswg_watchedcase_value@OData.Community.Display.V1.FormattedValue"
|
||||
];
|
||||
|
||||
element[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
] =
|
||||
element.pinswg_WatchedCase[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
] =
|
||||
element.pinswg_WatchedCase[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
];
|
||||
element._pinswg_associatedlpa_value =
|
||||
element.pinswg_WatchedCase._pinswg_associatedlpa_value;
|
||||
element[
|
||||
];
|
||||
element._pinswg_associatedlpa_value =
|
||||
element.pinswg_WatchedCase._pinswg_associatedlpa_value;
|
||||
element[
|
||||
"_ownerid_value@OData.Community.Display.V1.FormattedValue"
|
||||
] =
|
||||
element.pinswg_WatchedCase[
|
||||
"_ownerid_value@OData.Community.Display.V1.FormattedValue"
|
||||
] =
|
||||
element.pinswg_WatchedCase[
|
||||
"_ownerid_value@OData.Community.Display.V1.FormattedValue"
|
||||
];
|
||||
element._ownerid_value =
|
||||
element.pinswg_WatchedCase._ownerid_value;
|
||||
];
|
||||
element._ownerid_value = element.pinswg_WatchedCase._ownerid_value;
|
||||
|
||||
delete element.pinswg_WatchedCase;
|
||||
});
|
||||
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
delete element.pinswg_WatchedCase;
|
||||
});
|
||||
|
||||
return respondSuccess(res, data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "WATCHED_CASES_PROXY_FETCH_FAILED",
|
||||
message: "Failed to fetch watched cases proxy details"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,43 +11,61 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var contactId = req.query.contactId;
|
||||
var token = await getToken();
|
||||
var data = JSON.stringify(req.body);
|
||||
var queryUrl = "contacts(" + contactId + ")";
|
||||
const contactId = req.query.contactId;
|
||||
|
||||
var config = {
|
||||
method: "patch",
|
||||
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json",
|
||||
"Prefer": 'odata.include-annotations="*",return=representation',
|
||||
"Authorization": "Bearer " + token.access_token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: data
|
||||
};
|
||||
|
||||
console.log(config);
|
||||
|
||||
return axios(config)
|
||||
.then(({ data }) => {
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
if (typeof contactId !== "string" || contactId.trim().length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "CONTACT_ID_REQUIRED",
|
||||
message: "contactId is required"
|
||||
});
|
||||
}
|
||||
|
||||
if (!req.body || Object.keys(req.body).length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "ACCOUNT_UPDATE_PAYLOAD_REQUIRED",
|
||||
message: "Account update payload is required"
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await getToken();
|
||||
const data = JSON.stringify(req.body);
|
||||
const queryUrl = "contacts(" + contactId + ")";
|
||||
|
||||
const config = {
|
||||
method: "patch",
|
||||
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
Accept: "application/json",
|
||||
Prefer: 'odata.include-annotations="*",return=representation',
|
||||
Authorization: "Bearer " + token.access_token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data
|
||||
};
|
||||
|
||||
const response = await axios(config);
|
||||
return respondSuccess(res, response.data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "ACCOUNT_UPDATE_FAILED",
|
||||
message: "Failed to update account"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,41 +11,61 @@
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
import { getToken } from "../../../actions/core/token";
|
||||
import { hashAPIPath } from "../../../actions/core/hash";
|
||||
import { respondError, respondSuccess } from "../middleware/apiResponse";
|
||||
|
||||
const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export default async function ApiProxy(req, res) {
|
||||
var contactId = req.query.contactId;
|
||||
var token = await getToken();
|
||||
var data = JSON.stringify(req.body);
|
||||
var queryUrl = "contacts(" + contactId + ")";
|
||||
const contactId = req.query.contactId;
|
||||
|
||||
var config = {
|
||||
method: "patch",
|
||||
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json",
|
||||
"Prefer": 'odata.include-annotations="*",return=representation',
|
||||
"Authorization": "Bearer " + token.access_token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data: data
|
||||
};
|
||||
|
||||
return axios(config)
|
||||
.then(({ data }) => {
|
||||
res.status(200).json(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
res.status(400).json(error);
|
||||
if (typeof contactId !== "string" || contactId.trim().length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "CONTACT_ID_REQUIRED",
|
||||
message: "contactId is required"
|
||||
});
|
||||
}
|
||||
|
||||
if (!req.body || Object.keys(req.body).length === 0) {
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "PASSWORD_UPDATE_PAYLOAD_REQUIRED",
|
||||
message: "Password update payload is required"
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const token = await getToken();
|
||||
const data = JSON.stringify(req.body);
|
||||
const queryUrl = "contacts(" + contactId + ")";
|
||||
|
||||
const config = {
|
||||
method: "patch",
|
||||
url: WEBAPI_URL + queryUrl + hashAPIPath(queryUrl),
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
Accept: "application/json",
|
||||
Prefer: 'odata.include-annotations="*",return=representation',
|
||||
Authorization: "Bearer " + token.access_token,
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
data
|
||||
};
|
||||
|
||||
const response = await axios(config);
|
||||
return respondSuccess(res, response.data);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return respondError(res, {
|
||||
status: 400,
|
||||
code: "PASSWORD_UPDATE_FAILED",
|
||||
message: "Failed to update password"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -442,6 +442,535 @@ test("getemailaccountcheck success returns existing data payload contract", asyn
|
||||
});
|
||||
});
|
||||
|
||||
test("getwatchedcasesproxy returns LOGGED_IN_USER_ID_REQUIRED when loggedInUserId missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getwatchedcasesproxy_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"LOGGED_IN_USER_ID_REQUIRED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getwatchedcasesproxy catch path returns WATCHED_CASES_PROXY_FETCH_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getwatchedcasesproxy_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { loggedInUserId: "c1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"WATCHED_CASES_PROXY_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getmyrepresentationsproxy returns LOGGED_IN_USER_ID_REQUIRED when loggedInUserId missing", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/endpoint/getmyrepresentationsproxy_api.js",
|
||||
{
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"LOGGED_IN_USER_ID_REQUIRED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getmyrepresentationsproxy catch path returns MY_REPRESENTATIONS_PROXY_FETCH_FAILED", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/endpoint/getmyrepresentationsproxy_api.js",
|
||||
{
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: { loggedInUserId: "c1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"MY_REPRESENTATIONS_PROXY_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getrepresentationsproxy returns INCIDENT_ID_REQUIRED when incidentID missing", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/endpoint/getrepresentationsproxy_api.js",
|
||||
{
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "INCIDENT_ID_REQUIRED");
|
||||
});
|
||||
|
||||
test("getrepresentationsproxy catch path returns REPRESENTATIONS_PROXY_FETCH_FAILED", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/endpoint/getrepresentationsproxy_api.js",
|
||||
{
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: { incidentID: "i1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"REPRESENTATIONS_PROXY_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getawaitingsubmissionproxy returns LOGGED_IN_USER_ID_REQUIRED when loggedInUserId missing", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/endpoint/getawaitingsubmissionproxy_api.js",
|
||||
{
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"LOGGED_IN_USER_ID_REQUIRED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getawaitingsubmissionproxy catch path returns AWAITING_SUBMISSION_PROXY_FETCH_FAILED", async () => {
|
||||
const mod = loadModule(
|
||||
"pages/api/endpoint/getawaitingsubmissionproxy_api.js",
|
||||
{
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeaders: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
}
|
||||
);
|
||||
|
||||
const req = { query: { loggedInUserId: "c1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"AWAITING_SUBMISSION_PROXY_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
test("createaccount returns ACCOUNT_PAYLOAD_REQUIRED when body missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/createaccount_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => ({ data: { contactid: "c1" } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {}, body: undefined };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"ACCOUNT_PAYLOAD_REQUIRED"
|
||||
);
|
||||
});
|
||||
|
||||
test("createaccount catch path returns ACCOUNT_CREATE_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/createaccount_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => {
|
||||
throw new Error("relay failed");
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {}, body: { firstname: "A" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "ACCOUNT_CREATE_FAILED");
|
||||
});
|
||||
|
||||
test("updateaccount returns CONTACT_ID_REQUIRED when contactId missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/updateaccount_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => ({ data: { contactid: "c1" } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {}, body: { firstname: "A" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "CONTACT_ID_REQUIRED");
|
||||
});
|
||||
|
||||
test("updateaccount returns ACCOUNT_UPDATE_PAYLOAD_REQUIRED when body missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/updateaccount_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => ({ data: { contactid: "c1" } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { contactId: "c1" }, body: undefined };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"ACCOUNT_UPDATE_PAYLOAD_REQUIRED"
|
||||
);
|
||||
});
|
||||
|
||||
test("updateaccount catch path returns ACCOUNT_UPDATE_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/updateaccount_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => {
|
||||
throw new Error("relay failed");
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { contactId: "c1" }, body: { firstname: "A" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "ACCOUNT_UPDATE_FAILED");
|
||||
});
|
||||
|
||||
test("updatepassword returns CONTACT_ID_REQUIRED when contactId missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/updatepassword_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => ({ data: { contactid: "c1" } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {}, body: { pinswg_password: "abc" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "CONTACT_ID_REQUIRED");
|
||||
});
|
||||
|
||||
test("updatepassword returns PASSWORD_UPDATE_PAYLOAD_REQUIRED when body missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/updatepassword_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => ({ data: { contactid: "c1" } }),
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { contactId: "c1" }, body: undefined };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"PASSWORD_UPDATE_PAYLOAD_REQUIRED"
|
||||
);
|
||||
});
|
||||
|
||||
test("updatepassword catch path returns PASSWORD_UPDATE_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/updatepassword_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
axios: async () => {
|
||||
throw new Error("relay failed");
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: { contactId: "c1" },
|
||||
body: { pinswg_password: "abc" }
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "PASSWORD_UPDATE_FAILED");
|
||||
});
|
||||
|
||||
test("getbasicsearch returns SEARCH_STRING_REQUIRED when searchString missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getbasicsearch_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "SEARCH_STRING_REQUIRED");
|
||||
});
|
||||
|
||||
test("getbasicsearch catch path returns BASIC_SEARCH_FETCH_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getbasicsearch_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { searchString: "CAS" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"BASIC_SEARCH_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getcasemessage returns CASE_ID_REQUIRED when id missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getcasemessage_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "CASE_ID_REQUIRED");
|
||||
});
|
||||
|
||||
test("getcasemessage catch path returns CASE_MESSAGE_FETCH_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getcasemessage_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { id: "i1" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"CASE_MESSAGE_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
test("getadvancedsearch returns SEARCH_STRING_REQUIRED when searchstring missing", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getadvancedsearch_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: {} };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "SEARCH_STRING_REQUIRED");
|
||||
});
|
||||
|
||||
test("getadvancedsearch returns INVALID_SEARCH_STRING when searchstring invalid JSON", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getadvancedsearch_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: { get: async () => ({ data: { value: [] } }) },
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = { query: { searchstring: "not-json" } };
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(res.state.jsonBody.error.code, "INVALID_SEARCH_STRING");
|
||||
});
|
||||
|
||||
test("getadvancedsearch catch path returns ADVANCED_SEARCH_FETCH_FAILED", async () => {
|
||||
const mod = loadModule("pages/api/endpoint/getadvancedsearch_api.js", {
|
||||
respondError: respondErrorMock,
|
||||
respondSuccess: respondSuccessMock,
|
||||
getToken: async () => ({ access_token: "token" }),
|
||||
hashAPIPath: () => "&hash=expected",
|
||||
azureHeadersPaged: () => ({}),
|
||||
axios: {
|
||||
get: async () => {
|
||||
throw new Error("relay failed");
|
||||
}
|
||||
},
|
||||
consoleLogger: () => {}
|
||||
});
|
||||
|
||||
const req = {
|
||||
query: {
|
||||
searchstring: encodeURI(
|
||||
JSON.stringify({ q: "cas", lpa: "l1", apt: "1" })
|
||||
)
|
||||
}
|
||||
};
|
||||
const res = createRes();
|
||||
await mod.default(req, res);
|
||||
|
||||
assert.strictEqual(res.state.statusCode, 400);
|
||||
assert.strictEqual(
|
||||
res.state.jsonBody.error.code,
|
||||
"ADVANCED_SEARCH_FETCH_FAILED"
|
||||
);
|
||||
});
|
||||
|
||||
const run = async () => {
|
||||
let passed = 0;
|
||||
for (const currentTest of tests) {
|
||||
|
||||
Reference in New Issue
Block a user