nice
This commit is contained in:
parent
8ec0397288
commit
d1872e7c7d
@ -128,3 +128,21 @@ class SharesTests(TestCase):
|
||||
users=self.client.get('/api/drive/admin/users/',{'q':'alice-admin-list'})
|
||||
self.assertEqual(users.status_code,200,users.data)
|
||||
self.assertEqual(users.data['users'][0]['space_name'],self.root.display_name)
|
||||
|
||||
def test_members_never_lists_viewer_as_direct_added_user(self):
|
||||
"""Hide redundant grants for the viewer or space owner, not real guests."""
|
||||
User = get_user_model()
|
||||
delegate = User.objects.create_user('delegate', password='ComplexPassword123!')
|
||||
guest = User.objects.create_user('real-guest', password='ComplexPassword123!')
|
||||
SpaceGrant.objects.create(space=self.root, user=self.admin, can_invite=True)
|
||||
SpaceGrant.objects.create(space=self.root, user=delegate, can_invite=True)
|
||||
SpaceGrant.objects.create(space=self.root, user=guest)
|
||||
|
||||
response = self.client.get('/api/drive/spaces/members/', {'parent_space': self.root.pk})
|
||||
self.assertEqual(response.status_code, 200, response.data)
|
||||
self.assertEqual({g['user_id'] for g in response.data['grants']}, {delegate.pk, guest.pk})
|
||||
|
||||
self.client.force_authenticate(user=delegate)
|
||||
response = self.client.get('/api/drive/spaces/members/', {'parent_space': self.root.pk})
|
||||
self.assertEqual(response.status_code, 200, response.data)
|
||||
self.assertEqual([g['user_id'] for g in response.data['grants']], [guest.pk])
|
||||
|
||||
@ -93,9 +93,14 @@ def members(request):
|
||||
if not manager(request.user,parent):return error('Gestion des invitations non autorisée.',403)
|
||||
children=DriveSpace.objects.filter(parent=parent,private_owner__isnull=True).select_related('user','parent').order_by('id')
|
||||
invitations=SpaceInvitation.objects.filter(parent_space=parent).order_by('-created_at')[:100]
|
||||
# Existing memberships of the viewer/space manager are not directly added users.
|
||||
excluded_ids = {request.user.pk, parent.user_id, parent.managed_by_id}
|
||||
grants = (SpaceGrant.objects.filter(space=parent)
|
||||
.exclude(user_id__in=[pk for pk in excluded_ids if pk is not None])
|
||||
.select_related('user').order_by('user__username'))
|
||||
return Response({'parent':space_info(parent,request.user),
|
||||
'children':[space_info(c,request.user) for c in children if not c.private_owner_id],
|
||||
'grants':[grant_info(g) for g in SpaceGrant.objects.filter(space=parent).select_related('user').order_by('user__username')],
|
||||
'grants':[grant_info(g) for g in grants],
|
||||
'invitations':[invitation_info(i) for i in invitations]})
|
||||
|
||||
|
||||
|
||||
@ -42,10 +42,8 @@ export default function DriveExplorer({ controller, user }) {
|
||||
|
||||
<div className="mb-5 flex flex-wrap items-end justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="mb-2 flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
{isTrash
|
||||
? <span className="px-1">Tous les espaces accessibles</span>
|
||||
: <button onClick={goRoot} className="rounded px-1 py-1 hover:bg-muted">{view === 'shared' ? 'Partagés avec moi' : activeSpace?.is_private ? 'Mes fichiers' : activeSpace?.display_name || 'Mes fichiers'}</button>}
|
||||
{!isTrash && <div className="mb-2 flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<button onClick={goRoot} className="rounded px-1 py-1 hover:bg-muted">{view === 'shared' ? 'Partagés avec moi' : activeSpace?.is_private ? 'Mes fichiers' : activeSpace?.display_name || 'Mes fichiers'}</button>
|
||||
{(view === 'files' || view === 'shared') && !search && trail.map(folder => (
|
||||
<React.Fragment key={folder.id}>
|
||||
<ChevronRight className="size-3.5" />
|
||||
@ -56,7 +54,7 @@ export default function DriveExplorer({ controller, user }) {
|
||||
<ChevronRight className="size-3.5" />
|
||||
<span>{headerNames[view]}</span>
|
||||
</>}
|
||||
</div>
|
||||
</div>}
|
||||
<h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
|
||||
<p className="mt-1 text-sm text-muted-foreground">
|
||||
{loading ? 'Chargement…' : `${items.length} élément${items.length > 1 ? 's' : ''}`}
|
||||
|
||||
@ -43,6 +43,11 @@ export default function MembersPage({ controller, user, embedded = false }) {
|
||||
const selectedManagedSpace = managed.find(space => space.id === parentId)
|
||||
// Never render stale information from a previously selected parent space.
|
||||
const selectedRecord = record?.parent?.id === parentId ? record : null
|
||||
// An account must never appear among its own directly added members.
|
||||
const directGrants = (selectedRecord?.grants || []).filter(grant =>
|
||||
Number(grant.user_id) !== Number(user.id) &&
|
||||
Number(grant.user_id) !== Number(selectedRecord.parent.user_id)
|
||||
)
|
||||
const managedKey = managed.map(space => space.id).join(',')
|
||||
useEffect(() => { if (managedSpaceId) setParentId(managedSpaceId) }, [managedSpaceId])
|
||||
useEffect(() => {
|
||||
@ -178,8 +183,8 @@ export default function MembersPage({ controller, user, embedded = false }) {
|
||||
<label className="flex items-center gap-2 text-sm"><Checkbox disabled={!selectedManagedSpace?.can_invite} checked={directRights.can_invite} onCheckedChange={v=>setDirectRights(prev=>({...prev,can_invite:!!v}))}/> Autoriser la gestion des utilisateurs de cet espace</label>
|
||||
<Button disabled={busy} onClick={addExisting}>Ajouter cet utilisateur</Button>
|
||||
</div>}
|
||||
{!!selectedRecord?.grants?.length && <div className="space-y-2 border-t pt-3"><h3 className="text-sm font-semibold">Utilisateurs ajoutés directement</h3>
|
||||
{record.grants.map(g=><DirectMember key={g.id} grant={g} maxRights={selectedManagedSpace} busy={busy} save={data=>updateGrant(g.id,data)} remove={()=>revokeGrant(g.id)}/>)}
|
||||
{!!directGrants.length && <div className="space-y-2 border-t pt-3"><h3 className="text-sm font-semibold">Utilisateurs ajoutés directement</h3>
|
||||
{directGrants.map(g=><DirectMember key={g.id} grant={g} maxRights={selectedManagedSpace} busy={busy} save={data=>updateGrant(g.id,data)} remove={()=>revokeGrant(g.id)}/>)}
|
||||
</div>}
|
||||
</div>
|
||||
<div className="rounded-2xl border bg-card p-5 space-y-4">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user