-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: implementation with dynamic partition generator
- Loading branch information
1 parent
e800ae7
commit 7e1c023
Showing
9 changed files
with
348 additions
and
6 deletions.
There are no files selected for viewing
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
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
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
92 changes: 92 additions & 0 deletions
92
openedx/core/djangoapps/content/learning_sequences/api/processors/team_partition_groups.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,92 @@ | ||
""" | ||
Outline processors for applying team user partition groups. | ||
""" | ||
import logging | ||
from datetime import datetime | ||
from typing import Dict | ||
|
||
from opaque_keys.edx.keys import CourseKey | ||
|
||
from openedx.core import types | ||
from openedx.core.djangoapps.content.learning_sequences.api.processors.base import OutlineProcessor | ||
from openedx.core.djangoapps.course_groups.partition_generator import create_team_set_partition_with_course_id | ||
from openedx.core.djangoapps.course_groups.partition_scheme import CONTENT_GROUPS_FOR_TEAMS | ||
from xmodule.partitions.partitions import Group | ||
from xmodule.partitions.partitions_service import get_user_partition_groups | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
|
||
class TeamPartitionGroupsOutlineProcessor(OutlineProcessor): | ||
""" | ||
Processor for applying all team user partition groups. | ||
This processor is used to remove content from the course outline based on | ||
the user's team membership. It is used in the courseware API to remove | ||
content from the course outline before it is returned to the client. | ||
""" | ||
def __init__(self, course_key: CourseKey, user: types.User, at_time: datetime): | ||
super().__init__(course_key, user, at_time) | ||
self.team_groups: Dict[str, Group] = {} | ||
self.user_group = None | ||
|
||
def load_data(self, _) -> None: | ||
""" | ||
Pull team groups for this course and which group the user is in. | ||
""" | ||
user_partitions = create_team_set_partition_with_course_id(self.course_key) | ||
self.team_groups = get_user_partition_groups( | ||
self.course_key, | ||
user_partitions, | ||
self.user, | ||
partition_dict_key="id", | ||
) | ||
self.user_groups = [] | ||
for _, group in self.team_groups.items(): | ||
self.user_groups.append(group.id) | ||
|
||
def _is_user_excluded_by_partition_group(self, user_partition_groups): | ||
""" | ||
Is the user part of the group to which the block is restricting content? | ||
The user is excluded if the block is in a partition group, but the user | ||
is not in that group. | ||
""" | ||
if not CONTENT_GROUPS_FOR_TEAMS.is_enabled(self.course_key): | ||
return False | ||
|
||
if not user_partition_groups: | ||
return False | ||
|
||
if not self.user_groups: | ||
return False | ||
|
||
for partition_id, groups in user_partition_groups.items(): | ||
if partition_id not in self.team_groups: | ||
continue | ||
if self.team_groups[partition_id].id in groups: | ||
return False | ||
|
||
return True | ||
|
||
def usage_keys_to_remove(self, full_course_outline): | ||
""" | ||
Content group exclusions remove the content entirely. | ||
This method returns the usage keys of all content that should be | ||
removed from the course outline based on the user's team membership. | ||
""" | ||
removed_usage_keys = set() | ||
for section in full_course_outline.sections: | ||
remove_all_children = False | ||
if self._is_user_excluded_by_partition_group( | ||
section.user_partition_groups | ||
): | ||
removed_usage_keys.add(section.usage_key) | ||
remove_all_children = True | ||
for seq in section.sequences: | ||
if remove_all_children or self._is_user_excluded_by_partition_group( | ||
seq.user_partition_groups | ||
): | ||
removed_usage_keys.add(seq.usage_key) | ||
return removed_usage_keys |
74 changes: 74 additions & 0 deletions
74
openedx/core/djangoapps/course_groups/partition_generator.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,74 @@ | ||
""" | ||
The team dynamic partition generation to be part of the | ||
openedx.dynamic_partition plugin. | ||
""" | ||
import logging | ||
|
||
from django.conf import settings | ||
from django.utils.translation import gettext_lazy as _ | ||
from openedx.core.djangoapps.course_groups.partition_scheme import CONTENT_GROUPS_FOR_TEAMS | ||
|
||
from xmodule.partitions.partitions import UserPartition, UserPartitionError | ||
from xmodule.services import TeamsConfigurationService | ||
|
||
log = logging.getLogger(__name__) | ||
|
||
FEATURES = getattr(settings, 'FEATURES', {}) | ||
MINIMUM_DYNAMIC_TEAM_PARTITION_ID = 51 | ||
TEAM_SCHEME = "team" | ||
|
||
|
||
def create_team_set_partition_with_course_id(course_id, team_sets=None): | ||
""" | ||
Create and return the dynamic enrollment track user partition based only on course_id. | ||
If it cannot be created, None is returned. | ||
""" | ||
if not team_sets: | ||
team_sets = get_team_sets(course_id) or {} | ||
|
||
try: | ||
team_scheme = UserPartition.get_scheme(TEAM_SCHEME) | ||
except UserPartitionError: | ||
log.warning("No 'team' scheme registered, TeamUserPartition will not be created.") | ||
return None | ||
|
||
# Get team-sets from course and create user partitions for each team-set | ||
# Then get teams from each team-set and create user groups for each team | ||
partitions = [] | ||
for team_set in team_sets: | ||
partition = team_scheme.create_user_partition( | ||
id=team_set.dynamic_user_partition_id, | ||
name=f"Team set {team_set.name} groups", | ||
description=_("Partition for segmenting users by team-set"), | ||
parameters={ | ||
"course_id": str(course_id), | ||
"team_set_id": team_set.teamset_id, | ||
} | ||
) | ||
if partition: | ||
partitions.append(partition) | ||
|
||
return partitions | ||
|
||
|
||
def create_team_set_partition(course): | ||
""" | ||
Get the dynamic enrollment track user partition based on the team-sets of the course. | ||
""" | ||
if not CONTENT_GROUPS_FOR_TEAMS.is_enabled(course.id): | ||
return [] | ||
return create_team_set_partition_with_course_id( | ||
course.id, | ||
get_team_sets(course.id), | ||
) | ||
|
||
|
||
def get_team_sets(course_key): | ||
""" | ||
Get team-sets of the course. | ||
""" | ||
team_sets = TeamsConfigurationService().get_teams_configuration(course_key).teamsets | ||
if not team_sets: | ||
return None | ||
|
||
return team_sets |
Oops, something went wrong.