Skip to content

Commit

Permalink
Add Manufacturing topic; update upserter to make adding child topics …
Browse files Browse the repository at this point in the history
…easier (#1364)

* Add Manufacturing topic; update upserter to make adding child topics easier

* Updating the rollback to match on the topic's own uuid
  • Loading branch information
jkachel authored Aug 6, 2024
1 parent 5ef8945 commit 42e8c59
Show file tree
Hide file tree
Showing 4 changed files with 181 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
"""
Update the topics; add Manufacturing under Engineering
This is intended to fix https://github.com/mitodl/hq/issues/5076 - no additional
mappings since the topics for Principals of Manufacturing include "Manufacturing"
so it should match on name directly.
"""

from django.db import migrations

from channels.constants import ChannelType
from learning_resources.utils import upsert_topic_data_string

map_changes = """
---
topics:
- icon:
id: 4176e385-92c5-4e02-b3cc-4f34d9a4bf40
mappings: []
name: Manufacturing
children: []
parent: 952604ab-ae23-45b3-a040-0e5f26fe42df
"""


def add_new_mapping(apps, schema_editor):
"""Upsert the map_changes data above."""

upsert_topic_data_string(map_changes)


def rollback_new_mapping(apps, schema_editor):
"""Remove the Manufacturing topic."""

LearningResourceTopic = apps.get_model(
"learning_resources", "LearningResourceTopic"
)
Channel = apps.get_model("channels", "Channel")

topic = LearningResourceTopic.objects.filter(
topic_uuid="4176e385-92c5-4e02-b3cc-4f34d9a4bf40",
).get()

Channel.objects.filter(
channel_type=ChannelType.topic.name,
topic_detail__topic=topic,
).all().delete()

topic.delete()


class Migration(migrations.Migration):
dependencies = [
(
"data_fixtures",
"0007_topic_mappings_edx_add_programming_coding_to_computer_science",
),
]

operations = [migrations.RunPython(add_new_mapping, rollback_new_mapping)]
9 changes: 8 additions & 1 deletion learning_resources/data/README-topics.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,16 @@ topics:
- offeror topic
- other offeror topic
children: []
parent: optional ID for the parent (read the Updating section before using this)
```

Children use the same format as the items under `topics`.
Children use the same format as the items under `topics`. Topic IDs are UUIDs.

## Updating topics (and the `parent` element)

A given topic's parent/child relationship is usually defined by their position in the yaml file. Children are in the parent's `children` list and the upsert function uses this when it creates the topics in the database.

There is a slight problem with this - if you want to _modify_ a topic, you now have to specify the whole tree, or the upsert code won't know what they belong to. This is where the `parent` element comes in. You can set this to the UUID of the parent that it should have, and the upserter will load that topic and use it as the parent so you don't have to specify the whole tree.

## Transforming topic maps

Expand Down
17 changes: 17 additions & 0 deletions learning_resources/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ def _walk_topic_map(topics: list, parent: None | LearningResourceTopic = None) -
- icon - the icon we should display for the topic (a Remixicon, generally)
- mappings - mappings for topics found in offeror data
- children - child topics (records in this same format)
- parent - specific parent for the topic
A more detailed definition of this is in data/README-topics.md.
Args:
Expand All @@ -503,6 +504,22 @@ def _walk_topic_map(topics: list, parent: None | LearningResourceTopic = None) -
"icon": topic["icon"] or "",
}

if not parent and "parent" in topic:
# Topic specifies a parent, so let's try to grab it.
try:
defaults["parent"] = LearningResourceTopic.objects.filter(
topic_uuid=topic["parent"]
).get()
except LearningResourceTopic.DoesNotExist:
log.warning(
(
"_walk_topic_map: topic %s specified a parent %s but"
" the parent did not exist"
),
topic["name"],
topic["parent"],
)

if topic["id"]:
defaults["topic_uuid"] = topic["id"]

Expand Down
97 changes: 97 additions & 0 deletions learning_resources/utils_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,103 @@ def test_modify_topic_data_string(mocker):
)


def test_modify_topic_with_parent(mocker):
"""Test that the parent option is processed correctly when upserting topics"""

mock_pluggy = mocker.patch("learning_resources.utils.topic_upserted_actions")

base_topic_file = """
---
topics:
- icon: RiRobot2Line
id: c06109bf-cff8-4873-b04b-f5e66e3e1764
mappings:
mitx:
- Electronics
ocw:
- Technology
name: Data Science, Analytics & Computer Technology
children:
- children: []
icon: RiRobot2Line
id: 4cd6156e-51a0-4da4-add4-6f81e106cd43
mappings:
ocw:
- Programming Languages
- Software Design and Engineering
mitx:
- Computer Science
name: Programming & Coding
"""

new_topic_file = """
---
topics:
- children: []
icon: RiRobot2Line
id: d335c250-1292-4391-a7cb-3181f803e0f3
mappings: []
name: Debugging
parent: 4cd6156e-51a0-4da4-add4-6f81e106cd43
"""

new_topic_nested_parent_file = """
topics:
- icon: RiRobot2Line
id: c06109bf-cff8-4873-b04b-f5e66e3e1764
mappings:
mitx:
- Electronics
ocw:
- Technology
name: Data Science, Analytics & Computer Technology
children:
- children: []
icon: RiRobot2Line
id: ea647bfc-cc83-42c7-b685-b5c2088b30af
mappings: []
name: Google Analytics
"""

upsert_topic_data_string(base_topic_file)

assert mock_pluggy.called

main_topic = LearningResourceTopic.objects.filter(
topic_uuid="c06109bf-cff8-4873-b04b-f5e66e3e1764"
)

assert main_topic.exists()
main_topic = main_topic.get()

sub_topic = LearningResourceTopic.objects.filter(parent=main_topic)

assert sub_topic.exists()
sub_topic = sub_topic.get()

upsert_topic_data_string(new_topic_file)

new_topic = LearningResourceTopic.objects.filter(
topic_uuid="d335c250-1292-4391-a7cb-3181f803e0f3"
)

assert new_topic.exists()
assert new_topic.get().parent == sub_topic

upsert_topic_data_string(new_topic_nested_parent_file)

main_topic.refresh_from_db()

sub_topic = LearningResourceTopic.objects.filter(parent=main_topic)
assert sub_topic.count() == 2

for topic in sub_topic.all():
assert str(topic.topic_uuid) in [
"ea647bfc-cc83-42c7-b685-b5c2088b30af",
"4cd6156e-51a0-4da4-add4-6f81e106cd43",
]


def test_add_parent_topics_to_learning_resource(fixture_resource):
"""Ensure the parent topics get added to the resource."""

Expand Down

0 comments on commit 42e8c59

Please sign in to comment.