Commit 519f9189 by Simon Chen

Populate the publisher with required course data from course_metadata

EDUCATOR-676
parent 0a75314a
import io
import logging import logging
import requests
from django.core.files import File
from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole from course_discovery.apps.publisher.choices import CourseRunStateChoices, CourseStateChoices, PublisherUserRole
from course_discovery.apps.publisher.models import Course, CourseRun, CourseRunState, CourseState, Seat from course_discovery.apps.publisher.models import Course, CourseRun, CourseRunState, CourseState, Seat
...@@ -33,7 +37,7 @@ def process_course(meta_data_course): ...@@ -33,7 +37,7 @@ def process_course(meta_data_course):
create_or_update_course(meta_data_course, available_organization) create_or_update_course(meta_data_course, available_organization)
except: # pylint: disable=bare-except except: # pylint: disable=bare-except
logger.error('Exception appear for course-id [%s].', meta_data_course.uuid) logger.exception('Exception appear for course-id [%s].', meta_data_course.uuid)
def create_or_update_course(meta_data_course, available_organization): def create_or_update_course(meta_data_course, available_organization):
...@@ -57,7 +61,10 @@ def create_or_update_course(meta_data_course, available_organization): ...@@ -57,7 +61,10 @@ def create_or_update_course(meta_data_course, available_organization):
'level_type': meta_data_course.level_type, 'level_type': meta_data_course.level_type,
'primary_subject': primary_subject, 'secondary_subject': secondary_subject, 'primary_subject': primary_subject, 'secondary_subject': secondary_subject,
'tertiary_subject': tertiary_subject, 'tertiary_subject': tertiary_subject,
'video_link': meta_data_course.video.src if meta_data_course.video else None 'video_link': meta_data_course.video.src if meta_data_course.video else None,
'expected_learnings': meta_data_course.outcome,
'prerequisites': meta_data_course.prerequisites_raw,
'syllabus': meta_data_course.syllabus_raw,
} }
publisher_course, created = Course.objects.update_or_create( publisher_course, created = Course.objects.update_or_create(
...@@ -65,6 +72,8 @@ def create_or_update_course(meta_data_course, available_organization): ...@@ -65,6 +72,8 @@ def create_or_update_course(meta_data_course, available_organization):
defaults=defaults defaults=defaults
) )
transfer_course_image(meta_data_course, publisher_course)
if created: if created:
if available_organization: if available_organization:
publisher_course.organizations.add(available_organization) publisher_course.organizations.add(available_organization)
...@@ -84,6 +93,28 @@ def create_or_update_course(meta_data_course, available_organization): ...@@ -84,6 +93,28 @@ def create_or_update_course(meta_data_course, available_organization):
create_course_runs(meta_data_course, publisher_course) create_course_runs(meta_data_course, publisher_course)
def transfer_course_image(meta_data_course, publisher_course):
if meta_data_course.image:
publisher_course.image.save(
meta_data_course.image.name,
meta_data_course.image.file
)
elif meta_data_course.card_image_url:
response = requests.get(meta_data_course.card_image_url)
if response.status_code == 200:
img_name = meta_data_course.card_image_url.split('/')[-1]
with io.BytesIO() as fp:
fp.write(response.content)
publisher_course.image.save(img_name, File(fp))
else:
logger.error(
'Failed to download image for course [%s] from [%s]. Server responded with status [%d].',
meta_data_course.uuid,
meta_data_course.card_image_url,
response.status_code
)
def create_course_runs(meta_data_course, publisher_course): def create_course_runs(meta_data_course, publisher_course):
# create or update canonical course-run for the course. # create or update canonical course-run for the course.
canonical_course_run = meta_data_course.canonical_course_run canonical_course_run = meta_data_course.canonical_course_run
......
import logging
import ddt import ddt
import mock import mock
import responses
from django.core.management import CommandError, call_command from django.core.management import CommandError, call_command
from django.db import IntegrityError from django.db import IntegrityError
from django.test import TestCase from django.test import TestCase
from testfixtures import LogCapture from testfixtures import LogCapture
from course_discovery.apps.core.tests.helpers import make_image_file
from course_discovery.apps.course_metadata.models import CourseRun from course_discovery.apps.course_metadata.models import CourseRun
from course_discovery.apps.course_metadata.tests.factories import (CourseFactory, CourseRunFactory, OrganizationFactory, from course_discovery.apps.course_metadata.tests.factories import (
PersonFactory, SeatFactory, SubjectFactory) CourseFactory, CourseRunFactory, OrganizationFactory, PersonFactory, SeatFactory, SubjectFactory
)
from course_discovery.apps.ietf_language_tags.models import LanguageTag from course_discovery.apps.ietf_language_tags.models import LanguageTag
from course_discovery.apps.publisher.dataloader.create_courses import logger as dataloader_logger from course_discovery.apps.publisher.dataloader.create_courses import logger as dataloader_logger
from course_discovery.apps.publisher.dataloader.update_course_runs import logger as update_logger from course_discovery.apps.publisher.dataloader.update_course_runs import logger as update_logger
...@@ -101,7 +106,11 @@ class CreateCoursesTests(TestCase): ...@@ -101,7 +106,11 @@ class CreateCoursesTests(TestCase):
transcript_languages = LanguageTag.objects.all()[:2] transcript_languages = LanguageTag.objects.all()[:2]
self.subjects = SubjectFactory.create_batch(3) self.subjects = SubjectFactory.create_batch(3)
self.course = CourseFactory(subjects=self.subjects) self.test_image = make_image_file('testimage.jpg')
self.course = CourseFactory(
subjects=self.subjects,
image__from_file=self.test_image
)
self.command_name = 'import_metadata_courses' self.command_name = 'import_metadata_courses'
self.command_args = ['--start_id={}'.format(self.course.id), '--end_id={}'.format(self.course.id)] self.command_args = ['--start_id={}'.format(self.course.id), '--end_id={}'.format(self.course.id)]
...@@ -204,6 +213,54 @@ class CreateCoursesTests(TestCase): ...@@ -204,6 +213,54 @@ class CreateCoursesTests(TestCase):
), ),
) )
@responses.activate
def test_course_with_card_image_url(self):
self.course.image.delete()
self.test_image.open()
responses.add(
responses.GET,
self.course.card_image_url,
body=self.test_image.read(),
content_type='image/jpeg'
)
call_command(self.command_name, *self.command_args)
self.test_image.close()
publisher_course = Publisher_Course.objects.all().first()
self._assert_course(publisher_course)
@responses.activate
def test_course_with_non_existent_card_image_url(self):
self.course.image.delete()
request_status_code = 404
responses.add(
responses.GET,
self.course.card_image_url,
body=None,
content_type='image/jpeg',
status=request_status_code
)
with LogCapture(dataloader_logger.name, level=logging.ERROR) as log_capture:
call_command(self.command_name, *self.command_args)
log_capture.check(
(
dataloader_logger.name,
'ERROR',
'Failed to download image for course [{}] from [{}]. Server responded with status [{}].'.format(
self.course.uuid,
self.course.card_image_url,
request_status_code
)
)
)
def test_course_without_image(self):
self.course.image.delete()
self.course.card_image_url = None
self.course.save()
call_command(self.command_name, *self.command_args)
publisher_course = Publisher_Course.objects.all().first()
self._assert_course(publisher_course)
def test_course_run_without_seats(self): def test_course_run_without_seats(self):
""" Verify that import works fine even if course-run has no seats.""" """ Verify that import works fine even if course-run has no seats."""
self.course.canonical_course_run.seats.all().delete() self.course.canonical_course_run.seats.all().delete()
...@@ -234,6 +291,12 @@ class CreateCoursesTests(TestCase): ...@@ -234,6 +291,12 @@ class CreateCoursesTests(TestCase):
), ),
) )
def _assert_course_image(self, publisher_course):
if self.course.image or self.course.card_image_url:
assert publisher_course.image.url is not None
else:
assert bool(publisher_course.image) is False
def _assert_course(self, publisher_course): def _assert_course(self, publisher_course):
""" Verify that publisher course and metadata course has correct values.""" """ Verify that publisher course and metadata course has correct values."""
...@@ -258,6 +321,11 @@ class CreateCoursesTests(TestCase): ...@@ -258,6 +321,11 @@ class CreateCoursesTests(TestCase):
else: else:
self.assertFalse(publisher_course.video_link) self.assertFalse(publisher_course.video_link)
assert publisher_course.prerequisites == self.course.prerequisites_raw
assert publisher_course.syllabus == self.course.syllabus_raw
assert publisher_course.expected_learnings == self.course.outcome
self._assert_course_image(publisher_course)
def _assert_course_run(self, publisher_course_run, metadata_course_run): def _assert_course_run(self, publisher_course_run, metadata_course_run):
""" Verify that publisher course-run and metadata course run has correct values.""" """ Verify that publisher course-run and metadata course run has correct values."""
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment