-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add default enrollment models #2259
Conversation
eb54fbe
to
fe71e9d
Compare
619692e
to
ee01911
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few non-blocking questions. Great job!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[curious] 2 observations.
If the DefaultEnterpriseEnrollmentIntention
content_key
enrollable course differs from DefaultEnterpriseEnrollmentRealization
, EnterpriseCourseEnrollment
enrolled course, are there any consequences from the mismatch?
Were there any alternatives considered?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a stab at trying to clarify any potential mismatches.
The content_key
on DefaultEnterpriseEnrollmentIntention
is either a top-level course key or a course run key during configuration to remain flexible for ECS; however, we will always discern the correct course run key to use for enrollment based on the provided content_key
.
Post-enrollment related models (e.g., EnterpriseCourseEnrollment
and DefaultEnterpriseEnrollmentRealization
) will always primarily be associated with the course run associated with the DefaultEnterpriseEnrollmentIntention
:
- If
content_key
is a top-level course, the course run key used when enrolling (converting toEnterpriseCourseEnrollment
andDefaultEnterpriseEnrollmentRealization
) is the currently advertised course run. - If the
content_key
is a specific course run, we'll always try to enroll in the explicitly configured course run key (not the advertised course run).
This content_key
will be passed to the EnterpriseCatalogApiClient().get_content_metadata_content_identifier
method. When passing a course run key to this endpoint, it'll actually return the top-level course metadata associated with the course run, not just the specified course run's metadata (this is primarily due to catalogs containing courses, not course runs and we generally say that if the top-level course is in a customer's catalog, all of its course runs are, too (with exceptions like the ongoing restricted runs work).
If the content_key
configured for a DefaultEnterpriseEnrollmentIntention
is a top-level course, there is a chance the currently advertised course run used for future enrollment intentions might change over time from previous redeemed/enrolled DefaultEnterpriseEnrollmentIntention
s. However, I think this is mitigated in that the DefaultEnterpriseEnrollmentRealization
ensures the resulting, converted enrollment is still related to the original DefaultEnterpriseEnrollmentIntention
, despite a potential content_key
vs. enrollment ID match.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is nice, so I copied it into a new section of the ADR.
content_type = models.CharField( | ||
max_length=127, | ||
blank=False, | ||
null=False, | ||
choices=DEFAULT_ENROLLMENT_CONTENT_TYPE_CHOICES, | ||
help_text=_( | ||
"The type of content (e.g. a course vs. a course run)." | ||
), | ||
) | ||
content_key = models.CharField( | ||
max_length=255, | ||
blank=False, | ||
null=False, | ||
help_text=_( | ||
"A course or course run that related users should be automatically enrolled into." | ||
), | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[questionx2] is there some benefit to including parent_content_key
as a field? Should we bring the pattern of is_assigned_course_run
from access here as well, is_default_course_run
?
|
||
|
||
@admin.register(models.DefaultEnterpriseEnrollmentIntention) | ||
class DefaultEnterpriseEnrollmentIntentionAdmin(admin.ModelAdmin): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit/consideration: I wonder if it's worth getting djangoql
(GitHub) integrated within edx-enterprise, starting with the new models?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's a stab at trying to clarify any potential mismatches.
The content_key
on DefaultEnterpriseEnrollmentIntention
is either a top-level course key or a course run key during configuration to remain flexible for ECS; however, we will always discern the correct course run key to use for enrollment based on the provided content_key
.
Post-enrollment related models (e.g., EnterpriseCourseEnrollment
and DefaultEnterpriseEnrollmentRealization
) will always primarily be associated with the course run associated with the DefaultEnterpriseEnrollmentIntention
:
- If
content_key
is a top-level course, the course run key used when enrolling (converting toEnterpriseCourseEnrollment
andDefaultEnterpriseEnrollmentRealization
) is the currently advertised course run. - If the
content_key
is a specific course run, we'll always try to enroll in the explicitly configured course run key (not the advertised course run).
This content_key
will be passed to the EnterpriseCatalogApiClient().get_content_metadata_content_identifier
method. When passing a course run key to this endpoint, it'll actually return the top-level course metadata associated with the course run, not just the specified course run's metadata (this is primarily due to catalogs containing courses, not course runs and we generally say that if the top-level course is in a customer's catalog, all of its course runs are, too (with exceptions like the ongoing restricted runs work).
If the content_key
configured for a DefaultEnterpriseEnrollmentIntention
is a top-level course, there is a chance the currently advertised course run used for future enrollment intentions might change over time from previous redeemed/enrolled DefaultEnterpriseEnrollmentIntention
s. However, I think this is mitigated in that the DefaultEnterpriseEnrollmentRealization
ensures the resulting, converted enrollment is still related to the original DefaultEnterpriseEnrollmentIntention
, despite a potential content_key
vs. enrollment ID match.
the default enrollment flow should cause the "realization" of default enrollments for learners | ||
into the currently-advertised, enrollable run for a course. | ||
2. Default Enrollments should be loosely coupled to subsidy type. | ||
3. Unenrollment: If a learner chooses to unenroll from a default course, they should not be automatically re-enrolled. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might it also be worth calling out the "learner is already enrolled" case? Or do you think would be better suited for another ADR more about the proposed default-enterprise-enrollment-intentions/learner-status
GET API instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there should be a distinct ADR (loosely) describing the proposed API contract.
make this efficient). | ||
3. We're introducing more complexity in terms of how subsidized enterprise enrollments | ||
can come into existence. | ||
4. The realization model makes the provenance of default enrollments explicit and easy to examine. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎉
"The customer for which this default enrollment will be realized.", | ||
) | ||
) | ||
content_type = models.CharField( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[curious] What's your thinking around how this field would be utilized? From a functionality perspective, I'm not we'd necessary need it per se for the computed properties to function BUT having this field would definitely help better understand/analyze/query these models to understand how many courses vs. course runs are configured.
Do you think this is intended to be manually set at time of configuring a DefaultEnterpriseEnrollmentIntention
, or would it be programmatically set after saving based on deducing whether the provided content_key
is a course vs. course run (perhaps based on the content metadata API request made to enterprise-catalog which I believe returns the content_key
vs. parent_content_key
relationship?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either one - we could populate it automatically based on a simple regular expression.
) | ||
) | ||
content_type = models.CharField( | ||
max_length=127, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit/curious: Why 127
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(2^7 - 1). i.e the same reason we use max_length
of 255 instead of 256. I'm not sure how much this matters, if it matters at all. There used to be some thing about using one fewer chars than a power of two to make page fetches more efficient (I think).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, TIL haha.
2. Default Enrollments should be loosely coupled to subsidy type. | ||
3. Unenrollment: If a learner chooses to unenroll from a default course, they should not be automatically re-enrolled. | ||
4. Graceful handling of license revocation: Upon license revocation, we currently downgrade the learner’s | ||
enrollment mode to ``audit``. This fact should be visible from any new APIs exposed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call to make the course mode known in the proposed default-enterprise-enrollment-intentions/learner-status/
GET API.
fa285e5
to
2acd810
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, one addtl nit about the name of PendingEnterpriseCourseEnrollments
vs. PendingEnrollments
in the ADR.
Enterprise needs a solution for managing automated enrollments into "default" courses or specific course runs | ||
for enterprise learners. Importantly, we need this solution to work for learners where we have no information | ||
about the identity of learner who will eventually be associated with an ``EnterpriseCustomer``. For that reason, | ||
the solution described below does not involve ``PendingEnterpriseCourseEnrollments`` or anything similar - |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: the model name for pending enrollments is only PendingEnrollments
(source).
) | ||
) | ||
content_type = models.CharField( | ||
max_length=127, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, TIL haha.
2acd810
to
36d5b35
Compare
Adds two models, `DefaultEnterpriseEnrollmentIntention` and `DefaultEnterpriseEnrollmentRealization`. The former defines, for a customer, a course/run that associated users should be automatically enrolled into. The latter represents the relationship between that intention record and a realized EnterpriseCourseEnrollment; persisting realized enrollments in this way will help to make read operations related to default enrollments much more efficient. ENT-9577
36d5b35
to
59d1d40
Compare
Adds two models,
DefaultEnterpriseEnrollmentIntention
andDefaultEnterpriseEnrollmentRealization
. The former defines, for a customer, a course/run that associated users should be automatically enrolled into. The latter represents the relationship between that intention record and a realized EnterpriseCourseEnrollment; persisting realized enrollments in this way will help to make read operations related to default enrollments much more efficient.ENT-9577
Merge checklist:
requirements/*.txt
files)base.in
if needed in production but edx-platform doesn't install ittest-master.in
if edx-platform pins it, with a matching versionmake upgrade && make requirements
have been run to regenerate requirementsmake static
has been run to update webpack bundling if any static content was updated./manage.py makemigrations
has been run./manage.py lms makemigrations
in the shell.Post merge:
(so basically once your build finishes, after maybe a minute you should see the new version in PyPi automatically (on refresh))
make upgrade
in edx-platform will look for the latest version in PyPi.