Skip to content

Commit

Permalink
Merge pull request #1069 from torchbox/feature/1301-multiple-program-…
Browse files Browse the repository at this point in the history
…types

#1301 - PROGRAMME FINDER | MRes Healthcare & Design and MRes RCA
  • Loading branch information
patrickcuagan authored Jan 21, 2025
2 parents 2d8f478 + 52baff0 commit 2ac0993
Show file tree
Hide file tree
Showing 18 changed files with 313 additions and 45 deletions.
12 changes: 10 additions & 2 deletions rca/enquire_to_study/tests/test_forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,21 @@
EnquiryFormSubmission,
EnquiryFormSubmissionProgrammesOrderable,
)
from rca.programmes.factories import ProgrammePageFactory
from rca.programmes.factories import (
ProgrammePageFactory,
ProgrammePageProgrammeTypeFactory,
ProgrammeTypeFactory,
)


class TestEnquireToStudyForm(TestCase):
def setUp(self):
self.start_date = StartDateFactory(qs_code="test-code")
self.enquiry_reason = EnquiryReasonFactory()
page = ProgrammePageFactory(qs_code=1)
ProgrammePageProgrammeTypeFactory(
page=page, programme_type=ProgrammeTypeFactory()
)
self.form_data = {
"first_name": "Monty",
"last_name": "python",
Expand All @@ -25,7 +33,7 @@ def setUp(self):
"country_of_residence": "GB",
"city": "Bristol",
"country_of_citizenship": "GB",
"programmes": [ProgrammePageFactory(qs_code=1, programme_type__pk=2).pk],
"programmes": [page.pk],
"start_date": self.start_date.pk,
"enquiry_reason": self.enquiry_reason.pk,
"enquiry_questions": "What is your name?",
Expand Down
12 changes: 10 additions & 2 deletions rca/enquire_to_study/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@
from rca.enquire_to_study.models import EnquireToStudySettings, EnquiryFormSubmission
from rca.enquire_to_study.views import EnquireToStudyFormView
from rca.enquire_to_study.wagtail_hooks import EnquiryFormSubmissionAdmin
from rca.programmes.factories import ProgrammePageFactory
from rca.programmes.factories import (
ProgrammePageFactory,
ProgrammePageProgrammeTypeFactory,
ProgrammeTypeFactory,
)


class EnquireToStudyFormViewTest(TestCase):
Expand Down Expand Up @@ -54,6 +58,10 @@ def setUp(self):
email_content="Test email content",
site_id=Site.objects.get().pk,
)
page = ProgrammePageFactory(qs_code=1)
ProgrammePageProgrammeTypeFactory(
page=page, programme_type=ProgrammeTypeFactory()
)

self.form_data = {
"first_name": "Monty",
Expand All @@ -63,7 +71,7 @@ def setUp(self):
"country_of_residence": "GB",
"city": "Bristol",
"country_of_citizenship": "GB",
"programmes": [ProgrammePageFactory(qs_code=1, programme_type__pk=2).pk],
"programmes": [page.pk],
"start_date": StartDateFactory(qs_code="test-code").pk,
"enquiry_reason": EnquiryReasonFactory().pk,
"enquiry_questions": "What is your name?",
Expand Down
15 changes: 13 additions & 2 deletions rca/programmes/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
import wagtail_factories
from faker import Factory as FakerFactory

from .models import DegreeLevel, ProgrammePage, ProgrammeType
from .models import (
DegreeLevel,
ProgrammePage,
ProgrammePageProgrammeType,
ProgrammeType,
)

faker = FakerFactory.create()

Expand Down Expand Up @@ -31,4 +36,10 @@ class Meta:
scholarships_information = factory.Faker("text", max_nb_chars=100)
search_description = factory.Faker("text", max_nb_chars=25)
degree_level = factory.SubFactory(DegreeLevelFactory)
programme_type = factory.SubFactory(ProgrammeTypeFactory)


class ProgrammePageProgrammeTypeFactory(factory.django.DjangoModelFactory):
class Meta:
model = ProgrammePageProgrammeType

page = factory.SubFactory(ProgrammePageFactory)
44 changes: 44 additions & 0 deletions rca/programmes/migrations/0093_programmepageprogrammetype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Generated by Django 4.2.16 on 2025-01-14 14:23

from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields


class Migration(migrations.Migration):

dependencies = [
("programmes", "0092_link_block_url_label"),
]

operations = [
migrations.CreateModel(
name="ProgrammePageProgrammeType",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"page",
modelcluster.fields.ParentalKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="programme_types",
to="programmes.programmepage",
),
),
(
"programme_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to="programmes.programmetype",
),
),
],
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 4.2.16 on 2025-01-14 14:25

