Skip to content

Commit

Permalink
feat: product_type = degree in management command for SFMC Course Cat…
Browse files Browse the repository at this point in the history
…alog POC'
  • Loading branch information
hamza-56 committed Sep 2, 2024
1 parent 83681de commit 3295e16
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from django.db.models import Prefetch

from course_discovery.apps.course_metadata.gspread_client import GspreadClient
from course_discovery.apps.course_metadata.models import Course, CourseType, SubjectTranslation
from course_discovery.apps.course_metadata.models import Course, CourseType, SubjectTranslation, Program

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -73,7 +73,7 @@ def get_products(self, product_type, product_source):
'verified', 'spoc-verified-audit'
]

if (product_type := product_type.lower()) in ['executive_education', 'bootcamp', 'ocm_course']:
if product_type in ['executive_education', 'bootcamp', 'ocm_course']:
queryset = Course.objects.available()

if product_type == 'ocm_course':
Expand All @@ -100,6 +100,26 @@ def get_products(self, product_type, product_source):
'subjects',
subject_translations
)
elif product_type == 'degree':
queryset = Program.objects.marketable() \
.exclude(degree__isnull=True) \
.select_related('partner', 'type')

if product_source:
queryset = queryset.filter(product_source__slug=product_source)

subject_translations = Prefetch(
'courses__subjects__translations',
queryset=SubjectTranslation.objects.filter(language_code='es'),
to_attr='spanish_translations'
)

return queryset.prefetch_related(
'authoring_organizations',
'courses__subjects',
'courses__course_runs',
subject_translations,
)
else:
# Return empty queryset if invalid product type specified
return Course.objects.none()
Expand All @@ -112,28 +132,43 @@ def write_csv_header(self, output_csv):
writer.writeheader()
return writer

