Skip to content

feat: allow admins to upload attachments to tickets - #64

Merged
ikennot merged 1 commit into
developmentfrom
feat/admin-attachments
Apr 12, 2026
Merged

feat: allow admins to upload attachments to tickets#64
ikennot merged 1 commit into
developmentfrom
feat/admin-attachments

Conversation

@ikennot

@ikennot ikennot commented Apr 12, 2026

Copy link
Copy Markdown
Owner

Type of Change

  • feat — new feature
  • fix — bug fix
  • chore — maintenance, dependencies, config
  • docs — documentation only
  • refactor — code change that neither fixes a bug nor adds a feature
  • test — adding or updating tests

Labels

p2-medium feat security backend

What Changed

  • AttachmentController: opened POST /api/tickets/{id}/attachments to ADMIN role in addition to STUDENT
  • AttachmentService: gated ownership check, email-verified check, and admin notifications behind a isStudent flag; admins bypass these gates and can upload to any ticket
  • SecurityUtils: hardened getCurrentRole() — replaced fragile iterator().next() with an explicit stream search by ROLE_ prefix; added null guards on getAuthentication() in both getCurrentUserId() and getCurrentRole() to throw controlled AppException(401) instead of NPE
  • AttachmentService: added explicit unknown-role rejection (403) before the student/admin branching so no unexpected role can silently bypass ownership checks; added null-safe check on ticket.getUserId() before .equals()
  • Docs: updated roles-permissions.md and api-contract.md to reflect admin upload permission

Why

Admins needed the ability to attach supporting documents (e.g. resolution screenshots, policy PDFs) directly to tickets. The original implementation restricted uploads to students only. The fix also closes three security gaps found during code review: a fragile role-lookup that could silently mis-identify a role, an implicit role guard that any unknown role value could bypass, and a potential NPE on tickets with a null owner.

How to Test

  1. Authenticate as an admin and obtain a JWT
  2. POST /api/tickets/{id}/attachments with form-data key file pointing to a JPEG or PDF
  3. Expect 201 response with a signed URL in the payload
  4. Repeat with a student JWT on a ticket they do not own — expect 403 FORBIDDEN
  5. Repeat with an admin JWT on a CLOSED ticket — expect 403 TICKET_CLOSED

Related Issues

Screenshots

N/A

Checklist

  • Code follows the Google Java Style Guide
  • No business logic in controllers
  • Ownership + role checks are in the service layer
  • All responses use ApiResponse<T> wrapper
  • No secrets or credentials committed
  • application.yaml is NOT staged
  • CI passes

@ikennot
ikennot merged commit 4520d25 into development Apr 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant