Skip to content

Commit

Permalink
Merge pull request #739 from openedx/iahmad/ENT-8192
Browse files Browse the repository at this point in the history
feat: Added content metadata tags for academy detail page
  • Loading branch information
irfanuddinahmad authored Jan 10, 2024
2 parents 3f1fbe8 + 278e7ca commit 6c2f81d
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 49 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by Django 4.2.7 on 2024-01-08 20:33

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('catalog', '0037_alter_historicalcontentmetadata_options_and_more'),
('academy', '0001_initial'),
]

operations = [
migrations.AddField(
model_name='tag',
name='content_metadata',
field=models.ManyToManyField(related_name='tags', to='catalog.contentmetadata'),
),
]
6 changes: 5 additions & 1 deletion enterprise_catalog/apps/academy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
from model_utils.models import TimeStampedModel
from simple_history.models import HistoricalRecords

from enterprise_catalog.apps.catalog.models import EnterpriseCatalog
from enterprise_catalog.apps.catalog.models import (
ContentMetadata,
EnterpriseCatalog,
)


class Tag(models.Model):
Expand All @@ -19,6 +22,7 @@ class Tag(models.Model):
"""
title = models.CharField(max_length=255, help_text=_('Tag title'))
description = models.TextField(help_text=_('Tag description.'))
content_metadata = models.ManyToManyField(ContentMetadata, related_name='tags')

class Meta:
verbose_name = _('Tag')
Expand Down
8 changes: 8 additions & 0 deletions enterprise_catalog/apps/academy/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
from factory.fuzzy import FuzzyText

from enterprise_catalog.apps.academy.models import Academy, Tag
from enterprise_catalog.apps.catalog.constants import COURSE
from enterprise_catalog.apps.catalog.tests.factories import (
ContentMetadataFactory,
EnterpriseCatalogFactory,
)

Expand All @@ -18,6 +20,12 @@ class Meta:

title = FuzzyText(length=32)

@factory.post_generation
def content_metadata(self, create, extracted, **kwargs): # pylint: disable=unused-argument
content_metadata1 = ContentMetadataFactory.create(content_type=COURSE)
content_metadata2 = ContentMetadataFactory.create(content_type=COURSE)
self.content_metadata.set([content_metadata1, content_metadata2]) # pylint: disable=no-member


class AcademyFactory(factory.django.DjangoModelFactory):
"""
Expand Down
8 changes: 5 additions & 3 deletions enterprise_catalog/apps/api/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -784,6 +784,7 @@ def _get_algolia_products_for_batch(
'enterprise_catalogs',
'enterprise_catalogs__academies',
'enterprise_catalogs__academies__tags',
'enterprise_catalogs__academies__tags__content_metadata',
)

