Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DO NOT MERGE] Feature/3869 commissioner document feed #4008

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions fec/fec/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,73 @@
for category in report_category_groups.keys():
report_child_categories.update(report_category_groups[category])

# TODO
# commissioner_item_categories are a single taxonomy with a faked hierarchy
commissioner_item_categories = OrderedDict([
('ballot-measures', 'Ballot Measures'),
('best-efforts', '"Best Efforts"'),
('contention-language', 'Contention Language'),
('family-member-contributions', 'Family Member Contributions'),
('coordination', 'Coordination'),
('coordination/super-pacs', '↳ Super PACs'),
('coordination/leadership-pac', '↳ Leadership PAC'),
('coordination/hybrid-pacs', '↳ Hybrid PACs'),
('coordination/corporations', '↳ Corporations'),
('coordination/dark-money-groups-501c4', '↳ Dark Money Groups/501(c)(4)'),
('coordination/state-political-party', '↳ State Political Party'),
('coordination/membership-organization-pacs', '↳ Membership Organization PACs'),
('contract-dispute', 'Contract Dispute'),
('corporate-spending', 'Corporate Spending'),
('corporate-spending/employee-coercion-threats-of-reprisal', '↳ Employee Coercion/Threats of Reprisal'),
('corporate-spending/in-kind-contributions', '↳ In-Kind Contributions'),
('corporate-spending/extending-credit', '↳ Extending Credit'),
('corporate-spending/preparing-mailers', '↳ Preparing Mailers'),
('corporate-spending/business-associations', '↳ Business Associations'),
('corporate-spending/lobbyists-delivering-funds-on-behalf-of-corporation',
'↳ Lobbyists Delivering Funds on Behalf of Corporation'),
('corporate-spending/nonprofit-corporation', '↳ Nonprofit Corporation'),
('corporate-spending/salary-payments', '↳ Salary Payments'),
('corporate-spending/improper-refund', '↳ Improper Refund'),
('corporate-spending/express-advocacy', '↳ Express Advocacy'),
('dark-money-501c4-groups', 'Dark Money/501(c)(4) groups'),
('dark-money-501c4-groups/political-committee-status', '↳ Political Committee Status'),
('dark-money-501c4-groups/failing-to-disclose-independent-expenditure',
'↳ Failing to Disclose Independent Expenditure'),
('disclaimers', 'Disclaimers'),
('disclaimers/brochure', '↳ Brochure'),
('disclaimers/printed-box-requirement', '↳ Printed Box Requirement'),
('disclaimers/internet', '↳ Internet'),
('disclaimers/newspaper', '↳ Newspaper'),
('disclaimers/mailer', '↳ Mailer'),
('disclaimers/robocall', '↳ Robocall'),
('disclaimers/radio', '↳ Radio'),
('disclaimers/signs', '↳ Signs'),
('disclaimers/television', '↳ Television'),
('electioneering-communications', 'Electioneering Communications'),
('express-advocacy', 'Express Advocacy'),
('failing-to-disclose-independent-expenditure', 'Failing to Disclose Independent Expenditure'),
('foreign-spending', 'Foreign Spending'),
('hloga-air-travel', 'HLOGA/Air Travel'),
('hosting-debates', 'Hosting Debates'),
('increased-activity', 'Increased Activity'),
('lobbyist-activity', 'Lobbyist Activity'),
('membership-communications-exception', 'Membership Communications Exception'),
('mischaracterization-of-party-in-court-filing', 'Mischaracterization of Party in Court Filing'),
('payroll-deduction', 'Payroll Deduction'),
('personal-use', 'Personal Use'),
('press-exemption', 'Press Exemption'),
('soft-money-use-of-non-federal-money-on-federal-expenses',
'Soft Money/Use of Non-Federal Money on Federal Expenses'),
('sale-use', 'Sale & Use'),
('straw-donors-conduit-contributions', 'Straw Donors/Conduit Contributions'),
('super-pac-not-disclosing-till-after-election', 'Super PAC not disclosing till after election'),
('testing-the-waters-candidate-status', 'Testing the Waters/Candidate Status'),
('unions', 'Unions'),
('use-of-opponents-name-without-permission', 'Use of Opponent’s Name Without Permission'),
('volunteer-exemption', 'Volunteer Exemption'),
('volunteer-mailers-exemption', 'Volunteer Mailers Exemption'),
])


