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') ]
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') ]
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
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)
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'), ])
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'
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') ]
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']
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()
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
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)
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)
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
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]
"""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,
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()
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()
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)