Skip to content
Snippets Groups Projects
models.py 4.73 KiB
import json

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 (
    FieldPanel,
    InlinePanel,
    PageChooserPanel,
    StreamFieldPanel,
)

from wagtail.wagtailcore.fields import StreamField
from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
from wagtail.wagtailsearch import index

from opentech.apply.categories.models import Option
from opentech.public.utils.blocks import StoryBlock
from opentech.public.utils.models import (
    BaseFunding,
    BasePage,
    FundingMixin,
    RelatedPage,
)

from .widgets import CategoriesWidget


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')

    panels = [
        PageChooserPanel('page', 'projects.ProjectPage'),
    ]


class ProjectFunding(BaseFunding):
    page = ParentalKey('ProjectPage', related_name='funding')


class ProjectPage(FundingMixin, BasePage):
    STATUSES = (
        ('idea', "Just an Idea. (Pre-alpha)"),
        ('exists', "It Exists! (Alpha/Beta)"),
        ('release', "It's basically done. (Release)"),
        ('production', "People Use it. (Production)"),
    )

    subpage_types = []
    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
    )
    status = models.CharField(choices=STATUSES, max_length=25, default=STATUSES[0][0])
    body = StreamField(StoryBlock())

    categories = models.TextField()

    search_fields = BasePage.search_fields + [
        index.SearchField('introduction'),
        index.SearchField('body'),
    ]

    content_panels = BasePage.content_panels + [
        ImageChooserPanel('icon'),
        FieldPanel('introduction'),
        FieldPanel('status'),
        StreamFieldPanel('body'),
        FieldPanel('categories', widget=CategoriesWidget),
        InlinePanel('contact_details', label="Contact Details"),
        InlinePanel('related_pages', label="Related Projects"),
    ] + FundingMixin.content_panels

    def category_options(self):
        categories = json.loads(self.categories)
        options = [int(id) for options in categories.values() for id in options]
        return Option.objects.select_related().filter(id__in=options).order_by('category')

class ProjectIndexPage(BasePage):
    subpage_types = ['ProjectPage']
    parent_page_types = ['home.Homepage']

    introduction = models.TextField(blank=True)

    content_panels = BasePage.content_panels + [
        FieldPanel('introduction'),
    ]

    search_fields = BasePage.search_fields + [
        index.SearchField('introduction'),
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        subpages = self.get_children().live()
        per_page = settings.DEFAULT_PER_PAGE
        page_number = request.GET.get('page')
        paginator = Paginator(subpages, per_page)

        try:
            subpages = paginator.page(page_number)
        except PageNotAnInteger:
            subpages = paginator.page(1)
        except EmptyPage:
            subpages = paginator.page(paginator.num_pages)

        context['subpages'] = subpages

        return context