Skip to content

Fix link reach/role and add ancestors link access info #846

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
80eb392
🐛(backend) fix link definition select options linked to ancestors
sampaccoud Apr 6, 2025
8d05a85
✨(backend) add ancestors links definitions to document abilities
sampaccoud Apr 6, 2025
3d8500c
♻️(backend) remove different reach for authenticated and anonymous
sampaccoud Apr 11, 2025
6023f69
♻️(backend) refactor resource access viewset
sampaccoud Apr 12, 2025
7960869
♻️(backend) factorize document query set annotation
sampaccoud Apr 12, 2025
866aef8
✨(backend) we want to display ancestors accesses on a document share
sampaccoud Apr 12, 2025
0821f78
✨(backend) give an order to choices
sampaccoud Apr 23, 2025
938fea7
♻️(backend) refactor get_select_options to take definitions dict
sampaccoud Apr 24, 2025
b28d13d
✅(backend) fix randomly failing test on user search
sampaccoud May 2, 2025
a635f9c
♻️(backend) simplify roles by returning only the max role
sampaccoud Apr 25, 2025
3d189dc
✨(backend) add ancestors link reach and role to document API
sampaccoud Apr 28, 2025
4ec03e6
✨(backend) add computed link reach and role to document API
sampaccoud Apr 28, 2025
f913a38
♻️(backend) optimize refactoring access abilities and fix inheritance
sampaccoud May 2, 2025
1a619c4
✨(backend) add max ancestors role field to document access endpoint
sampaccoud May 2, 2025
43481db
♻️(backend) stop requiring owner for non-root documents
sampaccoud May 4, 2025
806f61c
✅(backend) fix randomly failing test due to delay before check
sampaccoud May 4, 2025
5f8af4e
🐛(backend) allow creating accesses when privileged by heritage
sampaccoud May 6, 2025
e74d05f
✨(backend) add document path and depth to accesses endpoint
sampaccoud May 7, 2025
1db8794
🐛(backend) fix creating/updating document accesses for teams
sampaccoud May 7, 2025
0302be0
♻️(backend) simplify further select options on link reach/role
sampaccoud May 9, 2025
23cf004
✨(backend) add max_role field to the document access API endpoint
sampaccoud May 13, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ and this project adheres to

## Added

- ✨(backend) include ancestors accesses on document accesses list view #846
- ✨(backend) add ancestors links reach and role to document API #846
- 🚸(backend) make document search on title accent-insensitive #874
- 🚩 add homepage feature flag #861
- 📝(doc) update contributing policy (commit signatures are now mandatory) #895
Expand All @@ -48,12 +50,15 @@ and this project adheres to

## Changed

- ♻️(backend) stop requiring owner for non-root documents #846
- ♻️(backend) simplify roles by ranking them and return only the max role #846
- ⚡️(frontend) reduce unblocking time for config #867
- ♻️(frontend) bind UI with ability access #900
- ♻️(frontend) use built-in Quote block #908

## Fixed

- 🐛(backend) fix link definition select options linked to ancestors #846
- 🐛(nginx) fix 404 when accessing a doc #866
- 🔒️(drf) disable browsable HTML API renderer #919
- 🔒(frontend) enhance file download security #889
Expand Down
84 changes: 75 additions & 9 deletions src/backend/core/api/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from rest_framework import permissions

from core import choices
from core.models import DocumentAccess, RoleChoices, get_trashbin_cutoff

ACTION_FOR_METHOD_TO_PERMISSION = {
Expand Down Expand Up @@ -96,26 +97,27 @@ def has_permission(self, request, view):
).exists()


class AccessPermission(permissions.BasePermission):
"""Permission class for access objects."""
class ResourceWithAccessPermission(permissions.BasePermission):
"""A permission class for templates."""

def has_permission(self, request, view):
"""check create permission for templates."""
return request.user.is_authenticated or view.action != "create"

def has_object_permission(self, request, view, obj):
"""Check permission for a given object."""
abilities = obj.get_abilities(request.user)
action = view.action
try:
action = ACTION_FOR_METHOD_TO_PERMISSION[view.action][request.method]
except KeyError:
pass
return abilities.get(action, False)


class DocumentAccessPermission(AccessPermission):
class DocumentPermission(permissions.BasePermission):
"""Subclass to handle soft deletion specificities."""

def has_permission(self, request, view):
"""check create permission for documents."""
return request.user.is_authenticated or view.action != "create"

def has_object_permission(self, request, view, obj):
"""
Return a 404 on deleted documents
Expand All @@ -127,10 +129,74 @@ def has_object_permission(self, request, view, obj):
) and deleted_at < get_trashbin_cutoff():
raise Http404

# Compute permission first to ensure the "user_roles" attribute is set
has_permission = super().has_object_permission(request, view, obj)
abilities = obj.get_abilities(request.user)
action = view.action
try:
action = ACTION_FOR_METHOD_TO_PERMISSION[view.action][request.method]
except KeyError:
pass

has_permission = abilities.get(action, False)

if obj.ancestors_deleted_at and not RoleChoices.OWNER in obj.user_roles:
raise Http404

return has_permission


class DocumentAccessPermission(IsAuthenticated):
"""Permission class for document access objects."""

def has_permission(self, request, view):
"""check create permission for accesses in documents tree."""
if super().has_permission(request, view) is False:
return False

if view.action == "create":
role = view.document.get_role(request.user)
if role not in choices.PRIVILEGED_ROLES:
raise exceptions.PermissionDenied(
"You are not allowed to manage accesses for this resource."
)

return True

def has_object_permission(self, request, view, obj):
"""Check permission for a given object."""
abilities = obj.get_abilities(request.user)

requested_role = request.data.get("role")
if requested_role and requested_role not in abilities.get("set_role_to", []):
return False

action = view.action
return abilities.get(action, False)


class TemplateAccessPermission(IsAuthenticated):
"""Permission class for template access objects."""

def has_permission(self, request, view):
"""check create permission for template accesses."""
if super().has_permission(request, view) is False:
return False

if view.action == "create":
roles = view.template.get_roles(request.user)
if not set(roles).intersection(set(choices.PRIVILEGED_ROLES)):
raise exceptions.PermissionDenied(
"You are not allowed to manage accesses for this template."
)

return True

def has_object_permission(self, request, view, obj):
"""Check permission for a given object."""
abilities = obj.get_abilities(request.user)

requested_role = request.data.get("role")
if requested_role and requested_role not in abilities.get("set_role_to", []):
return False

action = view.action
return abilities.get(action, False)
Loading
Loading