from django.db import migrations

def migrate_programme_type_to_programme_types(apps, schema_editor):
# Get the models
ProgrammePage = apps.get_model("programmes", "ProgrammePage")
ProgrammePageProgrammeType = apps.get_model("programmes", "ProgrammePageProgrammeType")

for page in ProgrammePage.objects.all():
if programme_type := page.programme_type:
ProgrammePageProgrammeType.objects.create(
page_id=page.id,
programme_type=programme_type,
)


class Migration(migrations.Migration):

dependencies = [
("programmes", "0093_programmepageprogrammetype"),
]

operations = [
migrations.RunPython(migrate_programme_type_to_programme_types, reverse_code=migrations.RunPython.noop),
]
17 changes: 17 additions & 0 deletions rca/programmes/migrations/0095_remove_programme_type_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 4.2.16 on 2025-01-17 08:54

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
("programmes", "0094_migrate_programme_type_to_programme_types"),
]

operations = [
migrations.RemoveField(
model_name="programmepage",
name="programme_type",
),
]
37 changes: 23 additions & 14 deletions rca/programmes/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ def get_fake_slug(self):
return slugify(self.display_name)


class ProgrammePageProgrammeType(models.Model):
page = ParentalKey("programmes.ProgrammePage", related_name="programme_types")
programme_type = models.ForeignKey(
"programmes.ProgrammeType",
on_delete=models.CASCADE,
)
panels = [FieldPanel("programme_type")]

def __str__(self):
return self.programme_type.title


class ProgrammePageRelatedSchoolsAndResearchPages(RelatedPage):
source_page = ParentalKey(
"ProgrammePage", related_name="related_schools_and_research_pages"
Expand Down Expand Up @@ -330,13 +342,6 @@ class ProgrammePage(TapMixin, ContactFieldsMixin, BasePage):
degree_level = models.ForeignKey(
DegreeLevel, on_delete=models.SET_NULL, blank=False, null=True, related_name="+"
)
programme_type = models.ForeignKey(
ProgrammeType,
on_delete=models.SET_NULL,
blank=False,
null=True,
related_name="+",
)
hero_image = models.ForeignKey(
"images.CustomImage",
null=True,
Expand Down Expand Up @@ -615,10 +620,7 @@ class ProgrammePage(TapMixin, ContactFieldsMixin, BasePage):
# Taxonomy, relationships etc
FieldPanel("degree_level"),
InlinePanel("subjects", label="Subjects"),
FieldPanel(
"programme_type",
help_text="Used to show content related to this programme page",
),
InlinePanel("programme_types", label="Programme Types"),
MultiFieldPanel(
[
FieldPanel("hero_image"),
Expand Down Expand Up @@ -844,7 +846,14 @@ class ProgrammePage(TapMixin, ContactFieldsMixin, BasePage):
index.SearchField("scholarship_accordion_items"),
index.SearchField("scholarship_information_blocks"),
index.SearchField("more_information_blocks", boost=2),
index.RelatedFields("programme_type", [index.SearchField("display_name")]),
index.RelatedFields(
"programme_types",
[
index.RelatedFields(
"programme_type", [index.SearchField("display_name")]
)
],
),
index.RelatedFields(
"programme_locations",
[index.RelatedFields("programme_location", [index.SearchField("title")])],
Expand Down Expand Up @@ -876,7 +885,7 @@ class ProgrammePage(TapMixin, ContactFieldsMixin, BasePage):
api_fields = [
# Fields for filtering and display, shared with shortcourses.ShortCoursePage.
APIField("subjects"),
APIField("programme_type"),
APIField("programme_types"),
APIField("related_schools_and_research_pages"),
APIField(
"summary",
Expand Down Expand Up @@ -1169,7 +1178,7 @@ def get_context(self, request, *args, **kwargs):

filters = [
{"id": "subjects", "title": "Subject", "items": subjects},
{"id": "programme_type", "title": "Type", "items": programme_types},
{"id": "programme_types", "title": "Type", "items": programme_types},
{
"id": "related_schools_and_research_pages",
"title": "Schools & centres",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,17 @@ <h3 class="related-content__title heading heading--five" property="schema:name">
<svg width="12" height="8" class="related-content__icon" aria-hidden="true"><use xlink:href="#arrow"></use></svg>
</a>
</h3>
<p class="related-content__degree body body--one" property="schema:EducationalCredentialAwarded">{% firstof related_item.degree_level related_item.programme_type %}</p>
{% with programme_types=related_item.programme_types.all %}
{% if related_item.degree_levels %}
<p class="related-content__degree body body--one" property="schema:EducationalCredentialAwarded">{{ related_item.degree_level }}</p>
{% else %}
<p class="related-content__degree body body--one" property="schema:EducationalCredentialAwarded">
{% for item in programme_types %}
{{ item.programme_type.display_name }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
{% endif %}
{% endwith %}
</div>
<p class="related-content__copy body body--one" property="schema:description">
{% firstof related_item.programme_description_subtitle related_item.introduction related_item.listing_summary %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,25 @@ <h3 class="related-content__title body body--one" property="schema:name">
<svg width="12" height="8" class="related-content__icon" aria-hidden="true"><use xlink:href="#arrow"></use></svg>
</a>
</h3>
{% if related_item.degree_level %}
<p class="related-content__degree body body--two" property="schema:EducationalCredentialAwarded">{{ related_item.degree_level }}</p>
{% elif related_item.programme_type %}
<p class="related-content__degree body body--two">{{ related_item.booking_summary|default:related_item.programme_type }}</p>
{% elif related_item.meta %}
<p class="related-content__degree body body--two">{{ related_item.meta }}</p>
{% elif related_item.get_verbose_name == 'Guide page' %}
<p class="related-content__degree body body--two">Guide</p>
{% endif %}
{% with programme_types=related_item.programme_types.all %}
{% if related_item.degree_level %}
<p class="related-content__degree body body--two" property="schema:EducationalCredentialAwarded">{{ related_item.degree_level }}</p>
{% elif programme_types %}
{% if related_item.booking_summary %}
<p class="related-content__degree body body--two">{{ related_item.booking_summary }}</p>
{% else %}
<p class="related-content__degree body body--two">
{% for item in programme_types %}
{{ item.programme_type.display_name }}{% if not forloop.last %}, {% endif %}
{% endfor %}
</p>
{% endif %}
{% elif related_item.meta %}
<p class="related-content__degree body body--two">{{ related_item.meta }}</p>
{% elif related_item.get_verbose_name == 'Guide page' %}
<p class="related-content__degree body body--two">Guide</p>
{% endif %}
{% endwith %}
</div>
<p class="related-content__copy body body--two" property="schema:description">
{% firstof related_item.programme_description_subtitle related_item.introduction|default:''|striptags related_item.listing_summary %}
Expand Down
2 changes: 1 addition & 1 deletion rca/schools/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ def get_short_courses_index_link(self):
).first()
if short_course_type:
return (
f"{self.get_programme_index_link()}?category=programme_type&"
f"{self.get_programme_index_link()}?category=programme_types&"
f"value={short_course_type.id}-{slugify(short_course_type.display_name)}"
)

Expand Down
11 changes: 9 additions & 2 deletions rca/shortcourses/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@

from rca.programmes.factories import ProgrammeTypeFactory

from .models import ShortCoursePage
from .models import ShortCoursePage, ShortCourseProgrammeType


class ShortCoursePageFactory(wagtail_factories.PageFactory):
class Meta:
model = ShortCoursePage

title = factory.Faker("text", max_nb_chars=25)
programme_type = factory.SubFactory(ProgrammeTypeFactory)
show_register_link = False


class ShortCourseProgrammeTypeFactory(factory.django.DjangoModelFactory):
class Meta:
model = ShortCourseProgrammeType

page = factory.SubFactory(ShortCoursePageFactory)
programme_type = factory.SubFactory(ProgrammeTypeFactory)
46 changes: 46 additions & 0 deletions rca/shortcourses/migrations/0039_shortcourseprogrammetype.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# Generated by Django 4.2.16 on 2025-01-14 14:45

from django.db import migrations, models
import django.db.models.deletion
import modelcluster.fields


class Migration(migrations.Migration):

dependencies = [
("programmes", "0094_migrate_programme_type_to_programme_types"),
("shortcourses", "0038_shortcoursepage_dates"),
]

operations = [
migrations.CreateModel(
name="ShortCourseProgrammeType",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"page",
modelcluster.fields.ParentalKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="programme_types",
to="shortcourses.shortcoursepage",
),
),
(
"programme_type",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="short_course",
to="programmes.programmetype",
),
),
],
),
]
Loading

0 comments on commit 2ac0993

Please sign in to comment.