diff --git a/coderdojochi/admin.py b/coderdojochi/admin.py index 12aaadf9..920e9d0a 100644 --- a/coderdojochi/admin.py +++ b/coderdojochi/admin.py @@ -507,6 +507,8 @@ class CourseAdmin(ImportExportMixin, ImportExportActionModelAdmin): "description", ] + filter_horizontal = ["prerequisite"] + prepopulated_fields = { "slug": ("title",), } diff --git a/coderdojochi/migrations/0038_course_prerequisite.py b/coderdojochi/migrations/0038_course_prerequisite.py new file mode 100644 index 00000000..a330857a --- /dev/null +++ b/coderdojochi/migrations/0038_course_prerequisite.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.5 on 2021-01-30 19:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('coderdojochi', '0037_auto_20210118_1808'), + ] + + operations = [ + migrations.AddField( + model_name='course', + name='prerequisite', + field=models.ManyToManyField(blank=True, limit_choices_to={'is_active': True}, to='coderdojochi.Course'), + ), + ] diff --git a/coderdojochi/models/course.py b/coderdojochi/models/course.py index 74b5ac36..7e183877 100644 --- a/coderdojochi/models/course.py +++ b/coderdojochi/models/course.py @@ -58,6 +58,8 @@ class Course(CommonInfo): default=True, ) + prerequisite = models.ManyToManyField("self", symmetrical=False, blank=True, limit_choices_to={"is_active": True}) + def __str__(self): if self.code: return f"{self.code} | {self.title}" diff --git a/coderdojochi/models/session.py b/coderdojochi/models/session.py index b49ec70e..311598a6 100644 --- a/coderdojochi/models/session.py +++ b/coderdojochi/models/session.py @@ -3,7 +3,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.urls.base import reverse -from django.utils import formats +from django.utils import formats, timezone from django.utils.functional import cached_property from .common import CommonInfo @@ -307,6 +307,21 @@ def get_mentor_capacity(self): else: return int(self.capacity / 2) + def get_course_prerequisites_needed(self, student): + from .order import Order + + student_previous_orders = Order.objects.filter( + student=student, + session__start_date__lt=timezone.now(), + session__course__id__in=self.course.prerequisite.values_list("id"), + ).exclude(check_in=None) + + student_prerequisites_needed = self.course.prerequisite.exclude( + id__in=student_previous_orders.values("session__course__id") + ).distinct("id") + + return student_prerequisites_needed + class PartnerPasswordAccess(CommonInfo): from .user import CDCUser diff --git a/coderdojochi/templates/guardian/session_detail.html b/coderdojochi/templates/guardian/session_detail.html index 6d33be2e..283bf2f9 100644 --- a/coderdojochi/templates/guardian/session_detail.html +++ b/coderdojochi/templates/guardian/session_detail.html @@ -115,6 +115,18 @@
Microphone and Speakers: We highly recommend headphones with a built-in microphone, however any microphone and speakers will work in a quiet room.
{% endif %} + + {% if object.course.prerequisite.all.count > 0 %} +Ever wanted to start building your own game but didn't know where to start? Ever thought it would be cool to have a computer draw a picture or create an animation for you?
\r\n\r\nBy the end of the session, students will have the understanding of Canvas using the Javascript programming language. Students will learn how to break down tasks and objects to understand how they are built.
", + "duration": "03:00:00", + "minimum_age": 10, + "maximum_age": 18, + "is_active": true, + "prerequisite": [ + 4 + ] } } ] diff --git a/fixtures/14-coderdojochi.session.json b/fixtures/14-coderdojochi.session.json index 229c6458..3571f903 100644 --- a/fixtures/14-coderdojochi.session.json +++ b/fixtures/14-coderdojochi.session.json @@ -22,8 +22,8 @@ "partner_message": "", "announced_date_mentors": null, "announced_date_guardians": null, - "image_url": "classes/0001.jpg", - "bg_image": "", + "image_url": null, + "bg_image": null, "mentors_week_reminder_sent": true, "mentors_day_reminder_sent": true, "gender_limitation": "male", @@ -63,8 +63,8 @@ "partner_message": "", "announced_date_mentors": null, "announced_date_guardians": null, - "image_url": "classes/0002.jpg", - "bg_image": "", + "image_url": null, + "bg_image": null, "mentors_week_reminder_sent": false, "mentors_day_reminder_sent": false, "gender_limitation": null, @@ -91,24 +91,24 @@ "start_date": "2021-03-03T16:00:00Z", "location": 2, "capacity": 20, - "mentor_capacity": null, + "mentor_capacity": 10, "instructor": 1, "cost": "0.00", "minimum_cost": null, "maximum_cost": null, - "additional_info": null, + "additional_info": "", "external_enrollment_url": null, "is_active": true, "is_public": true, - "password": "", - "partner_message": "", + "password": "password", + "partner_message": "The password below is password
", "announced_date_mentors": null, "announced_date_guardians": null, - "image_url": "classes/0003.jpg", - "bg_image": "", + "image_url": null, + "bg_image": null, "mentors_week_reminder_sent": false, "mentors_day_reminder_sent": false, - "gender_limitation": "Male", + "gender_limitation": null, "override_minimum_age_limitation": null, "override_maximum_age_limitation": null, "online_video_link": null, @@ -128,16 +128,16 @@ "fields": { "created_at": "2000-01-01T06:00:00Z", "updated_at": "2000-01-01T06:00:00Z", - "course": 1, + "course": 4, "start_date": "2021-04-04T15:00:00Z", - "location": 1, + "location": 3, "capacity": 20, - "mentor_capacity": null, + "mentor_capacity": 10, "instructor": 1, "cost": "0.00", "minimum_cost": null, "maximum_cost": null, - "additional_info": null, + "additional_info": "", "external_enrollment_url": null, "is_active": true, "is_public": true, @@ -145,8 +145,8 @@ "partner_message": "", "announced_date_mentors": null, "announced_date_guardians": null, - "image_url": "classes/0004.jpg", - "bg_image": "", + "image_url": null, + "bg_image": null, "mentors_week_reminder_sent": false, "mentors_day_reminder_sent": false, "gender_limitation": null, @@ -169,25 +169,25 @@ "fields": { "created_at": "2000-01-01T06:00:00Z", "updated_at": "2000-01-01T06:00:00Z", - "course": 1, + "course": 15, "start_date": "2021-05-05T16:00:00Z", "location": 3, "capacity": 20, - "mentor_capacity": null, + "mentor_capacity": 10, "instructor": 1, "cost": "0.00", "minimum_cost": null, "maximum_cost": null, - "additional_info": null, + "additional_info": "", "external_enrollment_url": null, "is_active": true, "is_public": true, - "password": "password", - "partner_message": "The password below is password
", + "password": "", + "partner_message": "", "announced_date_mentors": null, "announced_date_guardians": null, - "image_url": "classes/0001.jpg", - "bg_image": "", + "image_url": null, + "bg_image": null, "mentors_week_reminder_sent": false, "mentors_day_reminder_sent": false, "gender_limitation": "female", @@ -228,7 +228,7 @@ "announced_date_mentors": null, "announced_date_guardians": null, "image_url": null, - "bg_image": "", + "bg_image": null, "mentors_week_reminder_sent": false, "mentors_day_reminder_sent": false, "gender_limitation": null, diff --git a/weallcode/templates/weallcode/programs.html b/weallcode/templates/weallcode/programs.html index 2f969c8d..b61512aa 100644 --- a/weallcode/templates/weallcode/programs.html +++ b/weallcode/templates/weallcode/programs.html @@ -90,7 +90,7 @@{{ session.course.description|safe|truncatechars_html:280 }}
- +