Merge pull request #28168 from edx/jhynes/microba-1289_overviews-continued

refactor: Remove use of CourseOverview model directly in the Certificates app
This commit is contained in:
Justin Hynes
2021-07-13 12:40:59 -04:00
committed by GitHub
10 changed files with 166 additions and 58 deletions

View File

@@ -44,7 +44,6 @@ from lms.djangoapps.certificates.utils import (
has_html_certificates_enabled as _has_html_certificates_enabled
)
from openedx.core.djangoapps.content.course_overviews.api import get_course_overview_or_none
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
log = logging.getLogger("edx.certificate")
User = get_user_model()
@@ -243,7 +242,7 @@ def certificate_downloadable_status(student, course_key):
'uuid': None,
}
course_overview = CourseOverview.get_from_id(course_key)
course_overview = get_course_overview_or_none(course_key)
if (
not certificates_viewable_for_course(course_overview) and
CertificateStatuses.is_passing_status(current_status['status']) and

View File

@@ -396,7 +396,7 @@ class CertificatesListRestApiTest(AuthAndScopesTestMixin, SharedModuleStoreTestC
expected_download_url = reverse('certificates:render_cert_by_uuid', kwargs=kwargs)
self.assert_success_response_for_student(response, download_url=expected_download_url)
@patch('lms.djangoapps.certificates.apis.v0.views.get_course_run_details')
@patch('openedx.core.djangoapps.content.course_overviews.api.get_course_run_details')
def test_certificate_without_course(self, mock_get_course_run_details):
"""
Verify that certificates are returned for deleted XML courses.

View File

@@ -21,8 +21,11 @@ from lms.djangoapps.certificates.api import (
get_certificates_for_user
)
from lms.djangoapps.certificates.apis.v0.permissions import IsOwnerOrPublicCertificates
from openedx.core.djangoapps.catalog.utils import get_course_run_details
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.content.course_overviews.api import (
get_course_overview_or_none,
get_course_overviews_from_ids,
get_pseudo_course_overview
)
from openedx.core.djangoapps.user_api.accounts.api import visible_fields
from openedx.core.lib.api.authentication import BearerAuthenticationAllowInactiveUser
@@ -97,7 +100,7 @@ class CertificatesDetailView(APIView):
def get(self, request, username, course_id):
"""
Gets a certificate information.
Retrieves certificate information for a user in a specified course run.
Args:
request (Request): Django request object.
@@ -123,9 +126,10 @@ class CertificatesDetailView(APIView):
data={'error_code': 'no_certificate_for_user'}
)
course_overview = CourseOverview.get_from_id(course_id)
course_overview = get_course_overview_or_none(course_id)
# return 404 if it's not a PDF certificates and there is no active certificate configuration.
if not user_cert['is_pdf_certificate'] and not course_overview.has_any_active_web_certificate:
if not user_cert['is_pdf_certificate'] and (not course_overview or
not course_overview.has_any_active_web_certificate):
return Response(
status=404,
data={'error_code': 'no_certificate_configuration_for_course'}
@@ -174,7 +178,7 @@ class CertificatesListView(APIView):
)
])
def get(self, request, username):
"""Get a paginated list of bookmarks for a user.
"""Get a paginated list of certificates for a user.
**Use Case**
@@ -270,32 +274,22 @@ class CertificatesListView(APIView):
passing_certificates[course_key] = course_certificate
viewable_certificates = []
for course_key, course_overview in CourseOverview.get_from_ids(
list(passing_certificates.keys())
).items():
course_ids = list(passing_certificates.keys())
course_overviews = get_course_overviews_from_ids(course_ids)
for course_key, course_overview in course_overviews.items():
if not course_overview:
# For deleted XML courses in which learners have a valid certificate.
# i.e. MITx/7.00x/2013_Spring
course_overview = self._get_pseudo_course_overview(course_key)
course_overview = get_pseudo_course_overview(course_key)
if certificates_viewable_for_course(course_overview):
course_certificate = passing_certificates[course_key]
# add certificate into viewable certificate list only if it's a PDF certificate
# or there is an active certificate configuration.
if course_certificate['is_pdf_certificate'] or course_overview.has_any_active_web_certificate:
if course_certificate['is_pdf_certificate'] or (course_overview and
course_overview.has_any_active_web_certificate):
course_certificate['course_display_name'] = course_overview.display_name_with_default
course_certificate['course_organization'] = course_overview.display_org_with_default
viewable_certificates.append(course_certificate)
viewable_certificates.sort(key=lambda certificate: certificate['created'])
return viewable_certificates
def _get_pseudo_course_overview(self, course_key):
"""
Returns a pseudo course overview object for deleted courses.
"""
course_run = get_course_run_details(course_key, ['title'])
return CourseOverview(
display_name=course_run.get('title'),
display_org_with_default=course_key.org,
certificates_show_before_end=True
)

