class AbstractLink(models.Model): """Abstract class for a navigation link.""" class Meta: abstract = True label_en = models.CharField( max_length=255, verbose_name='Label [en]' ) label_fr = models.CharField( max_length=255, verbose_name='Label [fr]', blank=True, ) page = ForeignKeyField( model='wagtailcore.Page', required=True, ) panels = [ PageChooserPanel('page'), FieldRowPanel(children=( FieldPanel('label_en'), FieldPanel('label_fr'), )), ] @cached_property def label(self): """Define localised menu label.""" return get_localised_field_value(self, 'label')
class TestimonialItem(models.Model): """Abstract class for testimonial item.""" class Meta: abstract = True testimonial = ForeignKeyField( model='testimonials.Testimonial', required=True, on_delete=models.CASCADE, )
class Member(index.Indexed, models.Model): """A snippet model for members.""" class Meta: ordering = ['name'] name = models.CharField( max_length=255, unique=True, ) image = WagtailImageField( required=False, help_text='Optional: image for the member' ) constituency = ForeignKeyField( model='taxonomies.Constituency', related_name='member', required=True, help_text='The constituency of the member', ) url = models.URLField( max_length=255, blank=True, help_text='Optional: URL for the member', ) date_joined = models.DateField( help_text='Year that the member joined' ) active = models.BooleanField( blank=True, default=True, help_text='Only active members will be displayed on the site', ) translation_fields = [ 'name', ] panels = [ FieldPanel('name'), ImageChooserPanel('image'), NoEmptyLabelFieldPanel( 'constituency', widget=forms.RadioSelect, classname='non-floated-options', ), FieldPanel('url'), FieldPanel('date_joined'), FieldPanel('active'), ] def __str__(self): """Override magic method to return member name.""" return self.name
class BaseRelatedPageItem(models.Model): """Abstract class for related page.""" class Meta: abstract = True page = ForeignKeyField( model='wagtailcore.Page', required=True, on_delete=models.CASCADE, help_text='Page link for the item' )
class GetInvolvedItem(models.Model): """Abstract class for get involved item.""" class Meta: abstract = True title = models.CharField( max_length=255, help_text='Title for the item', ) image = WagtailImageField(required=False, help_text='Optional: image for the item') description = RichTextField( help_text='Description for the item', features=['link', 'ul'], ) page = ForeignKeyField(model='wagtailcore.Page', required=False, on_delete=models.CASCADE, help_text='Optional: page link for the item') link_label = models.CharField( blank=True, max_length=255, help_text='Optional: link label for the item', )
class HomeFieldsMixin(models.Model): """Abstract mixin class for the home page db fields.""" class Meta: abstract = True use_legacy_template = models.BooleanField( blank=True, default=True, help_text= 'Use the legacy template with hard-coded text for front end display?', ) header_video = models.URLField( max_length=255, blank=True, help_text='Optional: video embed URL for page header', ) activities_description = models.CharField( max_length=255, help_text='Description for the activities statistics section', ) organisations_description = models.CharField( max_length=255, help_text='Description for the organisations statistics section', ) getting_started_title = models.CharField( max_length=255, help_text='Title for the getting started section', ) about_iati_title = models.CharField( max_length=255, help_text='Title for the about IATI section', ) about_iati_description = models.TextField( help_text='Description for the about IATI section', ) about_iati_video = models.URLField( max_length=255, blank=True, help_text='Optional: video embed URL for the about IATI section', ) about_iati_page = ForeignKeyField( model='wagtailcore.Page', required=True, ) about_iati_link_label = models.CharField( max_length=255, help_text='Link label for the about IATI section', ) iati_in_action_title = models.CharField( max_length=255, help_text='Title for the IATI in action section', ) iati_in_action_description = models.TextField( blank=True, help_text='Optional: description for the IATI in action section', ) iati_tools_title = models.CharField( max_length=255, help_text='Title for the IATI tools section', ) iati_tools_description = models.TextField( blank=True, help_text='Optional: description for the IATI tools section', ) latest_news_title = models.CharField( max_length=255, help_text='Title for the latest new section', ) latest_news_link_label = models.CharField( max_length=255, help_text='Label for the view all news button', ) latest_news_tweets_title = models.CharField( max_length=255, help_text='Title for the latest news Twitter section', ) @cached_property def testimonial(self): """Get and return a random testomional or none if there is an error.""" try: return self.testimonial_items.all().order_by( '?').first().testimonial except AttributeError: return None @cached_property def getting_started(self): """Create and return a list of getting started items, added to list if the page is live.""" return [x for x in self.getting_started_items.all() if x.page.live] @cached_property def iati_in_action_featured(self): """Get and return the first IATI in action featured item, if the page is live.""" featured = self.iati_in_action_featured_item.all().first() return featured if featured.page.live else None @cached_property def iati_in_action(self): """Create and return a list of IATI in action items, added to list if the page is live.""" return [x for x in self.iati_in_action_items.all() if x.page.live] @cached_property def tools(self): """Create and return a list of IATI tools items, added to list if the page is live.""" return [ x.page.specific for x in self.iati_tools_items.all() if x.page.live ] @cached_property def news_index(self): """Create and return the first live news index page.""" from news.models import NewsIndexPage return NewsIndexPage.objects.live().first() @cached_property def selected_news(self): """Create and return a list of selected latest news items, added to list if the page is live.""" return [ x.page.specific for x in self.latest_news_items.all() if x.page.live ] @cached_property def news(self): """Return a list of news items using get selected or fallback.""" from news.models import NewsPage return get_selected_or_fallback( selected=self.selected_news, fallback=NewsPage.objects, max_length=3, order='-date', )
class PageNotice(AbstractNotice): """A snippet class for page notices.""" allow_dismiss = models.BooleanField( default=False, blank=True, ) display_location = models.CharField(max_length=255, choices=DISPLAY_LOCATIONS, default=DISPLAY_LOCATIONS[1][0]) page = ForeignKeyField( model='wagtailcore.Page', required=False, on_delete=models.CASCADE, ) panels = [ FieldPanel('content'), FieldPanel( 'notice_type', widget=forms.RadioSelect, classname='non-floated-options', ), MultiFieldPanel( [ FieldPanel('allow_dismiss'), ], heading='Allow dismiss', description= 'Select to allow visitors to dismiss this message for two weeks.'), MultiFieldPanel( [ DisplayTypeFieldPanel(), ], heading='Display location', description= 'Select the location of this notice. If more than one notice is applicable to a page, the most specific wil be displayed.' ), ] def clean(self): """Page field is optional, so raise a validation error when a notice is not global.""" if self.display_location != DISPLAY_LOCATIONS[0][0] and not self.page: raise ValidationError({'page': 'This field is required'}) return super().clean() @classmethod def get_notice(cls, page, request): """Class method for finding most specific notice to match a page.""" # return if no page if not page: return cls.objects.none() # get dismissed uuids dismissed = cls.dismissed(request) # is there a selected page with same id? location = DISPLAY_LOCATIONS[1][0] notices = cls.objects.all().filter( page=page, display_location=location).exclude(uuid__in=dismissed) if notices.first(): return notices.first() # is there a matching selected page and child page? location = DISPLAY_LOCATIONS[2][0] notices = cls.objects.all().filter( page=page, display_location=location).exclude(uuid__in=dismissed) if notices.first(): return notices.first() # get ancestors to check for child pages current_page = Page.objects.filter(id=page.id).first() ancestors = Page.objects.ancestor_of(current_page).values_list( 'id', flat=True) # is the page a child of a selected page and child page option? location = DISPLAY_LOCATIONS[2][0] notices = cls.objects.all().filter( page__id__in=[ancestors], display_location=location).exclude(uuid__in=dismissed) if notices.first(): return notices.first() # is the page a child of selected page children only option? location = DISPLAY_LOCATIONS[3][0] notices = cls.objects.all().filter( page__id__in=[ancestors], display_location=location).exclude(uuid__in=dismissed) if notices.first(): return notices.first() # is there a global notice? location = DISPLAY_LOCATIONS[0][0] notices = cls.objects.all().filter(display_location=location).exclude( uuid__in=dismissed) if notices.last(): return notices.last() # nothing found, return none return cls.objects.none()