Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #3544 +/- ##
===========================================
+ Coverage 73.76% 77.91% +4.15%
===========================================
Files 148 156 +8
Lines 10841 12109 +1268
===========================================
+ Hits 7997 9435 +1438
+ Misses 2844 2674 -170 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
1cd0a80 to
7c1bf5e
Compare
7c1bf5e to
98c998b
Compare
…-level-perms # Conflicts: # helpdesk/helpdesk/doctype/hd_ticket/hd_ticket.json # helpdesk/patches.txt
|
Tick the box to add this pull request to the merge queue (same as
|
|
A stale base could undo a restriction the admin set while the field was listed. Removal now restores the base only when that raises the level, so exposing a removed field always takes Customize Form.
The template refuses to show key at any permission level, since it authenticates guest feedback links. The migration also lifts shown custom fields below the visible level to 7, still never lowering.
The Default template used to write custom-field permission levels directly, which raced with Customize Form and needed a base_permlevel column to undo it. Permission levels now stay a static security floor; the template's visible_to tier only narrows what each role sees on helpdesk pages, enforced by the HDTicket read override and the app's own endpoints. Agent-only fields are dropped from hardcoded portal rows via a _hidden_fields list, and a cosmetic patch backfills visible_to on rows that predate the column.
creation_fillable_template_fields keyed on hide_from_customer, the flag synced from visible_to. Read the tier directly so the write path uses the same source of truth as the rest of the field-visibility code.
- prune permlevel-hidden fields in hidden_ticket_fields, so every caller drops both sets and not just the template tier - keep the contact card when raised_by is hidden - let a portal reply reopen a replied or resolved ticket - let the closing email's rating reach the closed ticket - keep the merge link when the agent has no write at the internal level - stop treating System Manager as an agent - refuse renaming the Default template Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JwkkywUhXWkgjQuf5ad9XV
Custom DocPerm rows make Frappe ignore the JSON perms, so these sites never get the new permlevel grants and read the protected fields as empty. - write the level 7 and 8 rows for roles that can already read a ticket - add the customer roles, which a June 2026 JSON-only change never gave them - hide template rows the validator would refuse to save after the backfill Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JwkkywUhXWkgjQuf5ad9XV
get_fields_meta already strips agent-only rows for customers, so the three portal filters never removed anything. Visibility now has one owner on the server and the payload no longer carries visible_to.
The warning tells an admin to raise a permission level but not what that means. The link opens in a new tab so an unsaved template is not lost.
creation_fillable_template_fields -> customer_fillable_template_fields, customer_may_fill_at_creation -> can_customer_fill_at_creation, and the permlevel tuple they read to match.
tearDown runs before every addCleanup, so the deletions no longer need a wrapper that switches back to Administrator first.
`hidden_ticket_fields`, `unreadable_fields` and `fields_visible_to` were the only noun-named fetchers beside seventy-odd `get_` ones, including the framework's `get_permitted_fields` they wrap. The docstring on `get_hidden_ticket_fields` restated the new name, so it states the contract instead. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGwyVdR1M2WGd9bex8TxRR
`get_list_data` looked the hidden set up twice and filtered `rows` twice: once before the query, and again after the standard fields loop put `_assign` back. Compute it once, keep hidden standard fields out of that loop, and drop the `fields` cleanup pass. The set is `hidden_fields` at every site now; `hidden` named an adjective. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGwyVdR1M2WGd9bex8TxRR
The result became role-dependent, so the cache went `user=True`. That splits one entry into one per user, and `clear_cache()` only reaches the calling user's key, so a Visible to change left everyone else stale for an hour. The frontend fetches this once per session under frappe-ui's own cache, so nothing is lost. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UGwyVdR1M2WGd9bex8TxRR
| frappe.get_all( | ||
| "HD Ticket Template Field", | ||
| pluck="fieldname", | ||
| filters={ | ||
| "parent": DEFAULT_TICKET_TEMPLATE, | ||
| "parenttype": "HD Ticket Template", | ||
| "visible_to": audience, | ||
| }, |
There was a problem hiding this comment.
Permission-Aware Queries Required
The new visibility lookup uses frappe.get_all(), as does customer_fillable_template_fields() in hd_ticket.py. This violates the repository directive to prefer permission-aware frappe.get_list() for new code, so the requirement must be satisfied before merging.
Context Used: AGENTS.md (source)
Prompt To Fix With AI
This is a comment left during a code review.
Path: helpdesk/field_visibility.py
Line: 54-61
Comment:
**Permission-Aware Queries Required**
The new visibility lookup uses `frappe.get_all()`, as does `customer_fillable_template_fields()` in `hd_ticket.py`. This violates the repository directive to prefer permission-aware `frappe.get_list()` for new code, so the requirement must be satisfied before merging.
**Context Used:** AGENTS.md ([source](https://github.com/frappe/helpdesk/blob/develop/AGENTS.md))
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Problem
From the portal a customer could set agent-only fields on their own ticket —
priority,sla,response_by— withfrappe.client.set_value, and fakeraised_by,contactorcustomerat creation.Fix
/api/resourceincluded. 1–6 stay free for a site's own scheme.prevent_customer_edits()invalidate. Levels can't cover this: a customer needs level-0 write just to create a ticket. They keepfeedback,feedback_extraand closing the ticket.subject,status,description,template,attachment,content_type,feedback,feedback_extra,feedback_ratingraised_by,contact,customer,priority,ticket_type,agent_group,sla,status_category,response_by,resolution_by,on_hold_since,first_response_time,first_responded_on,first_response_failed_by,resolution_date,resolution_time,resolution_failed_bykey,summary,resolution_details,agreement_status,service_level_agreement_creation,opening_date,opening_time,avg_response_time,total_hold_time,user_resolution_time,raised_outside_working_hours,last_agent_response,last_customer_response,email_account,via_customer_portal,is_merged,merged_with,ticket_split_fromAlso fixes the fallout of hiding fields: portal reply no longer reopening a ticket, the closing-email rating link, 500 on tickets with no contact, merge losing
is_merged, blank list columns and filters that raisedPermissionError, Default template rename, and an agent's whole-document save blanking hidden fields.Breaking changes
hide_from_customeris replaced by Visible to; a patch carries old values over. Update anything reading the flag.raised_byforced to their own address andvia_customer_portalset. System Manager keeps full field access through the new level-7/8 perm rows.Existing sites
harden_hd_ticket_field_permissionswrites the level-7/8 perm rows (a singleCustom DocPermrow makes Frappe ignore shipped perms, so a customised site would read every protected field as empty — agents too).backfill_template_field_visible_tomoves oldhide_from_customervalues across. Both idempotent, neither writes a field's level.Testing
118 tests in
test_hd_ticket.py, 20 intest_field_visibility.py, 2 intest_hd_email_feedback.py.