# Search index constants
# These are the parent pages for which we want *all* descendants of, not just direct children
Expand Down
37 changes: 37 additions & 0 deletions fec/fec/templates/partials/commissioner-item.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{# Template based on /fec/fec/templates/partials/update.html #}

<!-- {% load wagtailimages_tags %} -->
{% load filters %}

<article class="post">
<div class="post__pre">
{{ item.display_date }}
</div>
<div class="row">
<div class="usa-width-three-fourths">
<h3>
{% if item.links_count == 1 %}
{% if item.link_doc %}
<a href="{{ item.link_doc }}">{{ item.title }}</a> <i class="icon icon--inline--right icon--inline--left i-document"></i> (PDF)
{% elif item.link_html %}
<a href="{{ item.link_html }}">{{ item.title }}</a> <i class="icon icon--inline--right icon--inline--left i-share"></i> (HTML)
{% elif item.link_pdf %}
<a href="{{ item.link_pdf }}">{{ item.title }}</a> <i class="icon icon--inline--right icon--inline--left i-document"></i> (PDF)
{% elif item.link_video %}
<a href="{{ item.link_video }}">{{ item.title }}</a> <i class="icon icon--inline--right icon--inline--left i-share"></i> (HTML)
{% endif %}
{% else %}
{{ item.title }} {{ item.links_string|safe }}
{% endif %}
</h3>
{% if item.category %}
<div class="post__meta t-sans">
<a class="tag tag--secondary" href="./?category={{item.slug_category}}">{{item.pretty_category}}</a>
{% if item.pretty_subject %}
in: <a href="./?category={{item.slug_category}}&subject={{item.slug_subject}}">{{ item.pretty_subject|capfirst }}</a>
{% endif %}
</div>
{% endif %}
</div>
</div>
</article>
7 changes: 6 additions & 1 deletion fec/fec/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.conf.urls import include, url
from django.conf.urls import include, url, re_path
from django.conf import settings
from django.contrib import admin

from django.views.generic.base import TemplateView

from wagtail.admin import urls as wagtailadmin_urls
Expand All @@ -22,6 +23,10 @@
url(r'^auth/', include(uaa_urls)),
url(r'^admin/', include(wagtailadmin_urls)),
url(r'^calendar/$', home_views.calendar),
re_path(
r'^about/leadership-and-structure/(?P<commissioner_slug>[a-z0-9]+-[a-z0-9]+[a-z0-9-]*)/statements-and-opinions/$', # noqa: E501
home_views.commissioner_statements_and_opinions
),
url(r'^about/leadership-and-structure/commissioners/$', home_views.commissioners),
url(r'^documents/', include(wagtaildocs_urls)),
url(r'^help-candidates-and-committees/question-rad/$', home_views.contact_rad),
Expand Down
178 changes: 167 additions & 11 deletions fec/home/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,38 @@
from wagtail.core import blocks
from wagtail.admin.edit_handlers import (
FieldPanel,
StreamFieldPanel,
PageChooserPanel,
HelpPanel,
InlinePanel,
MultiFieldPanel)
MultiFieldPanel,
PageChooserPanel,
StreamFieldPanel,
)
from wagtail.images.blocks import ImageChooserBlock
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.documents.blocks import DocumentChooserBlock
from wagtail.snippets.models import register_snippet
from wagtail.search import index
from wagtail.snippets.models import register_snippet
from django.db.models.signals import m2m_changed
from wagtail.contrib.table_block.blocks import TableBlock
from fec import constants

from home.blocks import (ThumbnailBlock, # AsideLinkBlock,
ContactInfoBlock, CitationsBlock, ResourceBlock,
OptionBlock, CollectionBlock, DocumentFeedBlurb,
ExampleParagraph, ExampleForms, ExampleImage,
CustomTableBlock, ReportingExampleCards, InternalButtonBlock,
ExternalButtonBlock, SnippetChooserBlock)
from home.blocks import (
CitationsBlock,
CollectionBlock,
ContactInfoBlock,
CustomTableBlock,
DocumentChooserBlock,
DocumentFeedBlurb,
ExampleForms,
ExampleImage,
ExampleParagraph,
ExternalButtonBlock,
InternalButtonBlock,
OptionBlock,
ReportingExampleCards,
ResourceBlock,
SnippetChooserBlock,
ThumbnailBlock,
)

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -840,6 +853,149 @@ def get_context(self, request):
return context


