Skip to content

Conversation

@UtkarshDixit-97
Copy link

6563

Resolves #6563

Supervisor and admins can now directly impersonate as volunteer and view the case details

You can login as supervisor , see a case details and directly click on "View/Edit" button and it will impersonate the said volunteer and take you to the view page page as that volunteer, then you can edit

  • Previously you used to click on edit (as supervisor) and it would take you to volunteer page and then you would had to impersonate and then find the case.
  • this makes workflow easier for supervisor and admin
  • Note - The workflow remains the same for volunteers, no change to them

Screenshots please :)

[Note - Video is attached, i suggest we rename the button to "Impersonate and View/edit", but for now as per original ticket , i have kept it simple and went ahead with original requirement of "View/Edit"]

2026-01-27-03-24-28.1.mp4

@github-actions github-actions bot added ruby Pull requests that update Ruby code erb labels Jan 27, 2026
compwron
compwron previously approved these changes Jan 28, 2026
Copy link
Collaborator

@compwron compwron left a comment

Choose a reason for hiding this comment

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

:)

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Improves the case contact workflow for supervisors/admins by adding a “View/Edit” action from the CASA Case Details page that impersonates the case contact’s author before navigating.

Changes:

  • Add a new case_contacts/impersonate_and_edit route and controller action to impersonate a volunteer from the case details workflow.
  • Update the case contact card partial to show a “View/Edit” link for supervisors/admins (instead of “Edit”) when acting on another user’s contact.
  • Update the view spec to assert the new link target.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

File Description
spec/views/case_contacts/case_contact.html.erb_spec.rb Updates the view spec expectation to match the new “View/Edit” link behavior.
config/routes.rb Adds a new route for the impersonation workflow entrypoint.
app/views/case_contacts/_case_contact.html.erb Changes the supervisor/admin action link from direct edit to impersonation-based “View/Edit”.
app/controllers/case_contacts_controller.rb Adds impersonate_and_edit action and volunteer lookup used by the new workflow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +80 to 86
it "shows view/edit button" do
assign :case_contact, case_contact
assign :casa_cases, [case_contact.casa_case]

render(partial: "case_contacts/case_contact", locals: {contact: case_contact})
expect(rendered).to have_link(nil, href: "/case_contacts/#{case_contact.id}/edit")
expect(rendered).to have_link(nil, href: "/case_contacts/impersonate_and_edit?creator_id=#{case_contact.creator.id}")
end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This spec asserts the impersonation URL without casa_case_id, but the partial builds the link using casa_case_id: @casa_case when it’s rendered from the case details page (the primary usage). As written, the spec passes even if @casa_case is accidentally missing, which would later cause the controller redirect to fail at runtime.

Assign @casa_case in the spec and assert the full generated href (preferably using the route helper), and also assert the visible link text (e.g., "View/Edit") to avoid matching an unrelated link.

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +69
def impersonate_and_edit
impersonate_user(@volunteer)

redirect_to casa_case_path(params[:casa_case_id])
end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

New behavior is introduced via impersonate_and_edit, but there’s no request/system spec covering it (especially authorization and the post-impersonation redirect behavior). The existing suite already has request coverage for CaseContactsController actions (e.g., spec/requests/case_contacts_spec.rb).

Add request specs for this endpoint for (1) authorized supervisor/admin, (2) unauthorized volunteer, and (3) cross-org volunteer id, so regressions in impersonation security/redirect behavior are caught.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Comment on lines +65 to +69
def impersonate_and_edit
impersonate_user(@volunteer)

redirect_to casa_case_path(params[:casa_case_id])
end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

impersonate_and_edit performs an impersonation without any Pundit authorization (and verify_authorized explicitly skips this action). This allows any authenticated user who can hit this endpoint to impersonate arbitrary volunteers by id, bypassing VolunteerPolicy#impersonate?.

Authorize the target user (e.g., authorize @volunteer, :impersonate?) and remove the action from the verify_authorized exception list so authorization is enforced consistently.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

def impersonate_and_edit
impersonate_user(@volunteer)

redirect_to casa_case_path(params[:casa_case_id])
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

Redirecting to casa_case_path(params[:casa_case_id]) after impersonation can fail because volunteers are only authorized to view cases they are actively assigned to (see CasaCasePolicy#show?). If the case contact was authored by a volunteer who is no longer actively assigned, the impersonated session will be blocked from the case details page, defeating the workflow.

Consider redirecting directly to the case contact edit flow (passing the case contact id) rather than the case details page, or otherwise ensuring the impersonated volunteer can access the target case.

Suggested change
redirect_to casa_case_path(params[:casa_case_id])
redirect_to case_contact_form_path(:details, case_contact_id: params[:id])

Copilot uses AI. Check for mistakes.
Comment on lines +109 to +111
def set_volunteer
@volunteer = Volunteer.find(params[:creator_id])
end
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

set_volunteer uses Volunteer.find(params[:creator_id]) with no scoping to the current organization. Combined with the missing authorization on impersonate_and_edit, this enables cross-organization impersonation by guessing ids.

Even with authorization added, it’s safer to scope the lookup (e.g., via policy_scope(Volunteer) or current_organization.volunteers) and to handle non-volunteer creators gracefully (since CaseContact#creator can be a Supervisor/CasaAdmin).

Copilot uses AI. Check for mistakes.
Copy link
Collaborator

Choose a reason for hiding this comment

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

@copilot open a new pull request to apply changes based on this feedback

Copy link
Collaborator

Choose a reason for hiding this comment

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

This is my first time seeing Copilot reviews so maybe I'm misunderstanding something. Why would we open a new PR instead of modifying this PR? I don't think we'd want to merge it without this change since its a security issue.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I would merge the new PR into this PR before merging this PR into main
This also allows multiple concurrent changes
Feel free to do the changes by hand instead if you prefer

Comment on lines +109 to +111
def set_volunteer
@volunteer = Volunteer.find(params[:creator_id])
end
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is my first time seeing Copilot reviews so maybe I'm misunderstanding something. Why would we open a new PR instead of modifying this PR? I don't think we'd want to merge it without this change since its a security issue.

<div class="mr-2">
<%= link_to edit_case_contact_path(contact), class: "text-danger", data: { turbo: false } do %>
<i class="lni lni-pencil-alt"></i> Edit
<% if (current_user.casa_admin? || current_user.supervisor?) && contact.creator&.volunteer? && contact.creator != current_user %>
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is there anywhere in the back end that we verify its only a CASA admin or supervisor submitting this request? We don't want a volunteer doing that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be in a "policy" file

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

Labels

erb ruby Pull requests that update Ruby code Tests! 🎉💖👏

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve case contact editing workflow for supervisors/admins

3 participants