├── .coveragerc
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .github
└── PULL_REQUEST_TEMPLATE
├── .gitignore
├── .pre-commit-config.yaml
├── LICENSE
├── README.md
├── allegation
├── .gitignore
├── __init__.py
├── admin.py
├── factories.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models
│ ├── __init__.py
│ ├── compiler.py
│ ├── managers.py
│ ├── query.py
│ ├── query_sets.py
│ └── utils.py
├── query_builders.py
├── serializers.py
├── services
│ ├── __init__.py
│ ├── download_allegations.py
│ ├── merge_officers.py
│ └── outcome_analytics.py
├── static
│ ├── allegation
│ │ ├── css
│ │ │ ├── MarkerCluster.Default.css
│ │ │ ├── MarkerCluster.css
│ │ │ └── table.css
│ │ ├── img
│ │ │ ├── 64x_map_marker.png
│ │ │ ├── UCPD-1.jpg
│ │ │ ├── arrow_down.png
│ │ │ ├── arrow_right.png
│ │ │ ├── complaint-flowchart-1.png
│ │ │ ├── complaint-flowchart-2.png
│ │ │ ├── data-ad.png
│ │ │ ├── data-chart.png
│ │ │ ├── dianebond2.jpg
│ │ │ ├── finding-ad.png
│ │ │ ├── findings-main-1.png
│ │ │ ├── graph-1.svg
│ │ │ ├── graph-2.svg
│ │ │ ├── graph-3.svg
│ │ │ ├── methodology.png
│ │ │ ├── story-ad.png
│ │ │ ├── story-main-1.png
│ │ │ ├── story-main-2.png
│ │ │ ├── story-main-3.png
│ │ │ ├── story-main-4.png
│ │ │ └── story-main-5.png
│ │ ├── js
│ │ │ ├── actions
│ │ │ │ ├── ComplaintList
│ │ │ │ │ ├── ComplaintListActions.js
│ │ │ │ │ ├── ComplaintListServerActions.js
│ │ │ │ │ ├── OutcomeAnalysisServerActionCreator.js
│ │ │ │ │ └── OutcomeFilterActions.js
│ │ │ │ ├── DataToolPage
│ │ │ │ │ ├── AllegationActions.js
│ │ │ │ │ ├── OverlayActions.js
│ │ │ │ │ ├── RaceGenderTabActions.js
│ │ │ │ │ ├── RaceGenderTabServerActions.js
│ │ │ │ │ ├── SunburstServerActions.js
│ │ │ │ │ └── TabActions.js
│ │ │ │ ├── DisclaimerActions.js
│ │ │ │ ├── DownloadActions.js
│ │ │ │ ├── DownloadServerActions.js
│ │ │ │ ├── EmbedActions.js
│ │ │ │ ├── FilterActions.js
│ │ │ │ ├── FilterTagsActions.js
│ │ │ │ ├── InvestigatorPage
│ │ │ │ │ └── InvestigatorPageActions.js
│ │ │ │ ├── MapActions.js
│ │ │ │ ├── NavActions.js
│ │ │ │ ├── Officer
│ │ │ │ │ └── CheckMarkActions.js
│ │ │ │ ├── OfficerActions.js
│ │ │ │ ├── OfficerPage
│ │ │ │ │ ├── OfficerPageActions.js
│ │ │ │ │ ├── OfficerPageServerActions.js
│ │ │ │ │ ├── StoryActions.js
│ │ │ │ │ ├── StoryListActions.js
│ │ │ │ │ └── TimelineActions.js
│ │ │ │ ├── RequestDocumentActions.js
│ │ │ │ ├── SessionActions.js
│ │ │ │ ├── ShareBarActions.js
│ │ │ │ ├── SiteTitleActions.js
│ │ │ │ ├── SummaryActions.js
│ │ │ │ ├── SunburstActions.js
│ │ │ │ ├── WagtailPagesActions.js
│ │ │ │ └── WagtailPagesServerActions.js
│ │ │ ├── app.js
│ │ │ ├── components
│ │ │ │ ├── Base.react.js
│ │ │ │ ├── DataToolPage.react.js
│ │ │ │ ├── DataToolPage
│ │ │ │ │ ├── Allegation.react.js
│ │ │ │ │ ├── Allegation
│ │ │ │ │ │ ├── AllegationDetails.react.js
│ │ │ │ │ │ └── AllegationSummary.react.js
│ │ │ │ │ ├── Complaint.react.js
│ │ │ │ │ ├── Complaint
│ │ │ │ │ │ ├── Document.react.js
│ │ │ │ │ │ ├── Documents.react.js
│ │ │ │ │ │ ├── Investigator.react.js
│ │ │ │ │ │ ├── Location.react.js
│ │ │ │ │ │ ├── OfficerList.react.js
│ │ │ │ │ │ ├── PoliceWitness.react.js
│ │ │ │ │ │ ├── RequestModal.react.js
│ │ │ │ │ │ ├── Summary.react.js
│ │ │ │ │ │ ├── Timeline.react.js
│ │ │ │ │ │ └── TimelineAndLocation.react.js
│ │ │ │ │ ├── ComplaintList
│ │ │ │ │ │ ├── OutcomeFilter.react.js
│ │ │ │ │ │ └── OutcomeFilterItem.react.js
│ │ │ │ │ ├── ComplaintListRow.react.js
│ │ │ │ │ ├── ComplaintSection.react.js
│ │ │ │ │ ├── Counter.react.js
│ │ │ │ │ ├── Disclaimer.react.js
│ │ │ │ │ ├── DonutChart.react.js
│ │ │ │ │ ├── Download.react.js
│ │ │ │ │ ├── Embed.react.js
│ │ │ │ │ ├── Embed
│ │ │ │ │ │ └── Mixin.react.js
│ │ │ │ │ ├── FilterTags.react.js
│ │ │ │ │ ├── Footer.react.js
│ │ │ │ │ ├── HorizontalPercentageChart.react.js
│ │ │ │ │ ├── HorizontalPercentageChart
│ │ │ │ │ │ ├── HorizontalBarSVG.react.js
│ │ │ │ │ │ └── LabelBar.react.js
│ │ │ │ │ ├── Map.react.js
│ │ │ │ │ ├── Officer.react.js
│ │ │ │ │ ├── Officer
│ │ │ │ │ │ ├── CheckMark.react.js
│ │ │ │ │ │ ├── Map.react.js
│ │ │ │ │ │ ├── OfficerMixin.react.js
│ │ │ │ │ │ └── Timeline.react.js
│ │ │ │ │ ├── OfficerDetail.react.js
│ │ │ │ │ ├── OfficerDetail
│ │ │ │ │ │ └── OfficerInformation.react.js
│ │ │ │ │ ├── OfficerList.react.js
│ │ │ │ │ ├── Overlay.react.js
│ │ │ │ │ ├── RaceGenderAgeTab.react.js
│ │ │ │ │ ├── Share
│ │ │ │ │ │ ├── ShareBar.react.js
│ │ │ │ │ │ └── ShareButton.react.js
│ │ │ │ │ ├── Summary.react.js
│ │ │ │ │ ├── SummaryChildRow.react.js
│ │ │ │ │ ├── SummaryRow.react.js
│ │ │ │ │ ├── SummarySection
│ │ │ │ │ │ └── ExtraInformation.react.js
│ │ │ │ │ ├── Sunburst.react.js
│ │ │ │ │ ├── Sunburst
│ │ │ │ │ │ ├── Breadcrumb.react.js
│ │ │ │ │ │ ├── Legend.react.js
│ │ │ │ │ │ └── SunburstChartLegend.react.js
│ │ │ │ │ └── Tabs.react.js
│ │ │ │ ├── GlossaryPage.react.js
│ │ │ │ ├── IndexPage.react.js
│ │ │ │ ├── IndexTabContent
│ │ │ │ │ ├── DataPage.react.js
│ │ │ │ │ ├── FindingPage.react.js
│ │ │ │ │ ├── MethodPage.react.js
│ │ │ │ │ └── StoryPage.react.js
│ │ │ │ ├── InvestigatorPage.react.js
│ │ │ │ ├── InvestigatorPage
│ │ │ │ │ ├── InvestigationList.react.js
│ │ │ │ │ ├── InvestigationListRow.react.js
│ │ │ │ │ ├── InvestigationsSection.react.js
│ │ │ │ │ ├── InvestigatorDetail.react.js
│ │ │ │ │ ├── InvestigatorInformation.react.js
│ │ │ │ │ └── Timeline.react.js
│ │ │ │ ├── OfficerPage.react.js
│ │ │ │ ├── OfficerPage
│ │ │ │ │ ├── ComplaintList.react.js
│ │ │ │ │ ├── ComplaintSection.react.js
│ │ │ │ │ ├── RelatedOfficers.react.js
│ │ │ │ │ ├── Story.react.js
│ │ │ │ │ └── StoryList.react.js
│ │ │ │ ├── PageAnimator.react.js
│ │ │ │ ├── Router.react.js
│ │ │ │ ├── Shared
│ │ │ │ │ ├── Back.react.js
│ │ │ │ │ ├── HappyFox.react.js
│ │ │ │ │ ├── HelpText.react.js
│ │ │ │ │ ├── InterfaceText.react.js
│ │ │ │ │ ├── LandingFooter.react.js
│ │ │ │ │ ├── LoadingPage.react.js
│ │ │ │ │ ├── Logo.react.js
│ │ │ │ │ ├── Nav2.react.js
│ │ │ │ │ ├── ReadMore.react.js
│ │ │ │ │ ├── Search.react.js
│ │ │ │ │ ├── SiteLinks.react.js
│ │ │ │ │ ├── SiteTitle.react.js
│ │ │ │ │ ├── StatePropagateCSSTransitionGroup.react.js
│ │ │ │ │ └── StatePropagateCSSTransitionGroupChild.react.js
│ │ │ │ ├── Wagtail
│ │ │ │ │ ├── GlossaryTableRow.react.js
│ │ │ │ │ ├── GlossaryTableSection.react.js
│ │ │ │ │ └── RowSection.react.js
│ │ │ │ └── WagtailPage.react.js
│ │ │ ├── constants
│ │ │ │ ├── AppConstants.js
│ │ │ │ ├── MapConstants.js
│ │ │ │ └── RequestDocumentConstants.js
│ │ │ ├── dispatcher
│ │ │ │ └── AppDispatcher.js
│ │ │ ├── keyboardShortcuts.js
│ │ │ ├── mixins
│ │ │ │ └── IndexTabContentMixin.js
│ │ │ ├── presenters
│ │ │ │ ├── AllegationPresenterFactory.js
│ │ │ │ ├── ComplainingWitnessPresenter.js
│ │ │ │ ├── ComplaintPresenter.js
│ │ │ │ ├── DocumentPresenter.js
│ │ │ │ ├── GenderPresenter.js
│ │ │ │ ├── InvestigatorPresenter.js
│ │ │ │ ├── OfficerPresenter.js
│ │ │ │ └── RequestDocumentErrorPresenter.js
│ │ │ ├── stores
│ │ │ │ ├── AppStore.js
│ │ │ │ ├── Base.js
│ │ │ │ ├── Complaint
│ │ │ │ │ └── AllegationDetailsStore.js
│ │ │ │ ├── ComplaintListStore.js
│ │ │ │ ├── DataToolPage
│ │ │ │ │ ├── OverlayStore.js
│ │ │ │ │ ├── RaceGenderAgeTabStore.js
│ │ │ │ │ ├── ShareButtonStore.js
│ │ │ │ │ └── TabsStore.js
│ │ │ │ ├── DisclaimerStore.js
│ │ │ │ ├── DownloadStore.js
│ │ │ │ ├── EmbedStore.js
│ │ │ │ ├── FilterTagStore.js
│ │ │ │ ├── InvestigatorPageStore.js
│ │ │ │ ├── MapStore.js
│ │ │ │ ├── NavStore.js
│ │ │ │ ├── Officer
│ │ │ │ │ ├── CheckMarkStore.js
│ │ │ │ │ └── StoryListStore.js
│ │ │ │ ├── OfficerListStore.js
│ │ │ │ ├── OfficerPage
│ │ │ │ │ ├── ComplaintSectionStore.js
│ │ │ │ │ ├── RelatedOfficersStore.js
│ │ │ │ │ ├── StoryStore.js
│ │ │ │ │ └── TimelineStore.js
│ │ │ │ ├── OfficerPageStore.js
│ │ │ │ ├── SessionStore.js
│ │ │ │ ├── SiteTitleStore.js
│ │ │ │ ├── SummaryStore.js
│ │ │ │ ├── SunburstStore.js
│ │ │ │ └── WagtailPagesStore.js
│ │ │ ├── sunburst-app.js
│ │ │ ├── test-preprocessor.js
│ │ │ ├── test_utils
│ │ │ │ ├── ElementUtils.js
│ │ │ │ └── Factory.js
│ │ │ ├── tests
│ │ │ │ ├── actions
│ │ │ │ │ ├── FilterTagsActions.js
│ │ │ │ │ ├── OverlayActions.js
│ │ │ │ │ └── ShareBar.js
│ │ │ │ ├── components
│ │ │ │ │ ├── DataToolPage
│ │ │ │ │ │ ├── Allegation
│ │ │ │ │ │ │ └── AllegationSummary.js
│ │ │ │ │ │ ├── Complaint
│ │ │ │ │ │ │ ├── Document.js
│ │ │ │ │ │ │ └── Documents.js
│ │ │ │ │ │ ├── HorizontalPercentageChart
│ │ │ │ │ │ │ ├── HorizontalBarSVG.js
│ │ │ │ │ │ │ └── LabelBar.js
│ │ │ │ │ │ ├── Overlay.js
│ │ │ │ │ │ ├── RaceGenderAgeTab.js
│ │ │ │ │ │ └── Share
│ │ │ │ │ │ │ └── ShareBar.js
│ │ │ │ │ ├── HorizontalPercentageChart.js
│ │ │ │ │ ├── Shared
│ │ │ │ │ │ ├── InterfaceText.js
│ │ │ │ │ │ ├── Nav2.js
│ │ │ │ │ │ └── SiteTitle.js
│ │ │ │ │ ├── Wagtail
│ │ │ │ │ │ ├── GlossaryTableSection.js
│ │ │ │ │ │ └── RowSection.js
│ │ │ │ │ └── WagtailPage.js
│ │ │ │ ├── factories
│ │ │ │ │ ├── ComplaintFactory.js
│ │ │ │ │ └── DocumentFactory.js
│ │ │ │ ├── presenters
│ │ │ │ │ ├── AllegationPresenterFactory.js
│ │ │ │ │ ├── DocumentPresenter.js
│ │ │ │ │ └── RequestDocumentErrorPresenter.js
│ │ │ │ ├── stores
│ │ │ │ │ ├── DataToolPage
│ │ │ │ │ │ ├── OverlayStore.js
│ │ │ │ │ │ ├── RaceGenderAgeTabStore.js
│ │ │ │ │ │ └── ShareButton.js
│ │ │ │ │ └── FilterTagStore.js
│ │ │ │ └── utils
│ │ │ │ │ ├── DOMUtils.js
│ │ │ │ │ ├── RaceGenderAPITransformation.js
│ │ │ │ │ ├── calculatePercentages.js
│ │ │ │ │ └── tests
│ │ │ │ │ └── Factory.js
│ │ │ └── utils
│ │ │ │ ├── AllegationAPI.js
│ │ │ │ ├── ComplaintListAPI.js
│ │ │ │ ├── DOMUtils.js
│ │ │ │ ├── DateTimeUtil.js
│ │ │ │ ├── DocumentCloudAPI.js
│ │ │ │ ├── DownloadAPI.js
│ │ │ │ ├── InterfaceTextUtil.js
│ │ │ │ ├── InvestigatorPageAPI.js
│ │ │ │ ├── MapAPI.js
│ │ │ │ ├── MobileUtils.js
│ │ │ │ ├── OfficerPageAPIUtil.js
│ │ │ │ ├── OutcomeAnalysisAPI.js
│ │ │ │ ├── RaceGenderAPI.js
│ │ │ │ ├── RaceGenderAPITransformation.js
│ │ │ │ ├── SessionAPI.js
│ │ │ │ ├── StoryListAPI.js
│ │ │ │ ├── SunburstAPI.js
│ │ │ │ ├── TagUtil.js
│ │ │ │ ├── TimelineAPI.js
│ │ │ │ ├── WagtailPagesAPI.js
│ │ │ │ ├── api
│ │ │ │ └── APIUtil.js
│ │ │ │ ├── calculatePercentages.js
│ │ │ │ ├── d3utils
│ │ │ │ └── SunburstChartD3.js
│ │ │ │ ├── jQuery.js
│ │ │ │ ├── location.js
│ │ │ │ ├── querybuilders
│ │ │ │ ├── AllegationFetcherQueryBuilder.js
│ │ │ │ ├── AllegationFilterTagsQueryBuilder.js
│ │ │ │ ├── AllegationOfficerQueryBuilder.js
│ │ │ │ ├── AllegationOutcomeFilterQueryBuilder.js
│ │ │ │ └── QueryBuilderUtil.js
│ │ │ │ └── tests
│ │ │ │ ├── Factory.js
│ │ │ │ ├── f.js
│ │ │ │ └── should.js
│ │ └── package.json
│ └── icomoon
│ │ ├── fonts
│ │ ├── icomoon.eot
│ │ ├── icomoon.svg
│ │ ├── icomoon.ttf
│ │ └── icomoon.woff
│ │ └── icomoon.css
├── tasks.py
├── templates
│ └── allegation
│ │ ├── allegation_list.html
│ │ ├── base.html
│ │ ├── disclaimer.html
│ │ ├── home.html
│ │ ├── index.html
│ │ ├── landing
│ │ ├── find_page.html
│ │ ├── methodology_page.html
│ │ ├── request_file_form.html
│ │ ├── sign_up_form.html
│ │ └── story_page.html
│ │ └── sunburst.html
├── tests
│ ├── __init__.py
│ ├── constants.py
│ ├── live
│ │ ├── __init__.py
│ │ ├── test_db_integrity.py
│ │ └── test_server_integrity.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── query.py
│ │ ├── test_models_utils.py
│ │ ├── test_officer.py
│ │ └── test_query_set_manager.py
│ ├── query_builders
│ │ ├── __init__.py
│ │ └── test_officer_allegation_query_builder.py
│ ├── serializers
│ │ ├── __init__.py
│ │ └── test_sunburst_serializer.py
│ ├── services
│ │ ├── __init__.py
│ │ ├── test_download_allegations.py
│ │ ├── test_merge_officers.py
│ │ └── test_outcome_analytics.py
│ ├── utils
│ │ ├── allegation_row_helper_mixin.py
│ │ ├── autocomplete_test_helper_mixin.py
│ │ ├── filter_tags_test_mixin.py
│ │ └── outcome_filter.py
│ ├── utils_tests
│ │ ├── __init__.py
│ │ └── test_session.py
│ └── views
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── test_allegation_area_api_view.py
│ │ ├── test_allegation_download_view.py
│ │ ├── test_allegation_search_view.py
│ │ ├── test_allegation_sunburst_api_view.py
│ │ ├── test_allegation_view.py
│ │ ├── test_home_page.py
│ │ ├── test_init_view.py
│ │ ├── test_officer_allegation_analysis_api_view.py
│ │ ├── test_officer_allegation_api_view.py
│ │ ├── test_officer_allegation_cluster_api_view.py
│ │ ├── test_officer_allegation_filter_data_source.py
│ │ ├── test_officer_allegation_gis_api_view.py
│ │ ├── test_officer_allegation_officer_api_view.py
│ │ ├── test_officer_allegation_summary_api_view.py
│ │ ├── test_police_witness_api_view.py
│ │ ├── test_race_gender_api_view.py
│ │ ├── test_session_view.py
│ │ ├── test_sunburst_image_view.py
│ │ └── ui
│ │ ├── __init__.py
│ │ ├── test_active_officer.py
│ │ ├── test_active_tab_ui.py
│ │ ├── test_allegation_detail.py
│ │ ├── test_allegation_filter_ui.py
│ │ ├── test_allegation_summary.py
│ │ ├── test_datatool_categories_tab.py
│ │ ├── test_download_allegation.py
│ │ ├── test_embed_mode.py
│ │ ├── test_home_page.py
│ │ ├── test_mobile_display.py
│ │ ├── test_officer_detail_page.py
│ │ ├── test_race_gender_age_tab.py
│ │ ├── test_redirect_mobile_urls_to_desktop.py
│ │ ├── test_site_title.py
│ │ └── test_sunburst_page.py
├── urls.py
├── utils
│ ├── __init__.py
│ ├── date.py
│ ├── query.py
│ └── session.py
└── views
│ ├── __init__.py
│ ├── allegation_download_view.py
│ ├── allegation_search_view.py
│ ├── allegation_view.py
│ ├── landing_view.py
│ ├── officer_allegation_analysis_api_view.py
│ ├── officer_allegation_api_view.py
│ ├── officer_allegation_race_gender_api.py
│ ├── officer_allegation_sunburst_view.py
│ ├── session_view.py
│ ├── sunburst_image_view.py
│ └── sunburst_view.py
├── api
├── __init__.py
├── admin.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_setting_export_excel_disclaimer.py
│ ├── 0003_add_meta_description_and_keywords.py
│ └── __init__.py
├── models
│ └── __init__.py
├── serializers
│ ├── __init__.py
│ ├── filter_log_serializer.py
│ ├── interfacetext_serializer.py
│ ├── investigator_serializer.py
│ ├── officer_serializer.py
│ ├── session_alias_serializer.py
│ ├── session_analytic_serializer.py
│ ├── session_serializer.py
│ ├── setting_serializer.py
│ ├── story_serializer.py
│ └── suggestion_log_serializer.py
├── tests
│ ├── __init__.py
│ └── views
│ │ ├── __init__.py
│ │ └── test_session_view.py
├── urls.py
└── views
│ ├── __init__.py
│ ├── officer_view.py
│ └── session_view.py
├── bin
├── collect_static
├── install_bower
├── post_compile
├── shows_pr_since_last_deploy
├── start_dev.sh
└── stop_dev.sh
├── circle.yml
├── common
├── __init__.py
├── actions.py
├── admin.py
├── apps.py
├── constants.py
├── data
│ └── category.csv
├── decorators.py
├── factories
│ └── __init__.py
├── fixtures
│ ├── area.json
│ ├── beats.js
│ └── neighborhoods.js
├── json_serializer.py
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ ├── base_process_allegation_from_pdf.py
│ │ ├── build_google_sitemap.py
│ │ ├── calculate_allegations_count.py
│ │ ├── capitalize_officer_name.py
│ │ ├── capture_homepage_screen.py
│ │ ├── check_beat_and_point.py
│ │ ├── clean_officer_names.py
│ │ ├── correct_allegation_outcome_finding.py
│ │ ├── extract_allegations_from_pdf_to_csv.py
│ │ ├── extract_allegations_from_pdf_to_database.py
│ │ ├── fix_final_finding_null.py
│ │ ├── fix_race.py
│ │ ├── generate_sunburst_csv.py
│ │ ├── geocode_allegations.py
│ │ ├── get_allegation_date_only.py
│ │ ├── import_allegation_csv.py
│ │ ├── import_beat_data.py
│ │ ├── import_complaint_accused.py
│ │ ├── import_data.py
│ │ ├── import_extended_witness_data.py
│ │ ├── import_investigator_data.py
│ │ ├── import_new_data.py
│ │ ├── import_officer_birth_year.py
│ │ ├── import_police_officer_witness.py
│ │ ├── import_star_data.py
│ │ ├── import_witness_data.py
│ │ ├── increase_school_radius.py
│ │ ├── insert_thankyou_message_interface_text.py
│ │ ├── investigator_summary.py
│ │ ├── migrate_session_filters.py
│ │ ├── normalize_race_data.py
│ │ ├── populate_documents_for_allegation.py
│ │ ├── prewarm_caches.py
│ │ ├── reimport_school_grounds.py
│ │ ├── set_final_outcome.py
│ │ ├── update_allegation_category_names.py
│ │ └── update_documents.py
├── middleware
│ ├── __init__.py
│ ├── cache.py
│ ├── json_as_html.py
│ ├── mobile_redirect.py
│ ├── subdomain.py
│ └── user_agent.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_documentcrawler.py
│ ├── 0003_officerallegation_officer_age.py
│ ├── 0004_officerallegation_officer_age_data.py
│ ├── 0005_remove_document_fields_from_allegation.py
│ ├── 0006_create_officeralias_table.py
│ ├── 0007_create_officerbadgenumber_table.py
│ ├── 0008_create_policeunit_table.py
│ ├── 0009_policeunit_data.py
│ ├── 0010_rename_unit_column.py
│ └── __init__.py
├── models
│ ├── __init__.py
│ ├── suggestible.py
│ └── time_stamp.py
├── services
│ ├── __init__.py
│ └── lookup_service.py
├── signals
│ ├── __init__.py
│ └── handlers.py
├── static
│ ├── fonts
│ │ ├── SF-Compact-Display-Black.otf
│ │ ├── SF-Compact-Display-Bold.otf
│ │ ├── SF-Compact-Display-Heavy.otf
│ │ ├── SF-Compact-Display-Light.otf
│ │ ├── SF-Compact-Display-Medium.otf
│ │ ├── SF-Compact-Display-Regular.otf
│ │ ├── SF-Compact-Display-Semibold.otf
│ │ ├── SF-Compact-Display-Thin.otf
│ │ ├── SF-Compact-Display-Ultralight.otf
│ │ ├── SF-Compact-Text-Bold.otf
│ │ ├── SF-Compact-Text-BoldItalic.otf
│ │ ├── SF-Compact-Text-Heavy.otf
│ │ ├── SF-Compact-Text-HeavyItalic.otf
│ │ ├── SF-Compact-Text-Light.otf
│ │ ├── SF-Compact-Text-LightItalic.otf
│ │ ├── SF-Compact-Text-Medium.otf
│ │ ├── SF-Compact-Text-MediumItalic.otf
│ │ ├── SF-Compact-Text-Regular.otf
│ │ ├── SF-Compact-Text-RegularItalic.otf
│ │ ├── SF-Compact-Text-Semibold.otf
│ │ └── SF-Compact-Text-SemiboldItalic.otf
│ ├── img
│ │ ├── 64x_map_marker.png
│ │ ├── complaint_process.png
│ │ ├── cpdp-logo.svg
│ │ ├── default.gif
│ │ ├── favicon.ico
│ │ ├── ii-logo-hover.svg
│ │ ├── ii-logo.svg
│ │ ├── logo.png
│ │ ├── logox2.png
│ │ ├── map-fade-hover.png
│ │ ├── map-fade.png
│ │ ├── map.png
│ │ ├── page-header.png
│ │ └── rackspace.svg
│ ├── js
│ │ ├── acorn.js
│ │ ├── ajax_loading_animation.js
│ │ ├── blanket.js
│ │ ├── foot_define.js
│ │ ├── head_define.js
│ │ ├── jquery-ui.custom.min.js
│ │ ├── jquery.mobile.custom.min.js
│ │ └── selenium_coverage.js
│ ├── sass
│ │ ├── data_tool_page.sass
│ │ ├── data_tool_page
│ │ │ ├── embed.sass
│ │ │ ├── horizontal_percentage_chart.sass
│ │ │ ├── race_gender_age_tab.sass
│ │ │ ├── race_gender_tab.sass
│ │ │ └── share.sass
│ │ ├── donut-chart.sass
│ │ ├── glossary_page.sass
│ │ ├── landing_page
│ │ │ └── style.sass
│ │ ├── mobile.sass
│ │ ├── officer-detail.sass
│ │ ├── officer-profile.sass
│ │ ├── officer_page.sass
│ │ ├── search.sass
│ │ ├── shared.sass
│ │ ├── shared
│ │ │ ├── loading_page.sass
│ │ │ ├── overlay.sass
│ │ │ ├── sf-compact-font.sass
│ │ │ └── site-links.sass
│ │ ├── style.sass
│ │ ├── sunburst.sass
│ │ ├── test.sass
│ │ └── wagtail
│ │ │ └── glossary-table-section.sass
│ ├── sunburst.html
│ ├── sunburst.json
│ └── sunburst
│ │ ├── d3.v3.min.js
│ │ ├── font.css
│ │ ├── sequences.css
│ │ └── sequences.js
├── templates
│ ├── 404.html
│ ├── 500.html
│ ├── _footer_nav.html
│ ├── _notification.html
│ ├── _notification_message.html
│ ├── _top_banner.html
│ ├── _top_nav.html
│ ├── base.html
│ ├── common
│ │ └── user_name_block.html
│ ├── general
│ │ ├── form_render.html
│ │ └── form_requirement.html
│ ├── google_analytics.html
│ └── homepage.html
├── templatetags
│ ├── __init__.py
│ ├── bootstrap.py
│ ├── common_filters.py
│ └── common_tags.py
├── tests
│ ├── __init__.py
│ ├── admin
│ │ ├── __init__.py
│ │ └── test_export_csv.py
│ ├── core.py
│ ├── integrations
│ │ ├── __init__.py
│ │ ├── test_google_analytics.py
│ │ ├── test_redirect_mobile.py
│ │ └── test_sub_domain.py
│ ├── management
│ │ ├── __init__.py
│ │ └── commands
│ │ │ ├── Test-Data-Officers-Appt_date_and_stars.csv
│ │ │ ├── __init__.py
│ │ │ ├── test_capitalize_officer_name.py
│ │ │ ├── test_clean_officer_names.py
│ │ │ ├── test_fix_final_finding_null.py
│ │ │ ├── test_fix_race.py
│ │ │ ├── test_import_star_data.py
│ │ │ ├── test_increase_school_radius.py
│ │ │ ├── test_insert_thankyou_message_interface_text.py
│ │ │ ├── test_normalize_race_data.py
│ │ │ ├── test_officer_profile_link.py
│ │ │ ├── test_reimport_school_grounds.py
│ │ │ └── test_update_document.py
│ ├── middleware
│ │ ├── __init__.py
│ │ └── test_user_agent.py
│ ├── mixins
│ │ ├── __init__.py
│ │ ├── outcome_filter_mixin.py
│ │ └── sunburst_chart_mixin.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── test_investigator_model.py
│ │ └── test_suggestible.py
│ ├── runner.py
│ ├── services
│ │ ├── __init__.py
│ │ └── test_lookup_service.py
│ ├── test_transforms.py
│ ├── test_utils.py
│ ├── utils
│ │ ├── __init__.py
│ │ └── test_mobile_url_hash_util.py
│ └── views
│ │ ├── __init__.py
│ │ └── test_lookup_view.py
├── transforms.py
├── urls.py
├── utils
│ ├── __init__.py
│ ├── geocode.py
│ ├── hashid.py
│ ├── haystack.py
│ ├── http_request.py
│ └── mobile_url_hash_util.py
└── views
│ ├── __init__.py
│ └── lookup_view.py
├── cpdb
├── __init__.py
├── celery.py
├── context_precessors.py
├── loaders.py
├── settings
│ ├── __init__.py
│ ├── base.py
│ ├── local
│ │ ├── __init__.py
│ │ └── common.py
│ ├── prod
│ │ ├── __init__.py
│ │ ├── common.py
│ │ ├── digitalocean.py
│ │ └── staging.py
│ └── test
│ │ ├── __init__.py
│ │ ├── circleci.py
│ │ └── common.py
├── urls.py
└── wsgi.py
├── dashboard
├── __init__.py
├── admin.py
├── authentication.py
├── exceptions.py
├── forms
│ ├── __init__.py
│ ├── alias_form.py
│ ├── document_request_status_form.py
│ ├── officer_form.py
│ └── session_alias_form.py
├── migrations
│ └── __init__.py
├── models
│ └── __init__.py
├── query_builders.py
├── serializers.py
├── services
│ ├── __init__.py
│ └── documentcloud_service.py
├── static
│ └── dashboard
│ │ ├── js
│ │ ├── actions
│ │ │ ├── DocumentSection
│ │ │ │ ├── AddDocumentLinkModalActions.js
│ │ │ │ ├── DocumentActions.js
│ │ │ │ ├── DocumentCloudActions.js
│ │ │ │ ├── DocumentCrawlStatActions.js
│ │ │ │ ├── DocumentListActions.js
│ │ │ │ └── TabsActions.js
│ │ │ ├── InterfaceTextActions.js
│ │ │ ├── NavigationActions.js
│ │ │ ├── OfficerSection
│ │ │ │ ├── Officer
│ │ │ │ │ ├── ProfileActions.js
│ │ │ │ │ ├── StoryFormActions.js
│ │ │ │ │ ├── StoryListActions.js
│ │ │ │ │ └── TabsActions.js
│ │ │ │ ├── OfficerActions.js
│ │ │ │ ├── OfficerListActions.js
│ │ │ │ └── SearchActions.js
│ │ │ ├── OfficerSectionActions.js
│ │ │ ├── OverviewSection
│ │ │ │ ├── NewSessionPerDayChartActions.js
│ │ │ │ ├── PeriodPickerActions.js
│ │ │ │ └── QueryItemListActions.js
│ │ │ ├── SearchSection
│ │ │ │ ├── AddAliasModalActions.js
│ │ │ │ ├── AddAliasModalServerActions.js
│ │ │ │ ├── QueryListActions.js
│ │ │ │ ├── QueryListFilterActions.js
│ │ │ │ ├── SearchActions.js
│ │ │ │ └── SearchResultsActions.js
│ │ │ ├── SearchTrafficServerActions.js
│ │ │ ├── SessionSection
│ │ │ │ ├── AddSessionAliasModalActions.js
│ │ │ │ ├── AddSessionAliasModalServerActions.js
│ │ │ │ ├── SessionsActions.js
│ │ │ │ ├── SessionsAliasActions.js
│ │ │ │ └── TabsActions.js
│ │ │ └── SettingActions.js
│ │ ├── app.js
│ │ ├── components
│ │ │ ├── Base.react.js
│ │ │ ├── Content.react.js
│ │ │ ├── DocumentSection.react.js
│ │ │ ├── DocumentSection
│ │ │ │ ├── AddDocumentLinkModal.react.js
│ │ │ │ ├── Document.react.js
│ │ │ │ ├── DocumentCrawlLog.react.js
│ │ │ │ ├── DocumentCrawlStats.react.js
│ │ │ │ ├── DocumentList.react.js
│ │ │ │ ├── DocumentMixin.js
│ │ │ │ ├── QueryList.react.js
│ │ │ │ ├── Tabs.react.js
│ │ │ │ └── UploadDocumentModal.react.js
│ │ │ ├── Form
│ │ │ │ └── Mixin.react.js
│ │ │ ├── InterfaceTextSection.react.js
│ │ │ ├── Navigation.react.js
│ │ │ ├── Navigation
│ │ │ │ └── Item.react.js
│ │ │ ├── OfficerSection.react.js
│ │ │ ├── OfficerSection
│ │ │ │ ├── Officer.react.js
│ │ │ │ ├── Officer
│ │ │ │ │ ├── Profile.react.js
│ │ │ │ │ ├── StoryForm.react.js
│ │ │ │ │ ├── StoryList.react.js
│ │ │ │ │ └── Tabs.react.js
│ │ │ │ ├── OfficerList.react.js
│ │ │ │ └── Search.react.js
│ │ │ ├── OverviewSection.react.js
│ │ │ ├── OverviewSection
│ │ │ │ ├── NewSessionPerDay.react.js
│ │ │ │ ├── NewSessionPerDay
│ │ │ │ │ └── NewSessionPerDayChart.react.js
│ │ │ │ ├── PeriodPicker.react.js
│ │ │ │ ├── QueryItem.react.js
│ │ │ │ ├── QueryItemList.react.js
│ │ │ │ └── SearchTrafficChart.react.js
│ │ │ ├── Period.react.js
│ │ │ ├── SearchSection.react.js
│ │ │ ├── SearchSection
│ │ │ │ ├── AddAliasModal.react.js
│ │ │ │ ├── QueryList.react.js
│ │ │ │ ├── QueryListFilter.react.js
│ │ │ │ └── Search.react.js
│ │ │ ├── SessionSection.react.js
│ │ │ ├── SessionSection
│ │ │ │ ├── AddSessionAliasModal.react.js
│ │ │ │ ├── Search.react.js
│ │ │ │ ├── SessionAliasList.react.js
│ │ │ │ ├── SessionHistory.react.js
│ │ │ │ ├── SessionList.react.js
│ │ │ │ └── Tabs.react.js
│ │ │ ├── SettingSection.react.js
│ │ │ └── Shared
│ │ │ │ ├── BootstrapSelectInput.react.js
│ │ │ │ ├── BootstrapTextInput.react.js
│ │ │ │ ├── DropzoneUpload.react.js
│ │ │ │ └── Icon.react.js
│ │ ├── constants
│ │ │ └── AppConstants.js
│ │ ├── dispatcher
│ │ │ └── AppDispatcher.js
│ │ ├── presenters
│ │ │ └── AllegationDocumentPresenter.js
│ │ ├── stores
│ │ │ ├── Base.js
│ │ │ ├── ContentStore.js
│ │ │ ├── DocumentSection
│ │ │ │ ├── AddDocumentLinkModalStore.js
│ │ │ │ ├── DocumentCrawlStatStore.js
│ │ │ │ ├── DocumentListStore.js
│ │ │ │ ├── DocumentStore.js
│ │ │ │ └── TabsStore.js
│ │ │ ├── DocumentSectionStore.js
│ │ │ ├── InterfaceTextSectionStore.js
│ │ │ ├── NavigationStore.js
│ │ │ ├── OfficerSection
│ │ │ │ ├── Officer
│ │ │ │ │ ├── ProfileStore.js
│ │ │ │ │ ├── StoryFormStore.js
│ │ │ │ │ ├── StoryListStore.js
│ │ │ │ │ └── TabsStore.js
│ │ │ │ ├── OfficerListStore.js
│ │ │ │ ├── OfficerStore.js
│ │ │ │ └── SearchStore.js
│ │ │ ├── OfficerSectionStore.js
│ │ │ ├── OverviewSection
│ │ │ │ ├── NewSessionPerDay
│ │ │ │ │ └── NewSessionPerDayChartStore.js
│ │ │ │ ├── PeriodPickerStore.js
│ │ │ │ ├── QueryListItemStore.js
│ │ │ │ └── SearchTrafficChartStore.js
│ │ │ ├── SearchSection
│ │ │ │ ├── AddAliasModalStore.js
│ │ │ │ ├── QueryListFilterStore.js
│ │ │ │ ├── QueryListStore.js
│ │ │ │ └── SearchStore.js
│ │ │ ├── SessionSection
│ │ │ │ ├── AddSessionAliasModalStore.js
│ │ │ │ ├── SessionAliasListStore.js
│ │ │ │ ├── SessionListStore.js
│ │ │ │ └── SessionSearchStore.js
│ │ │ ├── SessionSectionStore.js
│ │ │ └── SettingSectionStore.js
│ │ ├── tests
│ │ │ └── components
│ │ │ │ ├── DocumentSection.js
│ │ │ │ ├── DocumentSection
│ │ │ │ └── UploadDocumentModal.js
│ │ │ │ └── Shared
│ │ │ │ ├── BootstrapTextInput.js
│ │ │ │ └── DropzoneUpload.js
│ │ └── utils
│ │ │ ├── AliasAPI.js
│ │ │ ├── CollectionUtils.js
│ │ │ ├── DateTimeUtil.js
│ │ │ ├── DocumentCloudAPI.js
│ │ │ ├── DocumentCrawlStatAPI.js
│ │ │ ├── DocumentRequestAPI.js
│ │ │ ├── DocumentRequestAnalysisAPI.js
│ │ │ ├── DocumentRequestStatusAPI.js
│ │ │ ├── FilterLogPresenter.js
│ │ │ ├── InterfaceTextAPI.js
│ │ │ ├── NewSessionAnalyticAPI.js
│ │ │ ├── OfficerAPI.js
│ │ │ ├── SearchResultsAPI.js
│ │ │ ├── SearchTrafficAPI.js
│ │ │ ├── SessionAliasAPI.js
│ │ │ ├── SessionsAPI.js
│ │ │ ├── SettingAPI.js
│ │ │ ├── StoryAPI.js
│ │ │ └── SuggestionLogPresenter.js
│ │ └── sass
│ │ ├── bootstrap_override.sass
│ │ ├── document_section.sass
│ │ ├── navigation.sass
│ │ ├── navigation
│ │ └── item.sass
│ │ ├── officer_section.sass
│ │ ├── overview_section.sass
│ │ ├── overview_section
│ │ ├── period_picker.sass
│ │ └── query_item_list.sass
│ │ ├── search_section.sass
│ │ ├── search_section
│ │ ├── query_list.sass
│ │ ├── query_list_filter.sass
│ │ └── search.sass
│ │ ├── session_section.sass
│ │ ├── session_section
│ │ └── session_history.sass
│ │ ├── setting_section
│ │ └── react_tags.sass
│ │ ├── style.sass
│ │ ├── variables.sass
│ │ └── vendor
│ │ └── react-select.sass
├── templates
│ └── dashboard
│ │ └── index.html
├── tests
│ ├── __init__.py
│ ├── integrations
│ │ ├── __init__.py
│ │ ├── test_document_request.py
│ │ ├── test_interfacetext.py
│ │ ├── test_officer_profile.py
│ │ ├── test_search_results.py
│ │ ├── test_sessions.py
│ │ └── test_settings.py
│ ├── services
│ │ ├── __init__.py
│ │ └── test_documentcloud_service.py
│ ├── test_allegation_resource.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_admin_allegation_request_analysis_view.py
│ │ ├── test_admin_investigation_documents_export_view.py
│ │ ├── test_admin_upload_document_view.py
│ │ ├── test_alias_view.py
│ │ ├── test_allegation_request_view.py
│ │ ├── test_document_link_view.py
│ │ ├── test_document_request_status_view.py
│ │ ├── test_officer_view.py
│ │ ├── test_query_data_view.py
│ │ ├── test_search_traffic_view.py
│ │ ├── test_session_alias_view.py
│ │ ├── test_session_analytic_view.py
│ │ ├── test_session_view.py
│ │ └── test_story_type_view.py
├── urls.py
├── utils
│ ├── __init__.py
│ └── document_cloud_utils.py
└── views
│ ├── __init__.py
│ ├── admin_allegation_request_analysis_view.py
│ ├── admin_analysis_dashboard_view.py
│ ├── admin_document_upload_view.py
│ ├── admin_investigation_documents_export_view.py
│ ├── admin_session_alias_view.py
│ ├── admin_session_analytics_view.py
│ ├── alias_view.py
│ ├── allegation_request_view.py
│ ├── crawl_stats.py
│ ├── document_link_view.py
│ ├── document_request_status_view.py
│ ├── interfacetext_view.py
│ ├── officer_view.py
│ ├── query_data_view.py
│ ├── search_traffic.py
│ ├── sessions_view.py
│ ├── settings_view.py
│ ├── story_type_view.py
│ └── story_view.py
├── document
├── __init__.py
├── apps.py
├── factories.py
├── forms.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_requestemail_session.py
│ ├── 0003_document.py
│ ├── 0004_requestmail_session_nullable.py
│ ├── 0005_reference_requestemail_to_document.py
│ └── __init__.py
├── models
│ ├── __init__.py
│ └── document_request_query_set.py
├── response.py
├── signals
│ ├── __init__.py
│ └── handlers.py
├── tasks.py
├── templates
│ └── document
│ │ └── view.html
├── tests
│ ├── __init__.py
│ ├── forms
│ │ └── test_request_email_form.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── test_document_model.py
│ │ ├── test_document_request_query_set.py
│ │ └── test_query_set_manager.py
│ ├── test_response.py
│ ├── test_utils.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_request_view.py
│ │ └── ui
│ │ └── __init__.py
├── urls.py
├── utils.py
└── views
│ ├── __init__.py
│ └── request_view.py
├── embed
├── __init__.py
├── migrations
│ └── __init__.py
├── models
│ └── __init__.py
├── static
│ └── embed
│ │ ├── css
│ │ └── embed.css
│ │ └── test.html
├── templates
│ └── embed
│ │ └── embed.html
├── tests
│ ├── __init__.py
│ └── views
│ │ └── __init__.py
├── urls.py
└── views
│ ├── __init__.py
│ └── embed_view.py
├── graph
├── __init__.py
├── migrations
│ └── __init__.py
└── static
│ └── graph
│ └── css
│ └── complained-officers.css
├── gulp_tasks
├── build_allegation_js.js
├── build_allegation_sass.js
├── build_dashboard_js.js
├── build_dashboard_sass.js
├── build_mobile_js.js
├── build_mobile_sass.js
├── build_sunburst_js.js
├── build_test_sass.js
├── collect_all_templates.js
├── collect_bower_fonts.js
├── collectstatic.js
├── mkdir.js
├── transform_allegation_base_template.js
├── transform_allegation_template.js
├── transform_base_template.js
├── transform_dashboard_template.js
├── transform_mobile_template.js
├── transform_sunburst_template.js
├── utils
│ ├── build_js.js
│ ├── build_sass.js
│ ├── replace_static_tag_with_real_path.js
│ └── watch_js.js
├── watch_allegation_js.js
├── watch_dashboard_js.js
└── watch_mobile_js.js
├── gulpfile.js
├── install_phantomjs.sh
├── investigator
├── __init__.py
├── migrations
│ └── __init__.py
├── services
│ ├── __init__.py
│ ├── investigator_details_service.py
│ └── timeline_service.py
├── tests
│ ├── __init__.py
│ ├── integrations
│ │ ├── __init__.py
│ │ └── test_browse_investigator_page.py
│ ├── services
│ │ ├── __init__.py
│ │ ├── test_investigator_details_service.py
│ │ └── test_timeline_service.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_investigator_detail_view.py
│ │ └── ui
│ │ ├── __init__.py
│ │ ├── test_investigator_outcome_filter.py
│ │ └── test_investigator_view.py
├── urls.py
└── views
│ ├── __init__.py
│ └── investigator_detail_view.py
├── manage.py
├── mobile
├── __init__.py
├── admin.py
├── constants.py
├── exceptions
│ ├── __init__.py
│ └── bad_request_api_exception.py
├── migrations
│ └── __init__.py
├── models.py
├── serializers
│ ├── __init__.py
│ ├── mobile_allegation_view_serializer.py
│ ├── mobile_document_request_view_serializer.py
│ ├── mobile_interfacetext_serializer.py
│ ├── mobile_officer_view_serializer.py
│ ├── mobile_suggestion_view_serializer.py
│ └── shared.py
├── services
│ ├── __init__.py
│ ├── mobile_redirector_service.py
│ ├── mobile_suggestion_service.py
│ ├── officer_allegation_service.py
│ ├── officer_distribution_service.py
│ └── related_officer_service.py
├── static
│ └── mobile
│ │ ├── fonts
│ │ ├── sanfranciscodisplay-bold-webfont.woff
│ │ ├── sanfranciscodisplay-medium-webfont.woff
│ │ ├── sanfranciscodisplay-regular-webfont.woff
│ │ ├── sanfranciscodisplay-semibold-webfont.woff
│ │ ├── sanfranciscodisplay-thin-webfont.woff
│ │ └── sanfranciscodisplay-ultralight-webfont.woff
│ │ ├── img
│ │ └── loading.gif
│ │ ├── js
│ │ ├── actions
│ │ │ ├── ComplaintPage
│ │ │ │ ├── ComplaintPageActions.js
│ │ │ │ ├── ComplaintPageServerActions.js
│ │ │ │ └── RequestActions.js
│ │ │ ├── MainPage
│ │ │ │ ├── MainPageServerActions.js
│ │ │ │ └── SearchBarActions.js
│ │ │ ├── OfficerPage
│ │ │ │ └── OfficerPageServerActions.js
│ │ │ └── Shared
│ │ │ │ ├── InterfaceTextActions.js
│ │ │ │ └── SearchablePageActions.js
│ │ ├── app.js
│ │ ├── components
│ │ │ ├── App.react.js
│ │ │ ├── Base.react.js
│ │ │ ├── ComplaintPage.react.js
│ │ │ ├── ComplaintPage
│ │ │ │ ├── AccompliceOfficerSection.react.js
│ │ │ │ ├── AgainstSection.react.js
│ │ │ │ ├── AgainstSection
│ │ │ │ │ ├── AgainstCard.react.js
│ │ │ │ │ └── AgainstCard
│ │ │ │ │ │ ├── InvestigationTimeline.react.js
│ │ │ │ │ │ └── InvestigationTimeline
│ │ │ │ │ │ ├── ThreeNodesTimeline.react.js
│ │ │ │ │ │ └── TwoNodesTimeline.react.js
│ │ │ │ ├── ComplainingWitness.react.js
│ │ │ │ ├── DocumentSection.react.js
│ │ │ │ ├── DocumentSection
│ │ │ │ │ ├── DocumentCard.react.js
│ │ │ │ │ └── DocumentCard
│ │ │ │ │ │ └── RequestModalContent.react.js
│ │ │ │ ├── InvestigatorSection.react.js
│ │ │ │ ├── Location.react.js
│ │ │ │ ├── Location
│ │ │ │ │ └── Map.react.js
│ │ │ │ ├── NotMatchedCategoryPage.react.js
│ │ │ │ ├── NotMatchedComplaintPage.react.js
│ │ │ │ ├── OfficerAllegationDetail.react.js
│ │ │ │ └── ToggleComplaintPage.react.js
│ │ │ ├── Lib
│ │ │ │ ├── Modal.react.js
│ │ │ │ └── SimpleEventSystem.js
│ │ │ ├── MainPage.react.js
│ │ │ ├── MainPage
│ │ │ │ ├── MainPageContent.react.js
│ │ │ │ ├── PageNotFound.react.js
│ │ │ │ └── ProjectSummary.react.js
│ │ │ ├── NoMatch.react.js
│ │ │ ├── OfficerPage.react.js
│ │ │ ├── OfficerPage
│ │ │ │ ├── ComplaintsTab.react.js
│ │ │ │ ├── NotMatchedOfficerPage.react.js
│ │ │ │ ├── OfficerHeader.react.js
│ │ │ │ ├── RelatedOfficersTab.react.js
│ │ │ │ ├── RelatedOfficersTab
│ │ │ │ │ ├── NoRelatedOfficer.react.js
│ │ │ │ │ └── RelatedOfficerItem.react.js
│ │ │ │ ├── SummaryTab.react.js
│ │ │ │ └── SummaryTab
│ │ │ │ │ ├── OfficerAnalyticSection.react.js
│ │ │ │ │ ├── OfficerAnalyticSection
│ │ │ │ │ └── DistributionCurve.react.js
│ │ │ │ │ └── OfficerSummarySection.react.js
│ │ │ └── Shared
│ │ │ │ ├── About.react.js
│ │ │ │ ├── HighlightText.react.js
│ │ │ │ ├── InterfaceText.react.js
│ │ │ │ ├── LoadingPage.react.js
│ │ │ │ ├── OfficerAllegationItem.react.js
│ │ │ │ ├── OfficerAllegationItem
│ │ │ │ └── CircleList.react.js
│ │ │ │ ├── OfficerCard.react.js
│ │ │ │ ├── SearchablePage.react.js
│ │ │ │ ├── SearchablePage
│ │ │ │ ├── SearchBar.react.js
│ │ │ │ ├── SearchResults.react.js
│ │ │ │ └── SearchResults
│ │ │ │ │ ├── FailedSearch.react.js
│ │ │ │ │ ├── SuccessfulSearch.react.js
│ │ │ │ │ └── SuccessfulSearch
│ │ │ │ │ ├── ComplaintResult.react.js
│ │ │ │ │ └── OfficerResult.react.js
│ │ │ │ ├── SimpleTab.react.js
│ │ │ │ ├── TickIcon.js
│ │ │ │ └── Wrapper.react.js
│ │ ├── constants
│ │ │ └── AppConstants.js
│ │ ├── dispatcher
│ │ │ └── AppDispatcher.js
│ │ ├── presenters
│ │ │ ├── AllegationPresenter.js
│ │ │ ├── ComplainingWitnessPresenter.js
│ │ │ ├── DocumentPresenter.js
│ │ │ ├── GenderPresenter.js
│ │ │ ├── OfficerAllegationPresenter.js
│ │ │ ├── OfficerPresenter.js
│ │ │ ├── Page
│ │ │ │ ├── ComplaintPagePresenter.js
│ │ │ │ ├── ComplaintResultPresenter.js
│ │ │ │ ├── OfficerPagePresenter.js
│ │ │ │ └── ToggleComplaintPagePresenter.js
│ │ │ ├── RequestDocumentErrorPresenter.js
│ │ │ └── SuggestionPresenter.js
│ │ ├── stores
│ │ │ ├── Base.js
│ │ │ ├── ComplaintPage
│ │ │ │ ├── ComplaintPageStore.js
│ │ │ │ └── RequestStore.js
│ │ │ ├── MainPage
│ │ │ │ ├── SearchBarStore.js
│ │ │ │ └── SearchResultsStore.js
│ │ │ ├── MainPageStore.js
│ │ │ ├── OfficerPage
│ │ │ │ └── OfficerPageStore.js
│ │ │ └── Shared
│ │ │ │ ├── InterfaceTextStore.js
│ │ │ │ └── SearchablePageStore.js
│ │ ├── tests
│ │ │ ├── actions
│ │ │ │ ├── ComplaintPage
│ │ │ │ │ ├── ComplaintPageActions.js
│ │ │ │ │ ├── ComplaintPageServerActions.js
│ │ │ │ │ └── RequestActions.js
│ │ │ │ └── Shared
│ │ │ │ │ └── InterfaceTextActions.js
│ │ │ ├── components
│ │ │ │ ├── ComplaintPage.js
│ │ │ │ ├── ComplaintPage
│ │ │ │ │ ├── AccompliceOfficerSection.js
│ │ │ │ │ ├── AgainstSection.js
│ │ │ │ │ ├── AgainstSection
│ │ │ │ │ │ ├── AgainstCard.js
│ │ │ │ │ │ └── AgainstCard
│ │ │ │ │ │ │ ├── InvestigationTimeline.js
│ │ │ │ │ │ │ └── InvestigationTimeline
│ │ │ │ │ │ │ ├── ThreeNodesTimeline.js
│ │ │ │ │ │ │ └── TwoNodesTimeline.js
│ │ │ │ │ ├── ComplainingWitness.js
│ │ │ │ │ ├── DocumentSection.js
│ │ │ │ │ ├── DocumentSection
│ │ │ │ │ │ ├── DocumentCard.js
│ │ │ │ │ │ └── RequestModalContent.js
│ │ │ │ │ ├── InvestigatorSection.js
│ │ │ │ │ ├── Location.js
│ │ │ │ │ ├── Location
│ │ │ │ │ │ └── Map.js
│ │ │ │ │ ├── NotMatchComplaintPage.js
│ │ │ │ │ ├── NotMatchedCategoryPage.js
│ │ │ │ │ ├── OfficerAllegationDetail.js
│ │ │ │ │ └── ToggleComplaintPage.js
│ │ │ │ ├── Lib
│ │ │ │ │ ├── Modal.js
│ │ │ │ │ └── SimpleEventSystem.js
│ │ │ │ ├── OfficerPage
│ │ │ │ │ └── NotMatchOfficerPage.js
│ │ │ │ └── Shared
│ │ │ │ │ ├── InterfaceText.js
│ │ │ │ │ ├── OfficerAllegationItem.js
│ │ │ │ │ ├── OfficerAllegationItem
│ │ │ │ │ └── CirclList.js
│ │ │ │ │ ├── OfficerCard.js
│ │ │ │ │ └── SearchablePage
│ │ │ │ │ └── SearchResults
│ │ │ │ │ └── FailedSearch.js
│ │ │ ├── examples
│ │ │ │ └── components
│ │ │ │ │ ├── LoadablePage.js
│ │ │ │ │ └── SearchablePage.js
│ │ │ ├── factories
│ │ │ │ ├── AllegationFactory.js
│ │ │ │ ├── CategoryFactory.js
│ │ │ │ ├── ComplainingWitnessFactory.js
│ │ │ │ ├── ComplaintPageDataFactory.js
│ │ │ │ ├── DocumentFactory.js
│ │ │ │ ├── InvestigatorFactory.js
│ │ │ │ ├── OfficerAllegationFactory.js
│ │ │ │ ├── OfficerFactory.js
│ │ │ │ ├── OfficerPageDataFactory.js
│ │ │ │ ├── PointFactory.js
│ │ │ │ └── SuggestionFactory.js
│ │ │ ├── presenters
│ │ │ │ ├── AllegationPresenter.js
│ │ │ │ ├── ComplainingWitnessPresenter.js
│ │ │ │ ├── DocumentPresenter.js
│ │ │ │ ├── OfficerAllegationPresenter.js
│ │ │ │ ├── OfficerPresenter.js
│ │ │ │ ├── Page
│ │ │ │ │ ├── ComplaintPagePresenter.js
│ │ │ │ │ ├── OfficerPagePresenter.js
│ │ │ │ │ └── ToggleComplaintPagePresenter.js
│ │ │ │ └── RequestDocumentErrorPresenter.js
│ │ │ ├── stores
│ │ │ │ ├── ComplaintPage
│ │ │ │ │ ├── ComplaintPageStore.js
│ │ │ │ │ └── RequestStore.js
│ │ │ │ └── Shared
│ │ │ │ │ └── InterfaceTextStore.js
│ │ │ └── utils
│ │ │ │ ├── CollectionUtil.js
│ │ │ │ ├── DataTypeUtil.js
│ │ │ │ ├── DateUtil.js
│ │ │ │ ├── DeviceUtil.js
│ │ │ │ ├── InterfaceTextUtil.js
│ │ │ │ └── tests
│ │ │ │ └── Factory.js
│ │ └── utils
│ │ │ ├── AllegationResourceUtil.js
│ │ │ ├── CollectionUtil.js
│ │ │ ├── DataTypeUtil.js
│ │ │ ├── DateUtil.js
│ │ │ ├── DeviceUtil.js
│ │ │ ├── GaUtil.js
│ │ │ ├── HashUtil.js
│ │ │ ├── HelperUtil.js
│ │ │ ├── History.js
│ │ │ ├── InterfaceTextResourceUtil.js
│ │ │ ├── InterfaceTextUtil.js
│ │ │ ├── LocalStorageUtil.js
│ │ │ ├── MapFacade.js
│ │ │ ├── OfficerResourceUtil.js
│ │ │ ├── OfficerUtil.js
│ │ │ ├── RequestEmailResourceUtil.js
│ │ │ ├── SuggestionAPI.js
│ │ │ ├── SvgUtil.js
│ │ │ └── tests
│ │ │ ├── Factory.js
│ │ │ ├── SharedExample.js
│ │ │ ├── f.js
│ │ │ └── should
│ │ │ ├── React.js
│ │ │ └── SharedExample.js
│ │ └── sass
│ │ ├── complaint_page.sass
│ │ ├── complaint_page
│ │ ├── accomplice_officer_section.sass
│ │ ├── against_section.sass
│ │ ├── against_section
│ │ │ ├── against_card.sass
│ │ │ └── against_card
│ │ │ │ └── investigation_timeline.sass
│ │ ├── complaining_witness.sass
│ │ ├── document_section.sass
│ │ ├── document_section
│ │ │ ├── document_card.sass
│ │ │ └── document_card
│ │ │ │ └── request_modal_content.sass
│ │ ├── investigation_section.sass
│ │ ├── location.sass
│ │ ├── location
│ │ │ └── map.sass
│ │ ├── not_matched_category_page.sass
│ │ ├── not_matched_complaint_page.sass
│ │ ├── officer_allegation_detail.sass
│ │ ├── police_witness.sass
│ │ └── toogle_complaint_page.sass
│ │ ├── fonts.sass
│ │ ├── grid.sass
│ │ ├── helper.sass
│ │ ├── helper
│ │ ├── animation.sass
│ │ └── officer_color_level.sass
│ │ ├── main_page.sass
│ │ ├── main_page
│ │ ├── main_page_content.sass
│ │ ├── page_not_found.sass
│ │ └── project_summary.sass
│ │ ├── officer_page.sass
│ │ ├── officer_page
│ │ ├── complaints_tab.sass
│ │ ├── not_matched_officer_page.sass
│ │ ├── officer_header.sass
│ │ ├── related_officer_tab.sass
│ │ ├── related_officer_tab
│ │ │ ├── no_related_officer.sass
│ │ │ └── related_officer_item.sass
│ │ ├── summary_tab.sass
│ │ └── summary_tab
│ │ │ ├── distribution_curve.sass
│ │ │ ├── officer_analytic_section.sass
│ │ │ └── officer_summary_section.sass
│ │ ├── shared.sass
│ │ ├── shared
│ │ ├── about.sass
│ │ ├── interface_text.sass
│ │ ├── loading_page.sass
│ │ ├── officer_allegation_item.sass
│ │ ├── officer_card.sass
│ │ ├── searchable_page.sass
│ │ ├── searchable_page
│ │ │ ├── search_bar.sass
│ │ │ ├── search_results.sass
│ │ │ └── search_results
│ │ │ │ ├── failed_search.sass
│ │ │ │ ├── successful_search.sass
│ │ │ │ └── successful_search
│ │ │ │ ├── complaint_result.sass
│ │ │ │ └── officer_result.sass
│ │ └── simple_tab.sass
│ │ ├── style.sass
│ │ └── variables.sass
├── templates
│ └── mobile
│ │ └── index.html
├── tests
│ ├── __init__.py
│ ├── integrations
│ │ ├── __init__.py
│ │ ├── test_mobile_complaint_page.py
│ │ ├── test_mobile_document_request.py
│ │ ├── test_mobile_google_analytics.py
│ │ ├── test_mobile_main_page.py
│ │ ├── test_mobile_officer_page.py
│ │ ├── test_mobile_redirect_from_desktop.py
│ │ ├── test_mobile_search_page.py
│ │ ├── test_mobile_search_term_should_be_reset.py
│ │ ├── test_mobile_searchable_page.py
│ │ └── test_mobile_simple_tab.py
│ ├── mixins
│ │ ├── __init__.py
│ │ └── mobile_visiting_url_mixins.py
│ ├── serializers
│ │ └── test_mobile_document_request_view_serializer.py
│ ├── services
│ │ ├── __init__.py
│ │ ├── test_mobile_distribution_service.py
│ │ ├── test_mobile_officer_allegation_service.py
│ │ ├── test_mobile_redirector_service.py
│ │ ├── test_mobile_suggestion_service.py
│ │ └── test_related_officer_service.py
│ ├── utils
│ │ ├── __init__.py
│ │ ├── test_cache_helper.py
│ │ ├── test_collection_helper.py
│ │ ├── test_mobile_url_builder.py
│ │ └── test_sql_helper.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_mobile_allegation_view.py
│ │ ├── test_mobile_data_tool_view.py
│ │ ├── test_mobile_document_request_view.py
│ │ ├── test_mobile_interface_text_view.py
│ │ ├── test_mobile_officer_view.py
│ │ ├── test_mobile_site_view.py
│ │ └── test_mobile_suggestion_view.py
├── urls.py
├── utils
│ ├── __init__.py
│ ├── cache_helper.py
│ ├── collection_helper.py
│ ├── mobile_url_builder.py
│ └── sql_helper.py
└── views
│ ├── __init__.py
│ ├── mobile_allegation_view.py
│ ├── mobile_data_tool_view.py
│ ├── mobile_document_request_view.py
│ ├── mobile_interface_text_view.py
│ ├── mobile_officer_view.py
│ ├── mobile_site_view.py
│ └── mobile_suggestion_view.py
├── npm-shrinkwrap.json
├── officer
├── __init__.py
├── admin.py
├── factories.py
├── migrations
│ ├── 0001_initial.py
│ └── __init__.py
├── models.py
├── serializers.py
├── tests
│ ├── __init__.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_count_view.py
│ │ ├── test_story_view.py
│ │ ├── test_timeline_view.py
│ │ └── ui
│ │ ├── __init__.py
│ │ ├── test_officer_outcome_filter.py
│ │ └── test_story_view.py
├── urls.py
└── views
│ ├── __init__.py
│ ├── count_view.py
│ ├── officer_detail_view.py
│ ├── story_view.py
│ └── timeline_view.py
├── package.json
├── pre_deploy.sh
├── requirements.txt
├── runtime.txt
├── search
├── __init__.py
├── admin.py
├── factories.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_filterlog_num_allegations.py
│ ├── 0003_auto_20150805_0316.py
│ ├── 0004_alias.py
│ ├── 0004_auto_20150812_0805.py
│ ├── 0005_merge.py
│ ├── 0006_auto_20150921_0248.py
│ ├── 0006_auto_20150922_0405.py
│ ├── 0007_merge.py
│ ├── 0008_alias_updated_at.py
│ ├── 0009_filterlog_user_agent.py
│ ├── 0010_auto_20151009_0919.py
│ ├── 0011_remove_suggestionlog_ip.py
│ ├── 0012_auto_20151012_0924.py
│ ├── 0013_sessionalias.py
│ ├── 0014_auto_20151203_0227.py
│ ├── 0015_sessionalias_title.py
│ ├── 0016_add_timestamp_fields.py
│ └── __init__.py
├── models
│ ├── __init__.py
│ ├── alias.py
│ ├── proxy_models.py
│ ├── session_alias.py
│ └── suggestion.py
├── search_backends.py
├── search_indexes.py
├── services
│ ├── __init__.py
│ ├── suggest
│ │ ├── __init__.py
│ │ ├── suggest_allegation.py
│ │ ├── suggest_allegation_category.py
│ │ ├── suggest_area.py
│ │ ├── suggest_data_source.py
│ │ ├── suggest_finding.py
│ │ ├── suggest_has.py
│ │ ├── suggest_incident_date.py
│ │ ├── suggest_investigator.py
│ │ ├── suggest_investigator_agency.py
│ │ ├── suggest_officer.py
│ │ ├── suggest_outcome.py
│ │ ├── suggest_race_gender.py
│ │ ├── suggest_repeat_offenders.py
│ │ └── suggest_session_alias.py
│ └── suggestion_service.py
├── static
│ └── search
│ │ └── js
│ │ └── search.js
├── templates
│ └── search
│ │ └── indexes
│ │ ├── common
│ │ ├── allegation_text.txt
│ │ ├── allegationcategory_text.txt
│ │ ├── area_text.txt
│ │ ├── investigator_text.txt
│ │ └── officer_text.txt
│ │ └── search
│ │ ├── allegationcategoryproxy_text.txt
│ │ ├── allegationproxy_text.txt
│ │ └── sessionalias_text.txt
├── tests
│ ├── __init__.py
│ ├── admin
│ │ ├── __init__.py
│ │ └── test_suggestion_admin.py
│ ├── services
│ │ ├── __init__.py
│ │ └── suggest
│ │ │ ├── __init__.py
│ │ │ ├── base_test_suggest.py
│ │ │ ├── test_special_suggest_cases.py
│ │ │ ├── test_suggest_allegation.py
│ │ │ ├── test_suggest_allegation_category.py
│ │ │ ├── test_suggest_allegation_summary.py
│ │ │ ├── test_suggest_area.py
│ │ │ ├── test_suggest_base.py
│ │ │ ├── test_suggest_data_source.py
│ │ │ ├── test_suggest_has.py
│ │ │ ├── test_suggest_incident_date.py
│ │ │ ├── test_suggest_investigator.py
│ │ │ ├── test_suggest_officer.py
│ │ │ └── test_suggest_session_alias.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_search_view.py
│ │ ├── test_suggest_view.py
│ │ └── ui
│ │ ├── __init__.py
│ │ └── test_search_ui.py
├── urls.py
├── utils
│ ├── __init__.py
│ ├── date.py
│ ├── format_suggest.py
│ └── zip_code.py
└── views
│ ├── __init__.py
│ └── suggest_view.py
├── setup.cfg
├── shapefiles
├── Boundaries - Police Districts (current)
│ ├── geo_fthy-xz3r-1.cst
│ ├── geo_fthy-xz3r-1.dbf
│ ├── geo_fthy-xz3r-1.prj
│ ├── geo_fthy-xz3r-1.shp
│ ├── geo_fthy-xz3r-1.shx
│ └── wfsrequest.txt
├── Boundaries_-_Neighborhoods
│ ├── Neighborhoods_2012b.dbf
│ ├── Neighborhoods_2012b.prj
│ ├── Neighborhoods_2012b.sbn
│ ├── Neighborhoods_2012b.sbx
│ ├── Neighborhoods_2012b.shp
│ └── Neighborhoods_2012b.shx
├── Boundaries_-_Wards__2015-_
│ ├── WARDS_2015.dbf
│ ├── WARDS_2015.prj
│ ├── WARDS_2015.shp
│ ├── WARDS_2015.shp.xml
│ └── WARDS_2015.shx
├── School_20Grounds
│ ├── School_Grounds.dbf
│ ├── School_Grounds.prj
│ ├── School_Grounds.sbn
│ ├── School_Grounds.sbx
│ ├── School_Grounds.shp
│ └── School_Grounds.shx
├── beats
│ ├── cpd_beats.dbf
│ ├── cpd_beats.prj
│ ├── cpd_beats.sbn
│ ├── cpd_beats.sbx
│ ├── cpd_beats.shp
│ ├── cpd_beats.shp.xml
│ └── cpd_beats.shx
└── communities
│ ├── CommAreas.dbf
│ ├── CommAreas.prj
│ ├── CommAreas.sbn
│ ├── CommAreas.sbx
│ ├── CommAreas.shp
│ └── CommAreas.shx
├── share
├── __init__.py
├── admin.py
├── factories.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_session_created_at.py
│ ├── 0003_auto_20151009_0919.py
│ ├── 0004_auto_20151014_0253.py
│ ├── 0005_auto_20151014_0255.py
│ ├── 0006_auto_20151103_0959.py
│ ├── 0007_session_active_tab.py
│ ├── 0008_auto_20151120_0414.py
│ ├── 0009_auto_20151123_0505.py
│ ├── 0010_session_searchable.py
│ ├── 0011_session_alias.py
│ ├── 0012_auto_20151201_0314.py
│ ├── 0013_session_sunburst_arc.py
│ ├── 0014_auto_20160112_0358.py
│ ├── 0015_session_shared.py
│ ├── 0016_session_selected_sunburst_arc.py
│ └── __init__.py
├── models.py
├── tests
│ ├── __init__.py
│ ├── admin
│ │ ├── __init__.py
│ │ └── test_admin_session.py
│ └── views
│ │ ├── __init__.py
│ │ ├── test_home_page_view.py
│ │ └── ui
│ │ ├── __init__.py
│ │ └── test_share_session.py
├── urls.py
└── views
│ └── __init__.py
├── start_gunicorn.sh
├── twitterbot
├── __init__.py
├── admin.py
├── factories.py
├── fixtures
│ └── vcr
│ │ └── test_auth.yaml
├── handlers.py
├── management
│ ├── __init__.py
│ └── commands
│ │ ├── __init__.py
│ │ └── start_twitterbot.py
├── migrations
│ ├── 0001_initial.py
│ ├── 0002_twitterbotresponselog.py
│ └── __init__.py
├── models.py
├── services
│ ├── __init__.py
│ ├── responses
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── investigators.py
│ │ └── officers.py
│ ├── twitter_bot_names_service.py
│ ├── twitter_bot_responses_service.py
│ ├── twitter_bot_service.py
│ └── twitter_bot_tweets_service.py
├── tests
│ ├── __init__.py
│ ├── handlers
│ │ ├── __init__.py
│ │ └── test_cpdb_tweet_handler.py
│ ├── models
│ │ ├── __init__.py
│ │ ├── test_twitter_bot_text_source.py
│ │ └── test_twitter_response.py
│ └── services
│ │ ├── __init__.py
│ │ ├── responses
│ │ ├── __init__.py
│ │ ├── test_base.py
│ │ ├── test_investigators.py
│ │ └── test_officers.py
│ │ ├── test_twitter_bot_names_service.py
│ │ ├── test_twitter_bot_responses_service.py
│ │ ├── test_twitter_bot_service.py
│ │ └── test_twitter_bot_tweets_service.py
└── utils
│ ├── __init__.py
│ ├── log.py
│ └── tweet.py
├── url_mediator
├── __init__.py
├── migrations
│ └── __init__.py
├── services
│ ├── __init__.py
│ ├── session_builder.py
│ └── url_mediator_suggestion_service.py
└── tests
│ ├── __init__.py
│ └── services
│ ├── __init__.py
│ ├── test_session_builder.py
│ └── test_url_mediator_suggestion_service.py
└── wagtail_app
├── __init__.py
├── factories.py
├── migrations
├── 0001_initial.py
├── 0002_create_homepage.py
├── 0003_glossary_page_data.py
├── __init__.py
└── glossary_data.csv
├── models.py
├── serializers.py
└── tests.py
/.coveragerc:
--------------------------------------------------------------------------------
1 | [report]
2 | omit =
3 | */migrations/*
4 | ~/.virtualenvs/*
5 | ~/virtualenvs/*
6 | common/json_serializer.py
7 | common/tests/runner.py
8 | common/tests/core.py
9 | common/middleware/cache.py
10 | manage.py
11 | */tests/*
12 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | indent_style = space
11 |
12 | # Set default charset
13 | [*.{js,py}]
14 | charset = utf-8
15 |
16 | [*.py]
17 | indent_size = 4
18 |
19 | [*.{js,sass}]
20 | indent_size = 2
21 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | **/*bundle*.js
2 | /static/
3 | **/bower_components/**
4 | **/*.min.js
5 | /common/
6 | /htmlcov/**
7 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | - repo: git://github.com/pre-commit/mirrors-eslint
2 | sha: aaa8651ac4833f38c66a6b1b475856f4b1e01c57
3 | hooks:
4 | - id: eslint
5 | additional_dependencies: ["eslint@2.0.0", "eslint-plugin-react@3.16.1"]
6 | - repo: git://github.com/pre-commit/pre-commit-hooks
7 | sha: 64943e86417774b9d6ba63c74e00f8cc3e2119e0
8 | hooks:
9 | - id: flake8
10 |
--------------------------------------------------------------------------------
/allegation/.gitignore:
--------------------------------------------------------------------------------
1 | /static/allegation/js/bundle.js
2 |
--------------------------------------------------------------------------------
/allegation/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/__init__.py
--------------------------------------------------------------------------------
/allegation/admin.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/admin.py
--------------------------------------------------------------------------------
/allegation/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/migrations/__init__.py
--------------------------------------------------------------------------------
/allegation/models/__init__.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Download(models.Model):
5 | query = models.TextField()
6 | finished = models.BooleanField(default=False)
7 | url = models.TextField()
8 |
--------------------------------------------------------------------------------
/allegation/models/compiler.py:
--------------------------------------------------------------------------------
1 | from django.db.models.sql.compiler import SQLCompiler
2 |
3 |
4 | class NullsLastSQLCompiler(SQLCompiler):
5 | def get_order_by(self):
6 | results = super(NullsLastSQLCompiler, self).get_order_by()
7 | if self.connection.vendor == 'postgresql' and results:
8 | return [(result[0], (
9 | result[1][0].replace('DESC', 'DESC NULLS LAST').replace('ASC', 'ASC NULLS FIRST'),
10 | result[1][1], result[1][2])) for result in results]
11 | return results
12 |
--------------------------------------------------------------------------------
/allegation/models/query_sets.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 | from allegation.models.query import NullsLastQuery
4 |
5 |
6 | class NullsLastQuerySet(models.query.QuerySet):
7 | def __init__(self, model=None, query=None, using=None, hints=None):
8 | super(NullsLastQuerySet, self).__init__(model, query, using, hints)
9 | self.query = query or NullsLastQuery(self.model)
10 |
11 |
12 | class AllegationQuerySet(NullsLastQuerySet):
13 | pass
14 |
15 |
16 | class OfficerAllegationQuerySet(NullsLastQuerySet):
17 | pass
18 |
--------------------------------------------------------------------------------
/allegation/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/services/__init__.py
--------------------------------------------------------------------------------
/allegation/static/allegation/css/MarkerCluster.css:
--------------------------------------------------------------------------------
1 | .leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow {
2 | -webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in;
3 | -moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in;
4 | -o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in;
5 | transition: transform 0.3s ease-out, opacity 0.3s ease-in;
6 | }
7 |
--------------------------------------------------------------------------------
/allegation/static/allegation/css/table.css:
--------------------------------------------------------------------------------
1 | #allegation-table_filter {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/allegation/static/allegation/img/64x_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/64x_map_marker.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/UCPD-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/UCPD-1.jpg
--------------------------------------------------------------------------------
/allegation/static/allegation/img/arrow_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/arrow_down.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/arrow_right.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/arrow_right.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/complaint-flowchart-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/complaint-flowchart-1.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/complaint-flowchart-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/complaint-flowchart-2.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/data-ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/data-ad.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/data-chart.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/data-chart.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/dianebond2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/dianebond2.jpg
--------------------------------------------------------------------------------
/allegation/static/allegation/img/finding-ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/finding-ad.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/findings-main-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/findings-main-1.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/methodology.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/methodology.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/story-ad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/story-ad.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/story-main-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/story-main-1.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/story-main-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/story-main-2.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/story-main-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/story-main-3.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/story-main-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/story-main-4.png
--------------------------------------------------------------------------------
/allegation/static/allegation/img/story-main-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/allegation/img/story-main-5.png
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/ComplaintList/OutcomeAnalysisServerActionCreator.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var OutcomeAnalysisServerActionCreator = {
5 | receivedAnalysisInformation: function (data) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RECEIVED_OUTCOME_FILTER_ANALYSIS,
8 | data: data
9 | });
10 | }
11 | };
12 |
13 | module.exports = OutcomeAnalysisServerActionCreator;
14 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DataToolPage/AllegationActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 |
5 | var AllegationActions = {
6 | receivedData: function (data) {
7 | AppDispatcher.dispatch({
8 | actionType: AppConstants.ALLEGATION_DETAILS_DATA_RECEIVED,
9 | data: data
10 | });
11 | }
12 | };
13 |
14 | module.exports = AllegationActions;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DataToolPage/OverlayActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 |
5 | var OverlayActions = {
6 | toggleOverlay: function () {
7 | AppDispatcher.dispatch({
8 | actionType: AppConstants.TOGGLE_OVERLAY
9 | });
10 | }
11 | };
12 |
13 | module.exports = OverlayActions;
14 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DataToolPage/RaceGenderTabActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var RaceGenderTabActions = {
5 | receivedData: function (data) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RACE_GENDER_TAB_RECEIVED_DATA,
8 | data: data
9 | });
10 | }
11 | };
12 |
13 | module.exports = RaceGenderTabActions;
14 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DataToolPage/RaceGenderTabServerActions.js:
--------------------------------------------------------------------------------
1 | var RaceGenderAPI = require('utils/RaceGenderAPI');
2 |
3 |
4 | var RaceGenderTabServerActions = {
5 | initData: function () {
6 | RaceGenderAPI.getData();
7 | }
8 | };
9 |
10 | module.exports = RaceGenderTabServerActions;
11 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DataToolPage/SunburstServerActions.js:
--------------------------------------------------------------------------------
1 | var SunburstAPI = require('utils/SunburstAPI');
2 |
3 |
4 | var SunburstServerActions = {
5 | initData: function () {
6 | SunburstAPI.getData();
7 | }
8 | };
9 |
10 | module.exports = SunburstServerActions;
11 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DataToolPage/TabActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 | var SessionAPI = require('utils/SessionAPI');
4 |
5 | var TabActions = {
6 | setActiveTab: function (tab) {
7 | AppDispatcher.dispatch({
8 | actionType: AppConstants.SET_ACTIVE_TAB,
9 | data: tab
10 | });
11 | SessionAPI.updateSessionInfo({'active_tab': tab});
12 | }
13 | };
14 |
15 | module.exports = TabActions;
16 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DownloadActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../dispatcher/AppDispatcher');
2 | var AppConstants = require('../constants/AppConstants');
3 |
4 | var DownloadActions = {
5 | process: function () {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.DOWNLOAD_PROCESS
8 | });
9 | }
10 | };
11 |
12 | module.exports = DownloadActions;
13 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/DownloadServerActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../dispatcher/AppDispatcher');
2 | var AppConstants = require('../constants/AppConstants');
3 |
4 | var DownloadServerActions = {
5 | completeGeneratedDownload: function (href) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.GENERATED_DOWNLOAD,
8 | href: href
9 | });
10 | }
11 | };
12 |
13 | module.exports = DownloadServerActions;
14 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/EmbedActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../dispatcher/AppDispatcher');
2 | var AppConstants = require('../constants/AppConstants');
3 |
4 | var EmbedAction = {
5 | enterEmbedMode: function () {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.ENTER_EMBED_MODE
8 | });
9 | },
10 |
11 | leaveEmbedMode: function () {
12 | AppDispatcher.dispatch({
13 | actionType: AppConstants.LEAVE_EMBED_MODE
14 | });
15 | }
16 | };
17 |
18 | module.exports = EmbedAction;
19 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/InvestigatorPage/InvestigatorPageActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 |
5 | var InvestigatorPageActions = {
6 | receivedInvestigatorData: function (data) {
7 | AppDispatcher.dispatch({
8 | actionType: AppConstants.RECEIVED_INVESTIGATOR_DATA,
9 | data: data
10 | });
11 | }
12 | };
13 |
14 | module.exports = InvestigatorPageActions;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/Officer/CheckMarkActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 |
5 | var CheckMarkActions = {
6 | mouseOut: function (officer) {
7 | AppDispatcher.dispatch({
8 | actionType: AppConstants.OFFICER_MOUSE_OUT,
9 | officer: officer
10 | });
11 | }
12 | };
13 |
14 | module.exports = CheckMarkActions;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/OfficerPage/OfficerPageActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('dispatcher/AppDispatcher');
2 | var AppConstants = require('constants/AppConstants');
3 |
4 |
5 | var OfficerPageActions = {
6 | receivedOfficerData: function (data) {
7 | AppDispatcher.dispatch({
8 | actionType: AppConstants.RECEIVED_OFFICER_DATA,
9 | data: data
10 | });
11 | }
12 | };
13 |
14 | module.exports = OfficerPageActions;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/OfficerPage/OfficerPageServerActions.js:
--------------------------------------------------------------------------------
1 | var OfficerPageAPIUtil = require('utils/OfficerPageAPIUtil');
2 |
3 | var OfficerPageActions = {
4 | getOfficerData: function (officer) {
5 | OfficerPageAPIUtil.getOfficerData(officer);
6 | }
7 | };
8 |
9 | module.exports = OfficerPageActions;
10 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/OfficerPage/StoryActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var StoryListActions = {
5 | setThumbUrl: function (story, thumbUrl) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_STORY_DOCUMENT_THUMB,
8 | story: story,
9 | thumbUrl: thumbUrl
10 | });
11 | }
12 | };
13 |
14 | module.exports = StoryListActions;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/OfficerPage/StoryListActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var StoryListActions = {
5 | receiveStories: function (stories) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RECEIVE_STORIES,
8 | data: stories
9 | });
10 | }
11 | };
12 |
13 | module.exports = StoryListActions;
14 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/OfficerPage/TimelineActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var TimelineActions = {
5 | receivedData: function (timeline) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RECEIVED_TIMELINE_DATA,
8 | data: timeline
9 | });
10 | }
11 | };
12 |
13 | module.exports = TimelineActions;
14 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/SiteTitleActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../dispatcher/AppDispatcher');
2 | var AppConstants = require('../constants/AppConstants');
3 | var SessionAPI = require('utils/SessionAPI');
4 |
5 | var SiteTitleActions = {
6 |
7 | changeSiteTitle: function (title) {
8 | AppDispatcher.dispatch({
9 | actionType: AppConstants.CHANGE_SITE_TITLE,
10 | title: title
11 | });
12 | SessionAPI.updateSiteTitleDelayed500ms(title);
13 | }
14 |
15 | };
16 |
17 | module.exports = SiteTitleActions;
18 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/actions/WagtailPagesServerActions.js:
--------------------------------------------------------------------------------
1 | var WagtailPagesAPI = require('utils/WagtailPagesAPI');
2 |
3 |
4 | var WagtailPagesServerActions = {
5 | initData: function () {
6 | WagtailPagesAPI.getGlossaryData();
7 | }
8 | };
9 |
10 | module.exports = WagtailPagesServerActions;
11 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/components/Shared/InterfaceText.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var PropTypes = React.PropTypes;
3 |
4 | var InterfaceTextUtil = require('utils/InterfaceTextUtil');
5 |
6 |
7 | var InterfaceText = React.createClass({
8 | propTypes: {
9 | identifier: PropTypes.string
10 | },
11 |
12 | render: function () {
13 | var text = InterfaceTextUtil.get(this.props.identifier);
14 |
15 | return (
16 |
{ text }
17 | );
18 | }
19 | });
20 |
21 | module.exports = InterfaceText;
22 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/components/Shared/LoadingPage.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 |
4 | var LoadingPage = React.createClass({
5 | render: function () {
6 | return (
7 |
8 |
9 |
12 |
13 |
14 | );
15 | }
16 | });
17 |
18 | module.exports = LoadingPage;
19 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/constants/RequestDocumentConstants.js:
--------------------------------------------------------------------------------
1 | var keyMirror = require('keymirror');
2 |
3 | module.exports = keyMirror({
4 | REQUEST_DOCUMENT: null,
5 | DOCUMENT_REQUESTED: null,
6 | DOCUMENT_REQUEST_FAILED: null
7 | });
8 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/keyboardShortcuts.js:
--------------------------------------------------------------------------------
1 | var Mousetrap = require('mousetrap');
2 | var FilterTagsAction = require('actions/FilterTagsActions');
3 |
4 |
5 | Mousetrap.bind(['shift'], function (e) {
6 | FilterTagsAction.toggleStackingMode();
7 | });
8 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/mixins/IndexTabContentMixin.js:
--------------------------------------------------------------------------------
1 | var classnames = require('classnames');
2 |
3 | var NavActions = require('actions/NavActions');
4 |
5 |
6 | var IndexTabContentMixin = {
7 | navigate: function (e) {
8 | NavActions.goToPage($(e.target).data('target'));
9 | },
10 |
11 | getPanelClass: function (tab) {
12 | return classnames('tab-pane active', {
13 | 'landing-page': tab != 'data'
14 | });
15 | }
16 | };
17 |
18 | module.exports = IndexTabContentMixin;
19 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/presenters/ComplainingWitnessPresenter.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 | var gender = require('presenters/GenderPresenter');
4 |
5 |
6 | var ComplainingWitnessPresenter = function (complainingWitness) {
7 | var age = complainingWitness.age ? 'Age ' + complainingWitness.age : '';
8 | var genderReadable = gender(complainingWitness.gender);
9 | var race = complainingWitness.race || '';
10 |
11 | return _([race, genderReadable, age]).compact().join(', ');
12 | };
13 |
14 | module.exports = ComplainingWitnessPresenter;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/presenters/GenderPresenter.js:
--------------------------------------------------------------------------------
1 | var GenderMap = {
2 | 'F':'Female',
3 | 'M':'Male',
4 | 'X':'X'
5 | };
6 |
7 | var GenderPresenter = function (gender) {
8 | return gender && GenderMap[gender.toUpperCase()] || 'N/A';
9 | };
10 |
11 | module.exports = GenderPresenter;
12 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/presenters/InvestigatorPresenter.js:
--------------------------------------------------------------------------------
1 | var AppConstants = require('../constants/AppConstants');
2 |
3 |
4 | var InvestigatorPresenter = function (investigator) {
5 |
6 | var unitName = function () {
7 | return AppConstants.UNITS[investigator.unit] || 'Unknown unit';
8 | };
9 |
10 | return {
11 | name: (investigator.name || '').toUpperCase(),
12 | rank: investigator.current_rank || 'N/A',
13 | unitWithName: investigator.unit ? unitName() : 'Unknown unit'
14 | };
15 | };
16 |
17 | module.exports = InvestigatorPresenter;
18 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/presenters/RequestDocumentErrorPresenter.js:
--------------------------------------------------------------------------------
1 | var RequestDocumentErrorPresenter = function (errors) {
2 | var errorMessage = function () {
3 | if ('email' in errors) {
4 | return 'Please provide a valid email address';
5 | }
6 | return 'An error has occurred while processing your request';
7 | };
8 |
9 | return {
10 | 'errorMessage': errorMessage()
11 | };
12 | };
13 |
14 | module.exports = RequestDocumentErrorPresenter;
15 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/test-preprocessor.js:
--------------------------------------------------------------------------------
1 | // preprocessor.js
2 | var ReactTools = require('react-tools');
3 | module.exports = {
4 | process: function (src) {
5 | return ReactTools.transform(src);
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/test_utils/Factory.js:
--------------------------------------------------------------------------------
1 | var n = 0;
2 |
3 | var Factory = {
4 | createTagValue: function () {
5 | n++;
6 | return {
7 | value: 'value_' + n,
8 | category: 'category_' + n,
9 | displayValue: 'displayValue_' + n,
10 | displayCategory: 'displayCategory_' + n
11 | };
12 | }
13 | };
14 |
15 | module.exports = Factory;
16 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/tests/actions/OverlayActions.js:
--------------------------------------------------------------------------------
1 | var OverlayActions = require('actions/DataToolPage/OverlayActions');
2 | var AppConstants = require('constants/AppConstants');
3 | var AppDispatcher = require('dispatcher/AppDispatcher');
4 |
5 | require('should');
6 |
7 |
8 | describe('Overlay Actions', function () {
9 | it('should dispatch toggle overlay', function () {
10 | OverlayActions.toggleOverlay();
11 | AppDispatcher.dispatch.calledWithMatch({
12 | actionType: AppConstants.TOGGLE_OVERLAY
13 | }).should.be.true();
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/tests/factories/ComplaintFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 |
3 |
4 | f.define('Complaint', {
5 | 'officer_allegation': function () {
6 | return {};
7 | },
8 | 'documents': function () {
9 | return [];
10 | },
11 | 'officer': function () {
12 | return {};
13 | },
14 | 'officers': function () {
15 | return [];
16 | },
17 | 'allegation': function () {
18 | return {};
19 | }
20 | });
21 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/tests/factories/DocumentFactory.js:
--------------------------------------------------------------------------------
1 | var faker = require('faker');
2 |
3 | var f = require('utils/tests/f');
4 |
5 |
6 | f.define('Document', {
7 | 'title': function () {
8 | return faker.random.words();
9 | },
10 | 'documentcloud_id': function () {
11 | return 0;
12 | },
13 | 'type': function () {
14 | return 'CR';
15 | },
16 | 'requested': function () {
17 | return false;
18 | },
19 | 'pending': function () {
20 | return false;
21 | },
22 | 'normalized_title': function () {
23 | return '';
24 | }
25 | });
26 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/AllegationAPI.js:
--------------------------------------------------------------------------------
1 | var AppConstants = require('../constants/AppConstants');
2 | var AllegationActions = require('actions/DataToolPage/AllegationActions');
3 |
4 | var AllegationAPI = {
5 | getData: function (crid) {
6 | $.getJSON(AppConstants.ALLEGATION_DETAILS_API_ENDPOINT, { crid: crid }, function (data) {
7 | AllegationActions.receivedData(data);
8 | });
9 | }
10 | };
11 |
12 | module.exports = AllegationAPI;
13 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/DateTimeUtil.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 |
3 | var DateTimeUtil = {
4 | displayDateTime: function (date, format) {
5 | var momentDate = moment(date);
6 |
7 | if (momentDate.isValid()) {
8 | return momentDate.format(format);
9 | } else {
10 | return '';
11 | }
12 | }
13 | };
14 |
15 | module.exports = DateTimeUtil;
16 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/DocumentCloudAPI.js:
--------------------------------------------------------------------------------
1 | var jQuery = require('utils/jQuery');
2 | var StoryActions = require('actions/OfficerPage/StoryActions');
3 |
4 |
5 | var DocumentCloudAPI = {
6 | getThumbnail: function (story) {
7 |
8 | var url = story.url.replace(/\.html$/, '.json').replace('/documents/', '/api/documents/');
9 |
10 | jQuery.getJSON(url, function (data) {
11 | StoryActions.setThumbUrl(story, data.document.resources.thumbnail);
12 | });
13 | }
14 | };
15 |
16 | module.exports = DocumentCloudAPI;
17 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/InterfaceTextUtil.js:
--------------------------------------------------------------------------------
1 | var InterfaceTextUtil = {
2 | get: function (identifier) {
3 | return INTERFACE_TEXTS[identifier] || '';
4 | }
5 | };
6 |
7 | module.exports = InterfaceTextUtil;
8 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/MobileUtils.js:
--------------------------------------------------------------------------------
1 | var AppConstants = require('constants/AppConstants');
2 | var isMobile = require('ismobilejs');
3 |
4 | var MobileUtils = {
5 | isMobileView: function () {
6 | return $(window).width() < AppConstants.DESKTOP_SCREEN_WIDTH && isMobile.any;
7 | }
8 | };
9 |
10 | module.exports = MobileUtils;
11 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/OfficerPageAPIUtil.js:
--------------------------------------------------------------------------------
1 | var AppConstants = require('constants/AppConstants');
2 | var OfficerPageActions = require('actions/OfficerPage/OfficerPageActions');
3 |
4 | var ajax = null;
5 |
6 | var OfficerPageAPIUtil = {
7 | getOfficerData: function (officer) {
8 | if (ajax) {
9 | ajax.abort();
10 | }
11 |
12 | ajax = $.getJSON(AppConstants.OFFICER_PAGE_API_ENDPOINT, {'pk': officer}, function (data) {
13 | OfficerPageActions.receivedOfficerData(data);
14 | });
15 | }
16 | };
17 |
18 | module.exports = OfficerPageAPIUtil;
19 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/StoryListAPI.js:
--------------------------------------------------------------------------------
1 | var StoryListActions = require('actions/OfficerPage/StoryListActions');
2 |
3 | var StoryListAPI = {
4 | get: function (officerId) {
5 | jQuery.get('/officer/stories/', {officer: officerId}, function (data) {
6 | StoryListActions.receiveStories(data.stories);
7 | });
8 | }
9 | };
10 |
11 | module.exports = StoryListAPI;
12 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/TimelineAPI.js:
--------------------------------------------------------------------------------
1 | var TimelineActions = require('actions/OfficerPage/TimelineActions');
2 |
3 |
4 | var TimelineAPI = {
5 | getTimelineData: function (officerId) {
6 | $.getJSON('/officer/timeline/', {'officer': officerId}, function (data) {
7 | TimelineActions.receivedData(data);
8 | });
9 | }
10 | };
11 |
12 | module.exports = TimelineAPI;
13 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/location.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | getWindowHref: function () {
3 | return window.location.href;
4 | },
5 |
6 | popup: function (url) {
7 | window.open(url, 'pop', 'width=600, height=400, scrollbars=no');
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/querybuilders/QueryBuilderUtil.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 |
4 | var mergeArray = function (objValue, srcValue) {
5 | if (_.isArray(objValue)) {
6 | return _.union(objValue, srcValue);
7 | }
8 | };
9 |
10 |
11 | var QueryBuilderUtil = {
12 | mergeQueryParams: function (params) {
13 | return _.merge.apply(this, params.concat(mergeArray));
14 | }
15 | };
16 |
17 | module.exports = QueryBuilderUtil;
18 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/tests/f.js:
--------------------------------------------------------------------------------
1 | var Factory = require('utils/tests/Factory');
2 |
3 | module.exports = Factory();
4 |
--------------------------------------------------------------------------------
/allegation/static/allegation/js/utils/tests/should.js:
--------------------------------------------------------------------------------
1 | var should = require('should');
2 |
3 | should.Assertion.add('contains', function (str) {
4 | this.obj.indexOf(str).should.not.equal(-1);
5 | });
6 |
--------------------------------------------------------------------------------
/allegation/static/icomoon/fonts/icomoon.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/icomoon/fonts/icomoon.eot
--------------------------------------------------------------------------------
/allegation/static/icomoon/fonts/icomoon.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/icomoon/fonts/icomoon.ttf
--------------------------------------------------------------------------------
/allegation/static/icomoon/fonts/icomoon.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/static/icomoon/fonts/icomoon.woff
--------------------------------------------------------------------------------
/allegation/tasks.py:
--------------------------------------------------------------------------------
1 | from allegation.services.download_allegations import download_allegations # NOQA
2 |
--------------------------------------------------------------------------------
/allegation/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/constants.py:
--------------------------------------------------------------------------------
1 | TEST_DOCUMENT_URL = 'https://www.documentcloud.org/documents/1273509-cr-1002643.html'
2 |
--------------------------------------------------------------------------------
/allegation/tests/live/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/live/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/live/test_server_integrity.py:
--------------------------------------------------------------------------------
1 | from django.core.mail import send_mail
2 | from unittest.case import skip
3 |
4 | from common.tests.core import SimpleTestCase
5 |
6 |
7 | class LiveServerIntegrityTestCase(SimpleTestCase):
8 | skip_msg = 'Only need to run after production deploy, with live data'
9 |
10 | @skip(skip_msg)
11 | def test_email(self):
12 | return_code = send_mail('Production test email', 'Yo', None, ['giang.nguyen@eastagile.com'], fail_silently=True)
13 | return_code.should.equal(1)
14 |
--------------------------------------------------------------------------------
/allegation/tests/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/models/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/models/query.py:
--------------------------------------------------------------------------------
1 | from allegation.models.query import NullsLastQuery
2 | from common.tests.core import SimpleTestCase
3 | from common.models import Allegation
4 |
5 |
6 | class NullsLastQueryTestCase(SimpleTestCase):
7 | def test_get_compiler_raise_value_error(self):
8 | query = NullsLastQuery(Allegation)
9 | query.get_compiler.when.called_with(None, None).should.throw(ValueError)
10 |
--------------------------------------------------------------------------------
/allegation/tests/query_builders/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/query_builders/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/serializers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/serializers/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/services/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/utils/allegation_row_helper_mixin.py:
--------------------------------------------------------------------------------
1 | class AllegationRowHelperMixin(object):
2 | def open_complaint_detail(self):
3 | self.visit_home()
4 | self.find('.checkmark').click()
5 |
--------------------------------------------------------------------------------
/allegation/tests/utils/filter_tags_test_mixin.py:
--------------------------------------------------------------------------------
1 | class FilterTagsTestMixin(object):
2 | def assert_have_filter_tags(self, category, value):
3 | filter_tags = self.find('#filter-tags').text.lower()
4 | filter_tags.should.contain(category.lower())
5 | filter_tags.should.contain(str(value).lower())
6 |
7 | def assert_no_filter_tags(self):
8 | self.find_all('.filter').should.have.length_of(0)
9 |
--------------------------------------------------------------------------------
/allegation/tests/utils/outcome_filter.py:
--------------------------------------------------------------------------------
1 | from allegation.services.outcome_analytics import FILTERS
2 |
3 |
4 | def number_of_all_created_complaints():
5 | return sum(len(x) for x in FILTERS.values())
6 |
--------------------------------------------------------------------------------
/allegation/tests/utils_tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/utils_tests/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/views/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/views/base.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 |
3 |
4 | class OfficerAllegationApiTestBase(SimpleTestCase):
5 | _multiprocess_can_split_ = True
6 | _overridden_settings = {
7 | 'ALLEGATION_LIST_ITEM_COUNT': 10,
8 | }
9 |
--------------------------------------------------------------------------------
/allegation/tests/views/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/tests/views/ui/__init__.py
--------------------------------------------------------------------------------
/allegation/tests/views/ui/test_mobile_display.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import BaseMobileLiveTestCase
2 |
3 |
4 | class MobileDisplayTestCase(BaseMobileLiveTestCase):
5 | def test_data_tool_page_display(self):
6 | self.visit_home()
7 | self.find('.nav-tabs .map').text.should.contain('Map')
8 |
9 | self.link('Outcomes').click()
10 | self.find('.nav-tabs .map').get_attribute('class').shouldnt.contain('active')
11 |
--------------------------------------------------------------------------------
/allegation/tests/views/ui/test_sunburst_page.py:
--------------------------------------------------------------------------------
1 | from django.core.urlresolvers import reverse
2 |
3 | from common.tests.core import BaseLiveTestCase
4 | from share.factories import SessionFactory
5 |
6 |
7 | class SunburstPageTestCase(BaseLiveTestCase):
8 |
9 | def test_get_sunburst_page(self):
10 | session_hash = SessionFactory().hash_id
11 | self.visit(reverse('allegation:sunburst', args=[session_hash]))
12 | self.find('svg g path').should.be.ok
13 |
--------------------------------------------------------------------------------
/allegation/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/allegation/utils/__init__.py
--------------------------------------------------------------------------------
/allegation/utils/date.py:
--------------------------------------------------------------------------------
1 | import random
2 | import time
3 | import datetime
4 |
5 | from common.constants import DATE_ONLY_FORMAT
6 |
7 |
8 | def tomorrow():
9 | return datetime.datetime.now() + datetime.timedelta(days=1)
10 |
11 |
12 | def generate_random_date(start, end, format=DATE_ONLY_FORMAT):
13 | etime = time.mktime(time.strptime(end, format))
14 | stime = time.mktime(time.strptime(start, format))
15 |
16 | ptime = stime + random.random() * (etime - stime)
17 |
18 | return time.strftime(format, time.localtime(ptime))
19 |
--------------------------------------------------------------------------------
/allegation/utils/session.py:
--------------------------------------------------------------------------------
1 | def build_query_string_from_session(session):
2 | parts = []
3 | for objs in session.query.get('filters', {}).values():
4 | for obj in objs:
5 | if 'filter' in obj:
6 | parts.append(obj['filter'])
7 | else:
8 | parts.append('%s=%s' % (obj['category'], obj['value']))
9 | return '&'.join(parts)
10 |
--------------------------------------------------------------------------------
/allegation/views/landing_view.py:
--------------------------------------------------------------------------------
1 | from django.views.generic.base import TemplateView
2 |
3 |
4 | class LandingView(TemplateView):
5 | template_name = "allegation/landing.html"
6 |
--------------------------------------------------------------------------------
/api/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/api/__init__.py
--------------------------------------------------------------------------------
/api/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 | from api.models import InterfaceText
5 |
6 | admin.site.register(InterfaceText, admin.ModelAdmin)
7 |
--------------------------------------------------------------------------------
/api/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/api/migrations/__init__.py
--------------------------------------------------------------------------------
/api/serializers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/api/serializers/__init__.py
--------------------------------------------------------------------------------
/api/serializers/interfacetext_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from api.models import InterfaceText
4 |
5 |
6 | class InterfaceTextSerializer(serializers.ModelSerializer):
7 |
8 | class Meta:
9 | model = InterfaceText
10 |
--------------------------------------------------------------------------------
/api/serializers/investigator_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from common.models import Investigator
4 |
5 |
6 | class InvestigatorSerializer(serializers.HyperlinkedModelSerializer):
7 | class Meta:
8 | model = Investigator
9 | fields = (
10 | 'id',
11 | 'raw_name',
12 | 'name',
13 | 'complaint_count',
14 | 'discipline_count',
15 | 'current_rank'
16 | )
17 |
--------------------------------------------------------------------------------
/api/serializers/session_analytic_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from share.models import Session
4 |
5 |
6 | class SessionAnalyticSerializer(serializers.ModelSerializer):
7 | created_date = serializers.DateTimeField()
8 | count = serializers.IntegerField()
9 |
10 | class Meta:
11 | model = Session
12 | fields = (
13 | 'created_date',
14 | 'count'
15 | )
16 |
--------------------------------------------------------------------------------
/api/serializers/story_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from officer.models import Story
4 |
5 |
6 | class StorySerializer(serializers.HyperlinkedModelSerializer):
7 | class Meta:
8 | model = Story
9 | fields = ('id',
10 | 'officer',
11 | 'title',
12 | 'slug',
13 | 'short_description',
14 | 'content',
15 | 'story_type',
16 | 'created_date',
17 | 'url',
18 | )
19 |
--------------------------------------------------------------------------------
/api/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/api/tests/__init__.py
--------------------------------------------------------------------------------
/api/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/api/tests/views/__init__.py
--------------------------------------------------------------------------------
/api/tests/views/test_session_view.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 | from share.factories import SessionFactory
3 |
4 |
5 | class SessionViewTestCase(SimpleTestCase):
6 | def test_get_session_by_hash(self):
7 | session = SessionFactory()
8 | response = self.client.get("/api/sessions/{hash}/".format(hash=session.hash_id))
9 | response.status_code.should.equal(200)
10 | response_json = self.json(response)
11 | response_json['title'].should.equal(session.title)
12 |
--------------------------------------------------------------------------------
/api/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url, include
2 | from rest_framework import routers
3 |
4 | from api.views.officer_view import OfficerViewSet
5 | from api.views.session_view import SessionViewSet
6 |
7 |
8 | router = routers.DefaultRouter()
9 | router.register(r'officers', OfficerViewSet)
10 | router.register(r'sessions', SessionViewSet)
11 |
12 |
13 | urlpatterns = [
14 | url(r'^', include(router.urls)),
15 | ]
16 |
--------------------------------------------------------------------------------
/api/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/api/views/__init__.py
--------------------------------------------------------------------------------
/api/views/officer_view.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 |
3 | from api.serializers.officer_serializer import OfficerSerializer
4 | from common.models import Officer
5 |
6 |
7 | class OfficerViewSet(viewsets.ReadOnlyModelViewSet):
8 | queryset = Officer.objects.all()
9 | serializer_class = OfficerSerializer
10 |
--------------------------------------------------------------------------------
/api/views/session_view.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 |
3 | from api.serializers.session_serializer import SessionSerializer
4 | from share.models import Session
5 |
6 |
7 | class SessionViewSet(viewsets.ReadOnlyModelViewSet):
8 | queryset = Session.objects.all()
9 | serializer_class = SessionSerializer
10 |
11 | def get_object(self):
12 | if 'pk' in self.kwargs:
13 | self.kwargs['pk'] = Session.id_from_hash(self.kwargs['pk'])[0]
14 | return super(SessionViewSet, self).get_object()
15 |
--------------------------------------------------------------------------------
/bin/collect_static:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -eo pipefail
3 |
4 | indent() {
5 | RE="s/^/ /"
6 | [ $(uname) == "Darwin" ] && sed -l "$RE" || sed -u "$RE"
7 | }
8 |
9 | MANAGE_FILE=$(find . -maxdepth 3 -type f -name 'manage.py' | head -1)
10 | MANAGE_FILE=${MANAGE_FILE:2}
11 |
12 | echo "-----> Collecting static files"
13 |
14 | python $MANAGE_FILE bower_install 2>&1
15 |
16 | python $MANAGE_FILE collectstatic --noinput --settings=cpdb.settings.local.dev 2>&1 | sed '/^Copying/d;/^$/d;/^ /d' | indent
17 |
18 | echo
19 |
--------------------------------------------------------------------------------
/bin/shows_pr_since_last_deploy:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | git checkout master
4 | CUR_ID="$(git rev-parse HEAD)"
5 | git checkout -b "master$CUR_ID"
6 | git merge develop -m "Merge changes from develop"
7 | echo "----------------- PULL REQUESTS SINCE LAST DEPLOY -----------------"
8 | git --no-pager log $CUR_ID..HEAD --pretty=oneline --abbrev-commit --grep "Merge pull request"
9 | echo "-------------------------------------------------------------------"
10 | git checkout master
11 | git branch -D "master$CUR_ID"
12 |
--------------------------------------------------------------------------------
/bin/start_dev.sh:
--------------------------------------------------------------------------------
1 | tmux new -d -s watch_allegation 'gulp watch_allegation; tmux detach'
2 | tmux new -d -s watch_mobile 'gulp watch_mobile; tmux detach'
3 | tmux new -d -s watch_dashboard 'gulp watch_dashboard; tmux detach'
4 | tmux new -d -s elasticsearch '../elasticsearch/bin/elasticsearch; tmux detach'
5 | tmux new -d -s redis_server 'redis-server; tmux detach;'
6 |
--------------------------------------------------------------------------------
/bin/stop_dev.sh:
--------------------------------------------------------------------------------
1 | tmux kill-server
2 |
--------------------------------------------------------------------------------
/common/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'common.apps.CommonConfig'
2 |
--------------------------------------------------------------------------------
/common/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CommonConfig(AppConfig):
5 | name = 'common'
6 | verbose_name = 'Common'
7 |
8 | def ready(self):
9 | import common.signals.handlers # NOQA
10 |
--------------------------------------------------------------------------------
/common/decorators.py:
--------------------------------------------------------------------------------
1 | from tqdm import tqdm
2 |
3 |
4 | def apply_with_progress_bar(desc=None):
5 | def decorator(key_func):
6 | def func_wrapper(iterable):
7 | pbar = tqdm(total=len(iterable), desc=desc)
8 | for obj in iterable:
9 | pbar.update()
10 | key_func(obj)
11 | pbar.close()
12 | return func_wrapper
13 | return decorator
14 |
--------------------------------------------------------------------------------
/common/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/management/__init__.py
--------------------------------------------------------------------------------
/common/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/management/commands/__init__.py
--------------------------------------------------------------------------------
/common/management/commands/build_google_sitemap.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | from django.utils.text import slugify
3 |
4 | from common.models import Officer
5 |
6 |
7 | class Command(BaseCommand):
8 | @staticmethod
9 | def officer_profile_link(officer):
10 | return 'http://cpdb.co/officer/{slug}/{id}'.format(id=officer.id, slug=slugify(officer.display_name))
11 |
12 | def handle(self, *args, **options):
13 | for officer in Officer.objects.all():
14 | self.stdout.write(self.officer_profile_link(officer))
15 |
--------------------------------------------------------------------------------
/common/management/commands/fix_final_finding_null.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from common.models import OfficerAllegation
4 |
5 |
6 | class Command(BaseCommand):
7 | help = 'Change final_finding None to ZZ instead'
8 |
9 | def handle(self, *args, **options):
10 | OfficerAllegation.objects.filter(final_finding=None)\
11 | .update(final_finding="ZZ")
12 |
--------------------------------------------------------------------------------
/common/management/commands/get_allegation_date_only.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from common.models import Allegation
4 |
5 |
6 | class Command(BaseCommand):
7 | help = 'Get date only from incident date'
8 |
9 | def handle(self, *args, **options):
10 | for allegation in Allegation.objects.all()\
11 | .filter(incident_date_only=None):
12 | if allegation.incident_date:
13 | allegation.incident_date_only = allegation.incident_date.date()
14 | allegation.save()
15 |
--------------------------------------------------------------------------------
/common/management/commands/normalize_race_data.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 | from common.models import Officer
3 |
4 |
5 | OLD_EMPTY_RACE = 'Unknown'
6 |
7 |
8 | class Command(BaseCommand):
9 | def handle(self, *args, **options):
10 | Officer.objects.filter(race=OLD_EMPTY_RACE).update(race='')
11 |
--------------------------------------------------------------------------------
/common/management/commands/populate_documents_for_allegation.py:
--------------------------------------------------------------------------------
1 | from django.core.management.base import BaseCommand
2 |
3 | from common.constants import DOCUMENT_TYPES
4 | from common.models import Allegation
5 |
6 |
7 | class Command(BaseCommand):
8 |
9 | def handle(self, *args, **options):
10 | allegations = Allegation.objects.filter()
11 |
12 | for allegation in allegations:
13 | for document_type in DOCUMENT_TYPES:
14 | allegation.documents.get_or_create(type=document_type[0])
15 |
--------------------------------------------------------------------------------
/common/middleware/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/middleware/__init__.py
--------------------------------------------------------------------------------
/common/middleware/user_agent.py:
--------------------------------------------------------------------------------
1 | BotNames = [
2 | 'Googlebot', 'Slurp', 'Twiceler', 'msnbot', 'KaloogaBot', 'YodaoBot', '"Baiduspider', 'googlebot', 'Speedy Spider',
3 | 'DotBot']
4 | param_name = 'deny_crawlers'
5 |
6 |
7 | class CrawlerDetector(object):
8 | def process_request(self, request):
9 | user_agent = request.META.get('HTTP_USER_AGENT', [])
10 |
11 | request.is_crawler = False
12 |
13 | for botname in BotNames:
14 | if botname in user_agent:
15 | request.is_crawler = True
16 | break
17 |
--------------------------------------------------------------------------------
/common/migrations/0003_officerallegation_officer_age.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('common', '0002_documentcrawler'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='officerallegation',
16 | name='officer_age',
17 | field=models.IntegerField(null=True, db_index=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/common/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/migrations/__init__.py
--------------------------------------------------------------------------------
/common/models/time_stamp.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class TimeStampedModel(models.Model):
5 | created_at = models.DateTimeField(auto_now_add=True)
6 | modified_at = models.DateTimeField(auto_now=True)
7 |
8 | class Meta:
9 | abstract = True
10 |
--------------------------------------------------------------------------------
/common/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/services/__init__.py
--------------------------------------------------------------------------------
/common/signals/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/signals/__init__.py
--------------------------------------------------------------------------------
/common/signals/handlers.py:
--------------------------------------------------------------------------------
1 | from django.db.models.signals import post_save
2 | from django.dispatch.dispatcher import receiver
3 |
4 | from common.constants import DOCUMENT_TYPES
5 | from common.models import Allegation
6 |
7 |
8 | @receiver(post_save, sender=Allegation, dispatch_uid='create_documents_for_allegation')
9 | def create_documents_for_allegation(sender, instance, created, **kwargs):
10 | if created:
11 | for document_type in DOCUMENT_TYPES:
12 | instance.documents.get_or_create(type=document_type[0])
13 |
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Black.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Black.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Bold.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Heavy.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Heavy.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Light.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Light.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Medium.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Regular.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Semibold.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Thin.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Thin.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Display-Ultralight.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Display-Ultralight.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-Bold.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-BoldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-BoldItalic.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-Heavy.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-Heavy.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-HeavyItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-HeavyItalic.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-Light.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-Light.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-LightItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-LightItalic.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-Medium.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-Medium.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-MediumItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-MediumItalic.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-Regular.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-RegularItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-RegularItalic.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-Semibold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-Semibold.otf
--------------------------------------------------------------------------------
/common/static/fonts/SF-Compact-Text-SemiboldItalic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/fonts/SF-Compact-Text-SemiboldItalic.otf
--------------------------------------------------------------------------------
/common/static/img/64x_map_marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/64x_map_marker.png
--------------------------------------------------------------------------------
/common/static/img/complaint_process.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/complaint_process.png
--------------------------------------------------------------------------------
/common/static/img/default.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/default.gif
--------------------------------------------------------------------------------
/common/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/favicon.ico
--------------------------------------------------------------------------------
/common/static/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/logo.png
--------------------------------------------------------------------------------
/common/static/img/logox2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/logox2.png
--------------------------------------------------------------------------------
/common/static/img/map-fade-hover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/map-fade-hover.png
--------------------------------------------------------------------------------
/common/static/img/map-fade.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/map-fade.png
--------------------------------------------------------------------------------
/common/static/img/map.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/map.png
--------------------------------------------------------------------------------
/common/static/img/page-header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/img/page-header.png
--------------------------------------------------------------------------------
/common/static/js/foot_define.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/static/js/foot_define.js
--------------------------------------------------------------------------------
/common/static/js/selenium_coverage.js:
--------------------------------------------------------------------------------
1 | // blanket.options({
2 | // timeout: 30000,
3 | // reporter: 'string'
4 | // });
5 |
6 | // blanket.customReporter=function(coverage_results){
7 | // window.coverage_results = coverage_results;
8 | // };
9 |
10 | // blanket.beforeStartTestRunner({
11 | // callback: function(){
12 | // blanket.setupCoverage();
13 | // blanket.onTestStart();
14 |
15 | // }
16 | // });
17 | initReact();
18 |
--------------------------------------------------------------------------------
/common/static/sass/data_tool_page.sass:
--------------------------------------------------------------------------------
1 | @import 'data_tool_page/race_gender_tab'
2 | @import 'data_tool_page/embed'
3 | @import 'data_tool_page/share'
4 | @import 'data_tool_page/horizontal_percentage_chart'
5 | @import 'data_tool_page/race_gender_age_tab'
6 |
--------------------------------------------------------------------------------
/common/static/sass/data_tool_page/race_gender_age_tab.sass:
--------------------------------------------------------------------------------
1 | .race-gender-age-tab
2 | padding: 30px
3 | padding-right: 60px
4 |
5 | .title
6 | font-size: 16.75px
7 | font-weight: bold
8 | margin-bottom: 10px
9 |
10 | @media (min-width: $screen-md-min)
11 | .race-gender-age-tab
12 | max-width: 612px
13 |
--------------------------------------------------------------------------------
/common/static/sass/data_tool_page/race_gender_tab.sass:
--------------------------------------------------------------------------------
1 | #gender-race-tab
2 | padding: 20px 0
3 | .chart-title
4 | font-size: 14px
5 | .vertical-chart-title
6 | top: 80px
7 | span
8 | transform: rotate(-90deg)
9 | float: left
10 | .row
11 | padding-top: 7x
12 | padding-bottom: 7px
13 |
14 | .relative
15 | postition: relative
16 | .vertical-title
17 | float: left
18 | position: absolute
19 | bottom: -15px
20 | display: inline-block
21 | left: -15px
22 | transform: rotate(-90deg)
23 | transform-origin: 0 0 0
--------------------------------------------------------------------------------
/common/static/sass/donut-chart.sass:
--------------------------------------------------------------------------------
1 | .donut-chart-inner-text
2 | color: #013270
3 |
4 | .donut-chart-fraction-text
5 | font-size: 28px
6 |
7 | .donut-chart-label-text
8 | font-size: 16px
9 |
--------------------------------------------------------------------------------
/common/static/sass/glossary_page.sass:
--------------------------------------------------------------------------------
1 | .glossary-page
2 | .row
3 | margin-bottom: 50px
4 |
--------------------------------------------------------------------------------
/common/static/sass/mobile.sass:
--------------------------------------------------------------------------------
1 | .mobile
2 | .chart-row
3 | .nav-tabs
4 | > li
5 | width: 25%
6 | #summary-container
7 | margin: 0
8 |
--------------------------------------------------------------------------------
/common/static/sass/officer-profile.sass:
--------------------------------------------------------------------------------
1 | .document-thumbnail
2 | border: solid 1px $color_blue_ribbon_approx
3 |
4 | .story
5 | >.title
6 | >a
7 | color: $color_mine_shaft_approx
8 |
9 | #officer-profile
10 | background-color: $color_spring_wood_approx2
11 |
12 | .sticky-footer
13 | padding-top: 36px
14 |
--------------------------------------------------------------------------------
/common/static/sass/shared.sass:
--------------------------------------------------------------------------------
1 | @import 'shared/site-links'
2 | @import 'shared/overlay'
3 |
--------------------------------------------------------------------------------
/common/static/sass/shared/overlay.sass:
--------------------------------------------------------------------------------
1 | #overlay
2 | &.active
3 | position: fixed
4 | top: 0
5 | width: 100%
6 | height: 100%
7 | opacity: .7
8 | background: black
9 | z-index: 1000
10 |
--------------------------------------------------------------------------------
/common/static/sass/shared/site-links.sass:
--------------------------------------------------------------------------------
1 | .site-links-wrapper
2 |
3 | .site-links
4 | background: transparent
5 | border-bottom: none
6 | color: #333
7 | padding: 15px
8 |
9 | li > a
10 | color: $color_deep_cerulean_approx !important // bad idea :(
11 | &:hover
12 | color: $color_deep_cerulean_approx !important
13 |
14 |
--------------------------------------------------------------------------------
/common/static/sass/test.sass:
--------------------------------------------------------------------------------
1 | *
2 | /*CSS transitions
3 | -o-transition-property: none !important
4 | -moz-transition-property: none !important
5 | -ms-transition-property: none !important
6 | -webkit-transition-property: none !important
7 | transition-property: none !important
8 | /*CSS transforms
9 | -o-transform: none !important
10 | -moz-transform: none !important
11 | -ms-transform: none !important
12 | -webkit-transform: none !important
13 | transform: none !important
14 | /*CSS animations
15 | animation-duration: 0s !important
16 |
--------------------------------------------------------------------------------
/common/static/sass/wagtail/glossary-table-section.sass:
--------------------------------------------------------------------------------
1 | .glossary-table
2 | & > tbody > tr > td
3 | border: none
4 | .term
5 | width: 30%
6 | color: black
7 | .definition
8 | width: 58%
9 | color: black
10 | .category
11 | width: 12%
12 |
--------------------------------------------------------------------------------
/common/static/sunburst.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |
--------------------------------------------------------------------------------
/common/templates/_footer_nav.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 | {% load url from future %}
3 |
8 |
--------------------------------------------------------------------------------
/common/templates/_notification.html:
--------------------------------------------------------------------------------
1 | {% load bootstrap %}
2 | {% if messages %}
3 |
4 | {% for message in messages %}
5 | {% render_message message %}
6 | {% endfor %}
7 |
8 | {% endif %}
--------------------------------------------------------------------------------
/common/templates/_notification_message.html:
--------------------------------------------------------------------------------
1 | {% if "template" in message.tags_array %}
2 | {% include message.message %}
3 | {% else %}
4 |
5 | {{ message }}
6 |
7 | {% endif %}
--------------------------------------------------------------------------------
/common/templates/_top_banner.html:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/templates/_top_banner.html
--------------------------------------------------------------------------------
/common/templates/common/user_name_block.html:
--------------------------------------------------------------------------------
1 | {% if user.fullname %}
2 | {{ user.fullname }}
3 | {% else %}
4 | {{ user.username }}
5 | {% endif %}
6 |
--------------------------------------------------------------------------------
/common/templates/general/form_requirement.html:
--------------------------------------------------------------------------------
1 | {% load staticfiles %}
2 | {% if datetimepicker %}
3 |
6 |
7 |
8 | {% endif %}
9 |
--------------------------------------------------------------------------------
/common/templates/homepage.html:
--------------------------------------------------------------------------------
1 | {% extends 'base.html' %}
2 | {% load i18n %}
3 |
--------------------------------------------------------------------------------
/common/templatetags/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/templatetags/__init__.py
--------------------------------------------------------------------------------
/common/templatetags/common_filters.py:
--------------------------------------------------------------------------------
1 | from django.template import Library
2 |
3 | register = Library()
4 |
5 |
6 | @register.filter
7 | def replace(var, args):
8 | if args is None:
9 | return False
10 | old, new = args.split(',')
11 | return var.replace(old, new)
12 |
--------------------------------------------------------------------------------
/common/templatetags/common_tags.py:
--------------------------------------------------------------------------------
1 | """
2 | Created on Jul 29, 2013
3 |
4 | @author: antipro
5 | """
6 |
--------------------------------------------------------------------------------
/common/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/__init__.py
--------------------------------------------------------------------------------
/common/tests/admin/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/admin/__init__.py
--------------------------------------------------------------------------------
/common/tests/integrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/integrations/__init__.py
--------------------------------------------------------------------------------
/common/tests/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/management/__init__.py
--------------------------------------------------------------------------------
/common/tests/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/management/commands/__init__.py
--------------------------------------------------------------------------------
/common/tests/middleware/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/middleware/__init__.py
--------------------------------------------------------------------------------
/common/tests/mixins/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/mixins/__init__.py
--------------------------------------------------------------------------------
/common/tests/mixins/outcome_filter_mixin.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import BaseLiveTestCase
2 |
3 |
4 | class OutcomeFilterTestMixin(BaseLiveTestCase):
5 | def get_outcome_tab_count(self):
6 | return len(self.find_all('.filters > span'))
7 |
8 | def get_outcome_tab_at(self, position):
9 | return self.find_all('.filters > span')[position]
10 |
11 | def assert_number_of_complaints_in_tab(self, numbers, position):
12 | self.get_outcome_tab_at(position).click()
13 | len(self.find_all('.complaint-row')).should.equal(numbers)
14 |
--------------------------------------------------------------------------------
/common/tests/mixins/sunburst_chart_mixin.py:
--------------------------------------------------------------------------------
1 | class SunburstChartTestMixin(object):
2 | def click_on_sunburst(self, index):
3 | self.browser.execute_script(
4 | '''
5 | var path = d3
6 | .select('g#sunburstd3-chart-container')
7 | .select('path:nth-child({index})');
8 |
9 | path.on('click').call(path.node(), path.datum());
10 | '''
11 | .format(index=index)
12 | )
13 | self.until_ajax_complete()
14 |
--------------------------------------------------------------------------------
/common/tests/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/models/__init__.py
--------------------------------------------------------------------------------
/common/tests/models/test_investigator_model.py:
--------------------------------------------------------------------------------
1 | from allegation.factories import InvestigatorFactory
2 | from common.tests.core import SimpleTestCase
3 |
4 |
5 | class InvestigatorModelTestCase(SimpleTestCase):
6 | def test_absolute_url(self):
7 | investigator = InvestigatorFactory(name='Daniel Neubeck')
8 | investigator.absolute_url.should.equal('/investigator/daniel-neubeck/%s' % investigator.id)
9 |
--------------------------------------------------------------------------------
/common/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/services/__init__.py
--------------------------------------------------------------------------------
/common/tests/utils/test_mobile_url_hash_util.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 | from common.utils.mobile_url_hash_util import MobileUrlHashUtil
3 |
4 |
5 | class MobileUrlHashUtilTest(SimpleTestCase):
6 | def setUp(self):
7 | self.manager = MobileUrlHashUtil()
8 |
9 | def test_encode(self):
10 | self.manager.encode(123).should.be.equal('pJ84j3ME')
11 |
12 | def test_decode(self):
13 | hash = 'KJeZ1BMz'
14 | self.manager.decode(hash).should.be.equal(436)
15 |
--------------------------------------------------------------------------------
/common/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/common/tests/views/__init__.py
--------------------------------------------------------------------------------
/common/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from common.views.lookup_view import LookupView
4 |
5 | urlpatterns = [
6 | url(r'^(?P.*)$', LookupView.as_view(), name='lookup')
7 | ]
8 |
--------------------------------------------------------------------------------
/common/utils/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'user'
2 |
--------------------------------------------------------------------------------
/common/utils/hashid.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 | from hashids import Hashids
3 |
4 | hash_obj = Hashids(settings.SECRET_KEY, min_length=6)
5 |
--------------------------------------------------------------------------------
/common/utils/haystack.py:
--------------------------------------------------------------------------------
1 | from haystack.management.commands.rebuild_index import Command as RebuildIndexCommand
2 |
3 |
4 | def rebuild_index():
5 | cmd = RebuildIndexCommand()
6 | cmd.handle(interactive=False, verbosity=0)
7 |
--------------------------------------------------------------------------------
/common/utils/http_request.py:
--------------------------------------------------------------------------------
1 | def get_client_ip(request):
2 | x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
3 | if x_forwarded_for:
4 | ip = x_forwarded_for.split(',')[0]
5 | else:
6 | ip = request.META.get('REMOTE_ADDR')
7 | return ip
8 |
--------------------------------------------------------------------------------
/common/utils/mobile_url_hash_util.py:
--------------------------------------------------------------------------------
1 | from hashids import Hashids
2 |
3 | from common.constants import MOBILE_SALT
4 |
5 |
6 | class MobileUrlHashUtil(object):
7 | def __init__(self):
8 | self.instance = Hashids(MOBILE_SALT, min_length=8)
9 |
10 | def encode(self, str):
11 | return self.instance.encode(str)
12 |
13 | def decode(self, str):
14 | return self.instance.decode(str)[0]
15 |
--------------------------------------------------------------------------------
/common/views/__init__.py:
--------------------------------------------------------------------------------
1 | from django.http.response import HttpResponseRedirect
2 |
3 |
4 | def handler404(request):
5 | return HttpResponseRedirect("/")
6 |
--------------------------------------------------------------------------------
/cpdb/__init__.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | # This will make sure the app is always imported when
4 | # Django starts so that shared_task will use this app.
5 | from .celery import app as celery_app # NOQA
6 |
--------------------------------------------------------------------------------
/cpdb/celery.py:
--------------------------------------------------------------------------------
1 | from __future__ import absolute_import
2 |
3 | import os
4 |
5 | from celery import Celery
6 |
7 | # set the default Django settings module for the 'celery' program.
8 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'cpdb.settings.local.common')
9 |
10 | from django.conf import settings # NOQA
11 |
12 | app = Celery('cpdb')
13 |
14 | # Using a string here means the worker will not have to
15 | # pickle the object when using Windows.
16 | app.config_from_object('django.conf:settings')
17 | app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
18 |
--------------------------------------------------------------------------------
/cpdb/context_precessors.py:
--------------------------------------------------------------------------------
1 | from django.conf import settings
2 |
3 |
4 | def env_settings(_):
5 | return {
6 | 'DJANGO_ENV': settings.DJANGO_ENV,
7 | }
8 |
--------------------------------------------------------------------------------
/cpdb/settings/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/cpdb/settings/__init__.py
--------------------------------------------------------------------------------
/cpdb/settings/local/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/cpdb/settings/local/__init__.py
--------------------------------------------------------------------------------
/cpdb/settings/prod/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/cpdb/settings/prod/__init__.py
--------------------------------------------------------------------------------
/cpdb/settings/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/cpdb/settings/test/__init__.py
--------------------------------------------------------------------------------
/cpdb/settings/test/circleci.py:
--------------------------------------------------------------------------------
1 | from cpdb.settings.test.common import * # NOQA
2 |
3 | DEBUG = True
4 |
5 | DATABASES = {
6 | 'default': {
7 | 'ENGINE': 'django.contrib.gis.db.backends.postgis',
8 | 'NAME': 'circle_test',
9 | 'HOST': 'localhost',
10 | 'PORT': '***REMOVED***',
11 | 'USER': 'ubuntu',
12 | 'TEST': {
13 | 'NAME': 'circle_test',
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/cpdb/wsgi.py:
--------------------------------------------------------------------------------
1 | """
2 | WSGI config for cpdb project.
3 |
4 | It exposes the WSGI callable as a module-level variable named ``application``.
5 |
6 | For more information on this file, see
7 | https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
8 | """
9 |
10 | import os
11 |
12 | from django.core.wsgi import get_wsgi_application
13 |
14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "cpdb.settings.prod.digitalocean")
15 |
16 | application = get_wsgi_application()
17 |
--------------------------------------------------------------------------------
/dashboard/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/__init__.py
--------------------------------------------------------------------------------
/dashboard/authentication.py:
--------------------------------------------------------------------------------
1 | from rest_framework import authentication
2 |
3 |
4 | class SessionAuthentication(authentication.SessionAuthentication):
5 | def enforce_csrf(self, request):
6 | return
7 |
--------------------------------------------------------------------------------
/dashboard/exceptions.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | class InvalidDocumentError(Exception):
4 | def __init__(self, message='Invalid document link'):
5 | self.message = message
6 |
7 | def __str__(self):
8 | return repr(self.message)
9 |
--------------------------------------------------------------------------------
/dashboard/forms/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'eastagile'
2 |
3 | from dashboard.forms.document_request_status_form import DocumentRequestStatusForm # NOQA
4 |
--------------------------------------------------------------------------------
/dashboard/forms/alias_form.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 |
3 | from search.models.alias import Alias
4 |
5 |
6 | class AliasForm(forms.ModelForm):
7 | class Meta:
8 | model = Alias
9 | fields = ('alias', 'target')
10 |
--------------------------------------------------------------------------------
/dashboard/forms/officer_form.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from common.models import Officer
3 |
4 |
5 | class OfficerForm(forms.ModelForm):
6 | class Meta:
7 | model = Officer
8 | fields = ('birth_year', 'star', 'officer_last', 'id', 'officer_first', 'gender', 'rank', 'unit', 'appt_date',
9 | 'race',)
10 |
--------------------------------------------------------------------------------
/dashboard/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/migrations/__init__.py
--------------------------------------------------------------------------------
/dashboard/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/models/__init__.py
--------------------------------------------------------------------------------
/dashboard/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/services/__init__.py
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/DocumentSection/DocumentCloudActions.js:
--------------------------------------------------------------------------------
1 | var DocumentCloudAPI = require('utils/DocumentCloudAPI');
2 |
3 |
4 | var DocumentCloudActions = {
5 | uploadDocument: function (data) {
6 | return DocumentCloudAPI.uploadDocument(data);
7 | }
8 | };
9 |
10 | module.exports = DocumentCloudActions;
11 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/NavigationActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../dispatcher/AppDispatcher');
2 | var AppConstants = require('../constants/AppConstants');
3 |
4 | var NavigationActions = {
5 | setActiveItem: function (activeItem) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_ACTIVE_NAV_ITEM,
8 | activeItem: activeItem
9 | });
10 | }
11 | };
12 |
13 | module.exports = NavigationActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OfficerSection/Officer/TabsActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../../constants/AppConstants');
3 |
4 | var TabsActions = {
5 | setActive: function (method) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_OFFICER_TAB_ACTIVE,
8 | data: method
9 | });
10 | },
11 |
12 | goToStoryForm: function () {
13 | this.setActive('storyForm');
14 | }
15 | };
16 |
17 | module.exports = TabsActions;
18 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OfficerSection/OfficerListActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var OfficerListAction = {
5 | receivedOfficerList: function (data) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RECEIVED_OFFICER_LIST,
8 | data: data
9 | });
10 | }
11 | };
12 |
13 | module.exports = OfficerListAction;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OfficerSection/SearchActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var SearchActions = {
5 | search: function (query) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SEARCH_OFFICER_WITH_QUERY,
8 | data: query
9 | });
10 | }
11 | };
12 |
13 | module.exports = SearchActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OfficerSectionActions.js:
--------------------------------------------------------------------------------
1 | var OfficerAPI = require('../utils/OfficerAPI');
2 |
3 | var OfficerSectionActions = {
4 | loadOfficer: function (id) {
5 | OfficerAPI.loadById(id);
6 | }
7 | };
8 |
9 | module.exports = OfficerSectionActions;
10 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OverviewSection/NewSessionPerDayChartActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var NewSessionPerDayChartActions = {
5 | receivedData: function (data) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RECEIVED_NEW_SESSIONS_DATA,
8 | data: data
9 | });
10 | }
11 | };
12 |
13 | module.exports = NewSessionPerDayChartActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OverviewSection/PeriodPickerActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var PeriodPickerActions = {
5 | setPeriod: function (period) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_PERIOD,
8 | period: period
9 | });
10 | }
11 | };
12 |
13 | module.exports = PeriodPickerActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/OverviewSection/QueryItemListActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var QueryItemListActions = {
5 | setActiveItem: function (activeQueryItem) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_ACTIVE_QUERY_ITEM,
8 | activeQueryItem: activeQueryItem
9 | });
10 | }
11 | };
12 |
13 | module.exports = QueryItemListActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/SearchSection/QueryListActions.js:
--------------------------------------------------------------------------------
1 | var AppConstants = require('../../constants/AppConstants');
2 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
3 |
4 | var QueryListActions = {
5 | lockScroll: function () {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.LOCK_SCROLL
8 | });
9 | },
10 |
11 | sortBy: function (sortBy) {
12 | AppDispatcher.dispatch({
13 | actionType: AppConstants.SORT_QUERY_LIST,
14 | data: sortBy
15 | });
16 | }
17 | };
18 |
19 | module.exports = QueryListActions;
20 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/SearchSection/QueryListFilterActions.js:
--------------------------------------------------------------------------------
1 | var AppConstants = require('../../constants/AppConstants');
2 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
3 |
4 | var QueryListFilterActions = {
5 | setActiveItem: function (key) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_QUERY_LIST_ACTIVE_ITEM,
8 | data: key
9 | });
10 | }
11 | };
12 |
13 | module.exports = QueryListFilterActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/SearchSection/SearchActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var SearchActions = {
5 | searchFor: function (query) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SEARCH_FOR_SUGGESTIONS,
8 | data: query
9 | });
10 | }
11 | };
12 |
13 | module.exports = SearchActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/SearchTrafficServerActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../dispatcher/AppDispatcher');
2 | var AppConstants = require('../constants/AppConstants');
3 |
4 | var SearchTrafficServerActions = {
5 | receivedSearchTrafficData: function (data) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.RECEIVED_SEARCH_TRAFFIC_DATA,
8 | data: data
9 | });
10 | }
11 | };
12 |
13 | module.exports = SearchTrafficServerActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/actions/SessionSection/TabsActions.js:
--------------------------------------------------------------------------------
1 | var AppDispatcher = require('../../dispatcher/AppDispatcher');
2 | var AppConstants = require('../../constants/AppConstants');
3 |
4 | var TabsActions = {
5 | setActive: function (tab) {
6 | AppDispatcher.dispatch({
7 | actionType: AppConstants.SET_SESSION_ACTIVE_TAB,
8 | data: tab
9 | });
10 | }
11 | };
12 |
13 | module.exports = TabsActions;
14 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/components/Period.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var Period = React.createClass({
4 | getInitialState: function () {
5 | return {};
6 | },
7 |
8 | componentDidMount: function () {
9 |
10 | },
11 |
12 | componentWillUnmount: function () {
13 |
14 | },
15 |
16 | render: function () {
17 | return (
18 |
19 | );
20 | }
21 | });
22 |
23 | module.exports = Period;
24 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/components/Shared/Icon.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var PropTypes = React.PropTypes;
3 |
4 |
5 | var Icon = React.createClass({
6 | propTypes: {
7 | icon: PropTypes.string,
8 | size: PropTypes.string
9 | },
10 |
11 | render: function () {
12 | var icon = this.props.icon;
13 | icon = 'fa fa-' + icon;
14 |
15 | if ('size' in this.props) {
16 | icon += ' ' + this.props.size;
17 | }
18 |
19 | return (
20 |
21 | );
22 | }
23 | });
24 |
25 | module.exports = Icon;
26 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/dispatcher/AppDispatcher.js:
--------------------------------------------------------------------------------
1 | var Dispatcher = require('flux').Dispatcher;
2 |
3 | module.exports = new Dispatcher();
4 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/utils/CollectionUtils.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 | var CollectionUtils = {
4 | getMostFrequent: function (arr) {
5 | return _.chain(arr).countBy().pairs().max(_.last).head().value();
6 | }
7 | };
8 |
9 | module.exports = CollectionUtils;
10 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/utils/DateTimeUtil.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 |
3 | var DateTimeUtil = {
4 | displayDateTime: function (date, format) {
5 | var momentDate = moment(date);
6 |
7 | if (momentDate.isValid()) {
8 | return momentDate.format(format);
9 | } else {
10 | return '';
11 | }
12 | }
13 | };
14 |
15 | module.exports = DateTimeUtil;
16 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/utils/DocumentCrawlStatAPI.js:
--------------------------------------------------------------------------------
1 | var DocumentCrawlStatActions = require('actions/DocumentSection/DocumentCrawlStatActions');
2 | var AppConstants = require('../constants/AppConstants');
3 |
4 | var ajax = null;
5 |
6 | var DocumentCrawlStatsAPI = {
7 | get: function () {
8 | if (ajax) {
9 | ajax.abort();
10 | }
11 | ajax = jQuery.getJSON(AppConstants.DOCUMENT_CRAWL_STATS_END_POINT, function (data) {
12 | DocumentCrawlStatActions.setCrawlStats(data);
13 | });
14 | }
15 | };
16 |
17 | module.exports = DocumentCrawlStatsAPI;
18 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/js/utils/SuggestionLogPresenter.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 |
3 | var SuggestionLogPresenter = function (suggestion) {
4 | var unixTime = function () {
5 | return moment(suggestion.created_at).unix();
6 | };
7 |
8 | var asHistoryEntry = function () {
9 | return 'User search for ' + suggestion.search_query;
10 | };
11 |
12 | return {
13 | asHistoryEntry: asHistoryEntry(),
14 | unixTime: unixTime()
15 | };
16 | };
17 |
18 | module.exports = SuggestionLogPresenter;
19 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/navigation.sass:
--------------------------------------------------------------------------------
1 | #navigation-menu
2 | ul
3 | margin-bottom: 0
4 | padding-right: 0
5 | padding-left: 0
6 | li
7 | padding-left: 15px
8 | @import "navigation/item"
9 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/navigation/item.sass:
--------------------------------------------------------------------------------
1 | ul.navigation
2 | li
3 | color: $menu-text-color
4 | line-height: 3.4em
5 | padding-left: 30px
6 | &:hover
7 | cursor: pointer
8 | &.active, &:hover
9 | color: $menu-text-active-color
10 | background-color: $menu-active-bg-color
11 | .fa
12 | margin-right: 10px
13 |
14 | @media(max-width: 767px)
15 | display: inline-block
16 | padding: 5px 10px
17 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/officer_section.sass:
--------------------------------------------------------------------------------
1 | .form-control
2 | &.search
3 | padding-left: 10px
4 |
5 | #officers
6 | .summary
7 | margin: 10px 0
8 |
9 | .actions
10 | button
11 | &+ button
12 | margin-left: 10px
13 |
14 | .medium-editor
15 | padding: 6px 10px
16 | background: transparent
17 | border: 1px solid $color-mine-shaft
18 |
19 | .row.profile-head-line
20 | margin-top: 36px
21 | margin-bottom: 24px
22 |
23 | .row.story-head-line
24 | margin-top: 40px
25 | margin-bottom: 24px
26 |
27 | @import 'vendor/react-select.sass'
28 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/overview_section.sass:
--------------------------------------------------------------------------------
1 | .section-header
2 | font-size: 20px
3 | #search-traffic-chart-wrapper
4 | max-height: 300px
5 | canvas
6 | max-height: 300px
7 | @import "overview_section/period_picker"
8 | @import "overview_section/query_item_list"
9 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/overview_section/period_picker.sass:
--------------------------------------------------------------------------------
1 | #period-picker
2 | display: inline-block
3 | margin-right: 20px
4 | float: right
5 | li
6 | float: left
7 | padding: 5px 10px
8 | margin-right: 5px
9 | line-height: 20px
10 | color: $period-picker-color
11 |
12 | &.active, &:hover
13 | background: none
14 | border-bottom: solid 1px $period-picker-active-color
15 | color: $period-picker-active-color
16 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/overview_section/query_item_list.sass:
--------------------------------------------------------------------------------
1 | #query-list-item
2 | li
3 | border-bottom: solid #ccc 1px
4 | padding: 10px
5 | &:hover
6 | background: $menu-active-bg-color
7 | @media(max-width: 1000px)
8 | display: inline-block
9 | width: 20%
10 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/search_section.sass:
--------------------------------------------------------------------------------
1 | #add-alias
2 | margin-top: 20px
3 | button
4 | i
5 | margin-right: 10px
6 |
7 | @import 'search_section/query_list'
8 | @import 'search_section/query_list_filter'
9 | @import 'search_section/search'
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/search_section/query_list_filter.sass:
--------------------------------------------------------------------------------
1 | ul.filter
2 | list-style: none
3 | margin-top: 10px
4 | padding-left: 0
5 | li
6 | display: inline-block
7 | line-height: 20px
8 | margin-right: 30px
9 | padding: 0 2px
10 | color: $color-dusty-gray
11 | border-bottom: 2px solid transparent
12 | &.active,&:hover
13 | cursor: pointer
14 | color: $color-mine-shaft
15 | border-bottom-color: $color-mine-shaft
16 | background-color: transparent
17 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/search_section/search.sass:
--------------------------------------------------------------------------------
1 | #search
2 | max-width: 300px
3 | float: right
4 | @media(max-width: 764px)
5 | max-width: 200px
6 |
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/session_section.sass:
--------------------------------------------------------------------------------
1 | @import 'session_section/session_history'
--------------------------------------------------------------------------------
/dashboard/static/dashboard/sass/session_section/session_history.sass:
--------------------------------------------------------------------------------
1 | .histories
2 | li
3 | color: inherit
4 | line-height: initial
5 | padding: 0
6 | li:hover
7 | background: initial
--------------------------------------------------------------------------------
/dashboard/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/tests/__init__.py
--------------------------------------------------------------------------------
/dashboard/tests/integrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/tests/integrations/__init__.py
--------------------------------------------------------------------------------
/dashboard/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/tests/services/__init__.py
--------------------------------------------------------------------------------
/dashboard/tests/views/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'eastagile'
2 |
--------------------------------------------------------------------------------
/dashboard/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/dashboard/utils/__init__.py
--------------------------------------------------------------------------------
/dashboard/views/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'user'
2 |
--------------------------------------------------------------------------------
/dashboard/views/admin_analysis_dashboard_view.py:
--------------------------------------------------------------------------------
1 | from django.views.generic.base import TemplateView
2 |
3 |
4 | class AdminAnalysisDashboardView(TemplateView):
5 | template_name = "dashboard/index.html"
6 |
--------------------------------------------------------------------------------
/dashboard/views/crawl_stats.py:
--------------------------------------------------------------------------------
1 | from common.models import DocumentCrawler
2 | from document.response import JsonResponse
3 |
4 |
5 | def crawl_stats(request):
6 |
7 | docs = DocumentCrawler.objects.all().values('timestamp', 'num_documents').order_by('-timestamp')
8 | return JsonResponse({
9 | 'status': 200,
10 | 'docs': docs
11 | })
12 |
--------------------------------------------------------------------------------
/dashboard/views/document_request_status_view.py:
--------------------------------------------------------------------------------
1 | from django.views.generic.base import View
2 | from dashboard.forms import DocumentRequestStatusForm
3 | from document.response import JsonResponse, HttpResponseBadRequest
4 |
5 |
6 | class DocumentRequestStatusView(View):
7 | def post(self, request):
8 | form = DocumentRequestStatusForm(request.POST)
9 | if not form.is_valid():
10 | return HttpResponseBadRequest(form=form)
11 |
12 | form.process()
13 |
14 | return JsonResponse()
15 |
--------------------------------------------------------------------------------
/dashboard/views/interfacetext_view.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 |
3 | from api.serializers.interfacetext_serializer import InterfaceTextSerializer
4 | from dashboard.authentication import SessionAuthentication
5 |
6 | from api.models import InterfaceText
7 |
8 |
9 | class InterfaceTextView(viewsets.ModelViewSet):
10 | queryset = InterfaceText.objects.all()
11 | serializer_class = InterfaceTextSerializer
12 | authentication_classes = (SessionAuthentication,)
13 |
--------------------------------------------------------------------------------
/dashboard/views/settings_view.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 |
3 | from api.serializers.setting_serializer import SettingSerializer
4 | from dashboard.authentication import SessionAuthentication
5 |
6 | from api.models import Setting
7 |
8 |
9 | class AdminSettingsView(viewsets.ModelViewSet):
10 | queryset = Setting.objects.all()
11 | serializer_class = SettingSerializer
12 | authentication_classes = (SessionAuthentication,)
13 |
--------------------------------------------------------------------------------
/dashboard/views/story_type_view.py:
--------------------------------------------------------------------------------
1 | from django.views.generic.base import View
2 |
3 | from document.response import JsonResponse
4 | from officer.models import Story
5 |
6 |
7 | class StoryTypeView(View):
8 | def get(self, request):
9 | query = request.GET.get('query', '')
10 |
11 | limit = 10
12 | types = Story.objects.distinct('story_type').filter(story_type__icontains=query)\
13 | .values_list('story_type', flat=True)[:limit]
14 |
15 | return JsonResponse(data={
16 | 'data': list(types),
17 | })
18 |
--------------------------------------------------------------------------------
/document/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'document.apps.DocumentConfig'
2 |
--------------------------------------------------------------------------------
/document/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class DocumentConfig(AppConfig):
5 | name = 'document'
6 | verbose_name = 'Document'
7 |
8 | def ready(self):
9 | import document.signals.handlers # NOQA
10 |
--------------------------------------------------------------------------------
/document/migrations/0004_requestmail_session_nullable.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('document', '0003_document'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='requestemail',
16 | name='session',
17 | field=models.ForeignKey(null=True, to='share.Session'),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/document/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/migrations/__init__.py
--------------------------------------------------------------------------------
/document/signals/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/signals/__init__.py
--------------------------------------------------------------------------------
/document/tasks.py:
--------------------------------------------------------------------------------
1 | from document.utils import send_document_notification # NOQA
2 |
--------------------------------------------------------------------------------
/document/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/tests/__init__.py
--------------------------------------------------------------------------------
/document/tests/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/tests/models/__init__.py
--------------------------------------------------------------------------------
/document/tests/models/test_document_model.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 | from document.factories import RequestEmailFactory, DocumentFactory
3 | from document.models import Document
4 |
5 |
6 | class DocumentModelTestCase(SimpleTestCase):
7 | def test_update_num_requests(self):
8 | document = DocumentFactory()
9 |
10 | num_requests = document.number_of_request
11 | RequestEmailFactory(document=document)
12 |
13 | Document.objects.get(id=document.id).number_of_request.should.equal(num_requests + 1)
14 |
--------------------------------------------------------------------------------
/document/tests/test_response.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 | from document import response
3 |
4 |
5 | class ResponseTestCase(SimpleTestCase):
6 | def test_json_reponse_protect_safe(self):
7 | response.JsonResponse.when.called_with([1]).should.throw(
8 | TypeError,
9 | 'In order to allow non-dict objects to be serialized set the safe parameter to False'
10 | )
11 |
--------------------------------------------------------------------------------
/document/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/tests/views/__init__.py
--------------------------------------------------------------------------------
/document/tests/views/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/tests/views/ui/__init__.py
--------------------------------------------------------------------------------
/document/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 |
3 | from document.views.request_view import RequestView
4 |
5 |
6 | urlpatterns = [
7 | url(r'^request/$', RequestView.as_view(), name='request'),
8 | ]
9 |
--------------------------------------------------------------------------------
/document/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/document/views/__init__.py
--------------------------------------------------------------------------------
/document/views/request_view.py:
--------------------------------------------------------------------------------
1 | from django.http.response import JsonResponse
2 | from django.views.generic.base import View
3 |
4 | from document.forms import RequestEmailForm
5 | from document.response import HttpResponseBadRequest
6 |
7 |
8 | class RequestView(View):
9 | def post(self, request):
10 | form = RequestEmailForm(request.POST)
11 | if not form.is_valid():
12 | return HttpResponseBadRequest(form)
13 |
14 | form.save()
15 |
16 | return JsonResponse({
17 | "success": True
18 | })
19 |
--------------------------------------------------------------------------------
/embed/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/embed/__init__.py
--------------------------------------------------------------------------------
/embed/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/embed/migrations/__init__.py
--------------------------------------------------------------------------------
/embed/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/embed/models/__init__.py
--------------------------------------------------------------------------------
/embed/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/embed/tests/__init__.py
--------------------------------------------------------------------------------
/embed/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/embed/tests/views/__init__.py
--------------------------------------------------------------------------------
/embed/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from django.views.decorators.cache import cache_page
3 | from django.views.decorators.clickjacking import xframe_options_exempt
4 |
5 | from embed.views.embed_view import EmbedView
6 |
7 | cache_view = cache_page(86400 * 90)
8 |
9 |
10 | urlpatterns = [
11 | url(r'^$', xframe_options_exempt(cache_view(EmbedView.as_view())), name='embed'),
12 | ]
13 |
--------------------------------------------------------------------------------
/embed/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/embed/views/__init__.py
--------------------------------------------------------------------------------
/graph/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/graph/__init__.py
--------------------------------------------------------------------------------
/graph/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/graph/migrations/__init__.py
--------------------------------------------------------------------------------
/gulp_tasks/build_allegation_js.js:
--------------------------------------------------------------------------------
1 | var buildJS = require('./utils/build_js');
2 |
3 |
4 | module.exports = function (production) {
5 | return buildJS({
6 | production: production,
7 | nodePath: 'allegation/static/allegation/js',
8 | entries: './allegation/static/allegation/js/app.js',
9 | bundleName: 'bundle.js',
10 | dest: './static/allegation/js/'
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/gulp_tasks/build_allegation_sass.js:
--------------------------------------------------------------------------------
1 | var buildSass = require('./utils/build_sass');
2 |
3 |
4 | module.exports = function (local, production) {
5 | return buildSass({
6 | src: './common/static/sass/style.sass',
7 | dest: local ? './local_static/css' : './static/css',
8 | fileName: 'style.css',
9 | production: production
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/gulp_tasks/build_dashboard_js.js:
--------------------------------------------------------------------------------
1 | var buildJS = require('./utils/build_js');
2 |
3 |
4 | module.exports = function (production) {
5 | return buildJS({
6 | production: production,
7 | nodePath: 'dashboard/static/dashboard/js',
8 | entries: './dashboard/static/dashboard/js/app.js',
9 | bundleName: 'bundle.js',
10 | dest: './static/dashboard/js/'
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/gulp_tasks/build_dashboard_sass.js:
--------------------------------------------------------------------------------
1 | var buildSass = require('./utils/build_sass');
2 |
3 |
4 | module.exports = function (local, production) {
5 | return buildSass({
6 | src: './dashboard/static/dashboard/sass/style.sass',
7 | dest: local ? './local_static/css' : './static/css',
8 | fileName: 'dashboard_style.css',
9 | production: production
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/gulp_tasks/build_mobile_js.js:
--------------------------------------------------------------------------------
1 | var buildJS = require('./utils/build_js');
2 |
3 |
4 | module.exports = function (production) {
5 | return buildJS({
6 | production: production,
7 | nodePath: 'mobile/static/mobile/js',
8 | entries: './mobile/static/mobile/js/app.js',
9 | bundleName: 'bundle.js',
10 | dest: './static/mobile/js/'
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/gulp_tasks/build_mobile_sass.js:
--------------------------------------------------------------------------------
1 | var buildSass = require('./utils/build_sass');
2 |
3 |
4 | module.exports = function (local, production) {
5 | return buildSass({
6 | src: './mobile/static/mobile/sass/style.sass',
7 | dest: local ? './local_static/css' : './static/css',
8 | fileName: 'mobile_style.css',
9 | production: production
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/gulp_tasks/build_sunburst_js.js:
--------------------------------------------------------------------------------
1 | var buildJS = require('./utils/build_js');
2 |
3 |
4 | module.exports = function (production) {
5 | return buildJS({
6 | production: production,
7 | nodePath: 'allegation/static/allegation/js',
8 | entries: './allegation/static/allegation/js/sunburst-app.js',
9 | bundleName: 'sunburst-bundle.js',
10 | dest: './static/allegation/js/'
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/gulp_tasks/build_test_sass.js:
--------------------------------------------------------------------------------
1 | var buildSass = require('./utils/build_sass');
2 |
3 |
4 | module.exports = function (local) {
5 | return buildSass({
6 | src: './common/static/sass/test.sass',
7 | dest: local ? './local_static/css' : './static/css',
8 | fileName: 'test.css'
9 | });
10 | };
11 |
--------------------------------------------------------------------------------
/gulp_tasks/collect_bower_fonts.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 |
4 | module.exports = function () {
5 | return gulp.src([
6 | './bower_components/components-font-awesome/fonts/**/*',
7 | './bower_components/bootstrap/fonts/**/*',
8 | './bower_components/ratchet/fonts/**/*',
9 | './bower_components/bootstrap-material-design/fonts/**/*'
10 | ]).pipe(gulp.dest('./static/fonts/'));
11 | };
12 |
--------------------------------------------------------------------------------
/gulp_tasks/collectstatic.js:
--------------------------------------------------------------------------------
1 | var gutil = require('gulp-util');
2 | var exec = require('child_process').exec;
3 |
4 |
5 | module.exports = function (cb) {
6 | exec('python manage.py collectstatic -c --noinput', {maxBuffer: 1024 * 500}, function (err, stdout, stderr) {
7 | gutil.log(stdout);
8 | gutil.log(stderr);
9 | cb(err);
10 | });
11 | };
12 |
--------------------------------------------------------------------------------
/gulp_tasks/mkdir.js:
--------------------------------------------------------------------------------
1 | var gutil = require('gulp-util');
2 | var exec = require('child_process').exec;
3 |
4 |
5 | module.exports = function (dir) {
6 | return function (cb) {
7 | exec('mkdir ' + dir, function (err, stdout, stderr) {
8 | gutil.log(stdout);
9 | gutil.log(stderr);
10 | cb();
11 | });
12 | };
13 | };
14 |
--------------------------------------------------------------------------------
/gulp_tasks/utils/replace_static_tag_with_real_path.js:
--------------------------------------------------------------------------------
1 | var _ = require('lodash');
2 |
3 |
4 | module.exports = function replaceStaticTagWithRealPath(patterns) {
5 | return function (match) {
6 | _.each(patterns, function (data) {
7 | var regex = data[0];
8 | var replaceStr = data[1];
9 | match = match.replace(regex, replaceStr);
10 | });
11 |
12 | return match;
13 | };
14 | };
15 |
--------------------------------------------------------------------------------
/gulp_tasks/watch_allegation_js.js:
--------------------------------------------------------------------------------
1 | var watchJS = require('./utils/watch_js');
2 |
3 |
4 | module.exports = watchJS({
5 | entries: ['./allegation/static/allegation/js/app.js'],
6 | dest: './local_static/allegation/js/',
7 | fileName: 'bundle.js',
8 | nodePath: 'allegation/static/allegation/js'
9 | });
10 |
--------------------------------------------------------------------------------
/gulp_tasks/watch_dashboard_js.js:
--------------------------------------------------------------------------------
1 | var watchJS = require('./utils/watch_js');
2 |
3 |
4 | module.exports = watchJS({
5 | entries: ['./dashboard/static/dashboard/js/app.js'],
6 | dest: './local_static/dashboard/js/',
7 | fileName: 'bundle.js',
8 | nodePath: 'dashboard/static/dashboard/js'
9 | });
10 |
--------------------------------------------------------------------------------
/gulp_tasks/watch_mobile_js.js:
--------------------------------------------------------------------------------
1 | var watchJS = require('./utils/watch_js');
2 |
3 |
4 | module.exports = watchJS({
5 | entries: ['./mobile/static/mobile/js/app.js'],
6 | dest: './local_static/mobile/js/',
7 | fileName: 'bundle.js',
8 | nodePath: 'mobile/static/mobile/js'
9 | });
10 |
--------------------------------------------------------------------------------
/investigator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/__init__.py
--------------------------------------------------------------------------------
/investigator/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/migrations/__init__.py
--------------------------------------------------------------------------------
/investigator/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/services/__init__.py
--------------------------------------------------------------------------------
/investigator/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/tests/__init__.py
--------------------------------------------------------------------------------
/investigator/tests/integrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/tests/integrations/__init__.py
--------------------------------------------------------------------------------
/investigator/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/tests/services/__init__.py
--------------------------------------------------------------------------------
/investigator/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/tests/views/__init__.py
--------------------------------------------------------------------------------
/investigator/tests/views/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/tests/views/ui/__init__.py
--------------------------------------------------------------------------------
/investigator/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from django.views.decorators.cache import cache_page
3 |
4 | from allegation.views import AllegationListView
5 | from investigator.views.investigator_detail_view import InvestigatorDetailView
6 |
7 | cache_view = cache_page(86400)
8 |
9 |
10 | urlpatterns = [
11 | url(r'^$',
12 | cache_view(InvestigatorDetailView.as_view()),
13 | name='detail'),
14 | url(r'^(?P[a-z0-9]+(-[a-z0-9]+)*)/(?P\d+)$', cache_view(AllegationListView.as_view()), name='view'),
15 | ]
16 |
--------------------------------------------------------------------------------
/investigator/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/investigator/views/__init__.py
--------------------------------------------------------------------------------
/manage.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | import os
3 | import sys
4 |
5 | if __name__ == "__main__":
6 | if 'test' in sys.argv:
7 | default_settings_module = 'cpdb.settings.test.common'
8 | else:
9 | default_settings_module = "cpdb.settings.local.common"
10 |
11 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", default_settings_module)
12 |
13 | from django.core.management import execute_from_command_line
14 |
15 | execute_from_command_line(sys.argv)
16 |
--------------------------------------------------------------------------------
/mobile/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/__init__.py
--------------------------------------------------------------------------------
/mobile/admin.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/admin.py
--------------------------------------------------------------------------------
/mobile/constants.py:
--------------------------------------------------------------------------------
1 | from mobile.services.mobile_redirector_service import OfficerSessionDesktopToMobileRedirector, \
2 | AllegationSessionDesktopToMobileRedirector
3 |
4 | DEFAULT_REDIRECT_URL = '/mobile'
5 |
6 | DEFAULT_REDIRECTORS = [
7 | OfficerSessionDesktopToMobileRedirector,
8 | AllegationSessionDesktopToMobileRedirector
9 | ]
10 |
--------------------------------------------------------------------------------
/mobile/exceptions/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/exceptions/__init__.py
--------------------------------------------------------------------------------
/mobile/exceptions/bad_request_api_exception.py:
--------------------------------------------------------------------------------
1 | from rest_framework.exceptions import APIException
2 | from rest_framework.status import HTTP_400_BAD_REQUEST
3 |
4 |
5 | class BadRequestApiException(APIException):
6 | status_code = HTTP_400_BAD_REQUEST
7 | default_detail = 'Bad request'
8 |
--------------------------------------------------------------------------------
/mobile/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/migrations/__init__.py
--------------------------------------------------------------------------------
/mobile/models.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/models.py
--------------------------------------------------------------------------------
/mobile/serializers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/serializers/__init__.py
--------------------------------------------------------------------------------
/mobile/serializers/mobile_interfacetext_serializer.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from api.models import InterfaceText
4 |
5 |
6 | class InterfaceTextSerializer(serializers.ModelSerializer):
7 |
8 | class Meta:
9 | model = InterfaceText
10 |
--------------------------------------------------------------------------------
/mobile/serializers/shared.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 | from common.models import AllegationCategory
4 |
5 |
6 | class AllegationCategorySerializer(serializers.ModelSerializer):
7 | class Meta:
8 | model = AllegationCategory
9 | fields = (
10 | 'id',
11 | 'allegation_name',
12 | 'category'
13 | )
14 |
--------------------------------------------------------------------------------
/mobile/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/services/__init__.py
--------------------------------------------------------------------------------
/mobile/services/officer_allegation_service.py:
--------------------------------------------------------------------------------
1 | from common.models import Allegation
2 |
3 |
4 | class OfficerAllegationService(object):
5 | @staticmethod
6 | def get_allegations(officer_id):
7 | allegations = Allegation.objects.filter(officerallegation__officer_id=officer_id).prefetch_related(
8 | 'officerallegation_set__officer',
9 | 'officerallegation_set__cat')
10 | return allegations
11 |
--------------------------------------------------------------------------------
/mobile/static/mobile/fonts/sanfranciscodisplay-bold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/fonts/sanfranciscodisplay-bold-webfont.woff
--------------------------------------------------------------------------------
/mobile/static/mobile/fonts/sanfranciscodisplay-medium-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/fonts/sanfranciscodisplay-medium-webfont.woff
--------------------------------------------------------------------------------
/mobile/static/mobile/fonts/sanfranciscodisplay-regular-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/fonts/sanfranciscodisplay-regular-webfont.woff
--------------------------------------------------------------------------------
/mobile/static/mobile/fonts/sanfranciscodisplay-semibold-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/fonts/sanfranciscodisplay-semibold-webfont.woff
--------------------------------------------------------------------------------
/mobile/static/mobile/fonts/sanfranciscodisplay-thin-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/fonts/sanfranciscodisplay-thin-webfont.woff
--------------------------------------------------------------------------------
/mobile/static/mobile/fonts/sanfranciscodisplay-ultralight-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/fonts/sanfranciscodisplay-ultralight-webfont.woff
--------------------------------------------------------------------------------
/mobile/static/mobile/img/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/static/mobile/img/loading.gif
--------------------------------------------------------------------------------
/mobile/static/mobile/js/app.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var ReactDOM = require('react-dom');
3 | var App = require('./components/App.react');
4 |
5 |
6 | var element = document.getElementById('router');
7 |
8 | if (element) {
9 | ReactDOM.render(
10 | ,
11 | element
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/components/NoMatch.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var MainPage = require('components/MainPage.react');
4 |
5 |
6 | var NoMatch = React.createClass({
7 | render: function () {
8 | return (
9 |
10 | );
11 | }
12 | });
13 |
14 | module.exports = NoMatch;
15 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/components/OfficerPage/RelatedOfficersTab/NoRelatedOfficer.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 |
4 | var NoRelatedOfficer = React.createClass({
5 | render: function () {
6 | return (
7 |
8 | No any officer related to this officer.
9 |
10 | );
11 | }
12 | });
13 |
14 | module.exports = NoRelatedOfficer;
15 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/components/Shared/About.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var cx = require('classnames');
3 |
4 | var About = React.createClass({
5 | propTypes: {
6 | topLeft: React.PropTypes.number
7 | },
8 |
9 | render: function () {
10 | var classNames = cx('animation bold', {'top-left': this.props.topLeft});
11 | return (
12 |
13 | About the data
14 |
15 | );
16 | }
17 | });
18 |
19 | module.exports = About;
20 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/components/Shared/LoadingPage.react.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 |
4 | var LoadingPage = React.createClass({
5 | render: function () {
6 | return (
7 |
8 |
9 |
12 |
13 |
14 | );
15 | }
16 | });
17 |
18 | module.exports = LoadingPage;
19 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/presenters/GenderPresenter.js:
--------------------------------------------------------------------------------
1 | var GenderPresenter = function (gender) {
2 | var humanReadable = function () {
3 | if (gender == 'M') return 'Male';
4 | if (gender == 'F') return 'Female';
5 | if (gender == 'X') return 'X';
6 | return 'Gender unknown';
7 | };
8 |
9 | return {
10 | 'humanReadable': humanReadable()
11 | };
12 | };
13 |
14 | module.exports = GenderPresenter;
15 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/presenters/RequestDocumentErrorPresenter.js:
--------------------------------------------------------------------------------
1 | var RequestDocumentErrorPresenter = function (errors) {
2 | var errorMessage;
3 |
4 | errors = errors || {};
5 |
6 | errorMessage = function () {
7 | if ('email' in errors) {
8 | return 'Please provide a valid email address.';
9 | }
10 | return 'An issue has occurred while processing your request.';
11 | };
12 |
13 | return {
14 | 'errorMessage': errorMessage()
15 | };
16 | };
17 |
18 | module.exports = RequestDocumentErrorPresenter;
19 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/tests/factories/CategoryFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 | var faker = require('faker');
3 |
4 |
5 | f.define('Category', {
6 | 'id': function () {
7 | return faker.random.number(1000);
8 | },
9 | 'allegation_name': function () {
10 | return faker.lorem.words(4);
11 | },
12 | 'category': function () {
13 | return faker.lorem.words(2);
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/tests/factories/ComplainingWitnessFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 | var faker = require('faker');
3 |
4 |
5 | f.define('ComplainingWitness', {
6 | 'cwit_id': function () {
7 | return faker.random.number(10000);
8 | },
9 |
10 | 'gender': function () {
11 | return 'M';
12 | },
13 |
14 | 'race': function () {
15 | return 'Black';
16 | },
17 |
18 | 'age': function () {
19 | return faker.random.number(50);
20 | }
21 | });
22 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/tests/factories/ComplaintPageDataFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 |
3 | f.define('ComplaintPageData', {
4 | 'complaining_witnesses': function () {
5 | return f.createBatch(2, 'ComplainingWitness');
6 | },
7 |
8 | 'allegation': function () {
9 | return f.create('Allegation');
10 | }
11 | });
12 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/tests/factories/InvestigatorFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 | var faker = require('faker');
3 |
4 |
5 | f.define('Investigator', {
6 | 'name': function () {
7 | return faker.name.findName();
8 | },
9 | 'complaint_count': function () {
10 | return faker.random.number(50);
11 | },
12 | 'discipline_count': function () {
13 | return faker.random.number(50);
14 | },
15 | 'current_rank': function () {
16 | return faker.lorem.words(2);
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/tests/factories/OfficerPageDataFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 |
3 | require('tests/factories/AllegationFactory');
4 | require('tests/factories/OfficerFactory');
5 |
6 |
7 | f.define('OfficerPageData', {
8 | 'detail': function () {
9 | return f.create('Officer');
10 | },
11 |
12 | 'complaints': function () {
13 | return f.createBatch(2, 'Allegation');
14 | },
15 |
16 | 'co_accused': function () {
17 | return [];
18 | },
19 |
20 | 'distribution': function () {
21 | return [];
22 | }
23 | });
24 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/tests/factories/PointFactory.js:
--------------------------------------------------------------------------------
1 | var f = require('utils/tests/f');
2 |
3 |
4 | f.define('Point', {
5 | 'x': function () {
6 | return -87.601107;
7 | },
8 |
9 | 'y': function () {
10 | return 41.705677;
11 | }
12 | });
13 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/DataTypeUtil.js:
--------------------------------------------------------------------------------
1 | var DataTypeUtil = {
2 | isNumeric: function (val) {
3 | return /^\d+$/.test(val);
4 | },
5 |
6 | isValidCridQueryFormat: function (val) {
7 | return /^(cr|crid)?(\s+)?(\d+)$/.test(val.toLowerCase());
8 | }
9 | };
10 |
11 | module.exports = DataTypeUtil;
12 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/DateUtil.js:
--------------------------------------------------------------------------------
1 | var moment = require('moment');
2 |
3 | var AppConstants = require('constants/AppConstants');
4 |
5 |
6 | var DateUtil = {
7 | sanitizeDate : function (date, inputFormat) {
8 | var momentDate;
9 | inputFormat = inputFormat || AppConstants.SIMPLE_SERVER_DATE_FORMAT;
10 |
11 | momentDate = moment(date, inputFormat);
12 |
13 | return momentDate.isValid() ? momentDate : null;
14 | }
15 | };
16 |
17 | module.exports = DateUtil;
18 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/DeviceUtil.js:
--------------------------------------------------------------------------------
1 | var DeviceUtil = {
2 | getUserAgent: function () {
3 | return navigator.userAgent;
4 | },
5 |
6 | isiOSDevice: function () {
7 | return /iPhone|iPad|iPod/i.test(this.getUserAgent());
8 | }
9 | };
10 |
11 | module.exports = DeviceUtil;
12 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/GaUtil.js:
--------------------------------------------------------------------------------
1 | var GaUtil = {
2 | track: function (type, category, action, label) {
3 | ga('send', type, category, action, label);
4 | }
5 | };
6 |
7 | module.exports = GaUtil;
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/HashUtil.js:
--------------------------------------------------------------------------------
1 | var Hashids = require('hashids');
2 |
3 | var AppConstants = require('constants/AppConstants');
4 |
5 |
6 | module.exports = (new Hashids(AppConstants.SALT, 8));
7 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/History.js:
--------------------------------------------------------------------------------
1 | var History = require('history');
2 |
3 | var history = History.useBasename(History.createHistory)({
4 | basename: '/'
5 | });
6 |
7 | module.exports = history;
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/LocalStorageUtil.js:
--------------------------------------------------------------------------------
1 | var LocalStorageUtil = {
2 | getItem: function (key) {
3 | localStorage.getItem(key);
4 | },
5 |
6 | setItem: function (key, value) {
7 | localStorage.setItem(key, value);
8 | }
9 | };
10 |
11 | module.exports = LocalStorageUtil;
12 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/SvgUtil.js:
--------------------------------------------------------------------------------
1 | var HelperUtil = require('utils/HelperUtil');
2 |
3 |
4 | var SvgUtil = {
5 | arrayToPoints: function (data, scaleX, scaleY) {
6 | var result = '';
7 | var i;
8 |
9 | for (i = 0; i < data.length; i++) {
10 | result = [result, HelperUtil.format('{i},{value}', {'i': i * scaleX, 'value': data[i] * scaleY})].join(' ');
11 | }
12 |
13 | return result;
14 | }
15 | };
16 |
17 | module.exports = SvgUtil;
18 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/tests/SharedExample.js:
--------------------------------------------------------------------------------
1 | var SharedExample = function () {
2 | var examples = {};
3 |
4 | var define = function (name, assertion) {
5 | if (!(name in examples)) {
6 | examples[name] = assertion;
7 | }
8 | };
9 |
10 |
11 | var get = function (name) {
12 | return examples[name];
13 | };
14 |
15 | return {
16 | 'define': define,
17 | 'get': get
18 | };
19 | };
20 |
21 | module.exports = SharedExample();
22 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/tests/f.js:
--------------------------------------------------------------------------------
1 | var Factory = require('utils/tests/Factory');
2 |
3 | module.exports = Factory();
4 |
--------------------------------------------------------------------------------
/mobile/static/mobile/js/utils/tests/should/SharedExample.js:
--------------------------------------------------------------------------------
1 | var should = require('should');
2 |
3 | var SharedExample = require('utils/tests/SharedExample');
4 |
5 |
6 | should.Assertion.add('behaveLike', function (name) {
7 | var example = SharedExample.get(name);
8 | example.apply(this, Array.prototype.slice.call(arguments, 1));
9 | });
10 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/accomplice_officer_section.sass:
--------------------------------------------------------------------------------
1 | .accomplice-officer-section
2 | .officer-list
3 | padding-left: 0
4 | margin-top: 0
5 | list-style: none
6 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/against_section.sass:
--------------------------------------------------------------------------------
1 | @import 'against_section/against_card'
2 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/against_section/against_card.sass:
--------------------------------------------------------------------------------
1 | @import 'against_card/investigation_timeline'
2 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/complaining_witness.sass:
--------------------------------------------------------------------------------
1 | .complaining-witness
2 | font-size: 17px
3 | margin-bottom: 11px
4 | .complaining-witness-list
5 | margin: 0
6 | font-size: 15px
7 | .complaining-witness-row
8 | line-height: 37px
9 | .circle-wrapper
10 | line-height: 33px
11 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/document_section.sass:
--------------------------------------------------------------------------------
1 | .document-section
2 | .section-header
3 | padding: 10px
4 | .document-list
5 | margin: 0
6 |
7 | @import 'document_section/document_card'
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/document_section/document_card.sass:
--------------------------------------------------------------------------------
1 | .document-card
2 | .circle-wrapper
3 | line-height: 33px
4 | .document-name
5 | font-size: 16px
6 | font-weight: 600
7 | &.blur
8 | color: $mamba
9 | .status
10 | font-size: 13px
11 | .action-type
12 | font-size: 14px
13 | color: $vivid-blue
14 | line-height: 33px
15 | .document-detail
16 | padding: 9px 0px
17 |
18 | @import 'document_card/request_modal_content'
19 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/investigation_section.sass:
--------------------------------------------------------------------------------
1 | .investigator-section
2 | .investigator-card
3 | .circle-wrapper
4 | line-height: 33px
5 | .investigator
6 | padding: 9px 0
7 | .name
8 | font-size: 16px
9 | .rank
10 | font-size: 14px
11 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/location.sass:
--------------------------------------------------------------------------------
1 | .location
2 | padding-bottom: 3px
3 | .location-detail
4 | margin: 10px 0
5 | font-size: 13px
6 | &.no-data
7 | height: 20px
8 | label
9 | color: $location-label-color
10 | .location-map
11 | padding-bottom: 37px
12 |
13 | @import 'location/map'
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/location/map.sass:
--------------------------------------------------------------------------------
1 | .map
2 | position: relative
3 | width: 100%
4 | padding: 10px
5 | height: 300px
6 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/not_matched_category_page.sass:
--------------------------------------------------------------------------------
1 | .not-matched-category-page
2 | color: $no-match-text-color
3 | background-color: $content-background
4 | padding: 10% 3%
5 |
6 | .category-number
7 | color: $no-match-crid-text-color
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/complaint_page/not_matched_complaint_page.sass:
--------------------------------------------------------------------------------
1 | .not-matched-complaint-page
2 | color: $no-match-text-color
3 | background-color: $content-background
4 | padding: 10% 3%
5 |
6 | .crid-number
7 | color: $no-match-crid-text-color
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/helper/officer_color_level.sass:
--------------------------------------------------------------------------------
1 | .circle
2 | width: 10px
3 | height: 10px
4 | border-radius: 50%
5 | display: inline-block
6 | background-color: $black
7 |
8 | .small-circle
9 | width: 6px
10 | height: 6px
11 |
12 | $levels: $level-0-color, $level-1-color, $level-2-color, $level-3-color, $level-4-color
13 |
14 | @for $i from 1 through length($levels)
15 | .circle-#{$i - 1}
16 | background-color: nth($levels, $i)
17 | .stroke-#{$i - 1}
18 | stroke: nth($levels, $i)
19 | .fill-#{$i - 1}
20 | fill: nth($levels, $i)
21 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/main_page.sass:
--------------------------------------------------------------------------------
1 | .main-page
2 | background-color: $search-page-background-color
3 | .bar-footer
4 | height: 70px
5 |
6 | @import 'main_page/main_page_content'
7 | @import 'main_page/page_not_found'
8 | @import 'main_page/project_summary'
9 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/main_page/main_page_content.sass:
--------------------------------------------------------------------------------
1 | .main-page-content
2 | position: relative
3 | width: 100%
4 | color: $logo-text-color
5 | background-color: $logo-background
6 | padding-bottom: 20px
7 | &.top-left
8 | background-color: transparent
9 | padding-bottom: 0
10 | .search-wrapper
11 | position: relative
12 | width: 100%
13 | padding: 0 3%
14 | &.top-left
15 | margin-top: 0
16 | position: relative
17 | padding: 0
18 | .search-results
19 | color: $search-results-text-color
20 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/main_page/page_not_found.sass:
--------------------------------------------------------------------------------
1 | #page-not-found
2 | position: absolute
3 | padding: 60px 20px
4 | color: $page-not-found-header-text-color
5 | background-color: $logo-background
6 | height: 380px
7 | &.top-left
8 | opacity: 0
9 | .page-not-found-header
10 | font-size: 25px
11 | font-weight: bold
12 | margin-bottom: 9px
13 | .page-not-found-description
14 | font-size: 15px
15 | line-height: 20px
16 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/main_page/project_summary.sass:
--------------------------------------------------------------------------------
1 | .project-summary
2 | display: block
3 | max-height: 300px
4 | &.top-left
5 | max-height: 0px
6 | overflow: hidden
7 | .cpdb-logo
8 | font-size: 30px
9 | font-weight: bold
10 | padding: 36px 20px 10px 20px
11 | .cpdb-description
12 | font-size: 15px
13 | line-height: 20px
14 | opacity: 0.5
15 | margin: 20px 20px
16 | .paragraph
17 | margin: 10px 0
18 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/complaints_tab.sass:
--------------------------------------------------------------------------------
1 | .complaints-tab
2 | background-color: $complaints-tab-background
3 | padding-top: 11px
4 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/not_matched_officer_page.sass:
--------------------------------------------------------------------------------
1 | .not-matched-officer-page
2 | color: $no-match-text-color
3 | background-color: $content-background
4 | padding: 10% 3%
5 |
6 | .officer-id
7 | color: $no-match-officer-id-text-color
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/officer_header.sass:
--------------------------------------------------------------------------------
1 | .officer-header
2 | background-color: $white
3 | .name
4 | color: $officer-name-color
5 | font-size: 25px
6 | font-weight: 700
7 | .badge-info
8 | font-size: 13px
9 | .badge-label
10 | color: $officer-label-color
11 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/related_officer_tab.sass:
--------------------------------------------------------------------------------
1 | @import 'related_officer_tab/related_officer_item'
2 | @import 'related_officer_tab/no_related_officer'
3 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/related_officer_tab/no_related_officer.sass:
--------------------------------------------------------------------------------
1 | .no-related-officer
2 | height: 100px
3 | text-align: center
4 | vertical-align: middle
5 | line-height: 100px
6 | background-color: $no-related-officer-background-color
7 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/related_officer_tab/related_officer_item.sass:
--------------------------------------------------------------------------------
1 | .related-officer-item
2 | font-size: 14px
3 | padding-top: 9px
4 | padding-bottom: 9px
5 | .name
6 | font-size: 16px
7 | font-weight: 700
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/summary_tab.sass:
--------------------------------------------------------------------------------
1 | .summary-tab
2 | font-size: 15px
3 | background-color: $white
4 |
5 | @import 'summary_tab/officer_summary_section'
6 | @import 'summary_tab/officer_analytic_section'
7 | @import 'summary_tab/distribution_curve'
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/summary_tab/officer_analytic_section.sass:
--------------------------------------------------------------------------------
1 | .officer-analytic-section
2 | .distribution-curve
3 | line-height: 250px
4 | font-size: 13px
5 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/officer_page/summary_tab/officer_summary_section.sass:
--------------------------------------------------------------------------------
1 | .officer-summary-section
2 | margin-top: 16px
3 | margin-bottom: 22px
4 | .label
5 | color: $officer-label-color
6 | font-weight: 600
7 | width: 18%
8 | display: inline-block
9 | vertical-align: top
10 | .value
11 | display: inline-block
12 | width: 82%
13 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared.sass:
--------------------------------------------------------------------------------
1 | @import 'shared/about'
2 | @import 'shared/loading_page'
3 | @import 'shared/simple_tab'
4 | @import 'shared/officer_card'
5 | @import 'shared/searchable_page'
6 | @import 'shared/officer_allegation_item'
7 | @import 'shared/interface_text'
8 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/about.sass:
--------------------------------------------------------------------------------
1 | #about
2 | background: $about-box-background
3 | color: $about-text-color
4 | padding: 10px 0px
5 | width: 139px
6 | text-align: center
7 | font-size: 16px
8 | bottom: 22px
9 | left: 10px
10 | position: fixed
11 | &.top-left
12 | opacity: 0
13 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/interface_text.sass:
--------------------------------------------------------------------------------
1 | .interface-text
2 | word-wrap: break-word
3 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/officer_card.sass:
--------------------------------------------------------------------------------
1 | .officer-card
2 | .circle-wrapper
3 | line-height: 34px
4 | .officer
5 | padding: 9px 0
6 | .name
7 | font-size: 16px
8 | .description
9 | font-size: 14px
10 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/searchable_page/search_results.sass:
--------------------------------------------------------------------------------
1 | @import 'search_results/successful_search'
2 | @import 'search_results/failed_search'
3 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/searchable_page/search_results/failed_search.sass:
--------------------------------------------------------------------------------
1 | .failed-search
2 | margin-top: 16px
3 | font-size: 15px
4 | line-height: 21px
5 | position: relative
6 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/searchable_page/search_results/successful_search.sass:
--------------------------------------------------------------------------------
1 | .success-search
2 | position: relative
3 | .suggestion-list
4 | list-style-type: none
5 | padding: 0
6 | margin: 0
7 | .highlight
8 | color: $suggestion-highlight-color
9 | .dot-bullet
10 | width: 20px
11 | display: inline-block
12 | text-align: center
13 | @import 'successful_search/officer_result'
14 | @import 'successful_search/complaint_result'
15 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/searchable_page/search_results/successful_search/complaint_result.sass:
--------------------------------------------------------------------------------
1 | .complaint-results
2 | .complaint-result-item
3 | margin: 10px 0
4 | background-color: $search-page-item-background-color
5 | padding: 10px 0
6 | font-size: 13px
7 | .complaint-category
8 | margin-top: 10px
9 | .sub-category
10 | font-size: 16px
11 | line-height: 25px
12 | .complaint-header
13 | .final-finding
14 | float: right
15 | .crid-title
16 | color: $search-page-crid-title-color
17 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/shared/simple_tab.sass:
--------------------------------------------------------------------------------
1 | .tab-content
2 | display: none
3 | animation: slide-out 0.3s forwards
4 | -webkit-animation: slide-out 0.3s forwards
5 | -moz-animation: slide-out 0.3s forwards
6 | -o-animation: slide-out 0.3s forwards
7 | &.reverse-animation
8 | animation: slide-in 0.3s forwards
9 | -webkit-animation: slide-in 0.3s forwards
10 | -moz-animation: slide-in 0.3s forwards
11 | -o-animation: slide-in 0.3s forwards
12 | &.active
13 | display: block
14 | &.no-animation
15 | animation: 0
16 | -webkit-animation: 0
17 |
--------------------------------------------------------------------------------
/mobile/static/mobile/sass/style.sass:
--------------------------------------------------------------------------------
1 | @import 'variables'
2 | @import 'fonts'
3 |
4 | body
5 | font-size: 17px
6 | font-family: -apple-system, 'San Francisco', 'Roboto', sans-serif
7 | color: $site-text-color
8 | line-height: initial
9 | background-color: $content-background
10 |
11 |
12 | @import 'helper'
13 | @import 'grid'
14 | @import 'main_page'
15 | @import 'complaint_page'
16 | @import 'officer_page'
17 | @import 'shared'
18 |
--------------------------------------------------------------------------------
/mobile/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/tests/__init__.py
--------------------------------------------------------------------------------
/mobile/tests/integrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/tests/integrations/__init__.py
--------------------------------------------------------------------------------
/mobile/tests/mixins/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'bebe'
2 |
--------------------------------------------------------------------------------
/mobile/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/tests/services/__init__.py
--------------------------------------------------------------------------------
/mobile/tests/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/tests/utils/__init__.py
--------------------------------------------------------------------------------
/mobile/tests/utils/test_collection_helper.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 | from mobile.utils.collection_helper import safe_get
3 |
4 |
5 | class CollectionHelperTest(SimpleTestCase):
6 | def test_safe_get(self):
7 | lst = [1]
8 |
9 | safe_get(lst, 0, 0).should.be.equal(1)
10 | safe_get(lst, 2, 0).should.be.equal(0)
11 |
--------------------------------------------------------------------------------
/mobile/tests/utils/test_sql_helper.py:
--------------------------------------------------------------------------------
1 | from mock import MagicMock
2 |
3 | from common.tests.core import SimpleTestCase
4 | from mobile.utils.sql_helper import SqlHelper
5 |
6 |
7 | class SqlHelperTest(SimpleTestCase):
8 | def test_array_as_sql(self):
9 | items = ['a', 'b', 'c']
10 | SqlHelper.array_as_sql(items).should.be.equal("'a','b','c'")
11 |
12 | def test_len_of_raw_queryset(self):
13 | raw_queryset = MagicMock()
14 | raw_queryset.__iter__.return_value = [1, 2]
15 | SqlHelper.len_of_raw_queryset(raw_queryset).should.be(2)
16 |
--------------------------------------------------------------------------------
/mobile/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/tests/views/__init__.py
--------------------------------------------------------------------------------
/mobile/tests/views/test_mobile_site_view.py:
--------------------------------------------------------------------------------
1 | from django.core.urlresolvers import reverse
2 |
3 | from common.tests.core import SimpleTestCase
4 |
5 |
6 | class MobileSiteViewTestCase(SimpleTestCase):
7 | def test_visit_mobile_view(self):
8 | self.visit(reverse('mobile:home'))
9 | self.response.status_code.should.equal(200)
10 | self.assertTemplateUsed(self.response, 'mobile/index.html')
11 |
--------------------------------------------------------------------------------
/mobile/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/utils/__init__.py
--------------------------------------------------------------------------------
/mobile/utils/collection_helper.py:
--------------------------------------------------------------------------------
1 | def safe_get(lst, index, default):
2 | try:
3 | return lst[index]
4 | except IndexError:
5 | return default
6 |
--------------------------------------------------------------------------------
/mobile/utils/sql_helper.py:
--------------------------------------------------------------------------------
1 | class SqlHelper(object):
2 | @staticmethod
3 | def array_as_sql(items=[]):
4 | return ','.join("'{}'".format(item) for item in items)
5 |
6 | @staticmethod
7 | def len_of_raw_queryset(raw_queryset):
8 | # Do not overuse this method, its purpose only for testing
9 | return sum(1 for _ in raw_queryset)
10 |
--------------------------------------------------------------------------------
/mobile/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/mobile/views/__init__.py
--------------------------------------------------------------------------------
/mobile/views/mobile_interface_text_view.py:
--------------------------------------------------------------------------------
1 | from rest_framework import viewsets
2 |
3 | from api.models import InterfaceText
4 | from mobile.serializers.mobile_interfacetext_serializer import InterfaceTextSerializer
5 |
6 |
7 | class MobileInterfaceTextView(viewsets.ModelViewSet):
8 | queryset = InterfaceText.objects.all()
9 | serializer_class = InterfaceTextSerializer
10 |
--------------------------------------------------------------------------------
/mobile/views/mobile_site_view.py:
--------------------------------------------------------------------------------
1 | from django.views.generic import TemplateView
2 |
3 |
4 | class MobileSiteView(TemplateView):
5 | template_name = 'mobile/index.html'
6 |
7 | def get_context_data(self, **kwargs):
8 | context = super(MobileSiteView, self).get_context_data(**kwargs)
9 | return context
10 |
11 | def get(self, request, hash_id=None, *args, **kwargs):
12 | return super(MobileSiteView, self).get(request, *args, **kwargs)
13 |
--------------------------------------------------------------------------------
/officer/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/officer/__init__.py
--------------------------------------------------------------------------------
/officer/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from common.actions import make_export_action
4 | from officer import models
5 |
6 |
7 | class StoryAdmin(admin.ModelAdmin):
8 | prepopulated_fields = {"slug": ("title",)}
9 | list_display = ('id', 'title', 'officer', 'created_date', 'custom_order')
10 | list_display_links = ('id', 'title')
11 | search_fields = ('title',)
12 | actions = make_export_action("Export Officer Stories to CSV")
13 |
14 | admin.site.register(models.Story, StoryAdmin)
15 |
--------------------------------------------------------------------------------
/officer/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/officer/migrations/__init__.py
--------------------------------------------------------------------------------
/officer/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/officer/tests/__init__.py
--------------------------------------------------------------------------------
/officer/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/officer/tests/views/__init__.py
--------------------------------------------------------------------------------
/officer/tests/views/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/officer/tests/views/ui/__init__.py
--------------------------------------------------------------------------------
/officer/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/officer/views/__init__.py
--------------------------------------------------------------------------------
/pre_deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin.bash
2 |
3 | echo "SELECT pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname = 'cpdb_staging’;" > psql cpdb; dropdb cpdb_staging; createdb cpdb_staging; pg_dump cpdb | psql cpdb_staging;
4 | ./manage capitalize_officer_name
5 | echo "DELETE FROM django_migrations WHERE app in ('common', 'officer', 'api');" | psql cpdb
6 | ./manage.py migrate common 0001 --fake
7 | ./manage.py migrate officer 0001 --fake
8 | ./manage.py migrate api 0001 --fake
9 |
--------------------------------------------------------------------------------
/runtime.txt:
--------------------------------------------------------------------------------
1 | python-3.4.2
2 |
--------------------------------------------------------------------------------
/search/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/__init__.py
--------------------------------------------------------------------------------
/search/migrations/0002_filterlog_num_allegations.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0001_initial'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='filterlog',
16 | name='num_allegations',
17 | field=models.PositiveIntegerField(default=0),
18 | preserve_default=False,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/search/migrations/0003_auto_20150805_0316.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0002_filterlog_num_allegations'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='filterlog',
16 | name='query',
17 | field=models.TextField(),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/search/migrations/0005_merge.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0004_alias'),
11 | ('search', '0004_auto_20150812_0805'),
12 | ]
13 |
14 | operations = [
15 | ]
16 |
--------------------------------------------------------------------------------
/search/migrations/0006_auto_20150921_0248.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0005_merge'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterUniqueTogether(
15 | name='alias',
16 | unique_together=set([('alias', 'target')]),
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/search/migrations/0007_merge.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0006_auto_20150922_0405'),
11 | ('search', '0006_auto_20150921_0248'),
12 | ]
13 |
14 | operations = [
15 | ]
16 |
--------------------------------------------------------------------------------
/search/migrations/0009_filterlog_user_agent.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0008_alias_updated_at'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='filterlog',
16 | name='user_agent',
17 | field=models.CharField(max_length=255, null=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/search/migrations/0011_remove_suggestionlog_ip.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0010_auto_20151009_0919'),
11 | ]
12 |
13 | operations = [
14 | migrations.RemoveField(
15 | model_name='suggestionlog',
16 | name='ip',
17 | ),
18 | ]
19 |
--------------------------------------------------------------------------------
/search/migrations/0015_sessionalias_title.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('search', '0014_auto_20151203_0227'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='sessionalias',
16 | name='title',
17 | field=models.CharField(max_length=254, default=''),
18 | preserve_default=False,
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/search/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/migrations/__init__.py
--------------------------------------------------------------------------------
/search/models/__init__.py:
--------------------------------------------------------------------------------
1 | from search.models.suggestion import SuggestionLog, FilterLog # NOQA
2 | from search.models.alias import Alias # NOQA
3 | from search.models.session_alias import SessionAlias # NOQA
4 |
--------------------------------------------------------------------------------
/search/models/alias.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 |
3 |
4 | class Alias(models.Model):
5 | alias = models.CharField(max_length=254)
6 | target = models.CharField(max_length=254)
7 | num_suggestions = models.IntegerField(default=0)
8 | num_usage = models.IntegerField(default=0)
9 | updated_at = models.DateTimeField(auto_now=True)
10 |
11 | class Meta:
12 | unique_together = (('alias', 'target'),)
13 |
--------------------------------------------------------------------------------
/search/models/proxy_models.py:
--------------------------------------------------------------------------------
1 | from common.models import AllegationCategory, Allegation
2 |
3 |
4 | class AllegationCategoryProxy(AllegationCategory):
5 | '''Proxy model for elasticsearch index'''
6 | class Meta:
7 | proxy = True
8 |
9 |
10 | class AllegationProxy(Allegation):
11 | '''Proxy model for elasticsearch index'''
12 | class Meta:
13 | proxy = True
14 |
--------------------------------------------------------------------------------
/search/models/session_alias.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.utils.translation import ugettext_lazy as _
3 |
4 | from common.models.time_stamp import TimeStampedModel
5 | from share.models import Session
6 |
7 |
8 | class SessionAlias(TimeStampedModel):
9 | alias = models.CharField(max_length=254)
10 | session = models.ForeignKey(Session)
11 | user = models.ForeignKey('common.User', default=1)
12 | title = models.CharField(max_length=254)
13 |
14 | class Meta:
15 | verbose_name_plural = _('aliases')
16 |
--------------------------------------------------------------------------------
/search/services/__init__.py:
--------------------------------------------------------------------------------
1 | REPEATER_DESC = {
2 | '10': 'Repeater (10+ complaints)',
3 | '20': 'Repeater (20+ complaints)'
4 | }
5 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/common/allegation_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.crid }}
2 | {{ object.city }}
3 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/common/allegationcategory_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.allegation_name }}
2 | {{ object.cat_id }}
3 | {{ object.category }}
4 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/common/area_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.area_name }}
2 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/common/investigator_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.investigator_name }}
2 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/common/officer_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.officer_first }}
2 | {{ object.officer_last }}
3 | {{ object.star }}
4 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/search/allegationcategoryproxy_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.allegation_distinct_city }}
2 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/search/allegationproxy_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.allegationcategory_distinct_category }}
2 |
--------------------------------------------------------------------------------
/search/templates/search/indexes/search/sessionalias_text.txt:
--------------------------------------------------------------------------------
1 | {{ object.alias }}
2 |
--------------------------------------------------------------------------------
/search/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/tests/__init__.py
--------------------------------------------------------------------------------
/search/tests/admin/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/tests/admin/__init__.py
--------------------------------------------------------------------------------
/search/tests/admin/test_suggestion_admin.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import BaseLiveTestCase
2 | from search.factories import SuggestionLogFactory
3 |
4 |
5 | class SuggestionAdminTestCase(BaseLiveTestCase):
6 | def test_suggestion_admin(self):
7 | self.login_user()
8 | log = SuggestionLogFactory()
9 | self.visit("/admin/models/")
10 |
11 | self.link("Suggestion logs").click()
12 | self.should_see_text(log.search_query)
13 |
--------------------------------------------------------------------------------
/search/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/tests/services/__init__.py
--------------------------------------------------------------------------------
/search/tests/services/suggest/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/tests/services/suggest/__init__.py
--------------------------------------------------------------------------------
/search/tests/services/suggest/base_test_suggest.py:
--------------------------------------------------------------------------------
1 | from common.utils.haystack import rebuild_index
2 |
3 | from common.models import Allegation, AllegationCategory, Officer
4 | from common.tests.core import SimpleTestCase
5 |
6 |
7 | class BaseSuggestTestCase(SimpleTestCase):
8 | def setUp(self):
9 | AllegationCategory.objects.all().delete()
10 | Officer.objects.all().delete()
11 | Allegation.objects.all().delete()
12 |
13 | def rebuild_index(self):
14 | rebuild_index()
15 |
16 | class Meta:
17 | abstract = True
18 |
--------------------------------------------------------------------------------
/search/tests/services/suggest/test_suggest_incident_date.py:
--------------------------------------------------------------------------------
1 | from search.services.suggest.suggest_incident_date import SuggestTimeOfDay
2 | from search.tests.services.suggest.base_test_suggest import BaseSuggestTestCase
3 |
4 |
5 | class SuggestIncidentDateTestCase(BaseSuggestTestCase):
6 | def test_time_of_day(self):
7 | for term in ['mor', 'mid', 'after', 'eve', 'nig']:
8 | SuggestTimeOfDay.query(term).should.contain('Incident Time of Day')
9 |
--------------------------------------------------------------------------------
/search/tests/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/tests/views/__init__.py
--------------------------------------------------------------------------------
/search/tests/views/test_search_view.py:
--------------------------------------------------------------------------------
1 | from common.tests.core import SimpleTestCase
2 |
3 |
4 | class SearchViewTestCase(SimpleTestCase):
5 | pass
6 |
--------------------------------------------------------------------------------
/search/tests/views/ui/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/tests/views/ui/__init__.py
--------------------------------------------------------------------------------
/search/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from django.views.decorators.cache import cache_page
3 |
4 | from search.views.suggest_view import SuggestView
5 |
6 |
7 | cache_view = cache_page(86400)
8 |
9 |
10 | urlpatterns = [
11 | url(r'^suggest/$', SuggestView.as_view(), name='suggest'),
12 | ]
13 |
--------------------------------------------------------------------------------
/search/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/utils/__init__.py
--------------------------------------------------------------------------------
/search/utils/zip_code.py:
--------------------------------------------------------------------------------
1 | # Chicago IL 123456
2 | def get_zipcode_from_city(str):
3 | zip_code = str.split()[-1]
4 | return zip_code if zip_code.isdigit() else ''
5 |
--------------------------------------------------------------------------------
/search/views/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/search/views/__init__.py
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [flake8]
2 | max-line-length = 120
3 | exclude = .tox,.git,*/migrations/*,*/static/CACHE/*,docs,node_modules
4 |
--------------------------------------------------------------------------------
/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.cst:
--------------------------------------------------------------------------------
1 | ISO-8859-1
--------------------------------------------------------------------------------
/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.dbf
--------------------------------------------------------------------------------
/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.prj:
--------------------------------------------------------------------------------
1 | GEOGCS["WGS 84", DATUM["World Geodetic System 1984", SPHEROID["WGS 84", 6378137.0, 298.257223563, AUTHORITY["EPSG","7030"]], AUTHORITY["EPSG","6326"]], PRIMEM["Greenwich", 0.0, AUTHORITY["EPSG","8901"]], UNIT["degree", 0.017453292519943295], AXIS["Geodetic longitude", EAST], AXIS["Geodetic latitude", NORTH], AUTHORITY["EPSG","4326"]]
--------------------------------------------------------------------------------
/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.shp
--------------------------------------------------------------------------------
/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries - Police Districts (current)/geo_fthy-xz3r-1.shx
--------------------------------------------------------------------------------
/shapefiles/Boundaries - Police Districts (current)/wfsrequest.txt:
--------------------------------------------------------------------------------
1 | http://10.1.0.48:9797/geo_fthy-xz3r/ows?service=WFS&version=1.1.0&request=GetFeature&typeName=geo_fthy-xz3r-1&outputFormat=SHAPE-ZIP&srsName=EPSG:4326
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.dbf
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_StatePlane_Illinois_East_FIPS_1201_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",984250.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-88.33333333333333],PARAMETER["Scale_Factor",0.999975],PARAMETER["Latitude_Of_Origin",36.66666666666666],UNIT["Foot_US",0.3048006096012192]]
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.sbn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.sbn
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.sbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.sbx
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.shp
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Neighborhoods/Neighborhoods_2012b.shx
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.dbf
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_StatePlane_Illinois_East_FIPS_1201_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",984250.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-88.33333333333333],PARAMETER["Scale_Factor",0.999975],PARAMETER["Latitude_Of_Origin",36.66666666666666],UNIT["Foot_US",0.3048006096012192]]
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.shp
--------------------------------------------------------------------------------
/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/Boundaries_-_Wards__2015-_/WARDS_2015.shx
--------------------------------------------------------------------------------
/shapefiles/School_20Grounds/School_Grounds.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_StatePlane_Illinois_East_FIPS_1201_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",984250.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-88.33333333333333],PARAMETER["Scale_Factor",0.999975],PARAMETER["Latitude_Of_Origin",36.66666666666666],UNIT["Foot_US",0.3048006096012192]]
--------------------------------------------------------------------------------
/shapefiles/School_20Grounds/School_Grounds.sbn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/School_20Grounds/School_Grounds.sbn
--------------------------------------------------------------------------------
/shapefiles/School_20Grounds/School_Grounds.sbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/School_20Grounds/School_Grounds.sbx
--------------------------------------------------------------------------------
/shapefiles/School_20Grounds/School_Grounds.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/School_20Grounds/School_Grounds.shp
--------------------------------------------------------------------------------
/shapefiles/School_20Grounds/School_Grounds.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/School_20Grounds/School_Grounds.shx
--------------------------------------------------------------------------------
/shapefiles/beats/cpd_beats.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/beats/cpd_beats.dbf
--------------------------------------------------------------------------------
/shapefiles/beats/cpd_beats.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_StatePlane_Illinois_East_FIPS_1201_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",984250.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-88.33333333333333],PARAMETER["Scale_Factor",0.999975],PARAMETER["Latitude_Of_Origin",36.66666666666666],UNIT["Foot_US",0.3048006096012192]]
--------------------------------------------------------------------------------
/shapefiles/beats/cpd_beats.sbn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/beats/cpd_beats.sbn
--------------------------------------------------------------------------------
/shapefiles/beats/cpd_beats.sbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/beats/cpd_beats.sbx
--------------------------------------------------------------------------------
/shapefiles/beats/cpd_beats.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/beats/cpd_beats.shp
--------------------------------------------------------------------------------
/shapefiles/beats/cpd_beats.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/beats/cpd_beats.shx
--------------------------------------------------------------------------------
/shapefiles/communities/CommAreas.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/communities/CommAreas.dbf
--------------------------------------------------------------------------------
/shapefiles/communities/CommAreas.prj:
--------------------------------------------------------------------------------
1 | PROJCS["NAD_1983_StatePlane_Illinois_East_FIPS_1201_Feet",GEOGCS["GCS_North_American_1983",DATUM["D_North_American_1983",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",984250.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",-88.33333333333333],PARAMETER["Scale_Factor",0.999975],PARAMETER["Latitude_Of_Origin",36.66666666666666],UNIT["Foot_US",0.3048006096012192]]
--------------------------------------------------------------------------------
/shapefiles/communities/CommAreas.sbn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/communities/CommAreas.sbn
--------------------------------------------------------------------------------
/shapefiles/communities/CommAreas.sbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/communities/CommAreas.sbx
--------------------------------------------------------------------------------
/shapefiles/communities/CommAreas.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/communities/CommAreas.shp
--------------------------------------------------------------------------------
/shapefiles/communities/CommAreas.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/shapefiles/communities/CommAreas.shx
--------------------------------------------------------------------------------
/share/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/share/__init__.py
--------------------------------------------------------------------------------
/share/migrations/0004_auto_20151014_0253.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0003_auto_20151009_0919'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='session',
16 | name='created_at',
17 | field=models.DateTimeField(null=True, auto_now_add=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/0005_auto_20151014_0255.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0004_auto_20151014_0253'),
11 | ]
12 |
13 | operations = [
14 | migrations.AlterField(
15 | model_name='session',
16 | name='ip',
17 | field=models.CharField(default='', max_length=40, null=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/0007_session_active_tab.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0006_auto_20151103_0959'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='session',
16 | name='active_tab',
17 | field=models.CharField(max_length=40, default=''),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/0009_auto_20151123_0505.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 | import django_extensions.db.fields.json
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('share', '0008_auto_20151120_0414'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='session',
17 | name='query',
18 | field=django_extensions.db.fields.json.JSONField(blank=True),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/share/migrations/0010_session_searchable.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0009_auto_20151123_0505'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='session',
16 | name='searchable',
17 | field=models.BooleanField(default=False),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/0011_session_alias.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0010_session_searchable'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='session',
16 | name='alias',
17 | field=models.CharField(blank=True, null=True, max_length=254),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/0012_auto_20151201_0314.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0011_session_alias'),
11 | ]
12 |
13 | operations = [
14 | migrations.RemoveField(
15 | model_name='session',
16 | name='alias',
17 | ),
18 | migrations.RemoveField(
19 | model_name='session',
20 | name='searchable',
21 | ),
22 | ]
23 |
--------------------------------------------------------------------------------
/share/migrations/0013_session_sunburst_arc.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0012_auto_20151201_0314'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='session',
16 | name='sunburst_arc',
17 | field=models.CharField(max_length=40, default='', blank=True),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/0015_session_shared.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import models, migrations
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ('share', '0014_auto_20160112_0358'),
11 | ]
12 |
13 | operations = [
14 | migrations.AddField(
15 | model_name='session',
16 | name='shared',
17 | field=models.BooleanField(default=False),
18 | ),
19 | ]
20 |
--------------------------------------------------------------------------------
/share/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/share/migrations/__init__.py
--------------------------------------------------------------------------------
/share/tests/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'user'
2 |
--------------------------------------------------------------------------------
/share/tests/admin/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/share/tests/admin/__init__.py
--------------------------------------------------------------------------------
/share/tests/views/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'user'
2 |
--------------------------------------------------------------------------------
/share/tests/views/ui/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'user'
2 |
--------------------------------------------------------------------------------
/share/urls.py:
--------------------------------------------------------------------------------
1 | urlpatterns = [
2 | ]
3 |
--------------------------------------------------------------------------------
/share/views/__init__.py:
--------------------------------------------------------------------------------
1 | __author__ = 'user'
2 |
--------------------------------------------------------------------------------
/twitterbot/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/__init__.py
--------------------------------------------------------------------------------
/twitterbot/management/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/management/__init__.py
--------------------------------------------------------------------------------
/twitterbot/management/commands/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/management/commands/__init__.py
--------------------------------------------------------------------------------
/twitterbot/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/migrations/__init__.py
--------------------------------------------------------------------------------
/twitterbot/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/services/__init__.py
--------------------------------------------------------------------------------
/twitterbot/services/responses/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/services/responses/__init__.py
--------------------------------------------------------------------------------
/twitterbot/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/tests/__init__.py
--------------------------------------------------------------------------------
/twitterbot/tests/handlers/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/tests/handlers/__init__.py
--------------------------------------------------------------------------------
/twitterbot/tests/models/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/tests/models/__init__.py
--------------------------------------------------------------------------------
/twitterbot/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/tests/services/__init__.py
--------------------------------------------------------------------------------
/twitterbot/tests/services/responses/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/tests/services/responses/__init__.py
--------------------------------------------------------------------------------
/twitterbot/utils/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/twitterbot/utils/__init__.py
--------------------------------------------------------------------------------
/twitterbot/utils/log.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import unicodedata
4 |
5 |
6 | def bot_log(message):
7 | if os.environ.get('TWITTER_DEBUG', None) == 'true':
8 | message = unicodedata.normalize('NFKD', message).encode('ascii', 'ignore')
9 | print(message)
10 |
--------------------------------------------------------------------------------
/twitterbot/utils/tweet.py:
--------------------------------------------------------------------------------
1 | def build_tweet_permalink(tweet):
2 | return 'https://twitter.com/{screen_name}/status/{id}'.format(screen_name=tweet.user.screen_name, id=tweet.id)
3 |
--------------------------------------------------------------------------------
/url_mediator/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/url_mediator/__init__.py
--------------------------------------------------------------------------------
/url_mediator/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/url_mediator/migrations/__init__.py
--------------------------------------------------------------------------------
/url_mediator/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/url_mediator/services/__init__.py
--------------------------------------------------------------------------------
/url_mediator/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/url_mediator/tests/__init__.py
--------------------------------------------------------------------------------
/url_mediator/tests/services/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/url_mediator/tests/services/__init__.py
--------------------------------------------------------------------------------
/wagtail_app/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/wagtail_app/__init__.py
--------------------------------------------------------------------------------
/wagtail_app/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/invinst/CPDB/c2d8ae8888b13d956cc1068742f18d45736d4121/wagtail_app/migrations/__init__.py
--------------------------------------------------------------------------------
/wagtail_app/serializers.py:
--------------------------------------------------------------------------------
1 | from rest_framework import serializers
2 |
3 |
4 | class GlossaryTableRowSerializer(serializers.Serializer):
5 | term = serializers.CharField()
6 | definition = serializers.CharField()
7 | category = serializers.CharField()
8 |
--------------------------------------------------------------------------------