Skip to content

Commit

Permalink
feat: more detailed taxonomies permission rules (openedx#33413)
Browse files Browse the repository at this point in the history
  • Loading branch information
rpenido authored Oct 19, 2023
1 parent 1d58bd1 commit 2482dd4
Show file tree
Hide file tree
Showing 13 changed files with 1,377 additions and 640 deletions.
8 changes: 7 additions & 1 deletion openedx/core/djangoapps/content_tagging/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,24 @@ def create_taxonomy(
enabled=True,
allow_multiple=False,
allow_free_text=False,
orgs: list[Organization] | None = None,
) -> Taxonomy:
"""
Creates, saves, and returns a new Taxonomy with the given attributes.
"""
return oel_tagging.create_taxonomy(
taxonomy = oel_tagging.create_taxonomy(
name=name,
description=description,
enabled=enabled,
allow_multiple=allow_multiple,
allow_free_text=allow_free_text,
)

if orgs is not None:
set_taxonomy_orgs(taxonomy=taxonomy, all_orgs=False, orgs=orgs)

return taxonomy


def set_taxonomy_orgs(
taxonomy: Taxonomy,
Expand Down
76 changes: 74 additions & 2 deletions openedx/core/djangoapps/content_tagging/rest_api/v1/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,92 @@
API Filters for content tagging org
"""

from django.db.models import Exists, OuterRef, Q
from rest_framework.filters import BaseFilterBackend

import openedx_tagging.core.tagging.rules as oel_tagging
from organizations.models import Organization

from ...rules import get_admin_orgs, get_user_orgs
from ...models import TaxonomyOrg


class UserOrgFilterBackend(BaseFilterBackend):
"""
Filter taxonomies based on user's orgs roles
Taxonomy admin can see all taxonomies
Everyone else can see only enabled taxonomies
Org staff can see all taxonomies from their orgs
Content creators and instructors can see enabled taxonomies avaliable to their orgs
"""

def filter_queryset(self, request, queryset, _):
if oel_tagging.is_taxonomy_admin(request.user):
return queryset

orgs = list(Organization.objects.all())
user_admin_orgs = get_admin_orgs(request.user, orgs)
user_orgs = get_user_orgs(request.user, orgs) # Orgs that the user is a content creator or instructor

if len(user_orgs) == 0 and len(user_admin_orgs) == 0:
return queryset.none()

return queryset.filter(
# Get enabled taxonomies available to all orgs, or from orgs that the user is
# a content creator or instructor
Q(
Exists(
TaxonomyOrg.objects
.filter(
taxonomy=OuterRef("pk"),
rel_type=TaxonomyOrg.RelType.OWNER,
)
.filter(
Q(org=None) |
Q(org__in=user_orgs)
)
),
enabled=True,
) |
# Get all taxonomies from orgs that the user is OrgStaff
Q(
Exists(
TaxonomyOrg.objects
.filter(taxonomy=OuterRef("pk"), rel_type=TaxonomyOrg.RelType.OWNER)
.filter(org__in=user_admin_orgs)
)
)
)


class ObjectTagTaxonomyOrgFilterBackend(BaseFilterBackend):
"""
Filter for ObjectTagViewSet to only show taxonomies that the user can view.
"""

def filter_queryset(self, request, queryset, _):
if oel_tagging.is_taxonomy_admin(request.user):
return queryset

return queryset.filter(enabled=True)
orgs = list(Organization.objects.all())
user_admin_orgs = get_admin_orgs(request.user, orgs)
user_orgs = get_user_orgs(request.user, orgs)
user_or_admin_orgs = list(set(user_orgs) | set(user_admin_orgs))

return queryset.filter(taxonomy__enabled=True).filter(
# Get ObjectTags from taxonomies available to all orgs, or from orgs that the user is
# a OrgStaff, content creator or instructor
Q(
Exists(
TaxonomyOrg.objects
.filter(
taxonomy=OuterRef("taxonomy_id"),
rel_type=TaxonomyOrg.RelType.OWNER,
)
.filter(
Q(org=None) |
Q(org__in=user_or_admin_orgs)
)
)
)
)
Loading

0 comments on commit 2482dd4

Please sign in to comment.