Completed
Pull Request — master (#155)
by
unknown
41s
created

SidebarAgenda.__str__()   A

Complexity

Conditions 1

Size

Total Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 2
rs 10
cc 1
1
"""
2
Models that extend mezzanine Pages and add JD specific data.
3
"""
4
5
from datetime import datetime
6
import os
7
from string import punctuation
8
import logging
9
logger = logging.getLogger(__name__)
10
11
from PIL import Image
12
13
from django.contrib.contenttypes.fields import GenericForeignKey
14
from django.contrib.contenttypes.models import ContentType
15
from django.core.exceptions import ValidationError
16
from django.db import models
17
from django.db.models import Q
18
from django.utils.translation import ugettext_lazy as _
19
from django.utils.encoding import force_text
20
from django.utils import timezone
21
from django.conf import settings
22
23
from mezzanine.blog.models import BlogCategory, BlogPost
24
from mezzanine.core.fields import FileField
25
from mezzanine.core.fields import RichTextField
26
from mezzanine.core.models import Orderable, RichText, SiteRelated
27
from mezzanine.core.models import CONTENT_STATUS_PUBLISHED
28
from mezzanine.pages.models import Page
29
30
31
class FooterLinks(SiteRelated):
32
    title = models.CharField(max_length=100, blank=True, default="")
33
34
    def __str__(self):
35
        return self.title
36
37
38
class FooterLink(SiteRelated, Orderable):
39
    title = models.CharField(max_length=100, blank=True, default="")
40
    url = models.CharField(max_length=500, blank=True, default="")
41
    footer_links = models.ForeignKey(FooterLinks, blank=True, null=True)
42
43
    def __str__(self):
44
        return self.title
45
46
47
class FooterInfo(SiteRelated):
48
    title = models.CharField(max_length=100, blank=True, default="")
49
    content = RichTextField()
50
51
    def __str__(self):
52
        return self.title
53
54
55
class Footer(SiteRelated):
56
    links_left = models.OneToOneField(FooterLinks, auto_created=True, related_name="links_left")
57
    links_middle = models.OneToOneField(FooterLinks, auto_created=True, related_name="links_right")
58
    info_right = models.OneToOneField(FooterInfo, auto_created=True)
59
60
    class Meta:
61
        verbose_name = "Footer"
62
        verbose_name_plural = "Footer"
63
64
65
def validate_header_image(imagepath):
66
    """ Validates the resolution of a header image. """
67
    absolute_imagepath = os.path.join(settings.MEDIA_ROOT, str(imagepath))
68
    im = Image.open(absolute_imagepath)
69
    width, height = im.size
70
    aspect_ratio = width/height
71
    if aspect_ratio < 2.0:
72
        raise ValidationError('Image aspect ratio should be at least 2 (for example 2000x1000px). The selected image is %i x %i. Please resize the image.' % (width, height))
73
    if width < 1000:
74
        raise ValidationError('Image resolution is too low. It should be at least 1000px wide. The selected image is %i x %i. Please find a larger image.' % (width, height))
75
76
77
class PageHeaderImage(SiteRelated):
78
    """ Page header image. """
79
    name = models.CharField(max_length=1000, blank=True, null=False, default="")
80
    page = models.ForeignKey(Page, blank=False, null=True)
81
    image = FileField(max_length=200, format="Image", validators=[validate_header_image])
82
83
84
class PageItem(SiteRelated):
85
    page = models.ForeignKey(Page, blank=False, null=True)
86
    visible = models.BooleanField(default=False)
87
88
    class Meta:
89
        abstract = True
90
91
92
class SidebarAgenda(PageItem):
93
    SITE = 'SI'
94
    ALL = 'AL'
95
    MAIN = 'MA'
96
    MAIN_AND_SITE = 'SM'
97
98
    EVENT_CHOICES = (
99
        (SITE, 'Site'),
100
        (ALL, 'All'),
101
        (MAIN, 'Main site'),
102
        (MAIN_AND_SITE, 'Main and site'),
103
    )
104
105
    type = models.CharField(max_length=2, choices=EVENT_CHOICES)
106
107
    class Meta:
108
        verbose_name = "Sidebar Agenda Item"
109
110
    def get_name(self):
111
        if self.type == self.MAIN_AND_SITE:
112
            return 'Events for current and main site'
113
        elif self.type == self.ALL:
114
            return 'Events for all sites'
115
        elif self.type == self.SITE:
116
            return 'Events for current site'
117
        elif self.type == self.MAIN:
118
            return 'Events for main site'
119
        assert False
120
121
    def __str__(self):
122
        return self.get_name()
123
124
125
class SidebarTwitter(PageItem):
126
127
    class Meta:
128
        verbose_name = "Sidebar Twitter Item"
129
130
131
class SidebarSocial(PageItem):
132
133
    class Meta:
134
        verbose_name = "Sidebar Social Media Item"
135
136
137
class SidebarRichText(PageItem):
138
    content = RichTextField()
139
140
    class Meta:
141
        verbose_name = "Sidebar RichText Item"
142
143
144
class SidebarLink(PageItem, Orderable):
145
    title = models.CharField(max_length=100, blank=True, default="")
146
    url = models.CharField(max_length=500, blank=True, default="")
147
148
149
class ActionBanner(PageItem):
150
    title = models.CharField(max_length=500, blank=True, default="")
151
    content = RichTextField()
152
    image = FileField(max_length=300, format="Image")
153
    button_title = models.CharField(max_length=500, blank=True, default="")
154
    button_url = models.CharField(max_length=500, blank=True, default="")
155
156
157
def validate_vision_image(imagepath):
158
    """ Validates the aspect ratio of a vision image. """
159
    absolute_imagepath = os.path.join(settings.MEDIA_ROOT, str(imagepath))
160
    im = Image.open(absolute_imagepath)
161
    width, height = im.size
162
    aspect_ratio = width/height
163
    if abs(aspect_ratio-1.5) > 0.1:
164
        raise ValidationError('Image aspect ratio should be 1.5 (for example 300x200px or 600x400px), selected image is %i x %i. Please resize the image.' % (width, height))
165
166
167
class VisionPage(Page, RichText):
168
    """
169
    """
170
    image = FileField(max_length=300, format="Image", blank=True, default="", validators=[validate_vision_image])
171
172
    class Meta:
173
        verbose_name = 'VisionPage'
174
175
176
class VisionsPage(Page, RichText):
177
    """
178
    """
179
    vision_pages = models.ManyToManyField(VisionPage, blank=True)
180
181
    class Meta:
182
        verbose_name = 'VisionsPage'
183
184
185
class HomePage(Page, RichText):
186
    """
187
    Page model for the site homepage.
188
    Only works properly when url points to the homepage '/' as url.
189
    """
190
    header_title = models.CharField(max_length=300, blank=True, default="")
191
    header_subtitle = models.CharField(max_length=500, blank=True, default="")
192
    news_category = models.ForeignKey(BlogCategory, null=True, blank=True)
193
    vision_pages = models.ManyToManyField(VisionPage, blank=True)
194
195
    @property
196
    def blog_posts(self):
197
        return get_public_blogposts(self.news_category)
198
199
    class Meta:
200
        verbose_name = 'Homepage'
201
202
203
204
class BlogCategoryPage(Page, RichText):
205
    """
206
    Model for a page that displays a list of posts in a single blog category.
207
    """
208
209
    blog_category = models.ForeignKey(BlogCategory, null=False, blank=False)
210
    show_excerpt = models.BooleanField(default=False, null=False, blank=False,
211
                                       help_text='Show only the first paragraph of a blog post.')
212
213
    class Meta:
214
        verbose_name = "Blog category page"
215
        verbose_name_plural = "Blog category pages"
216
217
218
def get_public_blogposts(blog_category):
219
    """ Returns all blogposts for a given category that are published and not expired. """
220
    blog_posts = BlogPost.objects.all().filter(categories=blog_category).filter(status=CONTENT_STATUS_PUBLISHED)
221
    return blog_posts.filter(publish_date__lte=timezone.now()).filter(Q(expiry_date__isnull=True)
222
                                                                      | Q(expiry_date__gte=timezone.now()))
223