Skip to content

feat: use respondent mode for third parties#3783

Open
Mohamed-Hacene wants to merge 9 commits intomainfrom
feat/third-parties-journey
Open

feat: use respondent mode for third parties#3783
Mohamed-Hacene wants to merge 9 commits intomainfrom
feat/third-parties-journey

Conversation

@Mohamed-Hacene
Copy link
Copy Markdown
Collaborator

@Mohamed-Hacene Mohamed-Hacene commented Mar 26, 2026

Summary by CodeRabbit

  • New Features

    • Expanded permissions for third-party respondents to view and manage requirement assignments and comments.
    • Third-party actor visibility configuration now available through API parameters.
  • Improvements

    • Simplified questionnaire email call-to-action URLs for better user experience.
    • Automated requirement assignment status transitions during audit workflows.
    • Enhanced navigation and routing for third-party users.
  • Bug Fixes

    • Fixed welcome email capitalization.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 26, 2026

📝 Walkthrough

Walkthrough

This pull request extends third-party actor functionality across the system by expanding their permissions, simplifying questionnaire URLs, automating requirement assignment creation for audits, and reconfiguring navigation and routing to accommodate third-party users as distinct actors in the platform.

Changes

Cohort / File(s) Summary
Third-Party Permissions & Access Control
backend/core/startup.py, frontend/src/lib/components/SideBar/navData.ts
Expanded third-party respondent permissions to include requirement assignment and comment operations; added BI-RL-TPR exclusion to navigation items (myAssignments, xRays, and complianceAssessments) to hide third-party-irrelevant sections.
Email & URL Simplification
backend/core/templates/tprm/third_party_email.html, backend/iam/models.py, backend/locale/fr/LC_MESSAGES/django.po
Removed /table-mode path segment from questionnaire URLs in email templates and user mailing logic; updated welcome message capitalization from "Ciso Assistant" to "CISO Assistant" across English and French locales.
Requirement Assignment & Audit Data Flow
backend/core/views.py, backend/tprm/serializers.py, backend/tprm/migrations/0016_assign_third_parties_to_audits.py, backend/tprm/test/test_serializers.py
Added automatic RequirementAssignment creation during audit creation via serializer hook; introduced migration to backfill requirement assignments for existing audits; changed email template object identifier from "compliance-assessments" to "auditee-assessments"; added bulk status transition of draft requirement assignments to in-progress post-mailing.
Third-Party User Navigation & Routing
frontend/src/routes/(app)/(internal)/+layout.server.ts, frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/assignments/+page.svelte
Redirect third-party users from /compliance-assessments to /auditee-dashboard on login; updated actor selection to include third-party actors via configurable include_third_parties query parameter.
Frontend UI & Testing Updates
frontend/src/routes/(app)/(third-party)/auditee-assessments/[id=uuid]/+page.svelte, frontend/tests/utils/mailer.ts, frontend/tests/utils/test-utils.ts, frontend/tests/functional/detailed/tprm.test.ts
Added data-testid to evidence accordion trigger; introduced getEmailBySubject() method for targeted email retrieval; updated test fixtures and third-party workflow tests to reflect new dashboard routing, simplified card-view questionnaire answering (removing table-mode), and automated requirement assignment creation flows.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Third-parties now dance in the system's design,
With permissions expanded and URLs aligned,
Requirements assigned, audits backfilled with care,
Dashboard redirects guide them with flair,
The burrow grows richer, inclusivity's theme! 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 55.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: use respondent mode for third parties' accurately reflects the main objective of the changeset - enabling third-party users to use a dedicated respondent/questionnaire mode with corresponding permission updates, template changes, and UI adjustments.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/third-parties-journey

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Mohamed-Hacene Mohamed-Hacene marked this pull request as ready for review March 27, 2026 17:34
@Mohamed-Hacene Mohamed-Hacene added the db-migration This branch contains migration files. Caution should be exercised when merging to avoid conflicts. label Mar 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
backend/tprm/migrations/0016_assign_third_parties_to_audits.py (1)

48-52: Noop reverse operation prevents rollback.

