From 35db98d73ff948917b745b7c64fa45d780087bf4 Mon Sep 17 00:00:00 2001 From: luminaryFlowers <71102109+luminaryFlowers@users.noreply.github.com> Date: Wed, 5 Jun 2024 09:45:45 -0700 Subject: [PATCH] created individual member page + improved existing page structure => pages which share sections (such as headings) are now to be created under a single "owner" page, and can be edited from there; child pages will use the sections from their owner --- ...age_black_dogear_box_link_text_and_more.py | 121 ++++++++++++++++++ app/impact_areas/models.py | 78 ++++++----- .../individual_impact_area_page.html | 14 +- app/members/__init__.py | 0 app/members/admin.py | 3 + app/members/apps.py | 6 + app/members/migrations/0001_initial.py | 47 +++++++ ..._individualmemberpage_location_and_more.py | 24 ++++ app/members/migrations/__init__.py | 0 app/members/models.py | 82 ++++++++++++ .../members/individual_member_page.html | 73 +++++++++++ app/members/tests.py | 3 + app/members/views.py | 3 + .../0016_individualnewspage_authors.py | 20 +++ ...ewspage_authors_posted_by_text_and_more.py | 23 ++++ .../0018_alter_individualnewspage_date.py | 18 +++ .../migrations/0019_newsownerpage_and_more.py | 66 ++++++++++ app/news/models.py | 54 +++++--- .../templates/news/individual_news_page.html | 25 +++- .../0008_programownerpage_and_more.py | 85 ++++++++++++ app/programs/models.py | 77 ++++++----- .../programs/individual_program_page.html | 16 +-- ...individualprojectpage_partners_and_more.py | 24 ++++ ...ividualprojectpage_project_contributors.py | 20 +++ ...ividualprojectpage_project_contributors.py | 20 +++ .../migrations/0018_projectownerpage.py | 41 ++++++ ...townerpage_view_all_events_url_and_more.py | 23 ++++ ...rojectpage_black_box_link_text_and_more.py | 77 +++++++++++ app/projects/models.py | 105 +++++++++------ .../projects/individual_project_page.html | 59 +++++---- .../components/news/NewsPreviewCarousel.html | 61 +++++++++ .../components/partners/PartnerViewBlock.html | 9 +- .../programs/ProgramCarouselBlock.html | 8 +- .../projects/ProjectPreviewBlockNews.html | 6 +- .../projects/ProjectPreviewCarousel.html | 61 +++++++++ hot_osm/locale/en/LC_MESSAGES/django.po | 2 +- hot_osm/locale/es/LC_MESSAGES/django.po | 2 +- hot_osm/locale/fr/LC_MESSAGES/django.po | 2 +- hot_osm/settings/base.py | 1 + media/images/temp_person.max-165x165.png | Bin 0 -> 4709 bytes media/images/temp_person.original.png | Bin 0 -> 4209 bytes media/original_images/temp_person.png | Bin 0 -> 2527 bytes 42 files changed, 1184 insertions(+), 175 deletions(-) create mode 100644 app/impact_areas/migrations/0014_remove_individualimpactareapage_black_dogear_box_link_text_and_more.py create mode 100644 app/members/__init__.py create mode 100644 app/members/admin.py create mode 100644 app/members/apps.py create mode 100644 app/members/migrations/0001_initial.py create mode 100644 app/members/migrations/0002_remove_individualmemberpage_location_and_more.py create mode 100644 app/members/migrations/__init__.py create mode 100644 app/members/models.py create mode 100644 app/members/templates/members/individual_member_page.html create mode 100644 app/members/tests.py create mode 100644 app/members/views.py create mode 100644 app/news/migrations/0016_individualnewspage_authors.py create mode 100644 app/news/migrations/0017_individualnewspage_authors_posted_by_text_and_more.py create mode 100644 app/news/migrations/0018_alter_individualnewspage_date.py create mode 100644 app/news/migrations/0019_newsownerpage_and_more.py create mode 100644 app/programs/migrations/0008_programownerpage_and_more.py create mode 100644 app/projects/migrations/0015_remove_individualprojectpage_partners_and_more.py create mode 100644 app/projects/migrations/0016_individualprojectpage_project_contributors.py create mode 100644 app/projects/migrations/0017_alter_individualprojectpage_project_contributors.py create mode 100644 app/projects/migrations/0018_projectownerpage.py create mode 100644 app/projects/migrations/0019_projectownerpage_view_all_events_url_and_more.py create mode 100644 app/projects/migrations/0020_remove_individualprojectpage_black_box_link_text_and_more.py create mode 100644 app/ui/templates/ui/components/news/NewsPreviewCarousel.html create mode 100644 app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html create mode 100644 media/images/temp_person.max-165x165.png create mode 100644 media/images/temp_person.original.png create mode 100644 media/original_images/temp_person.png diff --git a/app/impact_areas/migrations/0014_remove_individualimpactareapage_black_dogear_box_link_text_and_more.py b/app/impact_areas/migrations/0014_remove_individualimpactareapage_black_dogear_box_link_text_and_more.py new file mode 100644 index 0000000..ad98470 --- /dev/null +++ b/app/impact_areas/migrations/0014_remove_individualimpactareapage_black_dogear_box_link_text_and_more.py @@ -0,0 +1,121 @@ +# Generated by Django 4.2.7 on 2024-06-04 23:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('impact_areas', '0013_individualimpactareapage_external_icon_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualimpactareapage', + name='black_dogear_box_link_text', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='black_dogear_box_link_url', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='black_dogear_box_title', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='explore_impact_areas_text', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='load_more_projects_text', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='projects_title', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='red_dogear_box_link_text', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='red_dogear_box_link_url', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='red_dogear_box_title', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='use_cases_title', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='view_all_projects_link', + ), + migrations.RemoveField( + model_name='individualimpactareapage', + name='view_all_projects_text', + ), + migrations.AddField( + model_name='impactareaspage', + name='black_dogear_box_link_text', + field=models.CharField(default='Get Involved with HOT'), + ), + migrations.AddField( + model_name='impactareaspage', + name='black_dogear_box_link_url', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='impactareaspage', + name='black_dogear_box_title', + field=models.CharField(default='Check many opportunities to get involved with HOT!'), + ), + migrations.AddField( + model_name='impactareaspage', + name='explore_impact_areas_text', + field=models.CharField(default='Explore Other Impact Areas'), + ), + migrations.AddField( + model_name='impactareaspage', + name='load_more_projects_text', + field=models.CharField(default='Load More Projects'), + ), + migrations.AddField( + model_name='impactareaspage', + name='projects_title', + field=models.CharField(default='Projects'), + ), + migrations.AddField( + model_name='impactareaspage', + name='red_dogear_box_link_text', + field=models.CharField(default='View Tools & Resources'), + ), + migrations.AddField( + model_name='impactareaspage', + name='red_dogear_box_link_url', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='impactareaspage', + name='red_dogear_box_title', + field=models.CharField(default='Learn more about Tools & Resources and Data Access'), + ), + migrations.AddField( + model_name='impactareaspage', + name='use_cases_title', + field=models.CharField(default='Use Cases'), + ), + migrations.AddField( + model_name='impactareaspage', + name='view_all_projects_link', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='impactareaspage', + name='view_all_projects_text', + field=models.CharField(default='View all projects'), + ), + ] diff --git a/app/impact_areas/models.py b/app/impact_areas/models.py index 91fa638..d63017a 100644 --- a/app/impact_areas/models.py +++ b/app/impact_areas/models.py @@ -42,6 +42,10 @@ def get_context(self, request, *args, **kwargs): context['other_impact_areas'] = other_impact_areas return context + parent_page_type = [ + 'impact_areas.ImpactAreasPage' + ] + header_image = models.ForeignKey( "wagtailimages.Image", null=True, @@ -71,24 +75,8 @@ def get_context(self, request, *args, **kwargs): intro = RichTextField(blank=True) description = RichTextField(blank=True) - use_cases_title = models.CharField(default="Use Cases") use_cases = StreamField(UseCaseBlock(), use_json_field=True, blank=True, null=True) - projects_title = models.CharField(default="Projects") - view_all_projects_text = models.CharField(default="View all projects") - view_all_projects_link = models.URLField(blank=True) - load_more_projects_text = models.CharField(default="Load More Projects") - - explore_impact_areas_text = models.CharField(default="Explore Other Impact Areas") - - red_dogear_box_title = models.CharField(blank=True) - red_dogear_box_link_text = models.CharField(blank=True) - red_dogear_box_link_url = models.URLField(blank=True) - - black_dogear_box_title = models.CharField(blank=True) - black_dogear_box_link_text = models.CharField(blank=True) - black_dogear_box_link_url = models.URLField(blank=True) - content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('header_image'), @@ -101,24 +89,8 @@ def get_context(self, request, *args, **kwargs): FieldPanel('description'), ], heading="Body"), MultiFieldPanel([ - FieldPanel('use_cases_title'), FieldPanel('use_cases'), ], heading="Use Cases"), - MultiFieldPanel([ - FieldPanel('projects_title'), - FieldPanel('view_all_projects_text'), - FieldPanel('view_all_projects_link'), - FieldPanel('load_more_projects_text'), - ], heading="Projects"), - FieldPanel('explore_impact_areas_text'), - MultiFieldPanel([ - FieldPanel('red_dogear_box_title'), - FieldPanel('red_dogear_box_link_text'), - FieldPanel('red_dogear_box_link_url'), - FieldPanel('black_dogear_box_title'), - FieldPanel('black_dogear_box_link_text'), - FieldPanel('black_dogear_box_link_url'), - ], heading="Dogear Boxes"), ] @@ -134,6 +106,8 @@ class ImpactAreaBlock(StreamBlock): class ImpactAreasPage(Page): + max_count = 1 + intro = RichTextField(blank=True) image = models.ForeignKey( @@ -147,10 +121,48 @@ class ImpactAreasPage(Page): impact_area_blocks = StreamField(ImpactAreaBlock(), use_json_field=True, null=True) + # > IMPACT AREA SHARED FIELDS + use_cases_title = models.CharField(default="Use Cases") + + projects_title = models.CharField(default="Projects") + view_all_projects_text = models.CharField(default="View all projects") + view_all_projects_link = models.URLField(blank=True) + load_more_projects_text = models.CharField(default="Load More Projects") + + explore_impact_areas_text = models.CharField(default="Explore Other Impact Areas") + + red_dogear_box_title = models.CharField(default="Learn more about Tools & Resources and Data Access") + red_dogear_box_link_text = models.CharField(default="View Tools & Resources") + red_dogear_box_link_url = models.URLField(blank=True) + + black_dogear_box_title = models.CharField(default="Check many opportunities to get involved with HOT!") + black_dogear_box_link_text = models.CharField(default="Get Involved with HOT") + black_dogear_box_link_url = models.URLField(blank=True) + content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel('image'), FieldPanel('intro') ], heading="Header section"), - FieldPanel('impact_area_blocks') + FieldPanel('impact_area_blocks'), + MultiFieldPanel([ + MultiFieldPanel([ + FieldPanel('use_cases_title'), + ], heading="Use Cases"), + MultiFieldPanel([ + FieldPanel('projects_title'), + FieldPanel('view_all_projects_text'), + FieldPanel('view_all_projects_link'), + FieldPanel('load_more_projects_text'), + ], heading="Projects"), + FieldPanel('explore_impact_areas_text'), + MultiFieldPanel([ + FieldPanel('red_dogear_box_title'), + FieldPanel('red_dogear_box_link_text'), + FieldPanel('red_dogear_box_link_url'), + FieldPanel('black_dogear_box_title'), + FieldPanel('black_dogear_box_link_text'), + FieldPanel('black_dogear_box_link_url'), + ], heading="Dogear Boxes"), + ], heading="Impact Area Shared Fields"), ] diff --git a/app/impact_areas/templates/impact_areas/individual_impact_area_page.html b/app/impact_areas/templates/impact_areas/individual_impact_area_page.html index 7ee8749..3a971b0 100644 --- a/app/impact_areas/templates/impact_areas/individual_impact_area_page.html +++ b/app/impact_areas/templates/impact_areas/individual_impact_area_page.html @@ -26,7 +26,7 @@ {% comment %} USE CASES {% endcomment %} - {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.use_cases_title %} + {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.get_parent.specific.use_cases_title %}
{% for case in page.use_cases %} {% include "./components/UseCaseBox.html" with number=forloop.counter body=case.value.description linktext=case.value.link_text linkurl=case.value.link_url %} @@ -37,10 +37,10 @@
- {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.projects_title %} + {% include "ui/components/SectionHeadingWithUnderline.html" with title=page.get_parent.specific.projects_title %}

- {% include "ui/components/BaseLink.html" with linktext=page.view_all_projects_text linkurl=page.view_all_projects_link %} + {% include "ui/components/BaseLink.html" with linktext=page.get_parent.specific.view_all_projects_text linkurl=page.view_all_projects_link %}

@@ -58,7 +58,7 @@ hx-select-oob="#projects-list:beforeend, #next-project:outerHTML" > - Load More Projects + {{page.get_parent.specific.load_more_projects_text}} {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-90 text-hot-red" %} @@ -69,7 +69,7 @@ {% comment %} OTHER IMPACT AREAS {% endcomment %}

- {{ page.explore_impact_areas_text }} + {{ page.get_parent.specific.explore_impact_areas_text }}

{% for area in other_impact_areas %} @@ -91,10 +91,10 @@

{% comment %} DOGEAR BOXES {% endcomment %}
- {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.red_dogear_box_title linktext=page.red_dogear_box_link_text linkurl=page.red_dogear_box_link_url %} + {% include "ui/components/dogear_boxes/DogearRed.html" with title=page.get_parent.specific.red_dogear_box_title linktext=page.get_parent.specific.red_dogear_box_link_text linkurl=page.get_parent.specific.red_dogear_box_link_url %}
- {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.black_dogear_box_title linktext=page.black_dogear_box_link_text linkurl=page.black_dogear_box_link_url %} + {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.get_parent.specific.black_dogear_box_title linktext=page.get_parent.specific.black_dogear_box_link_text linkurl=page.get_parent.specific.black_dogear_box_link_url %}

diff --git a/app/members/__init__.py b/app/members/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/members/admin.py b/app/members/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/app/members/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/app/members/apps.py b/app/members/apps.py new file mode 100644 index 0000000..db4ad21 --- /dev/null +++ b/app/members/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class MembersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'app.members' diff --git a/app/members/migrations/0001_initial.py b/app/members/migrations/0001_initial.py new file mode 100644 index 0000000..4a06355 --- /dev/null +++ b/app/members/migrations/0001_initial.py @@ -0,0 +1,47 @@ +# Generated by Django 4.2.7 on 2024-06-03 23:02 + +from django.db import migrations, models +import django.db.models.deletion +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('wagtailimages', '0025_alter_image_file_alter_rendition_file'), + ] + + operations = [ + migrations.CreateModel( + name='MemberOwnerPage', + 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')), + ('on_the_web_title', models.CharField(default='On the Web')), + ('posts_title', models.CharField(default='Posts')), + ('project_contribution_title', models.CharField(default='Project Contribution')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.CreateModel( + name='IndividualMemberPage', + 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')), + ('position', models.CharField()), + ('location', models.CharField()), + ('introduction', wagtail.fields.RichTextField()), + ('on_the_web_links', wagtail.fields.StreamField([('blocks', wagtail.blocks.StructBlock([('link_text', wagtail.blocks.CharBlock(required=True)), ('link_url', wagtail.blocks.URLBlock(blank=True, required=False))]))], blank=True, use_json_field=True)), + ('image', models.ForeignKey(blank=True, help_text='An image of the member', 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/members/migrations/0002_remove_individualmemberpage_location_and_more.py b/app/members/migrations/0002_remove_individualmemberpage_location_and_more.py new file mode 100644 index 0000000..e8f6967 --- /dev/null +++ b/app/members/migrations/0002_remove_individualmemberpage_location_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2024-06-03 23:26 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mapping_hubs', '0008_alter_individualmappinghubpage_dogear_boxes'), + ('members', '0001_initial'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualmemberpage', + name='location', + ), + migrations.AddField( + model_name='individualmemberpage', + name='location_hub', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='mapping_hubs.individualmappinghubpage'), + ), + ] diff --git a/app/members/migrations/__init__.py b/app/members/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/members/models.py b/app/members/models.py new file mode 100644 index 0000000..00e53fe --- /dev/null +++ b/app/members/models.py @@ -0,0 +1,82 @@ +from django.db import models +from wagtail.admin.panels import FieldPanel, MultiFieldPanel +from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, PageChooserBlock +from wagtail.fields import RichTextField, StreamField +from wagtail.models import Page +from django.db.models import Q +from app.projects.models import IndividualProjectPage +from app.news.models import IndividualNewsPage + +class WebLinkStructBlock(StructBlock): + link_text = CharBlock(required=True) + link_url = URLBlock(required=False, blank=True) + + +class WebLinkBlock(StreamBlock): + blocks = WebLinkStructBlock() + + +class MemberOwnerPage(Page): + max_count = 1 + + on_the_web_title = models.CharField(default="On the Web") + posts_title = models.CharField(default="Posts") + project_contribution_title = models.CharField(default="Project Contribution") + + content_panels = Page.content_panels + [ + FieldPanel('on_the_web_title'), + FieldPanel('posts_title'), + FieldPanel('project_contribution_title'), + ] + +""" +This page should only be created as a child of a MemberOwnerPage! +Its template depends on fields from the MemberOwnerPage in order +to create one unifying place where unchanging fields may be modified. +""" +class IndividualMemberPage(Page): + def get_context(self, request, *args, **kwargs): + context = super().get_context(request, *args, **kwargs) + + news_posts = IndividualNewsPage.objects.live().filter( + Q(authors__contains=[{'type': 'author', 'value': context['page'].id}]) + ).filter(locale=context['page'].locale) + project_contributions = IndividualProjectPage.objects.live().filter( + Q(project_contributors__contains=[{'type': 'contributor', 'value': context['page'].id}]) + ).filter(locale=context['page'].locale) + + context['posts'] = news_posts + context['contributions'] = project_contributions + + return context + + parent_page_type = [ + 'members.MemberOwnerPage' + ] + + image = models.ForeignKey( + "wagtailimages.Image", + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name="+", + help_text="An image of the member", + ) + position = models.CharField() + location_hub = models.ForeignKey( + 'mapping_hubs.IndividualMappingHubPage', + null=True, + blank=True, + on_delete=models.SET_NULL, + related_name='+' + ) + introduction = RichTextField() + on_the_web_links = StreamField(WebLinkBlock(), blank=True, use_json_field=True) + + content_panels = Page.content_panels + [ + FieldPanel('image'), + FieldPanel('position'), + FieldPanel('location_hub'), + FieldPanel('introduction'), + FieldPanel('on_the_web_links'), + ] diff --git a/app/members/templates/members/individual_member_page.html b/app/members/templates/members/individual_member_page.html new file mode 100644 index 0000000..ccd2c59 --- /dev/null +++ b/app/members/templates/members/individual_member_page.html @@ -0,0 +1,73 @@ +{% extends "base.html" %} +{% load static %} +{% load wagtailcore_tags %} +{% load wagtailimages_tags %} +{% load compress %} +{% block body_class %}template-individualmappinghubpage{% endblock %} +{% block extra_css %} + {% compress css %} + {% endcompress css %} +{% endblock extra_css %} + +{% block content %} +
+ {% comment %} BODY SECTION {% endcomment %} +
+
+ {% if page.image %} + {% image page.image original class="md:w-full h-auto w-auto max-h-[24rem] object-contain" %} + {% endif %} +
+
+ {% comment %} TODO: REMOVE PLACEHOLDER AND IMPLEMENT PROPER (BASICALLY REQUIRES OTHER PAGES COMPLETION) {% endcomment %} +

+ Board + / + Voting Member + / + Staff +

+

{{page.title}}

+

+ {{page.position}} + / + {{page.location_hub.title}} +

+
+ {{page.introduction|safe}} +
+
+
+ + {% comment %} ON THE WEB LINKS {% endcomment %} + {% if page.on_the_web_links %} +
+
+
+

{{page.get_parent.specific.on_the_web_title}}

+
+ {% for link in page.on_the_web_links %} +

+ {% include "ui/components/BaseLink.html" with linktext=link.value.link_text linkurl=link.value.link_url %} +

+ {% endfor %} +
+
+
+ {% endif %} + + {% comment %} NEWS POSTS {% endcomment %} + {% if posts %} +
+ {% include "ui/components/news/NewsPreviewCarousel.html" with news=posts title=page.get_parent.specific.posts_title %} +
+ {% endif %} + + {% comment %} CONTRIBUTIONS {% endcomment %} + {% if contributions%} +
+ {% include "ui/components/projects/ProjectPreviewCarousel.html" with projects=contributions title=page.get_parent.specific.project_contribution_title %} +
+ {% endif %} +
+{% endblock %} \ No newline at end of file diff --git a/app/members/tests.py b/app/members/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/app/members/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/app/members/views.py b/app/members/views.py new file mode 100644 index 0000000..91ea44a --- /dev/null +++ b/app/members/views.py @@ -0,0 +1,3 @@ +from django.shortcuts import render + +# Create your views here. diff --git a/app/news/migrations/0016_individualnewspage_authors.py b/app/news/migrations/0016_individualnewspage_authors.py new file mode 100644 index 0000000..ecdcd16 --- /dev/null +++ b/app/news/migrations/0016_individualnewspage_authors.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-06-04 16:57 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0015_alter_individualnewspage_article_body'), + ] + + operations = [ + migrations.AddField( + model_name='individualnewspage', + name='authors', + field=wagtail.fields.StreamField([('author', wagtail.blocks.PageChooserBlock(page_type=['members.IndividualMemberPage']))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/news/migrations/0017_individualnewspage_authors_posted_by_text_and_more.py b/app/news/migrations/0017_individualnewspage_authors_posted_by_text_and_more.py new file mode 100644 index 0000000..2d5154e --- /dev/null +++ b/app/news/migrations/0017_individualnewspage_authors_posted_by_text_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2024-06-04 21:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0016_individualnewspage_authors'), + ] + + operations = [ + migrations.AddField( + model_name='individualnewspage', + name='authors_posted_by_text', + field=models.CharField(default='Posted by', help_text="The text which appears prior to the authors names; with 'posted by', the text displays as 'posted by [author]'."), + ), + migrations.AddField( + model_name='individualnewspage', + name='authors_posted_on_text', + field=models.CharField(default='on', help_text="The text which appears prior to the date; with 'on', it would display as 'on [date]'."), + ), + ] diff --git a/app/news/migrations/0018_alter_individualnewspage_date.py b/app/news/migrations/0018_alter_individualnewspage_date.py new file mode 100644 index 0000000..121acd0 --- /dev/null +++ b/app/news/migrations/0018_alter_individualnewspage_date.py @@ -0,0 +1,18 @@ +# Generated by Django 4.2.7 on 2024-06-04 22:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0017_individualnewspage_authors_posted_by_text_and_more'), + ] + + operations = [ + migrations.AlterField( + model_name='individualnewspage', + name='date', + field=models.DateField(help_text='Post date'), + ), + ] diff --git a/app/news/migrations/0019_newsownerpage_and_more.py b/app/news/migrations/0019_newsownerpage_and_more.py new file mode 100644 index 0000000..a0c57dd --- /dev/null +++ b/app/news/migrations/0019_newsownerpage_and_more.py @@ -0,0 +1,66 @@ +# Generated by Django 4.2.7 on 2024-06-04 23:03 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('news', '0018_alter_individualnewspage_date'), + ] + + operations = [ + migrations.CreateModel( + name='NewsOwnerPage', + 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')), + ('authors_posted_by_text', models.CharField(default='Posted by', help_text="The text which appears prior to the authors names; with 'posted by', the text displays as 'posted by [author]'.")), + ('authors_posted_on_text', models.CharField(default='on', help_text="The text which appears prior to the date; with 'on', it would display as 'on [date]'.")), + ('related_projects_title', models.CharField(default='Related Projects')), + ('related_news_title', models.CharField(default='Related News')), + ('view_all_news_text', models.CharField(default='View all News')), + ('view_all_news_url', models.URLField(blank=True)), + ('news_read_more_text', models.CharField(default='Read More')), + ('categories_title', models.CharField(default='Categories')), + ('tags_title', models.CharField(default='Tags')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.RemoveField( + model_name='individualnewspage', + name='authors_posted_by_text', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='authors_posted_on_text', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='categories_title', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='news_read_more_text', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='related_news_title', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='related_projects_title', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='tags_title', + ), + migrations.RemoveField( + model_name='individualnewspage', + name='view_all_news_text', + ), + ] diff --git a/app/news/models.py b/app/news/models.py index 8bc6cb6..d2c3b1e 100644 --- a/app/news/models.py +++ b/app/news/models.py @@ -12,6 +12,36 @@ from wagtail.snippets.models import register_snippet +class NewsOwnerPage(Page): + max_count = 1 + + authors_posted_by_text = models.CharField(default="Posted by", help_text="The text which appears prior to the authors names; with 'posted by', the text displays as 'posted by [author]'.") + authors_posted_on_text = models.CharField(default="on", help_text="The text which appears prior to the date; with 'on', it would display as 'on [date]'.") + related_projects_title = models.CharField(default="Related Projects") + related_news_title = models.CharField(default="Related News") + view_all_news_text = models.CharField(default="View all News") + view_all_news_url = models.URLField(blank=True) + news_read_more_text = models.CharField(default="Read More") + categories_title = models.CharField(default="Categories") + tags_title = models.CharField(default="Tags") + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel("authors_posted_by_text"), + FieldPanel("authors_posted_on_text"), + ], heading="Info"), + MultiFieldPanel([ + FieldPanel('related_projects_title'), + FieldPanel('related_news_title'), + FieldPanel('view_all_news_text'), + FieldPanel('view_all_news_url'), + FieldPanel('news_read_more_text'), + FieldPanel('categories_title'), + FieldPanel('tags_title'), + ], heading="Sidebar"), + ] + + @register_snippet class NewsCategory(models.Model): category_name = models.CharField() @@ -36,6 +66,12 @@ class NewsTag(TaggedItemBase): class IndividualNewsPage(Page): + parent_page_type = [ + 'news.NewsOwnerPage' + ] + + authors = StreamField([('author', PageChooserBlock(page_type="members.IndividualMemberPage"))], use_json_field=True, null=True, blank=True) + image = models.ForeignKey( "wagtailimages.Image", null=True, @@ -47,7 +83,7 @@ class IndividualNewsPage(Page): intro = RichTextField(blank=True) - date = models.DateField("Post date") + date = models.DateField(help_text="Post date") article_body = StreamField([ ('text_block', RichTextBlock(features=[ @@ -55,28 +91,22 @@ class IndividualNewsPage(Page): ])) ], use_json_field=True, null=True, blank=True) - # Question: are related projects/news chosen for the article, or are they based off something? - related_projects_title = models.CharField(default="Related Projects") related_projects = StreamField([ ('project_page', PageChooserBlock(page_type="projects.IndividualProjectPage")) ], use_json_field=True, null=True, blank=True) - related_news_title = models.CharField(default="Related News") - view_all_news_text = models.CharField(default="View all News") related_news = StreamField([ ('news_page', PageChooserBlock(page_type="news.IndividualNewsPage")) ], use_json_field=True, null=True, blank=True) - news_read_more_text = models.CharField(default="Read More") - categories_title = models.CharField(default="Categories") categories = ParentalManyToManyField('news.NewsCategory', blank=True) - tags_title = models.CharField(default="Tags") tags = ClusterTaggableManager(through=NewsTag, blank=True) content_panels = Page.content_panels + [ MultiFieldPanel([ - FieldPanel("date") + FieldPanel("authors"), + FieldPanel("date"), ], heading="Info"), MultiFieldPanel([ FieldPanel("image"), @@ -84,15 +114,9 @@ class IndividualNewsPage(Page): FieldPanel("article_body"), ], heading="Body"), MultiFieldPanel([ - FieldPanel('related_projects_title'), FieldPanel('related_projects'), - FieldPanel('related_news_title'), - FieldPanel('view_all_news_text'), FieldPanel('related_news'), - FieldPanel('news_read_more_text'), - FieldPanel('categories_title'), FieldPanel('categories', widget=forms.CheckboxSelectMultiple), - FieldPanel('tags_title'), FieldPanel('tags'), ], heading="Sidebar"), ] diff --git a/app/news/templates/news/individual_news_page.html b/app/news/templates/news/individual_news_page.html index d1869c1..26b25ac 100644 --- a/app/news/templates/news/individual_news_page.html +++ b/app/news/templates/news/individual_news_page.html @@ -14,7 +14,16 @@ {% comment %} HEADER {% endcomment %}

{{ page.title }}

-

Posted by Author on {{ page.date }}

+

+ {{page.get_parent.specific.authors_posted_by_text}} + {% for author in page.authors %} + {{author.value.title}} + {% if not forloop.last %} + , + {% endif %} + {% endfor %} + {{page.get_parent.specific.authors_posted_on_text}} {{ page.date }} +

@@ -35,7 +44,7 @@

{{ page.title }}


- {{ page.related_projects_title }} + {{ page.get_parent.specific.related_projects_title }}

{% with projects=page.related_projects %} @@ -51,13 +60,15 @@


- {{ page.related_news_title }} + {{ page.get_parent.specific.related_news_title }}

- {% include "ui/components/BaseLink.html" with linkurl="#" linktext=page.view_all_news_text %} +
+ {% include "ui/components/BaseLink.html" with linkurl="#" linktext=page.get_parent.specific.view_all_news_text %} +
{% with allnews=page.related_news %} {% for news in allnews %} - {% include "ui/components/news/NewsPreviewBlockNews.html" with news=news.value readmoretext=page.read_more_text %} + {% include "ui/components/news/NewsPreviewBlockNews.html" with news=news.value readmoretext=page.get_parent.specific.read_more_text %} {% endfor %} {% endwith %}
@@ -68,7 +79,7 @@


- {{ page.categories_title }} + {{ page.get_parent.specific.categories_title }}

{% with categories=page.categories.all %} @@ -84,7 +95,7 @@


- {{ page.tags_title }} + {{ page.get_parent.specific.tags_title }}

{% with tags=page.tags.all %} diff --git a/app/programs/migrations/0008_programownerpage_and_more.py b/app/programs/migrations/0008_programownerpage_and_more.py new file mode 100644 index 0000000..c0a645c --- /dev/null +++ b/app/programs/migrations/0008_programownerpage_and_more.py @@ -0,0 +1,85 @@ +# Generated by Django 4.2.7 on 2024-06-05 16:21 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('programs', '0007_alter_individualprogrampage_bottom_banner_text'), + ] + + operations = [ + migrations.CreateModel( + name='ProgramOwnerPage', + 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')), + ('stats_title', models.CharField(default='Stats')), + ('goals_title', models.CharField(default='Goals')), + ('projects_title', models.CharField(default='Projects')), + ('partners_title', models.CharField(default='Meet Our Partners')), + ('view_all_partners_title', models.CharField(default='View All Partners')), + ('view_all_partners_link', models.CharField(blank=True)), + ('more_programs_title', models.CharField(default='More Programs')), + ('view_all_programs_title', models.CharField(default='View All Programs')), + ('view_all_programs_link', models.URLField(blank=True)), + ('bottom_banner_text', models.CharField(default='Check out the many opportunities to get involved with HOT!')), + ('bottom_banner_url', models.URLField(blank=True)), + ('bottom_banner_url_text', models.CharField(default='Get Involved with HOT')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='bottom_banner_text', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='bottom_banner_url', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='bottom_banner_url_text', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='goals_title', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='more_programs_title', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='partners_title', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='projects_title', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='stats_title', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='view_all_partners_link', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='view_all_partners_title', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='view_all_programs_link', + ), + migrations.RemoveField( + model_name='individualprogrampage', + name='view_all_programs_title', + ), + ] diff --git a/app/programs/models.py b/app/programs/models.py index a639777..9e55079 100644 --- a/app/programs/models.py +++ b/app/programs/models.py @@ -33,6 +33,49 @@ class ProgramGoalBlock(StreamBlock): goal_block = IndividualGoalBlock() +class ProgramOwnerPage(Page): + max_count = 1 + + stats_title = models.CharField(default="Stats") + goals_title = models.CharField(default="Goals") + projects_title = models.CharField(default="Projects") + + partners_title = models.CharField(default="Meet Our Partners") + view_all_partners_title = models.CharField(default="View All Partners") + view_all_partners_link = models.CharField(blank=True) + + more_programs_title = models.CharField(default="More Programs") + view_all_programs_title = models.CharField(default="View All Programs") + view_all_programs_link = models.URLField(blank=True) + + bottom_banner_text = models.CharField(default="Check out the many opportunities to get involved with HOT!") + bottom_banner_url = models.URLField(blank=True) + bottom_banner_url_text = models.CharField(default="Get Involved with HOT") + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel("stats_title"), + FieldPanel("goals_title"), + FieldPanel("projects_title"), + ], heading="Various Section Titles"), + MultiFieldPanel([ + FieldPanel("partners_title"), + FieldPanel("view_all_partners_title"), + FieldPanel("view_all_partners_link"), + ], heading="Partners"), + MultiFieldPanel([ + FieldPanel("more_programs_title"), + FieldPanel("view_all_programs_title"), + FieldPanel("view_all_programs_link"), + ], heading="Programs"), + MultiFieldPanel([ + FieldPanel('bottom_banner_text'), + FieldPanel('bottom_banner_url'), + FieldPanel('bottom_banner_url_text'), + ]), + ] + + class IndividualProgramPage(Page): def get_context(self, request): context = super().get_context(request) @@ -40,6 +83,10 @@ def get_context(self, request): context['projects'] = projects return context + parent_page_type = [ + 'programs.ProgramOwnerPage' + ] + subtitle = RichTextField(blank=True) header_image = models.ForeignKey( "wagtailimages.Image", @@ -61,30 +108,16 @@ def get_context(self, request): help_text="Intro image" ) - stats_title = models.CharField(default="Stats") stats = StreamField(ProgramStatBlock(), use_json_field=True, null=True, blank=True) - goals_title = models.CharField(default="Goals") goals = StreamField(ProgramGoalBlock(), use_json_field=True, null=True, blank=True) - projects_title = models.CharField(default="Projects") - - partners_title = models.CharField(default="Meet Our Partners") - view_all_partners_title = models.CharField(default="View All Partners") - view_all_partners_link = models.CharField(blank=True) partners = ParentalManyToManyField('core.Partner', blank=True) - more_programs_title = models.CharField(default="More Programs") - view_all_programs_title = models.CharField(default="View All Programs") - view_all_programs_link = models.URLField(blank=True) more_programs = StreamField([ ('program_page', PageChooserBlock(page_type="programs.IndividualProgramPage")) ], use_json_field=True, null=True, blank=True) - bottom_banner_text = models.CharField(default="Check out the many opportunities to get involved with HOT!") - bottom_banner_url = models.URLField(blank=True) - bottom_banner_url_text = models.CharField(default="Get Involved with HOT") - content_panels = Page.content_panels + [ MultiFieldPanel([ FieldPanel("subtitle"), @@ -96,31 +129,15 @@ def get_context(self, request): FieldPanel("intro_image"), ], heading="Intro"), MultiFieldPanel([ - FieldPanel("stats_title"), FieldPanel("stats"), ], heading="Stats"), MultiFieldPanel([ - FieldPanel("goals_title"), FieldPanel("goals"), ], heading="Goals"), MultiFieldPanel([ - FieldPanel("projects_title"), - ], heading="Projects"), - MultiFieldPanel([ - FieldPanel("partners_title"), - FieldPanel("view_all_partners_title"), - FieldPanel("view_all_partners_link"), FieldPanel("partners", widget=forms.CheckboxSelectMultiple), ], heading="Partners"), MultiFieldPanel([ - FieldPanel("more_programs_title"), - FieldPanel("view_all_programs_title"), - FieldPanel("view_all_programs_link"), FieldPanel("more_programs"), ], heading="Programs"), - MultiFieldPanel([ - FieldPanel('bottom_banner_text'), - FieldPanel('bottom_banner_url'), - FieldPanel('bottom_banner_url_text'), - ]) ] diff --git a/app/programs/templates/programs/individual_program_page.html b/app/programs/templates/programs/individual_program_page.html index 8902f0a..469a6a4 100644 --- a/app/programs/templates/programs/individual_program_page.html +++ b/app/programs/templates/programs/individual_program_page.html @@ -24,7 +24,7 @@

- {{ page.stats_title }} + {{ page.get_parent.specific.stats_title }}

{% for stat in page.stats %} @@ -42,7 +42,7 @@

- {{ page.goals_title }} + {{ page.get_parent.specific.goals_title }}


@@ -60,7 +60,7 @@

- {{ page.projects_title }} + {{ page.get_parent.specific.projects_title }}


@@ -75,13 +75,13 @@

- {{ page.partners_title }} + {{ page.get_parent.specific.partners_title }}


- {% include "ui/components/BaseLink.html" with linkurl=page.view_all_partners_link linktext=page.view_all_partners_title %} + {% include "ui/components/BaseLink.html" with linkurl=page.get_parent.specific.view_all_partners_link linktext=page.get_parent.specific.view_all_partners_title %}
@@ -92,11 +92,11 @@

- {{ page.more_programs_title }} + {{ page.get_parent.specific.more_programs_title }}

- {% include "ui/components/BaseLink.html" with linkurl=page.view_all_programs_link linktext=page.view_all_programs_title %} + {% include "ui/components/BaseLink.html" with linkurl=page.get_parent.specific.view_all_programs_link linktext=page.get_parent.specific.view_all_programs_title %}
@@ -106,5 +106,5 @@

- {% include "ui/components/FooterBannerWithTextAndLink.html" with text=page.bottom_banner_text buttontext=page.bottom_banner_url_text url=page.bottom_banner_url %} + {% include "ui/components/FooterBannerWithTextAndLink.html" with text=page.get_parent.specific.bottom_banner_text buttontext=page.get_parent.specific.bottom_banner_url_text url=page.get_parent.specific.bottom_banner_url %} {% endblock %} diff --git a/app/projects/migrations/0015_remove_individualprojectpage_partners_and_more.py b/app/projects/migrations/0015_remove_individualprojectpage_partners_and_more.py new file mode 100644 index 0000000..2c0e8f5 --- /dev/null +++ b/app/projects/migrations/0015_remove_individualprojectpage_partners_and_more.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.7 on 2024-06-03 21:40 + +from django.db import migrations +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0002_alter_partner_partner_logo_alter_partner_partner_url'), + ('projects', '0014_alter_individualprojectpage_description'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualprojectpage', + name='partners', + ), + migrations.AddField( + model_name='individualprojectpage', + name='partners_list', + field=modelcluster.fields.ParentalManyToManyField(blank=True, to='core.partner'), + ), + ] diff --git a/app/projects/migrations/0016_individualprojectpage_project_contributors.py b/app/projects/migrations/0016_individualprojectpage_project_contributors.py new file mode 100644 index 0000000..ea8aa0e --- /dev/null +++ b/app/projects/migrations/0016_individualprojectpage_project_contributors.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-06-04 16:57 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0015_remove_individualprojectpage_partners_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='individualprojectpage', + name='project_contributors', + field=wagtail.fields.StreamField([('project', wagtail.blocks.PageChooserBlock(page_type=['members.IndividualMemberPage']))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/projects/migrations/0017_alter_individualprojectpage_project_contributors.py b/app/projects/migrations/0017_alter_individualprojectpage_project_contributors.py new file mode 100644 index 0000000..7abd609 --- /dev/null +++ b/app/projects/migrations/0017_alter_individualprojectpage_project_contributors.py @@ -0,0 +1,20 @@ +# Generated by Django 4.2.7 on 2024-06-04 17:21 + +from django.db import migrations +import wagtail.blocks +import wagtail.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0016_individualprojectpage_project_contributors'), + ] + + operations = [ + migrations.AlterField( + model_name='individualprojectpage', + name='project_contributors', + field=wagtail.fields.StreamField([('contributor', wagtail.blocks.PageChooserBlock(page_type=['members.IndividualMemberPage']))], blank=True, null=True, use_json_field=True), + ), + ] diff --git a/app/projects/migrations/0018_projectownerpage.py b/app/projects/migrations/0018_projectownerpage.py new file mode 100644 index 0000000..00330cc --- /dev/null +++ b/app/projects/migrations/0018_projectownerpage.py @@ -0,0 +1,41 @@ +# Generated by Django 4.2.7 on 2024-06-04 22:36 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0089_log_entry_data_json_null_to_object'), + ('projects', '0017_alter_individualprojectpage_project_contributors'), + ] + + operations = [ + migrations.CreateModel( + name='ProjectOwnerPage', + 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')), + ('impact_areas_title', models.CharField(default='Impact Areas')), + ('region_hub_title', models.CharField(default='Region Hub')), + ('duration_title', models.CharField(default='Duration')), + ('partners_title', models.CharField(default='Partners')), + ('tools_title', models.CharField(default='Tools')), + ('contact_title', models.CharField(default='Contact')), + ('related_news_title', models.CharField(default='Related News')), + ('view_all_news_text', models.CharField(default='View all News')), + ('related_events_title', models.CharField(default='Related Events')), + ('view_all_events_text', models.CharField(default='View all Events')), + ('red_box_title', models.CharField(default='Chat with Our Community')), + ('red_box_link_text', models.CharField(default='Get connected now')), + ('red_box_link_url', models.URLField(blank=True, null=True)), + ('black_box_title', models.CharField(default='Our Work')), + ('black_box_link_text', models.CharField(default='View Our Work')), + ('black_box_link_url', models.URLField(blank=True, null=True)), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/app/projects/migrations/0019_projectownerpage_view_all_events_url_and_more.py b/app/projects/migrations/0019_projectownerpage_view_all_events_url_and_more.py new file mode 100644 index 0000000..5072356 --- /dev/null +++ b/app/projects/migrations/0019_projectownerpage_view_all_events_url_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.7 on 2024-06-04 22:43 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0018_projectownerpage'), + ] + + operations = [ + migrations.AddField( + model_name='projectownerpage', + name='view_all_events_url', + field=models.URLField(blank=True), + ), + migrations.AddField( + model_name='projectownerpage', + name='view_all_news_url', + field=models.URLField(blank=True), + ), + ] diff --git a/app/projects/migrations/0020_remove_individualprojectpage_black_box_link_text_and_more.py b/app/projects/migrations/0020_remove_individualprojectpage_black_box_link_text_and_more.py new file mode 100644 index 0000000..f8cfd4f --- /dev/null +++ b/app/projects/migrations/0020_remove_individualprojectpage_black_box_link_text_and_more.py @@ -0,0 +1,77 @@ +# Generated by Django 4.2.7 on 2024-06-04 22:45 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('projects', '0019_projectownerpage_view_all_events_url_and_more'), + ] + + operations = [ + migrations.RemoveField( + model_name='individualprojectpage', + name='black_box_link_text', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='black_box_link_url', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='black_box_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='contact_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='duration_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='impact_areas_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='partners_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='red_box_link_text', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='red_box_link_url', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='red_box_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='region_hub_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='related_events_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='related_news_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='tools_title', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='view_all_events_text', + ), + migrations.RemoveField( + model_name='individualprojectpage', + name='view_all_news_text', + ), + ] diff --git a/app/projects/models.py b/app/projects/models.py index 183da20..8631672 100644 --- a/app/projects/models.py +++ b/app/projects/models.py @@ -1,12 +1,74 @@ +from django import forms from django.db import models from wagtail.models import Page from wagtail.fields import RichTextField, StreamField from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PageChooserPanel from wagtail.blocks import CharBlock, StreamBlock, StructBlock, URLBlock, RichTextBlock, PageChooserBlock +from modelcluster.fields import ParentalKey, ParentalManyToManyField +class ProjectOwnerPage(Page): + max_count = 1 + + impact_areas_title = models.CharField(default="Impact Areas") + region_hub_title = models.CharField(default="Region Hub") + duration_title = models.CharField(default="Duration") + partners_title = models.CharField(default="Partners") + tools_title = models.CharField(default="Tools") + contact_title = models.CharField(default="Contact") + + related_news_title = models.CharField(default="Related News") + view_all_news_text = models.CharField(default="View all News") + view_all_news_url = models.URLField(blank=True) + related_events_title = models.CharField(default="Related Events") + view_all_events_text = models.CharField(default="View all Events") + view_all_events_url = models.URLField(blank=True) + + red_box_title = models.CharField(default="Chat with Our Community") + red_box_link_text = models.CharField(default="Get connected now") + red_box_link_url = models.URLField(null=True, blank=True) + black_box_title = models.CharField(default="Our Work") + black_box_link_text = models.CharField(default="View Our Work") + black_box_link_url = models.URLField(null=True, blank=True) + + content_panels = Page.content_panels + [ + MultiFieldPanel([ + FieldPanel('impact_areas_title'), + FieldPanel('region_hub_title'), + FieldPanel('duration_title'), + FieldPanel('partners_title'), + FieldPanel('tools_title'), + FieldPanel('contact_title'), + MultiFieldPanel([ + FieldPanel('related_news_title'), + FieldPanel('view_all_news_text'), + FieldPanel('view_all_news_url'), + FieldPanel('related_events_title'), + FieldPanel('view_all_events_text'), + FieldPanel('view_all_events_url'), + ], heading="Related Pages"), + ], heading="Sidebar"), + 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="Footer"), + ] + + +""" +This page should only be created as a child of a ProjectOwnerPage! +Its template depends on fields from the ProjectOwnerPage in order +to create one unifying place where unchanging fields may be modified. +""" class IndividualProjectPage(Page): + parent_page_type = [ + 'projects.ProjectOwnerPage' + ] # > HEADER owner_program = models.ForeignKey( 'wagtailcore.Page', @@ -39,10 +101,8 @@ class IndividualProjectPage(Page): call_to_action_link_url = models.URLField(null=True, blank=True) # > SIDE BAR - impact_areas_title = models.CharField(default="Impact Areas") impact_area_list = StreamField([('impact_area', PageChooserBlock(page_type="impact_areas.IndividualImpactAreaPage"))], use_json_field=True, null=True, blank=True) - region_hub_title = models.CharField(default="Region Hub") owner_region_hub = models.ForeignKey( 'wagtailcore.Page', null=True, @@ -51,35 +111,19 @@ class IndividualProjectPage(Page): related_name='+' ) - duration_title = models.CharField(default="Duration") duration = models.CharField(default="Ongoing", blank=True) - partners_title = models.CharField(default="Partners") - partners = RichTextField(null=True, blank=True) # Will need to reference partners when they are added + partners_list = ParentalManyToManyField('core.Partner', blank=True) - tools_title = models.CharField(default="Tools") tools = RichTextField(null=True, blank=True) # Will need to reference tools when they are added - contact_title = models.CharField(default="Contact") contact = RichTextField(null=True, blank=True) - # Question: are related news/events chosen for the article, or are they based off something? - related_news_title = models.CharField(default="Related News") - view_all_news_text = models.CharField(default="View all News") related_news = StreamField([ ('news_page', PageChooserBlock(page_type="news.IndividualNewsPage")) ], use_json_field=True, null=True, blank=True) - related_events_title = models.CharField(default="Related Events") - view_all_events_text = models.CharField(default="View all Events") - - # > BOTTOM AREA - red_box_title = models.CharField(default="Chat with Our Community") - red_box_link_text = models.CharField(default="Get connected now") - red_box_link_url = models.URLField(null=True, blank=True) - black_box_title = models.CharField(default="Our Work") - black_box_link_text = models.CharField(default="View Our Work") - black_box_link_url = models.URLField(null=True, blank=True) + project_contributors = StreamField([('contributor', PageChooserBlock(page_type="members.IndividualMemberPage"))], use_json_field=True, null=True, blank=True) content_panels = Page.content_panels + [ MultiFieldPanel([ @@ -98,32 +142,17 @@ class IndividualProjectPage(Page): ], heading="Call to Action"), ], heading="Body"), MultiFieldPanel([ - FieldPanel('impact_areas_title'), FieldPanel('impact_area_list'), - FieldPanel('region_hub_title'), PageChooserPanel('owner_region_hub', 'mapping_hubs.IndividualMappingHubPage'), - FieldPanel('duration_title'), FieldPanel('duration'), - FieldPanel('partners_title'), - FieldPanel('partners'), - FieldPanel('tools_title'), + FieldPanel('partners_list', widget=forms.CheckboxSelectMultiple), FieldPanel('tools'), - FieldPanel('contact_title'), FieldPanel('contact'), MultiFieldPanel([ - FieldPanel('related_news_title'), - FieldPanel('view_all_news_text'), FieldPanel('related_news'), - FieldPanel('related_events_title'), - FieldPanel('view_all_events_text'), ], heading="Related Pages"), ], heading="Sidebar"), 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="Bottom"), + FieldPanel('project_contributors'), + ], heading="Extras") ] \ No newline at end of file diff --git a/app/projects/templates/projects/individual_project_page.html b/app/projects/templates/projects/individual_project_page.html index 0bcc47c..85ff86f 100644 --- a/app/projects/templates/projects/individual_project_page.html +++ b/app/projects/templates/projects/individual_project_page.html @@ -14,7 +14,6 @@
- {% comment %} BODY {% endcomment %}
@@ -31,52 +30,62 @@ {% comment %} NOTE TO SELF: the "safe" thing is only needed temporarily until everything is put in {% endcomment %}
-

{{page.impact_areas_title}}

-

{{page.impact_areas|safe}}

+

{{page.get_parent.specific.impact_areas_title}}

+ {% for area in page.impact_area_list %} +

{{area.value.title}}

+ {% endfor %}
-

{{page.region_hub_title}}

+

{{page.get_parent.specific.region_hub_title}}

{{page.owner_region_hub.title}}

-

{{page.duration_title}}

+

{{page.get_parent.specific.duration_title}}

{{page.duration}}

-

{{page.partners_title}}

-

{{page.partners|safe}}

+

{{page.get_parent.specific.partners_title}}

+ {% for partner in page.partners_list.all %} +

{{partner.partner_name}}

+ {% endfor %}
-

{{page.tools_title}}

+

{{page.get_parent.specific.tools_title}}

{{page.tools|safe}}

-

{{page.contact_title}}

+

{{page.get_parent.specific.contact_title}}

{{page.contact|safe}}

+ {% comment %} RELATED NEWS {% endcomment %} {% if page.related_news %} -
-

- {{ page.related_news_title }} -

- {% include "ui/components/BaseLink.html" with linkurl="#" linktext=page.view_all_news_text %} -
- {% with allnews=page.related_news %} - {% for news in allnews %} - {% include "ui/components/news/NewsPreviewBlockProjects.html" with news=news.value %} - {% endfor %} - {% endwith %} +
+

+ {{ page.get_parent.specific.related_news_title }} +

+
+ {% include "ui/components/BaseLink.html" with linkurl=page.get_parent.specific.view_all_news_url linktext=page.get_parent.specific.view_all_news_text %} +
+
+ {% with allnews=page.related_news %} + {% for news in allnews %} + {% include "ui/components/news/NewsPreviewBlockProjects.html" with news=news.value %} + {% endfor %} + {% endwith %} +
-
{% endif %} + {% comment %} RELATED EVENTS {% endcomment %}

- {{ page.related_events_title }} + {{ page.get_parent.specific.related_events_title }}

- {% include "ui/components/BaseLink.html" with linkurl="#" linktext=page.view_all_events_text %} +
+ {% include "ui/components/BaseLink.html" with linkurl=page.get_parent.specific.view_all_events_url linktext=page.get_parent.specific.view_all_events_text %} +
@@ -84,10 +93,10 @@

{% comment %} BOTTOM AREA {% endcomment %}
- {% 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/DogearRed.html" with title=page.get_parent.specific.red_box_title linktext=page.get_parent.specific.red_box_link_text linkurl=page.get_parent.specific.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 %} + {% include "ui/components/dogear_boxes/DogearBlack.html" with title=page.get_parent.specific.black_box_title linktext=page.get_parent.specific.black_box_link_text linkurl=page.get_parent.specific.black_box_link_url %}

diff --git a/app/ui/templates/ui/components/news/NewsPreviewCarousel.html b/app/ui/templates/ui/components/news/NewsPreviewCarousel.html new file mode 100644 index 0000000..70da95e --- /dev/null +++ b/app/ui/templates/ui/components/news/NewsPreviewCarousel.html @@ -0,0 +1,61 @@ +{% load wagtailimages_tags %} +
+
+ {% if title %} +
+

+ {{title}} +

+
+ {% endif %} + +
+ +
+ {% for article in news %} +
+ {% if article.value %} + {% include "ui/components/news/NewsPreviewBlockNews.html" with news=article.value %} + {% else %} + {% include "ui/components/news/NewsPreviewBlockNews.html" with news=article %} + {% endif %} +
+ {% endfor %} +
+ +
+
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-180" %} +
+
+
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" %} +
+
+
+
\ No newline at end of file diff --git a/app/ui/templates/ui/components/partners/PartnerViewBlock.html b/app/ui/templates/ui/components/partners/PartnerViewBlock.html index 3a59874..ea655b6 100644 --- a/app/ui/templates/ui/components/partners/PartnerViewBlock.html +++ b/app/ui/templates/ui/components/partners/PartnerViewBlock.html @@ -17,9 +17,12 @@
{% for partner in partners %} -
{% image partner.partner_logo original class="max-h-16 max-w-24 h-auto w-auto" %}
diff --git a/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html b/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html index d4f6d9c..a9fca4d 100644 --- a/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html +++ b/app/ui/templates/ui/components/programs/ProgramCarouselBlock.html @@ -15,9 +15,11 @@
{% for program in programs %} -
{% include "ui/components/programs/ProgramPreviewBlockBase.html" with program=program.value %}
diff --git a/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html b/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html index b9a801a..222ffed 100644 --- a/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html +++ b/app/ui/templates/ui/components/projects/ProjectPreviewBlockNews.html @@ -31,9 +31,9 @@
{% for area in project.impact_area_list %} - -

{{ area.value.title }}{% if not forloop.last %},{% endif %}

-
+

+ {{ area.value.title }}{% if not forloop.last %},{% endif %} +

{% endfor %}
\ No newline at end of file diff --git a/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html b/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html new file mode 100644 index 0000000..05ac3cd --- /dev/null +++ b/app/ui/templates/ui/components/projects/ProjectPreviewCarousel.html @@ -0,0 +1,61 @@ +{% load wagtailimages_tags %} +
+
+ {% if title %} +
+

+ {{title}} +

+
+ {% endif %} + +
+ +
+ {% for project in projects %} +
+ {% if project.value %} + {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project.value %} + {% else %} + {% include "ui/components/projects/ProjectPreviewBlockNews.html" with project=project %} + {% endif %} +
+ {% endfor %} +
+ +
+
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" with class="rotate-180" %} +
+
+
+
+ {% include "ui/components/icon_svgs/LinkCaret.html" %} +
+
+
+
\ No newline at end of file diff --git a/hot_osm/locale/en/LC_MESSAGES/django.po b/hot_osm/locale/en/LC_MESSAGES/django.po index 2d6b726..2e28bdc 100644 --- a/hot_osm/locale/en/LC_MESSAGES/django.po +++ b/hot_osm/locale/en/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-23 19:32+0000\n" +"POT-Creation-Date: 2024-06-03 23:08+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/hot_osm/locale/es/LC_MESSAGES/django.po b/hot_osm/locale/es/LC_MESSAGES/django.po index 46bf7f9..b37f0f5 100644 --- a/hot_osm/locale/es/LC_MESSAGES/django.po +++ b/hot_osm/locale/es/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-23 19:32+0000\n" +"POT-Creation-Date: 2024-06-03 23:08+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/hot_osm/locale/fr/LC_MESSAGES/django.po b/hot_osm/locale/fr/LC_MESSAGES/django.po index 6715543..bd8581f 100644 --- a/hot_osm/locale/fr/LC_MESSAGES/django.po +++ b/hot_osm/locale/fr/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-05-23 19:32+0000\n" +"POT-Creation-Date: 2024-06-03 23:08+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/hot_osm/settings/base.py b/hot_osm/settings/base.py index 911dcec..076eac0 100644 --- a/hot_osm/settings/base.py +++ b/hot_osm/settings/base.py @@ -36,6 +36,7 @@ "app.programs", "app.core", "app.mapping_hubs", + "app.members", "search", "users", "utils", diff --git a/media/images/temp_person.max-165x165.png b/media/images/temp_person.max-165x165.png new file mode 100644 index 0000000000000000000000000000000000000000..645d555e4d4a4620a6efb7b523e9520a0972a01f GIT binary patch literal 4709 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 literal 0 HcmV?d00001 diff --git a/media/original_images/temp_person.png b/media/original_images/temp_person.png new file mode 100644 index 0000000000000000000000000000000000000000..dc259af999517cc5dbc1b503db08a7cacf94d331 GIT binary patch literal 2527 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 literal 0 HcmV?d00001