eviltnan/freeturn

View on GitHub
home/models/pages.py

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
from datetime import timedelta

from django.db import models
from django.db.models import Count
from django.utils import timezone
from modelcluster.fields import ParentalManyToManyField, ParentalKey
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, MultiFieldPanel, FieldRowPanel
from wagtail.contrib.forms.edit_handlers import FormSubmissionsPanel
from wagtail.contrib.forms.models import AbstractFormField, AbstractEmailForm
from wagtail.core.fields import RichTextField
from wagtail.core.models import Page
from wagtail.documents import get_document_model_string
from wagtail.documents.edit_handlers import DocumentChooserPanel
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.search import index
from wagtailautocomplete.edit_handlers import AutocompletePanel

from home.forms import RecaptchaForm
from home.models.snippets import Technology


class HomePage(Page):
    background = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    claim = models.CharField(max_length=300,
                             help_text='Claim text placed under the name',
                             default='Freelance python developer')
    services = models.CharField(max_length=500,
                                help_text='Services you want to highlight',
                                default='Python, Django, Wagtail')
    picture = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        help_text='My picture'
    )
    max_count = 1
    subpage_types = [
        'home.PortfolioPage',
        'home.TechnologiesPage',
        'home.ContactPage'
    ]

    earliest_available = models.DateField(null=True, blank=True, default=timezone.now)

    stackoverflow_profile = models.URLField(null=True, blank=True)
    github_profile = models.URLField(null=True, blank=True)
    linkedin_profile = models.URLField(null=True, blank=True)

    content_panels = Page.content_panels + [
        FieldPanel('claim'),
        FieldPanel('services'),
        FieldPanel('earliest_available'),
        ImageChooserPanel('picture'),
        ImageChooserPanel('background'),
        FieldPanel('stackoverflow_profile'),
        FieldPanel('github_profile'),
        FieldPanel('linkedin_profile'),
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        context['forms'] = ContactPage.objects.filter(show_on_home=True).live()
        current_project = ProjectPage.objects.live().filter(
            start_date__lt=timezone.now()
        ).order_by('-start_date').first()
        context['current_project'] = current_project

        last_project = ProjectPage.objects.live().order_by('-start_date').first()
        context['earliest_available'] = self.earliest_available or last_project.start_date + timedelta(
            days=31 * (last_project.duration or 1)
        )
        return context


class PortfolioPage(Page):
    background = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    max_count = 1
    subpage_types = [
        'home.ProjectPage',
    ]

    content_panels = Page.content_panels + [
        ImageChooserPanel('background'),
    ]

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        technology = request.GET.get('technology')
        context['projects'] = ProjectPage.objects.child_of(self).live()
        if technology:
            context['projects'] = context['projects'].filter(technologies__name__in=[technology.lower()])
            context['technology'] = Technology.objects.filter(name=technology).first()
        context['projects'] = context['projects'].order_by('-start_date')
        return context


class ProjectPage(Page):
    logo = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    summary = models.CharField(max_length=511,
                               help_text='Short description to show on tiles and lists')
    description = RichTextField(help_text='Long description to show on the detail page')

    start_date = models.DateField(null=True, blank=True, db_index=True)
    duration = models.IntegerField(help_text='Duration in months, null=till now',
                                   null=True, blank=True)

    position = models.CharField(max_length=100,
                                default='Backend developer')

    search_fields = Page.search_fields + [
        index.SearchField('summary'),
        index.RelatedFields('technologies', [
            index.SearchField('name', partial_match=True, boost=10),
        ]),
        index.FilterField('start_date'),
    ]

    technologies = ParentalManyToManyField(
        'Technology',
        related_name='projects',
        blank=True
    )
    project_url = models.URLField(null=True, blank=True)  # url is a part of the parent model

    reference_letter = models.ForeignKey(
        get_document_model_string(),
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+',
        help_text='Reference letter for this project'
    )
    responsibilities = ParentalManyToManyField(
        'Responsibility',
        related_name='projects',
        blank=True
    )
    content_panels = Page.content_panels + [
        ImageChooserPanel('logo'),
        FieldPanel('summary'),
        FieldPanel('description'),
        FieldPanel('project_url'),
        FieldPanel('start_date'),
        FieldPanel('duration'),
        FieldPanel('position'),
        AutocompletePanel('technologies', target_model=Technology),
        FieldPanel('responsibilities'),
        DocumentChooserPanel('reference_letter'),
    ]
    subpage_types = []

    class Meta:
        ordering = ('-start_date',)


class TechnologiesPage(Page):
    background = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )

    content_panels = Page.content_panels + [
        ImageChooserPanel('background'),
    ]
    subpage_types = []
    max_count = 1

    def get_context(self, request, *args, **kwargs):
        context = super().get_context(request, *args, **kwargs)
        context['technologies'] = Technology.objects.annotate(
            projects_count=Count('projects')
        ).filter(projects_count__gt=0).order_by('-projects_count')
        context['portfolio'] = PortfolioPage.objects.last()
        return context


class FormField(AbstractFormField):
    page = ParentalKey('ContactPage', on_delete=models.CASCADE, related_name='form_fields')


class ContactPage(RecaptchaForm):
    background = models.ForeignKey(
        'wagtailimages.Image',
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='+'
    )
    intro = RichTextField(blank=True)
    thank_you_text = RichTextField(blank=True)
    show_on_home = models.BooleanField(default=False,
                                       help_text='Show link to this form on home page?')
    content_panels = AbstractEmailForm.content_panels + [
        FormSubmissionsPanel(),
        FieldPanel('intro', classname='full'),
        InlinePanel('form_fields', label='Form fields'),
        FieldPanel('thank_you_text', classname='full'),
        MultiFieldPanel([
            FieldRowPanel([
                FieldPanel('from_address', classname='col6'),
                FieldPanel('to_address', classname='col6'),
            ]),
            FieldPanel('subject'),
        ], 'Email'),
    ]
    settings_panels = AbstractEmailForm.settings_panels + [
        FieldPanel('show_on_home')
    ]