Using migrations.RunPython.noop as the reverse means this migration cannot be rolled back, which will leave orphaned RequirementAssignment records if needed. Consider whether a reverse function that deletes assignments created by this migration would be appropriate for your deployment strategy.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/tprm/migrations/0016_assign_third_parties_to_audits.py` around lines
48 - 52, The migration uses
migrations.RunPython(assign_third_parties_to_existing_audits,
migrations.RunPython.noop) which prevents rollback; implement a proper reverse
function (e.g.,
delete_assignments_created_by_assign_third_parties_to_existing_audits) that
finds and deletes only the RequirementAssignment records created by
assign_third_parties_to_existing_audits (use a reversible marker such as a
specific metadata flag, creation timestamp window, or querying by the same
criteria used for creation), add that function to the file, and replace
migrations.RunPython.noop with that reverse function so the migration can be
rolled back safely.
frontend/tests/functional/detailed/tprm.test.ts (1)

247-264: Consider reducing reliance on hardcoded timeouts.

The waitForTimeout calls (lines 250, 261) are documented as flakiness workarounds, but hardcoded waits are generally fragile in E2E tests. If this continues to be flaky, consider waiting for a specific condition (e.g., network idle, element state change) instead.

That said, the current approach is pragmatic and the comment explains the rationale.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/tests/functional/detailed/tprm.test.ts` around lines 247 - 264, The
test currently uses hardcoded waits in clickAndPause and after clicking
nextButton which causes fragility; replace the timeouts by waiting for specific
UI conditions: modify the clickAndPause helper and the loop that advances
requirements to wait for the target element/state instead of page.waitForTimeout
— e.g., after clicking use Locator.waitFor({ state: 'visible' | 'attached' }) or
page.waitForLoadState('networkidle') and use nextButton.waitFor({ state:
'enabled' }) or check element.isEnabled() before interacting; update references
to clickAndPause and nextButton in the test to use these conditional waits so
interactions wait for the actual element visibility/enabled state rather than
fixed delays.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/core/views.py`:
- Around line 9888-9890: The bulk update on instance.requirement_assignments
(changing RequirementAssignment.Status.DRAFT -> IN_PROGRESS) bypasses the
RequirementAssignment transition path and may promote assignments whose actors
were never notified (e.g., when instance.authors is empty or an author lacks
mailing()), so replace the raw update() with the same per-assignment transition
used by RequirementAssignmentViewSet.set_status(): iterate only the assignments
whose actor was actually notified (use the mailing() check on each
author/actor), call the existing transition method on each RequirementAssignment
instance (instead of bulk update) so permissions, events and notification hooks
run, and reuse the shared set_status logic to keep behavior consistent.

In `@backend/tprm/serializers.py`:
- Around line 212-225: The _create_requirement_assignment method creates
RequirementAssignment instances without explicitly setting the status, causing
inconsistency with the migration which sets status="in_progress"; update the
RequirementAssignment.objects.create call in _create_requirement_assignment to
pass status="in_progress" so new assignments match the migration's state,
referencing the _create_requirement_assignment function and the
RequirementAssignment model to locate the change.

---

Nitpick comments:
In `@backend/tprm/migrations/0016_assign_third_parties_to_audits.py`:
- Around line 48-52: The migration uses
migrations.RunPython(assign_third_parties_to_existing_audits,
migrations.RunPython.noop) which prevents rollback; implement a proper reverse
function (e.g.,
delete_assignments_created_by_assign_third_parties_to_existing_audits) that
finds and deletes only the RequirementAssignment records created by
assign_third_parties_to_existing_audits (use a reversible marker such as a
specific metadata flag, creation timestamp window, or querying by the same
criteria used for creation), add that function to the file, and replace
migrations.RunPython.noop with that reverse function so the migration can be
rolled back safely.

In `@frontend/tests/functional/detailed/tprm.test.ts`:
- Around line 247-264: The test currently uses hardcoded waits in clickAndPause
and after clicking nextButton which causes fragility; replace the timeouts by
waiting for specific UI conditions: modify the clickAndPause helper and the loop
that advances requirements to wait for the target element/state instead of
page.waitForTimeout — e.g., after clicking use Locator.waitFor({ state:
'visible' | 'attached' }) or page.waitForLoadState('networkidle') and use
nextButton.waitFor({ state: 'enabled' }) or check element.isEnabled() before
interacting; update references to clickAndPause and nextButton in the test to
use these conditional waits so interactions wait for the actual element
visibility/enabled state rather than fixed delays.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a1f5f4fa-23ab-4797-9d0e-ad7d77800482

📥 Commits

Reviewing files that changed from the base of the PR and between f5ee641 and 8c35e4b.

📒 Files selected for processing (15)
  • backend/core/startup.py
  • backend/core/templates/tprm/third_party_email.html
  • backend/core/views.py
  • backend/iam/models.py
  • backend/locale/fr/LC_MESSAGES/django.po
  • backend/tprm/migrations/0016_assign_third_parties_to_audits.py
  • backend/tprm/serializers.py
  • backend/tprm/test/test_serializers.py
  • frontend/src/lib/components/SideBar/navData.ts
  • frontend/src/routes/(app)/(internal)/+layout.server.ts
  • frontend/src/routes/(app)/(third-party)/auditee-assessments/[id=uuid]/+page.svelte
  • frontend/src/routes/(app)/(third-party)/compliance-assessments/[id=uuid]/assignments/+page.svelte
  • frontend/tests/functional/detailed/tprm.test.ts
  • frontend/tests/utils/mailer.ts
  • frontend/tests/utils/test-utils.ts

Comment on lines +9888 to +9890
instance.requirement_assignments.filter(
status=RequirementAssignment.Status.DRAFT
).update(status=RequirementAssignment.Status.IN_PROGRESS)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Bulk status promotion here can activate unnotified assignments and skips workflow guards.

If instance.authors is empty—or an author was skipped above because they have no mailing() implementation—you still return success and move every draft assignment to in_progress. The raw update() also bypasses the normal RequirementAssignment transition path, so the dedicated permission, event creation, and notification hooks never run. Please transition only the assignments whose actors were actually notified, via shared logic extracted from RequirementAssignmentViewSet.set_status().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/core/views.py` around lines 9888 - 9890, The bulk update on
instance.requirement_assignments (changing RequirementAssignment.Status.DRAFT ->
IN_PROGRESS) bypasses the RequirementAssignment transition path and may promote
assignments whose actors were never notified (e.g., when instance.authors is
empty or an author lacks mailing()), so replace the raw update() with the same
per-assignment transition used by RequirementAssignmentViewSet.set_status():
iterate only the assignments whose actor was actually notified (use the
mailing() check on each author/actor), call the existing transition method on
each RequirementAssignment instance (instead of bulk update) so permissions,
events and notification hooks run, and reuse the shared set_status logic to keep
behavior consistent.

