From 9f18f50d9b10a1e2d55c925bb2038e61e658cdc6 Mon Sep 17 00:00:00 2001
From: luminaryFlowers <71102109+luminaryFlowers@users.noreply.github.com>
Date: Mon, 29 Jul 2024 09:49:12 -0700
Subject: [PATCH] our partners, partner with us pages done, added event filters
---
.../0007_partnertype_partner_partner_type.py | 29 ++++
app/core/models.py | 26 ++-
...05_eventcategory_eventhosttype_and_more.py | 44 +++++
...06_alter_eventcategory_options_and_more.py | 27 ++++
...nerpage_event_categories_title_and_more.py | 23 +++
...08_alter_eventhosttype_options_and_more.py | 32 ++++
...eventownerpage_category_select_and_more.py | 28 ++++
app/events/models.py | 88 ++++++++++
.../templates/events/event_owner_page.html | 57 +++++++
.../events/individual_event_page.html | 35 +++-
app/partners/__init__.py | 0
app/partners/admin.py | 3 +
app/partners/apps.py | 6 +
app/partners/migrations/0001_initial.py | 44 +++++
...er_partnerwithuspage_black_box_link_url.py | 18 +++
..._partnerwithuspage_black_box_link_email.py | 18 +++
.../migrations/0004_ourpartnerspage.py | 38 +++++
...rtnerspage_black_box_link_text_and_more.py | 33 ++++
...0006_ourpartnerspage_filter_button_text.py | 18 +++
app/partners/migrations/__init__.py | 0
app/partners/models.py | 151 ++++++++++++++++++
.../templates/partners/our_partners_page.html | 78 +++++++++
.../partners/partner_with_us_page.html | 53 ++++++
app/partners/tests.py | 3 +
app/partners/views.py | 3 +
.../ui/components/FlexTitleWithLink.html | 11 +-
.../ui/components/PageHeaderWithBlur.html | 10 +-
home/templatetags/homepage_tags.py | 2 -
hot_osm/settings/base.py | 1 +
29 files changed, 866 insertions(+), 13 deletions(-)
create mode 100644 app/core/migrations/0007_partnertype_partner_partner_type.py
create mode 100644 app/events/migrations/0005_eventcategory_eventhosttype_and_more.py
create mode 100644 app/events/migrations/0006_alter_eventcategory_options_and_more.py
create mode 100644 app/events/migrations/0007_eventownerpage_event_categories_title_and_more.py
create mode 100644 app/events/migrations/0008_alter_eventhosttype_options_and_more.py
create mode 100644 app/events/migrations/0009_alter_eventownerpage_category_select_and_more.py
create mode 100644 app/partners/__init__.py
create mode 100644 app/partners/admin.py
create mode 100644 app/partners/apps.py
create mode 100644 app/partners/migrations/0001_initial.py
create mode 100644 app/partners/migrations/0002_alter_partnerwithuspage_black_box_link_url.py
create mode 100644 app/partners/migrations/0003_rename_black_box_link_url_partnerwithuspage_black_box_link_email.py
create mode 100644 app/partners/migrations/0004_ourpartnerspage.py
create mode 100644 app/partners/migrations/0005_alter_ourpartnerspage_black_box_link_text_and_more.py
create mode 100644 app/partners/migrations/0006_ourpartnerspage_filter_button_text.py
create mode 100644 app/partners/migrations/__init__.py
create mode 100644 app/partners/models.py
create mode 100644 app/partners/templates/partners/our_partners_page.html
create mode 100644 app/partners/templates/partners/partner_with_us_page.html
create mode 100644 app/partners/tests.py
create mode 100644 app/partners/views.py
diff --git a/app/core/migrations/0007_partnertype_partner_partner_type.py b/app/core/migrations/0007_partnertype_partner_partner_type.py
new file mode 100644
index 0000000..3e6defc
--- /dev/null
+++ b/app/core/migrations/0007_partnertype_partner_partner_type.py
@@ -0,0 +1,29 @@
+# Generated by Django 4.2.7 on 2024-07-25 23:16
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('core', '0006_delete_hotsearchablepage'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='PartnerType',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('type_name', models.CharField()),
+ ],
+ options={
+ 'verbose_name_plural': 'Partner Types',
+ },
+ ),
+ migrations.AddField(
+ model_name='partner',
+ name='partner_type',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.partnertype'),
+ ),
+ ]
diff --git a/app/core/models.py b/app/core/models.py
index 9e66f7b..49732e3 100644
--- a/app/core/models.py
+++ b/app/core/models.py
@@ -1,12 +1,28 @@
+from django import forms
from django.db import models
+
from wagtail.models import Page
from wagtail.fields import StreamField
from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock
-
from wagtail.snippets.models import register_snippet
from wagtail.admin.panels import FieldPanel, MultiFieldPanel, InlinePanel
+@register_snippet
+class PartnerType(models.Model):
+ type_name = models.CharField()
+
+ panels = [
+ FieldPanel("type_name")
+ ]
+
+ def __str__(self):
+ return self.type_name
+
+ class Meta:
+ verbose_name_plural = "Partner Types"
+
+
@register_snippet
class Partner(models.Model):
partner_name = models.CharField()
@@ -18,11 +34,19 @@ class Partner(models.Model):
help_text="Partner logo"
)
partner_url = models.URLField(blank=True)
+ partner_type = models.ForeignKey(
+ 'core.PartnerType',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
panels = [
FieldPanel("partner_name"),
FieldPanel("partner_logo"),
FieldPanel("partner_url"),
+ FieldPanel("partner_type", widget=forms.RadioSelect),
]
def __str__(self):
diff --git a/app/events/migrations/0005_eventcategory_eventhosttype_and_more.py b/app/events/migrations/0005_eventcategory_eventhosttype_and_more.py
new file mode 100644
index 0000000..781f5ec
--- /dev/null
+++ b/app/events/migrations/0005_eventcategory_eventhosttype_and_more.py
@@ -0,0 +1,44 @@
+# Generated by Django 4.2.7 on 2024-07-26 18:42
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('mapping_hubs', '0013_alter_mappinghubprojectspage_black_box_link_text_and_more'),
+ ('events', '0004_eventownerpage_keyword_search_hint_and_more'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='EventCategory',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('category_name', models.CharField()),
+ ],
+ ),
+ migrations.CreateModel(
+ name='EventHostType',
+ fields=[
+ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('type_name', models.CharField()),
+ ],
+ ),
+ migrations.AddField(
+ model_name='individualeventpage',
+ name='event_region_hub',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mapping_hubs.individualmappinghubpage'),
+ ),
+ migrations.AddField(
+ model_name='individualeventpage',
+ name='event_category',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='events.eventcategory'),
+ ),
+ migrations.AddField(
+ model_name='individualeventpage',
+ name='event_host_type',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='events.eventhosttype'),
+ ),
+ ]
diff --git a/app/events/migrations/0006_alter_eventcategory_options_and_more.py b/app/events/migrations/0006_alter_eventcategory_options_and_more.py
new file mode 100644
index 0000000..bcbffd0
--- /dev/null
+++ b/app/events/migrations/0006_alter_eventcategory_options_and_more.py
@@ -0,0 +1,27 @@
+# Generated by Django 4.2.7 on 2024-07-26 18:56
+
+from django.db import migrations
+import modelcluster.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('events', '0005_eventcategory_eventhosttype_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='eventcategory',
+ options={'verbose_name_plural': 'Event Categories'},
+ ),
+ migrations.RemoveField(
+ model_name='individualeventpage',
+ name='event_category',
+ ),
+ migrations.AddField(
+ model_name='individualeventpage',
+ name='event_categories',
+ field=modelcluster.fields.ParentalManyToManyField(blank=True, to='events.eventcategory'),
+ ),
+ ]
diff --git a/app/events/migrations/0007_eventownerpage_event_categories_title_and_more.py b/app/events/migrations/0007_eventownerpage_event_categories_title_and_more.py
new file mode 100644
index 0000000..3081615
--- /dev/null
+++ b/app/events/migrations/0007_eventownerpage_event_categories_title_and_more.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.2.7 on 2024-07-26 19:32
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('events', '0006_alter_eventcategory_options_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='eventownerpage',
+ name='event_categories_title',
+ field=models.CharField(default='Categories'),
+ ),
+ migrations.AddField(
+ model_name='eventownerpage',
+ name='event_region_hub_title',
+ field=models.CharField(default='Region Hub'),
+ ),
+ ]
diff --git a/app/events/migrations/0008_alter_eventhosttype_options_and_more.py b/app/events/migrations/0008_alter_eventhosttype_options_and_more.py
new file mode 100644
index 0000000..6afdc0f
--- /dev/null
+++ b/app/events/migrations/0008_alter_eventhosttype_options_and_more.py
@@ -0,0 +1,32 @@
+# Generated by Django 4.2.7 on 2024-07-26 21:28
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('events', '0007_eventownerpage_event_categories_title_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='eventhosttype',
+ options={'verbose_name_plural': 'Event Host Types'},
+ ),
+ migrations.AddField(
+ model_name='eventownerpage',
+ name='category_select',
+ field=models.CharField(default='Filter by category'),
+ ),
+ migrations.AddField(
+ model_name='eventownerpage',
+ name='filter_by_country',
+ field=models.CharField(default='Filter by country'),
+ ),
+ migrations.AddField(
+ model_name='eventownerpage',
+ name='host_type_select',
+ field=models.CharField(default='Filter by host type'),
+ ),
+ ]
diff --git a/app/events/migrations/0009_alter_eventownerpage_category_select_and_more.py b/app/events/migrations/0009_alter_eventownerpage_category_select_and_more.py
new file mode 100644
index 0000000..b2bfab5
--- /dev/null
+++ b/app/events/migrations/0009_alter_eventownerpage_category_select_and_more.py
@@ -0,0 +1,28 @@
+# Generated by Django 4.2.7 on 2024-07-26 21:29
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('events', '0008_alter_eventhosttype_options_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='eventownerpage',
+ name='category_select',
+ field=models.CharField(default='Filter by Category'),
+ ),
+ migrations.AlterField(
+ model_name='eventownerpage',
+ name='filter_by_country',
+ field=models.CharField(default='Filter by Country'),
+ ),
+ migrations.AlterField(
+ model_name='eventownerpage',
+ name='host_type_select',
+ field=models.CharField(default='Filter by Host Type'),
+ ),
+ ]
diff --git a/app/events/models.py b/app/events/models.py
index 7acc034..1d48f22 100644
--- a/app/events/models.py
+++ b/app/events/models.py
@@ -1,4 +1,6 @@
+from django import forms
from django.db import models
+from django.db.models import Q
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from wagtail.models import Page
@@ -7,6 +9,9 @@
from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from wagtail.search import index
+from wagtail.snippets.models import register_snippet
+
+from app.members.models import IndividualMappingHubPage
class EventOwnerPage(Page):
@@ -19,6 +24,28 @@ def get_context(self, request, *args, **kwargs):
if keyword:
events_list = events_list.search(keyword).get_queryset()
+ categories = EventCategory.objects.all()
+ query = Q()
+ for category in categories:
+ if request.GET.get(str(category), ''):
+ query = query | Q(event_categories=category)
+ events_list = events_list.filter(query)
+
+ # these queries and filters are done in seperate parts so that filtering is done as ANDs instead of ORs
+ event_host_types = EventHostType.objects.all()
+ query = Q()
+ for host_type in event_host_types:
+ if request.GET.get(str(host_type), ''):
+ query = query | Q(event_host_type=host_type)
+ events_list = events_list.filter(query)
+
+ hubs = IndividualMappingHubPage.objects.live().filter(locale=context['page'].locale)
+ query = Q()
+ for hub in hubs:
+ if request.GET.get(str(hub), ''):
+ query = query | Q(event_region_hub=hub)
+ events_list = events_list.filter(query).distinct()
+
match request.GET.get('sort', ''):
case 'sort.new':
events_list = events_list.order_by('-start_date_time')
@@ -43,6 +70,9 @@ def get_context(self, request, *args, **kwargs):
context['events'] = events
context['events_paginator'] = paginator
context['current_page'] = int(page)
+ context['categories'] = categories
+ context['hubs'] = hubs
+ context['event_host_types'] = event_host_types
return context
max_count = 1
@@ -52,6 +82,8 @@ def get_context(self, request, *args, **kwargs):
]
event_location_title = models.CharField(default="Event Location")
+ event_region_hub_title = models.CharField(default="Region Hub")
+ event_categories_title = models.CharField(default="Categories")
join_event_title = models.CharField(default="Join This Event")
rsvp_button_text = models.CharField(default="RSVP")
more_events_title = models.CharField(default="More Events")
@@ -60,6 +92,9 @@ def get_context(self, request, *args, **kwargs):
event_read_more_text = models.CharField(default="Read more")
keyword_search_hint = models.CharField(default="Search by keyword")
+ filter_by_country = models.CharField(default="Filter by Country")
+ host_type_select = models.CharField(default="Filter by Host Type")
+ category_select = models.CharField(default="Filter by Category")
sort_by_new = models.CharField(default="Sort by New")
sort_by_old = models.CharField(default="Sort by Old")
sort_by_titlea = models.CharField(default="Sort by Title Alphabetical")
@@ -70,6 +105,9 @@ def get_context(self, request, *args, **kwargs):
content_panels = Page.content_panels + [
MultiFieldPanel([
FieldPanel('keyword_search_hint'),
+ FieldPanel('filter_by_country'),
+ FieldPanel('host_type_select'),
+ FieldPanel('category_select'),
FieldPanel('sort_by_new'),
FieldPanel('sort_by_old'),
FieldPanel('sort_by_titlea'),
@@ -79,6 +117,8 @@ def get_context(self, request, *args, **kwargs):
], heading="Event Search Page"),
MultiFieldPanel([
FieldPanel('event_location_title'),
+ FieldPanel('event_region_hub_title'),
+ FieldPanel('event_categories_title'),
FieldPanel('join_event_title'),
FieldPanel('rsvp_button_text'),
FieldPanel('more_events_title'),
@@ -89,6 +129,36 @@ def get_context(self, request, *args, **kwargs):
]
+@register_snippet
+class EventHostType(models.Model):
+ type_name = models.CharField()
+
+ panels = [
+ FieldPanel("type_name")
+ ]
+
+ def __str__(self):
+ return self.type_name
+
+ class Meta:
+ verbose_name_plural = "Event Host Types"
+
+
+@register_snippet
+class EventCategory(models.Model):
+ category_name = models.CharField()
+
+ panels = [
+ FieldPanel("category_name")
+ ]
+
+ def __str__(self):
+ return self.category_name
+
+ class Meta:
+ verbose_name_plural = "Event Categories"
+
+
class IndividualEventPage(Page):
parent_page_types = [
'events.EventOwnerPage'
@@ -112,7 +182,22 @@ class IndividualEventPage(Page):
]))
], use_json_field=True, null=True)
+ event_host_type = models.ForeignKey(
+ 'events.EventHostType',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
event_location = models.CharField(blank=True)
+ event_region_hub = models.ForeignKey(
+ 'mapping_hubs.IndividualMappingHubPage',
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name='+'
+ )
+ event_categories = ParentalManyToManyField('events.EventCategory', blank=True)
rsvp_description = RichTextField(blank=True, help_text="If this field is empty, the RSVP description will not appear.")
rsvp_link = models.URLField(blank=True, help_text="If this field is empty, the RSVP button will not appear. If both RSVP Description and Link are empty, the RSVP section will be hidden.")
@@ -137,7 +222,10 @@ class IndividualEventPage(Page):
FieldPanel('extended_description'),
], heading="Body"),
MultiFieldPanel([
+ FieldPanel('event_host_type', widget=forms.RadioSelect),
FieldPanel('event_location'),
+ PageChooserPanel('event_region_hub'),
+ FieldPanel('event_categories', widget=forms.CheckboxSelectMultiple),
FieldPanel('rsvp_description'),
FieldPanel('rsvp_link'),
FieldPanel('more_events'),
diff --git a/app/events/templates/events/event_owner_page.html b/app/events/templates/events/event_owner_page.html
index 1d067b5..3ffad23 100644
--- a/app/events/templates/events/event_owner_page.html
+++ b/app/events/templates/events/event_owner_page.html
@@ -21,6 +21,63 @@
{{page.title}}
{% include "ui/components/icon_svgs/SearchIcon.html" with class="text-hot-red mx-3" %}
+ {% comment %} HOST TYPE {% endcomment %}
+
+
+
+ {{page.host_type_select}}
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %}
+
+
+
+ {% for event_host_type in event_host_types %}
+
+ {{event_host_type.type_name}}
+
+
+ {% endfor %}
+
+
+
+ {% comment %} CATEGORY {% endcomment %}
+
+
+
+ {{page.category_select}}
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %}
+
+
+
+ {% for category in categories %}
+
+ {{category.category_name}}
+
+
+ {% endfor %}
+
+
+
+ {% comment %} HUB {% endcomment %}
+
+
+
+ {{page.filter_by_country}}
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %}
+
+
+
+ {% for hub in hubs %}
+
+ {{hub.title}}
+
+
+ {% endfor %}
+
+
+
{% comment %} SORT {% endcomment %}
diff --git a/app/events/templates/events/individual_event_page.html b/app/events/templates/events/individual_event_page.html
index de51588..0598ed3 100644
--- a/app/events/templates/events/individual_event_page.html
+++ b/app/events/templates/events/individual_event_page.html
@@ -36,11 +36,40 @@
{{ page.title }}
{{page.get_parent.specific.event_location_title}}
-
- {{page.event_location}}
-
+ {% if page.event_host_type %}
+
+ {{page.event_host_type}}
+
+ {% endif %}
+ {% if page.event_location %}
+
+ {{page.event_location}}
+
+ {% endif %}
+ {% if page.event_region_hub %}
+
+ {{page.get_parent.specific.event_region_hub_title}}
+
+
+ {{page.event_region_hub.title}}
+
+
+ {% endif %}
+
+ {% if page.event_categories %}
+
+ {{page.get_parent.specific.event_categories_title}}
+
+
+ {% for category in page.event_categories.all %}
+ {{category}} {% if not forloop.last %}, {% endif %}
+ {% endfor %}
+
+
+ {% endif %}
+
{% if page.rsvp_description or page.rsvp_link %}
diff --git a/app/partners/__init__.py b/app/partners/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/partners/admin.py b/app/partners/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/app/partners/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/app/partners/apps.py b/app/partners/apps.py
new file mode 100644
index 0000000..6eb8a4b
--- /dev/null
+++ b/app/partners/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class PartnersConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'app.partners'
diff --git a/app/partners/migrations/0001_initial.py b/app/partners/migrations/0001_initial.py
new file mode 100644
index 0000000..b7f4b2c
--- /dev/null
+++ b/app/partners/migrations/0001_initial.py
@@ -0,0 +1,44 @@
+# Generated by Django 4.2.7 on 2024-07-25 18:00
+
+from django.db import migrations, models
+import django.db.models.deletion
+import wagtail.blocks
+import wagtail.fields
+import wagtail.images.blocks
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ('wagtailimages', '0025_alter_image_file_alter_rendition_file'),
+ ('wagtailcore', '0089_log_entry_data_json_null_to_object'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='PartnerWithUsPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
+ ('header_description', wagtail.fields.RichTextField(blank=True)),
+ ('intro', wagtail.fields.RichTextField(blank=True)),
+ ('partnership_types_title', models.CharField(default='Types of Partnerships')),
+ ('partnership_types', wagtail.fields.StreamField([('blocks', wagtail.blocks.StructBlock([('icon', wagtail.images.blocks.ImageChooserBlock()), ('title', wagtail.blocks.CharBlock()), ('description', wagtail.blocks.RichTextBlock())]))], blank=True, help_text='Blocks to be shown under the Types of Partnerships section.', null=True, use_json_field=True)),
+ ('meet_our_partners_title', models.CharField(default='Meet Our Partners')),
+ ('view_all_partners_text', models.CharField(default='View All Partners')),
+ ('view_all_partners_link', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)),
+ ('red_box_title', models.CharField(default='Still have questions?')),
+ ('red_box_link_text', models.CharField(default='Contact our team')),
+ ('red_box_link_url', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)),
+ ('black_box_title', models.CharField(default='Become a Partner')),
+ ('black_box_link_text', models.CharField(default='Email to partnerships@hotosm.org')),
+ ('black_box_link_url', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)),
+ ('header_image', models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ ]
diff --git a/app/partners/migrations/0002_alter_partnerwithuspage_black_box_link_url.py b/app/partners/migrations/0002_alter_partnerwithuspage_black_box_link_url.py
new file mode 100644
index 0000000..f1df0d9
--- /dev/null
+++ b/app/partners/migrations/0002_alter_partnerwithuspage_black_box_link_url.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.7 on 2024-07-25 19:30
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('partners', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='partnerwithuspage',
+ name='black_box_link_url',
+ field=models.EmailField(default='partnerships@hotosm.org', max_length=254),
+ ),
+ ]
diff --git a/app/partners/migrations/0003_rename_black_box_link_url_partnerwithuspage_black_box_link_email.py b/app/partners/migrations/0003_rename_black_box_link_url_partnerwithuspage_black_box_link_email.py
new file mode 100644
index 0000000..9ec3527
--- /dev/null
+++ b/app/partners/migrations/0003_rename_black_box_link_url_partnerwithuspage_black_box_link_email.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.7 on 2024-07-25 19:34
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('partners', '0002_alter_partnerwithuspage_black_box_link_url'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='partnerwithuspage',
+ old_name='black_box_link_url',
+ new_name='black_box_link_email',
+ ),
+ ]
diff --git a/app/partners/migrations/0004_ourpartnerspage.py b/app/partners/migrations/0004_ourpartnerspage.py
new file mode 100644
index 0000000..fb72bed
--- /dev/null
+++ b/app/partners/migrations/0004_ourpartnerspage.py
@@ -0,0 +1,38 @@
+# Generated by Django 4.2.7 on 2024-07-25 21:43
+
+from django.db import migrations, models
+import django.db.models.deletion
+import wagtail.blocks
+import wagtail.fields
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('wagtailcore', '0089_log_entry_data_json_null_to_object'),
+ ('wagtailimages', '0025_alter_image_file_alter_rendition_file'),
+ ('partners', '0003_rename_black_box_link_url_partnerwithuspage_black_box_link_email'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='OurPartnersPage',
+ fields=[
+ ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.page')),
+ ('intro', wagtail.fields.RichTextField(blank=True, help_text='This is shown in the header.')),
+ ('filter_by_type_text', models.CharField(default='Filter by Type')),
+ ('load_more_partners_text', models.CharField(default='Load More Partners')),
+ ('red_box_title', models.CharField(default='Join a working group')),
+ ('red_box_link_text', models.CharField(default='Working Groups')),
+ ('red_box_link_url', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)),
+ ('black_box_title', models.CharField(default='Contact a mapping community')),
+ ('black_box_link_text', models.CharField(default='Community Contact')),
+ ('black_box_link_url', wagtail.fields.StreamField([('page', wagtail.blocks.PageChooserBlock()), ('url', wagtail.blocks.URLBlock())], blank=True, use_json_field=True)),
+ ('header_image', models.ForeignKey(blank=True, help_text='Header image', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ bases=('wagtailcore.page',),
+ ),
+ ]
diff --git a/app/partners/migrations/0005_alter_ourpartnerspage_black_box_link_text_and_more.py b/app/partners/migrations/0005_alter_ourpartnerspage_black_box_link_text_and_more.py
new file mode 100644
index 0000000..d301782
--- /dev/null
+++ b/app/partners/migrations/0005_alter_ourpartnerspage_black_box_link_text_and_more.py
@@ -0,0 +1,33 @@
+# Generated by Django 4.2.7 on 2024-07-25 23:16
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('partners', '0004_ourpartnerspage'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='ourpartnerspage',
+ name='black_box_link_text',
+ field=models.CharField(default='Become a funder'),
+ ),
+ migrations.AlterField(
+ model_name='ourpartnerspage',
+ name='black_box_title',
+ field=models.CharField(default='Become a funding partner'),
+ ),
+ migrations.AlterField(
+ model_name='ourpartnerspage',
+ name='red_box_link_text',
+ field=models.CharField(default='Partner with us'),
+ ),
+ migrations.AlterField(
+ model_name='ourpartnerspage',
+ name='red_box_title',
+ field=models.CharField(default='Learn ways to partner with HOT'),
+ ),
+ ]
diff --git a/app/partners/migrations/0006_ourpartnerspage_filter_button_text.py b/app/partners/migrations/0006_ourpartnerspage_filter_button_text.py
new file mode 100644
index 0000000..47d6b22
--- /dev/null
+++ b/app/partners/migrations/0006_ourpartnerspage_filter_button_text.py
@@ -0,0 +1,18 @@
+# Generated by Django 4.2.7 on 2024-07-26 16:32
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('partners', '0005_alter_ourpartnerspage_black_box_link_text_and_more'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='ourpartnerspage',
+ name='filter_button_text',
+ field=models.CharField(default='Submit'),
+ ),
+ ]
diff --git a/app/partners/migrations/__init__.py b/app/partners/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/app/partners/models.py b/app/partners/models.py
new file mode 100644
index 0000000..9377506
--- /dev/null
+++ b/app/partners/models.py
@@ -0,0 +1,151 @@
+from django.db import models
+from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
+from django.db.models import Q
+
+from wagtail.admin.panels import FieldPanel, MultiFieldPanel
+from wagtail.fields import RichTextField, StreamField
+from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock
+from wagtail.images.blocks import ImageChooserBlock
+from wagtail.models import Page
+from app.core.models import LinkOrPageBlock, Partner, PartnerType
+
+
+# The "partners" snippet is in the core app's models.
+
+class PartnerWithUsPage(Page):
+ def get_context(self, request, *args, **kwargs):
+ context = super().get_context(request, *args, **kwargs)
+
+ partners = Partner.objects.all()
+
+ context['partners'] = partners
+ return context
+
+ max_count = 1
+
+ header_image = models.ForeignKey(
+ "wagtailimages.Image",
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name="+",
+ help_text="Header image"
+ )
+ header_description = RichTextField(blank=True)
+
+ intro = RichTextField(blank=True)
+
+ partnership_types_title = models.CharField(default="Types of Partnerships")
+ partnership_types = StreamField([
+ ('blocks', StructBlock([
+ ('icon', ImageChooserBlock()),
+ ('title', CharBlock()),
+ ('description', RichTextBlock())
+ ]))
+ ], use_json_field=True, null=True, blank=True, help_text="Blocks to be shown under the Types of Partnerships section.")
+
+ meet_our_partners_title = models.CharField(default="Meet Our Partners")
+ view_all_partners_text = models.CharField(default="View All Partners")
+ view_all_partners_link = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True)
+
+ red_box_title = models.CharField(default="Still have questions?")
+ red_box_link_text = models.CharField(default="Contact our team")
+ red_box_link_url = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True)
+ black_box_title = models.CharField(default="Become a Partner")
+ black_box_link_text = models.CharField(default="Email to partnerships@hotosm.org")
+ black_box_link_email = models.EmailField(default="partnerships@hotosm.org", max_length=254)
+
+ content_panels = Page.content_panels + [
+ MultiFieldPanel([
+ FieldPanel('header_image'),
+ FieldPanel('header_description'),
+ ], heading="Header"),
+ FieldPanel('intro'),
+ MultiFieldPanel([
+ FieldPanel('partnership_types_title'),
+ FieldPanel('partnership_types'),
+ ], heading="Types of Partnerships"),
+ MultiFieldPanel([
+ FieldPanel('meet_our_partners_title'),
+ FieldPanel('view_all_partners_text'),
+ FieldPanel('view_all_partners_link'),
+ ], heading="Meet Our Partners"),
+ MultiFieldPanel([
+ FieldPanel('red_box_title'),
+ FieldPanel('red_box_link_text'),
+ FieldPanel('red_box_link_url'),
+ FieldPanel('black_box_title'),
+ FieldPanel('black_box_link_text'),
+ FieldPanel('black_box_link_email'),
+ ], heading="Dogear Boxes"),
+ ]
+
+
+class OurPartnersPage(Page):
+ def get_context(self, request, *args, **kwargs):
+ context = super().get_context(request, *args, **kwargs)
+
+ partners = Partner.objects.all()
+
+ p_types = PartnerType.objects.all()
+ query = Q()
+ for p_type in p_types:
+ if request.GET.get(str(p_type), ''):
+ query = query | Q(partner_type__type_name=p_type)
+ partners = partners.filter(query).distinct()
+
+ page = request.GET.get('page', 1)
+ paginator = Paginator(partners, 12) # if you want more/less items per page (i.e., per load), change the number here to something else
+ try:
+ partners = paginator.page(page)
+ except PageNotAnInteger:
+ partners = paginator.page(1)
+ except EmptyPage:
+ partners = paginator.page(paginator.num_pages)
+
+ context['partners'] = partners
+ context['partner_types'] = p_types
+ return context
+
+ max_count = 1
+
+ header_image = models.ForeignKey(
+ "wagtailimages.Image",
+ null=True,
+ blank=True,
+ on_delete=models.SET_NULL,
+ related_name="+",
+ help_text="Header image"
+ )
+ intro = RichTextField(blank=True, help_text="This is shown in the header.")
+
+ filter_by_type_text = models.CharField(default="Filter by Type")
+
+ filter_button_text = models.CharField(default="Submit")
+
+ load_more_partners_text = models.CharField(default="Load More Partners")
+
+ red_box_title = models.CharField(default="Learn ways to partner with HOT")
+ red_box_link_text = models.CharField(default="Partner with us")
+ red_box_link_url = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True)
+ black_box_title = models.CharField(default="Become a funding partner")
+ black_box_link_text = models.CharField(default="Become a funder")
+ black_box_link_url = StreamField(LinkOrPageBlock(), use_json_field=True, blank=True)
+
+ content_panels = Page.content_panels + [
+ MultiFieldPanel([
+ FieldPanel('header_image'),
+ FieldPanel('intro'),
+ ], heading="Header"),
+ FieldPanel('filter_by_type_text'),
+ FieldPanel('filter_button_text'),
+ FieldPanel('load_more_partners_text'),
+ MultiFieldPanel([
+ FieldPanel('red_box_title'),
+ FieldPanel('red_box_link_text'),
+ FieldPanel('red_box_link_url'),
+ FieldPanel('black_box_title'),
+ FieldPanel('black_box_link_text'),
+ FieldPanel('black_box_link_url'),
+ ], heading="Dogear Boxes"),
+ ]
diff --git a/app/partners/templates/partners/our_partners_page.html b/app/partners/templates/partners/our_partners_page.html
new file mode 100644
index 0000000..2af7fa2
--- /dev/null
+++ b/app/partners/templates/partners/our_partners_page.html
@@ -0,0 +1,78 @@
+{% extends "base.html" %}
+{% load static %}
+{% load wagtailcore_tags %}
+{% load wagtailimages_tags %}
+{% load compress %}
+{% block body_class %}template-ourpartnerspage{% endblock %}
+{% block extra_css %}
+ {% compress css %}
+ {% endcompress css %}
+{% endblock extra_css %}
+
+{% block content %}
+ {% include "ui/components/PageHeaderWithBlur.html" with title=page.title subtitle=page.intro image=page.header_image full_length=True %}
+
+
+
+
+
+
+ {% for partner in partners %}
+
+ {% image partner.partner_logo original class="max-h-24 max-w-36 h-auto w-auto" %}
+
+ {% endfor %}
+
+
+ {% if partners.has_next %}
+ {% comment %} {% endcomment %}
+
+
+ {{page.load_more_partners_text}}
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %}
+
+ {% endif %}
+
+
+
+
+ {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_box_title linktext=page.red_box_link_text linkurl=page.red_box_link_url %}
+
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl=page.black_box_link_url %}
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/partners/templates/partners/partner_with_us_page.html b/app/partners/templates/partners/partner_with_us_page.html
new file mode 100644
index 0000000..491f0d3
--- /dev/null
+++ b/app/partners/templates/partners/partner_with_us_page.html
@@ -0,0 +1,53 @@
+{% extends "base.html" %}
+{% load static %}
+{% load wagtailcore_tags %}
+{% load wagtailimages_tags %}
+{% load compress %}
+{% block body_class %}template-partnerwithuspage{% endblock %}
+{% block extra_css %}
+ {% compress css %}
+ {% endcompress css %}
+{% endblock extra_css %}
+
+{% block content %}
+ {% include "ui/components/PageHeaderWithBlur.html" with title=page.title subtitle=page.header_description image=page.header_image full_length=True %}
+
+
+
+
+
+ {{page.intro|safe}}
+
+
+
+ {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.partnership_types_title %}
+
+ {% for block in page.partnership_types %}
+
+ {% image block.value.icon original class="h-8 w-8 mt-2" %}
+
+ {{block.value.title}}
+
+
+ {{block.value.description}}
+
+
+ {% endfor %}
+
+
+ {% include "ui/components/FlexTitleWithLink.html" with title=page.meet_our_partners_title linktext=page.view_all_partners_text linkurl=page.view_all_partners_link underline=True %}
+
+ {% include "ui/components/partners/PartnerViewBlock.html" %}
+
+
+
+
+ {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_box_title linktext=page.red_box_link_text linkurl=page.red_box_link_url %}
+
+
+ {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_box_title linktext=page.black_box_link_text linkurl="mailto:"|add:page.black_box_link_email %}
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/partners/tests.py b/app/partners/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/app/partners/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/app/partners/views.py b/app/partners/views.py
new file mode 100644
index 0000000..91ea44a
--- /dev/null
+++ b/app/partners/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/app/ui/templates/ui/components/FlexTitleWithLink.html b/app/ui/templates/ui/components/FlexTitleWithLink.html
index ecf2dc6..8141c90 100644
--- a/app/ui/templates/ui/components/FlexTitleWithLink.html
+++ b/app/ui/templates/ui/components/FlexTitleWithLink.html
@@ -7,9 +7,14 @@
- linkurl: string; the url for the link
{% endcomment %}
-
- {{title}}
-
+
+
+ {{title}}
+
+ {% if underline %}
+
+ {% endif %}
+
{% include "ui/components/BaseLink.html" %}
diff --git a/app/ui/templates/ui/components/PageHeaderWithBlur.html b/app/ui/templates/ui/components/PageHeaderWithBlur.html
index e67f2ed..6d1c3f2 100644
--- a/app/ui/templates/ui/components/PageHeaderWithBlur.html
+++ b/app/ui/templates/ui/components/PageHeaderWithBlur.html
@@ -14,12 +14,14 @@
-
+
{{ title }}
- {% if subtitle %}
- {{ subtitle|safe }}
- {% endif %}
+
+ {% if subtitle %}
+ {{ subtitle|safe }}
+ {% endif %}
+
diff --git a/home/templatetags/homepage_tags.py b/home/templatetags/homepage_tags.py
index 16500eb..cf36d38 100644
--- a/home/templatetags/homepage_tags.py
+++ b/home/templatetags/homepage_tags.py
@@ -16,8 +16,6 @@ def get_home_page(context):
if not home_page:
home_page = HomePage.objects.live().filter(locale=context['page'].locale).first().specific
-
- print(home_page)
return home_page
diff --git a/hot_osm/settings/base.py b/hot_osm/settings/base.py
index dcb9101..1adafa5 100644
--- a/hot_osm/settings/base.py
+++ b/hot_osm/settings/base.py
@@ -51,6 +51,7 @@
"app.volunteer_opportunities",
"app.rfp",
"app.misc",
+ "app.partners",
"search",
"users",
"utils",