Repository: uccser/cs-unplugged

Issue:
Implement first pass of website design
This issue is to implement the first pass on creating the CS Unplugged website.

Key pages are the:

- Homepage
- Topics page
- Navigation bar


Discussion:

Resolving patch:
diff --git a/csunplugged/topics/models.py b/csunplugged/topics/models.py
--- a/csunplugged/topics/models.py
+++ b/csunplugged/topics/models.py
@@ -1,3 +1,5 @@
+from collections import OrderedDict
+
 from django.db import models
 from resources.models import Resource
 
@@ -51,6 +53,26 @@ class UnitPlan(models.Model):
     name = models.CharField(max_length=100)
     content = models.TextField()
 
+    def lessons_by_age_group(self):
+        """Returns groups of lessons grouped by the lesson minimum age
+        and maximum ages, and then order by number.
+
+        Returns:
+            A ordered dictionary of grouped lessons.
+            The key is a tuple of the minimum age and maximum ages for
+            the lessons.
+            The value for a key is a sorted list of lessons.
+            The dictionary is ordered by minimum age, then maximum age.
+        """
+        grouped_lessons = OrderedDict()
+        lessons = self.unit_plan_lessons.order_by('min_age', 'max_age', 'number')
+        for lesson in lessons:
+            if (lesson.min_age, lesson.max_age) in grouped_lessons:
+                grouped_lessons[(lesson.min_age, lesson.max_age)].append(lesson)
+            else:
+                grouped_lessons[(lesson.min_age, lesson.max_age)] = [lesson]
+        return grouped_lessons
+
     def __str__(self):
         return self.name
 
@@ -71,6 +93,17 @@ class CurriculumIntegration(models.Model):
         related_name='curriculum_integrations'
     )
 
+    def has_prerequisite_lessons(self):
+        """Returns True if the curriculum integration has at
+        least one prerequisite lesson, otherwise False.
+
+        Returns:
+            True if the curriculum integration has at
+            least one prerequisite lesson, otherwise False.
+        """
+        # TODO: This method cannot be implemented until #123 is implemented
+        return False
+
     def __str__(self):
         return self.name
 
@@ -185,6 +218,16 @@ class Lesson(models.Model):
         related_name='lesson_generated_resources'
     )
 
+    def has_programming_exercises(self):
+        """Returns a boolean to state whether the lesson has any
+        programming exercises.
+
+        Returns:
+            True if the lesson has connected programming exercises.
+            Otherwise False.
+        """
+        return bool(self.programming_exercises.all())
+
     def __str__(self):
         return self.name
 
diff --git a/csunplugged/topics/urls.py b/csunplugged/topics/urls.py
--- a/csunplugged/topics/urls.py
+++ b/csunplugged/topics/urls.py
@@ -10,6 +10,12 @@
         views.IndexView.as_view(),
         name='index'
     ),
+    # eg: /topics/curriculum-integrations/
+    url(
+        r'^curriculum-integrations/$',
+        views.AllCurriculumIntegrationList.as_view(),
+        name='all_curriculum_integrations'
+    ),
     # eg: /topics/binary-numbers/
     url(
         r'^(?P<topic_slug>[-\w]+)/$',
diff --git a/csunplugged/topics/views.py b/csunplugged/topics/views.py
--- a/csunplugged/topics/views.py
+++ b/csunplugged/topics/views.py
@@ -31,10 +31,10 @@ def get_context_data(self, **kwargs):
         # Call the base implementation first to get a context
         context = super(TopicView, self).get_context_data(**kwargs)
         # Add in a QuerySet of all the connected unit plans
-        context['unit_plans'] = UnitPlan.objects.filter(topic=self.object).order_by('name')
-        # Add in a QuerySet of all the connected programming exercises
-        programming_exercises = ProgrammingExercise.objects.filter(topic=self.object)
-        context['programming_exercises'] = programming_exercises.order_by('exercise_set_number', 'exercise_number')
+        unit_plans = UnitPlan.objects.filter(topic=self.object).order_by('name').select_related()
+        for unit_plan in unit_plans:
+            unit_plan.lessons = unit_plan.lessons_by_age_group()
+        context['unit_plans'] = unit_plans
         # Add in a QuerySet of all the connected curriculum integrations
         context['curriculum_integrations'] = CurriculumIntegration.objects.filter(topic=self.object).order_by('number')
         return context
@@ -156,7 +156,7 @@ def get_context_data(self, **kwargs):
         context['topic'] = lesson.topic
         # Add all the connected learning outcomes
         context['programming_exercise_learning_outcomes'] = self.object.learning_outcomes.all()
-        context['implementations'] = self.object.implementations.all().select_related()
+        context['implementations'] = self.object.implementations.all().order_by('-language__name').select_related()
         return context
 
 
@@ -208,6 +208,16 @@ def get_context_data(self, **kwargs):
         return context
 
 
+class AllCurriculumIntegrationList(generic.ListView):
+    model = CurriculumIntegration
+    template_name = 'topics/all_curriculum_integration_list.html'
+    context_object_name = 'curriculum_integrations'
+
+    def get_queryset(self, **kwargs):
+        """Return all integrations for topic"""
+        return CurriculumIntegration.objects.select_related().order_by('topic__name', 'number')
+
+
 class CurriculumIntegrationView(generic.DetailView):
     model = CurriculumIntegration
     queryset = CurriculumIntegration.objects.all()


Test patch: