learning-paths-plugin 0.3.4rc6__tar.gz → 0.3.4rc7__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.4rc6 → learning_paths_plugin-0.3.4rc7}/CHANGELOG.rst +1 -0
- {learning_paths_plugin-0.3.4rc6/learning_paths_plugin.egg-info → learning_paths_plugin-0.3.4rc7}/PKG-INFO +2 -1
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/__init__.py +1 -1
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/admin.py +1 -1
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/serializers.py +7 -7
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/views.py +1 -3
- learning_paths_plugin-0.3.4rc7/learning_paths/migrations/0015_remove_learningpathenrollment_enrolled_at.py +17 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/models.py +11 -15
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7/learning_paths_plugin.egg-info}/PKG-INFO +2 -1
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths_plugin.egg-info/SOURCES.txt +1 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/LICENSE.txt +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/MANIFEST.in +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/README.rst +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/__init__.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/urls.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/__init__.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/filters.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/permissions.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/urls.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/utils.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/apps.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/compat.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/conftest.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/keys.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0001_initial.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0002_learningpath_uuid.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0003_learningpath_subtitle.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0004_auto_20240207_1633.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0005_learningpathstep_weight_learningpathgradingcriteria.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0006_enrollment_models.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0007_replace_uuid_with_learningpathkey.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0008_remove_learningpathstep_relative_due_date_in_days.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0009_remove_learningpath_slug.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0010_learningpath_invite_only.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0011_replace_learningpath_image_url_with_image.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0012_alter_learningpath_subtitle.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0013_enrollment_audit.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/0014_learningpathenrollmentallowed_is_active.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/migrations/__init__.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/receivers.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/settings.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/templates/learning_paths/base.html +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/urls.py +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths_plugin.egg-info/dependency_links.txt +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths_plugin.egg-info/entry_points.txt +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths_plugin.egg-info/not-zip-safe +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths_plugin.egg-info/requires.txt +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths_plugin.egg-info/top_level.txt +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/pyproject.toml +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/requirements/base.in +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/requirements/constraints.txt +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/setup.cfg +0 -0
- {learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-paths-plugin
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4rc7
|
|
4
4
|
Summary: Learning Paths plugin
|
|
5
5
|
Home-page: https://github.com/open-craft/learning-paths-plugin
|
|
6
6
|
Author: OpenCraft
|
|
@@ -133,6 +133,7 @@ Changed
|
|
|
133
133
|
=======
|
|
134
134
|
|
|
135
135
|
* The Learning Paths API includes start and end dates for its steps.
|
|
136
|
+
* Return enrollment date in the API instead of a boolean.
|
|
136
137
|
|
|
137
138
|
0.3.3 - 2025-05-23
|
|
138
139
|
******************
|
|
@@ -105,7 +105,7 @@ class LearningPathListSerializer(serializers.ModelSerializer):
|
|
|
105
105
|
|
|
106
106
|
steps = LearningPathStepSerializer(many=True, read_only=True)
|
|
107
107
|
required_completion = serializers.FloatField(source="grading_criteria.required_completion", read_only=True)
|
|
108
|
-
|
|
108
|
+
enrollment_date = serializers.SerializerMethodField()
|
|
109
109
|
invite_only = serializers.BooleanField()
|
|
110
110
|
image = serializers.ImageField(read_only=True)
|
|
111
111
|
|
|
@@ -118,17 +118,17 @@ class LearningPathListSerializer(serializers.ModelSerializer):
|
|
|
118
118
|
"sequential",
|
|
119
119
|
"steps",
|
|
120
120
|
"required_completion",
|
|
121
|
-
"
|
|
121
|
+
"enrollment_date",
|
|
122
122
|
"invite_only",
|
|
123
123
|
]
|
|
124
124
|
|
|
125
|
-
def
|
|
125
|
+
def get_enrollment_date(self, obj):
|
|
126
126
|
"""
|
|
127
127
|
Check if the current user is enrolled in this learning path.
|
|
128
128
|
"""
|
|
129
|
-
if hasattr(obj, "
|
|
130
|
-
return obj.
|
|
131
|
-
return
|
|
129
|
+
if hasattr(obj, "enrollment_date"):
|
|
130
|
+
return obj.enrollment_date
|
|
131
|
+
return None
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
class SkillSerializer(serializers.ModelSerializer):
|
|
@@ -183,4 +183,4 @@ class LearningPathDetailSerializer(LearningPathListSerializer):
|
|
|
183
183
|
class LearningPathEnrollmentSerializer(serializers.ModelSerializer):
|
|
184
184
|
class Meta:
|
|
185
185
|
model = LearningPathEnrollment
|
|
186
|
-
fields = ("user", "learning_path", "is_active", "
|
|
186
|
+
fields = ("user", "learning_path", "is_active", "created")
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/views.py
RENAMED
|
@@ -242,7 +242,6 @@ class LearningPathEnrollmentView(APIView):
|
|
|
242
242
|
return Response({"detail": "Enrollment exists."}, status=status.HTTP_409_CONFLICT)
|
|
243
243
|
|
|
244
244
|
enrollment.is_active = True
|
|
245
|
-
enrollment.enrolled_at = datetime.now(timezone.utc)
|
|
246
245
|
enrollment.save()
|
|
247
246
|
return Response(LearningPathEnrollmentSerializer(enrollment).data)
|
|
248
247
|
|
|
@@ -389,7 +388,6 @@ class BulkEnrollView(APIView):
|
|
|
389
388
|
if enrollment:
|
|
390
389
|
if not enrollment.is_active:
|
|
391
390
|
enrollment.is_active = True
|
|
392
|
-
enrollment.enrolled_at = datetime.now(timezone.utc)
|
|
393
391
|
enrolled_now = True
|
|
394
392
|
else:
|
|
395
393
|
audit_data["state_transition"] = LearningPathEnrollmentAudit.ENROLLED_TO_ENROLLED
|
|
@@ -519,7 +517,7 @@ class LearningPathCourseEnrollmentView(APIView):
|
|
|
519
517
|
:raises: Http404 if the learning path is not found or the user does not have access.
|
|
520
518
|
"""
|
|
521
519
|
return get_object_or_404(
|
|
522
|
-
LearningPath.objects.get_paths_visible_to_user(self.request.user).filter(
|
|
520
|
+
LearningPath.objects.get_paths_visible_to_user(self.request.user).filter(enrollment_date__isnull=False),
|
|
523
521
|
key=learning_path_key_str,
|
|
524
522
|
)
|
|
525
523
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-06-02 14:39
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
("learning_paths", "0014_learningpathenrollmentallowed_is_active"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.RemoveField(
|
|
14
|
+
model_name="learningpathenrollment",
|
|
15
|
+
name="enrolled_at",
|
|
16
|
+
),
|
|
17
|
+
]
|
|
@@ -38,27 +38,29 @@ class LearningPathManager(models.Manager):
|
|
|
38
38
|
|
|
39
39
|
def get_paths_visible_to_user(self, user: User) -> models.QuerySet:
|
|
40
40
|
"""
|
|
41
|
-
Return only learning paths that should be visible to the given user with enrollment
|
|
41
|
+
Return only learning paths that should be visible to the given user with an enrollment date.
|
|
42
42
|
|
|
43
43
|
For staff users: all learning paths.
|
|
44
44
|
For non-staff: non-invite-only paths or invite-only paths they're enrolled in.
|
|
45
45
|
|
|
46
|
-
Each learning path in the queryset is annotated with `
|
|
47
|
-
|
|
46
|
+
Each learning path in the queryset is annotated with `enrollment_date` indicating
|
|
47
|
+
the date when the user enrolled in that learning path (None if not enrolled).
|
|
48
|
+
Results are ordered by enrollment date (the most recent first), with non-enrolled paths at the end.
|
|
48
49
|
"""
|
|
49
50
|
queryset = self.get_queryset()
|
|
50
51
|
|
|
51
|
-
# Annotate each path with
|
|
52
|
-
|
|
52
|
+
# Annotate each path with the enrollment date.
|
|
53
|
+
enrollment_subquery = LearningPathEnrollment.objects.filter(
|
|
53
54
|
learning_path=OuterRef("pk"), user=user, is_active=True
|
|
54
|
-
)
|
|
55
|
-
queryset = queryset.annotate(
|
|
55
|
+
).values("created")[:1]
|
|
56
|
+
queryset = queryset.annotate(enrollment_date=models.Subquery(enrollment_subquery))
|
|
56
57
|
|
|
57
58
|
# Apply visibility filtering based on the user role.
|
|
58
59
|
if not user.is_staff:
|
|
59
|
-
queryset = queryset.filter(Q(invite_only=False) | Q(
|
|
60
|
+
queryset = queryset.filter(Q(invite_only=False) | Q(enrollment_date__isnull=False))
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
# Order by enrollment date (the most recent first), with null values at the end.
|
|
63
|
+
return queryset.order_by(models.F('enrollment_date').desc(nulls_last=True))
|
|
62
64
|
|
|
63
65
|
|
|
64
66
|
class LearningPath(TimeStampedModel):
|
|
@@ -289,12 +291,6 @@ class LearningPathEnrollment(TimeStampedModel):
|
|
|
289
291
|
default=True,
|
|
290
292
|
help_text=_("Indicates if the learner is enrolled or not in the Learning Path"),
|
|
291
293
|
)
|
|
292
|
-
enrolled_at = models.DateTimeField(
|
|
293
|
-
auto_now_add=True,
|
|
294
|
-
help_text=_(
|
|
295
|
-
"Timestamp of enrollment or un-enrollment. To be explicitly set when performing a learner enrollment."
|
|
296
|
-
),
|
|
297
|
-
)
|
|
298
294
|
tracker = FieldTracker(fields=["is_active"])
|
|
299
295
|
|
|
300
296
|
def __str__(self):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-paths-plugin
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4rc7
|
|
4
4
|
Summary: Learning Paths plugin
|
|
5
5
|
Home-page: https://github.com/open-craft/learning-paths-plugin
|
|
6
6
|
Author: OpenCraft
|
|
@@ -133,6 +133,7 @@ Changed
|
|
|
133
133
|
=======
|
|
134
134
|
|
|
135
135
|
* The Learning Paths API includes start and end dates for its steps.
|
|
136
|
+
* Return enrollment date in the API instead of a boolean.
|
|
136
137
|
|
|
137
138
|
0.3.3 - 2025-05-23
|
|
138
139
|
******************
|
|
@@ -38,6 +38,7 @@ 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
40
|
learning_paths/migrations/0014_learningpathenrollmentallowed_is_active.py
|
|
41
|
+
learning_paths/migrations/0015_remove_learningpathenrollment_enrolled_at.py
|
|
41
42
|
learning_paths/migrations/__init__.py
|
|
42
43
|
learning_paths/templates/learning_paths/base.html
|
|
43
44
|
learning_paths_plugin.egg-info/PKG-INFO
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/__init__.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/urls.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/__init__.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/filters.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/urls.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/api/v1/utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/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
|
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/learning_paths/receivers.py
RENAMED
|
File without changes
|
{learning_paths_plugin-0.3.4rc6 → learning_paths_plugin-0.3.4rc7}/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.4rc6 → learning_paths_plugin-0.3.4rc7}/requirements/constraints.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|