def get_transformed_data(self, product):
def get_transformed_data(self, product, product_type):
"""
Transforms the product data for product's catalog
"""
authoring_orgs = product.authoring_organizations.all()
return {

common_data = {
"UUID": str(product.uuid),
"Title": product.title,
"Organizations Name": ", ".join(org.name for org in authoring_orgs),
"Organizations Logo": ", ".join(
org.logo_image.url for org in authoring_orgs if org.logo_image
),
"Organizations Logo": ", ".join(org.logo_image.url for org in authoring_orgs if org.logo_image),
"Organizations Abbr": ", ".join(org.key for org in authoring_orgs),
"Languages": product.languages_codes,
"Subjects": ", ".join(subject.name for subject in product.subjects.all()),
"Subjects Spanish": ", ".join(
translation.name for subject in product.subjects.all()
for translation in subject.spanish_translations
),
"Marketing URL": product.marketing_url,
"Marketing Image": (product.image.url if product.image else ""),
}
if product_type in ['executive_education', 'bootcamp', 'ocm_course']:
common_data.update({
"Subjects": ", ".join(subject.name for subject in product.subjects.all()),
"Subjects Spanish": ", ".join(
translation.name for subject in product.subjects.all()
for translation in subject.spanish_translations
),
"Languages": product.languages_codes,
"Marketing Image": product.image.url if product.image else "",
})
elif product_type == 'degree':
common_data.update({
"Subjects": ", ".join(subject.name for subject in product.subjects),
"Subjects Spanish": ", ".join(
translation.name for subject in product.subjects
for translation in subject.spanish_translations
),
"Languages": ", ".join(language.code for language in product.languages),
"Marketing Image": product.card_image.url if product.card_image else "",
})

return common_data


def handle(self, *args, **options):
product_type = options.get('product_type')
Expand All @@ -152,6 +187,7 @@ def handle(self, *args, **options):
gspread_client = GspreadClient()

try:
product_type = product_type.lower()
products = self.get_products(product_type, product_source)
if not products.exists():
raise CommandError('No products found for the given criteria.')
Expand All @@ -163,15 +199,15 @@ def handle(self, *args, **options):
output_writer = self.write_csv_header(output_file)
for product in products:
try:
output_writer.writerow(self.get_transformed_data(product))
output_writer.writerow(self.get_transformed_data(product, product_type))
except Exception as e: # pylint: disable=broad-exception-caught
logger.error(f"Error writing product {product.uuid} to CSV: {str(e)}")
continue

logger.info(f'Populated {products_count} {product_type}s to {output_csv}')

elif gspread_client_flag:
csv_data = [self.get_transformed_data(product) for product in products]
csv_data = [self.get_transformed_data(product, product_type) for product in products]
gspread_client.write_data(
PRODUCT_CATALOG_CONFIG,
self.CATALOG_CSV_HEADERS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@

from course_discovery.apps.course_metadata.choices import CourseRunStatus
from course_discovery.apps.course_metadata.management.commands.populate_product_catalog import Command
from course_discovery.apps.course_metadata.models import Course, CourseType
from course_discovery.apps.course_metadata.models import Course, CourseType, ProgramType
from course_discovery.apps.course_metadata.tests.factories import (
CourseFactory, CourseRunFactory, CourseTypeFactory, PartnerFactory, SeatFactory, SourceFactory
CourseFactory, CourseRunFactory, CourseTypeFactory, PartnerFactory, SeatFactory, SourceFactory,
ProgramTypeFactory, DegreeFactory
)


Expand All @@ -37,6 +38,14 @@ def setUp(self):
self.course_run_2 = CourseRunFactory.create_batch(
2, course=Course.objects.all()[1]
)
self.program_type = ProgramTypeFactory.create(slug=ProgramType.MICROMASTERS)
self.degrees = DegreeFactory.create_batch(
2,
product_source=self.source,
partner=self.partner,
additional_metadata=None,
type=self.program_type,
)

def test_populate_product_catalog(self):
"""
Expand Down Expand Up @@ -65,6 +74,33 @@ def test_populate_product_catalog(self):
self.assertIn("Marketing URL", row)
self.assertIn("Marketing Image", row)

def test_populate_product_catalog_for_degree(self):
"""
Test populate_product_catalog command for degree product type and verify data has been populated successfully
"""
with NamedTemporaryFile(mode="w", delete=False) as output_csv:
call_command(
"populate_product_catalog",
product_type="degree",
output_csv=output_csv.name,
product_source="edx",
gspread_client_flag=False,
)

with open(output_csv.name, "r") as output_csv_file:
csv_reader = csv.DictReader(output_csv_file)
for row in csv_reader:
self.assertIn("UUID", row)
self.assertIn("Title", row)
self.assertIn("Organizations Name", row)
self.assertIn("Organizations Logo", row)
self.assertIn("Organizations Abbr", row)
self.assertIn("Languages", row)
self.assertIn("Subjects", row)
self.assertIn("Subjects Spanish", row)
self.assertIn("Marketing URL", row)
self.assertIn("Marketing Image", row)

@mock.patch(
"course_discovery.apps.course_metadata.management.commands.populate_product_catalog.Command.get_products"
)
Expand Down Expand Up @@ -114,7 +150,7 @@ def test_get_transformed_data(self):
product = self.courses[0]
command = Command()
product_authoring_orgs = product.authoring_organizations.all()
transformed_prod_data = command.get_transformed_data(product)
transformed_prod_data = command.get_transformed_data(product, "ocm_course")
assert transformed_prod_data == {
"UUID": str(product.uuid),
"Title": product.title,
Expand All @@ -140,6 +176,32 @@ def test_get_transformed_data(self):
"Marketing Image": (product.image.url if product.image else ""),
}

def test_get_transformed_data_for_degree(self):
"""
Verify get_transformed_data method is working correctly for degree
"""
product = self.degrees[0]
command = Command()
product_authoring_orgs = product.authoring_organizations.all()
transformed_prod_data = command.get_transformed_data(product, "degree")
assert transformed_prod_data == {
"UUID": str(product.uuid),
"Title": product.title,
"Organizations Name": ", ".join(org.name for org in product_authoring_orgs),
"Organizations Logo": ", ".join(
org.logo_image.url for org in product_authoring_orgs if org.logo_image
),
"Organizations Abbr": ", ".join(org.key for org in product_authoring_orgs),
"Languages": ", ".join(language.code for language in product.languages),
"Subjects": ", ".join(subject.name for subject in product.subjects),
"Subjects Spanish": ", ".join(
translation.name for subject in product.subjects
for translation in subject.spanish_translations
),
"Marketing URL": product.marketing_url,
"Marketing Image": product.card_image.url if product.card_image else "",
}

@mock.patch('course_discovery.apps.course_metadata.management.commands.populate_product_catalog.GspreadClient')
@mock.patch(
'course_discovery.apps.course_metadata.management.commands.populate_product_catalog.Command.get_products'
Expand Down

0 comments on commit 3295e16

Please sign in to comment.