Skip to content

Commit

Permalink
refactor: use more options for course visible and active
Browse files Browse the repository at this point in the history
Refactor (only_visible and only_active) to (visible_filter and active_filter)
  • Loading branch information
shadinaif committed May 24, 2024
1 parent b5dbabb commit 0fc52d0
Show file tree
Hide file tree
Showing 11 changed files with 313 additions and 123 deletions.
14 changes: 8 additions & 6 deletions futurex_openedx_extensions/dashboard/details/courses.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@


def get_courses_queryset(
tenant_ids: List, search_text: str = None, only_visible: bool = True, only_active: bool = False
tenant_ids: List, search_text: str = None, visible_filter: bool = True, active_filter: bool = None
) -> QuerySet:
"""
Get the courses queryset for the given tenant IDs and search text.
Expand All @@ -24,16 +24,18 @@ def get_courses_queryset(
:type tenant_ids: List
:param search_text: Search text to filter the courses by
:type search_text: str
:param only_visible: Whether to only include courses that are visible in the catalog
:type only_visible: bool
:param only_active: Whether to only include active courses
:type only_active: bool
:param visible_filter: Whether to only include courses that are visible in the catalog
:type visible_filter: bool
:param active_filter: Whether to only include active courses
:type active_filter: bool
:return: QuerySet of courses
:rtype: QuerySet
"""
course_org_filter_list = get_course_org_filter_list(tenant_ids)['course_org_filter_list']

queryset = get_base_queryset_courses(course_org_filter_list, only_visible=only_visible, only_active=only_active)
queryset = get_base_queryset_courses(
course_org_filter_list, visible_filter=visible_filter, active_filter=active_filter,
)

search_text = (search_text or '').strip()
if search_text:
Expand Down
134 changes: 87 additions & 47 deletions futurex_openedx_extensions/dashboard/details/learners.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,86 @@

from typing import List

from common.djangoapps.student.models import CourseAccessRole, UserSignupSource
from common.djangoapps.student.models import CourseAccessRole
from django.contrib.auth import get_user_model
from django.db.models import Count, Exists, OuterRef, Q, Subquery
from django.db.models.query import QuerySet

from futurex_openedx_extensions.helpers.querysets import get_base_queryset_courses
from futurex_openedx_extensions.helpers.tenants import get_course_org_filter_list, get_tenant_site
from futurex_openedx_extensions.helpers.querysets import get_base_queryset_courses, get_has_site_login_queryset
from futurex_openedx_extensions.helpers.tenants import get_course_org_filter_list, get_tenants_sites


def get_courses_count_for_learner_queryset(
course_org_filter_list: List[str],
visible_courses_filter: bool = True,
active_courses_filter: bool = None,
) -> QuerySet:
"""
Get the courses count for the given learner.
:param course_org_filter_list: List of course organizations to filter by
:type course_org_filter_list: List[str]
:param visible_courses_filter: Value to filter courses on catalog visibility. None means no filter.
:type visible_courses_filter: bool
:param active_courses_filter: Value to filter courses on active status. None means no filter.
:type active_courses_filter: bool
:return: QuerySet of learners
:rtype: QuerySet
"""
return Count(
'courseenrollment',
filter=(
Q(courseenrollment__course_id__in=get_base_queryset_courses(
course_org_filter_list,
visible_filter=visible_courses_filter,
active_filter=active_courses_filter,
)) &
~Exists(
CourseAccessRole.objects.filter(
user_id=OuterRef('id'),
org=OuterRef('courseenrollment__course__org')
)
)
),
distinct=True
)


def get_certificates_count_for_learner_queryset(
course_org_filter_list: List[str],
visible_courses_filter: bool = True,
active_courses_filter: bool = None,
) -> QuerySet:
"""
Annotate the given queryset with the certificate counts.
:param course_org_filter_list: List of course organizations to filter by
:type course_org_filter_list: List[str]
:param visible_courses_filter: Value to filter courses on catalog visibility. None means no filter.
:type visible_courses_filter: bool
:param active_courses_filter: Value to filter courses on active status. None means no filter.
:type active_courses_filter: bool
:return: QuerySet of learners
:rtype: QuerySet
"""
return Count(
'generatedcertificate',
filter=(
Q(generatedcertificate__course_id__in=Subquery(
get_base_queryset_courses(
course_org_filter_list,
visible_filter=visible_courses_filter,
active_filter=active_courses_filter
).values_list('id', flat=True)
)) &
Q(generatedcertificate__status='downloadable')
),
distinct=True
)


def get_learners_queryset(
tenant_ids: List, search_text: str = None, only_visible_courses: bool = True, only_active_courses: bool = False
tenant_ids: List, search_text: str = None, visible_courses_filter: bool = True, active_courses_filter: bool = None
) -> QuerySet:
"""
Get the learners queryset for the given tenant IDs and search text.
Expand All @@ -22,18 +91,15 @@ def get_learners_queryset(
:type tenant_ids: List
:param search_text: Search text to filter the learners by
:type search_text: str
:param only_visible_courses: Whether to only count courses that are visible in the catalog
:type only_visible_courses: bool
:param only_active_courses: Whether to only count active courses
:type only_active_courses: bool
:param visible_courses_filter: Whether to only count courses that are visible in the catalog
:type visible_courses_filter: bool
:param active_courses_filter: Whether to only count active courses
:type active_courses_filter: bool
:return: QuerySet of learners
:rtype: QuerySet
"""
course_org_filter_list = get_course_org_filter_list(tenant_ids)['course_org_filter_list']
tenant_sites = []
for tenant_id in tenant_ids:
if site := get_tenant_site(tenant_id):
tenant_sites.append(site)
tenant_sites = get_tenants_sites(tenant_ids)

