feat: implement validation and invalidation#118
Merged
Agrendalath merged 13 commits intomainfrom Feb 13, 2026
Merged
Conversation
fb44a7c to
0e6c112
Compare
7 tasks
1d9c576 to
a483669
Compare
184aefd to
6c6bded
Compare
6c6bded to
65de928
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces credential verification and invalidation capabilities, alongside a schema refactor to normalize credential data and add richer metadata.
Changes:
- Add a public API endpoint and UI page to verify credentials by a dedicated verification UUID, exposing limited, read-only metadata.
- Refactor the
Credentialmodel to referenceUserandCredentialConfigurationvia FKs, addverify_uuid,learning_context_name, and invalidation fields, and update generators and admin to support invalidation and reissue flows. - Extend and adjust the test suite (models, generators, admin, views) plus migrations, versioning, and documentation to cover the new behavior.
Reviewed changes
Copilot reviewed 21 out of 23 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
uv.lock |
Bumps the locked version of the local learning-credentials package to 0.5.0rc3 to match the code changes. |
pyproject.toml |
Updates the project version to 0.5.0rc3 for the new release containing verification and invalidation features. |
CHANGELOG.rst |
Adds a 0.5.0 section describing the new verification endpoint/UI and invalidation option. |
learning_credentials/models.py |
Refactors Credential to use user FK and configuration FK, adds verify_uuid, learning_context_name, invalidated_at, and invalidation_reason, implements automatic invalidation logic and a reissue() method, and adjusts CredentialConfiguration.generate_credential_for_user to work with the new schema and generator signature. |
learning_credentials/migrations/0008_validation.py |
Introduces verification and invalidation fields on Credential, backfills verify_uuid and learning_context_name, and removes the old unique_together constraint. |
learning_credentials/migrations/0009_credential_user_fk.py |
Migrates from an integer user_id on Credential to a proper user FK to AUTH_USER_MODEL. |
learning_credentials/migrations/0010_credential_configuration_fk.py |
Adds a FK from Credential to CredentialConfiguration and removes the redundant learning_context_key and credential_type fields from Credential. |
learning_credentials/migrations/0001_squashed_0010.py |
Provides a squashed initial migration that encapsulates the full current schema including Credential, CredentialConfiguration, assets, and new verification/invalidation fields for fresh installs. |
learning_credentials/generators.py |
Updates PDF generation to operate on a Credential instance, uses learning_context_name and verify_uuid, parameterizes the localized date, adds _get_credential_paths and _invalidate_credential helpers, and supports invalidation by archiving PDFs and clearing URLs. |
learning_credentials/compat.py |
Changes get_localized_credential_date to accept a datetime argument and format that timestamp in the configured timezone. |
learning_credentials/api/v1/serializers.py |
Adds CredentialSerializer exposing user_full_name, created, learning_context_name, status, and invalidation_reason for verification responses. |
learning_credentials/api/v1/views.py |
Extends the API with CredentialMetadataView to fetch credential metadata by verify_uuid, returning 404 on missing credentials. |
learning_credentials/api/v1/urls.py |
Wires the new metadata endpoint at v1/metadata/<uuid:uuid>/ under the existing API namespace. |
learning_credentials/urls.py |
Adds a TemplateView-based route for the credential verification page at /learning_credentials/verify/. |
learning_credentials/templates/learning_credentials/verify.html |
Implements a simple UI form that accepts a credential ID, calls the metadata API via fetch, and renders returned metadata in a details table. |
learning_credentials/admin.py |
Enhances admin for CredentialConfiguration and Credential (docstring-based help, read-only key fields, generate/reissue actions, disabled add/delete for credentials, and customized URL display and form behavior). |
tests/test_models.py |
Updates model tests to the new schema, adds coverage for invalidation and reissue logic, configuration-based generation using configuration and learning_context_name, and filtering logic using the new relationships. |
tests/test_generators.py |
Aligns generator tests with the new generate_pdf_credential signature, adds coverage for verify_uuid placeholders, output paths, invalidation/archiving behavior, and S3 ACL handling. |
tests/test_views.py |
Extends API tests to cover the new CredentialMetadataView, ensuring correct responses for valid, missing, and invalidated credentials. |
tests/test_admin.py |
Adds comprehensive tests for admin forms and actions, including docstring-based options help, configuration inline behavior, credential admin permissions, URL display, validation error handling, and the reissue action. |
tests/conftest.py |
Introduces reusable fixtures for mock retrieval/generation functions, mock credential types/configs, credential instances, email patching, and a temporary media root used by generator and asset tests. |
.gitignore |
Removes the now-obsolete external_certificates/ ignore, since credential PDFs are stored under the default storage path (learning_credentials/) instead. |
.coveragerc |
Stops excluding admin.py from coverage so the new admin tests are counted. |
Comments suppressed due to low confidence (1)
learning_credentials/generators.py:395
- The placeholder list in this docstring is now out of date:
_write_text_on_templateand the options plumbing also support{verify_uuid}(via theplaceholdersdict), but the documentation here still only mentions{name},{context_name}, and{issue_date}. To avoid confusing integrators configuring customtext_elements, please update this section to include{verify_uuid}in the list of available placeholders.
Options:
- template (required): The slug of the PDF template asset.
- template_multiline: Alternative template for multiline context names (when using '\n').
- defaults: Global defaults for all text elements.
- font: Font name (asset slug). Default: Helvetica.
- color: Hex color code. Default: #000.
- size: Font size in points. Default: 12.
- char_space: Character spacing. Default: 0.
- uppercase: Convert text to uppercase. Default: false.
- line_height: Line height multiplier for multiline text. Default: 1.1.
- text_elements: Configuration for text elements. Standard elements (name, context, date) have
defaults and render automatically. Set to false to hide.
Custom elements require 'text' and 'y' properties.
Element properties:
- text: Text content with {placeholder} substitution. Available: {name}, {context_name}, {issue_date}.
- y: Vertical position (PDF coordinates from bottom).
- size: Font size (inherited from defaults.size).
- font: Font name (inherited from defaults.font).
- color: Hex color (inherited from defaults.color).
- char_space: Character spacing (inherited from defaults.char_space).
- uppercase: Convert text to uppercase (inherited from defaults.uppercase).
- line_height: Line height multiplier for multiline text (inherited from defaults.line_height).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
learning_credentials/templates/learning_credentials/verify.html
Outdated
Show resolved
Hide resolved
learning_credentials/templates/learning_credentials/verify.html
Outdated
Show resolved
Hide resolved
be7cdce to
7b486e5
Compare
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Added
INVALIDATEDstatus.verify_uuidfield on credentials — a separate UUID used for third-party verification, distinct from the primary key.invalidated_attimestamp andinvalidation_reasonfields on theCredentialmodel.learning_context_namecached field on credentials for use in validation display./api/learning_credentials/v1/metadata/<uuid>/) to retrieve credential metadata by verification UUID.{verify_uuid}placeholder support in PDF text elements.test_admin.py) and included it in test coverage.Changed
user_id(IntegerField) with auserForeignKey to the User model.configurationForeignKey onCredentiallinking toCredentialConfiguration, replacingcredential_typeandlearning_context_keylookups.generate_pdf_credential()signature to accept aCredentialobject instead of separate parameters.external_certificates/to the configurableLEARNING_CREDENTIALS_OUTPUT_DIRsetting.get_localized_credential_date()now accepts an explicitdatetimeparameter.