# Retrieve ContentMetadata records for:
Expand Down Expand Up @@ -831,7 +832,7 @@ def _get_algolia_products_for_batch(
# First pass over the batch of content. The goal for this pass is to collect all the UUIDs directly associated with
# each content. This DOES NOT capture any UUIDs indirectly related to programs or pathways via associated courses
# or programs.
for metadata in content_metadata_to_process:
for metadata in content_metadata_to_process: # pylint: disable=too-many-nested-blocks
if metadata.content_type in (COURSE, PROGRAM, LEARNER_PATHWAY):
content_key = metadata.content_key
else:
Expand All @@ -856,8 +857,9 @@ def _get_algolia_products_for_batch(
academy_uuids_by_key[content_key].add(str(academy.uuid))
academy_uuids_by_catalog_uuid[str(catalog.uuid)].add(str(academy.uuid))
for tag in associated_academy_tags:
academy_tags_by_key[content_key].add(str(tag.title))
academy_tags_by_catalog_uuid[str(catalog.uuid)].add(str(tag.title))
if tag.content_metadata.filter(content_key=content_key):
academy_tags_by_key[content_key].add(str(tag.title))
academy_tags_by_catalog_uuid[str(catalog.uuid)].add(str(tag.title))

# Second pass. This time the goal is to capture indirect relationships on programs:
# * For each program:
Expand Down
55 changes: 10 additions & 45 deletions enterprise_catalog/apps/api/tests/test_tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,11 +681,13 @@ def setUp(self):

# Set up a catalog, query, and metadata for a course and course associated program
self.academy = AcademyFactory()
self.tag1 = self.academy.tags.all()[0]
self.enterprise_catalog_query = CatalogQueryFactory(uuid=SORTED_QUERY_UUID_LIST[0])
self.enterprise_catalog_courses = EnterpriseCatalogFactory(catalog_query=self.enterprise_catalog_query)
self.enterprise_catalog_courses.academies.add(self.academy)
self.course_metadata_published = ContentMetadataFactory(content_type=COURSE, content_key='course-1')
self.course_metadata_published.catalog_queries.set([self.enterprise_catalog_query])
self.course_metadata_published.tags.set([self.tag1])
self.course_metadata_unpublished = ContentMetadataFactory(content_type=COURSE, content_key='course-2')
self.course_metadata_unpublished.json_metadata.get('course_runs')[0].update({
'status': 'unpublished',
Expand Down Expand Up @@ -723,7 +725,7 @@ def _set_up_factory_data_for_algolia(self):
str(self.enterprise_catalog_course_runs.enterprise_uuid),
])
expected_academy_uuids = [str(self.academy.uuid)]
expected_academy_tags = sorted([tag.title for tag in self.academy.tags.all()])
expected_academy_tags = sorted([self.tag1.title])
expected_queries = sorted([(
str(self.enterprise_catalog_courses.catalog_query.uuid),
self.enterprise_catalog_courses.catalog_query.title,
Expand Down Expand Up @@ -1118,7 +1120,7 @@ def mock_replace_all_objects(products_iterable):
tasks.index_enterprise_catalog_in_algolia_task() # pylint: disable=no-value-for-parameter

products_found_log_records = [record for record in info_logs.output if ' products found.' in record]
assert ' 10 products found.' in products_found_log_records[0]
assert ' 9 products found.' in products_found_log_records[0]

# create expected data to be added/updated in the Algolia index.
expected_course_1_objects_to_index = []
Expand Down Expand Up @@ -1164,10 +1166,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'program-{program_uuid}-academy-uuids-0',
'academy_uuids': [str(self.enterprise_catalog_courses.academies.first().uuid)],
})
expected_program_1_objects_to_index.append({
'objectID': f'program-{program_uuid}-academy-tags-0',
'academy_tags': sorted([tag.title for tag in self.enterprise_catalog_courses.academies.first().tags.all()]),
})
expected_program_1_objects_to_index.append({
'objectID': f'program-{program_uuid}-catalog-query-uuids-0',
'enterprise_catalog_query_uuids': [str(self.enterprise_catalog_courses.catalog_query.uuid)],
Expand Down Expand Up @@ -1331,7 +1329,7 @@ def mock_replace_all_objects(products_iterable):
tasks.index_enterprise_catalog_in_algolia_task() # pylint: disable=no-value-for-parameter

products_found_log_records = [record for record in info_logs.output if ' products found.' in record]
assert ' 10 products found.' in products_found_log_records[0]
assert ' 9 products found.' in products_found_log_records[0]

# create expected data to be added/updated in the Algolia index.
expected_course_1_objects_to_index = []
Expand Down Expand Up @@ -1380,11 +1378,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'learnerpathway-{pathway_uuid}-academy-uuids-0',
'academy_uuids': [str(self.enterprise_catalog_courses.academies.first().uuid)],
})
expected_pathway_1_objects_to_index.append({
'key': pathway_1.content_key,
'objectID': f'learnerpathway-{pathway_uuid}-academy-tags-0',
'academy_tags': sorted([tag.title for tag in self.enterprise_catalog_courses.academies.first().tags.all()]),
})
expected_pathway_1_objects_to_index.append({
'key': pathway_1.content_key,
'objectID': f'learnerpathway-{pathway_uuid}-catalog-query-uuids-0',
Expand Down Expand Up @@ -1452,7 +1445,7 @@ def mock_replace_all_objects(products_iterable):
tasks.index_enterprise_catalog_in_algolia_task() # pylint: disable=no-value-for-parameter

products_found_log_records = [record for record in info_logs.output if ' products found.' in record]
assert ' 15 products found.' in products_found_log_records[0]
assert ' 13 products found.' in products_found_log_records[0]

# create expected data to be added/updated in the Algolia index.
expected_course_1_objects_to_index = []
Expand Down Expand Up @@ -1498,10 +1491,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'program-{program_uuid}-academy-uuids-0',
'academy_uuids': [str(self.enterprise_catalog_courses.academies.first().uuid)],
})
expected_program_1_objects_to_index.append({
'objectID': f'program-{program_uuid}-academy-tags-0',
'academy_tags': sorted([tag.title for tag in self.enterprise_catalog_courses.academies.first().tags.all()]),
})
expected_program_1_objects_to_index.append({
'objectID': f'program-{program_uuid}-catalog-query-uuids-0',
'enterprise_catalog_query_uuids': [str(self.enterprise_catalog_courses.catalog_query.uuid)],
Expand All @@ -1525,11 +1514,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'learnerpathway-{pathway_uuid}-academy-uuids-0',
'academy_uuids': [str(self.enterprise_catalog_courses.academies.first().uuid)],
})
expected_pathway_1_objects_to_index.append({
'key': pathway_1.content_key,
'objectID': f'learnerpathway-{pathway_uuid}-academy-tags-0',
'academy_tags': sorted([tag.title for tag in self.enterprise_catalog_courses.academies.first().tags.all()]),
})
expected_pathway_1_objects_to_index.append({
'key': pathway_1.content_key,
'objectID': f'learnerpathway-{pathway_uuid}-catalog-query-uuids-0',
Expand Down Expand Up @@ -1633,7 +1617,7 @@ def mock_replace_all_objects(products_iterable):
tasks.index_enterprise_catalog_in_algolia_task() # pylint: disable=no-value-for-parameter

products_found_log_records = [record for record in info_logs.output if ' products found.' in record]
assert ' 25 products found.' in products_found_log_records[0]
assert ' 23 products found.' in products_found_log_records[0]

# create expected data to be added/updated in the Algolia index.
expected_algolia_objects_to_index = []
Expand Down Expand Up @@ -1679,10 +1663,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'program-{program_uuid}-academy-uuids-0',
'academy_uuids': [str(self.enterprise_catalog_courses.academies.first().uuid)],
})
expected_algolia_program_objects3.append({
'objectID': f'program-{program_uuid}-academy-tags-0',
'academy_tags': sorted([tag.title for tag in self.enterprise_catalog_courses.academies.first().tags.all()]),
})
expected_algolia_program_objects3.append({
'objectID': f'program-{program_uuid}-catalog-query-uuids-0',
'enterprise_catalog_query_uuids': [str(self.enterprise_catalog_courses.catalog_query.uuid)],
Expand Down Expand Up @@ -1735,11 +1715,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'learnerpathway-{pathway_uuid}-academy-uuids-0',
'academy_uuids': [str(self.enterprise_catalog_courses.academies.first().uuid)],
})
expected_algolia_pathway_objects2.append({
'key': pathway_for_courserun.content_key,
'objectID': f'learnerpathway-{pathway_uuid}-academy-tags-0',
'academy_tags': sorted([tag.title for tag in self.enterprise_catalog_courses.academies.first().tags.all()]),
})
expected_algolia_pathway_objects2.append({
'key': pathway_for_courserun.content_key,
'objectID': f'learnerpathway-{pathway_uuid}-catalog-query-uuids-0',
Expand Down Expand Up @@ -1813,7 +1788,7 @@ def mock_replace_all_objects(products_iterable):
with self.assertLogs(level='INFO') as info_logs:
tasks.index_enterprise_catalog_in_algolia_task() # pylint: disable=no-value-for-parameter

assert ' 9 products found.' in info_logs.output[-1]
assert ' 8 products found.' in info_logs.output[-1]

# create expected data to be added/updated in the Algolia index.
expected_algolia_objects_to_index = []
Expand Down Expand Up @@ -1848,11 +1823,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'course-{published_course_uuid}-academy-tags-0',
'academy_tags': [algolia_data['academy_tags'][0]],
})
expected_algolia_objects_to_index.append({
'key': algolia_data['course_metadata_published'].content_key,
'objectID': f'course-{published_course_uuid}-academy-tags-1',
'academy_tags': [algolia_data['academy_tags'][1]],
})
expected_algolia_objects_to_index.append({
'key': algolia_data['course_metadata_published'].content_key,
'objectID': f'course-{published_course_uuid}-catalog-query-uuids-0',
Expand Down Expand Up @@ -1893,7 +1863,7 @@ def mock_replace_all_objects(products_iterable):
with self.assertLogs(level='INFO') as info_logs:
tasks.index_enterprise_catalog_in_algolia_task() # pylint: disable=no-value-for-parameter

assert ' 9 products found.' in info_logs.output[-1]
assert ' 8 products found.' in info_logs.output[-1]

# create expected data to be added/updated in the Algolia index.
expected_algolia_objects_to_index = []
Expand Down Expand Up @@ -1928,11 +1898,6 @@ def mock_replace_all_objects(products_iterable):
'objectID': f'course-{published_course_uuid}-academy-tags-0',
'academy_tags': [algolia_data['academy_tags'][0]],
})
expected_algolia_objects_to_index.append({
'key': algolia_data['course_metadata_published'].content_key,
'objectID': f'course-{published_course_uuid}-academy-tags-1',
'academy_tags': [algolia_data['academy_tags'][1]],
})
expected_algolia_objects_to_index.append({
'key': algolia_data['course_metadata_published'].content_key,
'objectID': f'course-{published_course_uuid}-catalog-query-uuids-0',
Expand Down Expand Up @@ -2004,7 +1969,7 @@ def test_index_algolia_dry_run(self, mock_search_client):
tasks.index_enterprise_catalog_in_algolia_task(force, dry_run)

mock_search_client().replace_all_objects.assert_not_called()
assert '[ENTERPRISE_CATALOG_ALGOLIA_REINDEX] [DRY RUN] 9 products found.' in info_logs.output[-1]
assert '[ENTERPRISE_CATALOG_ALGOLIA_REINDEX] [DRY RUN] 8 products found.' in info_logs.output[-1]
assert any(
'[ENTERPRISE_CATALOG_ALGOLIA_REINDEX] [DRY RUN] skipping algolia_client.replace_all_objects().' in record
for record in info_logs.output
Expand Down

0 comments on commit 6c2f81d

Please sign in to comment.