queryset = get_user_model().objects.filter(
is_superuser=False,
Expand All @@ -49,45 +115,19 @@ def get_learners_queryset(
)

queryset = queryset.annotate(
courses_count=Count(
'courseenrollment',
filter=(
Q(courseenrollment__course_id__in=get_base_queryset_courses(
course_org_filter_list,
only_visible=only_visible_courses,
only_active=only_active_courses,
)) &
~Exists(
CourseAccessRole.objects.filter(
user_id=OuterRef('id'),
org=OuterRef('courseenrollment__course__org')
)
)
),
distinct=True
courses_count=get_courses_count_for_learner_queryset(
course_org_filter_list,
visible_courses_filter=visible_courses_filter,
active_courses_filter=active_courses_filter,
)
).annotate(
certificates_count=Count(
'generatedcertificate',
filter=(
Q(generatedcertificate__course_id__in=Subquery(
get_base_queryset_courses(
course_org_filter_list,
only_visible=only_visible_courses,
only_active=only_active_courses
).values_list('id', flat=True)
)) &
Q(generatedcertificate__status='downloadable')
),
distinct=True
certificates_count=get_certificates_count_for_learner_queryset(
course_org_filter_list,
visible_courses_filter=visible_courses_filter,
active_courses_filter=active_courses_filter,
)
).annotate(
has_site_login=Exists(
UserSignupSource.objects.filter(
user_id=OuterRef('id'),
site__in=tenant_sites
)
)
has_site_login=get_has_site_login_queryset(tenant_sites)
).filter(
Q(courses_count__gt=0) | Q(has_site_login=True)
).select_related('profile').order_by('id')
Expand Down
14 changes: 7 additions & 7 deletions futurex_openedx_extensions/dashboard/statistics/certificates.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@


def get_certificates_count(
tenant_ids: List[int], only_visible_courses: bool = True, only_active_courses: bool = False
tenant_ids: List[int], visible_courses_filter: bool = True, active_courses_filter: bool = None
) -> Dict[str, int]:
"""
Get the count of issued certificates in the given tenants. The count is grouped by organization. Certificates
for admins, staff, and superusers are also included.
:param tenant_ids: List of tenant IDs to get the count for
:type tenant_ids: List[int]
:param only_visible_courses: Whether to only count courses that are visible in the catalog
:type only_visible_courses: bool
:param only_active_courses: Whether to only count active courses (according to dates)
:type only_active_courses: bool
:param visible_courses_filter: Value to filter courses on catalog visibility. None means no filter.
:type visible_courses_filter: bool
:param active_courses_filter: Value to filter courses on active status. None means no filter.
:type active_courses_filter: bool
:return: Count of certificates per organization
:rtype: Dict[str, int]
"""
Expand All @@ -33,8 +33,8 @@ def get_certificates_count(
status='downloadable',
course_id__in=get_base_queryset_courses(
course_org_filter_list,
only_visible=only_visible_courses,
only_active=only_active_courses,
visible_filter=visible_courses_filter,
active_filter=active_courses_filter,
),
).annotate(course_org=Subquery(
CourseOverview.objects.filter(
Expand Down
28 changes: 16 additions & 12 deletions futurex_openedx_extensions/dashboard/statistics/courses.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,46 +12,50 @@
from futurex_openedx_extensions.helpers.tenants import get_course_org_filter_list


def get_courses_count(tenant_ids: List[int], only_visible: bool = True, only_active: bool = False) -> QuerySet:
def get_courses_count(tenant_ids: List[int], visible_filter: bool = True, active_filter: bool = None) -> QuerySet:
"""
Get the count of courses in the given tenants
:param tenant_ids: List of tenant IDs to get the count for
:type tenant_ids: List[int]
:param only_visible: Whether to only count courses that are visible in the catalog
:type only_visible: bool
:param only_active: Whether to only count active courses (according to dates)
:type only_active: bool
:param visible_filter: Value to filter courses on catalog visibility. None means no filter.
:type visible_filter: bool
:param active_filter: Value to filter courses on active status. None means no filter.
:type active_filter: bool
:return: QuerySet of courses count per organization
:rtype: QuerySet
"""
course_org_filter_list = get_course_org_filter_list(tenant_ids)['course_org_filter_list']

q_set = get_base_queryset_courses(course_org_filter_list, only_visible=only_visible, only_active=only_active)
q_set = get_base_queryset_courses(
course_org_filter_list, visible_filter=visible_filter, active_filter=active_filter
)

return q_set.values('org').annotate(
courses_count=Count('id')
).order_by('org')


def get_courses_count_by_status(
tenant_ids: List[int], only_visible: bool = True, only_active: bool = False
tenant_ids: List[int], visible_filter: bool = True, active_filter: bool = None
) -> QuerySet:
"""
Get the count of courses in the given tenants by status
:param tenant_ids: List of tenant IDs to get the count for
:type tenant_ids: List[int]
:param only_visible: Whether to only count courses that are visible in the catalog
:type only_visible: bool
:param only_active: Whether to only count active courses (according to dates)
:type only_active: bool
:param visible_filter: Whether to only count courses that are visible in the catalog
:type visible_filter: bool
:param active_filter: Whether to only count active courses (according to dates)
:type active_filter: bool
:return: QuerySet of courses count per organization and status
:rtype: QuerySet
"""
course_org_filter_list = get_course_org_filter_list(tenant_ids)['course_org_filter_list']

q_set = get_base_queryset_courses(course_org_filter_list, only_visible=only_visible, only_active=only_active)
q_set = get_base_queryset_courses(
course_org_filter_list, visible_filter=visible_filter, active_filter=active_filter
)

q_set = q_set.annotate(
status=Case(
Expand Down
Loading

0 comments on commit 0fc52d0

Please sign in to comment.