Guard card edits #98
Labels
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Grandiras/Ponente#98
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Only let authors and admins edit cards - not everyone. Also add comment editing and moderation. So basically real permissions and scopes.
🤖 On it — follow along in the action run; the reply will link the full session transcript.
📜 Live transcript — updating every ~5 minutes while the task runs.
Pushed as
claude/issue-98.What changed
Services/CardPermissions.csis the one place the rules live. It takes the sameBoardViewerBoardAccessdoes, because "a DID, and whether it administers this deployment" is the whole of what either question needs —BoardAccessdecides which boards you may see, this decides what you may do to the things on one. A second actor type built from the same allowlist snapshot would just be a second thing to keep in step.Two of those are deliberate refusals to over-guard. Moving a card changes which column it is in and not a word of what it says — locking that to the author would make a kanban board a wall of other people's cards nobody may sort. And an admin who could edit a comment could change what a member is recorded as having said, under that member's name and avatar; moderation takes something down, it does not rewrite it. Tags and assignees, by contrast, follow the card's own rule, because they are saved by the same button — a guard you can walk round by re-tagging is not a guard.
It is enforced in the services (
PermissionDeniedException, which the pages turn into translated copy), not only in the markup — that is the difference between a permission and a hidden button, and it is what catches a circuit that had the dialog open when the rights changed.BoardPage,CalendarandCommentListrebuild their viewer where they reload their data, so a demotion lands on a page that is already open rather than at the next reconnect.Comment editing adds
Comment.EditedAt(migrationAddCommentEditedAt, null for every comment that predates it, no backfill needed). It is stamped only on a real change, and shown beside the time — a reply underneath may be answering words that are no longer there.Somebody else's card, as an ordinary member — the fields are text, the save and delete buttons are gone, one note says why, and the discussion below is still theirs:
The same card for its author (an admin here), hovering the other member's comment — one action on it, and it is the removing one:
Verified
dotnet buildclean (one pre-existing nullability warning inCalendar.razor:287, untouched by this).dotnet test Ponente.sln— 282 passed, including the newCardPermissionsTestsand the existing en/de key-parity and changelog guards.tests/e2e/permissions.spec.jsflow run and passing against a real running instance (Release build, Postgres, migration applied on startup): read-only dialog for a non-author, comment posted and rewritten by its author with the "edited" mark appearing, the member's own card fully editable, an admin editing that card, and an admin moderating the member's comment away. The container has no runtime for the PDS or the compose stack, so the second member came from a row inMembersplus/dev/logininstead of a PDS signup; the committed spec usesaccess.spec.js'ssignUpMemberhelper as the suite requires, and everything else in it is what was exercised. It has not been run underglobal-setup/global-teardown.Two traps the spec documents, both hit while writing it: the comment box is a
textareainside.modal-bodytoo, so "no editable fields" has to be scoped to.composer; and a comment being edited stops matching ahasTextfilter, since a textarea's value is not text content — hencedata-comment-idon the article.Also added: a changelog entry for 2.6.0 in both locales, a Who may change what section in
CLAUDE.md, and a convention line that a new card/comment mutation takes aBoardViewerwith no default argument.⏱ 26m 55s · 104 turns · tokens: 213.5k in / 75.0k out (+17109.2k cache-read)
📜 Full session transcript
→ Opened PR: #100