Skip to content
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/generate certificate management command #86

Merged
merged 5 commits into from
Apr 7, 2022

Conversation

jbpenrath
Copy link
Member

@jbpenrath jbpenrath commented Mar 18, 2022

Purpose

Now that we are able to retrieve enrollment grade from LMS, we need to be able to generate certificates.
The purpose of this pull request is to add a management command to generate certificate at regular interval through a cron task but also to allow staff users to generate certificates on demand through custom admin actions.

Furthermore, staff users are able to flag course runs as gradable in order to prevent certificate generation.

We added actions to generate certificates into three models (Product, Course and Order). So in this way, staff users are able to generate certificates for:

one or several orders

image

image

one or several products

image

image

one or several courses

image

image

a course - product couple

image

image

image

Proposal

  • Improve CourseRun model to mark a course run as gradable
  • Create a management command to generate all certificates available

Related issue: #75

@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from b263e8f to ee222fe Compare March 29, 2022 14:48
@jbpenrath jbpenrath added this to the GRADEO milestone Mar 29, 2022
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from ee222fe to 7005e52 Compare March 29, 2022 15:03
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from 7005e52 to 46249d8 Compare March 29, 2022 15:26
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
"""
codes = [course.code for course in queryset]
certificate_generated_count = management.call_command(
"create_certificates", courses=codes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it should be done like this... especially as the list of codes may be big. I would be better to factorize the code in a function that can be called by your command and by this function?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's try to resume your thought just to be sure I understand your request.

Do you mean, I should not use call_command here but create a function that I'll call here and within the management command?

Then instead to pass a long list of course codes as arguments, I could iterate over selected courses?

About this point, I could write something like this

certificate_generated_count = 0
for course in queryset.iterator():
  certificate_generated_count += management.call_command("create_certificates", courses=course.code)

summarize_certification_to_user(request, certificate_generated_count)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes that's what I meant but that's not what you proposed in the second part of your answer? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I misspoke. The code suggestion was only about my second point :

Then instead to pass a long list of course codes as arguments, I could iterate over selected courses?

But I'm not quit sure to understand why I should not use the management command here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I create an helpers module with two methods generate_certificate_for_order and generate_certificates_for_orders.

src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
course_runs = models.CourseRun.objects.filter(
course__in=graded_courses,
is_gradable=True,
start__lte=timezone.now(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or end_lte? I don't think we want to grade before the end of the course?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my point of view, the is_gradable flag should mediate this question. If a course leader wants to allow certification before the end of the course, he could and if he wants to wait the end of the course, he just has to update is_gradable once the course ended.

)

enrollments = order.enrollments.filter(
course_run__in=course_runs, is_active=True
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is a small trick here: you say "generate for order" but you may select enrollments here that are related to other orders staging the same course run... 🤔 Add a filter clause and a test if I'm right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using order.enrollments so there is no risk to get enrollment related to other order, nope?

@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch 2 times, most recently from f9784d9 to 4174c40 Compare April 1, 2022 13:41
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from bc08ca4 to f1ece51 Compare April 1, 2022 14:52
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch 2 times, most recently from 190e16a to 42123af Compare April 6, 2022 08:05
src/backend/joanie/core/admin.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/core/helpers.py Outdated Show resolved Hide resolved
course_run.course.product_relations.update(is_graded=False)
course = factories.CourseFactory(products=[product])
order = factories.OrderFactory(product=product, course=course)
certificate = models.Certificate.objects.filter(order=order)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it shouldn't be called certificate when it's a query. Same for other occurences in other test files.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed it certificate_qs

src/backend/joanie/tests/test_helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/tests/test_helpers.py Outdated Show resolved Hide resolved
src/backend/joanie/tests/test_models_enrollment.py Outdated Show resolved Hide resolved
src/backend/joanie/tests/test_models_enrollment.py Outdated Show resolved Hide resolved
Makefile Outdated Show resolved Hide resolved
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from 1714e42 to f4324e5 Compare April 7, 2022 09:16
This boolean field allow a course leader to mark its session as gradable.
Gradable course runs can be used to generate a certificate.
This property is a shortcut which retrieve the enrollment grade from its related
LMS then check if it is passed. To prevent to spam LMS, the setting
`JOANIE_ENROLLMENT_GRADE_CACHE_TTL` is used to store grade state in cache.
By default, for 10 minutes.
Create a management command which aims to be called by a cron task to generate
certificate at a regular interval. This command accepts three options (course,
product and order) to restrict review to those resources.
django-object-actions allows us to add custom actions with admin change views.
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from f4324e5 to 7cf84f4 Compare April 7, 2022 09:32
Create custom actions across all relevant models (products, course and orders)
to generate certificates through the bunch of provided resources.
@jbpenrath jbpenrath force-pushed the feat/generate-certificate-management-command branch from 7cf84f4 to 7620e67 Compare April 7, 2022 09:36
@jbpenrath jbpenrath merged commit c1c98ae into main Apr 7, 2022
@jbpenrath jbpenrath deleted the feat/generate-certificate-management-command branch April 7, 2022 09:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants