Repository: uccser/cs-unplugged

Issue:
Delete curriculum integrations list page
This page has duplicate information from the topic's page, therefore should be deleted and breadcrumbs streamlined.
Delete curriculum integrations list page
This page has duplicate information from the topic's page, therefore should be deleted and breadcrumbs streamlined.


Discussion:

Resolving patch:
diff --git a/csunplugged/topics/urls.py b/csunplugged/topics/urls.py
--- a/csunplugged/topics/urls.py
+++ b/csunplugged/topics/urls.py
@@ -36,12 +36,6 @@
         views.TopicView.as_view(),
         name='topic'
     ),
-    # eg: /topics/binary-numbers/integrations
-    url(
-        r'^(?P<topic_slug>[-\w]+)/integrations/$',
-        views.CurriculumIntegrationList.as_view(),
-        name='integration_list'
-    ),
     # eg: /topics/binary-numbers/integrations/binary-bracelets
     url(
         r'^(?P<topic_slug>[-\w]+)/integrations/(?P<integration_slug>[-\w]+)/$',
diff --git a/csunplugged/topics/views.py b/csunplugged/topics/views.py
--- a/csunplugged/topics/views.py
+++ b/csunplugged/topics/views.py
@@ -250,35 +250,6 @@ def get_context_data(self, **kwargs):
         return context
 
 
-class CurriculumIntegrationList(generic.ListView):
-    """View for list all curriculum inegrations for a topic."""
-
-    model = CurriculumIntegration
-    template_name = 'topics/curriculum_integration_list.html'
-    context_object_name = 'all_curriculum_integrations'
-
-    def get_queryset(self, **kwargs):
-        """Retrieve all curriculum integrations for a topic.
-
-        Returns:
-            Queryset of CurriculumIntegration objects.
-        """
-        return CurriculumIntegration.objects.filter(
-            topic__slug=self.kwargs.get('topic_slug', None)
-        ).select_related().order_by('number')
-
-    def get_context_data(self, **kwargs):
-        """Provide the context data for the curriculum integration list view.
-
-        Returns:
-            Dictionary of context data.
-        """
-        context = super(CurriculumIntegrationList, self).get_context_data(**kwargs)
-        # Loading objects under consistent context names for breadcrumbs
-        context['topic'] = get_object_or_404(Topic, slug=self.kwargs.get('topic_slug', None))
-        return context
-
-
 class AllCurriculumIntegrationList(generic.ListView):
     """View for listing all curriculum integrations."""
 
@@ -326,10 +297,13 @@ def get_context_data(self, **kwargs):
         # Loading objects under consistent context names for breadcrumbs
         context['topic'] = self.object.topic
         # Add in a QuerySet of all the connected curriculum areas
-        context['integration_curriculum_areas'] = self.object.curriculum_areas.all()
+        context['integration_curriculum_areas'] = self.object.curriculum_areas.order_by("name")
         # Add in a QuerySet of all the prerequisite lessons
         context['prerequisite_lessons'] = self.object.prerequisite_lessons.select_related().order_by(
-            'unit_plan__name', 'number'
+            'unit_plan__name',
+            'min_age',
+            'max_age',
+            'number'
         )
         return context
 


Test patch:
diff --git a/csunplugged/tests/general/templatetags/test_render_html_field.py b/csunplugged/tests/general/templatetags/test_render_html_field.py
--- a/csunplugged/tests/general/templatetags/test_render_html_field.py
+++ b/csunplugged/tests/general/templatetags/test_render_html_field.py
@@ -1,8 +1,7 @@
 from tests.BaseTestWithDB import BaseTestWithDB
 from django import template
 from topics.models import CurriculumIntegration
-from topics.models import Topic
-from model_mommy import mommy
+from tests.topics import create_topics_test_data
 
 
 class RenderHTMLFieldTest(BaseTestWithDB):
@@ -16,7 +15,7 @@ def render_template(self, string, context=None):
         return template.Template(string).render(context)
 
     def test_render_html_field_without_static(self):
-        topic = mommy.make(Topic)
+        topic = create_topics_test_data.create_test_topic(1)
         curriculum_integration_without_static = CurriculumIntegration.objects.create(
             topic=topic,
             slug="slug_1",
@@ -32,7 +31,7 @@ def test_render_html_field_without_static(self):
         self.assertHTMLEqual(rendered, "<p>Example text.</p>")
 
     def test_render_html_field_with_static(self):
-        topic = mommy.make(Topic)
+        topic = create_topics_test_data.create_test_topic(1)
         curriculum_integration_with_static = CurriculumIntegration.objects.create(
             topic=topic,
             slug="slug_2",
@@ -48,7 +47,7 @@ def test_render_html_field_with_static(self):
         self.assertHTMLEqual(rendered, "<img src='/staticfiles/img/logo-small.png'>")
 
     def test_render_html_field_empty(self):
-        topic = mommy.make(Topic)
+        topic = create_topics_test_data.create_test_topic(1)
         curriculum_integration_empty = CurriculumIntegration.objects.create(
             topic=topic,
             slug="slug_3",
@@ -78,7 +77,7 @@ def test_render_html_field_two_parameters(self):
         )
 
     def test_render_html_field_invalid_parameter(self):
-        topic = mommy.make(Topic)
+        topic = create_topics_test_data.create_test_topic(1)
         curriculum_integration_with_static = CurriculumIntegration.objects.create(
             topic=topic,
             slug="slug_2",
@@ -95,7 +94,7 @@ def test_render_html_field_invalid_parameter(self):
         )
 
     def test_render_html_field_missing_parameter(self):
-        topic = mommy.make(Topic)
+        topic = create_topics_test_data.create_test_topic(1)
         curriculum_integration_with_static = CurriculumIntegration.objects.create(
             topic=topic,
             slug="slug_2",
diff --git a/csunplugged/tests/topics/create_topics_test_data.py b/csunplugged/tests/topics/create_topics_test_data.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/create_topics_test_data.py
@@ -0,0 +1,102 @@
+"""Create test data for topic tests."""
+
+from topics.models import (
+    Topic,
+    Lesson,
+    CurriculumIntegration,
+    CurriculumArea,
+)
+
+
+def create_test_integration(topic, number, lessons=None, curriculum_areas=None):
+    """Create curriculum integration object.
+
+    Args:
+        topic: The related Topic object.
+        number: Integer representing the topic.
+        lessons: List of prerequisite lessons.
+        curriculum_areas: List of curriculum areas.
+
+    Returns:
+        CurriculumIntegration object.
+    """
+    integration = CurriculumIntegration(
+        topic=topic,
+        slug="integration_{}".format(number),
+        name="Integration {}".format(number),
+        number=number,
+        content="Content for integration {}.".format(number),
+    )
+    integration.save()
+    if lessons:
+        for lesson in lessons:
+            integration.prerequisite_lessons.add(lesson)
+    if curriculum_areas:
+        for curriculum_area in curriculum_areas:
+            integration.curriculum_areas.add(curriculum_area)
+    return integration
+
+
+def create_test_curriculum_area(number, parent=None):
+    """Create curriculum area object.
+
+    Args:
+        number: Integer representing the area.
+        parent: Parent of the curriculum area.
+
+    Returns:
+        CurriculumArea object.
+    """
+    area = CurriculumArea(
+        slug="area_{}".format(number),
+        name="Area {}".format(number),
+        parent=parent,
+    )
+    area.save()
+    return area
+
+
+def create_test_topic(number):
+    """Create topic object.
+
+    Args:
+        number: Integer representing the topic.
+
+    Returns:
+        Topic object.
+    """
+    topic = Topic(
+        slug="topic_{}".format(number),
+        name="Topic {}".format(number),
+        content="Content for topic {}.".format(number),
+    )
+    topic.save()
+    return topic
+
+
+def create_test_lesson(topic, unit_plan, number, min_age, max_age):
+    """Create lesson object.
+
+    Args:
+        topic: The related Topic object.
+        unit_plan: The related UnitPlan object.
+        number: Integer representing the topic.
+        min_age: Integer of the minimum age of the lesson.
+        max_age: Integer of the maximum age of the lesson.
+
+    Returns:
+        Lesson object.
+    """
+    lesson = Lesson(
+        topic=topic,
+        unit_plan=unit_plan,
+        slug="lesson_{}".format(number),
+        name="Lesson {} ({} to {})".format(number, min_age, max_age),
+        number=number,
+        duration=number,
+        content="Content for lesson {}.".format(number),
+        min_age=min_age,
+        max_age=max_age,
+    )
+    lesson.save()
+    return lesson
diff --git a/csunplugged/tests/topics/models/test_curriculum_integration.py b/csunplugged/tests/topics/models/test_curriculum_integration.py
--- a/csunplugged/tests/topics/models/test_curriculum_integration.py
+++ b/csunplugged/tests/topics/models/test_curriculum_integration.py
@@ -1,9 +1,9 @@
 from model_mommy import mommy
 from tests.BaseTestWithDB import BaseTestWithDB
 from topics.models import CurriculumIntegration
-from topics.models import Topic
 from topics.models import CurriculumArea
 from topics.models import Lesson
+from tests.topics import create_topics_test_data
 
 
 class CurriculumIntegrationModelTest(BaseTestWithDB):
@@ -13,7 +13,7 @@ def __init__(self, *args, **kwargs):
 
     def test_curriculum_integration(self):
         # Setup Auxliary Data
-        topic = mommy.make(Topic)
+        topic = create_topics_test_data.create_test_topic(1)
         curriculum_area = mommy.make(
             CurriculumArea,
             make_m2m=True,
diff --git a/csunplugged/tests/topics/urls/test_integration_list.py b/csunplugged/tests/topics/urls/test_integration_list.py
deleted file mode 100644
--- a/csunplugged/tests/topics/urls/test_integration_list.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from tests.BaseTestWithDB import BaseTestWithDB
-from django.urls import reverse
-
-
-class IntegrationListURLTest(BaseTestWithDB):
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        self.language = "en"
-
-    def test_valid_integration_list(self):
-        url = reverse("topics:integration_list", args=["binary-numbers"])
-        self.assertEqual(url, "/en/topics/binary-numbers/integrations/")
diff --git a/csunplugged/tests/topics/views/test_all_curriculum_integration_list.py b/csunplugged/tests/topics/views/test_all_curriculum_integration_list.py
deleted file mode 100644
diff --git a/csunplugged/tests/topics/views/test_all_curriculum_integration_view.py b/csunplugged/tests/topics/views/test_all_curriculum_integration_view.py
new file mode 100644
--- /dev/null
+++ b/csunplugged/tests/topics/views/test_all_curriculum_integration_view.py
@@ -0,0 +1,74 @@
+from django.urls import reverse
+from tests.BaseTestWithDB import BaseTestWithDB
+from tests.topics import create_topics_test_data
+
+
+class AllCurriculumIntegrationViewTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = "en"
+
+    def test_all_curriculum_integration_view_with_no_integrations(self):
+        url = reverse("topics:all_curriculum_integrations")
+        response = self.client.get(url)
+        self.assertEqual(200, response.status_code)
+        self.assertEqual(len(response.context["curriculum_integrations"]), 0)
+
+    def test_all_curriculum_integration_view_with_one_integration(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        create_topics_test_data.create_test_integration(topic, 1)
+
+        url = reverse("topics:all_curriculum_integrations")
+        response = self.client.get(url)
+        self.assertEqual(200, response.status_code)
+        self.assertEqual(len(response.context["curriculum_integrations"]), 1)
+        self.assertQuerysetEqual(
+            response.context["curriculum_integrations"],
+            ["<CurriculumIntegration: Integration 1>"]
+        )
+
+    def test_all_curriculum_integration_view_with_multiple_integration(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        create_topics_test_data.create_test_integration(topic, 1)
+        create_topics_test_data.create_test_integration(topic, 2)
+        create_topics_test_data.create_test_integration(topic, 3)
+
+        url = reverse("topics:all_curriculum_integrations")
+        response = self.client.get(url)
+        self.assertEqual(200, response.status_code)
+        self.assertEqual(len(response.context["curriculum_integrations"]), 3)
+        self.assertQuerysetEqual(
+            response.context["curriculum_integrations"],
+            [
+                "<CurriculumIntegration: Integration 1>",
+                "<CurriculumIntegration: Integration 2>",
+                "<CurriculumIntegration: Integration 3>",
+            ]
+        )
+
+    def test_all_curriculum_integration_view_order(self):
+        topic_1 = create_topics_test_data.create_test_topic(1)
+        topic_2 = create_topics_test_data.create_test_topic(2)
+        create_topics_test_data.create_test_integration(topic_2, 3)
+        create_topics_test_data.create_test_integration(topic_2, 2)
+        create_topics_test_data.create_test_integration(topic_2, 1)
+        create_topics_test_data.create_test_integration(topic_1, 4)
+        create_topics_test_data.create_test_integration(topic_1, 5)
+        create_topics_test_data.create_test_integration(topic_1, 6)
+
+        url = reverse("topics:all_curriculum_integrations")
+        response = self.client.get(url)
+        self.assertEqual(200, response.status_code)
+        self.assertEqual(len(response.context["curriculum_integrations"]), 6)
+        self.assertQuerysetEqual(
+            response.context["curriculum_integrations"],
+            [
+                "<CurriculumIntegration: Integration 4>",
+                "<CurriculumIntegration: Integration 5>",
+                "<CurriculumIntegration: Integration 6>",
+                "<CurriculumIntegration: Integration 1>",
+                "<CurriculumIntegration: Integration 2>",
+                "<CurriculumIntegration: Integration 3>",
+            ]
+        )
diff --git a/csunplugged/tests/topics/views/test_curriculum_integration_list.py b/csunplugged/tests/topics/views/test_curriculum_integration_list.py
deleted file mode 100644
diff --git a/csunplugged/tests/topics/views/test_curriculum_integration_view.py b/csunplugged/tests/topics/views/test_curriculum_integration_view.py
--- a/csunplugged/tests/topics/views/test_curriculum_integration_view.py
+++ b/csunplugged/tests/topics/views/test_curriculum_integration_view.py
@@ -0,0 +1,174 @@
+from django.urls import reverse
+from model_mommy import mommy
+from tests.BaseTestWithDB import BaseTestWithDB
+from tests.topics import create_topics_test_data
+from topics.models import UnitPlan
+
+
+class CurriculumIntegrationViewTest(BaseTestWithDB):
+
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        self.language = "en"
+
+    def test_curriculum_integration_view_with_valid_slugs(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        create_topics_test_data.create_test_integration(topic, 1)
+        kwargs = {
+            "topic_slug": topic.slug,
+            "integration_slug": "integration_1",
+            }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(200, response.status_code)
+
+    def test_curriculum_integration_view_with_invalid_topic_slug(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        create_topics_test_data.create_test_integration(topic, 1)
+        kwargs = {
+            "topic_slug": "no_slug",
+            "integration_slug": "integration_1",
+        }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(404, response.status_code)
+
+    def test_curriculum_integration_view_with_invalid_integration_slug(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        create_topics_test_data.create_test_integration(topic, 1)
+        kwargs = {
+            "topic_slug": topic.slug,
+            "integration_slug": "integration_2",
+            }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(404, response.status_code)
+
+    def test_curriculum_integration_view_topic_context(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        create_topics_test_data.create_test_integration(topic, 1)
+        kwargs = {
+            "topic_slug": "topic_1",
+            "integration_slug": "integration_1",
+        }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(
+            response.context["topic"],
+            topic
+        )
+
+    def test_curriculum_integration_view_curriculum_areas_context(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        area_1 = create_topics_test_data.create_test_curriculum_area(1)
+        area_2 = create_topics_test_data.create_test_curriculum_area(2)
+        create_topics_test_data.create_test_integration(
+            topic,
+            1,
+            curriculum_areas=[area_1, area_2]
+        )
+        kwargs = {
+            "topic_slug": "topic_1",
+            "integration_slug": "integration_1",
+        }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(
+            len(response.context["integration_curriculum_areas"]),
+            2
+        )
+        self.assertQuerysetEqual(
+            response.context["integration_curriculum_areas"],
+            [
+                "<CurriculumArea: Area 1>",
+                "<CurriculumArea: Area 2>",
+            ]
+        )
+
+    def test_curriculum_integration_view_prerequisite_lessons_context(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        unit_plan = mommy.make(UnitPlan)
+        lesson_1 = create_topics_test_data.create_test_lesson(
+            topic,
+            unit_plan,
+            1,
+            5,
+            7
+        )
+        lesson_2 = create_topics_test_data.create_test_lesson(
+            topic,
+            unit_plan,
+            2,
+            5,
+            7
+        )
+        create_topics_test_data.create_test_integration(
+            topic,
+            1,
+            lessons=[lesson_1, lesson_2]
+        )
+        kwargs = {
+            "topic_slug": "topic_1",
+            "integration_slug": "integration_1",
+        }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(
+            len(response.context["prerequisite_lessons"]),
+            2
+        )
+        self.assertQuerysetEqual(
+            response.context["prerequisite_lessons"],
+            [
+                "<Lesson: Lesson 1 (5 to 7)>",
+                "<Lesson: Lesson 2 (5 to 7)>",
+            ]
+        )
+
+    def test_curriculum_integration_view_prerequisite_lessons_context_order(self):
+        topic = create_topics_test_data.create_test_topic(1)
+        unit_plan = mommy.make(UnitPlan)
+        lesson_3 = create_topics_test_data.create_test_lesson(
+            topic,
+            unit_plan,
+            1,
+            8,
+            10
+        )
+        lesson_2 = create_topics_test_data.create_test_lesson(
+            topic,
+            unit_plan,
+            2,
+            5,
+            7
+        )
+        lesson_1 = create_topics_test_data.create_test_lesson(
+            topic,
+            unit_plan,
+            1,
+            5,
+            7
+        )
+        create_topics_test_data.create_test_integration(
+            topic,
+            1,
+            lessons=[lesson_3, lesson_2, lesson_1]
+        )
+        kwargs = {
+            "topic_slug": "topic_1",
+            "integration_slug": "integration_1",
+        }
+        url = reverse("topics:integration", kwargs=kwargs)
+        response = self.client.get(url)
+        self.assertEqual(
+            len(response.context["prerequisite_lessons"]),
+            3
+        )
+        self.assertQuerysetEqual(
+            response.context["prerequisite_lessons"],
+            [
+                "<Lesson: Lesson 1 (5 to 7)>",
+                "<Lesson: Lesson 2 (5 to 7)>",
+                "<Lesson: Lesson 1 (8 to 10)>",
+            ]
+        )