Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
marcospri committed Dec 16, 2024
1 parent 4d5d4de commit 684450a
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 deletions.
40 changes: 39 additions & 1 deletion lms/services/dashboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@
)
from lms.models.dashboard_admin import DashboardAdmin
from lms.security import Permissions
from lms.services import OrganizationService, RosterService, UserService
from lms.services import OrganizationService, RosterService, UserService, SegmentService


class DashboardService:
def __init__( # noqa: PLR0913, PLR0917
self,
request,
segment_service: SegmentService,
assignment_service,
course_service,
roster_service: RosterService,
Expand All @@ -33,6 +34,7 @@ def __init__( # noqa: PLR0913, PLR0917
):
self._db = request.db

self._segment_service = segment_service
self._assignment_service = assignment_service
self._course_service = course_service
self._roster_service = roster_service
Expand Down Expand Up @@ -211,10 +213,46 @@ def get_assignment_roster(
# Always return the results, no matter the source, sorted
return roster_last_updated, query.order_by(LMSUser.display_name, LMSUser.id)

def get_segment_roster(
self, authority_provided_id: str, h_userids: list[str] | None = None
) -> Select[tuple[LMSUser, bool]]:
"""Return a query that fetches the roster for a segment."""
segment = self._segment_service.get_segment(authority_provided_id)
rosters_enabled = (
segment
and segment.lms_course
and segment.lms_course.course.application_instance.settings.get(
"dashboard", "rosters"
)
)
roster_last_updated = self._roster_service.segment_roster_exists(segment)
if rosters_enabled and roster_last_updated:
# If rostering is enabled and we do have the data, use it
query = self._roster_service.get_segment_roster(
segment,
role_scope=RoleScope.COURSE,
role_type=RoleType.LEARNER,
h_userids=h_userids,
)

else:
# Always fallback to fetch users that have launched the assignment at some point
query = self._user_service.get_users_for_segment(
role_scope=RoleScope.COURSE,
role_type=RoleType.LEARNER,
segment_id=segment.id,
h_userids=h_userids,
# For launch data we always add the "active" column as true for compatibility with the roster query.
).add_columns(True)

# Always return the results, no matter the source, sorted
return query.order_by(LMSUser.display_name, LMSUser.id)


def factory(_context, request):
return DashboardService(
request=request,
segment_service=request.find_service(SegmentService),
assignment_service=request.find_service(name="assignment"),
course_service=request.find_service(name="course"),
organization_service=request.find_service(OrganizationService),
Expand Down
43 changes: 42 additions & 1 deletion lms/services/roster.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,27 @@ def assignment_roster_exists(self, assignment: Assignment) -> datetime | None:
.limit(1)
)

def segment_roster_exists(self, segment: LMSSegment) -> datetime | None:
"""
Check if we have roster data for the given segment.
In case we have roster data, return the last updated timestamp, None otherwise.
"""
return self._db.scalar(
select(LMSSegmentRoster.updated)
.where(LMSSegmentRoster.lms_segment_id == segment.id)
.order_by(LMSSegmentRoster.updated.desc())
.limit(1)
)

def get_assignment_roster(
self,
assignment: Assignment,
role_scope: RoleScope | None = None,
role_type: RoleType | None = None,
h_userids: list[str] | None = None,
) -> Select[tuple[LMSUser, bool]]:
"""Get the roster information for a course from our DB."""
"""Get the roster information for an assignment from our DB."""
roster_query = (
select(LMSUser, AssignmentRoster.active)
.join(LMSUser, AssignmentRoster.lms_user_id == LMSUser.id)
Expand All @@ -104,6 +117,34 @@ def get_assignment_roster(

return roster_query

def get_segment_roster(
self,
segment: LMSSegment,
role_scope: RoleScope | None = None,
role_type: RoleType | None = None,
h_userids: list[str] | None = None,
) -> Select[tuple[LMSUser, bool]]:
"""Get the roster information for a segment from our DB."""

roster_query = (
(select(LMSUser, LMSSegmentRoster.active).join(LMSUser))
.join(LMSSegmentRoster, LMSSegmentRoster.lms_user_id == LMSUser.id)
.join(LTIRole, LTIRole.id == LMSSegmentRoster.lti_role_id)
.where(LMSSegmentRoster.lms_segment_id == segment.id)
.distinct()
)

if role_scope:
roster_query = roster_query.where(LTIRole.scope == role_scope)

if role_type:
roster_query = roster_query.where(LTIRole.type == role_type)

if h_userids:
roster_query = roster_query.where(LMSUser.h_userid.in_(h_userids))

return roster_query

def fetch_course_roster(self, lms_course: LMSCourse) -> None:
"""Fetch the roster information for a course from the LMS."""
assert (
Expand Down
8 changes: 8 additions & 0 deletions lms/services/segment.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ def __init__(self, db, group_set_service: GroupSetService):
self._db = db
self._group_set_service = group_set_service

def get_segment(self, authority_provided_id: str) -> LMSSegment | None:
"""Get a segment by its authority_provided_id."""
return (
self._db.query(LMSSegment)
.filter_by(h_authority_provided_id=authority_provided_id)
.one_or_none()
)

def upsert_segments(
self,
course: LMSCourse,
Expand Down
10 changes: 10 additions & 0 deletions lms/views/dashboard/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,16 @@ def _students_query(
h_userids: list[str] | None = None,
) -> tuple[datetime | None, Select]:
course_ids = self.request.parsed_params.get("course_ids")

# Single segment fetch
if segment_authority_provided_ids and len(segment_authority_provided_ids) == 1:
# TODO SEGMETN CHECK

return self.dashboard_service.get_segment_roster(
segment_authority_provided_id=segment_authority_provided_ids,
h_userids=h_userids,
)

# Single assigment fetch
if (
assignment_ids
Expand Down

0 comments on commit 684450a

Please sign in to comment.