learning-paths-plugin 0.3.4rc4__tar.gz → 0.3.4rc6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/CHANGELOG.rst +5 -0
- {learning_paths_plugin-0.3.4rc4/learning_paths_plugin.egg-info → learning_paths_plugin-0.3.4rc6}/PKG-INFO +6 -1
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/__init__.py +1 -1
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/serializers.py +1 -1
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/views.py +27 -2
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/compat.py +4 -6
- learning_paths_plugin-0.3.4rc6/learning_paths/migrations/0014_learningpathenrollmentallowed_is_active.py +20 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/models.py +6 -3
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/receivers.py +4 -1
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6/learning_paths_plugin.egg-info}/PKG-INFO +6 -1
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths_plugin.egg-info/SOURCES.txt +1 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/LICENSE.txt +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/MANIFEST.in +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/README.rst +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/admin.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/__init__.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/urls.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/__init__.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/filters.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/permissions.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/urls.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/utils.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/apps.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/conftest.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/keys.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0001_initial.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0002_learningpath_uuid.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0003_learningpath_subtitle.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0004_auto_20240207_1633.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0005_learningpathstep_weight_learningpathgradingcriteria.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0006_enrollment_models.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0007_replace_uuid_with_learningpathkey.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0008_remove_learningpathstep_relative_due_date_in_days.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0009_remove_learningpath_slug.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0010_learningpath_invite_only.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0011_replace_learningpath_image_url_with_image.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0012_alter_learningpath_subtitle.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/0013_enrollment_audit.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/migrations/__init__.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/settings.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/templates/learning_paths/base.html +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/urls.py +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths_plugin.egg-info/dependency_links.txt +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths_plugin.egg-info/entry_points.txt +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths_plugin.egg-info/not-zip-safe +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths_plugin.egg-info/requires.txt +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths_plugin.egg-info/top_level.txt +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/pyproject.toml +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/requirements/base.in +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/requirements/constraints.txt +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/setup.cfg +0 -0
- {learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/setup.py +0 -0
|
@@ -25,6 +25,11 @@ Added
|
|
|
25
25
|
* Bulk unenrollment API.
|
|
26
26
|
* Enrollment audit model that tracks the enrollment state transitions.
|
|
27
27
|
|
|
28
|
+
Changed
|
|
29
|
+
=======
|
|
30
|
+
|
|
31
|
+
* The Learning Paths API includes start and end dates for its steps.
|
|
32
|
+
|
|
28
33
|
0.3.3 - 2025-05-23
|
|
29
34
|
******************
|
|
30
35
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-paths-plugin
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4rc6
|
|
4
4
|
Summary: Learning Paths plugin
|
|
5
5
|
Home-page: https://github.com/open-craft/learning-paths-plugin
|
|
6
6
|
Author: OpenCraft
|
|
@@ -129,6 +129,11 @@ Added
|
|
|
129
129
|
* Bulk unenrollment API.
|
|
130
130
|
* Enrollment audit model that tracks the enrollment state transitions.
|
|
131
131
|
|
|
132
|
+
Changed
|
|
133
|
+
=======
|
|
134
|
+
|
|
135
|
+
* The Learning Paths API includes start and end dates for its steps.
|
|
136
|
+
|
|
132
137
|
0.3.3 - 2025-05-23
|
|
133
138
|
******************
|
|
134
139
|
|
|
@@ -97,7 +97,7 @@ class LearningPathGradeSerializer(serializers.Serializer):
|
|
|
97
97
|
class LearningPathStepSerializer(serializers.ModelSerializer):
|
|
98
98
|
class Meta:
|
|
99
99
|
model = LearningPathStep
|
|
100
|
-
fields = ["order", "course_key", "
|
|
100
|
+
fields = ["order", "course_key", "course_dates", "weight"]
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
class LearningPathListSerializer(serializers.ModelSerializer):
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/views.py
RENAMED
|
@@ -452,12 +452,13 @@ class BulkEnrollView(APIView):
|
|
|
452
452
|
`role` (str, optional): User role, used for audit.
|
|
453
453
|
|
|
454
454
|
* For existing users, it deactivates their LearningPathEnrollment records.
|
|
455
|
-
*
|
|
455
|
+
* For emails with active LearningPathEnrollmentAllowed records, it deactivates those records.
|
|
456
456
|
|
|
457
457
|
"""
|
|
458
|
-
learning_paths, existing_users,
|
|
458
|
+
learning_paths, existing_users, emails = self._setup_bulk_operation(request)
|
|
459
459
|
|
|
460
460
|
enrollments_unenrolled = []
|
|
461
|
+
enrollment_allowed_deactivated = []
|
|
461
462
|
|
|
462
463
|
for learning_path in learning_paths:
|
|
463
464
|
for user in existing_users:
|
|
@@ -474,9 +475,33 @@ class BulkEnrollView(APIView):
|
|
|
474
475
|
enrollment._audit = audit_data # pylint: disable=protected-access
|
|
475
476
|
enrollment.save()
|
|
476
477
|
|
|
478
|
+
for email in emails:
|
|
479
|
+
try:
|
|
480
|
+
validate_email(email)
|
|
481
|
+
except ValidationError:
|
|
482
|
+
logger.warning("BulkEnrollView: Invalid email: %s", email)
|
|
483
|
+
continue
|
|
484
|
+
|
|
485
|
+
enrollment_allowed = LearningPathEnrollmentAllowed.objects.filter(
|
|
486
|
+
email=email,
|
|
487
|
+
learning_path=learning_path,
|
|
488
|
+
).first()
|
|
489
|
+
|
|
490
|
+
if enrollment_allowed:
|
|
491
|
+
if enrollment_allowed.is_active:
|
|
492
|
+
state_transition = LearningPathEnrollmentAudit.ALLOWEDTOENROLL_TO_UNENROLLED
|
|
493
|
+
enrollment_allowed.is_active = False
|
|
494
|
+
enrollment_allowed_deactivated.append(enrollment_allowed)
|
|
495
|
+
else:
|
|
496
|
+
state_transition = LearningPathEnrollmentAudit.UNENROLLED_TO_UNENROLLED
|
|
497
|
+
audit_data = self._create_audit_data(request, state_transition)
|
|
498
|
+
enrollment_allowed._audit = audit_data # pylint: disable=protected-access
|
|
499
|
+
enrollment_allowed.save()
|
|
500
|
+
|
|
477
501
|
return Response(
|
|
478
502
|
{
|
|
479
503
|
"enrollments_unenrolled": len(enrollments_unenrolled),
|
|
504
|
+
"enrollment_allowed_deactivated": len(enrollment_allowed_deactivated),
|
|
480
505
|
},
|
|
481
506
|
status=status.HTTP_204_NO_CONTENT,
|
|
482
507
|
)
|
|
@@ -46,18 +46,16 @@ def get_course_keys_with_outlines() -> list[CourseKey]:
|
|
|
46
46
|
return course_keys_with_outlines()
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def
|
|
50
|
-
"""
|
|
51
|
-
Retrieve course end date.
|
|
52
|
-
"""
|
|
49
|
+
def get_course_dates(course_key: CourseKey) -> tuple[datetime | None, datetime | None]:
|
|
50
|
+
"""Retrieve course start and end dates."""
|
|
53
51
|
# pylint: disable=import-outside-toplevel, import-error
|
|
54
52
|
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
|
|
55
53
|
|
|
56
54
|
try:
|
|
57
55
|
overview = CourseOverview.objects.get(id=course_key)
|
|
58
|
-
return overview.end
|
|
56
|
+
return overview.start, overview.end
|
|
59
57
|
except CourseOverview.DoesNotExist:
|
|
60
|
-
return None
|
|
58
|
+
return None, None
|
|
61
59
|
|
|
62
60
|
|
|
63
61
|
def enroll_user_in_course(user: AbstractBaseUser, course_key: CourseKey) -> bool:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-05-30 19:57
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("learning_paths", "0013_enrollment_audit"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name="learningpathenrollmentallowed",
|
|
15
|
+
name="is_active",
|
|
16
|
+
field=models.BooleanField(
|
|
17
|
+
db_index=True, default=True, help_text="Indicates if the enrollment allowance is active"
|
|
18
|
+
),
|
|
19
|
+
),
|
|
20
|
+
]
|
|
@@ -19,7 +19,7 @@ from model_utils.models import TimeStampedModel
|
|
|
19
19
|
from opaque_keys.edx.django.models import CourseKeyField
|
|
20
20
|
from slugify import slugify
|
|
21
21
|
|
|
22
|
-
from .compat import
|
|
22
|
+
from .compat import get_course_dates, get_user_course_grade
|
|
23
23
|
from .keys import LearningPathKeyField
|
|
24
24
|
|
|
25
25
|
log = logging.getLogger(__name__)
|
|
@@ -203,9 +203,9 @@ class LearningPathStep(TimeStampedModel):
|
|
|
203
203
|
)
|
|
204
204
|
|
|
205
205
|
@property
|
|
206
|
-
def
|
|
206
|
+
def course_dates(self) -> tuple[datetime | None, datetime | None]:
|
|
207
207
|
"""Retrieve the due date for this course."""
|
|
208
|
-
return
|
|
208
|
+
return get_course_dates(self.course_key)
|
|
209
209
|
|
|
210
210
|
def __str__(self):
|
|
211
211
|
"""User-friendly string representation of this model."""
|
|
@@ -372,6 +372,9 @@ class LearningPathEnrollmentAllowed(TimeStampedModel):
|
|
|
372
372
|
email = models.EmailField(db_index=True)
|
|
373
373
|
learning_path = models.ForeignKey(LearningPath, on_delete=models.CASCADE)
|
|
374
374
|
user = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
|
|
375
|
+
is_active = models.BooleanField(
|
|
376
|
+
default=True, db_index=True, help_text=_("Indicates if the enrollment allowance is active")
|
|
377
|
+
)
|
|
375
378
|
|
|
376
379
|
def __str__(self):
|
|
377
380
|
"""User-friendly string representation of this model."""
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/receivers.py
RENAMED
|
@@ -39,7 +39,7 @@ def process_pending_enrollments(sender, instance, created, **kwargs):
|
|
|
39
39
|
return
|
|
40
40
|
|
|
41
41
|
logger.info("[LearningPaths] Processing pending enrollments for user %s", instance)
|
|
42
|
-
pending_enrollments = LearningPathEnrollmentAllowed.objects.filter(email=instance.email)
|
|
42
|
+
pending_enrollments = LearningPathEnrollmentAllowed.objects.filter(email=instance.email, is_active=True)
|
|
43
43
|
enrollments_created = 0
|
|
44
44
|
|
|
45
45
|
for entry in pending_enrollments:
|
|
@@ -67,6 +67,7 @@ def process_pending_enrollments(sender, instance, created, **kwargs):
|
|
|
67
67
|
entry.learning_path.key,
|
|
68
68
|
)
|
|
69
69
|
finally:
|
|
70
|
+
entry.is_active = False
|
|
70
71
|
entry.user = instance
|
|
71
72
|
entry.save()
|
|
72
73
|
|
|
@@ -129,6 +130,8 @@ def create_enrollment_allowed_audit(sender, instance, created, **kwargs):
|
|
|
129
130
|
if not (audit_data := getattr(instance, "_audit", {})):
|
|
130
131
|
return
|
|
131
132
|
|
|
133
|
+
audit_data.setdefault("state_transition", LearningPathEnrollmentAudit.UNENROLLED_TO_ALLOWEDTOENROLL)
|
|
134
|
+
|
|
132
135
|
audit_data["state_transition"] = audit_data.get(
|
|
133
136
|
"state_transition", LearningPathEnrollmentAudit.UNENROLLED_TO_ALLOWEDTOENROLL
|
|
134
137
|
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-paths-plugin
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4rc6
|
|
4
4
|
Summary: Learning Paths plugin
|
|
5
5
|
Home-page: https://github.com/open-craft/learning-paths-plugin
|
|
6
6
|
Author: OpenCraft
|
|
@@ -129,6 +129,11 @@ Added
|
|
|
129
129
|
* Bulk unenrollment API.
|
|
130
130
|
* Enrollment audit model that tracks the enrollment state transitions.
|
|
131
131
|
|
|
132
|
+
Changed
|
|
133
|
+
=======
|
|
134
|
+
|
|
135
|
+
* The Learning Paths API includes start and end dates for its steps.
|
|
136
|
+
|
|
132
137
|
0.3.3 - 2025-05-23
|
|
133
138
|
******************
|
|
134
139
|
|
|
@@ -37,6 +37,7 @@ learning_paths/migrations/0010_learningpath_invite_only.py
|
|
|
37
37
|
learning_paths/migrations/0011_replace_learningpath_image_url_with_image.py
|
|
38
38
|
learning_paths/migrations/0012_alter_learningpath_subtitle.py
|
|
39
39
|
learning_paths/migrations/0013_enrollment_audit.py
|
|
40
|
+
learning_paths/migrations/0014_learningpathenrollmentallowed_is_active.py
|
|
40
41
|
learning_paths/migrations/__init__.py
|
|
41
42
|
learning_paths/templates/learning_paths/base.html
|
|
42
43
|
learning_paths_plugin.egg-info/PKG-INFO
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/__init__.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/urls.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/__init__.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/filters.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/urls.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/api/v1/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/conftest.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/learning_paths/settings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc4 → learning_paths_plugin-0.3.4rc6}/requirements/constraints.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|