# TODO
# We aren't planning to show individual commissioner items,
# only showing them in the list in commissioner_items_feed.html
class CommissionerItem(ContentPage):
related_document = StreamField([
('related_document', DocumentChooserBlock(
required=False,
null=True,
verbose_name='Linked document',
)
)],
blank=True,
)
display_date = models.DateField(default=datetime.date.today)
link_html = models.URLField(
max_length=255,
null=True,
verbose_name='HTML link',
blank=True,
)
link_pdf = models.URLField(
max_length=255,
# help_text='If linking to a Document, use the selector, not this field.',
null=True,
verbose_name='PDF link',
blank=True,
)
link_video = models.URLField(
max_length=255, null=True, verbose_name='Video link', blank=True,
)
category = models.CharField(
choices=constants.commissioner_item_categories.items(),
max_length=255,
null=True
)
commissioners = StreamField([
('commissioner', blocks.PageChooserBlock(
page_type=CommissionerPage, required=False, null=True, verbose_name='Connected commissioner(s)'
)),
])

content_panels = Page.content_panels + [
HelpPanel(
content='<p>This item will automatically be included in the "Statements and Opinions"\
list of any linked Commissioners.</p>',
heading='ITEM HELP',
),
MultiFieldPanel(
[
FieldPanel('link_html'),
FieldPanel('link_pdf'),
FieldPanel('link_video'),
StreamFieldPanel('related_document'),
],
heading='Content'
),
FieldPanel('display_date'),
FieldPanel('category'),
StreamFieldPanel('commissioners', help_text='Not required, but choose as many as needed.'),
]

@property
def slug_category(self):
cat_slug = ''
cat_slug = self.category.split('/')[0]
return cat_slug

@property
def slug_subject(self):
subj_slug = ''
subj_slug = self.category.split('/')[1]
return subj_slug

@property
def pretty_category(self):
parent_category = ''
parent_category = self.category.split('/')[0]

pretty_cat = str(constants.commissioner_item_categories[parent_category])
return pretty_cat

@property
def pretty_subject(self):
pretty_subj = str(constants.commissioner_item_categories[self.category])
# If there's no slash in the category, we're dealing with a category and not a subject
# so return nothing
#
# The 'secondary' category / taxonomy label starts with two special characters
# so they display correctly in the admin pull-downs.
# We're going to pull them off for the pretty label
if len(self.category.split('/')) == 1:
pretty_subj = ''
elif pretty_subj.find('↳ ') == 0:
pretty_subj = pretty_subj[2:]

return pretty_subj

@property
def link_doc(self):
# Check whether the StreamValue has a related document
rel_doc_url = False
for block in self.related_document:
rel_doc_url = block.value.url

return rel_doc_url

@property
def links_count(self):
count = 0
count = count + 1 if self.link_doc else count
count = count + 1 if self.link_html else count
count = count + 1 if self.link_pdf else count
count = count + 1 if self.link_video else count
return count

@property
def links_string(self):
links = []

if self.link_doc:
links.append(
'<i class="icon icon--inline--right icon--inline--left i-document"></i>\
<a href="{}" class="t-sans t-normal">PDF</a>'.format(self.link_doc)
)
if self.link_pdf:
links.append(
'<i class="icon icon--inline--right icon--inline--left i-share"></i>\
<a href="{}" class="t-sans t-normal" target="_blank">PDF</a>'.format(self.link_pdf)
)
if self.link_html:
links.append(
'<i class="icon icon--inline--right icon--inline--left i-share"></i>\
<a href="{}" class="t-sans t-normal" target="_blank">HTML</a>'.format(self.link_html)
)
if self.link_video:
links.append(
'<i class="icon icon--inline--right icon--inline--left i-share"></i>\
<a href="{}" class="t-sans t-normal" target="_blank">VIDEO</a>'.format(self.link_video)
)

return ' | '.join(links)


class CollectionPage(Page):
body = stream_factory(null=True, blank=True)
sidebar_title = models.CharField(max_length=255, null=True, blank=True)
Expand Down
Loading