├── .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 | 10 | 11 | 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 | 10 | 11 | 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 | --------------------------------------------------------------------------------