* fix: make the issued date displayed on previewed certificates match real certificates
This PR fixes an inconsistency in the dates displayed on certificates previewed via Studio with "real" certificates rendered to users.
It is possible for self-paced courses to be configured with a display behavior of "END" even though this configuration option should be invalid. The fix to this problem is beyond the scope of this PR. However, we can ensure we are selecting the correct display date for the certificate with a little bit of defensive coding.
I've added a check to ensure that we only use the end date of the course when the course is instructor-paced and configured with a display behavior of "END".
Fixes: https://github.com/openedx/platform-roadmap/issues/423
This PR updates the logic for determining the issued date shown on course certificates. For courses with a display behavior set to 'end date of the course', certificates earned by learners will now show the course run’s end date as the issued date.
for Open edX operators who still have users with legacy PDF certificates, retirement requires first extracting information from the user's GeneratedCertificate record in order to delete the 4 associated files for each PDF certificate, and then removing the links to the relevant files. this creates a management command to do that work.
After thinking about it, I have removed the update to `status` from this management command, as per the original specification of the ticket. I added it for completeness originally, but was already uncomfortable, because it's not exactly accurate. The `CertificateStatuses` enum does define a `deleted` status:
```
deleted - The PDF certificate has been deleted.
```
but I think it's inappropriate to use here.
#### Why not use `CertificateStatuses.deleted` in the first place
There are multiple places in the code where it's clear that almost all of the statuses are legacy and unused (eg. [Example 1](6c6fd84e53/lms/djangoapps/certificates/data.py (L12-L34)), [Example 2](1029de5537/common/djangoapps/student/helpers.py (L491-L492))). There are innumerable APIs in the system that have expectations about what might possibly be returned from a `GeneratedCertificate.status` object, and none of them is expecting `deleted`
#### Why not revoke the certificate
Ultimately, the certificate isn't revoked, which has a specific meaning around saying it was unearned. The certificate was earned; it has simply been deleted. We should not be kicking off program certificate invalidation, because that's not what's happening. We should be trusting the normal user retirement process to remove/purge PII from any program certificates that might exist. The nature of web certificates simply means that we are going through this process outside of the normal retirement flow. The normal retirement flow can be trusted to implement any certificate object revocation/removal/PII-purging, and doing an extra step outside of that flow is counterproductive.
#### Why not robustly add a flow for `CertificateStatuses.deleted`
When PDF certificates were removed from the system, they weren't removed in their entirety. Instead, we have this vestigial remains of PDF certificates code, just enough to allow learners to display and use the ones that they already have, without any of the support systems for modifying them. Adding a `deleted` status, verifying that all other APIs wouldn't break in the presence of a certificate with that status, adding the signals to process and propagate the change: all of this would be adding more tech debt upon the already existing technical debt which is the PDF certs code. Better to simply add this one necessary data integrity change, and focus on a process which might allow us to eventually remove the web certificates code.
#### Why it is good enough to ignore the status
The original ask was simply to enforce data integrity: to remove links to files that have been deleted, as an indication that they've been deleted. I only added `status` update out of a (misplaced but well-intentioned) completionist urge.
FIXES: APER-3889
* feat!: removes deprecated v1 certificate behavior
this removes the long-deprecated v1 certificate behavior. This removes
the old-style date selection behavior (ie., not a choice between
*Immediately upon passing*, *End date of course*, *A date after the course
end date*), which is no longer reliably maintained or supported in
Studio or Credentials.
FIXES: #35399
* feat: removing visible_date-to-creds updates per-cert
The credentials IDA now relies on the course certificate configuration
and (if present) `certificate_available_date` for displayability. We no
longer need to send `visible_date` updates for every awarded certificate
when a course overview changes.
* feat: linting before touching all these files
All these files are old enough, relative either to our current linting
rules or our current linter automation, that modifying anything in them
either makes the linter cranky or wants to reformat the entire file.
Rather than mixing cleanup with code changes, this commit just lints
this set of files to our current standards.
The LMS `certificates` app `README` has been, and the
openedx core `credentials` and `programs` READMEs have been created.
This will clarify not only what the limited responsibilities
of each of these django apps is, but also the way they interact with
each other.
FIXES: APER-2929
[APER-3241]
This PR updates the retirement pipeline to purge learners' names from certificate records when their account is being retired.
It also introduces a new management command that can be used by Open edX operators to purge the leftover name data (PII data) from the `certificates_generatedcertificate` table. This is designed as a one-time use data fixup, as the retirement functionality should clean this moving forward.
one time data migration for certificates that ended up in a broken
state (not marked is unavailable, but having invalidation records).
FIXES: APER-1322
undid my auto formatters reordering of the includes, because I'm
assuming that's what the lint-amnesty directives are there for. Best
practice would have a human-written comment explaining why they need to
stay there, but I'm just going have to assume it's correct, Because no
such human-written comment exists.
FIXES: APER-2851
adds a management command to modify certificate templates, with a dry
run option. Inherently unsafe; just as a search and replace on the first
string match.
TODO:
* unit tests
* make sure the multi-line string replacements work via django admin
FIXES: APER-2851
* feat: receiver for invalidate certificate
- consumes event of exam attempt rejected
- initial commit, need to make tests
* temp: moving consumer from signals to handlers.py
- Still need to make this work
- Need to make tests work too
* feat: refactored underlying code to api.py
- tests still need to be tweaked
* fix: commit history
* fix: improve api func name + add source param
This PR adds the ability for the LMS to publish `CERTIFICATE_REVOKED` events to the Event Bus. There is also work in progress for Credentials to consume these events.
[APER-2347]
This PR updates the name of the topic we are publishing our `CERTIFICATE_CREATED` events to. We had put a very generic name when writing the publishing code (and this was way before the actual topic was created). Now that the Confluent configuration is ready we need to update the name in our publishing code.
[APER-2344]
We would like to start consuming Certificate related events in Credentials from the event bus. This PR starts the process by publishing CERTIFICATE_CREATED events to the event bus. It also introduces a new feature flag (`SEND_CERTIFICATE_CREATED_SIGNAL`) to gate the functionality.