learning-credentials 0.5.4__tar.gz → 0.5.5__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.4 → learning_credentials-0.5.5}/CHANGELOG.rst +9 -0
- {learning_credentials-0.5.4/learning_credentials.egg-info → learning_credentials-0.5.5}/PKG-INFO +10 -1
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/generators.py +3 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5/learning_credentials.egg-info}/PKG-INFO +10 -1
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/pyproject.toml +1 -1
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_generators.py +40 -1
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/LICENSE.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/MANIFEST.in +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/README.rst +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/__init__.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/admin.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/__init__.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/urls.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/__init__.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/permissions.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/serializers.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/urls.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/views.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/apps.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/compat.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/conf/locale/config.yaml +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/exceptions.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0001_initial.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0002_migrate_to_learning_credentials.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0003_rename_certificates_to_credentials.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0004_replace_course_keys_with_learning_context_keys.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0005_rename_processors_and_generators.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0006_cleanup_openedx_certificates_tables.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0007_migrate_to_text_elements_format.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0008_validation.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0009_credential_user_fk.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/0010_credential_configuration_fk.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/migrations/__init__.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/models.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/processors.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/settings/__init__.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/settings/common.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/settings/production.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/tasks.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/templates/learning_credentials/base.html +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/body.html +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/body.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/from_name.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/head.html +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/templates/learning_credentials/edx_ace/certificate_generated/email/subject.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/urls.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials.egg-info/SOURCES.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials.egg-info/dependency_links.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials.egg-info/entry_points.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials.egg-info/requires.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials.egg-info/top_level.txt +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/setup.cfg +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_admin.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_migrations.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_models.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_processors.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_tasks.py +0 -0
- {learning_credentials-0.5.4 → learning_credentials-0.5.5}/tests/test_views.py +0 -0
|
@@ -16,6 +16,15 @@ Unreleased
|
|
|
16
16
|
|
|
17
17
|
*
|
|
18
18
|
|
|
19
|
+
0.5.5 - 2026-11-11
|
|
20
|
+
******************
|
|
21
|
+
|
|
22
|
+
Fixed
|
|
23
|
+
=====
|
|
24
|
+
|
|
25
|
+
* Missing text (e.g., name, context, date) in encrypted PDF credentials generated with ``pypdf>=7.0.0``. The merged
|
|
26
|
+
content streams are now serialized before encryption, so the overlay is no longer saved as an empty stream.
|
|
27
|
+
|
|
19
28
|
0.5.4 - 2026-11-10
|
|
20
29
|
******************
|
|
21
30
|
|
{learning_credentials-0.5.4/learning_credentials.egg-info → learning_credentials-0.5.5}/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.5
|
|
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,15 @@ Unreleased
|
|
|
177
177
|
|
|
178
178
|
*
|
|
179
179
|
|
|
180
|
+
0.5.5 - 2026-11-11
|
|
181
|
+
******************
|
|
182
|
+
|
|
183
|
+
Fixed
|
|
184
|
+
=====
|
|
185
|
+
|
|
186
|
+
* Missing text (e.g., name, context, date) in encrypted PDF credentials generated with ``pypdf>=7.0.0``. The merged
|
|
187
|
+
content streams are now serialized before encryption, so the overlay is no longer saved as an empty stream.
|
|
188
|
+
|
|
180
189
|
0.5.4 - 2026-11-10
|
|
181
190
|
******************
|
|
182
191
|
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/generators.py
RENAMED
|
@@ -451,6 +451,9 @@ def generate_pdf_credential(credential: Credential, options: dict[str, Any], *,
|
|
|
451
451
|
overlay_pdf = PdfReader(io.BytesIO(pdf_canvas.getpdfdata()))
|
|
452
452
|
page = pdf_writer.add_page(template)
|
|
453
453
|
page.merge_page(overlay_pdf.pages[0])
|
|
454
|
+
# Serialize the merged content streams. Otherwise, `pypdf>=7.0.0` encrypts the raw stream data before the
|
|
455
|
+
# pending operations of the merged overlay are written, which results in an empty overlay stream.
|
|
456
|
+
page.compress_content_streams()
|
|
454
457
|
|
|
455
458
|
url = _save_credential(pdf_writer, credential.uuid)
|
|
456
459
|
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5/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.5
|
|
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,15 @@ Unreleased
|
|
|
177
177
|
|
|
178
178
|
*
|
|
179
179
|
|
|
180
|
+
0.5.5 - 2026-11-11
|
|
181
|
+
******************
|
|
182
|
+
|
|
183
|
+
Fixed
|
|
184
|
+
=====
|
|
185
|
+
|
|
186
|
+
* Missing text (e.g., name, context, date) in encrypted PDF credentials generated with ``pypdf>=7.0.0``. The merged
|
|
187
|
+
content streams are now serialized before encryption, so the overlay is no longer saved as an empty stream.
|
|
188
|
+
|
|
180
189
|
0.5.4 - 2026-11-10
|
|
181
190
|
******************
|
|
182
191
|
|
|
@@ -12,7 +12,7 @@ from django.core.files.base import ContentFile
|
|
|
12
12
|
from django.core.files.storage import DefaultStorage, FileSystemStorage
|
|
13
13
|
from django.test import override_settings
|
|
14
14
|
from inmemorystorage import InMemoryStorage
|
|
15
|
-
from pypdf import PdfWriter
|
|
15
|
+
from pypdf import PdfReader, PdfWriter
|
|
16
16
|
from pypdf.constants import UserAccessPermissions
|
|
17
17
|
|
|
18
18
|
from learning_credentials.exceptions import AssetNotFoundError
|
|
@@ -571,6 +571,45 @@ def test_generate_pdf_credential_merges_overlay_into_template(mock_get_asset_by_
|
|
|
571
571
|
assert 'Test Course' in page_text
|
|
572
572
|
|
|
573
573
|
|
|
574
|
+
@patch('learning_credentials.generators.CredentialAsset.get_asset_by_slug')
|
|
575
|
+
def test_generate_pdf_credential_saved_file_contains_overlay(mock_get_asset_by_slug: Mock):
|
|
576
|
+
"""
|
|
577
|
+
Test that the saved (encrypted) PDF contains the overlay text.
|
|
578
|
+
|
|
579
|
+
With ``pypdf>=7.0.0``, encryption reads the raw stream data of content streams that were modified during the merge
|
|
580
|
+
before they are serialized, so the overlay was written as an empty stream.
|
|
581
|
+
"""
|
|
582
|
+
template_writer = PdfWriter()
|
|
583
|
+
template_writer.add_blank_page(width=842, height=595)
|
|
584
|
+
template_buffer = io.BytesIO()
|
|
585
|
+
template_writer.write(template_buffer)
|
|
586
|
+
mock_get_asset_by_slug.return_value = ContentFile(template_buffer.getvalue(), name='template.pdf')
|
|
587
|
+
|
|
588
|
+
credential = Mock(
|
|
589
|
+
uuid=uuid4(),
|
|
590
|
+
user_full_name='Test User',
|
|
591
|
+
learning_context_name='Test Course',
|
|
592
|
+
verify_uuid=uuid4(),
|
|
593
|
+
created=Mock(),
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
storage = InMemoryStorage()
|
|
597
|
+
with (
|
|
598
|
+
patch('learning_credentials.generators.default_storage', storage),
|
|
599
|
+
patch('learning_credentials.generators.get_localized_credential_date', return_value='April 1, 2021'),
|
|
600
|
+
):
|
|
601
|
+
generate_pdf_credential(credential, {'template': 'template'})
|
|
602
|
+
|
|
603
|
+
with storage.open(f'learning_credentials/{credential.uuid}.pdf', 'rb') as saved_file:
|
|
604
|
+
reader = PdfReader(io.BytesIO(saved_file.read()))
|
|
605
|
+
assert reader.is_encrypted
|
|
606
|
+
reader.decrypt('')
|
|
607
|
+
page_text = reader.pages[0].extract_text()
|
|
608
|
+
assert 'Test User' in page_text
|
|
609
|
+
assert 'Test Course' in page_text
|
|
610
|
+
assert 'April 1, 2021' in page_text
|
|
611
|
+
|
|
612
|
+
|
|
574
613
|
def test_generate_pdf_credential_no_template():
|
|
575
614
|
"""Test that generate_pdf_credential raises ValueError when no template is specified."""
|
|
576
615
|
credential = Mock(learning_context_name='Test Course')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/__init__.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/permissions.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/serializers.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/urls.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/api/v1/views.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/exceptions.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
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/processors.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/learning_credentials/settings/__init__.py
RENAMED
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/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.4 → learning_credentials-0.5.5}/learning_credentials.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{learning_credentials-0.5.4 → learning_credentials-0.5.5}/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
|
|
File without changes
|