diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..fc052dc --- /dev/null +++ b/.eslintrc @@ -0,0 +1,23 @@ +{ + "root": true, + "env": { + "browser": true, + "es2021": true, + "jquery": true + }, + "plugins": [ + "html" + ], + "parserOptions": { + "ecmaVersion": "latest" + }, + "extends": [ + "eslint-config-semistandard" + ], + "globals": { + "URI": "readonly" + }, + "rules": { + "comma-dangle": "error", + } +} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 6c8ae35..21843ae 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -19,3 +19,7 @@ jobs: ${{ runner.os }}-pip- - run: pip install -r requirements_dev.txt - run: flake8 + + - run: npm install + - run: ./node_modules/eslint/bin/eslint.js --ext .js --ext .html cove/cove_360/templates/** + - run: ./node_modules/eslint/bin/eslint.js --ext .js --ext .html cove/cove_360/static/dataexplore/js/** diff --git a/360-ds b/360-ds index de307c8..41fcb85 160000 --- a/360-ds +++ b/360-ds @@ -1 +1 @@ -Subproject commit de307c87b0eeba4d5ab8f673783f0e73b5ff613c +Subproject commit 41fcb85bb48b9f153928a4ebffc55a0d1f2b4ef9 diff --git a/cove/cove_360/context_processors.py b/cove/cove_360/context_processors.py index 26de178..bf6047e 100644 --- a/cove/cove_360/context_processors.py +++ b/cove/cove_360/context_processors.py @@ -5,4 +5,5 @@ def additional_context(request): return { "DATA_SUBMISSION_ENABLED": settings.DATA_SUBMISSION_ENABLED, "DEBUG": settings.DEBUG, + "DISABLE_COOKIE_POPUP": settings.DISABLE_COOKIE_POPUP, } diff --git a/cove/cove_360/fixtures/additional_fields.json b/cove/cove_360/fixtures/additional_fields.json new file mode 100644 index 0000000..c4dbb9f --- /dev/null +++ b/cove/cove_360/fixtures/additional_fields.json @@ -0,0 +1,27 @@ +{ + "grants": [ + { + "id": "360G-sampletrust-105177/Z/14/Z", + "awardDate": "2024-12-30", + "amountAwarded": 10, + "url": "http://example.com", + "title": "test", + "currency": "GBP", + "description": "test", + "AdditionalField": "2", + "CheckMicOne": "two", + "recipientOrganization": [ + { + "id": "GB-323242-test", + "name": "Example Project Limited" + } + ], + "fundingOrganization": [ + { + "id": "GB-323242-test", + "name": "Example Project Limited" + } + ] + } + ] +} diff --git a/cove/cove_360/fixtures/duration_usefulness.json b/cove/cove_360/fixtures/duration_usefulness.json new file mode 100644 index 0000000..9543e8f --- /dev/null +++ b/cove/cove_360/fixtures/duration_usefulness.json @@ -0,0 +1,25 @@ +{ + "grants": [ + { + "id": "360G-sampletrust-105177/Z/14/Z", + "awardDate": "2024-12-30", + "amountAwarded": 10, + "url": "http://example.com", + "title": "test", + "currency": "GBP", + "description": "test", + "recipientOrganization": [ + { + "id": "GB-323242-test", + "name": "Example Project Limited" + } + ], + "fundingOrganization": [ + { + "id": "GB-323242-test", + "name": "Example Project Limited" + } + ] + } + ] +} diff --git a/cove/cove_360/fixtures/multiple_funder_names_org_ids.json b/cove/cove_360/fixtures/multiple_funder_names_org_ids.json new file mode 100644 index 0000000..865951f --- /dev/null +++ b/cove/cove_360/fixtures/multiple_funder_names_org_ids.json @@ -0,0 +1,57 @@ +{ + "grants": [ + { + "id": "360G-sampletrust-105177/Z/14/Z", + "awardDate": "2024-12-30", + "amountAwarded": 10, + "url": "http://example.com", + "title": "test", + "currency": "GBP", + "description": "test", + "plannedDates": [ + { + "duration": 30 + } + ], + "recipientOrganization": [ + { + "id": "GB-323242-test", + "name": "Example Project Limited" + } + ], + "fundingOrganization": [ + { + "id": "GB-12345-test", + "name": "Example Funder Limited" + } + ] + }, + { + "id": "360G-sampletrust-123452", + "awardDate": "2024-12-30", + "amountAwarded": 10, + "url": "http://example.com", + "title": "test two", + "currency": "GBP", + "description": "test two", + "plannedDates": [ + { + "duration": 30 + } + ], + "recipientOrganization": [ + { + "id": "GB-323242-test", + "name": "Example Project Limited" + } + ], + "fundingOrganization": [ + { + "id": "GB-12345-test", + "name": "Example Funder" + } + ] + } + + ] +} diff --git a/cove/cove_360/fixtures/publishers.json b/cove/cove_360/fixtures/publishers.json index 6592cc6..90a9952 100644 --- a/cove/cove_360/fixtures/publishers.json +++ b/cove/cove_360/fixtures/publishers.json @@ -9,7 +9,8 @@ "self_publish": { "enabled": true, "authorised_domains": [ - "test-data.360dev1.vs.mythic-beasts.com" + "test-data.360dev1.vs.mythic-beasts.com", + "www.threesixtygiving.org" ] } } diff --git a/cove/cove_360/sass/_bootstrap-variables-360.scss b/cove/cove_360/sass/_bootstrap-variables-360.scss deleted file mode 100644 index adf5fcf..0000000 --- a/cove/cove_360/sass/_bootstrap-variables-360.scss +++ /dev/null @@ -1,872 +0,0 @@ -$bootstrap-sass-asset-helper: false !default; -// Flatly 3.3.6 -// Bootswatch -// Variables -// MIT License (see LICENCE.rst) -// -------------------------------------------------- - - -//== Colors -// -//## Gray and brand colors for use across Bootstrap. - -$gray-base: #000 !default; -$gray-darker: lighten($gray-base, 13.5%) !default; // #222 -$gray-dark: #7b8a8b !default; // #333 -$gray: #95a5a6 !default; // #555 -$gray-light: #b4bcc2 !default; // #999 -$gray-lighter: #ecf0f1 !default; // #eee - -$brand-primary: #2C3E50 !default; -$brand-success: hsla(185, 40%, 30%, 1) !default;// #ff9222 !default; -$brand-info: #ADADAD !default; -$brand-warning: #F39C12 !default; -$brand-danger: #E74C3C !default; - - -//== Scaffolding -// -//## Settings for some of the most global styles. - -//** Background color for ``. -$body-bg: #fff !default; -//** Global text color on ``. -$text-color: $brand-primary !default; - -//** Global textual link color. -$link-color: $brand-success !default; -//** Link hover color set via `darken()` function. -$link-hover-color: $link-color !default; -//** Link hover decoration. -$link-hover-decoration: underline !default; - - -//== Typography -// -//## Font, line-height, and color for body text, headings, and more. - -$font-family-sans-serif: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif !default; -$font-family-serif: Georgia, "Times New Roman", Times, serif !default; -//** Default monospace fonts for ``, ``, and `
`.
-$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace !default;
-$font-family-base:        $font-family-sans-serif !default;
-
-$font-size-base:          15px !default;
-$font-size-large:         ceil(($font-size-base * 1.25)) !default; // ~18px
-$font-size-small:         ceil(($font-size-base * 0.95)) !default; // ~12px
-
-$font-size-h1:            floor(($font-size-base * 2.6)) !default; // ~36px
-$font-size-h2:            floor(($font-size-base * 2.15)) !default; // ~30px
-$font-size-h3:            ceil(($font-size-base * 1.7)) !default; // ~24px
-$font-size-h4:            ceil(($font-size-base * 1.25)) !default; // ~18px
-$font-size-h5:            $font-size-base !default;
-$font-size-h6:            ceil(($font-size-base * 0.85)) !default; // ~12px
-
-//** Unit-less `line-height` for use in components like buttons.
-$line-height-base:        1.428571429 !default; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-$line-height-computed:    floor(($font-size-base * $line-height-base)) !default; // ~20px
-
-//** By default, this inherits from the ``.
-$headings-font-family:    'Assistant', sans-serif !default;
-$headings-font-weight:    100 !default;
-$headings-line-height:    1.1 !default;
-$headings-color:          inherit !default;
-
-
-//== Iconography
-//
-//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-//** Load fonts from this directory.
-$icon-font-path: if($bootstrap-sass-asset-helper, "bootstrap/", "../fonts/bootstrap/") !default;
-//** File name for all font files.
-$icon-font-name:          "glyphicons-halflings-regular" !default;
-//** Element ID within SVG icon file.
-$icon-font-svg-id:        "glyphicons_halflingsregular" !default;
-
-
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-$padding-base-vertical:     10px !default;
-$padding-base-horizontal:   15px !default;
-
-$padding-large-vertical:    18px !default;
-$padding-large-horizontal:  27px !default;
-
-$padding-small-vertical:    6px !default;
-$padding-small-horizontal:  9px !default;
-
-$padding-xs-vertical:       1px !default;
-$padding-xs-horizontal:     5px !default;
-
-$line-height-large:         1.3333333 !default; // extra decimals for Win 8.1 Chrome
-$line-height-small:         1.5 !default;
-
-$border-radius-base:        4px !default;
-$border-radius-large:       6px !default;
-$border-radius-small:       3px !default;
-
-//** Global color for active items (e.g., navs or dropdowns).
-$component-active-color:    #fff !default;
-//** Global background color for active items (e.g., navs or dropdowns).
-$component-active-bg:       $brand-primary !default;
-
-//** Width of the `border` for generating carets that indicator dropdowns.
-$caret-width-base:          4px !default;
-//** Carets increase slightly in size for larger components.
-$caret-width-large:         5px !default;
-
-
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Padding for ``s and ``s.
-$table-cell-padding:            8px !default;
-//** Padding for cells in `.table-condensed`.
-$table-condensed-cell-padding:  5px !default;
-
-//** Default background color used for all tables.
-$table-bg:                      transparent !default;
-//** Background color used for `.table-striped`.
-$table-bg-accent:               #f9f9f9 !default;
-//** Background color used for `.table-hover`.
-$table-bg-hover:                $gray-lighter !default;
-$table-bg-active:               $table-bg-hover !default;
-
-//** Border color for table and cell borders.
-$table-border-color:            $gray-lighter !default;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-$btn-font-weight:                normal !default;
-
-$btn-default-color:              #fff !default;
-$btn-default-bg:                 $gray !default;
-$btn-default-border:             $btn-default-bg !default;
-
-$btn-primary-color:              $btn-default-color !default;
-$btn-primary-bg:                 $brand-primary !default;
-$btn-primary-border:             $btn-primary-bg !default;
-
-$btn-success-color:              $btn-default-color !default;
-$btn-success-bg:                 $brand-success !default;
-$btn-success-border:             $btn-success-bg !default;
-
-$btn-info-color:                 $btn-default-color !default;
-$btn-info-bg:                    $brand-info !default;
-$btn-info-border:                $btn-info-bg !default;
-
-$btn-warning-color:              $btn-default-color !default;
-$btn-warning-bg:                 $brand-warning !default;
-$btn-warning-border:             $btn-warning-bg !default;
-
-$btn-danger-color:               $btn-default-color !default;
-$btn-danger-bg:                  $brand-danger !default;
-$btn-danger-border:              $btn-danger-bg !default;
-
-$btn-link-disabled-color:        $gray-light !default;
-
-// Allows for customizing button radius independently from global border radius
-$btn-border-radius-base:         $border-radius-base !default;
-$btn-border-radius-large:        $border-radius-large !default;
-$btn-border-radius-small:        $border-radius-small !default;
-
-
-//== Forms
-//
-//##
-
-//** `` background color
-$input-bg:                       #fff !default;
-//** `` background color
-$input-bg-disabled:              $gray-lighter !default;
-
-//** Text color for ``s
-$input-color:                    $text-color !default;
-//** `` border color
-$input-border:                   #dce4ec !default;
-
-// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
-//** Default `.form-control` border radius
-// This has no effect on ``s in CSS.
-$input-border-radius:            $border-radius-base !default;
-//** Large `.form-control` border radius
-$input-border-radius-large:      $border-radius-large !default;
-//** Small `.form-control` border radius
-$input-border-radius-small:      $border-radius-small !default;
-
-//** Border color for inputs on focus
-$input-border-focus:             $brand-primary !default;
-
-//** Placeholder text color
-$input-color-placeholder:        #acb6c0 !default;
-
-//** Default `.form-control` height
-$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 4) !default;
-//** Large `.form-control` height
-$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 4) !default;
-//** Small `.form-control` height
-$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 4) !default;
-
-//** `.form-group` margin
-$form-group-margin-bottom:       15px !default;
-
-$legend-color:                   $text-color !default;
-$legend-border-color:            transparent !default;
-
-//** Background color for textual input addons
-$input-group-addon-bg:           $gray-lighter !default;
-//** Border color for textual input addons
-$input-group-addon-border-color: $input-border !default;
-
-//** Disabled cursor for form controls and buttons.
-$cursor-disabled:                not-allowed !default;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-$dropdown-bg:                    #fff !default;
-//** Dropdown menu `border-color`.
-$dropdown-border:                rgba(0,0,0,.15) !default;
-//** Dropdown menu `border-color` **for IE8**.
-$dropdown-fallback-border:       #ccc !default;
-//** Divider color for between dropdown items.
-$dropdown-divider-bg:            #e5e5e5 !default;
-
-//** Dropdown link text color.
-$dropdown-link-color:            $gray-dark !default;
-//** Hover color for dropdown links.
-$dropdown-link-hover-color:      #fff !default;
-//** Hover background for dropdown links.
-$dropdown-link-hover-bg:         $component-active-bg !default;
-
-//** Active dropdown menu item text color.
-$dropdown-link-active-color:     #fff !default;
-//** Active dropdown menu item background color.
-$dropdown-link-active-bg:        $component-active-bg !default;
-
-//** Disabled dropdown menu item background color.
-$dropdown-link-disabled-color:   $gray-light !default;
-
-//** Text color for headers within dropdown menus.
-$dropdown-header-color:          $gray-light !default;
-
-//** Deprecated `$dropdown-caret-color` as of v3.1.0
-$dropdown-caret-color:           #000 !default;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-$zindex-navbar:            1000 !default;
-$zindex-dropdown:          1000 !default;
-$zindex-popover:           1060 !default;
-$zindex-tooltip:           1070 !default;
-$zindex-navbar-fixed:      1030 !default;
-$zindex-modal-background:  1040 !default;
-$zindex-modal:             1050 !default;
-
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
-
-// Extra small screen / phone
-//** Deprecated `$screen-xs` as of v3.0.1
-$screen-xs:                  480px !default;
-//** Deprecated `$screen-xs-min` as of v3.2.0
-$screen-xs-min:              $screen-xs !default;
-//** Deprecated `$screen-phone` as of v3.0.1
-$screen-phone:               $screen-xs-min !default;
-
-// Small screen / tablet
-//** Deprecated `$screen-sm` as of v3.0.1
-$screen-sm:                  768px !default;
-$screen-sm-min:              $screen-sm !default;
-//** Deprecated `$screen-tablet` as of v3.0.1
-$screen-tablet:              $screen-sm-min !default;
-
-// Medium screen / desktop
-//** Deprecated `$screen-md` as of v3.0.1
-$screen-md:                  992px !default;
-$screen-md-min:              $screen-md !default;
-//** Deprecated `$screen-desktop` as of v3.0.1
-$screen-desktop:             $screen-md-min !default;
-
-// Large screen / wide desktop
-//** Deprecated `$screen-lg` as of v3.0.1
-$screen-lg:                  1200px !default;
-$screen-lg-min:              $screen-lg !default;
-//** Deprecated `$screen-lg-desktop` as of v3.0.1
-$screen-lg-desktop:          $screen-lg-min !default;
-
-// So media queries don't overlap when required, provide a maximum
-$screen-xs-max:              ($screen-sm-min - 1) !default;
-$screen-sm-max:              ($screen-md-min - 1) !default;
-$screen-md-max:              ($screen-lg-min - 1) !default;
-
-
-//== Grid system
-//
-//## Define your custom responsive grid.
-
-//** Number of columns in the grid.
-$grid-columns:              12 !default;
-//** Padding between columns. Gets divided in half for the left and right.
-$grid-gutter-width:         30px !default;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-$grid-float-breakpoint:     $screen-sm-min !default;
-//** Point at which the navbar begins collapsing.
-$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
-
-
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-$container-tablet:             (720px + $grid-gutter-width) !default;
-//** For `$screen-sm-min` and up.
-$container-sm:                 $container-tablet !default;
-
-// Medium screen / desktop
-$container-desktop:            (940px + $grid-gutter-width) !default;
-//** For `$screen-md-min` and up.
-$container-md:                 $container-desktop !default;
-
-// Large screen / wide desktop
-$container-large-desktop:      (1140px + $grid-gutter-width) !default;
-//** For `$screen-lg-min` and up.
-$container-lg:                 $container-large-desktop !default;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-$navbar-height:                    80px !default;
-$navbar-margin-bottom:             $line-height-computed !default;
-$navbar-border-radius:             0;
-$navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
-$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
-$navbar-collapse-max-height:       340px !default;
-
-$navbar-default-color:             #fff !default;
-$navbar-default-bg:                $brand-primary !default;
-$navbar-default-border:            transparent !default;
-
-// Navbar links
-$navbar-default-link-color:                #fff !default;
-$navbar-default-link-hover-color:          $brand-success !default;
-$navbar-default-link-hover-bg:             transparent !default;
-$navbar-default-link-active-color:         #fff !default;
-$navbar-default-link-active-bg:            darken($navbar-default-bg, 10%) !default;
-$navbar-default-link-disabled-color:       #ccc !default;
-$navbar-default-link-disabled-bg:          transparent !default;
-
-// Navbar brand label
-$navbar-default-brand-color:               $navbar-default-link-color !default;
-$navbar-default-brand-hover-color:         $navbar-default-link-hover-color !default;
-$navbar-default-brand-hover-bg:            transparent !default;
-
-// Navbar toggle
-$navbar-default-toggle-hover-bg:           darken($navbar-default-bg, 10%) !default;
-$navbar-default-toggle-icon-bar-bg:        #fff !default;
-$navbar-default-toggle-border-color:       darken($navbar-default-bg, 10%) !default;
-
-
-//=== Inverted navbar
-// Reset inverted navbar basics
-$navbar-inverse-color:                      #fff !default;
-$navbar-inverse-bg:                         $brand-success !default;
-$navbar-inverse-border:                     transparent !default;
-
-// Inverted navbar links
-$navbar-inverse-link-color:                 #fff !default;
-$navbar-inverse-link-hover-color:           $brand-primary !default;
-$navbar-inverse-link-hover-bg:              transparent !default;
-$navbar-inverse-link-active-color:          #fff !default;
-$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 5%) !default;
-$navbar-inverse-link-disabled-color:        #ccc !default;
-$navbar-inverse-link-disabled-bg:           transparent !default;
-
-// Inverted navbar brand label
-$navbar-inverse-brand-color:                $navbar-inverse-link-color !default;
-$navbar-inverse-brand-hover-color:          $navbar-inverse-link-hover-color !default;
-$navbar-inverse-brand-hover-bg:             transparent !default;
-
-// Inverted navbar toggle
-$navbar-inverse-toggle-hover-bg:            darken($navbar-inverse-bg, 10%) !default;
-$navbar-inverse-toggle-icon-bar-bg:         #fff !default;
-$navbar-inverse-toggle-border-color:        darken($navbar-inverse-bg, 10%) !default;
-
-
-//== Navs
-//
-//##
-
-//=== Shared nav styles
-$nav-link-padding:                          10px 15px !default;
-$nav-link-hover-bg:                         $gray-lighter !default;
-
-$nav-disabled-link-color:                   $gray-light !default;
-$nav-disabled-link-hover-color:             $gray-light !default;
-
-//== Tabs
-$nav-tabs-border-color:                     $gray-lighter !default;
-
-$nav-tabs-link-hover-border-color:          $gray-lighter !default;
-
-$nav-tabs-active-link-hover-bg:             $body-bg !default;
-$nav-tabs-active-link-hover-color:          $brand-primary !default;
-$nav-tabs-active-link-hover-border-color:   $gray-lighter !default;
-
-$nav-tabs-justified-link-border-color:            $gray-lighter !default;
-$nav-tabs-justified-active-link-border-color:     $body-bg !default;
-
-//== Pills
-$nav-pills-border-radius:                   $border-radius-base !default;
-$nav-pills-active-link-hover-bg:            $component-active-bg !default;
-$nav-pills-active-link-hover-color:         $component-active-color !default;
-
-
-//== Pagination
-//
-//##
-
-$pagination-color:                     #fff !default;
-$pagination-bg:                        $brand-success !default;
-$pagination-border:                    transparent !default;
-
-$pagination-hover-color:               #fff !default;
-$pagination-hover-bg:                  darken($brand-success, 15%) !default;
-$pagination-hover-border:              transparent !default;
-
-$pagination-active-color:              #fff !default;
-$pagination-active-bg:                 darken($brand-success, 15%) !default;
-$pagination-active-border:             transparent !default;
-
-$pagination-disabled-color:            $gray-lighter !default;
-$pagination-disabled-bg:               lighten($brand-success, 15%) !default;
-$pagination-disabled-border:           transparent !default;
-
-
-//== Pager
-//
-//##
-
-$pager-bg:                             $pagination-bg !default;
-$pager-border:                         $pagination-border !default;
-$pager-border-radius:                  15px !default;
-
-$pager-hover-bg:                       $pagination-hover-bg !default;
-
-$pager-active-bg:                      $pagination-active-bg !default;
-$pager-active-color:                   $pagination-active-color !default;
-
-$pager-disabled-color:                 #fff !default;
-
-
-//== Jumbotron
-//
-//##
-
-$jumbotron-padding:              30px !default;
-$jumbotron-color:                inherit !default;
-$jumbotron-bg:                   $gray-lighter !default;
-$jumbotron-heading-color:        inherit !default;
-$jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
-$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-$state-success-text:             #fff !default;
-$state-success-bg:               $brand-success !default;
-$state-success-border:           $brand-success !default;
-
-$state-info-text:                #fff !default;
-$state-info-bg:                  $brand-info !default;
-$state-info-border:              $brand-info !default;
-
-$state-warning-text:             #fff !default;
-$state-warning-bg:               $brand-warning !default;
-$state-warning-border:           $brand-warning !default;
-
-$state-danger-text:              #fff !default;
-$state-danger-bg:                $brand-danger !default;
-$state-danger-border:            $brand-danger !default;
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
-$tooltip-max-width:           200px !default;
-//** Tooltip text color
-$tooltip-color:               #fff !default;
-//** Tooltip background color
-$tooltip-bg:                  #000 !default;
-$tooltip-opacity:             .9 !default;
-
-//** Tooltip arrow width
-$tooltip-arrow-width:         5px !default;
-//** Tooltip arrow color
-$tooltip-arrow-color:         $tooltip-bg !default;
-
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-$popover-bg:                          #fff !default;
-//** Popover maximum width
-$popover-max-width:                   276px !default;
-//** Popover border color
-$popover-border-color:                rgba(0,0,0,.2) !default;
-//** Popover fallback border color
-$popover-fallback-border-color:       #ccc !default;
-
-//** Popover title background color
-$popover-title-bg:                    darken($popover-bg, 3%) !default;
-
-//** Popover arrow width
-$popover-arrow-width:                 10px !default;
-//** Popover arrow color
-$popover-arrow-color:                 $popover-bg !default;
-
-//** Popover outer arrow width
-$popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
-//** Popover outer arrow color
-$popover-arrow-outer-color:           fadein($popover-border-color, 5%) !default;
-//** Popover outer arrow fallback color
-$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
-
-
-//== Labels
-//
-//##
-
-//** Default label background color
-$label-default-bg:            $btn-default-bg !default;
-//** Primary label background color
-$label-primary-bg:            $brand-primary !default;
-//** Success label background color
-$label-success-bg:            $brand-success !default;
-//** Info label background color
-$label-info-bg:               $brand-info !default;
-//** Warning label background color
-$label-warning-bg:            $brand-warning !default;
-//** Danger label background color
-$label-danger-bg:             $brand-danger !default;
-
-//** Default label text color
-$label-color:                 #fff !default;
-//** Default text color of a linked label
-$label-link-hover-color:      #fff !default;
-
-
-//== Modals
-//
-//##
-
-//** Padding applied to the modal body
-$modal-inner-padding:         20px !default;
-
-//** Padding applied to the modal title
-$modal-title-padding:         15px !default;
-//** Modal title line-height
-$modal-title-line-height:     $line-height-base !default;
-
-//** Background color of modal content area
-$modal-content-bg:                             #fff !default;
-//** Modal content border color
-$modal-content-border-color:                   rgba(0,0,0,.2) !default;
-//** Modal content border color **for IE8**
-$modal-content-fallback-border-color:          #999 !default;
-
-//** Modal backdrop background color
-$modal-backdrop-bg:           #000 !default;
-//** Modal backdrop opacity
-$modal-backdrop-opacity:      .5 !default;
-//** Modal header border color
-$modal-header-border-color:   #e5e5e5 !default;
-//** Modal footer border color
-$modal-footer-border-color:   $modal-header-border-color !default;
-
-$modal-lg:                    900px !default;
-$modal-md:                    600px !default;
-$modal-sm:                    300px !default;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
-
-$alert-padding:               15px !default;
-$alert-border-radius:         $border-radius-base !default;
-$alert-link-font-weight:      bold !default;
-
-$alert-success-bg:            $state-success-bg !default;
-$alert-success-text:          $state-success-text !default;
-$alert-success-border:        $state-success-border !default;
-
-$alert-info-bg:               $state-info-bg !default;
-$alert-info-text:             $state-info-text !default;
-$alert-info-border:           $state-info-border !default;
-
-$alert-warning-bg:            $state-warning-bg !default;
-$alert-warning-text:          $state-warning-text !default;
-$alert-warning-border:        $state-warning-border !default;
-
-$alert-danger-bg:             $state-danger-bg !default;
-$alert-danger-text:           $state-danger-text !default;
-$alert-danger-border:         $state-danger-border !default;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-$progress-bg:                 $gray-lighter !default;
-//** Progress bar text color
-$progress-bar-color:          #fff !default;
-//** Variable for setting rounded corners on progress bar.
-$progress-border-radius:      $border-radius-base !default;
-
-//** Default progress bar color
-$progress-bar-bg:             $brand-primary !default;
-//** Success progress bar color
-$progress-bar-success-bg:     $brand-success !default;
-//** Warning progress bar color
-$progress-bar-warning-bg:     $brand-warning !default;
-//** Danger progress bar color
-$progress-bar-danger-bg:      $brand-danger !default;
-//** Info progress bar color
-$progress-bar-info-bg:        $brand-info !default;
-
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-$list-group-bg:                 #fff !default;
-//** `.list-group-item` border color
-$list-group-border:             $gray-lighter !default;
-//** List group border radius
-$list-group-border-radius:      $border-radius-base !default;
-
-//** Background color of single list items on hover
-$list-group-hover-bg:           $gray-lighter !default;
-//** Text color of active list items
-$list-group-active-color:       $component-active-color !default;
-//** Background color of active list items
-$list-group-active-bg:          $component-active-bg !default;
-//** Border color of active list elements
-$list-group-active-border:      $list-group-active-bg !default;
-//** Text color for content within active list items
-$list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
-
-//** Text color of disabled list items
-$list-group-disabled-color:      $gray-light !default;
-//** Background color of disabled list items
-$list-group-disabled-bg:         $gray-lighter !default;
-//** Text color for content within disabled list items
-$list-group-disabled-text-color: $list-group-disabled-color !default;
-
-$list-group-link-color:         #555 !default;
-$list-group-link-hover-color:   $list-group-link-color !default;
-$list-group-link-heading-color: #333 !default;
-
-
-//== Panels
-//
-//##
-
-$panel-bg:                    #fff !default;
-$panel-body-padding:          15px !default;
-$panel-heading-padding:       10px 15px !default;
-$panel-footer-padding:        $panel-heading-padding !default;
-$panel-border-radius:         $border-radius-base !default;
-
-//** Border color for elements within panels
-$panel-inner-border:          $gray-lighter !default;
-$panel-footer-bg:             $gray-lighter !default;
-
-$panel-default-text:          $text-color !default;
-$panel-default-border:        $gray-lighter !default;
-$panel-default-heading-bg:    $gray-lighter !default;
-
-$panel-primary-text:          #fff !default;
-$panel-primary-border:        $brand-primary !default;
-$panel-primary-heading-bg:    $brand-primary !default;
-
-$panel-success-text:          $state-success-text !default;
-$panel-success-border:        $state-success-border !default;
-$panel-success-heading-bg:    $state-success-bg !default;
-
-$panel-info-text:             $state-info-text !default;
-$panel-info-border:           $state-info-border !default;
-$panel-info-heading-bg:       $state-info-bg !default;
-
-$panel-warning-text:          $state-warning-text !default;
-$panel-warning-border:        $state-warning-border !default;
-$panel-warning-heading-bg:    $state-warning-bg !default;
-
-$panel-danger-text:           $state-danger-text !default;
-$panel-danger-border:         $state-danger-border !default;
-$panel-danger-heading-bg:     $state-danger-bg !default;
-
-
-//== Thumbnails
-//
-//##
-
-//** Padding around the thumbnail image
-$thumbnail-padding:           4px !default;
-//** Thumbnail background color
-$thumbnail-bg:                $body-bg !default;
-//** Thumbnail border color
-$thumbnail-border:            $gray-lighter !default;
-//** Thumbnail border radius
-$thumbnail-border-radius:     $border-radius-base !default;
-
-//** Custom text color for thumbnail captions
-$thumbnail-caption-color:     $text-color !default;
-//** Padding around the thumbnail caption
-$thumbnail-caption-padding:   9px !default;
-
-
-//== Wells
-//
-//##
-
-$well-bg:                     $gray-lighter !default;
-$well-border:                 transparent !default;
-
-
-//== Badges
-//
-//##
-
-$badge-color:                 #fff !default;
-//** Linked badge text color on hover
-$badge-link-hover-color:      #fff !default;
-$badge-bg:                    $brand-primary !default;
-
-//** Badge text color in active nav link
-$badge-active-color:          $brand-primary !default;
-//** Badge background color in active nav link
-$badge-active-bg:             #fff !default;
-
-$badge-font-weight:           bold !default;
-$badge-line-height:           1 !default;
-$badge-border-radius:         10px !default;
-
-
-//== Breadcrumbs
-//
-//##
-
-$breadcrumb-padding-vertical:   8px !default;
-$breadcrumb-padding-horizontal: 15px !default;
-//** Breadcrumb background color
-$breadcrumb-bg:                 $gray-lighter !default;
-//** Breadcrumb text color
-$breadcrumb-color:              #ccc !default;
-//** Text color of current page in the breadcrumb
-$breadcrumb-active-color:       $gray !default;
-//** Textual separator for between breadcrumb elements
-$breadcrumb-separator:          "/" !default;
-
-
-//== Carousel
-//
-//##
-
-$carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6) !default;
-
-$carousel-control-color:                      #fff !default;
-$carousel-control-width:                      15% !default;
-$carousel-control-opacity:                    .5 !default;
-$carousel-control-font-size:                  20px !default;
-
-$carousel-indicator-active-bg:                #fff !default;
-$carousel-indicator-border-color:             #fff !default;
-
-$carousel-caption-color:                      #fff !default;
-
-
-//== Close
-//
-//##
-
-$close-font-weight:           bold !default;
-$close-color:                 #000 !default;
-$close-text-shadow:           none !default;
-
-
-//== Code
-//
-//##
-
-$code-color:                  #c7254e !default;
-$code-bg:                     #f9f2f4 !default;
-
-$kbd-color:                   #fff !default;
-$kbd-bg:                      #333 !default;
-
-$pre-bg:                      $gray-lighter !default;
-$pre-color:                   $gray-dark !default;
-$pre-border-color:            #ccc !default;
-$pre-scrollable-max-height:   340px !default;
-
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-$component-offset-horizontal: 180px !default;
-//** Text muted color
-$text-muted:                  $gray-light !default;
-//** Abbreviations and acronyms border color
-$abbr-border-color:           $gray-light !default;
-//** Headings small color
-$headings-small-color:        $gray-dark !default;
-//** Blockquote small color
-$blockquote-small-color:      $gray-light !default;
-//** Blockquote font size
-$blockquote-font-size:        ($font-size-base * 1.25) !default;
-//** Blockquote border color
-$blockquote-border-color:     $gray-lighter !default;
-//** Page header border color
-$page-header-border-color:    transparent !default;
-//** Width of horizontal description list titles
-$dl-horizontal-offset:        $component-offset-horizontal !default;
-//** Point at which .dl-horizontal becomes horizontal
-$dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
-//** Horizontal line color.
-$hr-border:                   $gray-lighter !default;
diff --git a/cove/cove_360/sass/_custom-360.scss b/cove/cove_360/sass/_custom-360.scss
deleted file mode 100644
index cea0954..0000000
--- a/cove/cove_360/sass/_custom-360.scss
+++ /dev/null
@@ -1,543 +0,0 @@
-// Flatly 3.3.5
-// Bootswatch
-// -----------------------------------------------------
-// Cove custom
-
-// Example search terms
-
-body {
-	background-color: white
-}
-
-.expand-collapse-all {
-	text-align: right;
-	padding-top: 100px;
-}
-
-.panel-title.panel-title-explore {
-	font-size: 30px;
-	cursor: pointer;
-
-	& small {
-		font-weight: 100;
-		font-size: 45%;
-	}
-
-	& .glyphicon-collapse-down, & .glyphicon-collapse-up {
-		padding-right: 0px;
-		line-height: 33px;
-		color: #666;
-	}
-
-	& span.glyphicon-save::before, {
-		color: #666;
-	}
-
-	& span.glyphicon-list-alt::before {
-		color: #666;
-		vertical-align: text-bottom;
-	}
-}
-
-.font-tick {
-	font-family: 'tick';
-	margin-right: 5px;
-
-	&.tick {
-		color: green;
-
-		&::after {
-			content: '\2713';
-		}
-	}
-
-	&.cross {
-		color: red;
-
-		&::after {
-					content: '\2715';
-			}
-	}
-
-	&.question {
-		color: orange;
-
-		&::after {
-			content: '?';
-		}
-	}
-}
-
-ul.pagination a{
-	padding: 4px;
-	font-size: 80%;
-}
-
-.explore-help {
-	margin: 12px 35px;
-}
-
-.panel-body p.icon-indent {
-	text-indent: 20px;
-
-	& span {
-		color: #666 !important;
-	}
-}
-
-.info-faq {
-	cursor: pointer;
-	margin-top:20px;
-	font-size: 16px;
-	color: #050505;
-	margin-bottom: 20px;
-	& span {
-		font-size:12px;
-		color: #ff9222;
-	}
-}
-
-.highlight-background-text {
-    background-color: #E7EBE8 !important;
-}
-
-
-////////////
-
-$web-font-path: "https://fonts.googleapis.com/css?family=Lato:400,700,400italic" !default;
-@import url($web-font-path);
-
-// Navbar =====================================================================
-
-.navbar {
-	border-width: 0;
-
-	&-default {
-
-		.badge {
-			background-color: #fff;
-			color: $navbar-default-bg;
-		}
-	}
-
-	&-inverse {
-
-		.badge {
-			background-color: #fff;
-			color: $navbar-inverse-bg;
-		}
-	}
-
-	&-brand {
-		//grantnav changes
-		color: #FFF;
-		font-family: 'Ostrich Sans',sans-serif;
-		font-size: 48px;
-		letter-spacing: 2px;
-		line-height: 1.9em;
-		padding: 0px 12px;
-		@media (min-width: $grid-float-breakpoint) {
-			.navbar > .container &,
-			.navbar > .container-fluid & {
-				margin-left: 0;
-			}
-		}
-		&:hover {
-			color: #FFF !important
-		}
-		//grantnav
-	}
-
-	&-header {
-		margin-left: 10px;
-	}
-}
-
-
-// Buttons ====================================================================
-
-.btn {
-	border-width: 2px;
-}
-
-.btn:active {
-	@include box-shadow(none);
-}
-
-.btn-group.open .dropdown-toggle {
-	@include box-shadow(none);
-}
-
-// Typography =================================================================
-
-.text-primary,
-.text-primary:hover {
-	color: $brand-primary;
-}
-
-.text-success,
-.text-success:hover {
-	color: $brand-success;
-}
-
-.text-danger,
-.text-danger:hover {
-	color: $brand-danger;
-}
-
-.text-warning,
-.text-warning:hover {
-	color: $brand-warning;
-}
-
-.text-info,
-.text-info:hover {
-	color: $brand-info;
-}
-
-// grantnav
-h1, .h1,
-h2, .h2,
-h3, .h3 {
-	margin-top: $line-height-computed;
-	margin-bottom: ($line-height-computed / 2);
-
-	small,
-	.small {
-		font-size: 85%;
-	}
-}
-h4, .h4,
-h5, .h5,
-h6, .h6 {
-	margin-top: ($line-height-computed / 2);
-	margin-bottom: ($line-height-computed / 2);
-
-	small,
-	.small {
-		font-size: 95%;
-	}
-}
-//
-
-// Tables =====================================================================
-
-table,
-.table {
-
-	a:not(.btn) {
-		text-decoration: underline;
-	}
-
-	.dropdown-menu a {
-		text-decoration: none;
-	}
-
-	.success,
-	.warning,
-	.danger,
-	.info {
-		color: #fff;
-
-		> th > a,
-		> td > a,
-		> a {
-			color: #fff;
-		}
-	}
-
-	> thead > tr > th,
-	> tbody > tr > th,
-	> tfoot > tr > th,
-	> thead > tr > td,
-	> tbody > tr > td,
-	> tfoot > tr > td {
-	}
-
-	&-bordered > thead > tr > th,
-	&-bordered > tbody > tr > th,
-	&-bordered > tfoot > tr > th,
-	&-bordered > thead > tr > td,
-	&-bordered > tbody > tr > td,
-	&-bordered > tfoot > tr > td {
-		border: 1px solid $table-border-color;
-	}
-}
-
-// Forms ======================================================================
-
-.form-control,
-input {
-	border-width: 2px;
-	@include box-shadow(none);
-
-	&:focus {
-		@include box-shadow(none);
-	}
-}
-
-.has-warning {
-	.help-block,
-	.control-label,
-	.radio,
-	.checkbox,
-	.radio-inline,
-	.checkbox-inline,
-	&.radio label,
-	&.checkbox label,
-	&.radio-inline label,
-	&.checkbox-inline label,
-	.form-control-feedback {
-		color: $brand-warning;
-	}
-
-	.form-control,
-	.form-control:focus {
-		border: 2px solid $brand-warning;
-	}
-
-	.input-group-addon {
-		border-color: $brand-warning;
-	}
-}
-
-.has-error {
-	.help-block,
-	.control-label,
-	.radio,
-	.checkbox,
-	.radio-inline,
-	.checkbox-inline,
-	&.radio label,
-	&.checkbox label,
-	&.radio-inline label,
-	&.checkbox-inline label,
-	.form-control-feedback {
-		color: $brand-danger;
-	}
-
-	.form-control,
-	.form-control:focus {
-		border: 2px solid $brand-danger;
-	}
-
-	.input-group-addon {
-		border-color: $brand-danger;
-	}
-}
-
-.has-success {
-	.help-block,
-	.control-label,
-	.radio,
-	.checkbox,
-	.radio-inline,
-	.checkbox-inline,
-	&.radio label,
-	&.checkbox label,
-	&.radio-inline label,
-	&.checkbox-inline label,
-	.form-control-feedback {
-		color: $brand-success;
-	}
-
-	.form-control,
-	.form-control:focus {
-		border: 2px solid $brand-success;
-	}
-
-	.input-group-addon {
-		border-color: $brand-success;
-	}
-}
-
-//grantnav
-
-::-webkit-input-placeholder {font-style:italic}
-::-moz-placeholder {font-style:italic} /* firefox 19+ */
-:-ms-input-placeholder {font-style:italic} /* ie */
-input:-moz-placeholder {font-style:italic}
-
-.container-wrapper {
-	background-color: $brand-success;
-	margin-top: -21px;
-	padding-top: 15px;
-}
-
-.search-box {
-	left: 18px;
-}
-
-.search-icon {
-	right: 18px;
-	z-index: 1000;
-	position: relative;
-}
-
-// Main search bar on landing page
-.large-search {
-	display: inline-block;
-	vertical-align: top;
-	width: 79%;
-	margin: 0 auto;
-	padding: 10px 20px;
-	border-radius: 12px;
-	border: 2px solid #e5831e;
-	background-color: #FFF;
-	font-size: 28px;
-	height: 79px;
-}
-
-.large-search-icon {
-	position: absolute;
-	right: 38px;
-	top: 12px;
-}
-
-// Example search terms container
-.search-help {
-	font-size: 1.1em;
-	color: #663a0e;
-	padding-top: 10px;
-	margin: 0 auto;
-	margin-bottom: 20px;
-	text-align: center;
-}
-
-.col-vlg-offset-1 {
-	@media (min-width: 1400px) {
-		width: 1300px;
-		margin-left: auto;
-		margin-right: auto;
-	}
-}
-//
-
-// Navs =======================================================================
-
-.nav {
-	.open > a,
-	.open > a:hover,
-	.open > a:focus {
-		border-color: transparent;
-	}
-}
-
-.pager {
-	a,
-	a:hover {
-		color: #fff;
-	}
-
-	.disabled {
-		&>a,
-		&>a:hover,
-		&>a:focus,
-		&>span {
-			background-color: $pagination-disabled-bg;
-		}
-	}
-}
-
-// Indicators =================================================================
-
-.close {
-	color: #fff;
-	text-decoration: none;
-	opacity: 0.4;
-
-	&:hover,
-	&:focus {
-		color: #fff;
-		opacity: 1;
-	}
-}
-
-.alert {
-
-	.alert-link {
-		color: #fff;
-		text-decoration: underline;
-	}
-}
-
-// Progress bars ==============================================================
-
-.progress {
-	height: 10px;
-	@include box-shadow(none);
-	.progress-bar {
-		font-size: 10px;
-		line-height: 10px;
-	}
-}
-
-// Containers =================================================================
-
-.well {
-	@include box-shadow(none);
-}
-
-a.list-group-item {
-
-	&.active,
-	&.active:hover,
-	&.active:focus {
-		border-color: $list-group-border;
-	}
-
-	&-success {
-		&.active {
-			background-color: $state-success-bg;
-		}
-
-		&.active:hover,
-		&.active:focus {
-			background-color: darken($state-success-bg, 5%);
-		}
-	}
-
-	&-warning {
-		&.active {
-			background-color: $state-warning-bg;
-		}
-		
-		&.active:hover,
-		&.active:focus {
-			background-color: darken($state-warning-bg, 5%);
-		}
-	}
-
-	&-danger {
-		&.active {
-			background-color: $state-danger-bg;
-		}
-		
-		&.active:hover,
-		&.active:focus {
-			background-color: darken($state-danger-bg, 5%);
-		}
-	}
-}
-
-.panel {
-	&-default {
-		.close {
-			color: $text-color;
-		}
-	}
-}
-
-.modal {
-	.close {
-		color: $text-color;
-	}
-}
-
-.popover {
-	color: $text-color;
-}
-
-html {
-	font-size: initial;
-}
\ No newline at end of file
diff --git a/cove/cove_360/sass/bootstrap/_bootstrap-compass.scss b/cove/cove_360/sass/bootstrap/_bootstrap-compass.scss
deleted file mode 100644
index 8fbc3cd..0000000
--- a/cove/cove_360/sass/bootstrap/_bootstrap-compass.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-@function twbs-font-path($path) {
-  @return font-url($path, true);
-}
-
-@function twbs-image-path($path) {
-  @return image-url($path, true);
-}
-
-$bootstrap-sass-asset-helper: true;
diff --git a/cove/cove_360/sass/bootstrap/_bootstrap-mincer.scss b/cove/cove_360/sass/bootstrap/_bootstrap-mincer.scss
deleted file mode 100644
index 0c4655e..0000000
--- a/cove/cove_360/sass/bootstrap/_bootstrap-mincer.scss
+++ /dev/null
@@ -1,19 +0,0 @@
-// Mincer asset helper functions
-//
-// This must be imported into a .css.ejs.scss file.
-// Then, <% %>-interpolations will be parsed as strings by Sass, and evaluated by EJS after Sass compilation.
-
-
-@function twbs-font-path($path) {
-  // do something like following
-  // from "path/to/font.ext#suffix" to "<%- asset_path(path/to/font.ext)) + #suffix %>"
-  // from "path/to/font.ext?#suffix" to "<%- asset_path(path/to/font.ext)) + ?#suffix %>"
-  // or from "path/to/font.ext" just "<%- asset_path(path/to/font.ext)) %>"
-  @return "<%- asset_path("#{$path}".replace(/[#?].*$/, '')) + "#{$path}".replace(/(^[^#?]*)([#?]?.*$)/, '$2') %>";
-}
-
-@function twbs-image-path($file) {
-  @return "<%- asset_path("#{$file}") %>";
-}
-
-$bootstrap-sass-asset-helper: true;
diff --git a/cove/cove_360/sass/bootstrap/_bootstrap-sprockets.scss b/cove/cove_360/sass/bootstrap/_bootstrap-sprockets.scss
deleted file mode 100644
index 9fffc1e..0000000
--- a/cove/cove_360/sass/bootstrap/_bootstrap-sprockets.scss
+++ /dev/null
@@ -1,9 +0,0 @@
-@function twbs-font-path($path) {
-  @return font-path($path);
-}
-
-@function twbs-image-path($path) {
-  @return image-path($path);
-}
-
-$bootstrap-sass-asset-helper: true;
diff --git a/cove/cove_360/sass/bootstrap/_bootstrap.scss b/cove/cove_360/sass/bootstrap/_bootstrap.scss
deleted file mode 100644
index e72d1de..0000000
--- a/cove/cove_360/sass/bootstrap/_bootstrap.scss
+++ /dev/null
@@ -1,56 +0,0 @@
-/*!
- * Bootstrap v3.3.7 (http://getbootstrap.com)
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
- */
-
-// Core variables and mixins
-@import "bootstrap/variables";
-@import "bootstrap/mixins";
-
-// Reset and dependencies
-@import "bootstrap/normalize";
-@import "bootstrap/print";
-@import "bootstrap/glyphicons";
-
-// Core CSS
-@import "bootstrap/scaffolding";
-@import "bootstrap/type";
-@import "bootstrap/code";
-@import "bootstrap/grid";
-@import "bootstrap/tables";
-@import "bootstrap/forms";
-@import "bootstrap/buttons";
-
-// Components
-@import "bootstrap/component-animations";
-@import "bootstrap/dropdowns";
-@import "bootstrap/button-groups";
-@import "bootstrap/input-groups";
-@import "bootstrap/navs";
-@import "bootstrap/navbar";
-@import "bootstrap/breadcrumbs";
-@import "bootstrap/pagination";
-@import "bootstrap/pager";
-@import "bootstrap/labels";
-@import "bootstrap/badges";
-@import "bootstrap/jumbotron";
-@import "bootstrap/thumbnails";
-@import "bootstrap/alerts";
-@import "bootstrap/progress-bars";
-@import "bootstrap/media";
-@import "bootstrap/list-group";
-@import "bootstrap/panels";
-@import "bootstrap/responsive-embed";
-@import "bootstrap/wells";
-@import "bootstrap/close";
-
-// Components w/ JavaScript
-@import "bootstrap/modals";
-@import "bootstrap/tooltip";
-@import "bootstrap/popovers";
-@import "bootstrap/carousel";
-
-// Utility classes
-@import "bootstrap/utilities";
-@import "bootstrap/responsive-utilities";
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_alerts.scss b/cove/cove_360/sass/bootstrap/bootstrap/_alerts.scss
deleted file mode 100644
index 7d1e1fd..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_alerts.scss
+++ /dev/null
@@ -1,73 +0,0 @@
-//
-// Alerts
-// --------------------------------------------------
-
-
-// Base styles
-// -------------------------
-
-.alert {
-  padding: $alert-padding;
-  margin-bottom: $line-height-computed;
-  border: 1px solid transparent;
-  border-radius: $alert-border-radius;
-
-  // Headings for larger alerts
-  h4 {
-    margin-top: 0;
-    // Specified for the h4 to prevent conflicts of changing $headings-color
-    color: inherit;
-  }
-
-  // Provide class for links that match alerts
-  .alert-link {
-    font-weight: $alert-link-font-weight;
-  }
-
-  // Improve alignment and spacing of inner content
-  > p,
-  > ul {
-    margin-bottom: 0;
-  }
-
-  > p + p {
-    margin-top: 5px;
-  }
-}
-
-// Dismissible alerts
-//
-// Expand the right padding and account for the close button's positioning.
-
-.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.
-.alert-dismissible {
-  padding-right: ($alert-padding + 20);
-
-  // Adjust close link position
-  .close {
-    position: relative;
-    top: -2px;
-    right: -21px;
-    color: inherit;
-  }
-}
-
-// Alternate styles
-//
-// Generate contextual modifier classes for colorizing the alert.
-
-.alert-success {
-  @include alert-variant($alert-success-bg, $alert-success-border, $alert-success-text);
-}
-
-.alert-info {
-  @include alert-variant($alert-info-bg, $alert-info-border, $alert-info-text);
-}
-
-.alert-warning {
-  @include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-text);
-}
-
-.alert-danger {
-  @include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-text);
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_badges.scss b/cove/cove_360/sass/bootstrap/bootstrap/_badges.scss
deleted file mode 100644
index 70002e0..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_badges.scss
+++ /dev/null
@@ -1,68 +0,0 @@
-//
-// Badges
-// --------------------------------------------------
-
-
-// Base class
-.badge {
-  display: inline-block;
-  min-width: 10px;
-  padding: 3px 7px;
-  font-size: $font-size-small;
-  font-weight: $badge-font-weight;
-  color: $badge-color;
-  line-height: $badge-line-height;
-  vertical-align: middle;
-  white-space: nowrap;
-  text-align: center;
-  background-color: $badge-bg;
-  border-radius: $badge-border-radius;
-
-  // Empty badges collapse automatically (not available in IE8)
-  &:empty {
-    display: none;
-  }
-
-  // Quick fix for badges in buttons
-  .btn & {
-    position: relative;
-    top: -1px;
-  }
-
-  .btn-xs &,
-  .btn-group-xs > .btn & {
-    top: 0;
-    padding: 1px 5px;
-  }
-
-  // [converter] extracted a& to a.badge
-
-  // Account for badges in navs
-  .list-group-item.active > &,
-  .nav-pills > .active > a > & {
-    color: $badge-active-color;
-    background-color: $badge-active-bg;
-  }
-
-  .list-group-item > & {
-    float: right;
-  }
-
-  .list-group-item > & + & {
-    margin-right: 5px;
-  }
-
-  .nav-pills > li > a > & {
-    margin-left: 3px;
-  }
-}
-
-// Hover state, but only for links
-a.badge {
-  &:hover,
-  &:focus {
-    color: $badge-link-hover-color;
-    text-decoration: none;
-    cursor: pointer;
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_breadcrumbs.scss b/cove/cove_360/sass/bootstrap/bootstrap/_breadcrumbs.scss
deleted file mode 100644
index b61f0c7..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_breadcrumbs.scss
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// Breadcrumbs
-// --------------------------------------------------
-
-
-.breadcrumb {
-  padding: $breadcrumb-padding-vertical $breadcrumb-padding-horizontal;
-  margin-bottom: $line-height-computed;
-  list-style: none;
-  background-color: $breadcrumb-bg;
-  border-radius: $border-radius-base;
-
-  > li {
-    display: inline-block;
-
-    + li:before {
-      // [converter] Workaround for https://github.com/sass/libsass/issues/1115
-      $nbsp: "\00a0";
-      content: "#{$breadcrumb-separator}#{$nbsp}"; // Unicode space added since inline-block means non-collapsing white-space
-      padding: 0 5px;
-      color: $breadcrumb-color;
-    }
-  }
-
-  > .active {
-    color: $breadcrumb-active-color;
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_button-groups.scss b/cove/cove_360/sass/bootstrap/bootstrap/_button-groups.scss
deleted file mode 100644
index 4b385f5..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_button-groups.scss
+++ /dev/null
@@ -1,244 +0,0 @@
-//
-// Button groups
-// --------------------------------------------------
-
-// Make the div behave like a button
-.btn-group,
-.btn-group-vertical {
-  position: relative;
-  display: inline-block;
-  vertical-align: middle; // match .btn alignment given font-size hack above
-  > .btn {
-    position: relative;
-    float: left;
-    // Bring the "active" button to the front
-    &:hover,
-    &:focus,
-    &:active,
-    &.active {
-      z-index: 2;
-    }
-  }
-}
-
-// Prevent double borders when buttons are next to each other
-.btn-group {
-  .btn + .btn,
-  .btn + .btn-group,
-  .btn-group + .btn,
-  .btn-group + .btn-group {
-    margin-left: -1px;
-  }
-}
-
-// Optional: Group multiple button groups together for a toolbar
-.btn-toolbar {
-  margin-left: -5px; // Offset the first child's margin
-  @include clearfix;
-
-  .btn,
-  .btn-group,
-  .input-group {
-    float: left;
-  }
-  > .btn,
-  > .btn-group,
-  > .input-group {
-    margin-left: 5px;
-  }
-}
-
-.btn-group > .btn:not(:first-child):not(:last-child):not(.dropdown-toggle) {
-  border-radius: 0;
-}
-
-// Set corners individual because sometimes a single button can be in a .btn-group and we need :first-child and :last-child to both match
-.btn-group > .btn:first-child {
-  margin-left: 0;
-  &:not(:last-child):not(.dropdown-toggle) {
-    @include border-right-radius(0);
-  }
-}
-// Need .dropdown-toggle since :last-child doesn't apply, given that a .dropdown-menu is used immediately after it
-.btn-group > .btn:last-child:not(:first-child),
-.btn-group > .dropdown-toggle:not(:first-child) {
-  @include border-left-radius(0);
-}
-
-// Custom edits for including btn-groups within btn-groups (useful for including dropdown buttons within a btn-group)
-.btn-group > .btn-group {
-  float: left;
-}
-.btn-group > .btn-group:not(:first-child):not(:last-child) > .btn {
-  border-radius: 0;
-}
-.btn-group > .btn-group:first-child:not(:last-child) {
-  > .btn:last-child,
-  > .dropdown-toggle {
-    @include border-right-radius(0);
-  }
-}
-.btn-group > .btn-group:last-child:not(:first-child) > .btn:first-child {
-  @include border-left-radius(0);
-}
-
-// On active and open, don't show outline
-.btn-group .dropdown-toggle:active,
-.btn-group.open .dropdown-toggle {
-  outline: 0;
-}
-
-
-// Sizing
-//
-// Remix the default button sizing classes into new ones for easier manipulation.
-
-.btn-group-xs > .btn { @extend .btn-xs; }
-.btn-group-sm > .btn { @extend .btn-sm; }
-.btn-group-lg > .btn { @extend .btn-lg; }
-
-
-// Split button dropdowns
-// ----------------------
-
-// Give the line between buttons some depth
-.btn-group > .btn + .dropdown-toggle {
-  padding-left: 8px;
-  padding-right: 8px;
-}
-.btn-group > .btn-lg + .dropdown-toggle {
-  padding-left: 12px;
-  padding-right: 12px;
-}
-
-// The clickable button for toggling the menu
-// Remove the gradient and set the same inset shadow as the :active state
-.btn-group.open .dropdown-toggle {
-  @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
-
-  // Show no shadow for `.btn-link` since it has no other button styles.
-  &.btn-link {
-    @include box-shadow(none);
-  }
-}
-
-
-// Reposition the caret
-.btn .caret {
-  margin-left: 0;
-}
-// Carets in other button sizes
-.btn-lg .caret {
-  border-width: $caret-width-large $caret-width-large 0;
-  border-bottom-width: 0;
-}
-// Upside down carets for .dropup
-.dropup .btn-lg .caret {
-  border-width: 0 $caret-width-large $caret-width-large;
-}
-
-
-// Vertical button groups
-// ----------------------
-
-.btn-group-vertical {
-  > .btn,
-  > .btn-group,
-  > .btn-group > .btn {
-    display: block;
-    float: none;
-    width: 100%;
-    max-width: 100%;
-  }
-
-  // Clear floats so dropdown menus can be properly placed
-  > .btn-group {
-    @include clearfix;
-    > .btn {
-      float: none;
-    }
-  }
-
-  > .btn + .btn,
-  > .btn + .btn-group,
-  > .btn-group + .btn,
-  > .btn-group + .btn-group {
-    margin-top: -1px;
-    margin-left: 0;
-  }
-}
-
-.btn-group-vertical > .btn {
-  &:not(:first-child):not(:last-child) {
-    border-radius: 0;
-  }
-  &:first-child:not(:last-child) {
-    @include border-top-radius($btn-border-radius-base);
-    @include border-bottom-radius(0);
-  }
-  &:last-child:not(:first-child) {
-    @include border-top-radius(0);
-    @include border-bottom-radius($btn-border-radius-base);
-  }
-}
-.btn-group-vertical > .btn-group:not(:first-child):not(:last-child) > .btn {
-  border-radius: 0;
-}
-.btn-group-vertical > .btn-group:first-child:not(:last-child) {
-  > .btn:last-child,
-  > .dropdown-toggle {
-    @include border-bottom-radius(0);
-  }
-}
-.btn-group-vertical > .btn-group:last-child:not(:first-child) > .btn:first-child {
-  @include border-top-radius(0);
-}
-
-
-// Justified button groups
-// ----------------------
-
-.btn-group-justified {
-  display: table;
-  width: 100%;
-  table-layout: fixed;
-  border-collapse: separate;
-  > .btn,
-  > .btn-group {
-    float: none;
-    display: table-cell;
-    width: 1%;
-  }
-  > .btn-group .btn {
-    width: 100%;
-  }
-
-  > .btn-group .dropdown-menu {
-    left: auto;
-  }
-}
-
-
-// Checkbox and radio options
-//
-// In order to support the browser's form validation feedback, powered by the
-// `required` attribute, we have to "hide" the inputs via `clip`. We cannot use
-// `display: none;` or `visibility: hidden;` as that also hides the popover.
-// Simply visually hiding the inputs via `opacity` would leave them clickable in
-// certain cases which is prevented by using `clip` and `pointer-events`.
-// This way, we ensure a DOM element is visible to position the popover from.
-//
-// See https://github.com/twbs/bootstrap/pull/12794 and
-// https://github.com/twbs/bootstrap/pull/14559 for more information.
-
-[data-toggle="buttons"] {
-  > .btn,
-  > .btn-group > .btn {
-    input[type="radio"],
-    input[type="checkbox"] {
-      position: absolute;
-      clip: rect(0,0,0,0);
-      pointer-events: none;
-    }
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_buttons.scss b/cove/cove_360/sass/bootstrap/bootstrap/_buttons.scss
deleted file mode 100644
index 6452b70..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_buttons.scss
+++ /dev/null
@@ -1,168 +0,0 @@
-//
-// Buttons
-// --------------------------------------------------
-
-
-// Base styles
-// --------------------------------------------------
-
-.btn {
-  display: inline-block;
-  margin-bottom: 0; // For input.btn
-  font-weight: $btn-font-weight;
-  text-align: center;
-  vertical-align: middle;
-  touch-action: manipulation;
-  cursor: pointer;
-  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
-  border: 1px solid transparent;
-  white-space: nowrap;
-  @include button-size($padding-base-vertical, $padding-base-horizontal, $font-size-base, $line-height-base, $btn-border-radius-base);
-  @include user-select(none);
-
-  &,
-  &:active,
-  &.active {
-    &:focus,
-    &.focus {
-      @include tab-focus;
-    }
-  }
-
-  &:hover,
-  &:focus,
-  &.focus {
-    color: $btn-default-color;
-    text-decoration: none;
-  }
-
-  &:active,
-  &.active {
-    outline: 0;
-    background-image: none;
-    @include box-shadow(inset 0 3px 5px rgba(0,0,0,.125));
-  }
-
-  &.disabled,
-  &[disabled],
-  fieldset[disabled] & {
-    cursor: $cursor-disabled;
-    @include opacity(.65);
-    @include box-shadow(none);
-  }
-
-  // [converter] extracted a& to a.btn
-}
-
-a.btn {
-  &.disabled,
-  fieldset[disabled] & {
-    pointer-events: none; // Future-proof disabling of clicks on `` elements
-  }
-}
-
-
-// Alternate buttons
-// --------------------------------------------------
-
-.btn-default {
-  @include button-variant($btn-default-color, $btn-default-bg, $btn-default-border);
-}
-.btn-primary {
-  @include button-variant($btn-primary-color, $btn-primary-bg, $btn-primary-border);
-}
-// Success appears as green
-.btn-success {
-  @include button-variant($btn-success-color, $btn-success-bg, $btn-success-border);
-}
-// Info appears as blue-green
-.btn-info {
-  @include button-variant($btn-info-color, $btn-info-bg, $btn-info-border);
-}
-// Warning appears as orange
-.btn-warning {
-  @include button-variant($btn-warning-color, $btn-warning-bg, $btn-warning-border);
-}
-// Danger and error appear as red
-.btn-danger {
-  @include button-variant($btn-danger-color, $btn-danger-bg, $btn-danger-border);
-}
-
-
-// Link buttons
-// -------------------------
-
-// Make a button look and behave like a link
-.btn-link {
-  color: $link-color;
-  font-weight: normal;
-  border-radius: 0;
-
-  &,
-  &:active,
-  &.active,
-  &[disabled],
-  fieldset[disabled] & {
-    background-color: transparent;
-    @include box-shadow(none);
-  }
-  &,
-  &:hover,
-  &:focus,
-  &:active {
-    border-color: transparent;
-  }
-  &:hover,
-  &:focus {
-    color: $link-hover-color;
-    text-decoration: $link-hover-decoration;
-    background-color: transparent;
-  }
-  &[disabled],
-  fieldset[disabled] & {
-    &:hover,
-    &:focus {
-      color: $btn-link-disabled-color;
-      text-decoration: none;
-    }
-  }
-}
-
-
-// Button Sizes
-// --------------------------------------------------
-
-.btn-lg {
-  // line-height: ensure even-numbered height of button next to large input
-  @include button-size($padding-large-vertical, $padding-large-horizontal, $font-size-large, $line-height-large, $btn-border-radius-large);
-}
-.btn-sm {
-  // line-height: ensure proper height of button next to small input
-  @include button-size($padding-small-vertical, $padding-small-horizontal, $font-size-small, $line-height-small, $btn-border-radius-small);
-}
-.btn-xs {
-  @include button-size($padding-xs-vertical, $padding-xs-horizontal, $font-size-small, $line-height-small, $btn-border-radius-small);
-}
-
-
-// Block button
-// --------------------------------------------------
-
-.btn-block {
-  display: block;
-  width: 100%;
-}
-
-// Vertically space out multiple block buttons
-.btn-block + .btn-block {
-  margin-top: 5px;
-}
-
-// Specificity overrides
-input[type="submit"],
-input[type="reset"],
-input[type="button"] {
-  &.btn-block {
-    width: 100%;
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_carousel.scss b/cove/cove_360/sass/bootstrap/bootstrap/_carousel.scss
deleted file mode 100644
index 753d881..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_carousel.scss
+++ /dev/null
@@ -1,270 +0,0 @@
-//
-// Carousel
-// --------------------------------------------------
-
-
-// Wrapper for the slide container and indicators
-.carousel {
-  position: relative;
-}
-
-.carousel-inner {
-  position: relative;
-  overflow: hidden;
-  width: 100%;
-
-  > .item {
-    display: none;
-    position: relative;
-    @include transition(.6s ease-in-out left);
-
-    // Account for jankitude on images
-    > img,
-    > a > img {
-      @include img-responsive;
-      line-height: 1;
-    }
-
-    // WebKit CSS3 transforms for supported devices
-    @media all and (transform-3d), (-webkit-transform-3d) {
-      @include transition-transform(0.6s ease-in-out);
-      @include backface-visibility(hidden);
-      @include perspective(1000px);
-
-      &.next,
-      &.active.right {
-        @include translate3d(100%, 0, 0);
-        left: 0;
-      }
-      &.prev,
-      &.active.left {
-        @include translate3d(-100%, 0, 0);
-        left: 0;
-      }
-      &.next.left,
-      &.prev.right,
-      &.active {
-        @include translate3d(0, 0, 0);
-        left: 0;
-      }
-    }
-  }
-
-  > .active,
-  > .next,
-  > .prev {
-    display: block;
-  }
-
-  > .active {
-    left: 0;
-  }
-
-  > .next,
-  > .prev {
-    position: absolute;
-    top: 0;
-    width: 100%;
-  }
-
-  > .next {
-    left: 100%;
-  }
-  > .prev {
-    left: -100%;
-  }
-  > .next.left,
-  > .prev.right {
-    left: 0;
-  }
-
-  > .active.left {
-    left: -100%;
-  }
-  > .active.right {
-    left: 100%;
-  }
-
-}
-
-// Left/right controls for nav
-// ---------------------------
-
-.carousel-control {
-  position: absolute;
-  top: 0;
-  left: 0;
-  bottom: 0;
-  width: $carousel-control-width;
-  @include opacity($carousel-control-opacity);
-  font-size: $carousel-control-font-size;
-  color: $carousel-control-color;
-  text-align: center;
-  text-shadow: $carousel-text-shadow;
-  background-color: rgba(0, 0, 0, 0); // Fix IE9 click-thru bug
-  // We can't have this transition here because WebKit cancels the carousel
-  // animation if you trip this while in the middle of another animation.
-
-  // Set gradients for backgrounds
-  &.left {
-    @include gradient-horizontal($start-color: rgba(0,0,0,.5), $end-color: rgba(0,0,0,.0001));
-  }
-  &.right {
-    left: auto;
-    right: 0;
-    @include gradient-horizontal($start-color: rgba(0,0,0,.0001), $end-color: rgba(0,0,0,.5));
-  }
-
-  // Hover/focus state
-  &:hover,
-  &:focus {
-    outline: 0;
-    color: $carousel-control-color;
-    text-decoration: none;
-    @include opacity(.9);
-  }
-
-  // Toggles
-  .icon-prev,
-  .icon-next,
-  .glyphicon-chevron-left,
-  .glyphicon-chevron-right {
-    position: absolute;
-    top: 50%;
-    margin-top: -10px;
-    z-index: 5;
-    display: inline-block;
-  }
-  .icon-prev,
-  .glyphicon-chevron-left {
-    left: 50%;
-    margin-left: -10px;
-  }
-  .icon-next,
-  .glyphicon-chevron-right {
-    right: 50%;
-    margin-right: -10px;
-  }
-  .icon-prev,
-  .icon-next {
-    width:  20px;
-    height: 20px;
-    line-height: 1;
-    font-family: serif;
-  }
-
-
-  .icon-prev {
-    &:before {
-      content: '\2039';// SINGLE LEFT-POINTING ANGLE QUOTATION MARK (U+2039)
-    }
-  }
-  .icon-next {
-    &:before {
-      content: '\203a';// SINGLE RIGHT-POINTING ANGLE QUOTATION MARK (U+203A)
-    }
-  }
-}
-
-// Optional indicator pips
-//
-// Add an unordered list with the following class and add a list item for each
-// slide your carousel holds.
-
-.carousel-indicators {
-  position: absolute;
-  bottom: 10px;
-  left: 50%;
-  z-index: 15;
-  width: 60%;
-  margin-left: -30%;
-  padding-left: 0;
-  list-style: none;
-  text-align: center;
-
-  li {
-    display: inline-block;
-    width:  10px;
-    height: 10px;
-    margin: 1px;
-    text-indent: -999px;
-    border: 1px solid $carousel-indicator-border-color;
-    border-radius: 10px;
-    cursor: pointer;
-
-    // IE8-9 hack for event handling
-    //
-    // Internet Explorer 8-9 does not support clicks on elements without a set
-    // `background-color`. We cannot use `filter` since that's not viewed as a
-    // background color by the browser. Thus, a hack is needed.
-    // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Internet_Explorer
-    //
-    // For IE8, we set solid black as it doesn't support `rgba()`. For IE9, we
-    // set alpha transparency for the best results possible.
-    background-color: #000 \9; // IE8
-    background-color: rgba(0,0,0,0); // IE9
-  }
-  .active {
-    margin: 0;
-    width:  12px;
-    height: 12px;
-    background-color: $carousel-indicator-active-bg;
-  }
-}
-
-// Optional captions
-// -----------------------------
-// Hidden by default for smaller viewports
-.carousel-caption {
-  position: absolute;
-  left: 15%;
-  right: 15%;
-  bottom: 20px;
-  z-index: 10;
-  padding-top: 20px;
-  padding-bottom: 20px;
-  color: $carousel-caption-color;
-  text-align: center;
-  text-shadow: $carousel-text-shadow;
-  & .btn {
-    text-shadow: none; // No shadow for button elements in carousel-caption
-  }
-}
-
-
-// Scale up controls for tablets and up
-@media screen and (min-width: $screen-sm-min) {
-
-  // Scale up the controls a smidge
-  .carousel-control {
-    .glyphicon-chevron-left,
-    .glyphicon-chevron-right,
-    .icon-prev,
-    .icon-next {
-      width: ($carousel-control-font-size * 1.5);
-      height: ($carousel-control-font-size * 1.5);
-      margin-top: ($carousel-control-font-size / -2);
-      font-size: ($carousel-control-font-size * 1.5);
-    }
-    .glyphicon-chevron-left,
-    .icon-prev {
-      margin-left: ($carousel-control-font-size / -2);
-    }
-    .glyphicon-chevron-right,
-    .icon-next {
-      margin-right: ($carousel-control-font-size / -2);
-    }
-  }
-
-  // Show and left align the captions
-  .carousel-caption {
-    left: 20%;
-    right: 20%;
-    padding-bottom: 30px;
-  }
-
-  // Move up the indicators
-  .carousel-indicators {
-    bottom: 20px;
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_close.scss b/cove/cove_360/sass/bootstrap/bootstrap/_close.scss
deleted file mode 100644
index 3b74d8a..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_close.scss
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// Close icons
-// --------------------------------------------------
-
-
-.close {
-  float: right;
-  font-size: ($font-size-base * 1.5);
-  font-weight: $close-font-weight;
-  line-height: 1;
-  color: $close-color;
-  text-shadow: $close-text-shadow;
-  @include opacity(.2);
-
-  &:hover,
-  &:focus {
-    color: $close-color;
-    text-decoration: none;
-    cursor: pointer;
-    @include opacity(.5);
-  }
-
-  // [converter] extracted button& to button.close
-}
-
-// Additional properties for button version
-// iOS requires the button element instead of an anchor tag.
-// If you want the anchor version, it requires `href="#"`.
-// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
-button.close {
-  padding: 0;
-  cursor: pointer;
-  background: transparent;
-  border: 0;
-  -webkit-appearance: none;
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_code.scss b/cove/cove_360/sass/bootstrap/bootstrap/_code.scss
deleted file mode 100644
index caa5f06..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_code.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// Code (inline and block)
-// --------------------------------------------------
-
-
-// Inline and block code styles
-code,
-kbd,
-pre,
-samp {
-  font-family: $font-family-monospace;
-}
-
-// Inline code
-code {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: $code-color;
-  background-color: $code-bg;
-  border-radius: $border-radius-base;
-}
-
-// User input typically entered via keyboard
-kbd {
-  padding: 2px 4px;
-  font-size: 90%;
-  color: $kbd-color;
-  background-color: $kbd-bg;
-  border-radius: $border-radius-small;
-  box-shadow: inset 0 -1px 0 rgba(0,0,0,.25);
-
-  kbd {
-    padding: 0;
-    font-size: 100%;
-    font-weight: bold;
-    box-shadow: none;
-  }
-}
-
-// Blocks of code
-pre {
-  display: block;
-  padding: (($line-height-computed - 1) / 2);
-  margin: 0 0 ($line-height-computed / 2);
-  font-size: ($font-size-base - 1); // 14px to 13px
-  line-height: $line-height-base;
-  word-break: break-all;
-  word-wrap: break-word;
-  color: $pre-color;
-  background-color: $pre-bg;
-  border: 1px solid $pre-border-color;
-  border-radius: $border-radius-base;
-
-  // Account for some code outputs that place code tags in pre tags
-  code {
-    padding: 0;
-    font-size: inherit;
-    color: inherit;
-    white-space: pre-wrap;
-    background-color: transparent;
-    border-radius: 0;
-  }
-}
-
-// Enable scrollable blocks of code
-.pre-scrollable {
-  max-height: $pre-scrollable-max-height;
-  overflow-y: scroll;
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_component-animations.scss b/cove/cove_360/sass/bootstrap/bootstrap/_component-animations.scss
deleted file mode 100644
index ca3b43c..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_component-animations.scss
+++ /dev/null
@@ -1,37 +0,0 @@
-//
-// Component animations
-// --------------------------------------------------
-
-// Heads up!
-//
-// We don't use the `.opacity()` mixin here since it causes a bug with text
-// fields in IE7-8. Source: https://github.com/twbs/bootstrap/pull/3552.
-
-.fade {
-  opacity: 0;
-  @include transition(opacity .15s linear);
-  &.in {
-    opacity: 1;
-  }
-}
-
-.collapse {
-  display: none;
-
-  &.in      { display: block; }
-  // [converter] extracted tr&.in to tr.collapse.in
-  // [converter] extracted tbody&.in to tbody.collapse.in
-}
-
-tr.collapse.in    { display: table-row; }
-
-tbody.collapse.in { display: table-row-group; }
-
-.collapsing {
-  position: relative;
-  height: 0;
-  overflow: hidden;
-  @include transition-property(height, visibility);
-  @include transition-duration(.35s);
-  @include transition-timing-function(ease);
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_dropdowns.scss b/cove/cove_360/sass/bootstrap/bootstrap/_dropdowns.scss
deleted file mode 100644
index aac8459..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_dropdowns.scss
+++ /dev/null
@@ -1,216 +0,0 @@
-//
-// Dropdown menus
-// --------------------------------------------------
-
-
-// Dropdown arrow/caret
-.caret {
-  display: inline-block;
-  width: 0;
-  height: 0;
-  margin-left: 2px;
-  vertical-align: middle;
-  border-top:   $caret-width-base dashed;
-  border-top:   $caret-width-base solid \9; // IE8
-  border-right: $caret-width-base solid transparent;
-  border-left:  $caret-width-base solid transparent;
-}
-
-// The dropdown wrapper (div)
-.dropup,
-.dropdown {
-  position: relative;
-}
-
-// Prevent the focus on the dropdown toggle when closing dropdowns
-.dropdown-toggle:focus {
-  outline: 0;
-}
-
-// The dropdown menu (ul)
-.dropdown-menu {
-  position: absolute;
-  top: 100%;
-  left: 0;
-  z-index: $zindex-dropdown;
-  display: none; // none by default, but block on "open" of the menu
-  float: left;
-  min-width: 160px;
-  padding: 5px 0;
-  margin: 2px 0 0; // override default ul
-  list-style: none;
-  font-size: $font-size-base;
-  text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer)
-  background-color: $dropdown-bg;
-  border: 1px solid $dropdown-fallback-border; // IE8 fallback
-  border: 1px solid $dropdown-border;
-  border-radius: $border-radius-base;
-  @include box-shadow(0 6px 12px rgba(0,0,0,.175));
-  background-clip: padding-box;
-
-  // Aligns the dropdown menu to right
-  //
-  // Deprecated as of 3.1.0 in favor of `.dropdown-menu-[dir]`
-  &.pull-right {
-    right: 0;
-    left: auto;
-  }
-
-  // Dividers (basically an hr) within the dropdown
-  .divider {
-    @include nav-divider($dropdown-divider-bg);
-  }
-
-  // Links within the dropdown menu
-  > li > a {
-    display: block;
-    padding: 3px 20px;
-    clear: both;
-    font-weight: normal;
-    line-height: $line-height-base;
-    color: $dropdown-link-color;
-    white-space: nowrap; // prevent links from randomly breaking onto new lines
-  }
-}
-
-// Hover/Focus state
-.dropdown-menu > li > a {
-  &:hover,
-  &:focus {
-    text-decoration: none;
-    color: $dropdown-link-hover-color;
-    background-color: $dropdown-link-hover-bg;
-  }
-}
-
-// Active state
-.dropdown-menu > .active > a {
-  &,
-  &:hover,
-  &:focus {
-    color: $dropdown-link-active-color;
-    text-decoration: none;
-    outline: 0;
-    background-color: $dropdown-link-active-bg;
-  }
-}
-
-// Disabled state
-//
-// Gray out text and ensure the hover/focus state remains gray
-
-.dropdown-menu > .disabled > a {
-  &,
-  &:hover,
-  &:focus {
-    color: $dropdown-link-disabled-color;
-  }
-
-  // Nuke hover/focus effects
-  &:hover,
-  &:focus {
-    text-decoration: none;
-    background-color: transparent;
-    background-image: none; // Remove CSS gradient
-    @include reset-filter;
-    cursor: $cursor-disabled;
-  }
-}
-
-// Open state for the dropdown
-.open {
-  // Show the menu
-  > .dropdown-menu {
-    display: block;
-  }
-
-  // Remove the outline when :focus is triggered
-  > a {
-    outline: 0;
-  }
-}
-
-// Menu positioning
-//
-// Add extra class to `.dropdown-menu` to flip the alignment of the dropdown
-// menu with the parent.
-.dropdown-menu-right {
-  left: auto; // Reset the default from `.dropdown-menu`
-  right: 0;
-}
-// With v3, we enabled auto-flipping if you have a dropdown within a right
-// aligned nav component. To enable the undoing of that, we provide an override
-// to restore the default dropdown menu alignment.
-//
-// This is only for left-aligning a dropdown menu within a `.navbar-right` or
-// `.pull-right` nav component.
-.dropdown-menu-left {
-  left: 0;
-  right: auto;
-}
-
-// Dropdown section headers
-.dropdown-header {
-  display: block;
-  padding: 3px 20px;
-  font-size: $font-size-small;
-  line-height: $line-height-base;
-  color: $dropdown-header-color;
-  white-space: nowrap; // as with > li > a
-}
-
-// Backdrop to catch body clicks on mobile, etc.
-.dropdown-backdrop {
-  position: fixed;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  top: 0;
-  z-index: ($zindex-dropdown - 10);
-}
-
-// Right aligned dropdowns
-.pull-right > .dropdown-menu {
-  right: 0;
-  left: auto;
-}
-
-// Allow for dropdowns to go bottom up (aka, dropup-menu)
-//
-// Just add .dropup after the standard .dropdown class and you're set, bro.
-// TODO: abstract this so that the navbar fixed styles are not placed here?
-
-.dropup,
-.navbar-fixed-bottom .dropdown {
-  // Reverse the caret
-  .caret {
-    border-top: 0;
-    border-bottom: $caret-width-base dashed;
-    border-bottom: $caret-width-base solid \9; // IE8
-    content: "";
-  }
-  // Different positioning for bottom up menu
-  .dropdown-menu {
-    top: auto;
-    bottom: 100%;
-    margin-bottom: 2px;
-  }
-}
-
-
-// Component alignment
-//
-// Reiterate per navbar.less and the modified component alignment there.
-
-@media (min-width: $grid-float-breakpoint) {
-  .navbar-right {
-    .dropdown-menu {
-      right: 0; left: auto;
-    }
-    // Necessary for overrides of the default right aligned menu.
-    // Will remove come v4 in all likelihood.
-    .dropdown-menu-left {
-      left: 0; right: auto;
-    }
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_forms.scss b/cove/cove_360/sass/bootstrap/bootstrap/_forms.scss
deleted file mode 100644
index ac26a6a..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_forms.scss
+++ /dev/null
@@ -1,617 +0,0 @@
-//
-// Forms
-// --------------------------------------------------
-
-
-// Normalize non-controls
-//
-// Restyle and baseline non-control form elements.
-
-fieldset {
-  padding: 0;
-  margin: 0;
-  border: 0;
-  // Chrome and Firefox set a `min-width: min-content;` on fieldsets,
-  // so we reset that to ensure it behaves more like a standard block element.
-  // See https://github.com/twbs/bootstrap/issues/12359.
-  min-width: 0;
-}
-
-legend {
-  display: block;
-  width: 100%;
-  padding: 0;
-  margin-bottom: $line-height-computed;
-  font-size: ($font-size-base * 1.5);
-  line-height: inherit;
-  color: $legend-color;
-  border: 0;
-  border-bottom: 1px solid $legend-border-color;
-}
-
-label {
-  display: inline-block;
-  max-width: 100%; // Force IE8 to wrap long content (see https://github.com/twbs/bootstrap/issues/13141)
-  margin-bottom: 5px;
-  font-weight: bold;
-}
-
-
-// Normalize form controls
-//
-// While most of our form styles require extra classes, some basic normalization
-// is required to ensure optimum display with or without those classes to better
-// address browser inconsistencies.
-
-// Override content-box in Normalize (* isn't specific enough)
-input[type="search"] {
-  @include box-sizing(border-box);
-}
-
-// Position radios and checkboxes better
-input[type="radio"],
-input[type="checkbox"] {
-  margin: 4px 0 0;
-  margin-top: 1px \9; // IE8-9
-  line-height: normal;
-}
-
-input[type="file"] {
-  display: block;
-}
-
-// Make range inputs behave like textual form controls
-input[type="range"] {
-  display: block;
-  width: 100%;
-}
-
-// Make multiple select elements height not fixed
-select[multiple],
-select[size] {
-  height: auto;
-}
-
-// Focus for file, radio, and checkbox
-input[type="file"]:focus,
-input[type="radio"]:focus,
-input[type="checkbox"]:focus {
-  @include tab-focus;
-}
-
-// Adjust output element
-output {
-  display: block;
-  padding-top: ($padding-base-vertical + 1);
-  font-size: $font-size-base;
-  line-height: $line-height-base;
-  color: $input-color;
-}
-
-
-// Common form controls
-//
-// Shared size and type resets for form controls. Apply `.form-control` to any
-// of the following form controls:
-//
-// select
-// textarea
-// input[type="text"]
-// input[type="password"]
-// input[type="datetime"]
-// input[type="datetime-local"]
-// input[type="date"]
-// input[type="month"]
-// input[type="time"]
-// input[type="week"]
-// input[type="number"]
-// input[type="email"]
-// input[type="url"]
-// input[type="search"]
-// input[type="tel"]
-// input[type="color"]
-
-.form-control {
-  display: block;
-  width: 100%;
-  height: $input-height-base; // Make inputs at least the height of their button counterpart (base line-height + padding + border)
-  padding: $padding-base-vertical $padding-base-horizontal;
-  font-size: $font-size-base;
-  line-height: $line-height-base;
-  color: $input-color;
-  background-color: $input-bg;
-  background-image: none; // Reset unusual Firefox-on-Android default style; see https://github.com/necolas/normalize.css/issues/214
-  border: 1px solid $input-border;
-  border-radius: $input-border-radius; // Note: This has no effect on s in CSS.
-  @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075));
-  @include transition(border-color ease-in-out .15s, box-shadow ease-in-out .15s);
-
-  // Customize the `:focus` state to imitate native WebKit styles.
-  @include form-control-focus;
-
-  // Placeholder
-  @include placeholder;
-
-  // Unstyle the caret on `` background color
-$input-bg:                       #fff !default;
-//** `` background color
-$input-bg-disabled:              $gray-lighter !default;
-
-//** Text color for ``s
-$input-color:                    $gray !default;
-//** `` border color
-$input-border:                   #ccc !default;
-
-// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
-//** Default `.form-control` border radius
-// This has no effect on ``s in CSS.
-$input-border-radius:            $border-radius-base !default;
-//** Large `.form-control` border radius
-$input-border-radius-large:      $border-radius-large !default;
-//** Small `.form-control` border radius
-$input-border-radius-small:      $border-radius-small !default;
-
-//** Border color for inputs on focus
-$input-border-focus:             #66afe9 !default;
-
-//** Placeholder text color
-$input-color-placeholder:        #999 !default;
-
-//** Default `.form-control` height
-$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2) !default;
-//** Large `.form-control` height
-$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2) !default;
-//** Small `.form-control` height
-$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2) !default;
-
-//** `.form-group` margin
-$form-group-margin-bottom:       15px !default;
-
-$legend-color:                   $gray-dark !default;
-$legend-border-color:            #e5e5e5 !default;
-
-//** Background color for textual input addons
-$input-group-addon-bg:           $gray-lighter !default;
-//** Border color for textual input addons
-$input-group-addon-border-color: $input-border !default;
-
-//** Disabled cursor for form controls and buttons.
-$cursor-disabled:                not-allowed !default;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-$dropdown-bg:                    #fff !default;
-//** Dropdown menu `border-color`.
-$dropdown-border:                rgba(0,0,0,.15) !default;
-//** Dropdown menu `border-color` **for IE8**.
-$dropdown-fallback-border:       #ccc !default;
-//** Divider color for between dropdown items.
-$dropdown-divider-bg:            #e5e5e5 !default;
-
-//** Dropdown link text color.
-$dropdown-link-color:            $gray-dark !default;
-//** Hover color for dropdown links.
-$dropdown-link-hover-color:      darken($gray-dark, 5%) !default;
-//** Hover background for dropdown links.
-$dropdown-link-hover-bg:         #f5f5f5 !default;
-
-//** Active dropdown menu item text color.
-$dropdown-link-active-color:     $component-active-color !default;
-//** Active dropdown menu item background color.
-$dropdown-link-active-bg:        $component-active-bg !default;
-
-//** Disabled dropdown menu item background color.
-$dropdown-link-disabled-color:   $gray-light !default;
-
-//** Text color for headers within dropdown menus.
-$dropdown-header-color:          $gray-light !default;
-
-//** Deprecated `$dropdown-caret-color` as of v3.1.0
-$dropdown-caret-color:           #000 !default;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-$zindex-navbar:            1000 !default;
-$zindex-dropdown:          1000 !default;
-$zindex-popover:           1060 !default;
-$zindex-tooltip:           1070 !default;
-$zindex-navbar-fixed:      1030 !default;
-$zindex-modal-background:  1040 !default;
-$zindex-modal:             1050 !default;
-
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
-
-// Extra small screen / phone
-//** Deprecated `$screen-xs` as of v3.0.1
-$screen-xs:                  480px !default;
-//** Deprecated `$screen-xs-min` as of v3.2.0
-$screen-xs-min:              $screen-xs !default;
-//** Deprecated `$screen-phone` as of v3.0.1
-$screen-phone:               $screen-xs-min !default;
-
-// Small screen / tablet
-//** Deprecated `$screen-sm` as of v3.0.1
-$screen-sm:                  768px !default;
-$screen-sm-min:              $screen-sm !default;
-//** Deprecated `$screen-tablet` as of v3.0.1
-$screen-tablet:              $screen-sm-min !default;
-
-// Medium screen / desktop
-//** Deprecated `$screen-md` as of v3.0.1
-$screen-md:                  992px !default;
-$screen-md-min:              $screen-md !default;
-//** Deprecated `$screen-desktop` as of v3.0.1
-$screen-desktop:             $screen-md-min !default;
-
-// Large screen / wide desktop
-//** Deprecated `$screen-lg` as of v3.0.1
-$screen-lg:                  1200px !default;
-$screen-lg-min:              $screen-lg !default;
-//** Deprecated `$screen-lg-desktop` as of v3.0.1
-$screen-lg-desktop:          $screen-lg-min !default;
-
-// So media queries don't overlap when required, provide a maximum
-$screen-xs-max:              ($screen-sm-min - 1) !default;
-$screen-sm-max:              ($screen-md-min - 1) !default;
-$screen-md-max:              ($screen-lg-min - 1) !default;
-
-
-//== Grid system
-//
-//## Define your custom responsive grid.
-
-//** Number of columns in the grid.
-$grid-columns:              12 !default;
-//** Padding between columns. Gets divided in half for the left and right.
-$grid-gutter-width:         30px !default;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-$grid-float-breakpoint:     $screen-sm-min !default;
-//** Point at which the navbar begins collapsing.
-$grid-float-breakpoint-max: ($grid-float-breakpoint - 1) !default;
-
-
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-$container-tablet:             (720px + $grid-gutter-width) !default;
-//** For `$screen-sm-min` and up.
-$container-sm:                 $container-tablet !default;
-
-// Medium screen / desktop
-$container-desktop:            (940px + $grid-gutter-width) !default;
-//** For `$screen-md-min` and up.
-$container-md:                 $container-desktop !default;
-
-// Large screen / wide desktop
-$container-large-desktop:      (1140px + $grid-gutter-width) !default;
-//** For `$screen-lg-min` and up.
-$container-lg:                 $container-large-desktop !default;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-$navbar-height:                    50px !default;
-$navbar-margin-bottom:             $line-height-computed !default;
-$navbar-border-radius:             $border-radius-base !default;
-$navbar-padding-horizontal:        floor(($grid-gutter-width / 2)) !default;
-$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2) !default;
-$navbar-collapse-max-height:       340px !default;
-
-$navbar-default-color:             #777 !default;
-$navbar-default-bg:                #f8f8f8 !default;
-$navbar-default-border:            darken($navbar-default-bg, 6.5%) !default;
-
-// Navbar links
-$navbar-default-link-color:                #777 !default;
-$navbar-default-link-hover-color:          #333 !default;
-$navbar-default-link-hover-bg:             transparent !default;
-$navbar-default-link-active-color:         #555 !default;
-$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%) !default;
-$navbar-default-link-disabled-color:       #ccc !default;
-$navbar-default-link-disabled-bg:          transparent !default;
-
-// Navbar brand label
-$navbar-default-brand-color:               $navbar-default-link-color !default;
-$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%) !default;
-$navbar-default-brand-hover-bg:            transparent !default;
-
-// Navbar toggle
-$navbar-default-toggle-hover-bg:           #ddd !default;
-$navbar-default-toggle-icon-bar-bg:        #888 !default;
-$navbar-default-toggle-border-color:       #ddd !default;
-
-
-//=== Inverted navbar
-// Reset inverted navbar basics
-$navbar-inverse-color:                      lighten($gray-light, 15%) !default;
-$navbar-inverse-bg:                         #222 !default;
-$navbar-inverse-border:                     darken($navbar-inverse-bg, 10%) !default;
-
-// Inverted navbar links
-$navbar-inverse-link-color:                 lighten($gray-light, 15%) !default;
-$navbar-inverse-link-hover-color:           #fff !default;
-$navbar-inverse-link-hover-bg:              transparent !default;
-$navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color !default;
-$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%) !default;
-$navbar-inverse-link-disabled-color:        #444 !default;
-$navbar-inverse-link-disabled-bg:           transparent !default;
-
-// Inverted navbar brand label
-$navbar-inverse-brand-color:                $navbar-inverse-link-color !default;
-$navbar-inverse-brand-hover-color:          #fff !default;
-$navbar-inverse-brand-hover-bg:             transparent !default;
-
-// Inverted navbar toggle
-$navbar-inverse-toggle-hover-bg:            #333 !default;
-$navbar-inverse-toggle-icon-bar-bg:         #fff !default;
-$navbar-inverse-toggle-border-color:        #333 !default;
-
-
-//== Navs
-//
-//##
-
-//=== Shared nav styles
-$nav-link-padding:                          10px 15px !default;
-$nav-link-hover-bg:                         $gray-lighter !default;
-
-$nav-disabled-link-color:                   $gray-light !default;
-$nav-disabled-link-hover-color:             $gray-light !default;
-
-//== Tabs
-$nav-tabs-border-color:                     #ddd !default;
-
-$nav-tabs-link-hover-border-color:          $gray-lighter !default;
-
-$nav-tabs-active-link-hover-bg:             $body-bg !default;
-$nav-tabs-active-link-hover-color:          $gray !default;
-$nav-tabs-active-link-hover-border-color:   #ddd !default;
-
-$nav-tabs-justified-link-border-color:            #ddd !default;
-$nav-tabs-justified-active-link-border-color:     $body-bg !default;
-
-//== Pills
-$nav-pills-border-radius:                   $border-radius-base !default;
-$nav-pills-active-link-hover-bg:            $component-active-bg !default;
-$nav-pills-active-link-hover-color:         $component-active-color !default;
-
-
-//== Pagination
-//
-//##
-
-$pagination-color:                     $link-color !default;
-$pagination-bg:                        #fff !default;
-$pagination-border:                    #ddd !default;
-
-$pagination-hover-color:               $link-hover-color !default;
-$pagination-hover-bg:                  $gray-lighter !default;
-$pagination-hover-border:              #ddd !default;
-
-$pagination-active-color:              #fff !default;
-$pagination-active-bg:                 $brand-primary !default;
-$pagination-active-border:             $brand-primary !default;
-
-$pagination-disabled-color:            $gray-light !default;
-$pagination-disabled-bg:               #fff !default;
-$pagination-disabled-border:           #ddd !default;
-
-
-//== Pager
-//
-//##
-
-$pager-bg:                             $pagination-bg !default;
-$pager-border:                         $pagination-border !default;
-$pager-border-radius:                  15px !default;
-
-$pager-hover-bg:                       $pagination-hover-bg !default;
-
-$pager-active-bg:                      $pagination-active-bg !default;
-$pager-active-color:                   $pagination-active-color !default;
-
-$pager-disabled-color:                 $pagination-disabled-color !default;
-
-
-//== Jumbotron
-//
-//##
-
-$jumbotron-padding:              30px !default;
-$jumbotron-color:                inherit !default;
-$jumbotron-bg:                   $gray-lighter !default;
-$jumbotron-heading-color:        inherit !default;
-$jumbotron-font-size:            ceil(($font-size-base * 1.5)) !default;
-$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5)) !default;
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-$state-success-text:             #3c763d !default;
-$state-success-bg:               #dff0d8 !default;
-$state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%) !default;
-
-$state-info-text:                #31708f !default;
-$state-info-bg:                  #d9edf7 !default;
-$state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%) !default;
-
-$state-warning-text:             #8a6d3b !default;
-$state-warning-bg:               #fcf8e3 !default;
-$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%) !default;
-
-$state-danger-text:              #a94442 !default;
-$state-danger-bg:                #f2dede !default;
-$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%) !default;
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
-$tooltip-max-width:           200px !default;
-//** Tooltip text color
-$tooltip-color:               #fff !default;
-//** Tooltip background color
-$tooltip-bg:                  #000 !default;
-$tooltip-opacity:             .9 !default;
-
-//** Tooltip arrow width
-$tooltip-arrow-width:         5px !default;
-//** Tooltip arrow color
-$tooltip-arrow-color:         $tooltip-bg !default;
-
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-$popover-bg:                          #fff !default;
-//** Popover maximum width
-$popover-max-width:                   276px !default;
-//** Popover border color
-$popover-border-color:                rgba(0,0,0,.2) !default;
-//** Popover fallback border color
-$popover-fallback-border-color:       #ccc !default;
-
-//** Popover title background color
-$popover-title-bg:                    darken($popover-bg, 3%) !default;
-
-//** Popover arrow width
-$popover-arrow-width:                 10px !default;
-//** Popover arrow color
-$popover-arrow-color:                 $popover-bg !default;
-
-//** Popover outer arrow width
-$popover-arrow-outer-width:           ($popover-arrow-width + 1) !default;
-//** Popover outer arrow color
-$popover-arrow-outer-color:           fade_in($popover-border-color, 0.05) !default;
-//** Popover outer arrow fallback color
-$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 20%) !default;
-
-
-//== Labels
-//
-//##
-
-//** Default label background color
-$label-default-bg:            $gray-light !default;
-//** Primary label background color
-$label-primary-bg:            $brand-primary !default;
-//** Success label background color
-$label-success-bg:            $brand-success !default;
-//** Info label background color
-$label-info-bg:               $brand-info !default;
-//** Warning label background color
-$label-warning-bg:            $brand-warning !default;
-//** Danger label background color
-$label-danger-bg:             $brand-danger !default;
-
-//** Default label text color
-$label-color:                 #fff !default;
-//** Default text color of a linked label
-$label-link-hover-color:      #fff !default;
-
-
-//== Modals
-//
-//##
-
-//** Padding applied to the modal body
-$modal-inner-padding:         15px !default;
-
-//** Padding applied to the modal title
-$modal-title-padding:         15px !default;
-//** Modal title line-height
-$modal-title-line-height:     $line-height-base !default;
-
-//** Background color of modal content area
-$modal-content-bg:                             #fff !default;
-//** Modal content border color
-$modal-content-border-color:                   rgba(0,0,0,.2) !default;
-//** Modal content border color **for IE8**
-$modal-content-fallback-border-color:          #999 !default;
-
-//** Modal backdrop background color
-$modal-backdrop-bg:           #000 !default;
-//** Modal backdrop opacity
-$modal-backdrop-opacity:      .5 !default;
-//** Modal header border color
-$modal-header-border-color:   #e5e5e5 !default;
-//** Modal footer border color
-$modal-footer-border-color:   $modal-header-border-color !default;
-
-$modal-lg:                    900px !default;
-$modal-md:                    600px !default;
-$modal-sm:                    300px !default;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
-
-$alert-padding:               15px !default;
-$alert-border-radius:         $border-radius-base !default;
-$alert-link-font-weight:      bold !default;
-
-$alert-success-bg:            $state-success-bg !default;
-$alert-success-text:          $state-success-text !default;
-$alert-success-border:        $state-success-border !default;
-
-$alert-info-bg:               $state-info-bg !default;
-$alert-info-text:             $state-info-text !default;
-$alert-info-border:           $state-info-border !default;
-
-$alert-warning-bg:            $state-warning-bg !default;
-$alert-warning-text:          $state-warning-text !default;
-$alert-warning-border:        $state-warning-border !default;
-
-$alert-danger-bg:             $state-danger-bg !default;
-$alert-danger-text:           $state-danger-text !default;
-$alert-danger-border:         $state-danger-border !default;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-$progress-bg:                 #f5f5f5 !default;
-//** Progress bar text color
-$progress-bar-color:          #fff !default;
-//** Variable for setting rounded corners on progress bar.
-$progress-border-radius:      $border-radius-base !default;
-
-//** Default progress bar color
-$progress-bar-bg:             $brand-primary !default;
-//** Success progress bar color
-$progress-bar-success-bg:     $brand-success !default;
-//** Warning progress bar color
-$progress-bar-warning-bg:     $brand-warning !default;
-//** Danger progress bar color
-$progress-bar-danger-bg:      $brand-danger !default;
-//** Info progress bar color
-$progress-bar-info-bg:        $brand-info !default;
-
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-$list-group-bg:                 #fff !default;
-//** `.list-group-item` border color
-$list-group-border:             #ddd !default;
-//** List group border radius
-$list-group-border-radius:      $border-radius-base !default;
-
-//** Background color of single list items on hover
-$list-group-hover-bg:           #f5f5f5 !default;
-//** Text color of active list items
-$list-group-active-color:       $component-active-color !default;
-//** Background color of active list items
-$list-group-active-bg:          $component-active-bg !default;
-//** Border color of active list elements
-$list-group-active-border:      $list-group-active-bg !default;
-//** Text color for content within active list items
-$list-group-active-text-color:  lighten($list-group-active-bg, 40%) !default;
-
-//** Text color of disabled list items
-$list-group-disabled-color:      $gray-light !default;
-//** Background color of disabled list items
-$list-group-disabled-bg:         $gray-lighter !default;
-//** Text color for content within disabled list items
-$list-group-disabled-text-color: $list-group-disabled-color !default;
-
-$list-group-link-color:         #555 !default;
-$list-group-link-hover-color:   $list-group-link-color !default;
-$list-group-link-heading-color: #333 !default;
-
-
-//== Panels
-//
-//##
-
-$panel-bg:                    #fff !default;
-$panel-body-padding:          15px !default;
-$panel-heading-padding:       10px 15px !default;
-$panel-footer-padding:        $panel-heading-padding !default;
-$panel-border-radius:         $border-radius-base !default;
-
-//** Border color for elements within panels
-$panel-inner-border:          #ddd !default;
-$panel-footer-bg:             #f5f5f5 !default;
-
-$panel-default-text:          $gray-dark !default;
-$panel-default-border:        #ddd !default;
-$panel-default-heading-bg:    #f5f5f5 !default;
-
-$panel-primary-text:          #fff !default;
-$panel-primary-border:        $brand-primary !default;
-$panel-primary-heading-bg:    $brand-primary !default;
-
-$panel-success-text:          $state-success-text !default;
-$panel-success-border:        $state-success-border !default;
-$panel-success-heading-bg:    $state-success-bg !default;
-
-$panel-info-text:             $state-info-text !default;
-$panel-info-border:           $state-info-border !default;
-$panel-info-heading-bg:       $state-info-bg !default;
-
-$panel-warning-text:          $state-warning-text !default;
-$panel-warning-border:        $state-warning-border !default;
-$panel-warning-heading-bg:    $state-warning-bg !default;
-
-$panel-danger-text:           $state-danger-text !default;
-$panel-danger-border:         $state-danger-border !default;
-$panel-danger-heading-bg:     $state-danger-bg !default;
-
-
-//== Thumbnails
-//
-//##
-
-//** Padding around the thumbnail image
-$thumbnail-padding:           4px !default;
-//** Thumbnail background color
-$thumbnail-bg:                $body-bg !default;
-//** Thumbnail border color
-$thumbnail-border:            #ddd !default;
-//** Thumbnail border radius
-$thumbnail-border-radius:     $border-radius-base !default;
-
-//** Custom text color for thumbnail captions
-$thumbnail-caption-color:     $text-color !default;
-//** Padding around the thumbnail caption
-$thumbnail-caption-padding:   9px !default;
-
-
-//== Wells
-//
-//##
-
-$well-bg:                     #f5f5f5 !default;
-$well-border:                 darken($well-bg, 7%) !default;
-
-
-//== Badges
-//
-//##
-
-$badge-color:                 #fff !default;
-//** Linked badge text color on hover
-$badge-link-hover-color:      #fff !default;
-$badge-bg:                    $gray-light !default;
-
-//** Badge text color in active nav link
-$badge-active-color:          $link-color !default;
-//** Badge background color in active nav link
-$badge-active-bg:             #fff !default;
-
-$badge-font-weight:           bold !default;
-$badge-line-height:           1 !default;
-$badge-border-radius:         10px !default;
-
-
-//== Breadcrumbs
-//
-//##
-
-$breadcrumb-padding-vertical:   8px !default;
-$breadcrumb-padding-horizontal: 15px !default;
-//** Breadcrumb background color
-$breadcrumb-bg:                 #f5f5f5 !default;
-//** Breadcrumb text color
-$breadcrumb-color:              #ccc !default;
-//** Text color of current page in the breadcrumb
-$breadcrumb-active-color:       $gray-light !default;
-//** Textual separator for between breadcrumb elements
-$breadcrumb-separator:          "/" !default;
-
-
-//== Carousel
-//
-//##
-
-$carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6) !default;
-
-$carousel-control-color:                      #fff !default;
-$carousel-control-width:                      15% !default;
-$carousel-control-opacity:                    .5 !default;
-$carousel-control-font-size:                  20px !default;
-
-$carousel-indicator-active-bg:                #fff !default;
-$carousel-indicator-border-color:             #fff !default;
-
-$carousel-caption-color:                      #fff !default;
-
-
-//== Close
-//
-//##
-
-$close-font-weight:           bold !default;
-$close-color:                 #000 !default;
-$close-text-shadow:           0 1px 0 #fff !default;
-
-
-//== Code
-//
-//##
-
-$code-color:                  #c7254e !default;
-$code-bg:                     #f9f2f4 !default;
-
-$kbd-color:                   #fff !default;
-$kbd-bg:                      #333 !default;
-
-$pre-bg:                      #f5f5f5 !default;
-$pre-color:                   $gray-dark !default;
-$pre-border-color:            #ccc !default;
-$pre-scrollable-max-height:   340px !default;
-
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-$component-offset-horizontal: 180px !default;
-//** Text muted color
-$text-muted:                  $gray-light !default;
-//** Abbreviations and acronyms border color
-$abbr-border-color:           $gray-light !default;
-//** Headings small color
-$headings-small-color:        $gray-light !default;
-//** Blockquote small color
-$blockquote-small-color:      $gray-light !default;
-//** Blockquote font size
-$blockquote-font-size:        ($font-size-base * 1.25) !default;
-//** Blockquote border color
-$blockquote-border-color:     $gray-lighter !default;
-//** Page header border color
-$page-header-border-color:    $gray-lighter !default;
-//** Width of horizontal description list titles
-$dl-horizontal-offset:        $component-offset-horizontal !default;
-//** Point at which .dl-horizontal becomes horizontal
-$dl-horizontal-breakpoint:    $grid-float-breakpoint !default;
-//** Horizontal line color.
-$hr-border:                   $gray-lighter !default;
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/_wells.scss b/cove/cove_360/sass/bootstrap/bootstrap/_wells.scss
deleted file mode 100644
index b865711..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/_wells.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-//
-// Wells
-// --------------------------------------------------
-
-
-// Base class
-.well {
-  min-height: 20px;
-  padding: 19px;
-  margin-bottom: 20px;
-  background-color: $well-bg;
-  border: 1px solid $well-border;
-  border-radius: $border-radius-base;
-  @include box-shadow(inset 0 1px 1px rgba(0,0,0,.05));
-  blockquote {
-    border-color: #ddd;
-    border-color: rgba(0,0,0,.15);
-  }
-}
-
-// Sizes
-.well-lg {
-  padding: 24px;
-  border-radius: $border-radius-large;
-}
-.well-sm {
-  padding: 9px;
-  border-radius: $border-radius-small;
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_alerts.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_alerts.scss
deleted file mode 100644
index 3faf0b5..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_alerts.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-// Alerts
-
-@mixin alert-variant($background, $border, $text-color) {
-  background-color: $background;
-  border-color: $border;
-  color: $text-color;
-
-  hr {
-    border-top-color: darken($border, 5%);
-  }
-  .alert-link {
-    color: darken($text-color, 10%);
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_background-variant.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_background-variant.scss
deleted file mode 100644
index 4c7769e..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_background-variant.scss
+++ /dev/null
@@ -1,12 +0,0 @@
-// Contextual backgrounds
-
-// [converter] $parent hack
-@mixin bg-variant($parent, $color) {
-  #{$parent} {
-    background-color: $color;
-  }
-  a#{$parent}:hover,
-  a#{$parent}:focus {
-    background-color: darken($color, 10%);
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_border-radius.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_border-radius.scss
deleted file mode 100644
index ce19499..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_border-radius.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-// Single side border-radius
-
-@mixin border-top-radius($radius) {
-  border-top-right-radius: $radius;
-   border-top-left-radius: $radius;
-}
-@mixin border-right-radius($radius) {
-  border-bottom-right-radius: $radius;
-     border-top-right-radius: $radius;
-}
-@mixin border-bottom-radius($radius) {
-  border-bottom-right-radius: $radius;
-   border-bottom-left-radius: $radius;
-}
-@mixin border-left-radius($radius) {
-  border-bottom-left-radius: $radius;
-     border-top-left-radius: $radius;
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_buttons.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_buttons.scss
deleted file mode 100644
index b93f84b..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_buttons.scss
+++ /dev/null
@@ -1,65 +0,0 @@
-// Button variants
-//
-// Easily pump out default styles, as well as :hover, :focus, :active,
-// and disabled options for all buttons
-
-@mixin button-variant($color, $background, $border) {
-  color: $color;
-  background-color: $background;
-  border-color: $border;
-
-  &:focus,
-  &.focus {
-    color: $color;
-    background-color: darken($background, 10%);
-        border-color: darken($border, 25%);
-  }
-  &:hover {
-    color: $color;
-    background-color: darken($background, 10%);
-        border-color: darken($border, 12%);
-  }
-  &:active,
-  &.active,
-  .open > &.dropdown-toggle {
-    color: $color;
-    background-color: darken($background, 10%);
-        border-color: darken($border, 12%);
-
-    &:hover,
-    &:focus,
-    &.focus {
-      color: $color;
-      background-color: darken($background, 17%);
-          border-color: darken($border, 25%);
-    }
-  }
-  &:active,
-  &.active,
-  .open > &.dropdown-toggle {
-    background-image: none;
-  }
-  &.disabled,
-  &[disabled],
-  fieldset[disabled] & {
-    &:hover,
-    &:focus,
-    &.focus {
-      background-color: $background;
-          border-color: $border;
-    }
-  }
-
-  .badge {
-    color: $background;
-    background-color: $color;
-  }
-}
-
-// Button sizes
-@mixin button-size($padding-vertical, $padding-horizontal, $font-size, $line-height, $border-radius) {
-  padding: $padding-vertical $padding-horizontal;
-  font-size: $font-size;
-  line-height: $line-height;
-  border-radius: $border-radius;
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_center-block.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_center-block.scss
deleted file mode 100644
index e06fb5e..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_center-block.scss
+++ /dev/null
@@ -1,7 +0,0 @@
-// Center-align a block level element
-
-@mixin center-block() {
-  display: block;
-  margin-left: auto;
-  margin-right: auto;
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_clearfix.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_clearfix.scss
deleted file mode 100644
index dc3e2ab..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_clearfix.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-// Clearfix
-//
-// For modern browsers
-// 1. The space content is one way to avoid an Opera bug when the
-//    contenteditable attribute is included anywhere else in the document.
-//    Otherwise it causes space to appear at the top and bottom of elements
-//    that are clearfixed.
-// 2. The use of `table` rather than `block` is only necessary if using
-//    `:before` to contain the top-margins of child elements.
-//
-// Source: http://nicolasgallagher.com/micro-clearfix-hack/
-
-@mixin clearfix() {
-  &:before,
-  &:after {
-    content: " "; // 1
-    display: table; // 2
-  }
-  &:after {
-    clear: both;
-  }
-}
diff --git a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_forms.scss b/cove/cove_360/sass/bootstrap/bootstrap/mixins/_forms.scss
deleted file mode 100644
index 277aa5f..0000000
--- a/cove/cove_360/sass/bootstrap/bootstrap/mixins/_forms.scss
+++ /dev/null
@@ -1,88 +0,0 @@
-// Form validation states
-//
-// Used in forms.less to generate the form validation CSS for warnings, errors,
-// and successes.
-
-@mixin form-control-validation($text-color: #555, $border-color: #ccc, $background-color: #f5f5f5) {
-  // Color the label and help text
-  .help-block,
-  .control-label,
-  .radio,
-  .checkbox,
-  .radio-inline,
-  .checkbox-inline,
-  &.radio label,
-  &.checkbox label,
-  &.radio-inline label,
-  &.checkbox-inline label  {
-    color: $text-color;
-  }
-  // Set the border and box shadow on specific inputs to match
-  .form-control {
-    border-color: $border-color;
-    @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work
-    &:focus {
-      border-color: darken($border-color, 10%);
-      $shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten($border-color, 20%);
-      @include box-shadow($shadow);
-    }
-  }
-  // Set validation states also for addons
-  .input-group-addon {
-    color: $text-color;
-    border-color: $border-color;
-    background-color: $background-color;
-  }
-  // Optional feedback icon
-  .form-control-feedback {
-    color: $text-color;
-  }
-}
-
-
-// Form control focus state
-//
-// Generate a customized focus state and for any input with the specified color,
-// which defaults to the `$input-border-focus` variable.
-//
-// We highly encourage you to not customize the default value, but instead use
-// this to tweak colors on an as-needed basis. This aesthetic change is based on
-// WebKit's default styles, but applicable to a wider range of browsers. Its
-// usability and accessibility should be taken into account with any change.
-//
-// Example usage: change the default blue border and shadow to white for better
-// contrast against a dark gray background.
-@mixin form-control-focus($color: $input-border-focus) {
-  $color-rgba: rgba(red($color), green($color), blue($color), .6);
-  &:focus {
-    border-color: $color;
-    outline: 0;
-    @include box-shadow(inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px $color-rgba);
-  }
-}
-
-// Form control sizing
-//
-// Relative text size, padding, and border-radii changes for form controls. For
-// horizontal sizing, wrap controls in the predefined grid classes. `
-        
-      
-    {% endif %}
-    

{% blocktrans %}Formats{% endblocktrans %}

-

{% blocktrans %}The application accepts data in the formats set out in the {% endblocktrans %}360Giving Data Standard guidance.

-

{% blocktrans %}Acceptable files are: {% endblocktrans %}

-
    -
  • {% blocktrans %}Summary Spreadsheet - OpenDocument Spreadsheet, Excel, CSV (UTF-8, Windows-1252 and ISO-8859-1 encodings supported){% endblocktrans %}
  • -
  • {% blocktrans %}JSON built to the 360Giving JSON schema (UTF-8 encoding supported){% endblocktrans %}
  • -
  • {% blocktrans %}Multi-table data package - Excel{% endblocktrans %}
  • -
- - + {% include "cove_360/components/footer.html" %} -
-
-

{% blocktrans %}How to submit your data{% endblocktrans %}

-

{% blocktrans %} - Once 360Giving data has been published by an organisation, the file must be added to the 360Giving Data Registry so that the data to appear in 360Giving’s tools such as GrantNav and 360Insights. - {% endblocktrans %} -

-

{% blocktrans %} - Publishers of 360Giving data can add their valid 360Giving data files to the Data Registry using the 360Giving data file submission form. - {% endblocktrans %} -

-

{% blocktrans %}The submission form allows users to:{% endblocktrans %}

-
    -
  • Update an existing Data Registry entry with an updated version of an existing file
  • -
  • Add an entry for a new file to the Data Registry
  • -
-

Only publishers with an authorised website domain can use this submission process.

+ -

Authorised domains

-

By default, the website domain used by existing publishers to host their 360Giving data files will be authorised.

-

Organisations that publish 360Giving data for the first time can also use the 360Giving data file submission process once they have registered their website domain with 360Giving. To register to your website domain prior to publishing for the first time please contact 360Giving Helpdesk via support@threesixtygiving.org.

-

Publishers can opt out of authorising their website domain and using the 360Giving data file submission process on request.

-

Which domains are not authorised?

-

Data files published on multi-user hosting platforms like open data repositories, or file sharing services Google Sheets or Dropbox, cannot be authorised for use with the 360Giving data file submission process because the domain cannot be authorised as being unique to a particular organisation.

-

Files published in this way can be added to the 360Giving Data Registry by emailing 360Giving Helpdesk via support@threesixtygiving.org.

-

Further guidance

-

Read our full guidance on how to use the 360Giving data submission process.

- -
-
-{% endblock %} - -{% block bottomcontent2 %} - -{% if not DEBUG %} -{% include "cove_360/cookie_consent.html" %} -{% endif %} -{% include "cove_360/more_info.html" %} -{% include "cove_360/footer.html" %} -{% endblock %} + + + \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/common_errors.html b/cove/cove_360/templates/cove_360/common_errors.html index fa109ee..874efe2 100644 --- a/cove/cove_360/templates/cove_360/common_errors.html +++ b/cove/cove_360/templates/cove_360/common_errors.html @@ -1,4 +1,4 @@ -{% extends 'base.html' %} +{% extends request.current_app_base_template %} {% load i18n %} {% block content %} @@ -16,7 +16,7 @@

{% trans "Invalid 'uri' found" %}

{% blocktrans %}What is a URI? Short for “Uniform Resource Identifier” it is a sequence of characters that distinguishes one resource from another. A URL — short for “Uniform Resource Locator” — is a specific type of URI.{% endblocktrans %}

{% blocktrans %}When the 360Giving Data Standard requires data to be provided in the format of a URI, this will mean you will very likely be providing a URL — or website address.{% endblocktrans %}

- +

{% trans "Date is not in the correct format" %}

@@ -105,7 +105,7 @@

{% trans "(something) is missing but is required" %}

- +

{% trans "Invalid code found in (something)" %}

{% blocktrans %}In the 360Giving Data Standard, there are three fields that require publishers to use values from a predefined list. When we validate people's data, we check the values of those fields against those lists.{% endblocktrans %}

@@ -129,8 +129,8 @@

{% trans "Invalid code found in (something)" %}

{% blocktrans %}The currency and country code lists are referenced in the 360Giving JSON Schemas and the field descriptions link to the code lists on third-party websites.{% endblocktrans %}

- - + +

{% trans "Field x is not a string" %}

{% blocktrans %}Data in the 360Giving Data Standard is expected to be provided in a certain format.{% endblocktrans %}

diff --git a/cove/cove_360/templates/cove_360/cookie_consent.html b/cove/cove_360/templates/cove_360/components/cookie_consent.html similarity index 73% rename from cove/cove_360/templates/cove_360/cookie_consent.html rename to cove/cove_360/templates/cove_360/components/cookie_consent.html index 7b2eee2..74f9964 100644 --- a/cove/cove_360/templates/cove_360/cookie_consent.html +++ b/cove/cove_360/templates/cove_360/components/cookie_consent.html @@ -22,27 +22,27 @@
@@ -59,4 +59,4 @@
- + \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/components/explore/accuracy.html b/cove/cove_360/templates/cove_360/components/explore/accuracy.html new file mode 100644 index 0000000..1ff3560 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/explore/accuracy.html @@ -0,0 +1,92 @@ +{% load i18n %} +{% load humanize %} +{% load cove_tags %} + +

Data Accuracy

+ + {% if validation_errors or additional_closed_codelist_values %} +

The data provided did not pass validation therefore the accuracy of the data could not be determined. + {% else %} + + {% if quality_accuracy_checks_passed %} +

What is working well

+

checkCongratulations, {{quality_accuracy_checks_passed|length}} of our data accuracy checks passed.

+ {% endif %} + + + {% if quality_accuracy_errored %} +

{% blocktrans %}Quality accuracy checks failed due to an issue with the data. Fix some validation errors first.{% endblocktrans %}

+ {% else %} + + {% if quality_accuracy_checks %} +

Potential issues

+

{% blocktrans %}These checks highlight areas where your data may be incorrect or need further attention.{% endblocktrans %}

+ {% blocktrans %} +

For each check we give feedback on the issue and what steps may be taken to resolve it.

+

Receiving this feedback does not mean the data is invalid, and it can be ignored when not relevant.

+ {% endblocktrans %} + + {% for category in quality_accuracy_categories %} +

{{category}}

+ + + + + + + + + + {# using regroup here would be good if we had dictionaries #} + {% for message, json_location, spreadsheet_location in quality_accuracy_checks %} + {% if message.category == category %} + + + + {% if file_type == 'xlsx' or file_type == 'csv' %} + + {% else %} + + {% endif %} + + {% endif %} {# category filter #} + {% endfor %} + +
{% trans 'Passed' %}{% trans 'Check Description' %} {% trans 'First 3 Locations' %}
close + {{ message.heading }}

{{ message.message }} +
+
    + {% for location in spreadsheet_location|slice:":3" %} +
  • Sheet: {{location.sheet}} Row: {{location.row_number}} {% if location.header %} Header: {{location.header}} {% endif %}
  • + {% endfor %} + {% if spreadsheet_location|length > 3 %} +
  • + {% endif %} +
+
+
    + {% for location in json_location|slice:":3" %} +
  • {{location}}
  • + {% endfor %} + {% if json_location|length > 3 %} +
  • + {% endif %} +
+
+ {% endfor %} {# for each category #} + {% else %} +

No accuracy issues found.

+ {% endif %} + +{% for message, json_location, spreadsheet_location in quality_accuracy_checks %} +{% with msg=message.heading %} +{% if file_type == 'json' %} +{% cove_modal_errors className="quality_accuracy-checks-"|concat:forloop.counter modalTitle=msg errorList=json_location file_type=file_type full_table=False %} +{% else %} +{% cove_modal_errors className="quality_accuracy-checks-"|concat:forloop.counter modalTitle=msg errorList=spreadsheet_location file_type=file_type full_table=False %} +{% endif %} +{% endwith %} +{% endfor %} + +{% endif %} {# Quality accuracy errored #} +{% endif %} {# validation failed #} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/components/explore/summary.html b/cove/cove_360/templates/cove_360/components/explore/summary.html new file mode 100644 index 0000000..79491ea --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/explore/summary.html @@ -0,0 +1,324 @@ +{% load i18n %} +{% load humanize %} +{% load cove_tags %} + + +

{% trans "Summary" %}

+ + {% if validation_errors or additional_closed_codelist_values %} +
+

+ {% trans "This data does not use the 360Giving Data Standard correctly" %} ({% blocktrans count n_errors=validation_and_closed_codelist_errors_count %} {{n_errors}} Error.{% plural %}{{n_errors}} Errors {% endblocktrans %}) +

+

{% trans "Sorry your data is not yet using the 360Giving Data Standard. We used the " %} + 360Giving JSON Package Schema {% trans "to check this." %} + See Validity for further details. +

+
+ {% else %} +
+

{% trans "This data uses the 360Giving Data Standard correctly" %}

+

+ {% trans "Congratulations! Your data is using the 360Giving Data Standard. We used the " %} + 360Giving JSON Package Schema + {% trans "to check this." %} +

+
+ {% endif %} + + {% if conversion_warning_messages or conversion_error %} +
+

This data could not be converted ({% blocktrans count n_warnings=conversion_warning_messages|length %}{{n_warnings}} Error) {% plural %}{{n_warnings}} Errors){% endblocktrans %} + +

+

We could not converting the data for checking. See Data conversion errors for details. +

+
+ {% endif %} + + {% if conversion == 'flatten' %} +
+

File conversion successful

+

We have converted your JSON data into spreadsheet format. See Download and share for more details.

+
+ {% endif %} + +
+

+ The file "{{file_name}}" was + {% if source_url %} + {% trans "downloaded from " %} {{source_url}} + {% else %} + {% trans "uploaded " %} + {% endif %} + {% trans "on " %} {{created_date}} at {{created_time}}. +

+ +

Explore your data:

+
    + {% if additional_fields_count %} +
  1. Additional fields ({{additional_fields_count}})
  2. + {% endif %} + {% if conversion_warning_messages %} +
  3. Conversion errors ({{conversion_warning_messages|length}})
  4. + {% endif %} + + {% if metadata %} +
  5. Metadata
  6. + {% endif %} +
  7. File contents
  8. +
  9. Identifiers
  10. +
  11. Data convertor
  12. +
  13. Download and share
  14. +
  15. Further help
  16. +
+ + {% if conversion_warning_messages or conversion_error %} +
+

+ {% trans "Data conversion unsuccessful - " %} + {% blocktrans count n_warnings=conversion_warning_messages|length %}{{n_warnings}} Error has been found{% plural %}{{n_warnings}} Errors have been found{% endblocktrans %} +

+ +

{% trans "Before checking your data we needed to convert it to JSON" %}{% if conversion_error or conversion_warning_messages %}{% blocktrans %} but we were not able to do this successfully{% endblocktrans %}{% endif %}.

+ {% blocktrans %}This tool converts data into JSON because the 360Giving Data Standard uses a JSON Schema to describe the standard in a technical way.{% endblocktrans %}
+ {% blocktrans %}If a file cannot be converted to JSON it indicates that it cannot be correctly mapped to the standard and needs to be reviewed. If this is the case you should check the file and re-upload it once you’ve fixed the problem. The conversion errors below will give an indication of where the issue is.{% endblocktrans %} + {% if conversion_error %} +

{% blocktrans %}The JSON data could not be converted to spreadsheet due to the following error: {{conversion_error}}{% endblocktrans %}

+ {% include 'error_extra.html' %} + {% endif %} + + {% if conversion_warning_messages %} +

{% trans "Conversion errors:" %}

+
    + {% for warning_message in conversion_warning_messages %} +
  • {{warning_message}}
  • + {% endfor %} +
+

{% trans "Please resolve this error, as well as any others found, and test the data again." %} Load new file.

+ {% endif %} +{% endif %} {# / if conversion errors #} + + + + {% if metadata %} + +

Metadata

+
+
+ {% if metadata.publisher %} + Publisher: {{metadata.publisher.name}} ({{metadata.publisher.identifier}})
+ {% endif %} + {% if metadata.accessURL %} + Website that contains this Dataset: {{metadata.accessURL}}
+ {% endif %} + {% if metadata.identifier %} + Dataset Identifier: {{metadata.identifier}}
+ {% endif %} + {% if metadata.version %} + 360 Giving Schema Version: {{metadata.version}}
+ {% endif %} + {% if metadata.license %} + License: {{metadata.license}}
+ {% endif %} + {% if extension_metadatas %} + Extensions: {% for extension_metadata in extension_metadatas %}{{extension_metadata.id}} {% endfor %}
+ {% endif %} +
+
+ {% if metadata.publisher.logo %} + + {% endif %} +
+
+ {% endif %} {# end if the file had a metadata tab #} + + {% if metadata.downloadURL or metadata.title %} +

+ {% if metadata.title %} + {{metadata.title}} + {% endif %} + {% if metadata.downloadURL %} + Original Data Download + {% endif %} +

+ {% endif %} + + {% if metadata.description %} +

+ {{metadata.description}} +

+ {% endif %} + +
+

This file contains

+ +

{% trans "Use this section to get an overview of the data and check if this was what you were expecting to see." %}

+
    +
  • + {% blocktrans count n_grants=grants_aggregates.count|default:0 %}There is {{n_grants}} grant{% plural %}There are {{n_grants}} grants {% endblocktrans %} + {% blocktrans count n_recipients=grants_aggregates.distinct_recipient_org_identifier|length|default:0 %}to {{n_recipients}} recipient organisation and {% plural %}to {{n_recipients}} recipient organisations and{% endblocktrans %} + {% blocktrans count n_recipients_individuals=grants_aggregates.recipient_individuals_count|default:0 %}{{n_recipients_individuals}} to a recipient individual {% plural %}{{n_recipients_individuals}} to recipient individuals{% endblocktrans %}. +
  • +
  • {% blocktrans count n_funders=grants_aggregates.distinct_funding_org_identifier|length|default:0 %} The grants are made by {{n_funders}} funding organisation{% plural %} The grants are made by {{n_funders}} funding organisations{% endblocktrans %}.
  • +
  • + {% blocktrans count n_grants=grants_aggregates.count|default:0 %}The grant was awarded {% plural %}The grants were awarded {% endblocktrans %} + {% if grants_aggregates.min_award_date == grants_aggregates.max_award_date %} + {% blocktrans with start_date=grants_aggregates.min_award_date %}on {{start_date}}.{% endblocktrans %} + {% else %} + {% blocktrans with start_date=grants_aggregates.min_award_date end_date=grants_aggregates.max_award_date %}between {{start_date}} and {{end_date}}.{% endblocktrans %} + {% endif %} +
  • + + {% if metadata.issued %} +
  • + The file was issued on {{metadata.issued|slice:":10"}} +
  • + {% endif %} + {% if metadata.modified %} +
  • + The file was modified on {{metadata.modified|slice:":10"}} +
  • + {% endif %} + {% for currency_code, currency_aggregates in grants_aggregates.currencies.items %} +
  • + {% if currency_aggregates.count == 1 %} + {% if currency_aggregates.count == grants_aggregates.count %} + {% trans "The grant" %} + {% else %} + {% trans "1 grant" %} + {% endif %} + {% blocktrans with amount_awarded=currency_aggregates.total_amount|intcomma currency_symbol=currency_aggregates.currency_symbol|safe %} was awarded in {{currency_code}} with a value of {{currency_symbol}}{{amount_awarded}}.{% endblocktrans %} + {% else %} + {% if currency_aggregates.count == grants_aggregates.count %} + {% trans "The grants" %} + {% else %} + {{currency_aggregates.count}} {% trans "grants" %} + {% endif %} + {% blocktrans with n_grants=currency_aggregates.count total_amount=currency_aggregates.total_amount|intcomma max_amount=currency_aggregates.max_amount|intcomma min_amount=currency_aggregates.min_amount|intcomma currency_symbol=currency_aggregates.currency_symbol|safe %} were awarded in {{currency_code}} with a total value of {{currency_symbol}}{{total_amount}} and individual awards ranging from {{currency_symbol}}{{min_amount}} (lowest) to {{currency_symbol}}{{max_amount}} (highest).{% endblocktrans %} + {% endif %} +
  • + {% endfor %} + {% if csv_encoding and csv_encoding != "utf-8-sig" %} +
  • + {% blocktrans %} This file is not 'utf-8' encoded (it is {{csv_encoding}} encoded).{% endblocktrans %} +
  • + {% endif %} +
+ +{# / file contains #} + + {% if additional_fields_count %} +
+

+ {% blocktrans count n_additional_fields=additional_fields_count %} Additional fields{% plural %} Additional fields ({{n_additional_fields}}){% endblocktrans %} +

+ {% if data_only %} +

{% blocktrans %} Additional fields which do not use 360Giving Data Standard titles were found in your data.{% endblocktrans %}

+

{% blocktrans %} You are welcome to include additional fields in your data, however please check the field title(s) shown below to confirm if they are intended additions and not the result of spelling or formatting mistakes in the title. Please refer to the Common Errors section to see the correctly formatted field titles for the required fields. {% endblocktrans %}

+ {% include "additional_fields_table.html" %} + {% endif %} + {% for message, json_location, spreadsheet_location in additional_checks %} + {% with msg=message.heading %} + {% if file_type == 'json' %} + {% cove_modal_errors className="additional-checks-"|concat:forloop.counter modalTitle=msg errorList=json_location file_type=file_type full_table=False %} + {% else %} + {% cove_modal_errors className="additional-checks-"|concat:forloop.counter modalTitle=msg errorList=spreadsheet_location file_type=file_type full_table=False %} + {% endif %} + {% endwith %} + {% endfor %} + {% endif %} + + {# / additional fields #} + +

Identifiers

+ {% trans "Unique grant identifiers" %} + {% if grants_aggregates.unique_ids|length %} .{% endif %} + {% trans "Unique funder organisation identifiers" %} + {% if grants_aggregates.distinct_funding_org_identifier|length %} . + {% endif %} + {% trans "Unique recipient organisation identifiers" %} + {% if grants_aggregates.distinct_recipient_org_identifier|length %} .{% endif %} + +

{% blocktrans %}Do these results look correct?{% endblocktrans %}

+
    +
  • {% blocktrans %}Do the numbers of funders, grants and recipients match what you expect?{% endblocktrans %}
  • +
  • {% blocktrans %}Are the dates for the right time period?{% endblocktrans %}
  • +
  • {% blocktrans %}Do the currency and total value figures show the correct amounts?{% endblocktrans %}
  • +
+

{% blocktrans %}If any of this information appears incorrect, the feedback below will help you to investigate what happened. {% endblocktrans %}

+ +
+ +
+

Data conversion

+ {% if conversion == 'flattenable' %} +

Convert the data from JSON format to spreadsheet.

+
+ + {% csrf_token %} +
+ {% endif %} + + + + {% cove_360_modal_list className="unique-ids" modalTitle="Unique IDs" itemList=grants_aggregates.unique_ids %} + {% cove_360_modal_list className="distinct-funding-org-identifier" modalTitle="Funder Organisation IDs" itemList=grants_aggregates.distinct_funding_org_identifier %} + {% cove_360_modal_list className="distinct-recipient-org-identifier" modalTitle="Recipient Organisation IDs" itemList=grants_aggregates.distinct_recipient_org_identifier %} + +

+ {% trans "Download data and share these results" %} +

+

Share

+

{% trans "You can share these test results with others by using the following url:" %}

+

{{ current_url }} + +

+

{% trans "If your data is not suitable for sharing publicly, then you should treat this url with care. Only share it with people who have permission to access the data." %}

+

{% trans "After 7 days, the link will expire and the data will be deleted from our servers - so the results will no longer be available. You can revisit these results until then." %}

+

Download

+

{% trans "This application converts data in Excel and CSV format into JSON format, allowing you download the converted version." %}

+

{% trans "If your file is originally in JSON format select ‘Convert to Spreadsheet’ in the summary section to create an Excel version of the file." %}

+ + {% if not conversion_error and conversion != 'flattenable' %} +

{% trans "We provide the following formats to download:" %}

+ + {% else %} +

(No downloads available as the conversion hasn't happened, or has errored).

+ {% endif %} + {% if user.is_authenticated %} +

Original file download for admin users

+

Warning, this is the original file uploaded. Do not download if you don't trust whoever sent you a link to this page, it could contain a virus. Note that this box and this download link are only visible to admin users, not others you share this page with.

+ + {% endif %} +
+ +
+ +

Getting further help

+

You can read about common data errors and what causes them in the Common Errors section.

+

Visit our Data Quality Dashboard to see the data quality of 360Giving data as a whole and for each individual publisher. If you have already published data, you can view your own publisher page there too. It provides insights into the key features that make the data useful for analysis to help publishers to identify opportunities for their data to be improved.

+ diff --git a/cove/cove_360/templates/cove_360/components/explore/usefulness.html b/cove/cove_360/templates/cove_360/components/explore/usefulness.html new file mode 100644 index 0000000..91a3fc5 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/explore/usefulness.html @@ -0,0 +1,106 @@ +{% load i18n %} +{% load humanize %} +{% load cove_tags %} + +

Usefulness Opportunities

+ + {% if validation_errors or additional_closed_codelist_values %} +

The data provided did not pass validation therefore the usefulness of the data could not be determined. + {% else %} + +{% if usefulness_checks_passed %} +

What is working well

+

checkCongratulations, {{usefulness_checks_passed|length}} of our usefulness checks passed.

+ {% endif %} + + +{% if usefulness_checks_count %} +

Potential opportunities

+ {% if usefulness_checks_errored %} +

{% blocktrans %}Usefulness checks failed due to an issue with the data. Fix some validation errors first.{% endblocktrans %}

+ {% endif %} + + {% if usefulness_checks %} +

+ We identified {% blocktrans count n_usefulness_checks=usefulness_checks_count %} usefulness opportunity{% plural %}{{n_usefulness_checks}} usefulness opportunities{% endblocktrans %}. + {% blocktrans %}These usefulness checks highlight ways the data could be made more useful.{% endblocktrans %} +

+ + {% blocktrans %} +

These are the key features that make the data useful for analysis, which we recommend including in 360Giving data whenever possible.

+

Receiving this feedback does not mean the data is invalid and it can be ignored when not relevant.

+

Visit our Data Quality Dashboard to see the data quality of 360Giving data as a whole and for each individual publisher. If you have already published data, you can view your own publisher page there too. It provides insights into the key features that make the data useful for analysis to help publishers to identify opportunities for their data to be improved.

+ {% endblocktrans %} + + {% for category in usefulness_categories %} +

{{category}}

+ + + + + + + + + + + {% for message, json_location, spreadsheet_location in usefulness_checks %} + {% if message.category == category %} + + + + {% if file_type == 'xlsx' or file_type == 'csv' %} + + {% else %} + + {% endif %} + + {% endif %} {# end category filter #} + {% endfor %} + +
{% trans 'Failed' %}{% trans 'Check Description' %} {% trans 'First 3 Locations' %}
+
+
+ {{message.percentage|multiply:100}}% +
+
+
+ {{ message.heading }}

{{ message.message }} +
+
    + {% for location in spreadsheet_location|slice:":3" %} +
  • Sheet: {{location.sheet}} Row: {{location.row_number}} {% if location.header %} Header: {{location.header}} {% endif %}
  • + {% endfor %} + {% if spreadsheet_location|length > 3 %} +
  • + {% endif %} +
+
+ {# first 3 locations #} +
    + {% for location in json_location|slice:":3" %} +
  • {{location}}
  • + {% endfor %} + {% if json_location|length > 3 %} +
  • + {% endif %} +
+
+ {% endfor %} {# categories #} + + {% endif %} {# if count #} + + {% for message, json_location, spreadsheet_location in usefulness_checks %} + {% with msg=message.heading %} + {% if file_type == 'json' %} + {% cove_360_modal_errors className="usefulness-checks-"|concat:forloop.counter modalTitle=msg errorList=json_location file_type=file_type full_table=False %} + {% else %} + {% cove_360_modal_errors className="usefulness-checks-"|concat:forloop.counter modalTitle=msg errorList=spreadsheet_location file_type=file_type full_table=False %} + {% endif %} + {% endwith %} + {% endfor %} + + {% else %} +

No usefulness opportunities detected.

+ {% endif %} +{% endif %} {# validation failed #} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/components/explore/validity.html b/cove/cove_360/templates/cove_360/components/explore/validity.html new file mode 100644 index 0000000..6ce6e98 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/explore/validity.html @@ -0,0 +1,102 @@ +{% load i18n %} +{% load humanize %} +{% load cove_tags %} + +

Validation + {% if validation_and_closed_codelist_errors_count > 0 %} + Failed + {% else %} + Passed + {% endif %} +

+ +

+ {% if validation_and_closed_codelist_errors_count > 0 %} + {% trans "Validation failed means that the data does not meet " %} + {% else %} + {% trans "Validation passed means that the data meets " %} + {% endif %} + {% blocktrans %}the requirements of the 360Giving Data Standard.{% endblocktrans %} + {% blocktrans %} Making sure your data uses the standard correctly is important. Otherwise it cannot be used alongside other valid 360Giving data and cannot be included in 360Giving tools, such as GrantNav and 360Insights.{% endblocktrans %} +

+ + {% if extension_metadatas %} +

{% trans "The 360Giving Data Standard was extended using these extensions:" %}

+
    + {% for extension_metadata in extension_metadatas %} +
  1. {{extension_metadata.title}} ({{extension_metadata.id}})
  2. + {% endfor %} +
+ {% endif %} + + {% if validation_errors or additional_closed_codelist_values %} +

{% trans "The following errors are preventing your data from being valid 360Giving data. Please use the feedback below to find and resolve the issues in your file" %}

+ + {% with validation_errors=validation_errors_grouped.required error_prefix='required-' %} + {% if validation_errors %} + +

Missing Fields

+

Some or all of your entries were missing fields which are required by the 360Giving Data Standard.

+ {% include "cove_360/validation_table.html" %} + + + {% for error_json, error_extra in validation_errors %} + {% with error=error_json|json_decode %} + {% cove_360_modal_errors className="validation-errors-"|concat:error_prefix|concat:forloop.counter modalTitle=error.message errorList=error_extra.values file_type=file_type full_table=True %} + {% endwith %} + {% endfor %} + {% endif %} + {% endwith %} + {% with validation_errors=validation_errors_grouped.format error_prefix='format-' %} + {% if validation_errors %} + + +

Incorrect Formats

+ + +

Some or all of your entries have incorrectly formatted data.

+ {% include "cove_360/validation_table.html" %} + + + {% for error_json, error_extra in validation_errors %} + {% with error=error_json|json_decode %} + {% cove_360_modal_errors className="validation-errors-"|concat:error_prefix|concat:forloop.counter modalTitle=error.message errorList=error_extra.values file_type=file_type full_table=True %} + {% endwith %} + {% endfor %} + {% endif %} + {% endwith %} + {% if additional_closed_codelist_values %} + + +

{% trans 'Codelist Errors' %}

+ + + +

Some or all of your entries do not use the 360Giving Data Standard codelists correctly.

+

{% blocktrans %}The fields below use closed codelists. When using these fields, you must use one of the pre-defined codelist values. If you use a value that is not on the relevant codelist, your data will not pass structural checks.{% endblocktrans %}

+ + {% with additional_codelist_values=additional_closed_codelist_values %} + {% include "additional_codelist_values.html" %} + {% endwith %} + + + {% endif %} + {% endif %} + {% with validation_errors=validation_errors_grouped.other error_prefix='other-' %} + {% if validation_errors %} + + +

Other

+ + +

Other validation errors.

+ {% include "cove_360/validation_table.html" %} + + + {% for error_json, error_extra in validation_errors %} + {% with error=error_json|json_decode %} + {% cove_360_modal_errors className="validation-errors-"|concat:error_prefix|concat:forloop.counter modalTitle=error.message errorList=error_extra.values file_type=file_type full_table=True %} + {% endwith %} + {% endfor %} + {% endif %} + {% endwith %} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/components/explore_checking.html b/cove/cove_360/templates/cove_360/components/explore_checking.html new file mode 100644 index 0000000..248c85d --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/explore_checking.html @@ -0,0 +1,143 @@ +{% load i18n %} {% load humanize %} {% load cove_tags %} + +{% trans 'Converted from Original' as converted %} +{% trans 'Original' as original %} +{% trans 'Excel Spreadsheet (.xlsx)' as xlsx %} +{% trans 'OpenDocument Spreadsheet (.ods)' as ods %} +{% trans 'CSV Spreadsheet (.csv)' as csv %} +{% trans 'Excel Spreadsheet (.xlsx) with titles' as xlsx_titles %} +{% trans 'OpenDocument Spreadsheet (.ods) with titles' as ods_titles %} +{# Translators: JSON probably does not need a transalation: http://www.json.org/ #} +{% trans 'JSON' as JSON %} +{% trans 'XML' as XML %} + + + +

Checking file "{{file_name}}"

+ + + +
+
+
+
+
+

+ {{validation_and_closed_codelist_errors_count}} +

+

Validity errors to fix

+
+
+
+ +
+
+
+

+ {% if validation_and_closed_codelist_errors_count %} + 0 + {% else %} + {{quality_accuracy_checks_count}} + {% endif %} +

+

Potential accuracy issue

+
+
+
+ +
+
+
+

+ {% if validation_and_closed_codelist_errors_count %} + 0 + {% else %} + {{usefulness_checks_count }} + {% endif %} +

+

Usefulness opportunities

+
+
+
+
+ + +
+ + + + + + +
+ {% include "cove_360/components/explore/summary.html" %} +
+ + + + + + +
+ +
+ + \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/components/explore_publishing.html b/cove/cove_360/templates/cove_360/components/explore_publishing.html new file mode 100644 index 0000000..3cadd7f --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/explore_publishing.html @@ -0,0 +1,118 @@ +{% load i18n %} + +{% trans 'Converted from Original' as converted %} +{% trans 'Original' as original %} +{% trans 'Excel Spreadsheet (.xlsx)' as xlsx %} +{% trans 'OpenDocument Spreadsheet (.ods)' as ods %} +{% trans 'CSV Spreadsheet (.csv)' as csv %} +{% trans 'Excel Spreadsheet (.xlsx) with titles' as xlsx_titles %} +{% trans 'OpenDocument Spreadsheet (.ods) with titles' as ods_titles %} +{# Translators: JSON probably does not need a transalation: http://www.json.org/ #} +{% trans 'JSON' as JSON %} +{% trans 'XML' as XML %} +

{% trans "Submit your data" %}

+ +{% if validation_and_closed_codelist_errors_count > 0 %} +
+
+

+ {{validation_and_closed_codelist_errors_count}} +

+

Validity errors to fix before submitting

+
+
+ +{% endif %} + +{% if data_status.can_publish %} +

{% trans "Submitting for: " %}{{publisher.name}}

+

check{% trans "The data was checked and can now be submitted to the 360Giving Data Registry." %}

+

+ {% trans "Click the 'Submit your file' to fill out the 360Giving data file submission form. " %} + {% trans "Guidance about using the submission form." %} +

+ + Submit your file + +{% endif %} {# Data passed, Domain not recognised/approved #} +{% if data_status.passed and not data_status.can_publish %} +

+ {% blocktrans %} Sorry you aren't able to submit this file because the domain + name of the website hosting your file ({{source_url_domain}}) is not + authorised for publishing 360Giving data. {% endblocktrans %} +

+

+ {% blocktrans %} Please email 360Giving Helpdesk via + support@threesixtygiving.org + with the link to the file you want to submit to the Data Registry. + {% endblocktrans %} +

+{% endif %} +{# Validation failed #} {% if not data_status.passed %} +

+ {% blocktrans %}Sorry you aren't able to submit this file because it is not + valid 360Giving data.{% endblocktrans %} +

+

+ {% blocktrans %} Follow the feedback in the Data Quality Tool to make the amendments needed to + your data. Once your data passes the Data Quality tool checks, upload the + updated file to your website and then restart the 360Giving data file + submission process. The data did not pass the checks and cannot be published. + See results below. {% endblocktrans %} +

+ +

Open the file in Data Quality Tool to see validation errors.

+{% endif %} + +
+ +{% comment %} TODO no longer needed? + + + + + +

Report

+{% include "cove_360/components/explore/summary.html" %} +
+{% include "cove_360/components/explore/validity.html" %} +
+{% include "cove_360/components/explore/accuracy.html" %} +
+{% include "cove_360/components/explore/usefulness.html" %} +#} +{% endcomment %} + + diff --git a/cove/cove_360/templates/cove_360/components/footer.html b/cove/cove_360/templates/cove_360/components/footer.html new file mode 100644 index 0000000..7b129a4 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/footer.html @@ -0,0 +1,77 @@ +{% load i18n %} +{% load static %} + + \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_conditions.html b/cove/cove_360/templates/cove_360/components/terms/terms_conditions.html new file mode 100644 index 0000000..9e35206 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_conditions.html @@ -0,0 +1,17 @@ + +

Terms & conditions

+ +{% include "terms_conditions_intro.html" %} + +

The use of this website is subject to the following terms of use:

+ +

The content of the pages of this website is for your general information and use only. It is subject to change without notice.

+ +

Neither we nor any third parties provide any warranty or guarantee as to the accuracy, timeliness, performance, completeness or suitability of the information and materials found or offered on this website for any particular purpose. You acknowledge that such information and materials may contain inaccuracies or errors and we expressly exclude liability for any such inaccuracies or errors to the fullest extent permitted by law. +Your use of any information or materials on this website is entirely at your own risk, for which we shall not be liable. It shall be your own responsibility to ensure that any products, services or information available through this website meet your specific requirements. +This website contains material which is owned by or licensed to us. This material includes, but is not limited to, the design, layout, look, appearance and graphics. Reproduction is prohibited other than in accordance with the copyright notice, which forms part of these terms and conditions. +All trademarks reproduced in this website which are not the property of, or licensed to, the operator are acknowledged on the website. +Unauthorised use of this website may give rise to a claim for damages and/or be a criminal offence. +From time to time this website may also include links to other websites. These links are provided for your convenience to provide further information. They do not signify that we endorse the website(s). We have no responsibility for the content of the linked website(s). +Your use of this website and any dispute arising out of such use of the website is subject to the laws of England, Northern Ireland, Scotland and Wales.

+ diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_conditions_intro.html b/cove/cove_360/templates/cove_360/components/terms/terms_conditions_intro.html new file mode 100644 index 0000000..ba37058 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_conditions_intro.html @@ -0,0 +1,22 @@ +

+This web application is free software designed to help people check data published to the +{% if app == 'cove_360' %}360Giving Standard.{% endif %} +{% if app == 'cove_iati' %}IATI data standard.{% endif %} +

+ +

It is offered as service WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ +

+If you continue to browse and use this website, you are agreeing to comply with and be bound by the following terms and conditions of use, which together with our privacy notice govern + {% if app == 'cove_360' %}360Giving's{% endif %} + {% if app == 'cove_iati' %}Open Data Services Co-operative Limited's{% endif %} + relationship with you in relation to this website. If you disagree with any part of these terms and conditions, please do not use our website. +

+ +{% if app == 'cove_iati' %} +

The term 'Open Data Services Co-operative Limited' or 'us' or 'we' refers to the owner of the website. Our company registration number is 09506232. Our registered address is 1st Floor, Holyoake House, Hanover Street, Manchester, Greater Manchester, England, M60 0AS. You can contact us by email company@opendataservices.coop. There is more company information on the Open Data Services Co-operative Limited page at Open Corporates. The term 'you' refers to the user or viewer of our website.

+{% elif app == 'cove_360' %} +

The term ‘360Giving’ or ‘us’ or ‘we’ refers to the owner of the website. Our company registration number is 09668396. Our registered address is 360Giving, c/o Esmée Fairbairn Foundation, King's Place, 90 York Way, London, N1 9AG. You can contact us by email info@threesixtygiving.org.

+

The site is operated by Open Data Services Co-operative Limited.

+

The term 'Open Data Services Co-operative Limited' refers to the operator of the website on behalf of 360Giving. Open Data Services Co-operative Limited's company registration number is 09506232. Their registered address is 1st Floor, Holyoake House, Hanover Street, Manchester, Greater Manchester, England, M60 0AS. Email: company@opendataservices.coop

+{% endif %} diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_cookies.html b/cove/cove_360/templates/cove_360/components/terms/terms_cookies.html new file mode 100644 index 0000000..1dbc9be --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_cookies.html @@ -0,0 +1,37 @@ + +

How we use cookies

+

A cookie is a small file which asks permission to be placed on your computer's hard drive. Once you agree, the file is added and the cookie helps analyse web traffic or lets you know when you visit a particular site.

+ +

Cookies allow web applications to respond to you as an individual. The web application can tailor its operations to your needs, likes and dislikes by gathering and remembering information about your preferences. A cookie in no way gives us access to your computer or any information about you, other than the data you choose to share with us.

+ +

You can choose to accept or decline cookies. Most web browsers automatically accept cookies, but you can usually modify your browser setting to decline cookies if you prefer. This may prevent you from taking full advantage of the website.

+ +

In this website we use cookies to:

+ +
    +
  • Help us analyse how our website is used.
  • +
  • To ensure other sites can’t “forge” requests.
  • +
  • Remember your choices within the application, for your convenience.
  • +
+ +{% include "terms_cookies_we_use.html" %} + + +

If you do allow cookies to be used, Matomo uses 1st party cookies, set on the domain of this website. Cookies created by Matomo start with:

+
    +
  • _pk_ref
  • +
  • _pk_cvar
  • +
  • _pk_id
  • +
  • _pk_ses
  • +
+ +{% include "terms_cookies_links.html" %} + + +

The application is built using Django and we use that framework to set the following cookies:

+
    {% comment %}Translators: csrftoken and sessionid are names of cookies and do not need translation {% endcomment %} +
  • csrftoken - (to prevent cross site scripting attacks https://docs.djangoproject.com/en/1.8/ref/csrf/#how-it-works)
  • +
  • sessionid - (you will get this if you interact with the application, so that we can save the things you have done, e.g. select a language)"
  • +
+ +

If you choose not to accept these cookies the application may not work for you.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_cookies_link_matmo.html b/cove/cove_360/templates/cove_360/components/terms/terms_cookies_link_matmo.html new file mode 100644 index 0000000..b446b2a --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_cookies_link_matmo.html @@ -0,0 +1 @@ +

See: http://piwik.org/faq/general/faq_146/ for more information.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_cookies_links.html b/cove/cove_360/templates/cove_360/components/terms/terms_cookies_links.html new file mode 100644 index 0000000..a3afe6c --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_cookies_links.html @@ -0,0 +1,4 @@ +{% include "terms_cookies_link_matmo.html" %} + +{% include "terms_cookies_link_google_analytics.html" %} + diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_cookies_we_use.html b/cove/cove_360/templates/cove_360/components/terms/terms_cookies_we_use.html new file mode 100644 index 0000000..a200a7c --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_cookies_we_use.html @@ -0,0 +1,5 @@ +

+ We use Matomo {% if google_analytics_id %}and Google Analytics{% endif %} to analyse usage of our website (see "Understanding website visitor and traffic patterns" section below). + This uses cookies to identify you (anonymously) as the same user, so that we can analyse our web traffic better. + E.g. it allows us to count how many users we have, instead of just total page views or analyse what pages people commonly visit together. +

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_data_deleting.html b/cove/cove_360/templates/cove_360/components/terms/terms_data_deleting.html new file mode 100644 index 0000000..f9026d8 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_data_deleting.html @@ -0,0 +1,9 @@ + +

Deleting our copies of the files

+

When you provide data to the application we store the data you have provided in order to process it for you. We also enable derived versions of the data to be downloaded. Those derived versions and the original data are stored on our server.

+ +

After a period of time we will delete those files from our server, meaning they are no-longer available for download.

+ +

Information about how long files will be stored is made available to users directly through the interface, but will be for no longer than one year from the date of submission.

+ +

If you believe that any information we are holding on you is incorrect or incomplete, please write to or email us as soon as possible at the above address. We will promptly correct any information found to be incorrect.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_data_uploaded.html b/cove/cove_360/templates/cove_360/components/terms/terms_data_uploaded.html new file mode 100644 index 0000000..4d15ff6 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_data_uploaded.html @@ -0,0 +1,10 @@ + +

Data uploaded to this website

+ +

This application is designed so that people can submit files to the application, allow the application to process them and to then display information about them, generate alternative file formats of the original data, and provide those files for download.

+ +

Please do not submit any non-public personal data to this application.

+ +

We do not make use of any of the data within the files for purposes other than to create reports for you about the data you have submitted and to review the operation and output of the website.

+ +

We do create and store metadata about your use of the application, and about the files/data that you have uploaded in order to monitor how the application is being used.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_disclaimer.html b/cove/cove_360/templates/cove_360/components/terms/terms_disclaimer.html new file mode 100644 index 0000000..2eecc27 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_disclaimer.html @@ -0,0 +1,6 @@ + +

Website disclaimer

+

The information contained in this website is for general information purposes only. The information is provided by us and while we endeavour to keep the information up to date and correct, we make no representations or warranties of any kind, express or implied, about the completeness, accuracy, reliability, suitability or availability with respect to the website or the information, products, services, or related graphics contained on the website for any purpose. Any reliance you place on such information is therefore strictly at your own risk. +In no event will we be liable for any loss or damage including without limitation, indirect or consequential loss or damage, or any loss or damage whatsoever arising from loss of data or profits arising out of, or in connection with, the use of this website. +Through this website you are able to link to other websites which are not under the control of us. We have no control over the nature, content and availability of those sites. The inclusion of any links does not necessarily imply a recommendation or endorse the views expressed within them. +Every effort is made to keep the website up and running smoothly. However, we take no responsibility for, and will not be liable for, the website being temporarily unavailable due to technical issues beyond our control.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_links.html b/cove/cove_360/templates/cove_360/components/terms/terms_links.html new file mode 100644 index 0000000..3f3bd2c --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_links.html @@ -0,0 +1,3 @@ + +

Links to other websites

+

Our website may contain links to other websites of interest. However, once you have used these links to leave our site, you should note that we do not have any control over that other website. Therefore, we cannot be responsible for the protection and privacy of any information which you provide whilst visiting such sites and such sites are not governed by this privacy statement. You should exercise caution and look at the privacy statement applicable to the website in question.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_privacy.html b/cove/cove_360/templates/cove_360/components/terms/terms_privacy.html new file mode 100644 index 0000000..05b7fc6 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_privacy.html @@ -0,0 +1,22 @@ + + +

Privacy Notice

+ +{% include "terms_privacy_intro.html" %} + +

You have the following rights concerning this data:

    +
  • Right to be informed, which is the purpose of this privacy notice
  • +
  • Right to Access, Rectification, Erasure, and to Restrict Processing. Note that the right to Erasure and Restrict Processing are balanced against our legitimate interests. Where relevant, you need to provide information to re-identify yourself from our pseudonymised data, see GDPR Article 11
  • +
  • Right to object to our processing.
  • +

+ +

Our supervisory authority is the ICO in the UK. You have the right to lodge a complaint with them.

+ +

We process personal data for the following purposes:

    +
  • Understanding website visitor and traffic patterns
  • +
  • Understanding server behaviour
  • +
  • Identifying and being alerted to software errors
  • +

+ +We rely on legitimate interests (GDPR Article 6(1)(f)) as the lawful basis for this processing. Details about the type of data, the purpose of the processing and legitimate interests, and the storage and retention of the data are set out below. + diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_privacy_intro.html b/cove/cove_360/templates/cove_360/components/terms/terms_privacy_intro.html new file mode 100644 index 0000000..f2079ee --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_privacy_intro.html @@ -0,0 +1,18 @@ +

+{% if app == 'cove_360' %}360Giving{% endif %} +{% if app == 'cove_iati' %}Open Data Services Co-operative Limited{% endif %} +is committed to ensuring that your privacy is protected. This privacy notice sets out how we collect and process any personal data when you use this website.

+ +

We may change this notice from time to time by updating this page. This notice is effective from 24th May 2018.

+ +

Data controller:
+{% if app == 'cove_360' %} + 360Giving, c/o Esmée Fairbairn Foundation, King's Place, 90 York Way, London, N1 9AG. +{% elif app == 'cove_iati' %} + Open Data Services Co-operative Limited, 1st Floor, Holyoake House, Hanover Street, Manchester, Greater Manchester, England, M60 0AS. inbox+opendataservices+443f+data-protection@plan.io. +{% endif %} +
Contact us if would like a copy of the information held on you or if you believe that any information we are holding on you is incorrect or incomplete. +{% if app == 'cove_360' %} + You can contact us by email at: info@threesixtygiving.org +{% endif %} +

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_security.html b/cove/cove_360/templates/cove_360/components/terms/terms_security.html new file mode 100644 index 0000000..8ed54d7 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_security.html @@ -0,0 +1,3 @@ + +

Security

+

We are committed to ensuring that your information is secure. In order to prevent unauthorised access or disclosure, we have put in place suitable physical, electronic and managerial procedures to safeguard and secure the information we collect online.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_tracker_data_controller_international.html b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_data_controller_international.html new file mode 100644 index 0000000..e69de29 diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_tracker_matmo.html b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_matmo.html new file mode 100644 index 0000000..5b04c2c --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_matmo.html @@ -0,0 +1,23 @@ + + + +

Personal data we collect:

    +
  • Your IP address - this is pseudonymised by redacting the second half of the address
  • +
  • Referrer (what page you arrived at one of our web pages from)
  • +
  • Information about your device, OS and browser
  • +
We do not use this data to personally identify individuals, but it is possible that it could be used to do so, particularly if combined with other datasets.

+ +

You can opt out of this processing: +If you have set your web browser to "I do not want to be tracked" (DoNotTrack is enabled) then Matomo will not track your visit.

+ +

Matomo also it’s own opt out mechanism:

+ + + +

Data processors: {% if app != 'cove_iati' %}Open Data Services Co-operative Limited, {% endif %}Bytemark.

+ +{% include "terms_tracker_data_controller_international.html" %} + +{% include "terms_tracker_no_international.html" %} + +

The data is kept indefinitely, in pseudonymised form.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_tracker_no_international.html b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_no_international.html new file mode 100644 index 0000000..e1e08f3 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_no_international.html @@ -0,0 +1 @@ +

No data is transferred to third countries or international organisations.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_tracker_sentry.html b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_sentry.html new file mode 100644 index 0000000..0f67bc6 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_sentry.html @@ -0,0 +1,19 @@ +{% if sentry_dsn %} + +

Identifying and being alerted to software errors

+ When an error occurs on our site, we record details about the visit that caused it. We use Sentry for this. + +

Data we collect:

    +
  • Your IP address
  • +
  • User agent (information about the OS and browser that you use)
  • +
  • Referrer (what page you arrived at one of our web pages from)
  • +
We do not use this data to personally identify individuals, but it is possible that it could be used to do so, particularly if combined with other datasets.

+ +

Data processors: {% if app != 'cove_iati' %}Open Data Services Co-operative Limited, {% endif %}Sentry (Functional Software, Inc.)

+ + {% include "terms_tracker_data_controller_international.html" %} + +

Data is transferred to Functional Software, Inc. who are based in the USA.

+

The data is kept for 90 days.

+ +{% endif %} diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_tracker_server.html b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_server.html new file mode 100644 index 0000000..5764daf --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_tracker_server.html @@ -0,0 +1,16 @@ +

Understanding server behaviour

+We collect data about your visits to the website in server logs. This is for the purpose of debugging network issues, monitoring server usage, and identifying malicious usage. + +

Personal data we collect:

    +
  • Your IP address
  • +
  • User agent (information about the OS and browser that you use)
  • +
  • Referrer (what page you arrived at one of our web pages from)
  • +
We do not use this data to personally identify individuals, but it is possible that it could be used to do so, particularly if combined with other datasets.

+ +

Data processors: {% if app != 'cove_iati' %}Open Data Services Co-operative Limited, {% endif %}Bytemark.

+ +{% include "terms_tracker_data_controller_international.html" %} + +{% include "terms_tracker_no_international.html" %} + +

The data is kept indefinitely.

diff --git a/cove/cove_360/templates/cove_360/components/terms/terms_trackers.html b/cove/cove_360/templates/cove_360/components/terms/terms_trackers.html new file mode 100644 index 0000000..5a19678 --- /dev/null +++ b/cove/cove_360/templates/cove_360/components/terms/terms_trackers.html @@ -0,0 +1,11 @@ +

Understanding website visitor and traffic patterns

+ +

We collect data about your visits to the website, for the purpose of analysing how the website is used, so that we can improve it. A self hosted copy of Matomo is used for this.

+ +{% include "terms_tracker_matmo.html" %} + +{% include "terms_tracker_google_analytics.html" %} + +{% include "terms_tracker_server.html" %} + +{% include "terms_tracker_sentry.html" %} diff --git a/cove/cove_360/templates/cove_360/data_loading.html b/cove/cove_360/templates/cove_360/data_loading.html index 1b57d0f..41bd4c7 100644 --- a/cove/cove_360/templates/cove_360/data_loading.html +++ b/cove/cove_360/templates/cove_360/data_loading.html @@ -4,54 +4,62 @@ {% block explore_content %} -
-
-

Data processing is in progress

-

Upload data complete, data is now processing … - spinner -

-
    -
  • Converting data into machine readable format (JSON)
  • -
  • Running validation tests
  • -
  • Running quality tests
  • -
-
-
- -{% endblock %} - -{% block extrafooterscript %} +

Data processing is in progress

+

Upload data complete, data is now processing … +

+
+
+
+
+
+

+
    +
  • Converting data into machine readable format (JSON)
  • +
  • Running validation tests
  • +
  • Running quality tests
  • +
+
+ +async function updateStatus() { + try { + const response = await fetch(pollUrl); + const data = response.json(); + if (data.done) { + clearInterval(poller); + window.location.href = resultsUrl; + } + } catch { + console.error("Error updating status:", error); + window.location.href = resultsUrl; + } +} +const poller = setInterval(updateStatus, 5000); + + {% endblock %} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/error.html b/cove/cove_360/templates/cove_360/error.html new file mode 100644 index 0000000..062677b --- /dev/null +++ b/cove/cove_360/templates/cove_360/error.html @@ -0,0 +1,21 @@ +{% extends request.current_app_base_template %} +{% load i18n %} +{% block content %} +{# fixme this template isn't getting used #} +

{{ sub_title }}

+ + {{ msg | linebreaks }} + + {% include 'error_extra.html' %} + + {{ link_text }} + + +{% endblock %} + +{% block extrapiwik %} + +{% if piwik.dimension_map.page_type %} +_paq.push(['setCustomDimension', {{piwik.dimension_map.page_type}}, 'caught error']); +{% endif %} +{% endblock %} diff --git a/cove/cove_360/templates/cove_360/error_extra.html b/cove/cove_360/templates/cove_360/error_extra.html new file mode 100644 index 0000000..8be3804 --- /dev/null +++ b/cove/cove_360/templates/cove_360/error_extra.html @@ -0,0 +1,2 @@ +{% load i18n %} +

{% blocktrans %}If you think this is a bug, you can file an issue publicly on GitHub or {% endblocktrans %}{% trans "get in touch via email" %}{% if request.sentry.id %}, {% blocktrans %}referencing this error as {% endblocktrans %}{{ request.sentry.id }}{% endif %}. diff --git a/cove/cove_360/templates/cove_360/explore.html b/cove/cove_360/templates/cove_360/explore.html index 729f01a..e938745 100644 --- a/cove/cove_360/templates/cove_360/explore.html +++ b/cove/cove_360/templates/cove_360/explore.html @@ -1,828 +1,10 @@ {% extends 'explore.html' %} -{% load i18n %} -{% load humanize %} -{% load cove_tags %} -{% block header_button %} -{{block.super}} -

-{% endblock %} +{% block content %} +{% if submission_tool %} + {% include "cove_360/components/explore_publishing.html" %} +{% else %} + {% include "cove_360/components/explore_checking.html" %} +{% endif %} -{% block explore_content %} - - {% block data_supplied %} - - {% if "self_publishing" in data_status.supplied_data.parameters %} -
-
-

- {% if data_status.can_publish %} - - {% endif %} - {% trans "Submit your data" %}

-
-
- {% if data_status.can_publish %} -

{% trans "Submitting for:" %} {{publisher.name}}

-

{% trans "The data was checked and can now be submitted to the 360Giving Data Registry." %}

-

{% trans "Click the 'Submit your file' to fill out the 360Giving data file submission form. " %} {% trans "Guidance about using the submission form." %}

- Submit your file - {% endif %} - - {# Data passed, Domain not recognised/approved #} - {% if data_status.passed and not data_status.can_publish %} -

- {% blocktrans %} - Sorry you aren't able to submit this file because the domain name of the website hosting your file ({{source_url_domain}}) is not authorised for publishing 360Giving data. - {% endblocktrans %} -

-

- {% blocktrans %} - Please email 360Giving Helpdesk via support@threesixtygiving.org with the link to the file you want to submit to the Data Registry. - {% endblocktrans %} -

- {% endif %} - - {# Validation failed #} - {% if not data_status.passed %} -

{% blocktrans %}Sorry you aren't able to submit this file because it is not valid 360Giving data.{% endblocktrans %}

-

- {% blocktrans %} - Follow the feedback below to make the amendments needed to your data. Once your data passes the Data Quality tool checks, upload the updated file to your website and then restart the 360Giving data file submission process. - The data did not pass the checks and cannot be published. See results below. - {% endblocktrans %} -

- {% endif %} - - - -
-
- {% endif %} - -
-
-

- - {% trans "Summary: Your data at a glance" %} - -

-
-
-
-

- {% trans "Use this section to get an overview of the data and check if this was what you were expecting to see." %} -

-
-

- {% trans "A file was " %} - {% if source_url %} - {% trans "downloaded from " %} {{source_url}} - {% else %} - {% trans "uploaded " %} - {% endif %} - {% trans "on " %} {{created_date}}. -

- - {% if metadata %} -
- {% if metadata.publisher.logo %} -
- -
- {% endif %} -
- {% if metadata.publisher %} - Publisher: {{metadata.publisher.name}} ({{metadata.publisher.identifier}})
- {% endif %} - {% if metadata.accessURL %} - Website that contains this Dataset: {{metadata.accessURL}}
- {% endif %} - {% if metadata.identifier %} - Dataset Identifier: {{metadata.identifier}}
- {% endif %} - {% if metadata.version %} - 360 Giving Schema Version: {{metadata.version}}
- {% endif %} - {% if metadata.license %} - License: {{metadata.license}}
- {% endif %} - {% if extension_metadatas %} - Extensions: {% for extension_metadata in extension_metadatas %}{{extension_metadata.id}} {% endfor %}
- {% endif %} -
-
-
- {% endif %} - - {% if metadata.downloadURL or metadata.title %} -

- {% if metadata.title %} - {{metadata.title}} - {% endif %} - {% if metadata.downloadURL %} - Original Data Download - {% endif %} -

- {% endif %} - {% if metadata.description %} -

- {{metadata.description}} -

- {% endif %} - -
-

This file contains

-
    -
  • - {% blocktrans count n_funders=grants_aggregates.distinct_funding_org_identifier|length|default:0 %}Data about {{n_funders}} funder{% plural %}Data about {{n_funders}} funders{% endblocktrans %} -
  • -
  • - {% blocktrans count n_grants=grants_aggregates.count|default:0 %}There is {{n_grants}} grant{% plural %}There are {{n_grants}} grants {% endblocktrans %} - {% blocktrans count n_recipients=grants_aggregates.distinct_recipient_org_identifier|length|default:0 %}to {{n_recipients}} recipient organisation and {% plural %}to {{n_recipients}} recipient organisations and{% endblocktrans %} - {% blocktrans count n_recipients_individuals=grants_aggregates.recipient_individuals_count|default:0 %}{{n_recipients_individuals}} to a recipient individual {% plural %}{{n_recipients_individuals}} to recipient individuals{% endblocktrans %}. -
  • -
  • - {% blocktrans count n_grants=grants_aggregates.count|default:0 %}The grant was awarded {% plural %}The grants were awarded {% endblocktrans %} - {% if grants_aggregates.min_award_date == grants_aggregates.max_award_date %} - {% blocktrans with start_date=grants_aggregates.min_award_date %}on {{start_date}}.{% endblocktrans %} - {% else %} - {% blocktrans with start_date=grants_aggregates.min_award_date end_date=grants_aggregates.max_award_date %}between {{start_date}} and {{end_date}}.{% endblocktrans %} -
  • - {% endif %} - {% if metadata.issued %} -
  • - The file was issued on {{metadata.issued|slice:":10"}} -
  • - {% endif %} - {% if metadata.modified %} -
  • - The file was modified on {{metadata.modified|slice:":10"}} -
  • - {% endif %} - {% for currency_code, currency_aggregates in grants_aggregates.currencies.items %} -
  • - {% if currency_aggregates.count == 1 %} - {% if currency_aggregates.count == grants_aggregates.count %} - {% trans "The grant" %} - {% else %} - {% trans "1 grant" %} - {% endif %} - {% blocktrans with amount_awarded=currency_aggregates.total_amount|intcomma currency_symbol=currency_aggregates.currency_symbol|safe %} was awarded in {{currency_code}} with a value of {{currency_symbol}}{{amount_awarded}}.{% endblocktrans %} - {% else %} - {% if currency_aggregates.count == grants_aggregates.count %} - {% trans "The grants" %} - {% else %} - {{currency_aggregates.count}} {% trans "grants" %} - {% endif %} - {% blocktrans with n_grants=currency_aggregates.count total_amount=currency_aggregates.total_amount|intcomma max_amount=currency_aggregates.max_amount|intcomma min_amount=currency_aggregates.min_amount|intcomma currency_symbol=currency_aggregates.currency_symbol|safe %} were awarded in {{currency_code}} with a total value of {{currency_symbol}}{{total_amount}} and individual awards ranging from {{currency_symbol}}{{min_amount}} (lowest) to {{currency_symbol}}{{max_amount}} (highest).{% endblocktrans %} - {% endif %} -
  • - {% endfor %} - {% if csv_encoding and csv_encoding != "utf-8-sig" %} -
  • - {% blocktrans %} This file is not 'utf-8' encoded (it is {{csv_encoding}} encoded).{% endblocktrans %} -
  • - {% endif %} -
- -
-

{% blocktrans %}Do these results look correct?{% endblocktrans %}

-
    -
  • {% blocktrans %}Do the numbers of funders, grants and recipients match what you expect?{% endblocktrans %}
  • -
  • {% blocktrans %}Are the dates for the right time period?{% endblocktrans %}
  • -
  • {% blocktrans %}Do the currency and total value figures show the correct amounts?{% endblocktrans %}
  • -
-

{% blocktrans %}If any of this information appears incorrect, the feedback below will help you to investigate what happened. {% endblocktrans %}

- -
-

{% blocktrans %}About the feedback{% endblocktrans %}

-

{% blocktrans %}The feedback is split into several sections. Use the small arrow icon on the far right side to display or hide the details for each section.{% endblocktrans %}

-
    -
  • {% blocktrans %}a red cross indicates warnings or errors. These types of issues must be resolved before the data can be published and used alongside other valid 360Giving data. {% endblocktrans %}
  • -
  • {% blocktrans %}a green tick indicates that the file is valid 360Giving data. {% endblocktrans %}
  • -
  • {% blocktrans %}a question mark indicates additional checks which suggest ways to improve the quality or usefulness of the data. {% endblocktrans %}
  • -
-

A maximum of 10 additional checks can be displayed at once.

-

The check your data section allows you to review the data itself to help identify any issues.

-

If you make changes to the data prompted by this feedback, return here to upload the updated file for a new check. It may take several iterations to get the data to a state you are happy with and are ready to publish as open data.

- -
-

Getting further help

-

You can read about common data errors and what causes them in the Common Errors section.

-

Visit our Data Quality Dashboard to see the data quality of 360Giving data as a whole and for each individual publisher. If you have already published data, you can view your own publisher page there too. It provides insights into the key features that make the data useful for analysis to help publishers to identify opportunities for their data to be improved.

- - {% if conversion == 'flattenable' %} -
- - {% csrf_token %} -
- {% endif %} -
-
-
- {% endblock data_supplied %} - - {% block conversion %} - {% if conversion == 'unflatten' or conversion == 'flatten'%} -
-
-

- {% if conversion_warning_messages or conversion_error %} - - {% trans "Data conversion unsuccessful - " %} - {% else %} - - {% trans "Data conversion successful" %} - {% endif %} - {% if conversion_warning_messages %} - {% blocktrans count n_warnings=conversion_warning_messages|length %}{{n_warnings}} Error has been found{% plural %}{{n_warnings}} Errors have been found{% endblocktrans %} - {% endif %} - -

-
-
-
- {% if conversion == 'unflatten' %} -

{% trans "Before checking your data we needed to convert it to JSON" %}{% if conversion_error or conversion_warning_messages %}{% blocktrans %} but we were not able to do this successfully{% endblocktrans %}{% endif %}.

-
{% blocktrans %}This tool converts data into JSON because the 360Giving Data Standard uses a JSON Schema to describe the standard in a technical way.{% endblocktrans %}
- {% if conversion_error %} - {% blocktrans %}If a file cannot be converted to JSON it indicates that it cannot be correctly mapped to the standard and needs to be reviewed. If this is the case you should check the file and re-upload it once you’ve fixed the problem. The conversion errors below will give an indication of where the issue is.{% endblocktrans %} - {% endif %} -
- {% else %} -

We have converted your JSON data into spreadsheet format.

- {% if conversion_error %} -

{% blocktrans %}The JSON data could not be converted to spreadsheet due to the following error: {{conversion_error}}{% endblocktrans %}

- {% include 'error_extra.html' %} - {% endif %} - {% endif %} - {% if conversion_warning_messages %} -
-

{% trans "Conversion errors:" %}

-
    - {% for warning_message in conversion_warning_messages %} -
  • {{warning_message}}
  • - {% endfor %} -
-

{% trans "Please resolve this error, as well as any others found, and test the data again." %}

- {% endif %} -
-
-
- {% endif %} - {% endblock conversion %} - - {% block validation %} -
-
-

- {% if validation_errors or additional_closed_codelist_values %} - - {% trans "This data does not use the 360Giving Data Standard correctly" %} {% blocktrans count n_errors=validation_and_closed_codelist_errors_count %} {{n_errors}} Error.{% plural %}{{n_errors}} Errors {% endblocktrans %} - {% else %} - - {% trans "This data uses the 360Giving Data Standard correctly" %} - {% endif %} - -

-
-
-
-

- {% if validation_errors or additional_closed_codelist_values %} - {% trans "Sorry your data is not yet using the 360Giving Data Standard. We used the " %} - {% else %} - {% trans "Congratulations! Your data is using the 360Giving Data Standard. We used the " %} - {% endif %} - 360Giving JSON Package Schema - {% trans "to check this." %} -

-
{% trans "This means that the data" %} - {% if validation_errors or additional_closed_codelist_values %} - {% trans " does not meet " %} - {% else %} - {% trans " meets " %} - {% endif %} - - {% blocktrans %}the requirements of the 360Giving Data Standard.{% endblocktrans %} - {% blocktrans %} Making sure your data uses the standard correctly is important. Otherwise it cannot be used alongside other valid 360Giving data and cannot be included in 360Giving tools, such as GrantNav and 360Insights.{% endblocktrans %} -
- - {% if extension_metadatas %} -

{% trans "The 360Giving Data Standard was extended using these extensions:" %}

-
    - {% for extension_metadata in extension_metadatas %} -
  1. {{extension_metadata.title}} ({{extension_metadata.id}})
  2. - {% endfor %} -
- {% endif %} - - {% if validation_errors or additional_closed_codelist_values %} -
-

 {% trans "The following errors are preventing your data from being valid 360Giving data. Please use the feedback below to find and resolve the issues in your file" %}

-
- {% with validation_errors=validation_errors_grouped.required error_prefix='required-' %} - {% if validation_errors %} -
-
-

Missing Fields

-
-
-

Some or all of your entries were missing fields which are required by the 360Giving Data Standard.

- {% include "cove_360/validation_table.html" %} -
-
- {% for error_json, error_extra in validation_errors %} - {% with error=error_json|json_decode %} - {% cove_modal_errors className="validation-errors-"|concat:error_prefix|concat:forloop.counter modalTitle=error.message errorList=error_extra.values file_type=file_type full_table=True %} - {% endwith %} - {% endfor %} - {% endif %} - {% endwith %} - {% with validation_errors=validation_errors_grouped.format error_prefix='format-' %} - {% if validation_errors %} -
-
-

Incorrect Formats

-
-
-

Some or all of your entries have incorrectly formatted data.

- {% include "cove_360/validation_table.html" %} -
-
- {% for error_json, error_extra in validation_errors %} - {% with error=error_json|json_decode %} - {% cove_modal_errors className="validation-errors-"|concat:error_prefix|concat:forloop.counter modalTitle=error.message errorList=error_extra.values file_type=file_type full_table=True %} - {% endwith %} - {% endfor %} - {% endif %} - {% endwith %} - {% if additional_closed_codelist_values %} -
-
-

{% trans 'Codelist Errors' %}

-
-
-
-

Some or all of your entries do not use the 360Giving Data Standard codelists correctly.

-

{% blocktrans %}The fields below use closed codelists. When using these fields, you must use one of the pre-defined codelist values. If you use a value that is not on the relevant codelist, your data will not pass structural checks.{% endblocktrans %}

-
-

- {% with additional_codelist_values=additional_closed_codelist_values %} -
{% include "additional_codelist_values.html" %}
- {% endwith %} -
-
- {% endif %} - {% endif %} - {% with validation_errors=validation_errors_grouped.other error_prefix='other-' %} - {% if validation_errors %} -
-
-

Other

-
-
-

Other validation errors.

- {% include "cove_360/validation_table.html" %} -
-
- {% for error_json, error_extra in validation_errors %} - {% with error=error_json|json_decode %} - {% cove_modal_errors className="validation-errors-"|concat:error_prefix|concat:forloop.counter modalTitle=error.message errorList=error_extra.values file_type=file_type full_table=True %} - {% endwith %} - {% endfor %} - {% endif %} - {% endwith %} -
-
-
- {% endblock validation %} - - - {% block quality_accuracy %} - {% if quality_accuracy_checks_count %} -
-
-

- - {% trans "Data Quality Check: Incorrect values" %} - {% blocktrans count n_quality_accuracy_checks=quality_accuracy_checks_count %}{{n_quality_accuracy_checks}} Incorrect value check{% plural %}{{n_quality_accuracy_checks}} Incorrect value checks{% endblocktrans %} - -

-
-
- {% if quality_accuracy_checks_errored %} -
-
-
- {% blocktrans %}Quality checks failed due to an issue with the data. Fix some validation errors first.{% endblocktrans %} -
-
-
- {% endif %} - {% if quality_accuracy_checks %} -

{% blocktrans %}These checks highlight areas where your data may be incorrect or need further attention.{% endblocktrans %}

-
-
- {% blocktrans %} -

For each check we give feedback on the issue and what steps may be taken to resolve it.

-

Receiving this feedback does not mean the data is invalid, and it can be ignored when not relevant.

- {% endblocktrans %} -
-
- - - - - - - - - {% for message, json_location, spreadsheet_location in quality_accuracy_checks %} - - - {% if file_type == 'xlsx' or file_type == 'csv' %} - - {% else %} - - {% endif %} - - {% endfor %} - -
{% trans 'Check Description' %} {% trans 'First 3 Locations' %}
- {{ message.heading }}
{{ message.message }} -
-
    - {% for location in spreadsheet_location|slice:":3" %} -
  • Sheet: {{location.sheet}} Row: {{location.row_number}} {% if location.header %} Header: {{location.header}} {% endif %}
  • - {% endfor %} - {% if spreadsheet_location|length > 3 %} -
  • see all
  • - {% endif %} -
-
-
    - {% for location in json_location|slice:":3" %} -
  • {{location}}
  • - {% endfor %} - {% if json_location|length > 3 %} -
  • see all
  • - {% endif %} -
-
- {% endif %} -
- {% for message, json_location, spreadsheet_location in quality_accuracy_checks %} - {% with msg=message.heading %} - {% if file_type == 'json' %} - {% cove_modal_errors className="quality_accuracy-checks-"|concat:forloop.counter modalTitle=msg errorList=json_location file_type=file_type full_table=False %} - {% else %} - {% cove_modal_errors className="quality_accuracy-checks-"|concat:forloop.counter modalTitle=msg errorList=spreadsheet_location file_type=file_type full_table=False %} - {% endif %} - {% endwith %} - {% endfor %} -
- {% endif %} - {% endblock quality_accuracy %} - - {% block usefulness %} - {% if usefulness_checks_count %} -
-
-

- - {% trans "Data Quality Check: Usefulness" %} - {% blocktrans count n_usefulness_checks=usefulness_checks_count %} Usefulness checks{% plural %}{{n_usefulness_checks}} Usefulness checks{% endblocktrans %} - -

-
-
- {% if usefulness_checks_errored %} -
-
-
- {% blocktrans %}Usefulness checks failed due to an issue with the data. Fix some validation errors first.{% endblocktrans %} -
-
-
- {% endif %} - {% if usefulness_checks %} -

{% blocktrans %}These checks highlight ways the data could be made more useful.{% endblocktrans %}

-
-
- {% blocktrans %} -

These are the key features that make the data useful for analysis, which we recommend including in 360Giving data whenever possible.

-

Receiving this feedback does not mean the data is invalid and it can be ignored when not relevant.

-

Visit our Data Quality Dashboard to see the data quality of 360Giving data as a whole and for each individual publisher. If you have already published data, you can view your own publisher page there too. It provides insights into the key features that make the data useful for analysis to help publishers to identify opportunities for their data to be improved.

- - {% endblocktrans %} -
-
- - - - - - - - - {% for message, json_location, spreadsheet_location in usefulness_checks %} - - - {% if file_type == 'xlsx' or file_type == 'csv' %} - - {% else %} - - {% endif %} - - {% endfor %} - -
{% trans 'Check Description' %} {% trans 'First 3 Locations' %}
- {{ message.heading }}
{{ message.message }} -
-
    - {% for location in spreadsheet_location|slice:":3" %} -
  • Sheet: {{location.sheet}} Row: {{location.row_number}} {% if location.header %} Header: {{location.header}} {% endif %}
  • - {% endfor %} - {% if spreadsheet_location|length > 3 %} -
  • see all
  • - {% endif %} -
-
-
    - {% for location in json_location|slice:":3" %} -
  • {{location}}
  • - {% endfor %} - {% if json_location|length > 3 %} -
  • see all
  • - {% endif %} -
-
- {% endif %} -
- {% for message, json_location, spreadsheet_location in usefulness_checks %} - {% with msg=message.heading %} - {% if file_type == 'json' %} - {% cove_modal_errors className="usefulness-checks-"|concat:forloop.counter modalTitle=msg errorList=json_location file_type=file_type full_table=False %} - {% else %} - {% cove_modal_errors className="usefulness-checks-"|concat:forloop.counter modalTitle=msg errorList=spreadsheet_location file_type=file_type full_table=False %} - {% endif %} - {% endwith %} - {% endfor %} -
- {% endif %} - {% endblock usefulness %} - - {% block additional_fields %} - {% if additional_fields_count %} -
-
-

- - {% trans "Additional Fields" %} - {% blocktrans count n_additional_fields=additional_fields_count %} Additional fields{% plural %}{{n_additional_fields}} Additional fields{% endblocktrans %} - -

-
-
- {% if data_only %} -
-

{% blocktrans %} Additional fields which do not use 360Giving Data Standard titles were found in your data.{% endblocktrans %}

-

{% blocktrans %} You are welcome to include additional fields in your data, however please check the field title(s) shown below to confirm if they are intended additions and not the result of spelling or formatting mistakes in the title. Please refer to the Common Errors section to see the correctly formatted field titles for the required fields. {% endblocktrans %}

- {% include "additional_fields_table.html" %} - {% endif %} -
- {% for message, json_location, spreadsheet_location in additional_checks %} - {% with msg=message.heading %} - {% if file_type == 'json' %} - {% cove_modal_errors className="additional-checks-"|concat:forloop.counter modalTitle=msg errorList=json_location file_type=file_type full_table=False %} - {% else %} - {% cove_modal_errors className="additional-checks-"|concat:forloop.counter modalTitle=msg errorList=spreadsheet_location file_type=file_type full_table=False %} - {% endif %} - {% endwith %} - {% endfor %} -
- {% endif %} - {% endblock additional_fields %} - - {% block review %} -
-
-

- {% trans "Check your data" %} {% blocktrans count n_grants=grants_aggregates.count|default:0 %}{{n_grants}} Grant{% plural %}{{n_grants}} Grants{% endblocktrans %} - -

-
-
-
-

{% trans "Review your data." %}

-
- We recommend having a look over your data here. This table shows how the data looks after it has been converted. - {% if conversion_warning_messages or validation_errors or additional_fields_count %} - If anything seems unexpected this may be caused by any errors or warnings shown above. - {% endif %} -
-

{% trans "Click on the numbers below to see a list of unique identifiers." %}

- -
-
-
-
-
-

- {% trans 'Grants Table' %} -

-
-
- - - - - - - - - - - - {% for grant in grants|slice:":5000" %} - - - - - - - - {% endfor %} - -
idtitlecurrencyamountAwardeddateModified
{{grant.id}}{{grant.title }}{{grant.currency}}{{grant.amountAwarded}}{{grant.dateModified}}
-
-
-
-
-
-
-
- {% cove_modal_list className="unique-ids" modalTitle="Unique IDs" itemList=grants_aggregates.unique_ids %} - {% cove_modal_list className="distinct-funding-org-identifier" modalTitle="Funder Organisation IDs" itemList=grants_aggregates.distinct_funding_org_identifier %} - {% cove_modal_list className="distinct-recipient-org-identifier" modalTitle="Recipient Organisation IDs" itemList=grants_aggregates.distinct_recipient_org_identifier %} - {% endblock review %} - - {% block download_and_share %} -
-
-

- {% trans "Download data and share these results" %} - -

-
-
-
-

Share

-

{% trans "You can share these test results with others by using the following url:" %}

-
- {{ current_url }} -

{% trans "If your data is not suitable for sharing publicly, then you should treat this url with care. Only share it with people who have permission to access the data." %}

-
-

{% trans "After 7 days, the link will expire and the data will be deleted from our servers - so the results will no longer be available. You can revisit these results until then." %}

-

Download

-

{% trans "This application converts data in Excel and CSV format into JSON format, allowing you download the converted version." %}

-

{% trans "If your file is originally in JSON format select ‘Convert to Spreadsheet’ in the summary section to create an Excel version of the file." %}

- {% if not conversion_error and conversion != 'flattenable' %} -

{% trans "We provide the following formats to download:" %}

- - {% else %} -

(No downloads available as the conversion hasn't happened, or has errored).

- {% endif %} - {% if user.is_authenticated %} - - {% endif %} -
-
-
- {% endblock download_and_share %} - -{% endblock explore_content %} - -{% block extrafooterscript %} - {{ block.super }} - -{% endblock extrafooterscript %} - - -{% comment %} - -{% cove_modal_list className="duplicate-id-modal" modalTitle="Duplicate IDs" itemList=grants_aggregates.duplicate_ids %} -{% cove_modal_list className="funding-org-identifier-prefixes" modalTitle="Funding Organisation ID Prefixes" itemList=grants_aggregates.funding_org_identifier_prefixes %} -{% cove_modal_list className="funding-org-identifiers-unrecognised-prefixes" modalTitle="Unrecognised Funding Organisation ID Prefixes" itemList=grants_aggregates.funding_org_identifiers_unrecognised_prefixes %} -{% cove_modal_list className="recipient-org-identifier-prefixes" modalTitle="Recipient Organisation ID Prefixes" itemList=grants_aggregates.recipient_org_identifier_prefixes %} -{% cove_modal_list className="recipient-org-identifiers-unrecognised-prefixes" modalTitle="Unrecognised Recipient Organisation ID Prefixes" itemList=grants_aggregates.recipient_org_identifiers_unrecognised_prefixes %} - - -{% endcomment %} +{% endblock %} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/explore_advanced.html b/cove/cove_360/templates/cove_360/explore_advanced.html index 14fcd57..afc299c 100644 --- a/cove/cove_360/templates/cove_360/explore_advanced.html +++ b/cove/cove_360/templates/cove_360/explore_advanced.html @@ -139,11 +139,8 @@

Unrecognised Prefixes ({{grants_aggregates.recipient_org_identifiers_unrecog - - - -{% cove_modal_list className="duplicate-id-modal" modalTitle="Duplicate IDs" itemList=grants_aggregates.duplicate_ids %} -{% cove_modal_list className="unique-ids" modalTitle="Unique IDs" itemList=grants_aggregates.unique_ids %} +{% cove_360_modal_list className="duplicate-id-modal" modalTitle="Duplicate IDs" itemList=grants_aggregates.duplicate_ids %} +{% cove_360_modal_list className="unique-ids" modalTitle="Unique IDs" itemList=grants_aggregates.unique_ids %} {% endblock %} diff --git a/cove/cove_360/templates/cove_360/footer.html b/cove/cove_360/templates/cove_360/footer.html deleted file mode 100644 index 2b9cc90..0000000 --- a/cove/cove_360/templates/cove_360/footer.html +++ /dev/null @@ -1,89 +0,0 @@ -{% load i18n %} -{% load static %} - - diff --git a/cove/cove_360/templates/cove_360/home.html b/cove/cove_360/templates/cove_360/home.html new file mode 100644 index 0000000..62228dd --- /dev/null +++ b/cove/cove_360/templates/cove_360/home.html @@ -0,0 +1,65 @@ +{% extends 'base.html' %} +{% block 'content' %} +
+
+

{% blocktrans %}How to check your data{% endblocktrans %}

+ {% comment %}Translators: Paragraph that describes the application{% endcomment %} +

{% blocktrans %}Upload, paste or provide a link to data using the 360Giving Data Standard format, and this application will check whether it is valid 360Giving data, and provide feedback so that you can check for errors and see ways to improve its quality.{% endblocktrans %}

+

{% blocktrans %}The tool will convert between JSON, Excel and CSV formats, allowing you to download the original file, and the converted versions.{% endblocktrans %}

+

{% blocktrans %}This tool will: {% endblocktrans %}

+

{% blocktrans %} Check your data is valid.{% endblocktrans %}

+

{% blocktrans %}The term ‘valid‘ means the data includes the 10 core fields and the information has all the correct data formatting that is required by 360Giving Data Standard. When it passes these checks, you will know that it is formatted for use alongside other valid 360Giving data and can be included in 360Giving tools, such as GrantNav and 360Insights.{% endblocktrans %}

+

{% blocktrans %}It will not: {% endblocktrans %}

+

{% blocktrans %} Check your data is accurate.{% endblocktrans %}

+

{% blocktrans %} Check the data against your own open data policy.{% endblocktrans %}

+

{% blocktrans %} This means there may be further checks you need to carry out to make sure the information is accurate, and that the data does not include information that is unsuitable for publishing as open data. Read more about what to consider when publishing open grants data.{% endblocktrans %}

+ {% if request.path == "/" %} +

{% blocktrans %}Further guidance{% endblocktrans %}

+

{% blocktrans %}Read about common data errors and what causes them in the Common Errors section.{% endblocktrans %}

+

{% blocktrans %}To preview how this tool works, try loading some sample data.{% endblocktrans%}

+ {% endif %} +

{% blocktrans %}Formats{% endblocktrans %}

+

{% blocktrans %}The application accepts data in the formats set out in the {% endblocktrans %}360Giving Data Standard guidance.

+

{% blocktrans %}Acceptable files are: {% endblocktrans %}

+
    +
  • {% blocktrans %}Summary Spreadsheet - OpenDocument Spreadsheet, Excel, CSV (UTF-8, Windows-1252 and ISO-8859-1 encodings supported){% endblocktrans %}
  • +
  • {% blocktrans %}JSON built to the 360Giving JSON schema (UTF-8 encoding supported){% endblocktrans %}
  • +
  • {% blocktrans %}Multi-table data package - Excel{% endblocktrans %}
  • +
+
+
+ +
+
+

{% blocktrans %}How to submit your data{% endblocktrans %}

+

{% blocktrans %} + Once 360Giving data has been published by an organisation, the file must be added to the 360Giving Data Registry so that the data to appear in 360Giving’s tools such as GrantNav and 360Insights. + {% endblocktrans %} +

+

{% blocktrans %} + Publishers of 360Giving data can add their valid 360Giving data files to the Data Registry using the 360Giving data file submission form. + {% endblocktrans %} +

+

{% blocktrans %}The submission form allows users to:{% endblocktrans %}

+
    +
  • Update an existing Data Registry entry with an updated version of an existing file
  • +
  • Add an entry for a new file to the Data Registry
  • +
+

Only publishers with an authorised website domain can use this submission process.

+ +

Authorised domains

+

By default, the website domain used by existing publishers to host their 360Giving data files will be authorised.

+

Organisations that publish 360Giving data for the first time can also use the 360Giving data file submission process once they have registered their website domain with 360Giving. To register to your website domain prior to publishing for the first time please contact 360Giving Helpdesk via support@threesixtygiving.org.

+

Publishers can opt out of authorising their website domain and using the 360Giving data file submission process on request.

+

Which domains are not authorised?

+

Data files published on multi-user hosting platforms like open data repositories, or file sharing services Google Sheets or Dropbox, cannot be authorised for use with the 360Giving data file submission process because the domain cannot be authorised as being unique to a particular organisation.

+

Files published in this way can be added to the 360Giving Data Registry by emailing 360Giving Helpdesk via support@threesixtygiving.org.

+

Further guidance

+

Read our full guidance on how to use the 360Giving data submission process.

+ +
+
+ + + +{% endblock %} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/input.html b/cove/cove_360/templates/cove_360/input.html index be8bbd8..d8bbd60 100644 --- a/cove/cove_360/templates/cove_360/input.html +++ b/cove/cove_360/templates/cove_360/input.html @@ -1,139 +1,93 @@ {% extends request.current_app_base_template %} -{% load bootstrap3 %} {% load i18n %} -{# For original input.html see lib-cove-web/cove/templates/input.html #} +{% load bootstrap3 %} {# this is needed for lib-cove-web stuff #} +{% block content %} -{% block precontent %} -
-
-

Check your data

-

Upload or provide a link to a file, or paste JSON to check and convert your data and get feedback on whether it is valid 360Giving data.

-
-
-{% endblock %} + +

Check your data

+

Upload, provide a link to a file, or paste JSON to check and convert your data and get feedback on whether it is valid 360Giving data. +To preview how this tool works, try loading some sample data.

+ -{% block content %} - -
+
{% if 'upload' in input_methods %} -
- -
-
-
{% csrf_token %} - {% bootstrap_form forms.upload_form %} - {% buttons %} - - {% endbuttons %} -
-
-
-
+ + + {% trans "Upload" %} + + {% endif %} + {% if 'url' in input_methods %} -
- -
-
-
{% csrf_token %} - {% bootstrap_form forms.url_form %} - {% buttons %} - - {% endbuttons %} -
-
-
-
+ + + {% trans "Link" %} + + {% endif %} + {% if 'text' in input_methods %} -
- -
-
-
{% csrf_token %} - {% bootstrap_form forms.text_form %} - {% buttons %} - - {% endbuttons %} -
-
-
+ + + {% trans "Paste" %} + + {% endif %} -
+ +
-{% endblock %} -{% block postcontent %} -{% if DATA_SUBMISSION_ENABLED %} -
-
-

Submit your data

-

Submit your 360Giving data file to the 360Giving Data Registry. Your file will also be checked to make sure you are submitting valid 360Giving data.

+{% if 'upload' in input_methods %} +
+
{% csrf_token %} + {% bootstrap_form forms.upload_form %} + {% buttons %} -
-
+ + {% endbuttons %} + +
+{% endif %} -
-
-
- {% csrf_token %} - -
- - -
-
- -

Read our guidance on how to submit your data.

-
-
-
+{% if 'url' in input_methods %} + +{% endif %} + +{% if 'text' in input_methods %} + {% endif %} -{% endblock %} -{% block extrafooterscript %} - -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/cove/cove_360/templates/cove_360/modal_errors.html b/cove/cove_360/templates/cove_360/modal_errors.html new file mode 100644 index 0000000..2113325 --- /dev/null +++ b/cove/cove_360/templates/cove_360/modal_errors.html @@ -0,0 +1,65 @@ +{% load i18n %} +{% load cove_tags %} + diff --git a/cove/cove_360/templates/cove_360/modal_list.html b/cove/cove_360/templates/cove_360/modal_list.html new file mode 100644 index 0000000..3276218 --- /dev/null +++ b/cove/cove_360/templates/cove_360/modal_list.html @@ -0,0 +1,14 @@ + diff --git a/cove/cove_360/templates/cove_360/more_info.html b/cove/cove_360/templates/cove_360/more_info.html index 6499417..4baac63 100644 --- a/cove/cove_360/templates/cove_360/more_info.html +++ b/cove/cove_360/templates/cove_360/more_info.html @@ -31,15 +31,3 @@

{% blocktrans %}More Information {% endblocktrans %}

- diff --git a/cove/cove_360/templates/cove_360/page_header.html b/cove/cove_360/templates/cove_360/page_header.html new file mode 100644 index 0000000..90da630 --- /dev/null +++ b/cove/cove_360/templates/cove_360/page_header.html @@ -0,0 +1,38 @@ +{% load i18n %} +{% block page_header %} + +{% endblock %} diff --git a/cove/cove_360/templates/cove_360/publisher_not_found.html b/cove/cove_360/templates/cove_360/publisher_not_found.html index fe396f8..d07a0a1 100644 --- a/cove/cove_360/templates/cove_360/publisher_not_found.html +++ b/cove/cove_360/templates/cove_360/publisher_not_found.html @@ -1,30 +1,30 @@ -{% extends "explore.html" %} +{% extends request.current_app_base_template %} {% load i18n %} -{% block content %} -
-
-

- {% if data_status.can_publish %} - - {% endif %} - {% trans "Submit your data" %}

-
-
-

{% blocktrans %}Sorry you aren't able to submit this file because the domain name of the website hosting your file ({{source_url_domain}}) is not authorised for publishing 360Giving data.{% endblocktrans %}

-

{% blocktrans %}Please email 360Giving helpdesk via support@threesixtygiving.org with the link to the file you want to submit to the Data Registry.{% endblocktrans %}

-
-
- + _paq.push(['trackEvent', 'Status', validation, source]); + _paq.push(['trackPageView']); + }); + {% endblock %} diff --git a/cove/cove_360/templates/cove_360/publishing.html b/cove/cove_360/templates/cove_360/publishing.html new file mode 100644 index 0000000..09d0def --- /dev/null +++ b/cove/cove_360/templates/cove_360/publishing.html @@ -0,0 +1,30 @@ +{% extends request.current_app_base_template %} + +{% block header_title %}360Giving Data Submission 11Tool{% endblock %} +{% block hero_title %}Data Submission Tool{% endblock %} +{% block hero_blurb %}Submit your 360Giving data file to be included in the 360Giving Data Registry and tools{% endblock %} + +{% block content %} + +{% if DATA_SUBMISSION_ENABLED %} +

Submit your data

+

Submit your 360Giving data file to the 360Giving Data Registry. The file will be checked using the Data Quality Tool to check it is valid 360Giving data.

+
+ {% csrf_token %} + + + + +
+

Read our guidance on how to submit your data.

+{% else %} +

Data submission for publishing is not enabled on this instance of the Data Quality Tool.

+{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/cove/cove_360/templates/cove_360/stats.html b/cove/cove_360/templates/cove_360/stats.html new file mode 100644 index 0000000..b94c08e --- /dev/null +++ b/cove/cove_360/templates/cove_360/stats.html @@ -0,0 +1,35 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block content %} +

{% trans "Usage stats" %}

+ + + + + + + + + + + + + {% for num_days, total, by_form in upload_by_time_by_form %} + + + + + + + + {% endfor %} + + + + + + + + +
{% trans "Upload" %}{% trans "Link" %}{% trans "Paste" %}{% trans "Total" %}
{% blocktrans %}Last{% endblocktrans %} {{num_days}} {% blocktrans %}days{% endblocktrans %}{{by_form.upload_form|default:"0"}}{{by_form.url_form|default:"0"}}{{by_form.text_form|default:"0"}}{{total}}
{% trans "Ever" %}{{total_by_form.upload_form|default:"0"}}{{total_by_form.url_form|default:"0"}}{{total_by_form.text_form|default:"0"}}{{uploaded}}
+{% endblock content %} diff --git a/cove/cove_360/templates/cove_360/terms.html b/cove/cove_360/templates/cove_360/terms.html new file mode 100644 index 0000000..1e82bf6 --- /dev/null +++ b/cove/cove_360/templates/cove_360/terms.html @@ -0,0 +1,31 @@ +{% extends request.current_app_base_template %} +{% load i18n %} +{% block content %} + {% with app=request.current_app %} +
+ {% comment %} + The content is split into many small templates. + This is so if one cove instance wants to change only one small bit of the page, they can do so by providing replacement templates of only the bit they want to change. + For example, a cove instance may want to keep most of the page the same but add legal content for another tracker. + {% endcomment %} + + {% include "terms_conditions.html" %} + + {% include "terms_cookies.html" %} + + {% include "terms_privacy.html" %} + + {% include "terms_trackers.html" %} + + {% include "terms_data_uploaded.html" %} + + {% include "terms_data_deleting.html" %} + + {% include "terms_security.html" %} + + {% include "terms_links.html" %} + + {% include "terms_disclaimer.html" %} +
+ {% endwith %} +{% endblock %} diff --git a/cove/cove_360/templates/cove_360/validation_table.html b/cove/cove_360/templates/cove_360/validation_table.html index 0f8ef37..0367555 100644 --- a/cove/cove_360/templates/cove_360/validation_table.html +++ b/cove/cove_360/templates/cove_360/validation_table.html @@ -1,22 +1,25 @@ {% load i18n %} {% load cove_tags %} - - - - - - +
{% trans 'Error Description' %}{% trans 'Error Count' %}{% trans 'First 3 Examples' %}
+ + + + + + {% if file_type != 'xlsx' and file_type != 'csv' %} - + {% endif %} - + {% for error_json, error_extra in validation_errors %} {% with error=error_json|json_decode %} + - {% if error_extra.spreadsheet_style_errors_table %}
{% trans 'Passed' %}{% trans 'Error Description' %}{% trans 'Error Count' %}{% trans 'First 3 Examples' %}{% trans 'Location of first 3 errors' %}{% trans 'Location of first 3 errors' %}
close +

{{ error | html_error_msg }} {% if error.message_type in common_error_types %} @@ -30,25 +33,27 @@

{{ error.schema_title }}

{% endif %}
+ + +

{{error_extra.values|length}}

{% if error_extra.values|length > 3 %} - {% if error_prefix %} - - {% else %} - - {% endif %} - {{error_extra.values|length}} - - {% else %} - {{error_extra.values|length}} + {% if error_prefix %} + {% endif %} +
+ {% for sheet, table in error_extra.spreadsheet_style_errors_table.items %} {% if sheet %} Sheet: {{sheet}} - +
{% for row in table %} {% with rowcounter=forloop.counter %} @@ -57,9 +62,9 @@

{{ error.schema_title }}

{% else %} {% if cell.type == 'example' %} - + {% else %} - + {% endif %} {% endif %} {% endfor %} @@ -73,9 +78,10 @@

{{ error.schema_title }}

{% else %} {% with values=error_extra.values %} diff --git a/cove/cove_360/templatetags/cove_tags.py b/cove/cove_360/templatetags/cove_tags.py index fb8bef9..65d4553 100644 --- a/cove/cove_360/templatetags/cove_tags.py +++ b/cove/cove_360/templatetags/cove_tags.py @@ -2,6 +2,7 @@ from cove.templatetags.cove_tags import register from django.utils.html import mark_safe from django.utils.translation import gettext_lazy as _ +from cove.templatetags.cove_tags import cove_modal_errors, cove_modal_list @register.filter(name='html_error_msg') @@ -23,3 +24,26 @@ def html_error_msg_360(error): )) return html_error_msg(error) + + +# wrap lib-cove-web implementation to provide our own template +@register.inclusion_tag("cove_360/modal_errors.html") +def cove_360_modal_errors(**context): + return cove_modal_errors(**context) + + +# wrap lib-cove-web implementation to provide our own template +@register.inclusion_tag("cove_360/modal_list.html") +def cove_360_modal_list(**context): + return cove_modal_list(**context) + + +@register.filter("multiply") +def multiply(a, b): + """ Multiple a,b if result is less than one output 1 decimal place otherwise as a rounded int""" + res = a*b + + if res < 1: + return f"{(a*b):.1f}" + + return int(round(res)) diff --git a/cove/cove_360/tests_functional.py b/cove/cove_360/tests/test_browser.py similarity index 55% rename from cove/cove_360/tests_functional.py rename to cove/cove_360/tests/test_browser.py index 79ab707..c0f78aa 100644 --- a/cove/cove_360/tests_functional.py +++ b/cove/cove_360/tests/test_browser.py @@ -20,6 +20,8 @@ PREFIX_360 = os.environ.get('PREFIX_360', '/') +settings.DISABLE_COOKIE_POPUP = True + # Ensure the correct version of chromedriver is installed try: chromedriver_autoinstaller.install() @@ -36,7 +38,10 @@ def wait_for_results_page(browser): @pytest.fixture(scope="module") def browser(request): - if BROWSER == 'ChromeHeadless': + if BROWSER == 'Chrome': + chrome_options = Options() + browser = webdriver.Chrome(chrome_options=chrome_options) + elif BROWSER == 'ChromeHeadless': chrome_options = Options() chrome_options.add_argument("--headless") # uncomment this if "DevToolsActivePort" error @@ -44,6 +49,7 @@ def browser(request): browser = webdriver.Chrome(chrome_options=chrome_options) else: browser = getattr(webdriver, BROWSER)() + browser.implicitly_wait(3) request.addfinalizer(lambda: browser.quit()) return browser @@ -58,11 +64,11 @@ def server_url(request, live_server): @pytest.mark.parametrize(('source_filename', 'expected_text', 'conversion_successful'), [ - ('fundingproviders-grants_fixed_2_grants.json', ['A file was downloaded from', - 'There are 4 grants to 2 recipient organisations and 0 to recipient individuals', + ('fundingproviders-grants_fixed_2_grants.json', ['There are 4 grants to 2 recipient organisations and 0 to recipient individuals', 'The grants were awarded in GBP with a total value of £662,990 and individual awards ranging from £152,505 (lowest) to £178,990 (highest)', 'Convert to Spreadsheet', - 'data does not use the 360Giving Data Standard correctly 15 Errors', + 'data does not use the 360Giving Data Standard correctly', + '15 Errors', 'your data is not yet using the 360Giving Data Standard', 'Incorrect Formats', 'Non-unique id values', @@ -70,33 +76,34 @@ def server_url(request, live_server): 'Unique grant identifiers: 2', 'Unique funder organisation identifiers: 1', '360G-fundingproviders-000002/X/00/X'], True), - ('fundingproviders-grants_broken_grants.json', ['data does not use the 360Giving Data Standard correctly 15 Errors', - 'Check your data 4 Grants', + ('fundingproviders-grants_broken_grants.json', ['data does not use the 360Giving Data Standard correctly', + '15 Errors', 'Unique funder organisation identifiers: 2', 'Unique recipient organisation identifiers: 2', '360G-fundingproviders-000002/X/00/X'], True), - ('fundingproviders-grants_2_grants.xlsx', ['Data about 1 funder', + ('fundingproviders-grants_2_grants.xlsx', ['1 funding organisation', 'There are 2 grants to 1 recipient organisation and 0 to recipient individuals', 'The grants were awarded in GBP with a total value of £331,495', # check that there's no errors after the heading 'Data conversion successful\nBefore checking', - 'data does not use the 360Giving Data Standard correctly 7 Errors', + 'data does not use the 360Giving Data Standard correctly', + '7 Errors', 'description is missing but required', 'Sheet: grants Row: 2', - 'Check your data 2 Grants', 'Unique funder organisation identifiers: 1', 'Unique recipient organisation identifiers: 1', '360G-fundingproviders-000002/X/00/X'], True), # Test conversion warnings are shown ('tenders_releases_2_releases.xlsx', ['Data conversion unsuccessful - 5 Errors have been found', - 'data does not use the 360Giving Data Standard correctly 76 Errors', + 'data does not use the 360Giving Data Standard correctly', + '76 Errors', 'You may have a duplicate Identifier: We couldn\'t merge these rows with the id "1": field "ocid" in sheet "items": one cell has the value: "PW-14-00627094", the other cell has the value: "PW-14-00629344"' ], True), # Test that titles that aren't in the rollup are converted correctly # (See @check_url_input_result_page). ('fundingproviders-grants_2_grants_titleswithoutrollup.xlsx', [], True), # Test a 360 csv in cp1252 encoding - ('fundingproviders-grants_2_grants_cp1252.csv', ['Data about 1 funder', + ('fundingproviders-grants_2_grants_cp1252.csv', ['1 funding organisation', 'There are 2 grants to 1 recipient organisation and 0 to recipient individuals', 'The grants were awarded in GBP with a total value of £331,495', 'This file is not \'utf-8\' encoded (it is cp1252 encoded)'], True), @@ -189,13 +196,8 @@ def test_explore_360_url_input(server_url, browser, httpserver, source_filename, with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: httpserver.serve_content(fp.read()) - if 'CUSTOM_SERVER_URL' in os.environ: - # Use urls pointing to GitHub if we have a custom (probably non local) server URL - source_url = 'https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/' + source_filename - if authed: - pytest.skip() - else: - source_url = httpserver.url + PREFIX_360 + source_filename + + source_url = httpserver.url + PREFIX_360 + source_filename if authed: User = get_user_model() @@ -203,38 +205,23 @@ def test_explore_360_url_input(server_url, browser, httpserver, source_filename, force_login(user, browser, server_url) browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - time.sleep(0.5) - browser.find_element_by_id('id_source_url').send_keys(source_url) - browser.find_element_by_css_selector("#fetchURL > div.form-group > button.btn.btn-primary").click() + + browser.find_element(By.ID, "link-tab-link").click() + browser.find_element(By.ID, "id_source_url").send_keys(source_url) + browser.find_element(By.ID, "submit-link-btn").click() # Wait for the various redirects after click wait_for_results_page(browser) - data_url = browser.current_url - - # Click and un-collapse all explore sections - all_sections = browser.find_elements_by_class_name('panel-heading') - browser.find_element_by_class_name("cookie-consent-no").click() - for section in all_sections: - if section.get_attribute('data-toggle') == "collapse" and section.get_attribute('aria-expanded') != 'true': - section.click() - time.sleep(0.5) + # reload results page with ?open-all=true to see all values at once + browser.get(f"{browser.current_url}?open-all=true") # Do the assertions check_url_input_result_page(server_url, browser, httpserver, source_filename, expected_text, conversion_successful, authed) - if conversion_successful: - # Expand all sections with the expand all button this time - browser.find_element_by_link_text('Expand all').click() - - browser.get(data_url + '/advanced') - assert 'Advanced view' in browser.find_element_by_tag_name('body').text - def check_url_input_result_page(server_url, browser, httpserver, source_filename, expected_text, conversion_successful, authed): - body_text = browser.find_element_by_tag_name('body').text + body_text = browser.find_element(By.TAG_NAME, 'body').text body_text += browser.page_source if isinstance(expected_text, str): @@ -246,36 +233,30 @@ def check_url_input_result_page(server_url, browser, httpserver, source_filename if source_filename == 'validation_errors-3.json': assert 'UNSAFE' not in body_text - assert 'Data Quality Tool' in browser.find_element_by_class_name('title360').text - assert '360Giving' in browser.find_element_by_tag_name('body').text - if conversion_successful: if source_filename.endswith('.json'): if authed: assert 'Original file (json)' in body_text - original_file = browser.find_element_by_link_text('Original file (json)').get_attribute("href") + original_file = browser.find_element(By.LINK_TEXT, 'Original file (json)').get_attribute("href") else: assert 'Original file (json)' not in body_text elif source_filename.endswith('.xlsx'): if authed: assert 'Original file (xlsx)' in body_text - original_file = browser.find_element_by_link_text('Original file (xlsx)').get_attribute("href") + original_file = browser.find_element(By.LINK_TEXT, 'Original file (xlsx)').get_attribute("href") else: assert 'Original file (xlsx)' not in body_text assert 'JSON (Converted from Original) ' in body_text - converted_file = browser.find_element_by_link_text("JSON (Converted from Original)").get_attribute("href") + converted_file = browser.find_element(By.LINK_TEXT, "JSON (Converted from Original)").get_attribute("href") assert "unflattened.json" in converted_file elif source_filename.endswith('.csv'): if authed: assert 'Original file (csv)' in body_text - original_file = browser.find_element_by_link_text('Original file (csv)').get_attribute("href") + original_file = browser.find_element(By.LINK_TEXT, 'Original file (csv)').get_attribute("href") else: assert 'Original file (csv)' not in body_text - converted_file = browser.find_element_by_link_text("JSON (Converted from Original)").get_attribute("href") - assert "unflattened.json" in browser.find_element_by_link_text("JSON (Converted from Original)").get_attribute("href") - - # Test for Load New File button - assert 'Load New File' in body_text + converted_file = browser.find_element(By.LINK_TEXT, "JSON (Converted from Original)").get_attribute("href") + assert "unflattened.json" in browser.find_element(By.LINK_TEXT, "JSON (Converted from Original)").get_attribute("href") if authed: assert 'Note that this box and this download link are only visible to admin users' in body_text @@ -310,10 +291,6 @@ def check_url_input_result_page(server_url, browser, httpserver, source_filename ]) @pytest.mark.parametrize('flatten_or_unflatten', ['flatten', 'unflatten']) def test_flattentool_warnings(server_url, browser, httpserver, monkeypatch, warning_args, flatten_or_unflatten, iserror): - # If we're testing a remove server then we can't run this test as we can't - # set up the mocks - if 'CUSTOM_SERVER_URL' in os.environ: - pytest.skip() if flatten_or_unflatten == 'flatten': source_filename = 'example.json' else: @@ -345,18 +322,28 @@ def mockflatten(input_name, output_name, *args, **kwargs): # flattentool behaviour with a mock below httpserver.serve_content('{}') source_url = httpserver.url + '/' + source_filename - browser.get(server_url + '?source_url=' + source_url) + + browser.get(server_url) + + browser.find_element(By.ID, "link-tab-link").click() + browser.find_element(By.ID, "id_source_url").send_keys(source_url) + browser.find_element(By.ID, "submit-link-btn").click() + + wait_for_results_page(browser) + + # The file conversion stuff is in the summary section of the results + # (which is the default tab) if source_filename.endswith('.json'): - browser.find_element_by_name("flatten").click() + browser.find_element(By.NAME, "flatten").click() - time.sleep(3) + time.sleep(2) - assert 'Warning' not in browser.find_element_by_tag_name("body").text + assert 'Warning' not in browser.find_element(By.TAG_NAME, "body").text warning_heading = "Data conversion unsuccessful - 1 Error has been found" - conversion_title = browser.find_element_by_id('conversion-title') + conversion_title = browser.find_element(By.ID, "conversion-errors") conversion_title_text = conversion_title.text if iserror: @@ -364,104 +351,12 @@ def mockflatten(input_name, output_name, *args, **kwargs): assert warning_heading in conversion_title_text else: assert warning_heading in conversion_title_text - # should be a cross - assert conversion_title.find_element_by_class_name('font-tick').get_attribute('class') == 'font-tick cross' - browser.find_element_by_class_name("cookie-consent-no").click() - conversion_title.click() - time.sleep(2) - assert warning_args[0] in browser.find_element_by_id('conversion-body').text + assert warning_args[0] in browser.find_element(By.ID, "conversion-area").text else: if flatten_or_unflatten == 'flatten': assert warning_heading not in conversion_title_text else: assert warning_heading not in conversion_title_text - # should be a tick - assert conversion_title.find_element_by_class_name('font-tick').get_attribute('class') == 'font-tick tick' - - -@pytest.mark.parametrize(('link_text', 'url'), [ - ('360Giving', 'https://www.threesixtygiving.org/'), - ('Publisher Guidance', 'https://standard.threesixtygiving.org/en/latest/'), - ('Common Errors', 'common_errors'), - ]) -def test_footer_360(server_url, browser, link_text, url): - browser.get(server_url) - link = browser.find_element_by_link_text(link_text) - href = link.get_attribute("href") - assert url in href - - -def test_index_page_360(server_url, browser): - browser.get(server_url) - assert 'Data Quality Tool' in browser.find_element_by_class_name('title360').text - assert 'How to check your data' in browser.find_element_by_tag_name('body').text - assert 'Summary Spreadsheet - ' in browser.find_element_by_tag_name('body').text - assert 'JSON built to the 360Giving JSON schema' in browser.find_element_by_tag_name('body').text - assert 'Multi-table data package - Excel' in browser.find_element_by_tag_name('body').text - assert '360Giving' in browser.find_element_by_tag_name('body').text - - -@pytest.mark.parametrize(('link_text', 'url'), [ - ('360Giving Data Standard guidance', 'https://standard.threesixtygiving.org/en/latest/technical/reference/#reference'), - ('Excel', 'https://threesixtygiving-standard.readthedocs.io/en/latest/_static/summary-table/360-giving-schema-titles.xlsx'), - ('CSV', 'https://standard.threesixtygiving.org/en/latest/technical/templates-csv/'), - ('360Giving JSON schema', 'https://standard.threesixtygiving.org/en/latest/reference/#giving-json-schemas'), - ('Multi-table data package - Excel', 'https://threesixtygiving-standard.readthedocs.io/en/latest/_static/multi-table/360-giving-schema-fields.xlsx') - ]) -def test_index_page_360_links(server_url, browser, link_text, url): - browser.get(server_url) - link = browser.find_element_by_link_text(link_text) - href = link.get_attribute("href") - assert url in href - - -def test_common_index_elements(server_url, browser): - browser.get(server_url) - browser.find_element_by_css_selector('#more-information .panel-title').click() - time.sleep(0.5) - assert 'What happens to the data I provide to this site?' in browser.find_element_by_tag_name('body').text - assert 'Why do you delete data after seven days?' in browser.find_element_by_tag_name('body').text - assert 'Why provide converted versions?' in browser.find_element_by_tag_name('body').text - assert 'Terms & Conditions' in browser.find_element_by_tag_name('body').text - assert '360Giving' in browser.find_element_by_tag_name('body').text - - -def test_terms_page(server_url, browser): - browser.get(server_url + 'terms/') - assert 'Open Data Services Co-operative Limited' in browser.find_element_by_tag_name('body').text - assert 'Open Data Services Limited' not in browser.find_element_by_tag_name('body').text - assert '360Giving' in browser.find_element_by_tag_name('body').text - - -def test_accordion(server_url, browser): - browser.get(server_url) - - def buttons(): - return [b.is_displayed() for b in browser.find_elements(By.CSS_SELECTOR, "#accordion button")] - - time.sleep(0.5) - assert buttons() == [True, False, False] - assert 'Upload a file' in browser.find_elements_by_tag_name('label')[0].text - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - browser.implicitly_wait(1) - time.sleep(0.5) - assert buttons() == [False, True, False] - browser.find_element_by_partial_link_text('Paste').click() - time.sleep(0.5) - assert buttons() == [False, False, True] - assert 'Paste (JSON only)' in browser.find_elements_by_tag_name('label')[2].text - - # Now test that the whole banner is clickable - browser.find_element_by_id('headingOne').click() - time.sleep(0.5) - assert buttons() == [True, False, False] - browser.find_element_by_id('headingTwo').click() - time.sleep(0.5) - assert buttons() == [False, True, False] - browser.find_element_by_id('headingThree').click() - time.sleep(0.5) - assert buttons() == [False, False, True] @pytest.mark.parametrize(('source_filename'), [ @@ -470,85 +365,44 @@ def buttons(): def test_error_modal(server_url, browser, httpserver, source_filename): with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: httpserver.serve_content(fp.read()) - if 'CUSTOM_SERVER_URL' in os.environ: - # Use urls pointing to GitHub if we have a custom (probably non local) server URL - source_url = 'https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/' + source_filename - else: - source_url = httpserver.url + '/' + source_filename + + source_url = httpserver.url + '/' + source_filename browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - time.sleep(0.5) - browser.find_element_by_id('id_source_url').send_keys(source_url) - browser.find_element_by_css_selector("#fetchURL > div.form-group > button.btn.btn-primary").click() - - time.sleep(1) - - # Click and un-collapse all explore sections - all_sections = browser.find_elements_by_class_name('panel-heading') - browser.find_element_by_class_name("cookie-consent-no").click() - for section in all_sections: - if section.get_attribute('data-toggle') == "collapse" and section.get_attribute('aria-expanded') != 'true': - section.click() - time.sleep(0.5) - table_rows = browser.find_elements_by_css_selector('.validation-errors-format-1 tbody tr') + browser.find_element(By.ID, "link-tab-link").click() + browser.find_element(By.ID, "id_source_url").send_keys(source_url) + browser.find_element(By.ID, "submit-link-btn").click() + + wait_for_results_page(browser) + + # reload results page with ?open-all=true to see all values at once + browser.get(f"{browser.current_url}?open-all=true") + + table_rows = browser.find_elements(By.CSS_SELECTOR, ".validation-errors-format-1 tbody tr") assert len(table_rows) == 4 - browser.find_element_by_css_selector('a[data-target=".validation-errors-format-2"]').click() + browser.find_element(By.CSS_SELECTOR, "button[data-target-class=\"validation-errors-format-2\"]").click() - modal = browser.find_element_by_css_selector('.validation-errors-format-2') - assert "in" in modal.get_attribute("class").split() + modal = browser.find_element(By.CSS_SELECTOR, '.validation-errors-format-2') + assert "modal--shown" in modal.get_attribute("class").split() modal_text = modal.text assert "24/07/2014" in modal_text assert "grants/0/awardDate" in modal_text - browser.find_element_by_css_selector('div.modal.validation-errors-format-2 button.close').click() - browser.find_element_by_css_selector('a[data-target=".usefulness-checks-2"]').click() + browser.find_element(By.CSS_SELECTOR, ".validation-errors-format-2 .modal__close").click() + + browser.find_element(By.CSS_SELECTOR, "button[data-target-class=\"usefulness-checks-2\"]").click() - modal_additional_checks = browser.find_element_by_css_selector('.usefulness-checks-2') - assert "in" in modal_additional_checks.get_attribute("class").split() + modal_additional_checks = browser.find_element(By.CLASS_NAME, "usefulness-checks-2") + assert "modal--shown" in modal_additional_checks.get_attribute("class").split() modal_additional_checks_text = modal_additional_checks.text assert "4 recipient organisation grants do not have recipient organisation location information" in modal_additional_checks_text assert "grants/0/recipientOrganization/0/id" in modal_additional_checks_text - table_rows = browser.find_elements_by_css_selector('.usefulness-checks-2 tbody tr') + table_rows = browser.find_elements(By.CSS_SELECTOR, ".usefulness-checks-2 tbody tr") assert len(table_rows) == 4 -@pytest.mark.parametrize(('source_filename', 'expected_text'), [ - ('fundingproviders-grants_fixed_2_grants.json', '360Giving JSON Package Schema') - ]) -def test_check_schema_link_on_result_page(server_url, browser, httpserver, source_filename, expected_text): - with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: - httpserver.serve_content(fp.read()) - if 'CUSTOM_SERVER_URL' in os.environ: - # Use urls pointing to GitHub if we have a custom (probably non local) server URL - source_url = 'https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/' + source_filename - else: - source_url = httpserver.url + '/' + source_filename - - browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - time.sleep(0.5) - browser.find_element_by_id('id_source_url').send_keys(source_url) - browser.find_element_by_css_selector("#fetchURL > div.form-group > button.btn.btn-primary").click() - - time.sleep(1) - - # Click and un-collapse all explore sections - all_sections = browser.find_elements_by_class_name('panel-heading') - browser.find_element_by_class_name("cookie-consent-no").click() - for section in all_sections: - if section.get_attribute('data-toggle') == "collapse" and section.get_attribute('aria-expanded') != 'true': - section.click() - time.sleep(0.5) - schema_link = browser.find_element_by_link_text(expected_text) - schema_link.click() - browser.find_element_by_id('giving-json-schemas') - - @pytest.mark.parametrize(('data_url'), [ reverse_lazy('results', args=['0']), reverse_lazy('results', args=['324ea8eb-f080-43ce-a8c1-9f47b28162f3']), @@ -557,81 +411,52 @@ def test_url_invalid_dataset_request(server_url, browser, data_url): # Test a badly formed hexadecimal UUID string # Trim the / off reverse_lazy result as server_url has trailing slash to avoid # e.g. //results/0 + browser.get("%s%s" % (server_url, data_url[1:])) - assert "We don't seem to be able to find the data you requested." in browser.find_element_by_tag_name('body').text + assert "We don't seem to be able to find the data you requested." in browser.find_element(By.TAG_NAME, 'body').text # Test for well formed UUID that doesn't identify any dataset that exists browser.get("%s%s" % (server_url, reverse_lazy('results', args=['38e267ce-d395-46ba-acbf-2540cdd0c810'])[1:])) - assert "We don't seem to be able to find the data you requested." in browser.find_element_by_tag_name('body').text - assert '360Giving' in browser.find_element_by_tag_name('body').text - #363 - Tests there is padding round the 'go to home' button - success_button = browser.find_element_by_class_name('success-button') - assert success_button.value_of_css_property('padding-bottom') == '20px' + assert "We don't seem to be able to find the data you requested." in browser.find_element(By.TAG_NAME, 'body').text + assert '360Giving' in browser.find_element(By.TAG_NAME, 'body').text def test_500_error(server_url, browser): browser.get(server_url + 'test/500') # Check that our nice error message is there - assert 'Something went wrong' in browser.find_element_by_tag_name('body').text - # Check for the exclamation icon - # This helps to check that the theme including the css has been loaded - # properly - icon_span = browser.find_element_by_class_name('panel-danger').find_element_by_tag_name('span') - assert 'Glyphicons Halflings' in icon_span.value_of_css_property('font-family') - assert icon_span.value_of_css_property('color') == 'rgba(255, 255, 255, 1)' + assert 'Something went wrong' in browser.find_element(By.TAG_NAME, 'body').text def test_common_errors_page(server_url, browser): browser.get(server_url + 'common_errors/') - assert "Common Errors" in browser.find_element_by_tag_name('h2').text - assert '360Giving' in browser.find_element_by_tag_name('h1').text - - -@pytest.mark.parametrize(('anchor_text'), [ - ('uri'), - ('date-time'), - ('required'), - ('enum'), - ('string'), - ('number') - ]) -def test_common_errors_page_anchors(server_url, browser, anchor_text): - # Checks we have sections for each our error messages - browser.get(server_url + 'common_errors/') - browser.find_element_by_id(anchor_text) + assert "Common Errors" in browser.find_element(By.TAG_NAME, 'body').text + assert '360Giving' in browser.find_element(By.TAG_NAME, 'body').text def test_favicon(server_url, browser): browser.get(server_url) # we should not have a favicon link just now with pytest.raises(NoSuchElementException): - browser.find_element_by_xpath("//link[@rel='icon']") + browser.find_element(By.XPATH, "//link[@rel='icon']") def test_explore_360_sample_data_link(server_url, browser): browser.get(server_url) - browser.find_element_by_id("load-sample-data-btn").click() + browser.find_element(By.ID, "load-sample-data-btn").click() wait_for_results_page(browser) - body_text = browser.find_element_by_tag_name('body').text + body_text = browser.find_element(By.TAG_NAME, 'body').text - assert 'Summary: Your data at a glance' in body_text - assert 'Sorry, we can\'t process that data' not in body_text - # Show sample data link in the home page only - with pytest.raises(NoSuchElementException): - browser.find_element_by_id("load-sample-data-btn") + assert "This data uses the 360Giving Data Standard correctly" in body_text def test_publishing_invalid_domain(server_url, browser): settings.DATA_SUBMISSION_ENABLED = True os.environ["REGISTRY_PUBLISHERS_URL"] = "https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/publishers.json" - browser.get(server_url) + browser.get(f"{server_url}/publishing") - # Dismiss the cookie popup - browser.find_element_by_class_name("cookie-consent-no").click() - - url_input = browser.find_element(By.CSS_SELECTOR, "#self-publishing-form input[type='url']") + url_input = browser.find_element(By.ID, "source-url-input") url_input.send_keys("https://raw.githubusercontent.com/OpenDataServices/grantnav-sampledata/master/grantnav-20180903134856.json") browser.find_element(By.ID, "submit-for-publishing-btn").click() @@ -647,32 +472,24 @@ def test_codelist_validation(server_url, browser, httpserver): with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: httpserver.serve_content(fp.read()) - if 'CUSTOM_SERVER_URL' in os.environ: - # Use urls pointing to GitHub if we have a custom (probably non local) server URL - source_url = 'https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/' + source_filename - else: - source_url = httpserver.url + '/' + source_filename + + source_url = httpserver.url + '/' + source_filename browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - time.sleep(0.5) - browser.find_element_by_id('id_source_url').send_keys(source_url) - browser.find_element_by_css_selector("#fetchURL > div.form-group > button.btn.btn-primary").click() - time.sleep(1) + browser.find_element(By.ID, "link-tab-link").click() + browser.find_element(By.ID, "id_source_url").send_keys(source_url) + browser.find_element(By.ID, "submit-link-btn").click() - browser.find_element_by_class_name("cookie-consent-no").click() - time.sleep(0.5) + wait_for_results_page(browser) + # reload results page with ?open-all=true to see all values at once + browser.get(f"{browser.current_url}?open-all=true") - # Click and un-collapse validation section - browser.find_element_by_id('validation-panel-heading').click() - time.sleep(0.5) + body_text = browser.find_element(By.TAG_NAME, "body").text - validation_body_text = browser.find_element_by_id('validation-body').text - assert "Codelist Errors" in validation_body_text - assert "BAD" in validation_body_text - assert "FRG010" not in validation_body_text + assert "Codelist Errors" in body_text + assert "BAD" in body_text + assert "FRG010" not in body_text def test_oneof_validation(server_url, browser, httpserver): @@ -680,32 +497,22 @@ def test_oneof_validation(server_url, browser, httpserver): with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: httpserver.serve_content(fp.read()) - if 'CUSTOM_SERVER_URL' in os.environ: - # Use urls pointing to GitHub if we have a custom (probably non local) server URL - source_url = 'https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/' + source_filename - else: - source_url = httpserver.url + '/' + source_filename + + source_url = httpserver.url + '/' + source_filename browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - time.sleep(0.5) - browser.find_element_by_id('id_source_url').send_keys(source_url) - browser.find_element_by_css_selector("#fetchURL > div.form-group > button.btn.btn-primary").click() - time.sleep(1) + browser.find_element(By.ID, "link-tab-link").click() + browser.find_element(By.ID, "id_source_url").send_keys(source_url) + browser.find_element(By.ID, "submit-link-btn").click() - browser.find_element_by_class_name("cookie-consent-no").click() - time.sleep(0.5) + wait_for_results_page(browser) + # reload results page with ?open-all=true to see all values at once + browser.get(f"{browser.current_url}?open-all=true") - # Click and un-collapse validation section - browser.find_element_by_id('validation-panel-heading').click() - time.sleep(0.5) + body_text = browser.find_element(By.TAG_NAME, "body").text - validation_body_text = browser.find_element_by_id('validation-body').text - assert "Only 1 of recipientOrganization or recipientIndividual is permitted, but both are present" in validation_body_text - validation_body_html = browser.find_element_by_id("validation-body").get_attribute("innerHTML") - assert "Only 1 of recipientOrganization or recipientIndividual is permitted, but both are present" in validation_body_html + assert "Only 1 of recipientOrganization or recipientIndividual is permitted, but both are present" in body_text @pytest.mark.parametrize(('source_filename', 'expected_texts', 'unexpected_texts'), [ @@ -731,46 +538,43 @@ def test_oneof_validation(server_url, browser, httpserver): "Sheet: grants Row: 3 Header: Beneficiary Location:Geographic Code", "Sheet: grants Row: 4 Header: Beneficiary Location:Geographic Code", ], []), + ("duration_usefulness.json", [ + "1 grant does not contain plannedDates/0/duration or (plannedDates/startDate and plannedDates/endDate)", + ], []), + ("additional_fields.json", [ + "Additional fields which do not use 360Giving Data Standard titles were found in your data.", + ], []), + ("multiple_fundiner_names_org_ids.json", [ + "introduced an additional name for an existing Funding Org" + ], []), ]) def test_quality_checks(server_url, browser, httpserver, source_filename, expected_texts, unexpected_texts): with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: httpserver.serve_content(fp.read()) - if 'CUSTOM_SERVER_URL' in os.environ: - # Use urls pointing to GitHub if we have a custom (probably non local) server URL - source_url = 'https://raw.githubusercontent.com/ThreeSixtyGiving/dataquality/main/cove/cove_360/fixtures/' + source_filename - else: - source_url = httpserver.url + '/' + source_filename + + source_url = httpserver.url + '/' + source_filename browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() - browser.find_element_by_partial_link_text('Link').click() - time.sleep(0.5) - browser.find_element_by_id('id_source_url').send_keys(source_url) - browser.find_element_by_css_selector("#fetchURL > div.form-group > button.btn.btn-primary").click() - time.sleep(1) + browser.find_element(By.ID, "link-tab-link").click() + browser.find_element(By.ID, "id_source_url").send_keys(source_url) + browser.find_element(By.ID, "submit-link-btn").click() - browser.find_element_by_class_name("cookie-consent-no").click() - time.sleep(0.5) + wait_for_results_page(browser) - try: - # Click and un-collapse quality accuracy section - browser.find_element_by_id('quality-accuracy-panel-heading').click() - time.sleep(0.5) + # reload results page with ?open-all=true to see all values at once + browser.get(f"{browser.current_url}?open-all=true") - quality_accuracy_body_text = browser.find_element_by_id('quality-accuracy-body').text - except NoSuchElementException: - quality_accuracy_body_text = "" + body_text = browser.find_element(By.TAG_NAME, 'body').text for expected_text in expected_texts: - assert expected_text in quality_accuracy_body_text, f"Expected: '{expected_text}'\nGot: '{quality_accuracy_body_text}'" + assert expected_text in body_text, f"Expected: '{expected_text}'\nGot: '{body_text}'" for unexpected_text in unexpected_texts: - assert unexpected_text not in quality_accuracy_body_text + assert unexpected_text not in body_text def test_file_submission(server_url, browser, httpserver): # This code doesn't work reliably on github actions. Leaving here for future refactoring efforts - return """ Test the file submission process works to the point of getting to the "submit" into the sales force form @@ -785,23 +589,35 @@ def test_file_submission(server_url, browser, httpserver): Hint: Skip this test via pytest -k "not test_file_submission" if file submission credentials aren't available. """ + settings.DATA_SUBMISSION_ENABLED = True - browser.get(server_url) - browser.find_element_by_class_name("cookie-consent-no").click() + source_filename = "publishers.json" + # Create a publishers registry entry + with open(os.path.join('cove_360', 'fixtures', source_filename), 'rb') as fp: + httpserver.serve_content(fp.read()) + + os.environ["REGISTRY_PUBLISHERS_URL"] = f"{httpserver.url}/{source_filename}" + + browser.get(f"{server_url}/publishing/") valid_for_publishing = "https://www.threesixtygiving.org/wp-content/uploads/love-kingston-funding-data-2018.xlsx" - browser.find_element_by_id("source-url-input").send_keys(valid_for_publishing) - browser.find_element_by_id("submit-for-publishing-btn").click() + url_input = browser.find_element(By.ID, "source-url-input") + url_input.send_keys(valid_for_publishing) - time.sleep(2) + browser.find_element(By.ID, "submit-for-publishing-btn").click() - # Await for the validation checks to finish for a max of 30s - count = 0 - while "results" not in browser.current_url and count < 30: - time.sleep(1) - count = count + 1 + wait_for_results_page(browser) - body_text = browser.find_element_by_tag_name("body").text + body_text = browser.find_element(By.TAG_NAME, "body").text assert "The data was checked and can now be submitted to the 360Giving Data Registry." in body_text, f"Expected '...can now be submitted' in {body_text}" + + +def test_cookie_popup(server_url, browser, httpserver): + """ Test that re-enabling the cookie popup does what we expect by including the cookie template """ + settings.DISABLE_COOKIE_POPUP = False + + browser.get(server_url) + + assert "Allow analytics" in browser.find_element(By.ID, "cookie-dialog-title").text diff --git a/cove/cove_360/test_hypothesis.py b/cove/cove_360/tests/test_hypothesis.py similarity index 100% rename from cove/cove_360/test_hypothesis.py rename to cove/cove_360/tests/test_hypothesis.py diff --git a/cove/cove_360/test_input.py b/cove/cove_360/tests/test_input.py similarity index 100% rename from cove/cove_360/test_input.py rename to cove/cove_360/tests/test_input.py diff --git a/cove/cove_360/tests.py b/cove/cove_360/tests/tests.py similarity index 100% rename from cove/cove_360/tests.py rename to cove/cove_360/tests/tests.py diff --git a/cove/cove_360/views.py b/cove/cove_360/views.py index 25c13b3..7ac3462 100644 --- a/cove/cove_360/views.py +++ b/cove/cove_360/views.py @@ -61,6 +61,23 @@ def explore_360(request, pk, template='cove_360/explore.html'): cached_context = cache.get(pk) if cached_context and not request.POST.get("flatten"): + + if request.GET.get("new-mode"): + try: + db_data = SuppliedData.objects.get(pk=pk) + data_params = json.loads(db_data.parameters) + del data_params["self_publishing"] + db_data.parameters = json.dumps(data_params) + db_data.save() + data_status, dsc = SuppliedDataStatus.objects.get_or_create( + supplied_data=db_data, + ) + cached_context["data_status"] = data_status + cache.set(pk, cached_context) + + except KeyError: + pass + print("Cache hit") return render(request, template, cached_context) @@ -82,6 +99,7 @@ def explore_360(request, pk, template='cove_360/explore.html'): # bail out early so user doesn't have to wait for validation to complete return render(request, "cove_360/publisher_not_found.html", context) data_status._publisher = json.dumps(publisher) + context["submission_tool"] = True context["publisher"] = publisher lib_cove_config = LibCoveConfig() @@ -163,11 +181,7 @@ def explore_360(request, pk, template='cove_360/explore.html'): re.sub(r'([A-Z])', r'-\1', codelist_info['codelist'].split('.')[0]).lower() ) - # Experimental to test performance impacts - # Note False will currently leave the grants table in the UI empty - do_grants_display = True - - if do_grants_display and hasattr(json_data, 'get') and hasattr(json_data.get('grants'), '__iter__'): + if settings.GRANTS_TABLE and hasattr(json_data, 'get') and hasattr(json_data.get('grants'), '__iter__'): context['grants'] = json_data['grants'] context['metadata'] = {} @@ -179,6 +193,7 @@ def explore_360(request, pk, template='cove_360/explore.html'): else: context['grants'] = [] context['metadata'] = {} + context["json_data"] = {} context['first_render'] = not db_data.rendered if not db_data.rendered: @@ -189,11 +204,53 @@ def explore_360(request, pk, template='cove_360/explore.html'): data_status.passed = context['validation_errors_count'] == 0 data_status.save() - cache.set(pk, context) + import pprint + pprint.pprint(context, stream=open("/tmp/dqt.py", "w"), indent=2) + try: + context["usefulness_categories"] = set([message["category"] for message, a, b in context["usefulness_checks"]]) + except TypeError: + # if no usefulness_checks the iteration will fail + context["usefulness_categories"] = [] + + try: + context["quality_accuracy_categories"] = set([message["category"] for message, a, b in context["quality_accuracy_checks"]]) + except TypeError: + # if no quality quality_accuracy categories the iteration will fail + context["quality_accuracy_categories"] = [] + + try: + context["quality_accuracy_checks_passed"] = create_passed_tests_context_data(context["quality_accuracy_checks"], TEST_CLASSES["quality_accuracy"]) + except Exception: + context["quality_accuracy_errored"] = True + + try: + context["usefulness_checks_passed"] = create_passed_tests_context_data(context["usefulness_checks"], TEST_CLASSES["usefulness"]) + except Exception: + context["usefulness_errored"] = True + + cache.set(pk, context) return render(request, template, context) +def create_passed_tests_context_data(failed_tests, available_tests): + """ Creates a list of test that have passed """ + + passed_tests_names = [test[0]["type"] for test in failed_tests] + passed_test_case_headings = [] + + for test in available_tests: + if test.__name__ in passed_tests_names: + continue + # We instantiate the test with no data to be able to utilise the heading formatting code + # TODO this may no longer be needed + # passed_test_case = test(grants=[], aggregates={"count": 0, "recipient_individuals_count": 0}) + # passed_test_case_headings.append(mark_safe(passed_test_case.format_heading_count(test.check_text["heading"]))) + passed_test_case_headings.append(test.__name__) + + return passed_test_case_headings + + def common_errors(request): return render(request, 'cove_360/common_errors.html') diff --git a/cove/cove_project/settings.py b/cove/cove_project/settings.py index a477fe1..bf5d982 100644 --- a/cove/cove_project/settings.py +++ b/cove/cove_project/settings.py @@ -127,3 +127,12 @@ if "true" in os.environ.get("DATA_SUBMISSION_ENABLED", "").lower(): DATA_SUBMISSION_ENABLED = True + +DISABLE_COOKIE_POPUP = False + +if "true" in os.environ.get("DISABLE_COOKIE_POPUP", "").lower(): + DISABLE_COOKIE_POPUP = True + +# If enabled the grants data can be used in a template to create a browsable +# table of grants. +GRANTS_TABLE = False diff --git a/cove/cove_project/urls.py b/cove/cove_project/urls.py index 6870092..3922e4d 100644 --- a/cove/cove_project/urls.py +++ b/cove/cove_project/urls.py @@ -2,6 +2,7 @@ from django.conf.urls.static import static from django.conf import settings from django.urls import path +from django.views.generic import TemplateView from cove.urls import urlpatterns, handler500 # noqa: F401 @@ -15,7 +16,9 @@ path("api/results/", cove_360.api.ResultsApiView.as_view(), name="api-results"), url(r'^xhr_results_ready/(.+)$', cove_360.views.results_ready, name='xhr_results_ready'), url(r'^common_errors', cove_360.views.common_errors, name='common_errors'), - url(r'^additional_checks', cove_360.views.additional_checks, name='additional_checks') + url(r'^additional_checks', cove_360.views.additional_checks, name='additional_checks'), + path("publishing/", TemplateView.as_view(template_name="cove_360/publishing.html"), name="publishing"), + path("terms-conditions/", TemplateView.as_view(template_name="cove_360/terms.html"), name="terms-conditions"), ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/lib360dataquality/additional_test.py b/lib360dataquality/additional_test.py new file mode 100644 index 0000000..22cf9d7 --- /dev/null +++ b/lib360dataquality/additional_test.py @@ -0,0 +1,113 @@ + +class TestType(object): + QUALITY_TEST_CLASS = "quality_accuracy" + USEFULNESS_TEST_CLASS = "usefulness" + + +class TestRelevance(object): + RECIPIENT_ANY = "" + RECIPIENT_ORGANISATION = "recipient organisation" + RECIPIENT_INDIVIDUAL = "recipient individual" + + +class TestCategories(object): + GRANTS = "Grants" + ORGANISATIONS = "Organisations" + DATA_PROTECTION = "Data Protection" + DATES = "Dates" + LOCATION = "Location" + METADATA = "Metadata" + + +class AdditionalTest(object): + category = TestCategories.GRANTS + + def __init__(self, **kw): + self.grants = kw["grants"] + self.aggregates = kw["aggregates"] + self.grants_percentage = 0 + self.json_locations = [] + self.failed = False + self.count = 0 + self.heading = None + self.message = None + # Default to the most common type + self.relevant_grant_type = TestRelevance.RECIPIENT_ANY + + def process(self, grant, path_prefix): + # Each test must implement this function which is called on each grant after + # the class is initialised. + # Set self.count, self.failed, self.heading and self.message + pass + + def produce_message(self): + return { + "heading": self.heading, + "message": self.message, + "type": self.__class__.__name__, + "count": self.count, + "percentage": self.grants_percentage, + "category": self.__class__.category, + } + + def get_heading_count(self, test_class_type): + # The total grants is contextual e.g. a test may fail for a recipient org-id + # this is only relevant to grants to organisations and not individuals + if self.relevant_grant_type == TestRelevance.RECIPIENT_ANY: + total = self.aggregates["count"] + elif self.relevant_grant_type == TestRelevance.RECIPIENT_ORGANISATION: + total = self.aggregates["count"] - self.aggregates["recipient_individuals_count"] + elif self.relevant_grant_type == TestRelevance.RECIPIENT_INDIVIDUAL: + # if there are no individuals in this data then reset the count + if self.aggregates["recipient_individuals_count"] == 0: + self.count = 0 + total = self.aggregates["recipient_individuals_count"] + + # Guard against a division by 0 + if total < 1: + total = 1 + + self.grants_percentage = self.count / total + + # Return conditions + + if test_class_type == TestType.QUALITY_TEST_CLASS: + return self.count + + if self.aggregates["count"] == 1 and self.count == 1: + self.grants_percentage = 1.0 + return f"1 {self.relevant_grant_type}".strip() + + if self.count <= 5: + return f"{self.count} {self.relevant_grant_type}".strip() + + return f"{round(self.grants_percentage*100)}% of {self.relevant_grant_type}".strip() + + def format_heading_count(self, message, test_class_type=None, verb="have"): + """Build a string with count of grants plus message + + The grant count phrase for the test is pluralized and + prepended to message, eg: 1 grant has + message, + 2 grants have + message or 3 grants contain + message. + """ + noun = "grant" if self.count == 1 else "grants" + + # Positive result - "what is working well" + # Avoid double negative + if not message.startswith("not have") and message.startswith("not") and self.count == 0: + message = message[len("not"):] + if message.startswith("not have") and self.count == 0: + verb = "do" + # End positive result flip + + if verb == "have": + verb = "has" if self.count == 1 else verb + elif verb == "do": + verb = "does" if self.count == 1 else verb + else: + # Naively! + verb = verb + "s" if self.count == 1 else verb + + return "{} {} {} {}".format( + self.get_heading_count(test_class_type), noun, verb, message + ) diff --git a/lib360dataquality/check_field_present.py b/lib360dataquality/check_field_present.py index 27087fa..794bbe7 100644 --- a/lib360dataquality/check_field_present.py +++ b/lib360dataquality/check_field_present.py @@ -1,4 +1,4 @@ -from lib360dataquality.cove.threesixtygiving import AdditionalTest, RECIPIENT_INDIVIDUAL +from lib360dataquality.additional_test import AdditionalTest, TestRelevance from functools import wraps @@ -109,7 +109,7 @@ class IndividualsCodeListsNotPresent(FieldNotPresentBase): def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_INDIVIDUAL + self.relevant_grant_type = TestRelevance.RECIPIENT_INDIVIDUAL def check_field(self, grant): # Not relevant diff --git a/lib360dataquality/cove/threesixtygiving.py b/lib360dataquality/cove/threesixtygiving.py index e787d3e..eefe3d2 100644 --- a/lib360dataquality/cove/threesixtygiving.py +++ b/lib360dataquality/cove/threesixtygiving.py @@ -14,6 +14,8 @@ from libcove.lib.common import common_checks_context, get_additional_codelist_values, get_orgids_prefixes, validator from libcove.lib.tools import decimal_default from rangedict import RangeDict as range_dict +from lib360dataquality.additional_test import AdditionalTest, TestType, TestCategories, TestRelevance +from lib360dataquality.check_field_present import PlannedDurationNotPresent try: from django.utils.html import mark_safe @@ -23,8 +25,6 @@ def mark_safe(string): return string -QUALITY_TEST_CLASS = "quality_accuracy" -USEFULNESS_TEST_CLASS = "usefulness" DATES_JSON_LOCATION = { "award_date": "/awardDate", @@ -392,7 +392,7 @@ def common_checks_360( # If no particular test classes are supplied then run all defined here if not test_classes: - test_classes = [QUALITY_TEST_CLASS, USEFULNESS_TEST_CLASS] + test_classes = [TestType.QUALITY_TEST_CLASS, TestType.USEFULNESS_TEST_CLASS] if context["file_type"] == "xlsx": try: @@ -428,6 +428,7 @@ def common_checks_360( json_data, cell_source_map, TEST_CLASSES[test_class_type], + # Set ignore_errors to False for debugging checks otherwise all exceptions will pass ignore_errors=True, return_on_error=None, aggregates=context["grants_aggregates"], @@ -515,89 +516,6 @@ def flatten_dict(grant, path=""): yield ("{}/{}".format(path, key), value) -RECIPIENT_ANY = "" -RECIPIENT_ORGANISATION = "recipient organisation" -RECIPIENT_INDIVIDUAL = "recipient individual" - - -class AdditionalTest: - def __init__(self, **kw): - self.grants = kw["grants"] - self.aggregates = kw["aggregates"] - self.grants_percentage = 0 - self.json_locations = [] - self.failed = False - self.count = 0 - self.heading = None - self.message = None - # Default to the most common type - self.relevant_grant_type = RECIPIENT_ANY - - def process(self, grant, path_prefix): - pass - - def produce_message(self): - return { - "heading": self.heading, - "message": self.message, - "type": self.__class__.__name__, - "count": self.count, - "percentage": self.grants_percentage, - } - - def get_heading_count(self, test_class_type): - # The total grants is contextual e.g. a test may fail for a recipient org-id - # this is only relevant to grants to organisations and not individuals - if self.relevant_grant_type == RECIPIENT_ANY: - total = self.aggregates["count"] - elif self.relevant_grant_type == RECIPIENT_ORGANISATION: - total = self.aggregates["count"] - self.aggregates["recipient_individuals_count"] - elif self.relevant_grant_type == RECIPIENT_INDIVIDUAL: - # if there are no individuals in this data then reset the count - if self.aggregates["recipient_individuals_count"] == 0: - self.count = 0 - total = self.aggregates["recipient_individuals_count"] - - # Guard against a division by 0 - if total < 1: - total = 1 - - self.grants_percentage = self.count / total - - # Return conditions - - if test_class_type == QUALITY_TEST_CLASS: - return self.count - - if self.aggregates["count"] == 1 and self.count == 1: - self.grants_percentage = 1.0 - return f"1 {self.relevant_grant_type}".strip() - - if self.count <= 5: - return f"{self.count} {self.relevant_grant_type}".strip() - - return f"{round(self.grants_percentage*100)}% of {self.relevant_grant_type}".strip() - - def format_heading_count(self, message, test_class_type=None, verb="have"): - """Build a string with count of grants plus message - - The grant count phrase for the test is pluralized and - prepended to message, eg: 1 grant has + message, - 2 grants have + message or 3 grants contain + message. - """ - noun = "grant" if self.count == 1 else "grants" - if verb == "have": - verb = "has" if self.count == 1 else verb - elif verb == "do": - verb = "does" if self.count == 1 else verb - else: - # Naively! - verb = verb + "s" if self.count == 1 else verb - return "{} {} {} {}".format( - self.get_heading_count(test_class_type), noun, verb, message - ) - - class ZeroAmountTest(AdditionalTest): """Check if any grants have an amountAwarded of 0. @@ -615,6 +533,8 @@ class ZeroAmountTest(AdditionalTest): "using the data to understand how to interpret the information." ) + category = TestCategories.GRANTS + def process(self, grant, path_prefix): try: # check for == 0 explicitly, as other falsey values will be caught @@ -629,7 +549,7 @@ def process(self, grant, path_prefix): self.heading = mark_safe( self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) ) self.message = self.check_text["message"][self.grants_percentage] @@ -657,9 +577,11 @@ class RecipientOrg360GPrefix(AdditionalTest): "for further help." ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): try: @@ -695,6 +617,8 @@ class FundingOrg360GPrefix(AdditionalTest): "for further help." ) + category = TestCategories.ORGANISATIONS + def process(self, grant, path_prefix): try: for num, organization in enumerate(grant["fundingOrganization"]): @@ -729,9 +653,11 @@ class RecipientOrgUnrecognisedPrefix(AdditionalTest): 'guidance on organisation identifiers for further help.' ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): try: @@ -754,7 +680,7 @@ def process(self, grant, path_prefix): self.heading = mark_safe( self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) ) self.message = self.check_text["message"][self.grants_percentage] @@ -778,6 +704,8 @@ class FundingOrgUnrecognisedPrefix(AdditionalTest): 'guidance on organisation identifiers for further help.' ) + category = TestCategories.ORGANISATIONS + def process(self, grant, path_prefix): try: count_failure = False @@ -799,7 +727,7 @@ def process(self, grant, path_prefix): self.heading = mark_safe( self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) ) self.message = self.check_text["message"][self.grants_percentage] @@ -828,9 +756,11 @@ class RecipientOrgCharityNumber(AdditionalTest): "ignored." ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): try: @@ -855,7 +785,7 @@ def process(self, grant, path_prefix): self.heading = mark_safe( self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) ) self.message = self.check_text["message"][self.grants_percentage] @@ -885,9 +815,11 @@ class RecipientOrgCompanyNumber(AdditionalTest): "in which case this message can be ignored." ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): try: @@ -909,7 +841,7 @@ def process(self, grant, path_prefix): self.heading = mark_safe( self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) ) self.message = mark_safe(self.check_text["message"][self.grants_percentage]) @@ -934,9 +866,11 @@ class NoRecipientOrgCompanyCharityNumber(AdditionalTest): "ignore this notice." ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): try: @@ -985,9 +919,11 @@ class IncompleteRecipientOrg(AdditionalTest): "for further help. " ) + category = TestCategories.LOCATION + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): try: @@ -1030,6 +966,8 @@ class MoreThanOneFundingOrg(AdditionalTest): "of funders is correct, then you can ignore this error notice." ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kw): super().__init__(**kw) self.funding_organization_ids = [] @@ -1080,6 +1018,8 @@ class LooksLikeEmail(AdditionalTest): "refers." ) + category = TestCategories.DATA_PROTECTION + def process(self, grant, path_prefix): flattened_grant = OrderedDict(flatten_dict(grant)) for key, value in flattened_grant.items(): @@ -1092,7 +1032,7 @@ def process(self, grant, path_prefix): self.heading = self.format_heading_count( self.check_text["heading"], - test_class_type=QUALITY_TEST_CLASS, + test_class_type=TestType.QUALITY_TEST_CLASS, verb="contain", ) self.message = self.check_text["message"][self.grants_percentage] @@ -1115,6 +1055,8 @@ class NoGrantProgramme(AdditionalTest): "organisation does not have grant programmes this notice can be ignored." ) + category = TestCategories.GRANTS + def process(self, grant, path_prefix): grant_programme = grant.get("grantProgramme") if not grant_programme: @@ -1149,6 +1091,8 @@ class NoBeneficiaryLocation(AdditionalTest): "for further help." ) + category = TestCategories.LOCATION + def process(self, grant, path_prefix): beneficiary_location = grant.get("beneficiaryLocation") if not beneficiary_location: @@ -1172,6 +1116,8 @@ class TitleDescriptionSame(AdditionalTest): "Consider including a more detailed description if you have one." ) + category = TestCategories.GRANTS + def process(self, grant, path_prefix): title = grant.get("title") description = grant.get("description") @@ -1196,6 +1142,8 @@ class TitleLength(AdditionalTest): "can quickly understand the purpose of the grant." ) + category = TestCategories.GRANTS + def process(self, grant, path_prefix): title = grant.get("title", "") if len(title) > 140: @@ -1223,9 +1171,11 @@ class GrantIdUnexpectedChars(AdditionalTest): " for further help." ) + category = TestCategories.GRANTS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ANY + self.relevant_grant_type = TestRelevance.RECIPIENT_ANY def process(self, grant, path_prefix): if "\n" in grant.get("id"): @@ -1234,7 +1184,7 @@ def process(self, grant, path_prefix): self.count += 1 self.heading = self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) self.message = self.check_text["message"][self.grants_percentage] @@ -1253,9 +1203,11 @@ class OrganizationIdUnexpectedChars(AdditionalTest): " See our guidance on organisation identifiers " " for further help.") + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): for org_type in ("fundingOrganization", "recipientOrganization"): @@ -1272,7 +1224,7 @@ def process(self, grant, path_prefix): self.count += 1 self.heading = self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) self.message = self.check_text["message"][self.grants_percentage] @@ -1297,9 +1249,11 @@ class OrganizationIdLooksInvalid(AdditionalTest): "for further help." ) + category = TestCategories.ORGANISATIONS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_ORGANISATION + self.relevant_grant_type = TestRelevance.RECIPIENT_ORGANISATION def process(self, grant, path_prefix): for org_type in ("fundingOrganization", "recipientOrganization"): @@ -1322,7 +1276,7 @@ def process(self, grant, path_prefix): self.count += 1 self.heading = self.format_heading_count( - self.check_text["heading"], test_class_type=QUALITY_TEST_CLASS + self.check_text["heading"], test_class_type=TestType.QUALITY_TEST_CLASS ) self.message = self.check_text["message"][self.grants_percentage] @@ -1342,6 +1296,8 @@ class NoLastModified(AdditionalTest): "users to see when changes have been made and reconcile differences between versions of your data." ) + category = TestCategories.METADATA + def process(self, grant, path_prefix): last_modified = grant.get("dateModified") if not last_modified: @@ -1373,6 +1329,8 @@ class NoDataSource(AdditionalTest): "website." ) + category = TestCategories.METADATA + def process(self, grant, path_prefix): data_source = grant.get("dataSource") if not data_source: @@ -1401,6 +1359,8 @@ class ImpossibleDates(AdditionalTest): "or the 29th of February in a year that's not a leap year. This error is commonly caused by typos during data entry." ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1457,6 +1417,8 @@ class PlannedStartDateBeforeEndDate(AdditionalTest): "This can also be caused by inconsistent date formatting when data was prepared using spreadsheet software." ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1495,6 +1457,8 @@ class ActualStartDateBeforeEndDate(AdditionalTest): "This can also be caused by inconsistent date formatting when data was prepared using spreadsheet software." ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1531,6 +1495,8 @@ class FarFuturePlannedDates(AdditionalTest): "errors if this isn't expected." ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1571,6 +1537,8 @@ class FarFutureActualDates(AdditionalTest): "if this isn't expected." ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1610,6 +1578,8 @@ class FarPastDates(AdditionalTest): "data is about activities far in the past, but you should check for data entry errors if this isn't expected." ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1660,6 +1630,8 @@ class PostDatedAwardDates(AdditionalTest): "includes grants that are not yet fully committed" ) + category = TestCategories.DATES + def process(self, grant, path_prefix): grant_dates = create_grant_dates_dict(Grant(grant)) @@ -1696,9 +1668,11 @@ class RecipientIndWithoutToIndividualsDetails(AdditionalTest): "individuals." ) + category = TestCategories.GRANTS + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_INDIVIDUAL + self.relevant_grant_type = TestRelevance.RECIPIENT_INDIVIDUAL def process(self, grant, path_prefix): if "recipientIndividual" in grant and "toIndividualsDetails" not in grant: @@ -1726,9 +1700,11 @@ class RecipientIndDEI(AdditionalTest): "identifiable when combined with other information in the grant." ) + category = TestCategories.DATA_PROTECTION + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_INDIVIDUAL + self.relevant_grant_type = TestRelevance.RECIPIENT_INDIVIDUAL def process(self, grant, path_prefix): if "recipientIndividual" in grant and "project" in grant: @@ -1768,9 +1744,11 @@ class GeoCodePostcode(AdditionalTest): "grant." ) + category = TestCategories.DATA_PROTECTION + def __init__(self, **kwargs): super().__init__(**kwargs) - self.relevant_grant_type = RECIPIENT_INDIVIDUAL + self.relevant_grant_type = TestRelevance.RECIPIENT_INDIVIDUAL def process(self, grant, path_prefix): if "recipientIndividual" in grant: @@ -1787,8 +1765,57 @@ def process(self, grant, path_prefix): self.message = self.check_text["message"][self.grants_percentage] +class MultiFundingOrgIdsForName(AdditionalTest): + """Check for Funding org ids with multiple names.""" + + check_text = { + "heading": mark_safe("introduced an additional name for an existing Funding Org"), + "message": RangeDict(), + } + check_text["message"][(0, 100)] = mark_safe( + "Your data contains Funding Org names with differing org-ids. " + "Funding organisations typically only have one name and one org-id." + ) + + category = TestCategories.ORGANISATIONS + + def __init__(self, **kw): + super().__init__(**kw) + # zxy-name: { names: [] } + self.funding_organisation_id_name = {} + + def process(self, grant, path_prefix): + for num, organisation in enumerate(grant["fundingOrganization"]): + org_id = organisation["id"] + name = organisation["name"] + + try: + names = self.funding_organisation_id_name[organisation["id"]] + except KeyError: + # initialise the data + names = [name] + self.funding_organisation_id_name[org_id] = names + + if name not in names: + # We have a brand new name for this org id, suspicious. + names.append(name) + self.json_locations.append( + path_prefix + "/fundingOrganization/{}/name".format(num) + ) + self.count = self.count + 1 + self.failed = True + + self.heading = self.format_heading_count(self.check_text["heading"]) + self.message = mark_safe(self.check_text["message"][self.grants_percentage]) + + + + +# Default tests run in CoVE, these are also the base list +# for the Quality Dashboard checks. TEST_CLASSES = { - QUALITY_TEST_CLASS: [ + # Quality = Accuracy tests in cove + TestType.QUALITY_TEST_CLASS: [ ZeroAmountTest, FundingOrgUnrecognisedPrefix, RecipientOrgUnrecognisedPrefix, @@ -1806,11 +1833,11 @@ def process(self, grant, path_prefix): FarFutureActualDates, FarPastDates, PostDatedAwardDates, - RecipientIndWithoutToIndividualsDetails, RecipientIndDEI, GeoCodePostcode, + MultiFundingOrgIdsForName, ], - USEFULNESS_TEST_CLASS: [ + TestType.USEFULNESS_TEST_CLASS: [ RecipientOrg360GPrefix, FundingOrg360GPrefix, NoRecipientOrgCompanyCharityNumber, @@ -1821,6 +1848,8 @@ def process(self, grant, path_prefix): TitleLength, NoLastModified, NoDataSource, + RecipientIndWithoutToIndividualsDetails, + PlannedDurationNotPresent, ], } @@ -1865,10 +1894,13 @@ def create_grant_dates_dict(grant): grant_dates = {} award_date = grant.grant.get("awardDate") - planned_start_date = grant.grant.get("plannedDates", [{}])[0].get("startDate") - planned_end_date = grant.grant.get("plannedDates", [{}])[0].get("endDate") - actual_start_date = grant.grant.get("actualDates", [{}])[0].get("startDate") - actual_end_date = grant.grant.get("actualDates", [{}])[0].get("endDate") + try: + planned_start_date = grant.grant.get("plannedDates", [{}])[0].get("startDate") + planned_end_date = grant.grant.get("plannedDates", [{}])[0].get("endDate") + actual_start_date = grant.grant.get("actualDates", [{}])[0].get("startDate") + actual_end_date = grant.grant.get("actualDates", [{}])[0].get("endDate") + except IndexError: + return {} for date_type, input_date in [ ["award_date", award_date], diff --git a/package.json b/package.json new file mode 100644 index 0000000..bfd33bf --- /dev/null +++ b/package.json @@ -0,0 +1,14 @@ +{ + "devDependencies": { + "eslint": "^8.29.0", + "eslint-config-semistandard": "^17.0.0", + "eslint-config-standard": "^17.0.0", + "eslint-plugin-html": "^7.1.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-n": "^15.6.0", + "eslint-plugin-promise": "^6.1.1" + }, + "engines": { + "node": ">=14.0.0" + } +}
{{cell}}{{cell.value}}"{{cell.value}}"{{cell.value}}"{{cell.value}}" +
    {% for value in values|slice:":3" %} -
  • {{value.value}}
  • +
  • "{{value.value}}"
  • {% endfor %}