From 826feb21442b56e0fff3c5b46bd4d3d99b8bce36 Mon Sep 17 00:00:00 2001
From: Todd Dembrey <todd.dembrey@torchbox.com>
Date: Mon, 15 Jan 2018 17:14:10 +0000
Subject: [PATCH] Add more of the project fields

---
 .../projects/migrations/0001_initial.py       | 22 ++++++-
 opentech/public/projects/models.py            | 59 ++++++++++++++++++-
 .../templates/projects/project_page.html      | 33 +++++++++++
 3 files changed, 109 insertions(+), 5 deletions(-)
 create mode 100644 opentech/public/projects/templates/projects/project_page.html

diff --git a/opentech/public/projects/migrations/0001_initial.py b/opentech/public/projects/migrations/0001_initial.py
index 912214903..eaa4ee3ef 100644
--- a/opentech/public/projects/migrations/0001_initial.py
+++ b/opentech/public/projects/migrations/0001_initial.py
@@ -1,5 +1,5 @@
 # -*- coding: utf-8 -*-
-# Generated by Django 1.11.8 on 2018-01-05 16:18
+# Generated by Django 1.11.8 on 2018-01-15 16:50
 from __future__ import unicode_literals
 
 from django.db import migrations, models
@@ -18,11 +18,19 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('wagtailcore', '0040_page_draft_title'),
         ('images', '0001_initial'),
+        ('wagtailcore', '0040_page_draft_title'),
     ]
 
     operations = [
+        migrations.CreateModel(
+            name='ProjectContactDetails',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('service', models.CharField(choices=[('website', 'Main Website URL'), ('twitter', 'Twitter Handle'), ('github', 'Github Organisation or Project')], max_length=200)),
+                ('value', models.CharField(max_length=255)),
+            ],
+        ),
         migrations.CreateModel(
             name='ProjectIndexPage',
             fields=[
@@ -31,6 +39,7 @@ class Migration(migrations.Migration):
                 ('listing_title', models.CharField(blank=True, help_text='Override the page title used when this page appears in listings', max_length=255)),
                 ('listing_summary', models.CharField(blank=True, help_text="The text summary used when this page appears in listings. It's also used as the description for search engines if the 'Search description' field above is not defined.", max_length=255)),
                 ('introduction', models.TextField(blank=True)),
+                ('header_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
                 ('listing_image', models.ForeignKey(blank=True, help_text='Choose the image you wish to be displayed when this page appears in listings', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
                 ('social_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
             ],
@@ -47,7 +56,9 @@ class Migration(migrations.Migration):
                 ('listing_title', models.CharField(blank=True, help_text='Override the page title used when this page appears in listings', max_length=255)),
                 ('listing_summary', models.CharField(blank=True, help_text="The text summary used when this page appears in listings. It's also used as the description for search engines if the 'Search description' field above is not defined.", max_length=255)),
                 ('introduction', models.TextField(blank=True)),
-                ('body', wagtail.wagtailcore.fields.StreamField((('heading', wagtail.wagtailcore.blocks.CharBlock(classname='full title', icon='title')), ('paragraph', wagtail.wagtailcore.blocks.RichTextBlock()), ('image', wagtail.wagtailcore.blocks.StructBlock((('image', wagtail.wagtailimages.blocks.ImageChooserBlock()), ('caption', wagtail.wagtailcore.blocks.CharBlock(required=False))))), ('quote', wagtail.wagtailcore.blocks.StructBlock((('quote', wagtail.wagtailcore.blocks.CharBlock(classname='title')), ('attribution', wagtail.wagtailcore.blocks.CharBlock(required=False))))), ('embed', wagtail.wagtailembeds.blocks.EmbedBlock()), ('call_to_action', wagtail.wagtailsnippets.blocks.SnippetChooserBlock('utils.CallToActionSnippet', template='blocks/call_to_action_block.html')), ('document', wagtail.wagtailcore.blocks.StructBlock((('document', wagtail.wagtaildocs.blocks.DocumentChooserBlock()), ('title', wagtail.wagtailcore.blocks.CharBlock(required=False)))))))),
+                ('body', wagtail.wagtailcore.fields.StreamField((('heading', wagtail.wagtailcore.blocks.CharBlock(classname='full title', icon='title')), ('paragraph', wagtail.wagtailcore.blocks.RichTextBlock()), ('image', wagtail.wagtailcore.blocks.StructBlock((('image', wagtail.wagtailimages.blocks.ImageChooserBlock()), ('caption', wagtail.wagtailcore.blocks.CharBlock(required=False))))), ('quote', wagtail.wagtailcore.blocks.StructBlock((('quote', wagtail.wagtailcore.blocks.CharBlock(classname='title')), ('attribution', wagtail.wagtailcore.blocks.CharBlock(required=False)), ('job_title', wagtail.wagtailcore.blocks.CharBlock(required=False))))), ('embed', wagtail.wagtailembeds.blocks.EmbedBlock()), ('call_to_action', wagtail.wagtailsnippets.blocks.SnippetChooserBlock('utils.CallToActionSnippet', template='blocks/call_to_action_block.html')), ('document', wagtail.wagtailcore.blocks.StructBlock((('document', wagtail.wagtaildocs.blocks.DocumentChooserBlock()), ('title', wagtail.wagtailcore.blocks.CharBlock(required=False)))))))),
+                ('header_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
+                ('icon', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
                 ('listing_image', models.ForeignKey(blank=True, help_text='Choose the image you wish to be displayed when this page appears in listings', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
                 ('social_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='images.CustomImage')),
             ],
@@ -69,4 +80,9 @@ class Migration(migrations.Migration):
                 'abstract': False,
             },
         ),
+        migrations.AddField(
+            model_name='projectcontactdetails',
+            name='project_page',
+            field=modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='contact_details', to='projects.ProjectPage'),
+        ),
     ]
diff --git a/opentech/public/projects/models.py b/opentech/public/projects/models.py
index 004942abf..3535dc2cb 100644
--- a/opentech/public/projects/models.py
+++ b/opentech/public/projects/models.py
@@ -1,6 +1,8 @@
 from django.db import models
 from django.conf import settings
+from django.core.exceptions import ValidationError
 from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
+from django.core.validators import URLValidator
 
 from modelcluster.fields import ParentalKey
 from wagtail.wagtailadmin.edit_handlers import (
@@ -11,6 +13,7 @@ from wagtail.wagtailadmin.edit_handlers import (
 )
 
 from wagtail.wagtailcore.fields import StreamField
+from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
 from wagtail.wagtailsearch import index
 
 from opentech.public.utils.blocks import StoryBlock
@@ -20,6 +23,51 @@ from opentech.public.utils.models import (
 )
 
 
+class ProjectContactDetails(models.Model):
+    project_page = ParentalKey(
+        'ProjectPage',
+        related_name='contact_details'
+    )
+    site_titles = (
+        ('website', "Main Website URL"),
+        ('twitter', "Twitter Handle"),
+        ('github', "Github Organisation or Project"),
+    )
+    site_urls = (
+        ('website', ''),
+        ('twitter', 'https://twitter.com/'),
+        ('github', 'https://github.com/'),
+    )
+    service = models.CharField(
+        max_length=200,
+        choices=site_titles,
+    )
+    value = models.CharField(max_length=255)
+
+    @property
+    def url(self):
+        return dict(self.site_urls)[self.service] + self.value
+
+    def service_name(self):
+        site_display = {
+            'twitter': '@' + self.value,
+            'github': 'Github',
+            'website': 'Main Website',
+        }
+        return site_display[self.service]
+
+    def clean(self):
+        if self.service == 'twitter' and self.value.startswith('@'):
+            self.username = self.username[1:]
+
+        if self.service == 'website':
+            validate = URLValidator()
+            try:
+                validate(self.value)
+            except ValidationError as e:
+                raise ValidationError({'value': e})
+
+
 class ProjectPageRelatedPage(RelatedPage):
     source_page = ParentalKey('ProjectPage', related_name='related_pages')
 
@@ -33,13 +81,18 @@ class ProjectPage(BasePage):
     parent_page_types = ['ProjectIndexPage']
 
     introduction = models.TextField(blank=True)
+    icon = models.ForeignKey(
+        'images.CustomImage',
+        null=True,
+        blank=True,
+        related_name='+',
+        on_delete=models.SET_NULL
+    )
     body = StreamField(StoryBlock())
 
     # Fields to add:
     # otf_status
     # status
-    # social_accounts
-    # website
     # funding
 
     search_fields = BasePage.search_fields + [
@@ -48,8 +101,10 @@ class ProjectPage(BasePage):
     ]
 
     content_panels = BasePage.content_panels + [
+        ImageChooserPanel('icon'),
         FieldPanel('introduction'),
         StreamFieldPanel('body'),
+        InlinePanel('contact_details', label="Contact Details"),
         InlinePanel('related_pages', label="Related pages"),
     ]
 
diff --git a/opentech/public/projects/templates/projects/project_page.html b/opentech/public/projects/templates/projects/project_page.html
new file mode 100644
index 000000000..a6740d230
--- /dev/null
+++ b/opentech/public/projects/templates/projects/project_page.html
@@ -0,0 +1,33 @@
+{% extends "base.html" %}
+
+{% load wagtailcore_tags wagtailimages_tags %}
+
+
+{% block content %}
+    <div class="intro">
+        <div class="container">
+            {% if page.icon %}
+                {% image page.icon original %}
+            {% endif %}
+            <h1>{{ page.title }}</h1>
+            {% if page.introduction %}
+                <p>{{ page.introduction }}</p>
+            {% endif %}
+
+            {{ page.body }}
+
+            {% with contact_details=page.contact_details.all %}
+                {% if contact_details %}
+                    {% for contact in contact_details %}
+                <p><a href="{{ contact.url }}">
+                    <span class="icon {{ contact.service }}">{{ contact.service_name }}
+                        </a></p>
+                    {% endfor %}
+
+                {% endif %}
+            {% endwith %}
+
+        </div>
+    </div>
+
+{% endblock content %}
-- 
GitLab