Return absolute URIs from program_enrollments API responses (#21474)

Issues were caused in Learner Portal from inconsistency
in whether URLs returned by API calls were absolute
or relative. This commit standardizes them to all be
absolute.
This commit is contained in:
Kyle McCormick
2019-08-28 12:57:46 -04:00
committed by GitHub
parent b9a2646e4d
commit a8e4461ef7
2 changed files with 54 additions and 18 deletions

View File

@@ -1432,7 +1432,8 @@ class ProgramCourseEnrollmentOverviewViewTests(ProgramCacheTestCaseMixin, Shared
cls.yesterday = datetime.utcnow() - timedelta(1)
cls.tomorrow = datetime.utcnow() + timedelta(1)
cls.certificate_download_url = 'www.certificates.com'
cls.relative_certificate_download_url = '/download-the-certificates'
cls.absolute_certificate_download_url = 'http://www.certificates.com/'
def setUp(self):
super(ProgramCourseEnrollmentOverviewViewTests, self).setUp()
@@ -1471,13 +1472,13 @@ class ProgramCourseEnrollmentOverviewViewTests(ProgramCacheTestCaseMixin, Shared
self.program['curricula'][0]['courses'].append(self.course)
self.set_program_in_catalog_cache(self.program_uuid, self.program)
def create_generated_certificate(self):
def create_generated_certificate(self, download_url=None):
return GeneratedCertificateFactory.create(
user=self.student,
course_id=self.course_id,
status=CertificateStatuses.downloadable,
mode='verified',
download_url=self.certificate_download_url,
download_url=(download_url or self.relative_certificate_download_url),
grade="0.88",
verify_uuid=uuid4(),
)
@@ -1540,33 +1541,60 @@ class ProgramCourseEnrollmentOverviewViewTests(ProgramCacheTestCaseMixin, Shared
expected_course_run_ids = {text_type(other_course_key), text_type(self.course_id)}
self.assertEqual(expected_course_run_ids, actual_course_run_ids)
@mock.patch('lms.djangoapps.program_enrollments.api.v1.views.get_resume_urls_for_enrollments')
def test_resume_urls(self, mock_get_resume_urls):
self.client.login(username=self.student.username, password=self.password)
_GET_RESUME_URL = 'lms.djangoapps.program_enrollments.api.v1.views.get_resume_urls_for_enrollments'
@mock.patch(_GET_RESUME_URL)
def test_blank_resume_url_omitted(self, mock_get_resume_urls):
self.client.login(username=self.student.username, password=self.password)
mock_get_resume_urls.return_value = {self.course_id: ''}
response = self.client.get(self.get_url(self.program_uuid))
self.assertNotIn('resume_course_run_url', response.data['course_runs'][0])
resume_url = 'www.resume.com'
@mock.patch(_GET_RESUME_URL)
def test_relative_resume_url_becomes_absolute(self, mock_get_resume_urls):
self.client.login(username=self.student.username, password=self.password)
resume_url = '/resume-here'
mock_get_resume_urls.return_value = {self.course_id: resume_url}
response = self.client.get(self.get_url(self.program_uuid))
self.assertEqual(resume_url, response.data['course_runs'][0]['resume_course_run_url'])
response_resume_url = response.data['course_runs'][0]['resume_course_run_url']
self.assertTrue(response_resume_url.startswith("http://testserver"))
self.assertTrue(response_resume_url.endswith(resume_url))
def test_no_certificate_available(self):
@mock.patch(_GET_RESUME_URL)
def test_absolute_resume_url_stays_absolute(self, mock_get_resume_urls):
self.client.login(username=self.student.username, password=self.password)
resume_url = 'http://www.resume.com/'
mock_get_resume_urls.return_value = {self.course_id: resume_url}
response = self.client.get(self.get_url(self.program_uuid))
response_resume_url = response.data['course_runs'][0]['resume_course_run_url']
self.assertEqual(response_resume_url, resume_url)
def test_no_url_without_certificate(self):
self.client.login(username=self.student.username, password=self.password)
response = self.client.get(self.get_url(self.program_uuid))
self.assertEqual(status.HTTP_200_OK, response.status_code)
assert 'certificate_download_url' not in response.data['course_runs'][0]
self.assertNotIn('certificate_download_url', response.data['course_runs'][0])
def test_certificate_available(self):
def test_relative_certificate_url_becomes_absolute(self):
self.client.login(username=self.student.username, password=self.password)
self.create_generated_certificate()
self.create_generated_certificate(
download_url=self.relative_certificate_download_url
)
response = self.client.get(self.get_url(self.program_uuid))
self.assertEqual(status.HTTP_200_OK, response.status_code)
self.assertEqual(response.data['course_runs'][0]['certificate_download_url'], self.certificate_download_url)
response_url = response.data['course_runs'][0]['certificate_download_url']
self.assertTrue(response_url.startswith("http://testserver"))
self.assertTrue(response_url.endswith(self.relative_certificate_download_url))
def test_absolute_certificate_url_stays_absolute(self):
self.client.login(username=self.student.username, password=self.password)
self.create_generated_certificate(
download_url=self.absolute_certificate_download_url
)
response = self.client.get(self.get_url(self.program_uuid))
self.assertEqual(status.HTTP_200_OK, response.status_code)
response_url = response.data['course_runs'][0]['certificate_download_url']
self.assertEqual(response_url, self.absolute_certificate_download_url)
def test_no_due_dates(self):
self.client.login(username=self.student.username, password=self.password)

View File

@@ -956,9 +956,10 @@ class ProgramCourseEnrollmentOverviewView(DeveloperErrorViewMixin, ProgramSpecif
program course enrollment overview, where each overview contains the following keys:
* course_run_id: the id for the course run
* display_name: display name of the course run
* resume_course_run_url: the url that takes the user back to their position in the course run;
* resume_course_run_url: the absolute url that takes the user back to
their position in the course run;
if absent, user has not made progress in the course
* course_run_url: the url for the course run
* course_run_url: the absolute url for the course run
* start_date: the start date for the course run; null if no start date
* end_date: the end date for the course run' null if no end date
* course_run_status: the status of the course; one of "in_progress", "upcoming", and "completed"
@@ -1068,13 +1069,20 @@ class ProgramCourseEnrollmentOverviewView(DeveloperErrorViewMixin, ProgramSpecif
course_run_dict['emails_enabled'] = emails_enabled
if certificate_info.get('download_url'):
course_run_dict['certificate_download_url'] = certificate_info['download_url']
course_run_dict['certificate_download_url'] = request.build_absolute_uri(
certificate_info['download_url']
)
if self.program['type'] == 'MicroMasters':
course_run_dict['micromasters_title'] = self.program['title']
if course_run_resume_urls.get(enrollment.course_id):
course_run_dict['resume_course_run_url'] = course_run_resume_urls.get(enrollment.course_id)
relative_resume_course_run_url = course_run_resume_urls.get(
enrollment.course_id
)
course_run_dict['resume_course_run_url'] = request.build_absolute_uri(
relative_resume_course_run_url
)
course_runs.append(course_run_dict)