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 SublandingFilterablePage(FilterableFeedPageMixin, FilterableListMixin, CFGOVPage): header = StreamField([ ('hero', molecules.Hero()), ], blank=True) content = StreamField([ ('text_introduction', molecules.TextIntroduction()), ('full_width_text', organisms.FullWidthText()), ('filter_controls', organisms.FilterControls()), ('featured_content', molecules.FeaturedContent()), ('feedback', v1_blocks.Feedback()), ]) # 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()
class LandingPage(CFGOVPage): header = StreamField([ ('hero', molecules.Hero()), ('text_introduction', molecules.TextIntroduction()), ], blank=True) content = StreamField([ ('info_unit_group', organisms.InfoUnitGroup()), ('image_text_25_75_group', organisms.ImageText2575Group()), ('image_text_50_50_group', organisms.ImageText5050Group()), ('half_width_link_blob_group', organisms.HalfWidthLinkBlobGroup()), ('third_width_link_blob_group', organisms.ThirdWidthLinkBlobGroup()), ('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()
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 LegacyBlogPage(AbstractFilterPage): content = StreamField([ ('content', blocks.RawHTMLBlock(help_text='Content from WordPress unescaped.')), ('feedback', v1_blocks.Feedback()), ]) objects = CFGOVPageManager() edit_handler = AbstractFilterPage.generate_edit_handler( content_panel=StreamFieldPanel('content')) template = 'blog/blog_page.html'
class BlogPage(AbstractFilterPage): content = StreamField([ ('full_width_text', organisms.FullWidthText()), ('image_text_50_50_group', organisms.ImageText5050Group()), ('feedback', v1_blocks.Feedback()), ('email_signup', organisms.EmailSignUp()), ('expandable', organisms.Expandable()), ]) edit_handler = AbstractFilterPage.generate_edit_handler( content_panel=StreamFieldPanel('content')) template = 'blog/blog_page.html' objects = PageManager()
class BrowseFilterableContent(StreamBlock): """Defines the StreamField blocks for BrowseFilterablePage content. Pages can have at most one filterable list. """ full_width_text = organisms.FullWidthText() filter_controls = organisms.FilterableList() feedback = v1_blocks.Feedback() class Meta: block_counts = { 'filter_controls': {'max_num': 1}, }
class FormExplainerContent(StreamBlock): """Defines the StreamField blocks for FormExplainer page's content. Pages can have at most one Explainer block. """ explainer = Explainer() well = organisms.Well() info_unit_group = organisms.InfoUnitGroup() feedback = v1_blocks.Feedback() class Meta: block_counts = { 'explainer': { 'max_num': 1 }, }
class DocumentDetailPage(AbstractFilterPage): content = StreamField([ ('full_width_text', organisms.FullWidthText()), ('expandable', organisms.Expandable()), ('expandable_group', organisms.ExpandableGroup()), ('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()
class LegacyBlogPage(AbstractFilterPage): content = StreamField([ ('content', blocks.RawHTMLBlock(help_text='Content from WordPress unescaped.')), ('feedback', v1_blocks.Feedback()), ('reusable_text', v1_blocks.ReusableTextChooserBlock('v1.ReusableText')), ]) objects = CFGOVPageManager() edit_handler = AbstractFilterPage.generate_edit_handler( content_panel=StreamFieldPanel('content')) template = 'blog/blog_page.html' search_fields = AbstractFilterPage.search_fields + [ index.SearchField('content') ]
class BlogPage(AbstractFilterPage): content = StreamField([ ('full_width_text', organisms.FullWidthText()), ('info_unit_group', organisms.InfoUnitGroup()), ('expandable', organisms.Expandable()), ('well', organisms.Well()), ('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') ]
class SublandingFilterableContent(StreamBlock): """Defines the StreamField blocks for SublandingFilterablePage content. Pages can have at most one filterable list. """ text_introduction = molecules.TextIntroduction() full_width_text = organisms.FullWidthText() filter_controls = organisms.FilterableList() featured_content = organisms.FeaturedContent() feedback = v1_blocks.Feedback() class Meta: block_counts = { 'filter_controls': { 'max_num': 1 }, }
class BrowseFilterablePage(FilterableFeedPageMixin, FilterableListMixin, CFGOVPage): header = StreamField([ ('text_introduction', molecules.TextIntroduction()), ('featured_content', molecules.FeaturedContent()), ]) content = StreamField([ ('full_width_text', organisms.FullWidthText()), ('filter_controls', organisms.FilterControls()), ('feedback', v1_blocks.Feedback()), ]) 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() @property def page_js(self): return ( super(BrowseFilterablePage, self).page_js + ['secondary-navigation.js'] )
class AnswerPage(CFGOVPage): """Page type for Ask CFPB answers.""" from ask_cfpb.models import Answer last_edited = models.DateField( blank=True, null=True, help_text="Change the date to today if you make a significant change.") question = models.TextField(blank=True) statement = models.TextField( blank=True, help_text=( "(Optional) Use this field to rephrase the question title as " "a statement. Use only if this answer has been chosen to appear " "on a money topic portal (e.g. /consumer-tools/debt-collection).")) short_answer = RichTextField(blank=True, features=['link', 'document-link'], help_text='Optional answer intro') answer_content = StreamField(ask_blocks.AskAnswerContent(), blank=True, verbose_name='Answer') answer_base = models.ForeignKey(Answer, blank=True, null=True, related_name='answer_pages', on_delete=models.SET_NULL) redirect_to_page = models.ForeignKey( 'self', blank=True, null=True, on_delete=models.SET_NULL, related_name='redirect_to_pages', help_text="Choose another AnswerPage to redirect this page to") featured = models.BooleanField( default=False, help_text=("Check to make this one of two featured answers " "on the landing page.")) featured_rank = models.IntegerField(blank=True, null=True) category = models.ManyToManyField( 'Category', blank=True, help_text=("Categorize this answer. " "Avoid putting into more than one category.")) search_tags = models.CharField( max_length=1000, blank=True, help_text="Search words or phrases, separated by commas") related_resource = models.ForeignKey(RelatedResource, blank=True, null=True, on_delete=models.SET_NULL) related_questions = ParentalManyToManyField( 'self', symmetrical=False, blank=True, related_name='related_question', help_text='Maximum of 3 related questions') portal_topic = ParentalManyToManyField( PortalTopic, blank=True, help_text='Limit to 1 portal topic if possible') primary_portal_topic = ParentalKey( PortalTopic, blank=True, null=True, on_delete=models.SET_NULL, related_name='primary_portal_topic', help_text=("Use only if assigning more than one portal topic, " "to control which topic is used as a breadcrumb.")) portal_category = ParentalManyToManyField(PortalCategory, blank=True) user_feedback = StreamField([ ('feedback', v1_blocks.Feedback()), ], blank=True) content_panels = CFGOVPage.content_panels + [ MultiFieldPanel([ FieldPanel('last_edited'), FieldPanel('question'), FieldPanel('statement'), FieldPanel('short_answer') ], heading="Page content", classname="collapsible"), StreamFieldPanel('answer_content'), MultiFieldPanel([ SnippetChooserPanel('related_resource'), AutocompletePanel('related_questions', page_type='ask_cfpb.AnswerPage', is_single=False) ], heading="Related resources", classname="collapsible"), MultiFieldPanel([ FieldPanel('portal_topic', widget=forms.CheckboxSelectMultiple), FieldPanel('primary_portal_topic'), FieldPanel('portal_category', widget=forms.CheckboxSelectMultiple) ], heading="Portal tags", classname="collapsible"), MultiFieldPanel([FieldPanel('featured')], heading="Featured answer on Ask landing page", classname="collapsible"), MultiFieldPanel([ AutocompletePanel('redirect_to_page', page_type='ask_cfpb.AnswerPage') ], heading="Redirect to another answer", classname="collapsible"), MultiFieldPanel([StreamFieldPanel('user_feedback')], heading="User feedback", classname="collapsible collapsed"), ] sidebar = StreamField([ ('call_to_action', molecules.CallToAction()), ('related_links', molecules.RelatedLinks()), ('related_metadata', molecules.RelatedMetadata()), ('email_signup', organisms.EmailSignUp()), ('sidebar_contact', organisms.SidebarContactInfo()), ('rss_feed', molecules.RSSFeed()), ('social_media', molecules.SocialMedia()), ('reusable_text', v1_blocks.ReusableTextChooserBlock(ReusableText)), ], blank=True) sidebar_panels = [ StreamFieldPanel('sidebar'), ] search_fields = Page.search_fields + [ index.SearchField('answer_content'), index.SearchField('short_answer') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(sidebar_panels, heading='Sidebar'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) template = 'ask-cfpb/answer-page.html' objects = CFGOVPageManager() def get_sibling_url(self): if self.answer_base: if self.language == 'es': sibling = self.answer_base.english_page else: sibling = self.answer_base.spanish_page if sibling and sibling.live and not sibling.redirect_to_page: return sibling.url def get_context(self, request, *args, **kwargs): portal_topic = self.primary_portal_topic or self.portal_topic.first() context = super(AnswerPage, self).get_context(request) context['related_questions'] = self.related_questions.all() context['description'] = (self.short_answer if self.short_answer else Truncator(self.answer_content).words( 40, truncate=' ...')) context['last_edited'] = self.last_edited context['portal_page'] = get_portal_or_portal_search_page( portal_topic, language=self.language) context['breadcrumb_items'] = get_ask_breadcrumbs( language=self.language, portal_topic=portal_topic, ) context['about_us'] = get_standard_text(self.language, 'about_us') context['disclaimer'] = get_standard_text(self.language, 'disclaimer') context['sibling_url'] = self.get_sibling_url() return context def __str__(self): if self.answer_base: return '{}: {}'.format(self.answer_base.id, self.title) else: return self.title @property def clean_search_tags(self): return [tag.strip() for tag in self.search_tags.split(',')] @property def status_string(self): if self.redirect_to_page: if not self.live: return ("redirected but not live") else: return ("redirected") else: return super(AnswerPage, self).status_string # Returns an image for the page's meta Open Graph tag @property def meta_image(self): if self.social_sharing_image: return self.social_sharing_image if not self.category.exists(): return None return self.category.first().category_image # Overrides the default of page.id for comparing against split testing # clusters. See: core.feature_flags.in_split_testing_cluster @property def split_test_id(self): return self.answer_base.id
class AnswerPage(CFGOVPage): """ Page type for Ask CFPB answers. """ from ask_cfpb.models import Answer last_edited = models.DateField( blank=True, null=True, help_text="Change the date to today if you make a significant change.") question = models.TextField(blank=True) statement = models.TextField( blank=True, help_text=( "(Optional) Use this field to rephrase the question title as " "a statement. Use only if this answer has been chosen to appear " "on a money topic portal (e.g. /consumer-tools/debt-collection).")) short_answer = RichTextField(blank=True, help_text='Optional answer intro') answer = RichTextField( blank=True, features=[ 'bold', 'italic', 'h2', 'h3', 'h4', 'link', 'ol', 'ul', 'document-link', 'image', 'embed', 'ask-tips', 'edit-html' ], help_text=( "Do not use H2 or H3 to style text. Only use the HTML Editor " "for troubleshooting. To style tips, warnings and notes, " "select the content that will go inside the rule lines " "(so, title + paragraph) and click the Pencil button " "to style it. Re-select the content and click the button " "again to unstyle the tip.")) answer_base = models.ForeignKey(Answer, blank=True, null=True, related_name='answer_pages', on_delete=models.SET_NULL) redirect_to = models.ForeignKey( Answer, blank=True, null=True, on_delete=models.SET_NULL, related_name='redirected_pages', help_text="Choose another Answer to redirect this page to") redirect_to_page = models.ForeignKey( 'self', blank=True, null=True, on_delete=models.SET_NULL, related_name='redirect_to_pages', help_text="Choose another AnswerPage to redirect this page to") featured = models.BooleanField( default=False, help_text=("Check to make this one of two featured answers " "on the landing page.")) featured_rank = models.IntegerField(blank=True, null=True) category = models.ManyToManyField( 'Category', blank=True, help_text=("Categorize this answer. " "Avoid putting into more than one category.")) subcategory = models.ManyToManyField( 'SubCategory', blank=True, help_text=("Choose only subcategories that belong " "to one of the categories checked above.")) search_tags = models.CharField( max_length=1000, blank=True, help_text="Search words or phrases, separated by commas") related_resource = models.ForeignKey(RelatedResource, blank=True, null=True, on_delete=models.SET_NULL) related_questions = ParentalManyToManyField( 'self', symmetrical=False, blank=True, related_name='related_question', help_text='Maximum of 3 related questions') answer_id = models.IntegerField(default=0) portal_topic = ParentalManyToManyField( PortalTopic, blank=True, help_text='Limit to 1 portal topic if possible') primary_portal_topic = ParentalKey( PortalTopic, blank=True, null=True, on_delete=models.SET_NULL, related_name='primary_portal_topic', help_text=("Use only if assigning more than one portal topic, " "to control which topic is used as a breadcrumb.")) portal_category = ParentalManyToManyField(PortalCategory, blank=True) user_feedback = StreamField([ ('feedback', v1_blocks.Feedback()), ], blank=True) content_panels = CFGOVPage.content_panels + [ MultiFieldPanel([ FieldPanel('last_edited'), FieldPanel('question'), FieldPanel('statement'), FieldPanel('short_answer'), FieldPanel('answer') ], heading="Page content", classname="collapsible"), MultiFieldPanel([ SnippetChooserPanel('related_resource'), AutocompletePanel('related_questions', page_type='ask_cfpb.AnswerPage', is_single=False) ], heading="Related resources", classname="collapsible"), MultiFieldPanel([ FieldPanel('portal_topic', widget=forms.CheckboxSelectMultiple), FieldPanel('primary_portal_topic'), FieldPanel('portal_category', widget=forms.CheckboxSelectMultiple) ], heading="Portal tags", classname="collapsible"), MultiFieldPanel([ AutocompletePanel('redirect_to_page', page_type='ask_cfpb.AnswerPage') ], heading="Redirect to another answer", classname="collapsible"), MultiFieldPanel([StreamFieldPanel('user_feedback')], heading="User feedback", classname="collapsible collapsed"), ] sidebar = StreamField([ ('call_to_action', molecules.CallToAction()), ('related_links', molecules.RelatedLinks()), ('related_metadata', molecules.RelatedMetadata()), ('email_signup', organisms.EmailSignUp()), ('sidebar_contact', organisms.SidebarContactInfo()), ('rss_feed', molecules.RSSFeed()), ('social_media', molecules.SocialMedia()), ('reusable_text', v1_blocks.ReusableTextChooserBlock(ReusableText)), ], blank=True) sidebar_panels = [ StreamFieldPanel('sidebar'), ] search_fields = Page.search_fields + [ index.SearchField('answer'), index.SearchField('short_answer') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(sidebar_panels, heading='Sidebar (English only)'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) objects = CFGOVPageManager() def get_context(self, request, *args, **kwargs): context = super(AnswerPage, self).get_context(request) context['related_questions'] = self.related_questions.all() context['description'] = self.short_answer if self.short_answer \ else Truncator(self.answer).words(40, truncate=' ...') context['answer_id'] = self.answer_base.id if self.language == 'es': context['search_tags'] = self.clean_search_tags context['tweet_text'] = Truncator(self.question).chars( 100, truncate=' ...') context['disclaimer'] = get_reusable_text_snippet( SPANISH_DISCLAIMER_SNIPPET_TITLE) context['category'] = self.category.first() elif self.language == 'en': context['about_us'] = get_reusable_text_snippet( ABOUT_US_SNIPPET_TITLE) context['disclaimer'] = get_reusable_text_snippet( ENGLISH_DISCLAIMER_SNIPPET_TITLE) context['last_edited'] = self.last_edited # breadcrumbs and/or category should reflect # the referrer if it is a consumer tools portal or # ask category page context['category'], context['breadcrumb_items'] = \ get_question_referrer_data( request, self.category.all()) subcategories = [] for subcat in self.subcategory.all(): if subcat.parent == context['category']: subcategories.append(subcat) for related in subcat.related_subcategories.all(): if related.parent == context['category']: subcategories.append(related) context['subcategories'] = set(subcategories) return context def get_template(self, request): printable = request.GET.get('print', False) if self.language == 'es': if printable == 'true': return 'ask-cfpb/answer-page-spanish-printable.html' return 'ask-cfpb/answer-page-spanish.html' return 'ask-cfpb/answer-page.html' def __str__(self): if self.answer_base: return '{}: {}'.format(self.answer_base.id, self.title) else: return self.title @property def clean_search_tags(self): return [tag.strip() for tag in self.search_tags.split(',')] @property def status_string(self): if self.redirect_to_page: if not self.live: return ("redirected but not live") else: return ("redirected") else: return super(AnswerPage, self).status_string # Returns an image for the page's meta Open Graph tag @property def meta_image(self): if self.social_sharing_image: return self.social_sharing_image if not self.category.exists(): return None return self.category.first().category_image # Overrides the default of page.id for comparing against split testing # clusters. See: core.feature_flags.in_split_testing_cluster @property def split_test_id(self): return self.answer_base.id
class EnforcementActionPage(AbstractFilterPage): public_enforcement_action = models.CharField(max_length=150, blank=True) initial_filing_date = models.DateField(null=True, blank=True) settled_or_contested_at_filing = models.CharField(max_length=10, choices=[('Settled', 'Settled'), ('Contested', 'Contested')], blank=True) court = models.CharField(default='', max_length=150, blank=True) 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 = [ FieldPanel('public_enforcement_action'), FieldPanel('initial_filing_date'), InlinePanel('defendant_types', label='Defendant/Respondent Type'), InlinePanel('categories', label="Forum", min_num=1, max_num=2), FieldPanel('court'), InlinePanel('docket_numbers', label="Docket Number", min_num=1), FieldPanel('settled_or_contested_at_filing'), InlinePanel('statuses', label="Status", min_num=1), InlinePanel('products', label="Products"), InlinePanel('at_risk_groups', label="At Risk Groups"), InlinePanel('statutes', label="Statutes/Regulations"), InlinePanel('enforcement_dispositions', label='Final Disposition'), ] 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'), MultiFieldPanel(CFGOVPage.archive_panels, 'Archive'), ] 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') ] @classmethod def all_actions(cls): # Return the collection of all Enforcement Action Pages. # Exclude any pages in the Trash or otherwise not a child of the # EnforcementActionsFilterPage. try: # TODO: find a less hacky way to get only the pages in the # correct part of the page tree pg_id = 1327 parent_page = Page.objects.get(id=pg_id) query = cls.objects.child_of(parent_page) except (Page.DoesNotExist): query = cls.objects query = query.filter(initial_filing_date__isnull=False) query = query.live().order_by('-initial_filing_date') return query def get_context(self, request): context = super(EnforcementActionPage, self).get_context(request) dispositions = self.enforcement_dispositions.all() context.update({ 'total_consumer_relief': sum(disp.final_order_consumer_redress + disp.final_order_other_consumer_relief for disp in dispositions), 'total_cmp': sum(disp.final_order_civil_money_penalty for disp in dispositions), 'defendant_types': [ d.get_defendant_type_display() for d in self.defendant_types.all() ], 'statutes': [s.statute for s in self.statutes.all()], 'products': [p.product for p in self.products.all()], 'at_risk_groups': [g.at_risk_group for g in self.at_risk_groups.all()] }) return context
class AnswerPage(CFGOVPage): """Page type for Ask CFPB answers.""" from ask_cfpb.models.django import Answer last_edited = models.DateField( blank=True, null=True, help_text="Change the date to today if you make a significant change.") question = models.TextField(blank=True) statement = models.TextField( blank=True, help_text=( "(Optional) Use this field to rephrase the question title as " "a statement. Use only if this answer has been chosen to appear " "on a money topic portal (e.g. /consumer-tools/debt-collection).")) short_answer = RichTextField(blank=True, features=['link', 'document-link'], help_text='Optional answer intro') answer_content = StreamField(ask_blocks.AskAnswerContent(), blank=True, verbose_name='Answer') answer_base = models.ForeignKey(Answer, blank=True, null=True, related_name='answer_pages', on_delete=models.SET_NULL) redirect_to_page = models.ForeignKey( 'self', blank=True, null=True, on_delete=models.SET_NULL, related_name='redirect_to_pages', help_text="Choose another AnswerPage to redirect this page to") featured = models.BooleanField( default=False, help_text=("Check to make this one of two featured answers " "on the landing page.")) featured_rank = models.IntegerField(blank=True, null=True) category = models.ManyToManyField( 'Category', blank=True, help_text=("Categorize this answer. " "Avoid putting into more than one category.")) search_tags = models.CharField( max_length=1000, blank=True, help_text="Search words or phrases, separated by commas") related_resource = models.ForeignKey(RelatedResource, blank=True, null=True, on_delete=models.SET_NULL) related_questions = ParentalManyToManyField( 'self', symmetrical=False, blank=True, related_name='related_question', help_text='Maximum of 3 related questions') portal_topic = ParentalManyToManyField( PortalTopic, blank=True, help_text='Limit to 1 portal topic if possible') primary_portal_topic = ParentalKey( PortalTopic, blank=True, null=True, on_delete=models.SET_NULL, related_name='primary_portal_topic', help_text=("Use only if assigning more than one portal topic, " "to control which topic is used as a breadcrumb.")) portal_category = ParentalManyToManyField(PortalCategory, blank=True) user_feedback = StreamField([ ('feedback', v1_blocks.Feedback()), ], blank=True) share_and_print = models.BooleanField( default=False, help_text="Include share and print buttons above answer.") content_panels = CFGOVPage.content_panels + [ MultiFieldPanel([ FieldPanel('last_edited'), FieldPanel('question'), FieldPanel('statement'), FieldPanel('short_answer') ], heading="Page content", classname="collapsible"), FieldPanel('share_and_print'), StreamFieldPanel('answer_content'), MultiFieldPanel([ SnippetChooserPanel('related_resource'), AutocompletePanel('related_questions', target_model='ask_cfpb.AnswerPage') ], heading="Related resources", classname="collapsible"), MultiFieldPanel([ FieldPanel('portal_topic', widget=forms.CheckboxSelectMultiple), FieldPanel('primary_portal_topic'), FieldPanel('portal_category', widget=forms.CheckboxSelectMultiple) ], heading="Portal tags", classname="collapsible"), MultiFieldPanel([FieldPanel('featured')], heading="Featured answer on Ask landing page", classname="collapsible"), MultiFieldPanel([ AutocompletePanel('redirect_to_page', target_model='ask_cfpb.AnswerPage') ], heading="Redirect to another answer", classname="collapsible"), MultiFieldPanel([StreamFieldPanel('user_feedback')], heading="User feedback", classname="collapsible collapsed"), ] sidebar = StreamField([ ('call_to_action', molecules.CallToAction()), ('related_links', molecules.RelatedLinks()), ('related_metadata', molecules.RelatedMetadata()), ('email_signup', organisms.EmailSignUp()), ('sidebar_contact', organisms.SidebarContactInfo()), ('rss_feed', molecules.RSSFeed()), ('social_media', molecules.SocialMedia()), ('reusable_text', v1_blocks.ReusableTextChooserBlock(ReusableText)), ], blank=True) sidebar_panels = [ StreamFieldPanel('sidebar'), ] search_fields = Page.search_fields + [ index.SearchField('answer_content'), index.SearchField('short_answer') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(sidebar_panels, heading='Sidebar'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) template = 'ask-cfpb/answer-page.html' objects = CFGOVPageManager() def get_sibling_url(self): if self.answer_base: if self.language == 'es': sibling = self.answer_base.english_page else: sibling = self.answer_base.spanish_page if sibling and sibling.live and not sibling.redirect_to_page: return sibling.url def get_meta_description(self): """Determine what the page's meta and OpenGraph description should be Checks several different possible fields in order of preference. If none are found, returns an empty string, which is preferable to a generic description repeated on many pages. This method is overriding the standard one on CFGOVPage to factor in Ask CFPB AnswerPage-specific fields. """ preference_order = [ 'search_description', 'short_answer', 'first_text', ] candidates = {} if self.search_description: candidates['search_description'] = self.search_description if self.short_answer: candidates['short_answer'] = strip_tags(self.short_answer) if hasattr(self, 'answer_content'): for block in self.answer_content: if block.block_type == 'text': candidates['first_text'] = truncate_by_words_and_chars( strip_tags(block.value['content'].source), word_limit=35, char_limit=160) break for entry in preference_order: if candidates.get(entry): return candidates[entry] return '' def get_context(self, request, *args, **kwargs): # self.get_meta_description() is not called here because it is called # and added to the context by CFGOVPage's get_context() method. portal_topic = self.primary_portal_topic or self.portal_topic.first() context = super(AnswerPage, self).get_context(request) context['related_questions'] = self.related_questions.all() context['last_edited'] = self.last_edited context['portal_page'] = get_portal_or_portal_search_page( portal_topic, language=self.language) context['breadcrumb_items'] = get_ask_breadcrumbs( language=self.language, portal_topic=portal_topic, ) context['about_us'] = get_standard_text(self.language, 'about_us') context['disclaimer'] = get_standard_text(self.language, 'disclaimer') context['sibling_url'] = self.get_sibling_url() return context def answer_content_text(self): raw_text = extract_raw_text(self.answer_content.stream_data) return strip_tags(" ".join([self.short_answer, raw_text])) def answer_content_data(self): return truncate_by_words_and_chars(self.answer_content_text()) def short_answer_data(self): return ' '.join( RichTextField.get_searchable_content(self, self.short_answer)) def text(self): short_answer = self.short_answer_data() answer_text = self.answer_content_text() full_text = f"{short_answer}\n\n{answer_text}\n\n{self.question}" return full_text def __str__(self): if self.answer_base: return f"{self.answer_base.id}: {self.title}" else: return self.title @property def clean_search_tags(self): return [tag.strip() for tag in self.search_tags.split(",")] @property def status_string(self): if self.redirect_to_page: if not self.live: return ("redirected but not live") else: return ("redirected") else: return super(AnswerPage, self).status_string # Returns an image for the page's meta Open Graph tag @property def meta_image(self): if self.social_sharing_image: return self.social_sharing_image if not self.category.exists(): return None return self.category.first().category_image # Overrides the default of page.id for comparing against split testing # clusters. See: core.feature_flags.in_split_testing_cluster @property def split_test_id(self): return self.answer_base.id
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 SublandingPage(CFGOVPage): header = StreamField([ ('hero', molecules.Hero()), ], blank=True) content = StreamField([ ('text_introduction', molecules.TextIntroduction()), ('featured_content', molecules.FeaturedContent()), ('info_unit_group', organisms.InfoUnitGroup()), ('image_text_25_75_group', organisms.ImageText2575Group()), ('image_text_50_50_group', organisms.ImageText5050Group()), ('full_width_text', organisms.FullWidthText()), ('half_width_link_blob_group', organisms.HalfWidthLinkBlobGroup()), ('third_width_link_blob_group', organisms.ThirdWidthLinkBlobGroup()), ('post_preview_snapshot', organisms.PostPreviewSnapshot()), ('well', organisms.Well()), ('table', organisms.Table(editable=False)), ('table_block', organisms.AtomicTableBlock(table_options={'renderer': 'html'})), ('contact', organisms.MainContactInfo()), ('formfield_with_button', molecules.FormFieldWithButton()), ('reg_comment', organisms.RegComment()), ('feedback', v1_blocks.Feedback()), ('snippet_list', organisms.SnippetList()), ], 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'), ] 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() 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) for post in form.get_page_set(): posts_list.append(post) return sorted(posts_list, key=lambda p: p.date_published, reverse=True)[:limit]
class AnswerPage(CFGOVPage): """ Page type for Ask CFPB answers. """ from ask_cfpb.models import Answer question = RichTextField(blank=True, editable=False) answer = RichTextField(blank=True, editable=False) snippet = RichTextField( blank=True, help_text='Optional answer intro', editable=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) publish_date = models.DateTimeField(default=timezone.now) answer_base = models.ForeignKey( Answer, blank=True, null=True, related_name='answer_pages', on_delete=models.SET_NULL) redirect_to = models.ForeignKey( Answer, blank=True, null=True, on_delete=models.SET_NULL, related_name='redirected_pages', help_text="Choose another Answer to redirect this page to") content = StreamField([ ('feedback', v1_blocks.Feedback()), ], blank=True) content_panels = CFGOVPage.content_panels + [ FieldPanel('redirect_to'), ] sidebar = StreamField([ ('call_to_action', molecules.CallToAction()), ('related_links', molecules.RelatedLinks()), ('related_metadata', molecules.RelatedMetadata()), ('email_signup', organisms.EmailSignUp()), ('sidebar_contact', organisms.SidebarContactInfo()), ('rss_feed', molecules.RSSFeed()), ('social_media', molecules.SocialMedia()), ('reusable_text', v1_blocks.ReusableTextChooserBlock(ReusableText)), ], blank=True) sidebar_panels = [StreamFieldPanel('sidebar'), ] search_fields = Page.search_fields + [ index.SearchField('question'), index.SearchField('answer'), index.SearchField('answer_base'), index.FilterField('language') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(sidebar_panels, heading='Sidebar (English only)'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) objects = CFGOVPageManager() def get_context(self, request, *args, **kwargs): context = super(AnswerPage, self).get_context(request) context['answer_id'] = self.answer_base.id context['related_questions'] = self.answer_base.related_questions.all() context['description'] = self.snippet if self.snippet \ else Truncator(self.answer).words(40, truncate=' ...') context['audiences'] = [ {'text': audience.name, 'url': '/ask-cfpb/audience-{}'.format( slugify(audience.name))} for audience in self.answer_base.audiences.all()] if self.language == 'es': tag_dict = self.Answer.valid_tags(language='es') context['tags_es'] = [tag for tag in self.answer_base.tags_es if tag in tag_dict['valid_tags']] context['tweet_text'] = Truncator(self.question).chars( 100, truncate=' ...') context['disclaimer'] = get_reusable_text_snippet( SPANISH_DISCLAIMER_SNIPPET_TITLE) context['category'] = self.answer_base.category.first() elif self.language == 'en': # we're not using tags on English pages yet, so cut the overhead # tag_dict = self.Answer.valid_tags() # context['tags'] = [tag for tag in self.answer_base.tags # if tag in tag_dict['valid_tags']] context['about_us'] = get_reusable_text_snippet( ABOUT_US_SNIPPET_TITLE) context['disclaimer'] = get_reusable_text_snippet( ENGLISH_DISCLAIMER_SNIPPET_TITLE) context['last_edited'] = self.answer_base.last_edited # breadcrumbs and/or category should reflect # the referrer if it is a consumer tools portal or # ask category page context['category'], context['breadcrumb_items'] = \ get_question_referrer_data( request, self.answer_base.category.all()) subcategories = [] for subcat in self.answer_base.subcategory.all(): if subcat.parent == context['category']: subcategories.append(subcat) for related in subcat.related_subcategories.all(): if related.parent == context['category']: subcategories.append(related) context['subcategories'] = set(subcategories) return context def get_template(self, request): printable = request.GET.get('print', False) if self.language == 'es': if printable == 'true': return 'ask-cfpb/answer-page-spanish-printable.html' return 'ask-cfpb/answer-page-spanish.html' return 'ask-cfpb/answer-page.html' def __str__(self): if self.answer_base: return '{}: {}'.format(self.answer_base.id, self.title) else: return self.title @property def status_string(self): if self.redirect_to: if not self.live: return _("redirected but not live") else: return _("redirected") else: return super(AnswerPage, self).status_string # Returns an image for the page's meta Open Graph tag @property def meta_image(self): if self.answer_base.social_sharing_image: return self.answer_base.social_sharing_image if not self.answer_base.category.exists(): return None return self.answer_base.category.first().category_image
class AnswerPage(CFGOVPage): """ Page type for Ask CFPB answers. """ from ask_cfpb.models import Answer last_edited = models.DateField( blank=True, null=True, help_text="Change the date to today if you make a significant change.") question = models.TextField(blank=True) statement = models.TextField( blank=True, help_text=( "(Optional) Use this field to rephrase the question title as " "a statement. Use only if this answer has been chosen to appear " "on a money topic portal (e.g. /consumer-tools/debt-collection).")) answer = RichTextField( blank=True, features=[ 'bold', 'italic', 'h2', 'h3', 'h4', 'link', 'ol', 'ul', 'document-link', 'image', 'embed', 'ask-tips', 'edit-html' ], help_text=( "Do not use H2 or H3 to style text. Only use the HTML Editor " "for troubleshooting. To style tips, warnings and notes, " "select the content that will go inside the rule lines " "(so, title + paragraph) and click the Pencil button " "to style it. Re-select the content and click the button " "again to unstyle the tip.")) snippet = RichTextField(blank=True, help_text='Optional answer intro') search_tags = models.CharField( max_length=1000, blank=True, help_text="PLEASE DON'T USE. THIS FIELD IS NOT YET ACTIVATED.") answer_base = models.ForeignKey(Answer, blank=True, null=True, related_name='answer_pages', on_delete=models.SET_NULL) redirect_to = models.ForeignKey( Answer, blank=True, null=True, on_delete=models.SET_NULL, related_name='redirected_pages', help_text="Choose another Answer to redirect this page to") content = StreamField([ ('feedback', v1_blocks.Feedback()), ], blank=True) content_panels = CFGOVPage.content_panels + [ MultiFieldPanel([FieldRowPanel([FieldPanel('last_edited')])], heading="Visible time stamp"), FieldPanel('question'), FieldPanel('statement'), FieldPanel('snippet'), FieldPanel('answer'), FieldPanel('search_tags'), FieldPanel('redirect_to'), ] sidebar = StreamField([ ('call_to_action', molecules.CallToAction()), ('related_links', molecules.RelatedLinks()), ('related_metadata', molecules.RelatedMetadata()), ('email_signup', organisms.EmailSignUp()), ('sidebar_contact', organisms.SidebarContactInfo()), ('rss_feed', molecules.RSSFeed()), ('social_media', molecules.SocialMedia()), ('reusable_text', v1_blocks.ReusableTextChooserBlock(ReusableText)), ], blank=True) sidebar_panels = [ StreamFieldPanel('sidebar'), ] search_fields = Page.search_fields + [ index.SearchField('answer'), index.SearchField('snippet') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(sidebar_panels, heading='Sidebar (English only)'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) objects = CFGOVPageManager() def get_context(self, request, *args, **kwargs): context = super(AnswerPage, self).get_context(request) context['answer_id'] = self.answer_base.id context['related_questions'] = self.answer_base.related_questions.all() context['description'] = self.snippet if self.snippet \ else Truncator(self.answer).words(40, truncate=' ...') context['audiences'] = [{ 'text': audience.name, 'url': '/ask-cfpb/audience-{}'.format(slugify(audience.name)) } for audience in self.answer_base.audiences.all()] if self.language == 'es': tag_dict = self.Answer.valid_tags(language='es') context['tags_es'] = [ tag for tag in self.answer_base.clean_tags_es if tag in tag_dict['valid_tags'] ] context['tweet_text'] = Truncator(self.question).chars( 100, truncate=' ...') context['disclaimer'] = get_reusable_text_snippet( SPANISH_DISCLAIMER_SNIPPET_TITLE) context['category'] = self.answer_base.category.first() elif self.language == 'en': # we're not using tags on English pages yet, so cut the overhead # tag_dict = self.Answer.valid_tags() # context['tags'] = [tag for tag in self.answer_base.clean_tags # if tag in tag_dict['valid_tags']] context['about_us'] = get_reusable_text_snippet( ABOUT_US_SNIPPET_TITLE) context['disclaimer'] = get_reusable_text_snippet( ENGLISH_DISCLAIMER_SNIPPET_TITLE) context['last_edited'] = (self.last_edited or self.answer_base.last_edited) # breadcrumbs and/or category should reflect # the referrer if it is a consumer tools portal or # ask category page context['category'], context['breadcrumb_items'] = \ get_question_referrer_data( request, self.answer_base.category.all()) subcategories = [] for subcat in self.answer_base.subcategory.all(): if subcat.parent == context['category']: subcategories.append(subcat) for related in subcat.related_subcategories.all(): if related.parent == context['category']: subcategories.append(related) context['subcategories'] = set(subcategories) return context def get_template(self, request): printable = request.GET.get('print', False) if self.language == 'es': if printable == 'true': return 'ask-cfpb/answer-page-spanish-printable.html' return 'ask-cfpb/answer-page-spanish.html' return 'ask-cfpb/answer-page.html' def __str__(self): if self.answer_base: return '{}: {}'.format(self.answer_base.id, self.title) else: return self.title @property def status_string(self): if self.redirect_to: if not self.live: return _("redirected but not live") else: return _("redirected") else: return super(AnswerPage, self).status_string # Returns an image for the page's meta Open Graph tag @property def meta_image(self): if self.answer_base.social_sharing_image: return self.answer_base.social_sharing_image if not self.answer_base.category.exists(): return None return self.answer_base.category.first().category_image # Overrides the default of page.id for comparing against split testing # clusters. See: core.feature_flags.in_split_testing_cluster @property def split_test_id(self): return self.answer_base.id
class AnswerPage(CFGOVPage): """ Page type for Ask CFPB answers. """ from .django import Answer question = RichTextField(blank=True, editable=False) answer = RichTextField(blank=True, editable=False) snippet = RichTextField(blank=True, help_text='Optional answer intro', editable=False) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) publish_date = models.DateTimeField(default=timezone.now) answer_base = models.ForeignKey(Answer, blank=True, null=True, related_name='answer_pages', on_delete=models.SET_NULL) redirect_to = models.ForeignKey( Answer, blank=True, null=True, on_delete=models.SET_NULL, related_name='redirected_pages', help_text="Choose another Answer to redirect this page to") content = StreamField([ ('feedback', v1_blocks.Feedback()), ], blank=True) content_panels = CFGOVPage.content_panels + [ FieldPanel('redirect_to'), StreamFieldPanel('content'), ] search_fields = Page.search_fields + [ index.SearchField('question'), index.SearchField('answer'), index.SearchField('answer_base'), index.FilterField('language') ] edit_handler = TabbedInterface([ ObjectList(content_panels, heading='Content'), ObjectList(CFGOVPage.settings_panels, heading='Configuration'), ]) template = 'ask-cfpb/answer-page.html' objects = PageManager() def __str__(self): if self.answer_base: return '{}: {}'.format(self.answer_base.id, self.title) else: return self.title @property def status_string(self): if self.redirect_to: if not self.live: return _("redirected but not live") else: return _("redirected") else: return super(AnswerPage, self).status_string
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: posts_list.extend(AbstractFilterPage.objects.live().filter( CFGOVPage.objects.child_of_q(page))) return sorted(posts_list, key=lambda p: p.date_published, reverse=True)[:limit]
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') ]