feat(share,permissions): partage de page par groupes (page_shares)
- app/db.py: ajout colonne shared_with_group_id (FK user_groups, migration
backfill v5.x) dans page_shares
- app/routers/sharing.py: POST /api/pages/{id}/share accepte group_id
(upsert, verif FK groupe), GET /shares expose kind/group_name, synchro
bidirectionnelle avec page_permissions (mirror grant/revoke) pour que
PermissionManager donne un acces effectif (view/comment/edit) aux membres
du groupe; PUT/DELETE gardent le miroir a jour
- app/routers/board.py, library.py: received/made incluent les partages via
groupes (JOIN group_members)
- app/templates/_page_editor_content.html, _page_editor_scripts.html:
dialogue Share — invite groups (fetch /api/v2/groups, filtre deja partages),
pickInviteGroup, shareInvite(group_id), rendu accessList avec avatar groupe
- tests/test_share_groups.py: 10 tests (CRUD groupe, kind, miroir ACL)
Chore: inclut evolutions v6.4.0 deja en working copy (webhooks prod,
migrations, sync, config/main) pour garder l'arbre coherent.
This commit is contained in:
@@ -94,7 +94,27 @@
|
||||
<div class="sd-user-add">Invite</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="sd-user-empty" x-show="!inviteUsers.length">No matching users</div>
|
||||
<template x-if="inviteGroups && inviteGroups.length">
|
||||
<div>
|
||||
<div class="sd-user-empty" style="font-weight:600;">Groups</div>
|
||||
<template x-for="g in inviteGroups" :key="'g'+g.id">
|
||||
<div
|
||||
class="sd-user-item"
|
||||
@click="pickInviteGroup(g)"
|
||||
>
|
||||
<div class="sd-user-avatar" style="background:#5b5bd6;color:#fff;">
|
||||
<span x-text="(g.name || '?').charAt(0).toUpperCase()"></span>
|
||||
</div>
|
||||
<div class="sd-user-meta">
|
||||
<div class="sd-user-login" x-text="g.name"></div>
|
||||
<div class="sd-user-name" x-text="'Group · ' + (g.member_count || 0) + ' members'"></div>
|
||||
</div>
|
||||
<div class="sd-user-add">Invite</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<div class="sd-user-empty" x-show="!inviteUsers.length && !(inviteGroups && inviteGroups.length)">No matching users</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -113,17 +133,22 @@
|
||||
<div class="sd-avatar" x-show="a.user_avatar_url" style="overflow:hidden">
|
||||
<img :src="a.user_avatar_url" style="width:100%;height:100%;border-radius:50%;object-fit:cover;" />
|
||||
</div>
|
||||
<div class="sd-avatar" x-show="!a.user_avatar_url"
|
||||
<!-- Group avatar -->
|
||||
<div class="sd-avatar" x-show="(a.kind === 'group' || a.shared_with_group_id) && !a.user_avatar_url"
|
||||
style="background:#5b5bd6;color:#fff;"
|
||||
x-text="(a.group_name || '?')[0].toUpperCase()"
|
||||
></div>
|
||||
<div class="sd-avatar" x-show="!(a.kind === 'group' || a.shared_with_group_id) && !a.user_avatar_url"
|
||||
x-text="(a.user_full_name || a.user_login || a.shared_with_email || '?')[0].toUpperCase()"
|
||||
></div>
|
||||
<div>
|
||||
<div
|
||||
class="sd-participant-name"
|
||||
x-text="a.user_full_name || a.user_login || a.shared_with_email"
|
||||
x-text="(a.kind === 'group' || a.shared_with_group_id) ? (a.group_name || 'Group') : (a.user_full_name || a.user_login || a.shared_with_email)"
|
||||
></div>
|
||||
<div
|
||||
class="sd-participant-email"
|
||||
x-text="a.shared_with_email || a.user_login || ''"
|
||||
x-text="(a.kind === 'group' || a.shared_with_group_id) ? 'Group' : (a.shared_with_email || a.user_login || '')"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user