-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
10 changed files
with
167 additions
and
3 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
"""Permissions for the dashboard app""" | ||
from rest_framework.permissions import BasePermission | ||
|
||
from futurex_openedx_extensions.dashboard.utils import get_accessible_tenants | ||
|
||
|
||
class OnlyAccessibleTenants(BasePermission): | ||
"""Validate that the user has access to the tenant IDs provided in the request""" | ||
def has_permission(self, request, view): | ||
"""Validation logic for the permission class""" | ||
tenant_ids = request.query_params.get('tenant_ids') | ||
if not tenant_ids: | ||
# No tenant_ids provided | ||
return False | ||
user = request.user | ||
accessible_tenants = get_accessible_tenants(user) | ||
|
||
# Extract tenant_ids from query parameters | ||
if tenant_ids: | ||
tenant_ids = [int(id) for id in tenant_ids.split(',')] | ||
else: | ||
# No tenant_ids provided | ||
self.message = 'No tenant IDs provided.' | ||
return False | ||
|
||
# Check which tenant_ids are not in the accessible tenants list | ||
inaccessible_tenants = [str(tid) for tid in tenant_ids if tid not in accessible_tenants] | ||
|
||
if inaccessible_tenants: | ||
# Generate a custom message with the inaccessible tenant IDs | ||
self.message = f'User does not have access to tenant IDs: {", ".join(inaccessible_tenants)}.' | ||
return False | ||
|
||
return True |
Empty file.
12 changes: 12 additions & 0 deletions
12
futurex_openedx_extensions/dashboard/statistics/learners.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
"""functions for getting statistics about learners""" | ||
from __future__ import annotations | ||
from typing import List | ||
|
||
|
||
def get_learners_count(tenant_ids: List[int]) -> int: | ||
""" | ||
Get the count of learners in a tenant. | ||
:param tenant_ids: List of tenant IDs to get the count for | ||
""" | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
"""Views for the dashboard app""" | ||
from rest_framework.views import APIView | ||
from rest_framework.response import Response | ||
from rest_framework import status | ||
|
||
from futurex_openedx_extensions.helpers.mixins import TenantsCheckMixin | ||
|
||
|
||
class TotalCountsView(TenantsCheckMixin): | ||
"""View to get the total count statistics""" | ||
def get(self, request, *args, **kwargs): | ||
"""Get the total count statistics""" | ||
|
||
# Proceed with your view logic if the permission check passes | ||
return Response({"message": "Access granted"}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
"""helpers Django application initialization""" | ||
|
||
from django.apps import AppConfig | ||
|
||
|
||
class HelpersConfig(AppConfig): | ||
"""Configuration for the helpers Django application""" | ||
|
||
name = 'helpers' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
"""Type conversion helpers""" | ||
from __future__ import annotations | ||
from typing import List | ||
|
||
|
||
def ids_string_to_list(ids_string: str) -> List[int]: | ||
"""Convert a comma-separated string of ids to a list of integers""" | ||
if not ids_string: | ||
return [] | ||
return [int(id_value.strip()) for id_value in ids_string.split(",") if id_value.strip()] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
"""Base views to be used by other views""" | ||
|
||
from django.http import JsonResponse | ||
from rest_framework.views import APIView | ||
from rest_framework import status | ||
from futurex_openedx_extensions.helpers.tenants import check_tenant_access | ||
|
||
|
||
class TenantsCheckMixin(APIView): | ||
"""Mixin for views that require tenant information""" | ||
def dispatch(self, request, *args, **kwargs): | ||
"""Check if the user has access to the tenant IDs provided""" | ||
has_access, details = check_tenant_access(request.user, request.query_params.get('tenant_ids')) | ||
|
||
if not has_access: | ||
return JsonResponse(details, status=status.HTTP_403_FORBIDDEN) | ||
return super().dispatch(request, *args, **kwargs) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
"""Tenant management helpers""" | ||
from __future__ import annotations | ||
|
||
from django.contrib.auth import get_user_model | ||
from eox_tenant.models import Route | ||
from typing import List | ||
from futurex_openedx_extensions.helpers.convertrers import ids_string_to_list | ||
from django.db.models import Count | ||
|
||
|
||
|
||
def get_all_tenants() -> List[int]: | ||
""" | ||
TODO: Cache the result of this function | ||
Get all tenants in the system that have at least one organization associated with them | ||
:return: List of all tenant IDs | ||
:rtype: List[int] | ||
""" | ||
return Route.objects.annotate( | ||
orgs_count=Count('config__organizations') | ||
).filter( | ||
orgs_count__gt=0 | ||
).values_list('id', flat=True) | ||
|
||
|
||
def get_accessible_tenants(user: get_user_model()) -> List[int]: | ||
""" | ||
Get the tenants that the user has access to. | ||
:param user: The user to check. | ||
:type user: get_user_model() | ||
:return: List of accessible tenant IDs | ||
:rtype: List[int] | ||
""" | ||
if user.is_superuser or user.is_staff: | ||
return get_all_tenants() | ||
return [] | ||
|
||
|
||
def check_tenant_access(user: get_user_model(), tenant_ids_string: str) -> tuple[bool, dict]: | ||
""" | ||
Check if the user has access to the tenant IDs provided. | ||
:param user: The user to check. | ||
:type user: get_user_model() | ||
:param tenant_ids_string: Comma-separated string of tenant IDs | ||
:type tenant_ids_string: str | ||
:return: Tuple of a boolean indicating if the user has access and a dictionary with details if access is denied | ||
""" | ||
try: | ||
tenant_ids = ids_string_to_list(tenant_ids_string) | ||
except ValueError as e: | ||
return False, {"reason": "Invalid tenant IDs provided", "details": { | ||
"error": str(e) | ||
}} | ||
|
||
accessible_tenants = get_accessible_tenants(user) | ||
inaccessible_tenants = [t_id for t_id in tenant_ids if t_id not in accessible_tenants] | ||
|
||
if inaccessible_tenants: | ||
return False, { | ||
"reason": "user does not have access to these tenants", | ||
"details": {"tenant_ids": inaccessible_tenants} | ||
} | ||
|
||
return True, {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters