From bef144756eee5b59d5b66fc353478ea2938255f1 Mon Sep 17 00:00:00 2001 From: annagav Date: Wed, 18 Dec 2024 12:28:35 -0800 Subject: [PATCH 1/2] add option to generate certificates for a program (#2497) --- .../commands/manage_program_certificates.py | 84 ++++++++++++------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/courses/management/commands/manage_program_certificates.py b/courses/management/commands/manage_program_certificates.py index b5c7b73f38..cbc16f5f17 100644 --- a/courses/management/commands/manage_program_certificates.py +++ b/courses/management/commands/manage_program_certificates.py @@ -19,13 +19,15 @@ 4. Un-Revoke a program certificate for a user ./mange.py manage_program_certificates -—unrevoke —-program= -—user= +5. Generate Program certificate for all enrolled users in the program who have earned it +./mange.py manage_program_certificates --create -—program= """ from django.contrib.auth import get_user_model from django.core.management.base import BaseCommand, CommandError from courses.api import generate_program_certificate, manage_program_certificate_access -from courses.models import Program +from courses.models import Program, ProgramEnrollment from users.api import fetch_user User = get_user_model() @@ -45,7 +47,7 @@ def add_arguments(self, parser): "--user", type=str, help="The id, email or username of the enrolled User", - required=True, + required=False, ) parser.add_argument( "--program", @@ -75,7 +77,7 @@ def add_arguments(self, parser): super().add_arguments(parser) - def handle(self, *args, **options): # pylint: disable=too-many-locals # noqa: ARG002 + def handle(self, *args, **options): # pylint: disable=too-many-locals # noqa: ARG002, C901 """Handle command execution""" revoke = options.get("revoke") @@ -90,12 +92,13 @@ def handle(self, *args, **options): # pylint: disable=too-many-locals # noqa: "The command needs a valid action e.g. --revoke, --unrevoke, --create." # noqa: EM101 ) - try: - user = fetch_user(user) - except User.DoesNotExist: - raise CommandError( # noqa: B904 - f"Could not find a user with ={user}." # noqa: EM102 - ) + if user: + try: + user = fetch_user(user) + except User.DoesNotExist: + raise CommandError( # noqa: B904 + f"Could not find a user with ={user}." # noqa: EM102 + ) # Unable to obtain a program object based on the provided program readable id try: @@ -105,6 +108,10 @@ def handle(self, *args, **options): # pylint: disable=too-many-locals # noqa: # Handle revoke/un-revoke of a certificate if revoke or unrevoke: + if not user: + raise CommandError( + "If you want to revoke/unrevoke a user argument is required" # noqa: EM101 + ) revoke_status = manage_program_certificate_access( user=user, program=program, @@ -125,27 +132,44 @@ def handle(self, *args, **options): # pylint: disable=too-many-locals # noqa: # Handle the creation of the program certificate. elif create: - # If -f or --force argument is provided, we'll forcefully generate the program certificate - certificate, created_cert = generate_program_certificate( - user=user, program=program, force_create=force_create - ) - success_result = True - - if created_cert: - cert_status = "created" - elif certificate and not created_cert: - cert_status = "already exists" - else: - success_result = False - cert_status = ( - "ignored, certificates for required courses are missing, use " - "-f or --force argument to forcefully create a program certificate" + if user: + # If -f or --force argument is provided, we'll forcefully generate the program certificate + certificate, created_cert = generate_program_certificate( + user=user, program=program, force_create=force_create ) + success_result = True + + if created_cert: + cert_status = "created" + elif certificate and not created_cert: + cert_status = "already exists" + else: + success_result = False + cert_status = ( + "ignored, certificates for required courses are missing, use " + "-f or --force argument to forcefully create a program certificate" + ) + + result_summary = f"Certificate: {cert_status}" - result_summary = f"Certificate: {cert_status}" + result = f"Processed user {user.username} ({user.email}) in program {program.readable_id}. Result - {result_summary}" + result_output = self.style.SUCCESS(result) + if not success_result: + result_output = self.style.ERROR(result) + self.stdout.write(result_output) + else: + # generate certificates for all enrolled users + enrollments = ProgramEnrollment.objects.filter(program=program) + cert_count = 0 + for enrollment in enrollments: + certificate, created_cert = generate_program_certificate( + user=enrollment.user, program=program + ) + if created_cert: + cert_count += 1 - result = f"Processed user {user.username} ({user.email}) in program {program.readable_id}. Result - {result_summary}" - result_output = self.style.SUCCESS(result) - if not success_result: - result_output = self.style.ERROR(result) - self.stdout.write(result_output) + self.stdout.write( + self.style.SUCCESS( + f"Successfully created {cert_count} certificates for program {program.readable_id}" + ) + ) From a49a7e801dd6e600efe93c9f2aaed452369ec90e Mon Sep 17 00:00:00 2001 From: Doof Date: Wed, 18 Dec 2024 20:29:03 +0000 Subject: [PATCH 2/2] Release 0.108.2 --- RELEASE.rst | 5 +++++ main/settings.py | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/RELEASE.rst b/RELEASE.rst index 07450535e6..191460098c 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -1,6 +1,11 @@ Release Notes ============= +Version 0.108.2 +--------------- + +- add option to generate certificates for a program (#2497) + Version 0.108.1 (Released December 18, 2024) --------------- diff --git a/main/settings.py b/main/settings.py index 0c078e3155..357e98f652 100644 --- a/main/settings.py +++ b/main/settings.py @@ -29,7 +29,7 @@ from main.celery_utils import OffsettingSchedule from main.sentry import init_sentry -VERSION = "0.108.1" +VERSION = "0.108.2" log = logging.getLogger()