View File

@@ -30,7 +30,7 @@ from lms.djangoapps.badges.events.course_complete import course_badge_check
from lms.djangoapps.badges.events.course_meta import completion_check, course_group_check
from lms.djangoapps.certificates.data import CertificateStatuses
from lms.djangoapps.instructor_task.models import InstructorTask
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
from openedx.core.djangoapps.content.course_overviews.api import get_course_overview_or_none
from openedx.core.djangoapps.signals.signals import COURSE_CERT_AWARDED, COURSE_CERT_CHANGED, COURSE_CERT_REVOKED
from openedx.core.djangoapps.xmodule_django.models import NoneToEmptyManager
@@ -657,7 +657,12 @@ def certificate_info_for_user(user, course_id, grade, user_is_allowlisted, user_
certificate_type = 'N/A'
status = certificate_status(user_certificate)
certificate_generated = status['status'] == CertificateStatuses.downloadable
can_have_certificate = CourseOverview.get_from_id(course_id).may_certify()
can_have_certificate = False
course_overview = get_course_overview_or_none(course_id)
if course_overview:
can_have_certificate = course_overview.may_certify()
enrollment_mode, __ = CourseEnrollment.enrollment_mode_for_user(user, course_id)
mode_is_verified = enrollment_mode in CourseMode.VERIFIED_MODES
user_is_verified = grade is not None and mode_is_verified

View File

@@ -25,7 +25,6 @@ from lms.djangoapps.certificates.api import generate_certificate_task, get_certi
from lms.djangoapps.certificates.permissions import GENERATE_ALL_CERTIFICATES, VIEW_ALL_CERTIFICATES
from lms.djangoapps.instructor_task.api import generate_certificates_for_students
from openedx.core.djangoapps.content.course_overviews.api import get_course_overview_or_none
from openedx.core.djangoapps.content.course_overviews.models import CourseOverview
log = logging.getLogger(__name__)
@@ -113,16 +112,16 @@ def search_certificates(request):
except InvalidKeyError:
return HttpResponseBadRequest(_("Course id '{course_id}' is not valid").format(course_id=course_id))
else:
try:
if CourseOverview.get_from_id(course_key):
certificates = [certificate for certificate in certificates
if certificate['course_key'] == course_id]
if not certificates:
return JsonResponse([{'username': user.username, 'course_key': course_id, 'regenerate': False}])
except CourseOverview.DoesNotExist:
course_overview = get_course_overview_or_none(course_key)
if not course_overview:
msg = _("The course does not exist against the given key '{course_key}'").format(course_key=course_key)
return HttpResponseBadRequest(msg)
certificates = [certificate for certificate in certificates
if certificate['course_key'] == course_id]
if not certificates:
return JsonResponse([{'username': user.username, 'course_key': course_id, 'regenerate': False}])
return JsonResponse(certificates)
@@ -245,26 +244,24 @@ def generate_certificate_for_user(request):
if response is not None:
return response
try:
# Check that the course exists
CourseOverview.get_from_id(params["course_key"])
except CourseOverview.DoesNotExist:
course_overview = get_course_overview_or_none(params["course_key"])
if not course_overview:
msg = _("The course {course_key} does not exist").format(course_key=params["course_key"])
return HttpResponseBadRequest(msg)
else:
# Check that the user is enrolled in the course
if not CourseEnrollment.is_enrolled(params["user"], params["course_key"]):
msg = _("User {username} is not enrolled in the course {course_key}").format(
username=params["user"].username,
course_key=params["course_key"]
)
return HttpResponseBadRequest(msg)
# Attempt to generate certificate
generate_certificates_for_students(
request,
params["course_key"],
student_set="specific_student",
specific_student_id=params["user"].id
# Check that the user is enrolled in the course
if not CourseEnrollment.is_enrolled(params["user"], params["course_key"]):
msg = _("User {username} is not enrolled in the course {course_key}").format(
username=params["user"].username,
course_key=params["course_key"]
)
return HttpResponse(200)
return HttpResponseBadRequest(msg)
# Attempt to generate certificate
generate_certificates_for_students(
request,
params["course_key"],
student_set="specific_student",
specific_student_id=params["user"].id
)
return HttpResponse(200)

View File

@@ -44,7 +44,7 @@ from lms.djangoapps.certificates.models import (
)
from lms.djangoapps.certificates.permissions import PREVIEW_CERTIFICATES
from lms.djangoapps.certificates.utils import emit_certificate_event, get_certificate_url
from openedx.core.djangoapps.catalog.utils import get_course_run_details
from openedx.core.djangoapps.catalog.api import get_course_run_details
from openedx.core.djangoapps.certificates.api import display_date_for_certificate
from openedx.core.djangoapps.lang_pref.api import get_closest_released_language
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers