Skip to content

feat(proposals): speakers can see and edit their talk proposals - #274

Merged
harshtandiya merged 7 commits into
developfrom
feat/speaker-proposal-visibility
Jul 23, 2026
Merged

feat(proposals): speakers can see and edit their talk proposals#274
harshtandiya merged 7 commits into
developfrom
feat/speaker-proposal-visibility

Conversation

@harshtandiya

Copy link
Copy Markdown
Collaborator

Problem

Guest form submissions store submitted_by (and owner) as Guest. The dashboard listed proposals by submitted_by = session.user, and the if_owner DocPerm restricted reads to owner = user — so speakers who submitted as guest and created an account later could never see or edit their proposals, even though their email is right there in the speakers child table.

Fix

Visibility now derives from the speakers child table (any listed speaker email), plus submitter/owner:

  • Row-level access via hookspermission_query_conditions scopes list queries, has_permission guards single-document read/write. System Manager / Event Manager stay unrestricted. Replaces the if_owner restriction on Buzz User (which hooks cannot override and which blocked guest-owned docs).
  • buzz.api.proposals.get_my_proposals — typed (pydantic) endpoint returning proposals where the session user is submitter or listed speaker, so the dashboard tab stays personal even for managers who can read everything.
  • ProposalsList.vue — swaps useList + submitted_by filter for the new API.

Tests

TDD — 10 new integration tests (test_talk_proposal.py, test_proposals.py) covering speaker read/write/list on guest-submitted proposals, submitter-without-speaker-row, non-speaker denial, and manager access. buzz.api.test_forms still green.

Note: speaker emails are self-reported on guest forms, so anyone listed as speaker gains view/edit on that proposal — same trust level as the form itself, flagged as a conscious call.

🤖 Generated with Claude Code

harshtandiyaand others added 3 commits July 22, 2026 20:12
Guest form submissions leave owner/submitted_by as Guest, so speakers
could never see their own proposals. Row-level access now derives from
the speakers child table: permission_query_conditions scopes list
queries and a has_permission hook guards single documents, replacing
the if_owner restriction on Buzz User.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Returns proposals where the session user is the submitter or a listed
speaker, so the dashboard list stays personal even for roles that can
read all proposals. Rows are validated through a pydantic model.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
useList with a submitted_by filter missed guest-submitted proposals and
co-speaker talks; the API scopes rows to submitter-or-speaker
server-side.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@greptile-apps

greptile-appsBot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR lets registered speakers view and edit talk proposals submitted as guests. The main changes are:

  • Adds proposal list and document permission hooks based on submitter, owner, speaker email, and manager roles.
  • Adds a typed endpoint for proposals associated with the current user.
  • Updates the dashboard to use the new endpoint and a user-scoped cache key.
  • Adds integration tests for speaker, submitter, manager, unrelated-user, and mixed-case email access.

Confidence Score: 5/5

This looks safe to merge.

  • The proposal cache now includes the current session user.
  • Mixed-case speaker access is covered across document and list permissions.
  • The personal-proposals endpoint covers speaker, submitter, and unrelated-user cases.
  • No blocking issues were found in the updated code.

Important Files Changed

FilenameOverview
buzz/proposals/doctype/talk_proposal/talk_proposal.pyAdds query and document permission checks for submitters, owners, speakers, and managers.
buzz/api/proposals.pyAdds a typed endpoint returning proposals submitted by or associated with the current user.
buzz/hooks.pyRegisters the new Talk Proposal permission hooks.
dashboard/src/pages/ProposalsList.vueUses the personal-proposals endpoint and scopes its resource cache by session user.
dashboard/src/pages/Account.vueMakes the Talk Proposals tab available without a submitter-only precheck.
buzz/proposals/doctype/talk_proposal/test_talk_proposal.pyAdds permission tests for speakers, submitters, managers, unrelated users, and mixed-case emails.
buzz/api/test_proposals.pyAdds endpoint tests for proposal visibility and response shape.

Reviews (4): Last reviewed commit: "Merge branch 'develop' into feat/speaker..." | Re-trigger Greptile

Comment threaddashboard/src/pages/ProposalsList.vue Outdated
Comment threadbuzz/proposals/doctype/talk_proposal/talk_proposal.py Outdated
Comment threadbuzz/api/proposals.py
harshtandiyaand others added 3 commits July 22, 2026 20:20
The Talk Proposals tab is always shown, so the useList existed only for
a commented-out conditional and needlessly delayed the unknown-tab
redirect settle check.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Speaker email match in has_permission is now case-insensitive: user
emails are stored lowercase while guest-entered speaker emails keep
their casing. The proposals list cache key is scoped to the session
user again so a user switch cannot serve stale rows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@harshtandiya

Copy link
Copy Markdown
CollaboratorAuthor

Review findings actioned in 2b9f5c3:

  • Cache lacks user scope — fixed, cache key is ["proposals-list", session.user] again.
  • Email case blocks speaker access — confirmed real for the doc-level check (User emails are stored lowercase, guest-entered speaker emails keep their casing; the Python comparison was case-sensitive). Fixed with case-insensitive match + regression test. The SQL side already matched via MariaDB's ci collation — proven by the new test's get_list assertion.
  • Empty speaker set reaches IN filter — not reproducible: test_excludes_unrelated_proposals runs exactly this path (user with zero Proposal Speaker rows) and passes; Frappe's query builder handles empty in-lists. Skipping the guard.

🤖 Generated with Claude Code

@harshtandiyaharshtandiya added the backport main backport to main branch label Jul 23, 2026
@harshtandiya
harshtandiya merged commit 45a7887 into developJul 23, 2026
8 checks passed
@harshtandiya
harshtandiya deleted the feat/speaker-proposal-visibility branch July 23, 2026 04:51
@github-actions

Copy link
Copy Markdown
Contributor

Backport branch created but failed to create PR.
Request to create PR rejected with status 403.

(see action log for full response)

@harshtandiyaharshtandiya added backport main backport to main branch and removed backport main backport to main branch labels Jul 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Successfully created backport PR for main:

harshtandiya added a commit that referenced this pull request Jul 23, 2026
feat(proposals): speakers can see and edit their talk proposals (#274)
* feat(proposals): let speakers access talk proposals via speaker email
Guest form submissions leave owner/submitted_by as Guest, so speakers
could never see their own proposals. Row-level access now derives from
the speakers child table: permission_query_conditions scopes list
queries and a has_permission hook guards single documents, replacing
the if_owner restriction on Buzz User.
* feat(api): add get_my_proposals endpoint with typed response
Returns proposals where the session user is the submitter or a listed
speaker, so the dashboard list stays personal even for roles that can
read all proposals. Rows are validated through a pydantic model.
* feat(dashboard): list proposals via get_my_proposals API
useList with a submitted_by filter missed guest-submitted proposals and
co-speaker talks; the API scopes rows to submitter-or-speaker
server-side.
* chore(dashboard): drop unused proposals fetch from Account page
The Talk Proposals tab is always shown, so the useList existed only for
a commented-out conditional and needlessly delayed the unknown-tab
redirect settle check.
* chore(dashboard): inline Talk Proposals tab into static tab list
* fix(proposals): address review findings on speaker access
Speaker email match in has_permission is now case-insensitive: user
emails are stored lowercase while guest-entered speaker emails keep
their casing. The proposals list cache key is scoped to the session
user again so a user switch cannot serve stale rows.
---------
(cherry picked from commit 45a7887)
Co-authored-by: Harsh Tandiya <harsh.tandiya@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport mainbackport to main branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@harshtandiya