Comment on lines +212 to +225
def _create_requirement_assignment(self, audit, representatives):
"""Create a RequirementAssignment linking all requirement assessments to representative actors."""
actors = [rep.actor for rep in representatives if hasattr(rep, "actor")]
if not actors:
return
requirement_assessments = audit.requirement_assessments.all()
if not requirement_assessments.exists():
return
assignment = RequirementAssignment.objects.create(
compliance_assessment=audit,
folder=audit.folder,
)
assignment.actor.set(actors)
assignment.requirement_assessments.set(requirement_assessments)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing status field creates inconsistency with migration.

The migration (0016_assign_third_parties_to_audits.py) explicitly sets status="in_progress" when creating RequirementAssignment records, but this method relies on the model's default. This could lead to inconsistent states between newly created assignments and migrated ones.

Proposed fix to align status with migration
         assignment = RequirementAssignment.objects.create(
             compliance_assessment=audit,
             folder=audit.folder,
+            status="in_progress",
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/tprm/serializers.py` around lines 212 - 225, The
_create_requirement_assignment method creates RequirementAssignment instances
without explicitly setting the status, causing inconsistency with the migration
which sets status="in_progress"; update the RequirementAssignment.objects.create
call in _create_requirement_assignment to pass status="in_progress" so new
assignments match the migration's state, referencing the
_create_requirement_assignment function and the RequirementAssignment model to
locate the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

db-migration This branch contains migration files. Caution should be exercised when merging to avoid conflicts.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant