class ActivityLogPage(SublandingFilterablePage):
    template = 'activity-log/index.html'
    filterable_categories = ('Blog', 'Newsroom', 'Research Report')
    filterable_children_only = False
    filterable_per_page_limit = 100

    objects = PageManager()
class LearnPage(AbstractFilterPage):
    content = StreamField([
        ('full_width_text', organisms.FullWidthText()),
        ('info_unit_group', organisms.InfoUnitGroup()),
        ('expandable_group', organisms.ExpandableGroup()),
        ('contact_expandable_group', organisms.ContactExpandableGroup()),
        ('expandable', organisms.Expandable()),
        ('well', organisms.Well()),
        ('call_to_action', molecules.CallToAction()),
        ('email_signup', organisms.EmailSignUp()),
        ('video_player', organisms.VideoPlayer()),
        ('audio_player', organisms.AudioPlayer()),
        ('table_block', organisms.AtomicTableBlock(
            table_options={'renderer': 'html'}
        )),
        ('feedback', v1_blocks.Feedback()),
    ], blank=True)

    edit_handler = AbstractFilterPage.generate_edit_handler(
        content_panel=StreamFieldPanel('content')
    )
    template = 'learn-page/index.html'

    objects = PageManager()

    search_fields = AbstractFilterPage.search_fields + [
        index.SearchField('content')
    ]
class SublandingFilterablePage(FilterableListMixin, CFGOVPage):
    header = StreamField([
        ('hero', molecules.Hero()),
    ], blank=True)
    content = StreamField(SublandingFilterableContent)

    # General content tab
    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        StreamFieldPanel('content'),
    ]

    # Tab handler interface
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='General Content'),
        ObjectList(CFGOVPage.sidefoot_panels, heading='Sidebar'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    template = 'sublanding-page/index.html'

    objects = PageManager()

    search_fields = CFGOVPage.search_fields + [
        index.SearchField('content'),
        index.SearchField('header')
    ]
Exemple #4
0
class LandingPage(CFGOVPage):
    header = StreamField([
        ('hero', molecules.Hero()),
        ('text_introduction', molecules.TextIntroduction()),
    ],
                         blank=True)

    content = StreamField([
        ('info_unit_group', organisms.InfoUnitGroup()),
        ('well', organisms.Well()),
        ('feedback', v1_blocks.Feedback()),
    ],
                          blank=True)

    # General content tab
    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        StreamFieldPanel('content'),
    ]

    # Tab handler interface
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='General Content'),
        ObjectList(CFGOVPage.sidefoot_panels, heading='Sidebar'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    template = 'landing-page/index.html'

    objects = PageManager()

    search_fields = CFGOVPage.search_fields + [
        index.SearchField('content'),
        index.SearchField('header')
    ]
Exemple #5
0
class BlogPage(AbstractFilterPage):
    content = StreamField([
        ('full_width_text', organisms.FullWidthText()),
        ('info_unit_group', organisms.InfoUnitGroup()),
        ('expandable', organisms.Expandable()),
        ('well', organisms.Well()),
        ('video_player', organisms.VideoPlayer()),
        ('email_signup', organisms.EmailSignUp()),
        ('feedback', v1_blocks.Feedback()),
    ])
    edit_handler = AbstractFilterPage.generate_edit_handler(
        content_panel=StreamFieldPanel('content'))
    template = 'blog/blog_page.html'

    objects = PageManager()
    search_fields = AbstractFilterPage.search_fields + [
        index.SearchField('content')
    ]

    def get_context(self, request, *args, **kwargs):
        context = super(BlogPage, self).get_context(request, *args, **kwargs)

        context['rss_feed'] = get_appropriate_rss_feed_url_for_page(
            self, request=request)

        return context
Exemple #6
0
class HmdaHistoricDataPage(LearnPage):
    """
    A model for the new HMDA Historic Data page that displays links to S3 files
    containing HMDA data.
    """

    objects = PageManager()
    template = 'hmda/hmda-explorer.html'

    def get_context(self, request, *args, **kwargs):
        context = super(HmdaHistoricDataPage,
                        self).get_context(request, *args, **kwargs)

        form_data = self.form_data(request.GET)
        plain_language_records = \
            dict(HMDA_RECORDS_OPTIONS).get(form_data.get('records'))

        context.update({
            'form': HmdaFilterableForm(form_data),
            'title': self.get_title(form_data.get('geo')),
            'subtitle': plain_language_records,
            'files': self.get_data_files(**form_data),
        })

        return context

    def form_data(self, params):
        geo = self.value_or_default(HMDA_GEO_OPTIONS, params.get('geo'))
        labels = self.value_or_default(HMDA_FIELD_DESC_OPTIONS,
                                       params.get('field_descriptions'))
        record_set = self.value_or_default(HMDA_RECORDS_OPTIONS,
                                           params.get('records'))

        data = {
            'geo': geo,
            'field_descriptions': labels,
            'records': record_set
        }
        return data

    def get_title(self, geo):
        if geo == 'nationwide':
            return 'Showing nationwide records'
        else:
            location_name = dict(HMDA_GEO_OPTIONS).get(geo, "State")
            return 'Showing records for {}'.format(location_name)

    def value_or_default(self, options, user_input):
        options_dict = dict(options)
        if user_input in options_dict:
            return user_input
        else:
            return options[0][0]

    def get_data_files(self, geo, field_descriptions, records):
        files = LOAN_FILE_METADATA[geo][field_descriptions][records]

        # sort files in reverse chronological order
        return sorted(files.items(), key=lambda t: t[0], reverse=True)
Exemple #7
0
class ApplicationBase(EmailForm, WorkflowStreamForm):  # type: ignore
    is_createable = False

    # Adds validation around forms & workflows. Isn't on Workflow class due to not displaying workflow field on Round
    base_form_class = WorkflowFormAdminForm

    reviewers = ParentalManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='%(class)s_reviewers',
        limit_choices_to=LIMIT_TO_REVIEWERS,
        blank=True,
    )

    slack_channel = models.CharField(blank=True, max_length=128, help_text=_('The slack #channel for notifications.'))

    objects = PageManager.from_queryset(ApplicationBaseManager)()

    parent_page_types = ['apply_home.ApplyHomePage']

    def get_template(self, request, *args, **kwargs):
        # We want to force children to use our base template
        # template attribute is ignored by children
        return 'funds/application_base.html'

    def detail(self):
        # The location to find out more information
        return self.application_public.first()

    @cached_property
    def open_round(self):
        return RoundBase.objects.child_of(self).open().first()

    def next_deadline(self):
        try:
            return self.open_round.end_date
        except AttributeError:
            # There isn't an open round
            return None

    def serve(self, request):
        if hasattr(request, 'is_preview') or not self.open_round:
            return super().serve(request)

        # delegate to the open_round to use the latest form instances
        request.show_round = True
        return self.open_round.serve(request)

    content_panels = WorkflowStreamForm.content_panels + [
        FieldPanel('reviewers'),
        FieldPanel('slack_channel'),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        EmailForm.email_tab,
        ObjectList(WorkflowStreamForm.promote_panels, heading='Promote'),
    ])
Exemple #8
0
class HomePage(CFGOVPage):
    card_heading = models.CharField(max_length=40, null=True, blank=True)

    # Tab handler interface
    edit_handler = TabbedInterface([
        ObjectList([
            InlinePanel(
                'carousel_items', min_num=4, max_num=4, label="Carousel Item"),
        ],
                   heading='Carousel'),
        ObjectList([
            InlinePanel('info_units', min_num=6, max_num=6, label="Info Unit"),
        ],
                   heading='Info Units'),
        ObjectList([
            FieldPanel('card_heading'),
            InlinePanel('cards', min_num=3, max_num=3, label="Card"),
        ],
                   heading='Cards'),
        ObjectList(
            # The only general content panel is the page title, which isn't
            # displayed or used except for slug generation in Wagtail. For this
            # reason it lives on the configuration tab so that it doesn't
            # require a tab of its own.
            CFGOVPage.content_panels + CFGOVPage.settings_panels,
            heading='Configuration'),
    ])

    # Sets page to only be createable at the root
    parent_page_types = ['wagtailcore.Page']

    objects = PageManager()

    base_form_class = HomePageForm

    @property
    def page_js(self):
        return super(HomePage, self).page_js + ['home-page.js']

    def get_context(self, request):
        context = super(HomePage, self).get_context(request)

        context.update({
            'carousel_items':
            self.carousel_items.select_related('image'),
            'info_units': [
                info_unit.as_info_unit()
                for info_unit in self.info_units.select_related('image')
            ],
            'card_heading':
            self.card_heading,
            'cards':
            self.cards.all(),
        })

        return context
class EnforcementActionsFilterPage(BrowseFilterablePage):
    template = 'browse-filterable/index.html'
    objects = PageManager()

    @staticmethod
    def get_form_class():
        from .. import forms
        return forms.EnforcementActionsFilterForm

    @staticmethod
    def get_model_class():
        return EnforcementActionPage
class EventArchivePage(BrowseFilterablePage):
    template = 'browse-filterable/index.html'

    objects = PageManager()

    @staticmethod
    def get_model_class():
        return EventPage

    @staticmethod
    def get_form_class():
        from .. import forms
        return forms.EventArchiveFilterForm
class AgendaItemBlock(blocks.StructBlock):
    start_time = blocks.TimeBlock(label="Start", required=False)
    end_time = blocks.TimeBlock(label="End", required=False)
    description = blocks.CharBlock(max_length=100, required=False)
    location = blocks.CharBlock(max_length=100, required=False)
    speakers = blocks.ListBlock(blocks.StructBlock([
        ('name', blocks.CharBlock(required=False)),
        ('url', blocks.URLBlock(required=False)),
    ], icon='user', required=False))

    objects = PageManager()

    class Meta:
        icon = 'date'
Exemple #12
0
class PersonPage(FundingMixin, BasePage):
    subpage_types = []
    parent_page_types = ['PersonIndexPage']

    drupal_id = models.IntegerField(null=True, blank=True, editable=False)

    first_name = models.CharField(max_length=255, blank=True)
    last_name = models.CharField(max_length=255)
    photo = models.ForeignKey(
        'images.CustomImage',
        null=True,
        blank=True,
        related_name='+',
        on_delete=models.SET_NULL
    )
    active = models.BooleanField(default=True)
    job_title = models.CharField(max_length=255, blank=True)
    introduction = models.TextField(blank=True)
    website = models.URLField(blank=True, max_length=255)
    biography = StreamField(StoryBlock(), blank=True)
    email = models.EmailField(blank=True)

    objects = PageManager.from_queryset(PersonQuerySet)()

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

    content_panels = BasePage.content_panels + [
        MultiFieldPanel([
            FieldPanel('first_name'),
            FieldPanel('last_name'),
        ], heading="Name"),
        FieldPanel('active'),
        ImageChooserPanel('photo'),
        FieldPanel('job_title'),
        InlinePanel('social_media_profile', label='Social accounts'),
        FieldPanel('website'),
        MultiFieldPanel([
            FieldPanel('email'),
            InlinePanel('contact_details', label='Other Contact Methods'),
        ], heading='Contact information'),
        InlinePanel('person_types', label='Person types'),
        FieldPanel('introduction'),
        StreamFieldPanel('biography'),
        InlinePanel('funds_reviewed', label='Funds Reviewed'),
    ] + FundingMixin.content_panels
class CampaignPage(CFGOVPage):
    header = StreamField(CampaignHeader, blank=True)
    content = StreamField(CampaignContent, blank=True)

    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        StreamFieldPanel('content')
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    # Sets page to only be createable as the child of the homepage
    parent_page_types = ['v1.HomePage']

    objects = PageManager()
class DocumentDetailPage(AbstractFilterPage):
    content = StreamField([
        ('full_width_text', organisms.FullWidthText()),
        ('expandable', organisms.Expandable()),
        ('expandable_group', organisms.ExpandableGroup()),
        ('notification', molecules.Notification()),
        ('table_block', organisms.AtomicTableBlock(
            table_options={'renderer': 'html'})),
        ('feedback', v1_blocks.Feedback()),
    ], blank=True)
    edit_handler = AbstractFilterPage.generate_edit_handler(
        content_panel=StreamFieldPanel('content')
    )
    template = 'document-detail/index.html'

    objects = PageManager()

    search_fields = AbstractFilterPage.search_fields + [
        index.SearchField('content')
    ]
Exemple #15
0
class BrowseFilterablePage(FilterableListMixin, CFGOVPage):
    header = StreamField([
        ('text_introduction', molecules.TextIntroduction()),
        ('featured_content', organisms.FeaturedContent()),
    ])
    content = StreamField(BrowseFilterableContent)

    secondary_nav_exclude_sibling_pages = models.BooleanField(default=False)

    # General content tab
    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        StreamFieldPanel('content'),
    ]

    sidefoot_panels = CFGOVPage.sidefoot_panels + [
        FieldPanel('secondary_nav_exclude_sibling_pages'),
    ]

    # Tab handler interface
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='General Content'),
        ObjectList(sidefoot_panels, heading='SideFoot'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    template = 'browse-filterable/index.html'

    objects = PageManager()

    search_fields = CFGOVPage.search_fields + [
        index.SearchField('content'),
        index.SearchField('header')
    ]

    @property
    def page_js(self):
        return (
            super(BrowseFilterablePage, self).page_js
            + ['secondary-navigation.js']
        )
class MortgagePerformancePage(BrowsePage):
    """
    A model for data_research pages about mortgage delinquency
    and related data visualizations.
    """

    objects = PageManager()
    template = 'browse-basic/index.html'

    def get_mortgage_meta(self):
        meta_names = ['sampling_dates', 'download_files']
        meta_set = MortgageMetaData.objects.filter(name__in=meta_names)
        meta = {obj.name: obj.json_value for obj in meta_set}
        thru_date = parser.parse(meta['sampling_dates'][-1])
        from_date = parser.parse(meta['sampling_dates'][0])
        meta['thru_month'] = thru_date.strftime("%Y-%m")
        meta['thru_month_formatted'] = thru_date.strftime("%B %Y")
        meta['from_month_formatted'] = from_date.strftime("%B %Y")
        meta['pub_date_formatted'] = meta.get(
            'download_files')[meta['thru_month']]['pub_date']
        download_dates = sorted(meta['download_files'].keys(), reverse=True)
        meta['archive_dates'] = download_dates[1:]
        return meta

    def get_context(self, request, *args, **kwargs):
        context = super(MortgagePerformancePage, self).get_context(
            request, *args, **kwargs)
        context.update(self.get_mortgage_meta())
        if '30-89' in self.url:
            context.update({'delinquency': 'percent_30_60',
                            'time_frame': '30-89'})
        elif '90' in self.url:
            context.update({'delinquency': 'percent_90',
                            'time_frame': '90'})
        return context

    class Media:
        css = ['secondary-navigation.css']
Exemple #17
0
class RoundBase(WorkflowStreamForm, SubmittableStreamForm):  # type: ignore
    is_creatable = False
    submission_class = ApplicationSubmission

    objects = PageManager.from_queryset(RoundBaseManager)()

    subpage_types = []  # type: ignore

    lead = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        limit_choices_to=LIMIT_TO_STAFF,
        related_name='%(class)s_lead',
        on_delete=models.PROTECT,
    )
    reviewers = ParentalManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='%(class)s_reviewer',
        limit_choices_to=LIMIT_TO_REVIEWERS,
        blank=True,
    )
    start_date = models.DateField(default=date.today)
    end_date = models.DateField(
        blank=True,
        null=True,
        default=date.today,
        help_text='When no end date is provided the round will remain open indefinitely.'
    )
    sealed = models.BooleanField(default=False)

    content_panels = SubmittableStreamForm.content_panels + [
        FieldPanel('lead'),
        MultiFieldPanel([
            FieldRowPanel([
                FieldPanel('start_date'),
                FieldPanel('end_date'),
            ]),
        ], heading="Dates"),
        FieldPanel('reviewers'),
        ReadOnlyPanel('get_workflow_name_display', heading="Workflow"),
        # Forms comes from parental key in models/forms.py
        ReadOnlyInlinePanel('forms', help_text="Copied from the fund."),
        ReadOnlyInlinePanel('review_forms', help_text="Copied from the fund."),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(SubmittableStreamForm.promote_panels, heading='Promote'),
    ])

    def get_template(self, request, *args, **kwargs):
        # Make sure all children use the shared template
        return 'funds/round.html'

    def get_landing_page_template(self, request, *args, **kwargs):
        # Make sure all children use the shared template
        return 'funds/round_landing.html'

    @cached_property
    def fund(self):
        return self.get_parent()

    @property
    def is_sealed(self):
        return self.sealed and self.is_open

    @property
    def is_open(self):
        return self.start_date <= date.today() <= self.end_date

    def save(self, *args, **kwargs):
        is_new = not self.id
        if is_new and hasattr(self, 'parent_page'):
            parent_page = self.parent_page[self.__class__][self.title]
            self.workflow_name = parent_page.workflow_name
            self.reviewers = parent_page.reviewers.all()

        super().save(*args, **kwargs)

        if is_new and hasattr(self, 'parent_page'):
            # Would be nice to do this using model clusters as part of the __init__
            self._copy_forms('forms')
            self._copy_forms('review_forms')

    def _copy_forms(self, field):
        for form in getattr(self.get_parent().specific, field).all():
            new_form = self._meta.get_field(field).related_model
            self._copy_form(form, new_form)

    def _copy_form(self, form, new_class):
        # Create a copy of the existing form object
        new_form = form.form
        new_form.id = None
        new_form.name = '{} for {} ({})'.format(new_form.name, self.title, self.get_parent().title)
        new_form.save()
        new_class.objects.create(round=self, form=new_form)

    def get_submit_meta_data(self, **kwargs):
        return super().get_submit_meta_data(
            page=self.get_parent(),
            round=self,
            **kwargs,
        )

    def clean(self):
        super().clean()

        if self.end_date and self.start_date > self.end_date:
            raise ValidationError({
                'end_date': 'End date must come after the start date',
            })

        if self.end_date:
            conflict_query = (
                Q(start_date__range=[self.start_date, self.end_date]) |
                Q(end_date__range=[self.start_date, self.end_date]) |
                Q(start_date__lte=self.start_date, end_date__gte=self.end_date)
            )
        else:
            conflict_query = (
                Q(start_date__lte=self.start_date, end_date__isnull=True) |
                Q(end_date__gte=self.start_date)
            )

        if not self.id and hasattr(self, 'parent_page'):
            # Check if the create hook has added the parent page, we aren't an object yet.
            # Ensures we can access related objects during the clean phase instead of save.
            base_query = RoundBase.objects.child_of(self.parent_page[self.__class__][self.title])
        else:
            # don't need parent page, we are an actual object now.
            base_query = RoundBase.objects.sibling_of(self)

        conflicting_rounds = base_query.filter(
            conflict_query
        ).exclude(id=self.id)

        if conflicting_rounds.exists():
            error_message = mark_safe('Overlaps with the following rounds:<br> {}'.format(
                '<br>'.join([
                    f'<a href="{admin_url(round)}">{round.title}</a>: {round.start_date} - {round.end_date}'
                    for round in conflicting_rounds]
                )
            ))
            error = {
                'start_date': error_message,
            }
            if self.end_date:
                error['end_date'] = error_message

            raise ValidationError(error)

    def serve(self, request):
        if hasattr(request, 'is_preview') or hasattr(request, 'show_round'):
            return super().serve(request)

        # We hide the round as only the open round is used which is displayed through the
        # fund page
        raise Http404()
class EnforcementActionPage(AbstractFilterPage):
    sidebar_header = models.CharField(
        default='Action details',
        max_length=100
    )
    court = models.CharField(default='', max_length=150, blank=True)
    institution_type = models.CharField(max_length=50, choices=[
        ('Nonbank', 'Nonbank'),
        ('Bank', 'Bank')
    ])

    content = StreamField([
        ('full_width_text', organisms.FullWidthText()),
        ('expandable', organisms.Expandable()),
        ('expandable_group', organisms.ExpandableGroup()),
        ('notification', molecules.Notification()),
        ('table_block', organisms.AtomicTableBlock(
            table_options={'renderer': 'html'})),
        ('feedback', v1_blocks.Feedback()),
    ], blank=True)

    content_panels = [
        StreamFieldPanel('header'),
        StreamFieldPanel('content')
    ]

    metadata_panels = [
        MultiFieldPanel([
            FieldPanel('sidebar_header'),
            FieldPanel('court'),
            FieldPanel('institution_type'),
            FieldPanel('date_filed'),
            FieldPanel('tags', 'Tags'),
        ], heading='Basic Metadata'),
        MultiFieldPanel([
            InlinePanel(
                'docket_numbers',
                label="Docket Number",
                min_num=1
            ),
        ], heading='Docket Number'),
        MultiFieldPanel([
            InlinePanel('statuses', label="Enforcement Status", min_num=1),
        ], heading='Enforcement Status'),
        MultiFieldPanel([
            InlinePanel('categories', label="Categories",
                        min_num=1, max_num=2),
        ], heading='Categories'),
    ]

    settings_panels = [
        MultiFieldPanel(CFGOVPage.promote_panels, 'Settings'),
        MultiFieldPanel([
            FieldPanel('preview_title'),
            FieldPanel('preview_subheading'),
            FieldPanel('preview_description'),
            FieldPanel('secondary_link_url'),
            FieldPanel('secondary_link_text'),
            ImageChooserPanel('preview_image'),
        ], heading='Page Preview Fields', classname='collapsible'),
        FieldPanel('authors', 'Authors'),
        MultiFieldPanel([
            FieldPanel('date_published'),
            FieldPanel('comments_close_by'),
        ], 'Relevant Dates', classname='collapsible'),
        MultiFieldPanel(Page.settings_panels, 'Scheduled Publishing'),
        FieldPanel('language', 'Language'),
    ]

    edit_handler = TabbedInterface([
        ObjectList(
            AbstractFilterPage.content_panels + content_panels,
            heading='General Content'
        ),
        ObjectList(metadata_panels, heading='Metadata'),
        ObjectList(CFGOVPage.sidefoot_panels, heading='Sidebar'),
        ObjectList(settings_panels, heading='Configuration')
    ])

    template = 'enforcement-action/index.html'

    objects = PageManager()

    search_fields = AbstractFilterPage.search_fields + [
        index.SearchField('content')
    ]
class NewsroomLandingPage(CategoryFilterableMixin, BrowseFilterablePage):
    template = 'newsroom/index.html'
    filterable_categories = ['Newsroom']

    objects = PageManager()
Exemple #20
0
            data = self.file.read(256)
            if not data:
                break
            hash256.update(data)
        checksum = hash256.hexdigest()

        self.file.seek(original_position)
        return os.path.join(folder_name, checksum[:3], filename)


class CustomPageQuerySet(PageQuerySet):
    def about_spam(self):
        return self.filter(title__contains='spam')


CustomManager = PageManager.from_queryset(CustomPageQuerySet)


class CustomManagerPage(Page):
    objects = CustomManager()


class MyBasePage(Page):
    """
    A base Page model, used to set site-wide defaults and overrides.
    """
    objects = CustomManager()

    class Meta:
        abstract = True
Exemple #21
0
class RegulationsSearchPage(RoutablePageMixin, CFGOVPage):
    """A page for the custom search interface for regulations."""

    objects = PageManager()

    parent_page_types = ['regulations3k.RegulationLandingPage']
    subpage_types = []
    results = {}
    content_panels = CFGOVPage.content_panels
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    def get_template(self, request):
        template = 'regulations3k/search-regulations.html'
        if 'partial' in request.GET:
            template = 'regulations3k/search-regulations-results.html'
        return template

    def regulation_results_page_es7(self, request):
        all_regs = Part.objects.order_by('part_number')
        regs = validate_regs_list(request)
        order = validate_order(request)
        search_query = request.GET.get('q', '').strip()
        payload = {
            'search_query': search_query,
            'results': [],
            'total_results': 0,
            'regs': regs,
            'all_regs': [],
        }
        if not search_query or len(urllib.parse.unquote(search_query)) == 1:
            self.results = payload
            return TemplateResponse(request, self.get_template(request),
                                    self.get_context(request))
        search = SectionParagraphDocument.search().query('match',
                                                         text=search_query)
        search = search.highlight('text',
                                  pre_tags="<strong>",
                                  post_tags="</strong>")
        total_results = search.count()
        all_regs = [{
            'short_name':
            reg.short_name,
            'id':
            reg.part_number,
            'num_results':
            search.filter('term', part=reg.part_number).count(),
            'selected':
            reg.part_number in regs
        } for reg in all_regs]
        payload.update({'all_regs': all_regs, 'total_count': total_results})
        if regs:
            search = search.filter('terms', part=regs)
        if order == 'regulation':
            search = search.sort('part', 'section_order')
        search = search[0:total_results]
        response = search.execute()
        for hit in response[0:total_results]:
            try:
                snippet = Markup("".join(hit.meta.highlight.text[0]))
            except TypeError as e:
                logger.warning(
                    "Query string {} produced a TypeError: {}".format(
                        search_query, e))
                continue
            hit_payload = {
                'id':
                hit.paragraph_id,
                'part':
                hit.part,
                'reg':
                hit.short_name,
                'label':
                hit.title,
                'snippet':
                snippet,
                'url':
                "{}{}/{}/#{}".format(self.parent().url, hit.part,
                                     hit.section_label, hit.paragraph_id),
            }
            payload['results'].append(hit_payload)

        payload.update({'current_count': search.count()})
        self.results = payload
        context = self.get_context(request)
        num_results = validate_num_results(request)
        paginator = Paginator(payload['results'], num_results)
        page_number = validate_page_number(request, paginator)
        paginated_page = paginator.page(page_number)
        context.update({
            'current_count':
            payload['current_count'],
            'total_count':
            payload['total_count'],
            'paginator':
            paginator,
            'current_page':
            page_number,
            'num_results':
            num_results,
            'order':
            order,
            'results':
            paginated_page,
            'show_filters':
            any(reg['selected'] is True for reg in payload['all_regs'])
        })
        return TemplateResponse(request, self.get_template(request), context)

    @route(r'^results/')
    def regulation_results_page(self, request):
        if flag_enabled('ELASTICSEARCH_DSL_REGULATIONS'):
            return self.regulation_results_page_es7(request)
        all_regs = Part.objects.order_by('part_number')
        regs = validate_regs_list(request)
        order = validate_order(request)
        search_query = request.GET.get('q', '').strip()
        payload = {
            'search_query': search_query,
            'results': [],
            'total_results': 0,
            'regs': regs,
            'all_regs': [],
        }
        if not search_query or len(urllib.parse.unquote(search_query)) == 1:
            self.results = payload
            return TemplateResponse(request, self.get_template(request),
                                    self.get_context(request))
        sqs = SearchQuerySet().filter(content=search_query)
        payload.update({
            'all_regs': [{
                'short_name':
                reg.short_name,
                'id':
                reg.part_number,
                'num_results':
                sqs.filter(
                    part=reg.part_number).models(SectionParagraph).count(),
                'selected':
                reg.part_number in regs
            } for reg in all_regs]
        })
        payload.update({
            'total_count':
            sum([reg['num_results'] for reg in payload['all_regs']])
        })
        if len(regs) == 1:
            sqs = sqs.filter(part=regs[0])
        elif regs:
            sqs = sqs.filter(part__in=regs)
        if order == 'regulation':
            sqs = sqs.order_by('part', 'section_order')
        sqs = sqs.highlight(pre_tags=['<strong>'],
                            post_tags=['</strong>']).models(SectionParagraph)
        for hit in sqs:
            try:
                snippet = Markup(" ".join(hit.highlighted))
            except TypeError as e:
                logger.warning(
                    "Query string {} produced a TypeError: {}".format(
                        search_query, e))
                continue

            short_name = all_regs.get(part_number=hit.part).short_name
            hit_payload = {
                'id':
                hit.paragraph_id,
                'part':
                hit.part,
                'reg':
                short_name,
                'label':
                hit.title,
                'snippet':
                snippet,
                'url':
                "{}{}/{}/#{}".format(self.parent().url, hit.part,
                                     hit.section_label, hit.paragraph_id),
            }
            payload['results'].append(hit_payload)

        payload.update({'current_count': sqs.count()})
        self.results = payload
        context = self.get_context(request)
        num_results = validate_num_results(request)
        paginator = Paginator(payload['results'], num_results)
        page_number = validate_page_number(request, paginator)
        paginated_page = paginator.page(page_number)
        context.update({
            'current_count':
            payload['current_count'],
            'total_count':
            payload['total_count'],
            'paginator':
            paginator,
            'current_page':
            page_number,
            'num_results':
            num_results,
            'order':
            order,
            'results':
            paginated_page,
            'show_filters':
            any(reg['selected'] is True for reg in payload['all_regs'])
        })
        return TemplateResponse(request, self.get_template(request), context)
Exemple #22
0
class RegulationPage(RoutablePageMixin, SecondaryNavigationJSMixin, CFGOVPage):
    """A routable page for serving an eregulations page by Section ID."""

    objects = PageManager()
    parent_page_types = ['regulations3k.RegulationLandingPage']
    subpage_types = []

    template = 'regulations3k/browse-regulation.html'

    header = StreamField([
        ('text_introduction', molecules.TextIntroduction()),
    ],
                         blank=True)

    content = StreamField([
        ('info_unit_group', organisms.InfoUnitGroup()),
        ('full_width_text', organisms.FullWidthText()),
    ],
                          null=True,
                          blank=True)

    regulation = models.ForeignKey(Part,
                                   blank=True,
                                   null=True,
                                   on_delete=models.PROTECT,
                                   related_name='page')

    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        StreamFieldPanel('content'),
        FieldPanel('regulation', Part),
    ]

    secondary_nav_exclude_sibling_pages = models.BooleanField(default=False)

    sidefoot_panels = CFGOVPage.sidefoot_panels + [
        FieldPanel('secondary_nav_exclude_sibling_pages'),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='General Content'),
        ObjectList(sidefoot_panels, heading='Sidebar'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    def can_serve_draft_versions(self, request):
        perms = request.user.get_all_permissions()
        if (request.user.is_superuser
                or getattr(request, 'served_by_wagtail_sharing', False)
                or 'regulations3k.change_section' in perms):
            return True
        return False

    def get_versions_query(self, request):
        versions = self.regulation.versions

        if not self.can_serve_draft_versions(request):
            versions = versions.filter(draft=False)

        return versions

    def get_effective_version(self, request, date_str=None):
        """ Get the requested effective version if the user has permission """
        query_filter = {}

        if date_str is None:
            query_filter['effective_date__lte'] = date.today()
        else:
            query_filter['effective_date'] = date_str

        draft_permission = self.can_serve_draft_versions(request)
        if not draft_permission:
            query_filter['draft'] = False

        effective_version = self.regulation.versions.filter(
            **query_filter).order_by('-effective_date').first()

        if effective_version is None:
            raise Http404

        return effective_version

    def get_section_query(self, request=None, effective_version=None):
        """Query set for Sections in this regulation's effective version."""
        if effective_version is None:
            effective_version = self.get_effective_version(request)
        return Section.objects.filter(subpart__version=effective_version)

    def get_context(self, request, *args, **kwargs):
        context = super(RegulationPage,
                        self).get_context(request, *args, **kwargs)
        context.update({
            'regulation':
            self.regulation,
            'current_version':
            self.get_effective_version(request),
            'breadcrumb_items':
            self.get_breadcrumbs(request, *args, **kwargs),
            'search_url':
            (self.get_parent().url + 'search-regulations/results/?regs=' +
             self.regulation.part_number),
            'num_versions':
            self.get_versions_query(request).count(),
        })
        return context

    def get_breadcrumbs(self, request, section=None, **kwargs):
        crumbs = super(RegulationPage, self).get_breadcrumbs(request)

        if section is not None:
            crumbs = crumbs + [
                {
                    'href':
                    self.url + self.reverse_subpage(
                        'index',
                        kwargs={
                            k: v
                            for k, v in kwargs.items() if k == 'date_str'
                        }),
                    'title':
                    str(section.subpart.version.part),
                },
            ]

        return crumbs

    def get_urls_for_version(self, effective_version, section=None):
        base_url = self.get_full_url()
        versions_url = urljoin(base_url, 'versions') + '/'

        if effective_version.live_version:
            # This is the current version
            version_url = base_url
        else:
            # It's a past or future version, URLs have the date str
            date_str = str(effective_version.effective_date)
            version_url = urljoin(base_url, date_str) + '/'
            yield version_url

        if section is not None:
            yield urljoin(version_url, section.label) + '/'
        else:
            sections = self.get_section_query(
                effective_version=effective_version)
            yield version_url
            yield versions_url
            for section in sections.all():
                yield urljoin(version_url, section.label) + '/'

    def render_interp(self, context, raw_contents, **kwargs):
        template = get_template('regulations3k/inline_interps.html')

        # Extract the title from the raw regdown
        section_title_match = re.search(r'#+\s?(?P<section_title>.*)\s',
                                        raw_contents)
        if section_title_match is not None:
            context.update({'section_title': section_title_match.group(1)})
            span = section_title_match.span()
            raw_contents = raw_contents[:span[0]] + raw_contents[span[1]:]

        context.update({'contents': regdown(raw_contents)})
        context.update(kwargs)

        return template.render(context)

    @route(r'^(?:(?P<date_str>[0-9]{4}-[0-9]{2}-[0-9]{2})/)?$', name="index")
    def index_route(self, request, date_str=None):
        request.is_preview = getattr(request, 'is_preview', False)

        effective_version = self.get_effective_version(request,
                                                       date_str=date_str)
        section_query = self.get_section_query(
            effective_version=effective_version)
        sections = list(section_query.all())

        context = self.get_context(request)
        context.update({
            'requested_version':
            effective_version,
            'sections':
            sections,
            'get_secondary_nav_items':
            partial(get_secondary_nav_items,
                    sections=sections,
                    date_str=date_str),
        })

        if date_str is not None:
            context['date_str'] = date_str

        return TemplateResponse(request, self.get_template(request), context)

    @route(r'^versions/(?:(?P<section_label>' + label_re_str + r')/)?$',
           name="versions")
    def versions_page(self, request, section_label=None):
        section_query = self.get_section_query(request=request)
        sections = list(section_query.all())
        context = self.get_context(request, sections=sections)

        versions = [{
            'effective_date':
            v.effective_date,
            'date_str':
            str(v.effective_date),
            'sections':
            self.get_section_query(effective_version=v).all(),
            'draft':
            v.draft
        } for v in self.get_versions_query(request).order_by('-effective_date')
                    ]

        context.update({
            'versions':
            versions,
            'section_label':
            section_label,
            'get_secondary_nav_items':
            partial(get_secondary_nav_items, sections=sections),
        })

        return TemplateResponse(request, self.template, context)

    @route(r'^(?:(?P<date_str>[0-9]{4}-[0-9]{2}-[0-9]{2})/)?'
           r'(?P<section_label>' + label_re_str + r')/$',
           name="section")
    def section_page(self, request, date_str=None, section_label=None):
        """ Render a section of the currently effective regulation """

        effective_version = self.get_effective_version(request,
                                                       date_str=date_str)
        section_query = self.get_section_query(
            effective_version=effective_version)

        next_version = self.get_versions_query(request).filter(
            effective_date__gt=effective_version.effective_date).first()

        kwargs = {}
        if date_str is not None:
            kwargs['date_str'] = date_str

        try:
            section = section_query.get(label=section_label)
        except Section.DoesNotExist:
            return redirect(self.url +
                            self.reverse_subpage("index", kwargs=kwargs))

        sections = list(section_query.all())
        current_index = sections.index(section)
        context = self.get_context(request,
                                   section,
                                   sections=sections,
                                   **kwargs)

        content = regdown(
            section.contents,
            url_resolver=get_url_resolver(self, date_str=date_str),
            contents_resolver=get_contents_resolver(effective_version),
            render_block_reference=partial(self.render_interp, context))

        next_section = get_next_section(sections, current_index)
        previous_section = get_previous_section(sections, current_index)

        context.update({
            'requested_version':
            effective_version,
            'next_version':
            next_version,
            'section':
            section,
            'content':
            content,
            'get_secondary_nav_items':
            partial(get_secondary_nav_items,
                    sections=sections,
                    date_str=date_str),
            'next_section':
            next_section,
            'next_url':
            get_section_url(self, next_section, date_str=date_str),
            'previous_section':
            previous_section,
            'previous_url':
            get_section_url(self, previous_section, date_str=date_str),
        })

        return TemplateResponse(request, self.template, context)
Exemple #23
0
class BrowsePage(CFGOVPage):
    header = StreamField([
        ('text_introduction', molecules.TextIntroduction()),
        ('featured_content', organisms.FeaturedContent()),
    ],
                         blank=True)

    content = StreamField([
        ('full_width_text', organisms.FullWidthText()),
        ('info_unit_group', organisms.InfoUnitGroup()),
        ('expandable_group', organisms.ExpandableGroup()),
        ('expandable', organisms.Expandable()),
        ('well', organisms.Well()),
        ('video_player', organisms.VideoPlayer()),
        ('snippet_list', organisms.ResourceList()),
        ('table_block',
         organisms.AtomicTableBlock(table_options={'renderer': 'html'})),
        ('feedback', v1_blocks.Feedback()),
        ('raw_html_block', blocks.RawHTMLBlock(label='Raw HTML block')),
        ('conference_registration_form', ConferenceRegistrationForm()),
        ('chart_block', organisms.ChartBlock()),
        ('mortgage_chart_block', organisms.MortgageChartBlock()),
        ('mortgage_map_block', organisms.MortgageMapBlock()),
        ('mortgage_downloads_block', MortgageDataDownloads()),
        ('data_snapshot', organisms.DataSnapshot()),
        ('job_listing_table', JobListingTable()),
        ('bureau_structure', organisms.BureauStructure()),
        ('yes_checklist', YESChecklist()),
    ],
                          blank=True)

    secondary_nav_exclude_sibling_pages = models.BooleanField(default=False)

    share_and_print = models.BooleanField(
        default=False,
        help_text="Include share and print buttons above page content.")

    # General content tab
    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        FieldPanel('share_and_print'),
        StreamFieldPanel('content'),
    ]

    sidefoot_panels = CFGOVPage.sidefoot_panels + [
        FieldPanel('secondary_nav_exclude_sibling_pages'),
    ]

    # Tab handler interface
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='General Content'),
        ObjectList(sidefoot_panels, heading='Sidebar'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    template = 'browse-basic/index.html'

    objects = PageManager()

    search_fields = CFGOVPage.search_fields + [
        index.SearchField('content'),
        index.SearchField('header')
    ]

    @property
    def page_js(self):
        return (super(BrowsePage, self).page_js + ['secondary-navigation.js'])

    def get_context(self, request, *args, **kwargs):
        context = super(BrowsePage, self).get_context(request, *args, **kwargs)
        context.update({'get_secondary_nav_items': get_secondary_nav_items})
        return context
Exemple #24
0
class RegulationsSearchPage(RoutablePageMixin, CFGOVPage):
    """A page for the custom search interface for regulations."""

    objects = PageManager()

    parent_page_types = ['regulations3k.RegulationLandingPage']
    subpage_types = []
    results = {}
    content_panels = CFGOVPage.content_panels
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    def get_template(self, request):
        template = 'regulations3k/search-regulations.html'
        if 'partial' in request.GET:
            template = 'regulations3k/search-regulations-results.html'
        return template

    @route(r'^results/')
    def regulation_results_page(self, request):
        all_regs = Part.objects.order_by('part_number')
        regs = validate_regs_list(request)
        order = validate_order(request)

        payload = {
            'search_query': '',
            'results': [],
            'total_results': 0,
            'regs': regs,
            'all_regs': [],
        }

        search_form = SearchForm(request.GET)
        if (not search_form.is_valid() or len(
                urllib.parse.unquote(search_form.cleaned_data['q'])) == 1):
            self.results = payload
            return TemplateResponse(request, self.get_template(request),
                                    self.get_context(request))

        search_query = search_form.cleaned_data['q']
        payload['search_query'] = search_query

        search = SectionParagraphDocument.search().query('match',
                                                         text={
                                                             "query":
                                                             search_query,
                                                             "operator": "AND"
                                                         })
        search = search.highlight('text',
                                  pre_tags="<strong>",
                                  post_tags="</strong>")
        total_results = search.count()
        all_regs = [{
            'short_name':
            reg.short_name,
            'id':
            reg.part_number,
            'num_results':
            search.filter('term', part=reg.part_number).count(),
            'selected':
            reg.part_number in regs
        } for reg in all_regs]
        payload.update({'all_regs': all_regs, 'total_count': total_results})
        if regs:
            search = search.filter('terms', part=regs)
        if order == 'regulation':
            search = search.sort('part', 'section_order')
        search = search[0:total_results]
        response = search.execute()
        for hit in response[0:total_results]:
            try:
                snippet = Markup("".join(hit.meta.highlight.text[0]))
            except TypeError as e:
                logger.warning(
                    "Query string {} produced a TypeError: {}".format(
                        search_query, e))
                continue
            hit_payload = {
                'id':
                hit.paragraph_id,
                'part':
                hit.part,
                'reg':
                hit.short_name,
                'label':
                hit.title,
                'snippet':
                snippet,
                'url':
                "{}{}/{}/#{}".format(self.parent().url, hit.part,
                                     hit.section_label, hit.paragraph_id),
            }
            payload['results'].append(hit_payload)

        payload.update({'current_count': search.count()})
        self.results = payload
        context = self.get_context(request)
        num_results = validate_num_results(request)
        paginator = Paginator(payload['results'], num_results)
        page_number = validate_page_number(request, paginator)
        paginated_page = paginator.page(page_number)
        context.update({
            'current_count':
            payload['current_count'],
            'total_count':
            payload['total_count'],
            'paginator':
            paginator,
            'current_page':
            page_number,
            'num_results':
            num_results,
            'order':
            order,
            'results':
            paginated_page,
            'show_filters':
            any(reg['selected'] is True for reg in payload['all_regs'])
        })
        return TemplateResponse(request, self.get_template(request), context)
class SublandingPage(CFGOVPage):
    portal_topic = models.ForeignKey(
        'v1.PortalTopic',
        blank=True,
        null=True,
        related_name='portal_pages',
        on_delete=models.SET_NULL,
        help_text='Select a topic if this is a MONEY TOPICS portal page.')
    header = StreamField([
        ('hero', molecules.Hero()),
    ], blank=True)
    content = StreamField([
        ('text_introduction', molecules.TextIntroduction()),
        ('notification', molecules.Notification()),
        ('featured_content', organisms.FeaturedContent()),
        ('full_width_text', organisms.FullWidthText()),
        ('info_unit_group', organisms.InfoUnitGroup()),
        ('well', organisms.Well()),
        ('snippet_list', organisms.ResourceList()),
        ('post_preview_snapshot', organisms.PostPreviewSnapshot()),
        ('contact', organisms.MainContactInfo()),
        ('table_block', organisms.AtomicTableBlock(
            table_options={'renderer': 'html'}
        )),
        ('reg_comment', organisms.RegComment()),
        ('feedback', v1_blocks.Feedback()),
    ], blank=True)
    sidebar_breakout = StreamField([
        ('slug', blocks.CharBlock(icon='title')),
        ('heading', blocks.CharBlock(icon='title')),
        ('paragraph', blocks.RichTextBlock(icon='edit')),
        ('breakout_image', blocks.StructBlock([
            ('image', ImageChooserBlock()),
            ('is_round', blocks.BooleanBlock(required=False,
                                             default=True,
                                             label='Round?')),
            ('icon', blocks.CharBlock(help_text='Enter icon class name.')),
            ('heading', blocks.CharBlock(required=False,
                                         label='Introduction Heading')),
            ('body', blocks.TextBlock(required=False,
                                      label='Introduction Body')),
        ], heading='Breakout Image', icon='image')),
        ('related_posts', organisms.RelatedPosts()),
        ('job_listing_list', JobListingList()),
    ], blank=True)

    # General content tab
    content_panels = CFGOVPage.content_panels + [
        StreamFieldPanel('header'),
        StreamFieldPanel('content'),
        FieldPanel('portal_topic'),
    ]

    sidebar_panels = [
        StreamFieldPanel('sidebar_breakout'),
    ] + CFGOVPage.sidefoot_panels

    # Tab handler interface
    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='General Content'),
        ObjectList(sidebar_panels, heading='Sidebar'),
        ObjectList(CFGOVPage.settings_panels, heading='Configuration'),
    ])

    template = 'sublanding-page/index.html'

    objects = PageManager()

    search_fields = CFGOVPage.search_fields + [
        index.SearchField('content'),
        index.SearchField('header')
    ]

    def get_browsefilterable_posts(self, limit):
        filter_pages = [p.specific
                        for p in self.get_appropriate_descendants()
                        if 'FilterablePage' in p.specific_class.__name__
                        and 'archive' not in p.title.lower()]
        posts_list = []
        for page in filter_pages:
            eligible_children = AbstractFilterPage.objects.live().filter(
                CFGOVPage.objects.child_of_q(page)
            )

            form = FilterableListForm(filterable_pages=eligible_children,
                                      wagtail_block=None)
            for post in form.get_page_set():
                posts_list.append(post)
        return sorted(posts_list,
                      key=lambda p: p.date_published,
                      reverse=True)[:limit]
Exemple #26
0
        """Include only projects with the working group flag set"""
        return self.filter(working_group=True)

    def order_by_newest_grant(self):
        """order by grant start date, most recent grants first; secondary
        sort by project title"""
        # NOTE: using annotation to get just the most recent start date
        # to avoid issues with projects appearing multiple times.
        return self.annotate(
            last_start=models.Max("grants__start_date")).order_by(
                "-last_start", "title")


# custom manager for wagtail pages, see:
# https://docs.wagtail.io/en/stable/topics/pages.html#custom-page-managers
ProjectManager = PageManager.from_queryset(ProjectQuerySet)


class ProjectTag(TaggedItemBase):
    """Tags for Project pages."""

    content_object = ParentalKey("projects.Project",
                                 on_delete=models.CASCADE,
                                 related_name="tagged_items")


class Project(BasePage, ClusterableModel):
    """Page type for a CDH sponsored project or working group."""

    short_description = models.CharField(
        max_length=255,
Exemple #27
0
    def recent(self):
        """Find past events, most recent first.  Only includes events
        with end date in the past."""
        now = timezone.now()
        # construct a datetime based on now but with zero hour/minute/second
        today = datetime(now.year,
                         now.month,
                         now.day,
                         tzinfo=timezone.get_default_timezone())
        return self.filter(end_time__lt=today).order_by("-start_time")


# custom manager for wagtail pages, see:
# https://docs.wagtail.io/en/stable/topics/pages.html#custom-page-managers
EventManager = PageManager.from_queryset(EventQuerySet)


class EventTag(TaggedItemBase):
    """Tags for Event pages."""

    content_object = ParentalKey("events.Event",
                                 on_delete=models.CASCADE,
                                 related_name="tagged_items")


class Speaker(models.Model):
    """Relationship between Person and Event."""

    event = ParentalKey("events.Event", related_name="speakers")
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
class NewsroomLandingPage(BrowseFilterablePage):
    template = 'newsroom/index.html'
    filterable_categories = ['Newsroom']
    filterable_children_only = False

    objects = PageManager()
Exemple #29
0
class RoundBase(WorkflowStreamForm, SubmittableStreamForm):  # type: ignore
    is_creatable = False
    submission_class = ApplicationSubmission

    objects = PageManager.from_queryset(RoundBaseManager)()

    subpage_types = []  # type: ignore

    # Adds validation for making start_date required
    base_form_class = RoundBasePageAdminForm

    lead = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        limit_choices_to=LIMIT_TO_STAFF,
        related_name='%(class)s_lead',
        on_delete=models.PROTECT,
    )
    reviewers = ParentalManyToManyField(
        settings.AUTH_USER_MODEL,
        related_name='%(class)s_reviewer',
        limit_choices_to=LIMIT_TO_REVIEWERS,
        blank=True,
    )
    start_date = models.DateField(null=True, blank=True, default=date.today)
    end_date = models.DateField(
        blank=True,
        null=True,
        default=date.today,
        help_text='When no end date is provided the round will remain open indefinitely.'
    )
    sealed = models.BooleanField(default=False)

    content_panels = SubmittableStreamForm.content_panels + [
        FieldPanel('lead'),
        MultiFieldPanel([
            FieldRowPanel([
                FieldPanel('start_date'),
                FieldPanel('end_date'),
            ]),
        ], heading="Dates"),
        FieldPanel('reviewers', widget=forms.SelectMultiple(attrs={'size': '16'})),
        ReadOnlyPanel('get_workflow_name_display', heading="Workflow", help_text="Copied from the fund."),
        # Forms comes from parental key in models/forms.py
        ReadOnlyInlinePanel('forms', help_text="Copied from the fund."),
        ReadOnlyInlinePanel('review_forms', help_text="Copied from the fund."),
    ]

    edit_handler = TabbedInterface([
        ObjectList(content_panels, heading='Content'),
        ObjectList(SubmittableStreamForm.promote_panels, heading='Promote'),
    ])

    def get_template(self, request, *args, **kwargs):
        # Make sure all children use the shared template
        return 'funds/round.html'

    def get_landing_page_template(self, request, *args, **kwargs):
        # Make sure all children use the shared template
        return 'funds/round_landing.html'

    @cached_property
    def fund(self):
        return self.get_parent()

    @property
    def is_sealed(self):
        return self.sealed and self.is_open

    @property
    def is_open(self):
        return self.start_date <= date.today() <= self.end_date

    def save(self, *args, **kwargs):
        is_new = not self.id
        if is_new and hasattr(self, 'parent_page'):
            parent_page = self.parent_page[self.__class__][self.title]
            self.workflow_name = parent_page.workflow_name
            self.reviewers = parent_page.reviewers.all()

        super().save(*args, **kwargs)

        if is_new and hasattr(self, 'parent_page'):
            # Would be nice to do this using model clusters as part of the __init__
            self._copy_forms('forms')
            self._copy_forms('review_forms')

    def _copy_forms(self, field):
        for form in getattr(self.get_parent().specific, field).all():
            new_form = self._meta.get_field(field).related_model
            self._copy_form(form, new_form)

    def _copy_form(self, form, new_class):
        # Create a copy of the existing form object
        new_form = form.form
        new_form.id = None
        new_form.name = '{} for {} ({})'.format(new_form.name, self.title, self.get_parent().title)
        new_form.save()
        if hasattr(form, 'stage'):
            new_class.objects.create(round=self, form=new_form, stage=form.stage)
        else:
            new_class.objects.create(round=self, form=new_form)

    def get_submit_meta_data(self, **kwargs):
        return super().get_submit_meta_data(
            page=self.get_parent(),
            round=self,
            **kwargs,
        )

    def clean(self):
        super().clean()

        conflict_query = ()

        if self.start_date and self.end_date and self.start_date > self.end_date:
            raise ValidationError({
                'end_date': 'End date must come after the start date',
            })

        if self.start_date and self.end_date:
            conflict_query = (
                Q(start_date__range=[self.start_date, self.end_date]) |
                Q(end_date__range=[self.start_date, self.end_date]) |
                Q(start_date__lte=self.start_date, end_date__gte=self.end_date)
            )
        elif self.start_date:
            conflict_query = (
                Q(start_date__lte=self.start_date, end_date__isnull=True) |
                Q(end_date__gte=self.start_date)
            )

        if not self.id and hasattr(self, 'parent_page'):
            # Check if the create hook has added the parent page, we aren't an object yet.
            # Ensures we can access related objects during the clean phase instead of save.
            base_query = RoundBase.objects.child_of(self.parent_page[self.__class__][self.title])
        else:
            # don't need parent page, we are an actual object now.
            base_query = RoundBase.objects.sibling_of(self)

        if conflict_query:
            conflicting_rounds = base_query.filter(
                conflict_query
            ).exclude(id=self.id)

            if conflicting_rounds.exists():
                error_message = mark_safe('Overlaps with the following rounds:<br> {}'.format(
                    '<br>'.join([
                        f'<a href="{admin_url(round)}">{round.title}</a>: {round.start_date} - {round.end_date}'
                        for round in conflicting_rounds]
                    )
                ))
                error = {
                    'start_date': error_message,
                }
                if self.end_date:
                    error['end_date'] = error_message

                raise ValidationError(error)

    def get_initial_data_open_call_submission(self, submission_id):
        initial_values = {}

        try:
            submission_class = self.get_submission_class()
            submission = submission_class.objects.get(id=submission_id)
            if submission.status in OPEN_CALL_PHASES and self.get_parent() == submission.page:
                title_block_id = submission.named_blocks.get('title')
                if title_block_id:
                    field_data = submission.data(title_block_id)
                    initial_values[title_block_id] = field_data + ' (please edit)'

                for field_id in submission.first_group_normal_text_blocks:
                    field_data = submission.data(field_id)
                    initial_values[field_id] = field_data

                # Select first item in the Group toggle blocks
                for toggle_block_id, toggle_field in submission.group_toggle_blocks:
                    try:
                        initial_values[toggle_block_id] = toggle_field.value['choices'][0]
                    except IndexError:
                        initial_values[toggle_block_id] = 'yes'
                    except KeyError:
                        pass

        except (submission_class.DoesNotExist, ValueError):
            pass

        return initial_values

    def get_form_parameters(self, submission_id=None):
        form_parameters = {}

        if submission_id:
            initial_values = self.get_initial_data_open_call_submission(submission_id)
            if initial_values:
                form_parameters['initial'] = initial_values

        return form_parameters

    def get_form(self, *args, **kwargs):
        draft = kwargs.pop('draft', False)
        form_class = self.get_form_class(draft)
        submission_id = kwargs.pop('submission_id', None)
        if submission_id:
            form_params = self.get_form_parameters(submission_id=submission_id)
        else:
            form_params = self.get_form_parameters()
        form_params.update(kwargs)
        return form_class(*args, **form_params)

    def serve(self, request, *args, **kwargs):
        if hasattr(request, 'is_preview') or hasattr(request, 'show_round'):
            # Overriding serve method to pass submission id to get_form method
            copy_open_submission = request.GET.get('open_call_submission')
            if request.method == 'POST':
                draft = request.POST.get('draft', False)
                form = self.get_form(request.POST, request.FILES, page=self, user=request.user, draft=draft)

                if form.is_valid():
                    form_submission = self.process_form_submission(form, draft=draft)
                    return self.render_landing_page(request, form_submission, *args, **kwargs)
            else:
                form = self.get_form(page=self, user=request.user, submission_id=copy_open_submission)

            context = self.get_context(request)
            context['form'] = form
            context['show_all_group_fields'] = True if copy_open_submission else False
            return render(
                request,
                self.get_template(request),
                context
            )

        # We hide the round as only the open round is used which is displayed through the
        # fund page
        raise Http404()
Exemple #30
0
import datetime

from django.db.models import Q

from wagtail.core.query import PageQuerySet
from wagtail.core.models import PageManager


class ActiveInactivePageQuerySet(PageQuerySet):
    def active(self):
        td = datetime.datetime.today()
        return self.filter(Q(expire_at__isnull=True) | Q(expire_at__gt=td))

    def inactive(self):
        td = datetime.datetime.today()
        return self.filter(expire_at__lte=td)


ActiveInactivePageManager = PageManager.from_queryset(
    ActiveInactivePageQuerySet)