diff --git a/opentech/apply/funds/migrations/0038_recreate_objects_that_exist.py b/opentech/apply/funds/migrations/0038_recreate_objects_that_exist.py index 87b53bb1421cd03a9e175f339a893699b6ead64d..e6567c8b53d170d8f39211feec611a51332f4ee7 100644 --- a/opentech/apply/funds/migrations/0038_recreate_objects_that_exist.py +++ b/opentech/apply/funds/migrations/0038_recreate_objects_that_exist.py @@ -20,22 +20,17 @@ def recreate_objects(apps, schema_editor): model = apps.get_model('funds', model_name) new_model = apps.get_model('funds', new_model_name) for obj in new_model.objects.all(): + field_values = {} + for field in obj._meta.fields: + if field.name not in ['page_ptr']: + field_values[field.name] = getattr(obj, field.name) + kwargs = { f'{new_model_name.lower()}_ptr': obj, - 'title': obj.title, 'draft_title': obj.draft_title, - 'slug': obj.slug, 'content_type': content_type, - 'path': obj.path, - 'depth': obj.depth, - 'numchild': obj.numchild, - 'url_path': obj.url_path, } - try: - kwargs.update(lead=obj.lead) - except: - pass - + field_values.update(**kwargs) new_obj = model(**kwargs) new_obj.save() diff --git a/opentech/apply/funds/models/applications.py b/opentech/apply/funds/models/applications.py index b466fb8c7d930d81d033a8c89c3b08b6a496ba82..ffccab07721daae95a51c00cd87f30f666b43473 100644 --- a/opentech/apply/funds/models/applications.py +++ b/opentech/apply/funds/models/applications.py @@ -42,7 +42,7 @@ class ApplicationBase(EmailForm, WorkflowStreamForm): # type: ignore def detail(self): # The location to find out more information - return self.fund_public.first() + return self.application_public.first() @property def open_round(self): diff --git a/opentech/public/funds/migrations/0007_add_rfp_models_for_public.py b/opentech/public/funds/migrations/0007_add_rfp_models_for_public.py new file mode 100644 index 0000000000000000000000000000000000000000..a5a89979d5f2818d08cf58f9da777dd0732a85ba --- /dev/null +++ b/opentech/public/funds/migrations/0007_add_rfp_models_for_public.py @@ -0,0 +1,65 @@ +# Generated by Django 2.0.2 on 2018-08-03 09:31 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields +import opentech.public.funds.blocks +import wagtail.core.blocks +import wagtail.core.fields +import wagtail.documents.blocks +import wagtail.embeds.blocks +import wagtail.images.blocks +import wagtail.snippets.blocks + + +class Migration(migrations.Migration): + + dependencies = [ + ('images', '0001_initial'), + ('wagtailcore', '0040_page_draft_title'), + ('public_funds', '0006_fundindex_introduction'), + ] + + operations = [ + migrations.RenameModel( + old_name='FundPageRelatedPage', + new_name='BaseApplicationRelatedPage', + ), + migrations.RenameModel( + old_name='FundPage', + new_name='BaseApplicationPage', + ), + + migrations.RenameField( + model_name='baseapplicationpage', + old_name='fund_type', + new_name='application_type', + ), + migrations.AlterField( + model_name='baseapplicationpage', + name='application_type', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='application_public', to='wagtailcore.Page'), + ), + + migrations.CreateModel( + name='FundPage', + fields=[ + ('baseapplicationpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='public_funds.BaseApplicationPage')), + ], + options={ + 'abstract': False, + }, + bases=('public_funds.baseapplicationpage',), + ), + migrations.CreateModel( + name='RFPPage', + fields=[ + ('baseapplicationpage_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='public_funds.BaseApplicationPage')), + ], + options={ + 'abstract': False, + }, + bases=('public_funds.baseapplicationpage',), + ), + + ] diff --git a/opentech/public/funds/migrations/0008_recreate_pages.py b/opentech/public/funds/migrations/0008_recreate_pages.py new file mode 100644 index 0000000000000000000000000000000000000000..5536b4b06fea3c1868624dbe1243c2cdc6795c55 --- /dev/null +++ b/opentech/public/funds/migrations/0008_recreate_pages.py @@ -0,0 +1,45 @@ +# Generated by Django 2.0.2 on 2018-08-03 09:37 + +from django.db import migrations + + +def recreate_objects(apps, schema_editor): + # We removed the old definition of these objects, need to create + # a new object with a pointer back to that object, the underlying + # data structure was unaffected + ContentType = apps.get_model('contenttypes.ContentType') + + + for model_name, new_model_name in [ + ('FundPage', 'BaseApplicationPage'), + ]: + content_type, _ = ContentType.objects.get_or_create(model=model_name.lower(), app_label='public_funds') + + model = apps.get_model('public_funds', model_name) + new_model = apps.get_model('public_funds', new_model_name) + for obj in new_model.objects.all(): + field_values = {} + for field in obj._meta.fields: + if field.name not in ['page_ptr']: + field_values[field.name] = getattr(obj, field.name) + + kwargs = { + f'{new_model_name.lower()}_ptr': obj, + 'draft_title': obj.draft_title, + 'content_type': content_type, + } + field_values.update(**kwargs) + new_obj = model(**field_values) + new_obj.save() + + + +class Migration(migrations.Migration): + + dependencies = [ + ('public_funds', '0007_add_rfp_models_for_public'), + ] + + operations = [ + migrations.RunPython(recreate_objects, migrations.RunPython.noop), + ] diff --git a/opentech/public/funds/models.py b/opentech/public/funds/models.py index 6e578e4d81d30ed04454d5c9de1ecea43b48e55b..1f0da502a4b3ba2493dc98a498b33645f011116a 100644 --- a/opentech/public/funds/models.py +++ b/opentech/public/funds/models.py @@ -23,38 +23,55 @@ from opentech.public.utils.models import ( from .blocks import FundBlock, LabBlock -class FundPageRelatedPage(RelatedPage): - source_page = ParentalKey('FundPage', related_name='related_pages') +class BaseApplicationRelatedPage(RelatedPage): + source_page = ParentalKey('BaseApplicationPage', related_name='related_pages') -class FundPage(BasePage): +class BaseApplicationPage(BasePage): subpage_types = [] - parent_page_types = ['FundIndex'] + parent_page_types = [] + + application_type_model = '' introduction = models.TextField(blank=True) - fund_type = models.ForeignKey( + application_type = models.ForeignKey( 'wagtailcore.Page', blank=True, null=True, on_delete=models.SET_NULL, - related_name='fund_public', + related_name='application_public', ) body = StreamField(FundBlock()) content_panels = BasePage.content_panels + [ FieldPanel('introduction'), - PageChooserPanel('fund_type', 'funds.FundType'), StreamFieldPanel('body'), InlinePanel('related_pages', label="Related pages"), ] + def get_template(self, request, *args, **kwargs): + # Make sure all children use the shared template + return 'public_funds/fund_page.html' + @property def is_open(self): - return bool(self.fund_type.specific.open_round) + return self.application_type and bool(self.application_type.specific.open_round) @property def deadline(self): - return self.fund_type.specific.next_deadline() + return self.application_type and self.application_type.specific.next_deadline() + + +class FundPage(BaseApplicationPage): + parent_page_types = ['FundIndex'] + content_panels = BaseApplicationPage.content_panels[:] + content_panels.insert(-2, PageChooserPanel('application_type', 'funds.FundType')) + + +class RFPPage(BaseApplicationPage): + parent_page_types = ['LabPage'] + content_panels = BaseApplicationPage.content_panels[:] + content_panels.insert(-2, PageChooserPanel('application_type', 'funds.RequestForPartners')) class FundIndex(BasePage): @@ -90,7 +107,7 @@ class LabPageRelatedPage(RelatedPage): class LabPage(BasePage): - subpage_types = [] + subpage_types = ['RFPPage'] parent_page_types = ['LabIndex'] introduction = models.TextField(blank=True) @@ -126,6 +143,11 @@ class LabPage(BasePage): InlinePanel('related_pages', label="Related pages"), ] + def get_context(self, request): + context = super().get_context(request) + context['rfps'] = self.get_children().live().public() + return context + @property def is_open(self): return bool(self.lab_type.specific.open_round) diff --git a/opentech/public/funds/templates/public_funds/fund_page.html b/opentech/public/funds/templates/public_funds/fund_page.html index 2256f520bd803db37bf98d1bb8186a194bf40bb0..5487fa051274e628b655fa7d6edcd686bf9ecb67 100644 --- a/opentech/public/funds/templates/public_funds/fund_page.html +++ b/opentech/public/funds/templates/public_funds/fund_page.html @@ -5,7 +5,7 @@ {% load wagtailcore_tags wagtailimages_tags navigation_tags static %} {% block content %} - {% include "public_funds/includes/fund_apply_cta.html" with page=page apply_page=page.fund_type %} + {% include "public_funds/includes/fund_apply_cta.html" with page=page apply_page=page.application_type %} <div class="wrapper"> <section class="section section--main"> @@ -18,6 +18,6 @@ {% include_block page.body %} </section> </div> - {% include "public_funds/includes/fund_apply_cta.html" with page=page apply_page=page.fund_type %} + {% include "public_funds/includes/fund_apply_cta.html" with page=page apply_page=page.application_type %} {% include "includes/relatedcontent.html" with related_pages=page.related_pages.all %} {% endblock %} diff --git a/opentech/public/funds/templates/public_funds/lab_page.html b/opentech/public/funds/templates/public_funds/lab_page.html index 5effaa6c292fbae14cdfda0923d5ecb22557563f..caaa7ec073969805c90107a30649e68d2d1538b2 100644 --- a/opentech/public/funds/templates/public_funds/lab_page.html +++ b/opentech/public/funds/templates/public_funds/lab_page.html @@ -23,5 +23,5 @@ </section> </div> {% include "public_funds/includes/lab_apply_cta.html" %} - {% include "includes/relatedcontent.html" with related_pages=page.related_pages.all %} + {% include "includes/relatedcontent.html" with related_pages=rfps title="Related Requests"%} {% endblock %} diff --git a/opentech/public/home/migrations/0010_add_rfp_to_homepage.py b/opentech/public/home/migrations/0010_add_rfp_to_homepage.py new file mode 100644 index 0000000000000000000000000000000000000000..55e83b1bd290e6cdfbb2f336f3fb2b1d8f4012cf --- /dev/null +++ b/opentech/public/home/migrations/0010_add_rfp_to_homepage.py @@ -0,0 +1,48 @@ +# Generated by Django 2.0.2 on 2018-08-03 10:44 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0040_page_draft_title'), + ('home', '0009_django2_update'), + ] + + operations = [ + migrations.CreateModel( + name='PromotedRFPs', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), + ('page', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailcore.Page')), + ], + options={ + 'ordering': ['sort_order'], + 'abstract': False, + }, + ), + migrations.AddField( + model_name='homepage', + name='rfps_intro', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='homepage', + name='rfps_title', + field=models.CharField(default='Requests For Partners', max_length=255), + preserve_default=False, + ), + migrations.AddField( + model_name='promotedrfps', + name='source_page', + field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='promoted_rfps', to='home.HomePage'), + ), + migrations.AlterUniqueTogether( + name='promotedrfps', + unique_together={('page',)}, + ), + ] diff --git a/opentech/public/home/models.py b/opentech/public/home/models.py index 5918dd877c92418cd132950e7b2341234bfb7750..22e452eebbab95efe48922c799c91122a696a69b 100644 --- a/opentech/public/home/models.py +++ b/opentech/public/home/models.py @@ -9,7 +9,7 @@ from wagtail.search import index from opentech.public.utils.models import BasePage, RelatedPage -from opentech.public.funds.models import FundPage, LabPage +from opentech.public.funds.models import FundPage, LabPage, RFPPage from .blocks import OurWorkBlock @@ -42,6 +42,20 @@ class PromotedLabs(RelatedPage): ] +class PromotedRFPs(RelatedPage): + source_page = ParentalKey( + 'home.HomePage', + related_name='promoted_rfps' + ) + + class Meta(RelatedPage.Meta): + unique_together = ('page',) + + panels = [ + PageChooserPanel('page', 'public_funds.RFPPage'), + ] + + class HomePage(BasePage): # Only allow creating HomePages at the root level parent_page_types = ['wagtailcore.Page'] @@ -69,6 +83,9 @@ class HomePage(BasePage): labs_link = models.ForeignKey('wagtailcore.Page', related_name='+', on_delete=models.PROTECT) labs_link_text = models.CharField(max_length=255) + rfps_title = models.CharField(max_length=255) + rfps_intro = models.TextField(blank=True) + search_fields = BasePage.search_fields + [ index.SearchField('strapline'), ] @@ -99,6 +116,11 @@ class HomePage(BasePage): PageChooserPanel('labs_link'), FieldPanel('labs_link_text'), ], heading='Labs'), + MultiFieldPanel([ + FieldPanel('rfps_title'), + FieldPanel('rfps_intro'), + InlinePanel('promoted_rfps', label='Promoted RFPs', max_num=NUM_RELATED), + ], heading='Labs'), ] def get_related(self, page_type, base_list): @@ -125,4 +147,5 @@ class HomePage(BasePage): context = super().get_context(*args, **kwargs) context['lab_list'] = self.get_related(LabPage, self.promoted_labs) context['fund_list'] = self.get_related(FundPage, self.promoted_funds) + context['rfps_list'] = self.get_related(RFPPage, self.promoted_rfps) return context diff --git a/opentech/public/home/templates/home/home_page.html b/opentech/public/home/templates/home/home_page.html index 2a62505432eaa7d2b71092f49fc040e4783c801c..1b66674fdb85860b3672e7e00fae02eb029dc349 100644 --- a/opentech/public/home/templates/home/home_page.html +++ b/opentech/public/home/templates/home/home_page.html @@ -101,4 +101,6 @@ {% include "home/includes/list_block.html" with bg_color="light-grey" arrow_color="blue" card_modifier="card--lab" title=page.labs_title intro=page.labs_intro link=page.labs_link link_text=page.labs_link_text listing=lab_list %} + {% include "home/includes/list_block.html" with bg_color="dark" arrow_color="white" title=page.rfps_title intro=page.rfps_intro listing=rfps_list %} + {% endblock %} diff --git a/opentech/public/home/templates/home/includes/list_block.html b/opentech/public/home/templates/home/includes/list_block.html index e4feeb2840bb57228ef01a4c630c9b023c1827ad..2ba03c9ce9f1c45b9152c9ca2b246bda2505db46 100644 --- a/opentech/public/home/templates/home/includes/list_block.html +++ b/opentech/public/home/templates/home/includes/list_block.html @@ -6,12 +6,14 @@ <h2>{{ title }}</h2> <p>{{ intro }}</p> </div> - <div class="show-tablet"> - <a class="link link--arrow-pixels-{{ arrow_color }}" href="{% pageurl link %}"> - {{ link_text }} - <svg><use xlink:href="#arrow-head-pixels--solid"></use></svg> - </a> - </div> + {% if link_text and link %} + <div class="show-tablet"> + <a class="link link--arrow-pixels-{{ arrow_color }}" href="{% pageurl link %}"> + {{ link_text }} + <svg><use xlink:href="#arrow-head-pixels--solid"></use></svg> + </a> + </div> + {% endif %} </section> <section class="grid grid--max-three"> @@ -36,13 +38,15 @@ </a> {% endfor %} </section> - <div class="wrapper wrapper--center show-mobile"> - <h5 class="heading heading--contains-link"> - <a class="link link--arrow-pixels-{{ arrow_color }}" href="{% pageurl link %}"> - {{ link_text }} - <svg><use xlink:href="#arrow-head-pixels--solid"></use></svg> - </a> - </h5> - </div> + {% if link_text and link %} + <div class="wrapper wrapper--center show-mobile"> + <h5 class="heading heading--contains-link"> + <a class="link link--arrow-pixels-{{ arrow_color }}" href="{% pageurl link %}"> + {{ link_text }} + <svg><use xlink:href="#arrow-head-pixels--solid"></use></svg> + </a> + </h5> + </div> + {% endif %} </div> </div> diff --git a/opentech/templates/includes/relatedcontent.html b/opentech/templates/includes/relatedcontent.html index 668c2e9338783c2a992d555b5a0933ff4f51bffb..3e57941488965acfc317039713c3d6e72e0a8db7 100644 --- a/opentech/templates/includes/relatedcontent.html +++ b/opentech/templates/includes/relatedcontent.html @@ -3,7 +3,7 @@ {% if related_documents or related_pages %} <div class="wrapper wrapper--breakout wrapper--dark-bg wrapper--inner-space-xl"> <div class="wrapper wrapper--medium"> - <h2>You might also like...</h2> + <h2>{{ title|default:"You might also like..."}}</h2> <section class="grid grid--max-three"> {% for related_document in related_documents %} {% with document=related_document.document %} @@ -26,26 +26,10 @@ {# a related object links to the original page (related.source_page) and a related one (related.page) #} {% if related.page.live %} {% with specific_related_page=related.page.specific %} - <a class="card" href="{% pageurl specific_related_page %}"> - {% if specific_related_page.deadline %} - <h6 class="card__subheading"> - <svg class="icon icon--calendar apply-bar__icon"><use xlink:href="#calendar"></use></svg> - Next deadline: - <span>{{ specific_related_page.deadline|date:"M j, Y" }}</span> - </h6> - {% endif %} - {% if specific_related_page.listing_image %} - {% image specific_related_page.listing_image fill-450x300 %} - {% endif %} - <h4> - {{ specific_related_page.listing_title|default:specific_related_page.title }} - </h4> - {% if specific_related_page.listing_summary or specific_related_page.introduction %} - <p class="card__teaser">{{ specific_related_page.listing_summary|default:specific_related_page.introduction|truncatechars_html:130 }}</p> - {% endif %} - <svg class="icon icon--card-pixels"><use xlink:href="#arrow-head-pixels--transparent"></use></svg> - </a> + {% include "includes/relatedcontent_card.html" with page=specific_related_page %} {% endwith %} + {% else %} + {% include "includes/relatedcontent_card.html" with page=related %} {% endif %} {% endfor %} </section> diff --git a/opentech/templates/includes/relatedcontent_card.html b/opentech/templates/includes/relatedcontent_card.html new file mode 100644 index 0000000000000000000000000000000000000000..b60ecb4473e722b5ff0759748fdcf6d58dffc3ba --- /dev/null +++ b/opentech/templates/includes/relatedcontent_card.html @@ -0,0 +1,25 @@ +{% load wagtailcore_tags wagtailimages_tags %} + +{% with page=page.specific %} +<a class="card" href="{% pageurl page %}"> + <h6 class="card__subheading"> + {% if page.deadline %} + <svg class="icon icon--calendar apply-bar__icon"><use xlink:href="#calendar"></use></svg> + Next deadline: + <span>{{ page.deadline|date:"M j, Y" }}</span> + {% else %} + Closed + {% endif %} + </h6> + {% if page.listing_image %} + {% image page.listing_image fill-450x300 %} + {% endif %} + <h4> + {{ page.listing_title|default:page.title }} + </h4> + {% if page.listing_summary or page.introduction %} + <p class="card__teaser">{{ page.listing_summary|default:page.introduction|truncatechars_html:130 }}</p> + {% endif %} + <svg class="icon icon--card-pixels"><use xlink:href="#arrow-head-pixels--transparent"></use></svg> +</a> +{% endwith %}