learning-credentials 0.5.2__tar.gz → 0.5.3__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_credentials-0.5.2 → learning_credentials-0.5.3}/CHANGELOG.rst +10 -0
- {learning_credentials-0.5.2/learning_credentials.egg-info → learning_credentials-0.5.3}/PKG-INFO +11 -1
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/views.py +1 -1
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/models.py +16 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3/learning_credentials.egg-info}/PKG-INFO +11 -1
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/pyproject.toml +1 -1
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_models.py +30 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_views.py +35 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/LICENSE.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/MANIFEST.in +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/README.rst +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/__init__.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/admin.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/__init__.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/urls.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/__init__.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/permissions.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/serializers.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/urls.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/apps.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/compat.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/conf/locale/config.yaml +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/exceptions.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/generators.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0001_initial.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0002_migrate_to_learning_credentials.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0003_rename_certificates_to_credentials.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0004_replace_course_keys_with_learning_context_keys.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0005_rename_processors_and_generators.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0006_cleanup_openedx_certificates_tables.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0007_migrate_to_text_elements_format.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0008_validation.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0009_credential_user_fk.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/0010_credential_configuration_fk.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/migrations/__init__.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/processors.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/settings/__init__.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/settings/common.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/settings/production.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/tasks.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/templates/learning_credentials/base.html +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/body.html +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/body.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/from_name.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/head.html +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/subject.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/urls.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/SOURCES.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/dependency_links.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/entry_points.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/requires.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/top_level.txt +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/setup.cfg +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_admin.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_generators.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_migrations.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_processors.py +0 -0
- {learning_credentials-0.5.2 → learning_credentials-0.5.3}/tests/test_tasks.py +0 -0
|
@@ -16,6 +16,16 @@ Unreleased
|
|
|
16
16
|
|
|
17
17
|
*
|
|
18
18
|
|
|
19
|
+
0.5.3 - 2026-08-11
|
|
20
|
+
******************
|
|
21
|
+
|
|
22
|
+
Fixed
|
|
23
|
+
=====
|
|
24
|
+
|
|
25
|
+
* The ``is_generation_enabled`` field of the credential eligibility endpoint is now based on the ``expires`` field of
|
|
26
|
+
the periodic task, when it is set. The ``enabled`` flag is updated by Celery Beat (e.g., it disables expired and
|
|
27
|
+
already executed one-off tasks), so it does not reliably reflect the intended configuration.
|
|
28
|
+
|
|
19
29
|
0.5.2 - 2026-08-11
|
|
20
30
|
******************
|
|
21
31
|
|
{learning_credentials-0.5.2/learning_credentials.egg-info → learning_credentials-0.5.3}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-credentials
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: A pluggable service for preparing Open edX credentials.
|
|
5
5
|
Author-email: OpenCraft <help@opencraft.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -177,6 +177,16 @@ Unreleased
|
|
|
177
177
|
|
|
178
178
|
*
|
|
179
179
|
|
|
180
|
+
0.5.3 - 2026-08-11
|
|
181
|
+
******************
|
|
182
|
+
|
|
183
|
+
Fixed
|
|
184
|
+
=====
|
|
185
|
+
|
|
186
|
+
* The ``is_generation_enabled`` field of the credential eligibility endpoint is now based on the ``expires`` field of
|
|
187
|
+
the periodic task, when it is set. The ``enabled`` flag is updated by Celery Beat (e.g., it disables expired and
|
|
188
|
+
already executed one-off tasks), so it does not reliably reflect the intended configuration.
|
|
189
|
+
|
|
180
190
|
0.5.2 - 2026-08-11
|
|
181
191
|
******************
|
|
182
192
|
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/views.py
RENAMED
|
@@ -167,7 +167,7 @@ class CredentialEligibilityView(APIView):
|
|
|
167
167
|
return {
|
|
168
168
|
'credential_type_id': config.credential_type.pk,
|
|
169
169
|
'name': config.credential_type.name,
|
|
170
|
-
'is_generation_enabled': config.
|
|
170
|
+
'is_generation_enabled': config.is_generation_enabled,
|
|
171
171
|
**progress_data,
|
|
172
172
|
'existing_credential': existing_credential.uuid if existing_credential else None,
|
|
173
173
|
'existing_credential_url': existing_credential.download_url if existing_credential else None,
|
|
@@ -148,6 +148,22 @@ class CredentialConfiguration(TimeStampedModel):
|
|
|
148
148
|
self.periodic_task.args = json.dumps([self.id])
|
|
149
149
|
self.periodic_task.save()
|
|
150
150
|
|
|
151
|
+
@property
|
|
152
|
+
def is_generation_enabled(self) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Check whether credential generation is currently enabled for this configuration.
|
|
155
|
+
|
|
156
|
+
Celery Beat updates the `enabled` flag of the periodic task on its own (e.g., it disables one-off tasks once
|
|
157
|
+
they have run, and expired tasks), so it does not reliably reflect the intended configuration. When `expires`
|
|
158
|
+
is set, it defines the end of the generation window, so it takes precedence.
|
|
159
|
+
|
|
160
|
+
:return: True if credential generation is enabled, False otherwise.
|
|
161
|
+
"""
|
|
162
|
+
if self.periodic_task.expires:
|
|
163
|
+
return self.periodic_task.expires > timezone.now()
|
|
164
|
+
|
|
165
|
+
return self.periodic_task.enabled
|
|
166
|
+
|
|
151
167
|
@classmethod
|
|
152
168
|
def get_enabled_configurations(cls) -> QuerySet[Self]:
|
|
153
169
|
"""
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3/learning_credentials.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: learning-credentials
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.3
|
|
4
4
|
Summary: A pluggable service for preparing Open edX credentials.
|
|
5
5
|
Author-email: OpenCraft <help@opencraft.com>
|
|
6
6
|
License-Expression: AGPL-3.0-or-later
|
|
@@ -177,6 +177,16 @@ Unreleased
|
|
|
177
177
|
|
|
178
178
|
*
|
|
179
179
|
|
|
180
|
+
0.5.3 - 2026-08-11
|
|
181
|
+
******************
|
|
182
|
+
|
|
183
|
+
Fixed
|
|
184
|
+
=====
|
|
185
|
+
|
|
186
|
+
* The ``is_generation_enabled`` field of the credential eligibility endpoint is now based on the ``expires`` field of
|
|
187
|
+
the periodic task, when it is set. The ``enabled`` flag is updated by Celery Beat (e.g., it disables expired and
|
|
188
|
+
already executed one-off tasks), so it does not reliably reflect the intended configuration.
|
|
189
|
+
|
|
180
190
|
0.5.2 - 2026-08-11
|
|
181
191
|
******************
|
|
182
192
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from datetime import timedelta
|
|
5
6
|
from pathlib import Path
|
|
6
7
|
from typing import TYPE_CHECKING
|
|
7
8
|
from unittest.mock import Mock, patch
|
|
@@ -10,6 +11,7 @@ from uuid import uuid4
|
|
|
10
11
|
import pytest
|
|
11
12
|
from django.core.exceptions import ValidationError
|
|
12
13
|
from django.core.files.base import ContentFile
|
|
14
|
+
from django.utils import timezone
|
|
13
15
|
from django_celery_beat.models import PeriodicTask
|
|
14
16
|
|
|
15
17
|
from learning_credentials.exceptions import AssetNotFoundError, CredentialGenerationError
|
|
@@ -371,6 +373,34 @@ class TestCredentialConfiguration:
|
|
|
371
373
|
assert enabled_configs.count() == 1
|
|
372
374
|
assert enabled_configs.first() == mock_credential_config
|
|
373
375
|
|
|
376
|
+
@pytest.mark.django_db
|
|
377
|
+
@pytest.mark.parametrize(
|
|
378
|
+
('enabled', 'expires_offset', 'expected'),
|
|
379
|
+
[
|
|
380
|
+
# Without `expires`, the `enabled` flag of the periodic task is used.
|
|
381
|
+
(False, None, False),
|
|
382
|
+
(True, None, True),
|
|
383
|
+
# With `expires` set, it takes precedence over the `enabled` flag.
|
|
384
|
+
(False, timedelta(days=1), True),
|
|
385
|
+
(True, timedelta(days=-1), False),
|
|
386
|
+
(False, timedelta(days=-1), False),
|
|
387
|
+
(True, timedelta(days=1), True),
|
|
388
|
+
],
|
|
389
|
+
)
|
|
390
|
+
def test_is_generation_enabled(
|
|
391
|
+
self,
|
|
392
|
+
mock_credential_config: CredentialConfiguration,
|
|
393
|
+
enabled: bool,
|
|
394
|
+
expires_offset: timedelta | None,
|
|
395
|
+
expected: bool,
|
|
396
|
+
):
|
|
397
|
+
"""Test that the `expires` field takes precedence over the `enabled` flag, which Celery Beat updates."""
|
|
398
|
+
mock_credential_config.periodic_task.enabled = enabled
|
|
399
|
+
mock_credential_config.periodic_task.expires = timezone.now() + expires_offset if expires_offset else None
|
|
400
|
+
mock_credential_config.periodic_task.save()
|
|
401
|
+
|
|
402
|
+
assert mock_credential_config.is_generation_enabled is expected
|
|
403
|
+
|
|
374
404
|
@pytest.mark.django_db
|
|
375
405
|
def test_save_updates_existing_periodic_task(self, mock_credential_config: CredentialConfiguration):
|
|
376
406
|
"""Test that saving an existing CredentialConfiguration updates the periodic task."""
|
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
from datetime import timedelta
|
|
5
6
|
from typing import TYPE_CHECKING
|
|
6
7
|
from unittest.mock import Mock, patch
|
|
7
8
|
|
|
8
9
|
import pytest
|
|
9
10
|
from django.urls import reverse
|
|
11
|
+
from django.utils import timezone
|
|
10
12
|
from learning_paths.models import LearningPathStep
|
|
11
13
|
from rest_framework import status
|
|
12
14
|
from rest_framework.test import APIClient
|
|
@@ -313,6 +315,39 @@ class TestCredentialEligibilityView:
|
|
|
313
315
|
assert 'existing_credential' not in cred
|
|
314
316
|
assert 'existing_credential_url' not in cred
|
|
315
317
|
|
|
318
|
+
@pytest.mark.parametrize(
|
|
319
|
+
('enabled', 'expires_offset', 'expected'),
|
|
320
|
+
[
|
|
321
|
+
(False, None, False),
|
|
322
|
+
(True, None, True),
|
|
323
|
+
# Celery Beat disables expired tasks, so `expires` takes precedence over the `enabled` flag.
|
|
324
|
+
(False, timedelta(days=1), True),
|
|
325
|
+
(True, timedelta(days=-1), False),
|
|
326
|
+
],
|
|
327
|
+
)
|
|
328
|
+
@patch('learning_credentials.api.v1.permissions.get_course_enrollments')
|
|
329
|
+
def test_get_is_generation_enabled( # noqa: PLR0917
|
|
330
|
+
self,
|
|
331
|
+
mock_enrollments: Mock,
|
|
332
|
+
user: User,
|
|
333
|
+
course_key: CourseKey,
|
|
334
|
+
mock_credential_config: CredentialConfiguration,
|
|
335
|
+
enabled: bool,
|
|
336
|
+
expires_offset: timedelta | None,
|
|
337
|
+
expected: bool,
|
|
338
|
+
):
|
|
339
|
+
"""Test that the generation status is based on the `expires` field of the periodic task, when it is set."""
|
|
340
|
+
mock_enrollments.return_value = [user]
|
|
341
|
+
mock_credential_config.periodic_task.enabled = enabled
|
|
342
|
+
mock_credential_config.periodic_task.expires = timezone.now() + expires_offset if expires_offset else None
|
|
343
|
+
mock_credential_config.periodic_task.save()
|
|
344
|
+
|
|
345
|
+
with patch.object(CredentialConfiguration, 'get_user_eligibility_details', return_value={'is_eligible': True}):
|
|
346
|
+
response = self._make_get_request(user, course_key)
|
|
347
|
+
|
|
348
|
+
assert response.status_code == status.HTTP_200_OK
|
|
349
|
+
assert response.data['credentials'][0]['is_generation_enabled'] is expected
|
|
350
|
+
|
|
316
351
|
@patch('learning_credentials.api.v1.permissions.get_course_enrollments')
|
|
317
352
|
def test_get_filters_by_retrieval_func(
|
|
318
353
|
self,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/__init__.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/permissions.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/serializers.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/api/v1/urls.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/exceptions.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/generators.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
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/processors.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/settings/__init__.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials/settings/common.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_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.2 → learning_credentials-0.5.3}/learning_credentials.egg-info/requires.txt
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
|