Skip to content

Sharing: role management and the notify-by-email toggle #58

Description

@Adron

Product behaviour (/help/documents)

Three permission levels:

Role Can
Read-only view content only
Edit change content, but not rename, change public/private, or move
Admin also rename, switch public/private, move, delete
  • Adding someone or changing their role sends an in-app notification and, by default, an email. An "Email this person" tick can be unticked to skip the email; delivery also depends on the recipient's own Sharing notification settings.
  • Only the true owner can add people, change roles or remove them — even an Admin collaborator cannot manage sharing.

Acceptance criteria

  • Role selector on add and on change, using the documented three levels.
  • An "Email this person" toggle on the add path, defaulting to on.
  • Sharing management is visible only to the owner; Admin collaborators see the roster read-only.
  • Role semantics are enforced in the app's own affordances (an Edit collaborator does not see rename/move/visibility controls).

Activity

  1. Adron commented on Sep 16, 2026

    @Adron
    MemberAuthor

    ⚠️ The role vocabulary in this issue is wrong — the API does not accept Read-only / Edit / Admin

    I wrote these issues from /help/documents, which describes three permission levels as Read-only, Edit and Admin. Those are display names. The API rejects them. Verified live 2026-09-16 on a throwaway list:

    role=read-only     -> 400 {"error":"Invalid role. Must be watcher, collaborator, or manager"}
    role=edit          -> 400 {"error":"Invalid role. Must be watcher, collaborator, or manager"}
    role=admin         -> 400 {"error":"Invalid role. Must be watcher, collaborator, or manager"}
    
    role=watcher       -> 201 {"email":"…","role":"watcher","expiresAt":null,"url":"…/lists/invite/OG72S9Ee…"}
    role=collaborator  -> 201 {"email":"…","role":"collaborator","expiresAt":null,"url":"…"}
    role=manager       -> 201 {"email":"…","role":"manager","expiresAt":null,"url":"…"}
    

    So the wire values are watcher / collaborator / manager, and any UI needs an explicit mapping to the documented labels:

    Wire value Help-doc label Can
    watcher Read-only view content only
    collaborator Edit change content, but not rename, change public/private, or move
    manager Admin also rename, switch visibility, move, delete

    Don't send the display names, and don't show the wire values to users.

    Other live findings from #55/#56 (PRs #168/#169) that affect these issues

    The invite envelopes are asymmetric, which forces a read-after-write:

    POST   …/invites  -> 201 {email, role, expiresAt, url}     ← url, NO token
    GET    …/invites  -> 200 {invites:[{email, role, expiresAt, accepted, createdAt, token}]}  ← token, NO url
    DELETE …/invites/{token} -> 200 {"revoked":true}
    

    Revoke is keyed by token, which the create response doesn't return — so creating an invite must be followed by a GET to obtain a revocable handle. Copy-link rebuilds the URL from the token.

    role works despite the published OpenAPI request schema omitting it — that schema lists only email + expiresAt. Another case of the spec being thinner than reality; /help/api/sharing is right and the spec is wrong.

    Error shapes: invalid email → 400 "A valid email address is required"; unknown token → 404 "Invite not found or access denied" (note: not-found and not-permitted are deliberately indistinguishable).

    Ownership envelopes differ between domains — lists nest the object under data, documents under document; both carry userId, which neither ListSummary nor DocumentSummary models.

    customerStatus values are free / subscriber / subscriber:monthly / subscriber:annual — any non-free value grants access, so don't compare against the literal "subscriber".

    An undocumented notify:false on invite create is accepted (201) but not echoed back. It was deliberately not exposed in the UI because there's no way to confirm it actually suppresses the email — which is exactly what #58's "Email this person" toggle needs. Confirming that flag is the blocker for #58's notify toggle, and it needs a mailbox you control to verify.

    Still unverified for #57

    The claim/accept side (/api/{lists|documents}/invite/{token}) is cookie-session-only per the docs and needs a second verified account, so it is unimplemented. That's the substance of #57.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Deptharea:sharingArea: sharingparityWeb/API feature-parity work

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions