diff --git a/Gemfile b/Gemfile index 19c12020..acfe37b7 100644 --- a/Gemfile +++ b/Gemfile @@ -30,8 +30,6 @@ gem 'bcrypt', '~> 3.1.7' # gem 'capistrano-rails', group: :development gem 'activerecord-import' -gem 'cells-rails' # TODO: remove -gem 'cells-slim' # TODO: remove gem 'chartkick' gem 'groupdate' gem 'hamlit' @@ -49,7 +47,6 @@ gem 'activeadmin' gem 'devise', '~> 4.4.0' # Monitoring & metrics -gem 'intercom-rails' # TODO: review gem 'rollbar' group :production do gem 'rails_12factor' @@ -63,7 +60,6 @@ group :development, :test do gem 'capybara' gem 'dotenv-rails' gem 'factory_bot_rails' - gem 'rspec-cells' # TODO: remove gem 'rspec-rails', '3.5.2' gem 'selenium-webdriver' gem 'stripe-ruby-mock', require: 'stripe_mock' diff --git a/Gemfile.lock b/Gemfile.lock index ccefb9d3..8136cd13 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -73,17 +73,6 @@ GEM rack (>= 1.6.0) rack-test (>= 0.6.3) xpath (~> 3.1) - cells (4.1.7) - declarative-builder (< 0.2.0) - declarative-option (< 0.2.0) - tilt (>= 1.4, < 3) - uber (< 0.2.0) - cells-rails (0.0.8) - actionpack (>= 3.0) - cells (>= 4.1.6, < 5.0.0) - cells-slim (0.0.5) - cells (>= 4.0.1, < 6.0.0) - slim (~> 3.0) chartkick (2.2.4) childprocess (0.9.0) ffi (~> 1.0, >= 1.0.11) @@ -102,9 +91,6 @@ GEM crass (1.0.4) dante (0.2.0) database_cleaner (1.6.1) - declarative-builder (0.1.0) - declarative-option (< 0.2.0) - declarative-option (0.1.0) devise (4.4.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) @@ -151,8 +137,6 @@ GEM has_scope (~> 0.6) railties (>= 4.2, <= 5.2) responders - intercom-rails (0.3.5) - activesupport (> 3.0) jbuilder (2.7.0) activesupport (>= 4.2.0) multi_json (>= 1.2) @@ -274,9 +258,6 @@ GEM netrc (~> 0.8) rollbar (2.16.3) multi_json - rspec-cells (0.3.4) - cells (>= 4.0.0, < 6.0.0) - rspec-rails (~> 3.2) rspec-core (3.5.4) rspec-support (~> 3.5.0) rspec-expectations (3.5.0) @@ -325,9 +306,6 @@ GEM activemodel (> 4, < 5.2) sitemap_generator (5.3.1) builder (~> 3.0) - slim (3.0.8) - temple (>= 0.7.6, < 0.9) - tilt (>= 1.3.3, < 2.1) slop (3.6.0) spring (2.0.2) activesupport (>= 4.2) @@ -359,7 +337,6 @@ GEM turbolinks-source (5.1.0) tzinfo (1.2.5) thread_safe (~> 0.1) - uber (0.1.0) uglifier (3.2.0) execjs (>= 0.3.0, < 3) unf (0.1.4) @@ -399,8 +376,6 @@ DEPENDENCIES bullet byebug capybara - cells-rails - cells-slim chartkick climate_control database_cleaner @@ -410,7 +385,6 @@ DEPENDENCIES groupdate hamlit hashids - intercom-rails jbuilder (~> 2.5) kaminari listen (>= 3.0.5, < 3.2) @@ -425,7 +399,6 @@ DEPENDENCIES rails_12factor redcarpet rollbar - rspec-cells rspec-rails (= 3.5.2) rubocop sass-rails (~> 5.0) diff --git a/app/admin/funder.rb b/app/admin/funder.rb index d16e0820..38c5322e 100644 --- a/app/admin/funder.rb +++ b/app/admin/funder.rb @@ -1,5 +1,5 @@ ActiveAdmin.register Funder do - permit_params :active, :microsite, :name, :primary_color, :secondary_color, + permit_params :active, :name, :primary_color, :secondary_color, :slug, :website controller do @@ -16,7 +16,6 @@ def find_resource link_to funder.name, [:admin, funder] end column :active - column :microsite column :funds do |funder| funder.funds.size end @@ -32,7 +31,6 @@ def find_resource row :charity_number row :company_number row :active - row :microsite row :primary_color row :secondary_color row :opportunities_last_updated_at @@ -42,7 +40,6 @@ def find_resource table_for funder.funds do column :slug column :active - column :microsite column :actions do |fund| link_to 'View', [:admin, fund] link_to 'Edit', [:edit_admin, fund] @@ -56,7 +53,6 @@ def find_resource f.input :slug f.input :name f.input :active - f.input :microsite f.input :primary_color, as: :string f.input :secondary_color, as: :string end diff --git a/app/admin/recipient.rb b/app/admin/recipient.rb index d5f947eb..09970910 100644 --- a/app/admin/recipient.rb +++ b/app/admin/recipient.rb @@ -1,66 +1,46 @@ ActiveAdmin.register Recipient do - permit_params :name, :contact_number, :website, :street_address, :city, - :region, :postal_code, :country, :charity_number, - :company_number, :founded_on, :registered_on, :mission, :status, - :registered, :active_on_beehive, organisation_ids: [] + permit_params :category_name, :charity_number, :company_number, :country, + :description, :district, :income_band_name, :name, + :operating_for_name, :website controller do + def scoped_collection + end_of_association_chain.includes(:country) + end + def find_resource - scoped_collection.where(slug: params[:id]).first! + scoped_collection.find_by_hashid(params[:id]) end end filter :name - filter :charity_number - filter :company_number - filter :country - filter :registered - filter :founded_on + filter :category_code filter :created_at + filter :updated_at index do selectable_column column :name - column :website + column :category_name column :country - column :org_type - column :street_address - column :postal_code - column :latitude - column :longitude + column :created_at actions end show do - tabs do - tab 'Overview' do - attributes_table do - row :id - row :name - row :mission - row :status - row :founded_on - row(:registered) { status_tag(recipient.registered) } - row :registered_on - row :contact_number - row :website - row :charity_number - row :company_number - row('Users') do |recipient| - recipient.users.each.map{|user| "
  • #{user.email} | Authorised: #{user.authorised}
  • "}.join("").html_safe - end - end - end - - tab 'Address' do - attributes_table do - row :street_address - row :city - row :region - row :postal_code - row :country - end - end + attributes_table do + row :id + row :name + row :category_name + row :description + row :charity_number + row :company_number + row :country + row :district + row :income_band_name + row :operating_for_name + row :website + row :user end end end diff --git a/app/admin/user.rb b/app/admin/user.rb index bf7b10ae..ee8a7080 100644 --- a/app/admin/user.rb +++ b/app/admin/user.rb @@ -17,7 +17,7 @@ column :last_seen actions column 'Action' do |user| - link_to 'Impersonate', impersonate_admin_user_path(user), target: '_blank' + link_to 'Impersonate', impersonate_admin_user_path(user), target: '_blank', rel: 'noopener' end end diff --git a/app/assets/stylesheets/custom.sass b/app/assets/stylesheets/custom.sass index 9dcd9648..8146cec3 100644 --- a/app/assets/stylesheets/custom.sass +++ b/app/assets/stylesheets/custom.sass @@ -9,6 +9,8 @@ max-width: 125px @media screen and (max-width: 25rem) max-width: 120px +.crumb + margin: 0 5px @media screen and (max-width: 46.875rem) .bread, .crumb display: none @@ -146,6 +148,16 @@ article.featured width: 32px height: 30px +nav + @media screen and (max-width: 30rem) + a + font-size: 15px + .mx20 + margin-left: 10px + margin-right: 10px + .ml20 + margin-left: 10px + #navbar-logo width: 106px height: 20px diff --git a/app/cells/breadcrumb/show.slim b/app/cells/breadcrumb/show.slim deleted file mode 100644 index e856dbd7..00000000 --- a/app/cells/breadcrumb/show.slim +++ /dev/null @@ -1,6 +0,0 @@ -.maxw1050.mx-auto.px15.fs14.mb30 - a.lh18.bread href= root_path class=@color Home - - model.each_with_index do |(k, v), i| - .crumb<> class=@color › - a.bread class=[disabled(v), bold(i), @color] href= v title=k - .lh18.truncate= k diff --git a/app/cells/breadcrumb_cell.rb b/app/cells/breadcrumb_cell.rb deleted file mode 100644 index 963dea25..00000000 --- a/app/cells/breadcrumb_cell.rb +++ /dev/null @@ -1,19 +0,0 @@ -class BreadcrumbCell < Cell::ViewModel - def show - return unless model.is_a?(Hash) && model.present? - - model.delete_if { |k, _v| k.nil? } - @color = options[:color] || 'white' - render - end - - private - - def bold(i) - i == model.size - 1 ? 'bold' : nil - end - - def disabled(v) - v.blank? ? "disabled #{@color}" : nil - end -end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1432274a..ff8d8af4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,8 +7,6 @@ class ApplicationController < ActionController::Base before_action :current_user - skip_after_action :intercom_rails_auto_include - rescue_from ActionController::InvalidAuthenticityToken, with: :bad_token rescue_from Pundit::NotAuthorizedError, with: :user_not_authorised rescue_from ActionController::UnknownFormat do diff --git a/app/helpers/breadcrumbs_helper.rb b/app/helpers/breadcrumbs_helper.rb new file mode 100644 index 00000000..9bb44bb0 --- /dev/null +++ b/app/helpers/breadcrumbs_helper.rb @@ -0,0 +1,24 @@ +module BreadcrumbsHelper + def breadcrumbs(hash = {}, color: 'white') + items = [] + + hash.each_with_index do |(text, link), i| + items << tag.div('›', class: "crumb #{color}") + + opts = link.blank? ? "disabled #{color}" : color + + items << tag.a( + tag.div(text, class: 'truncate'), + class: "bread #{opts}", href: link + ) + end + + return if items.empty? + + items.last.sub!('bread', 'bold bread') + + "
    " \ + "Home" \ + "#{items.join}
    ".html_safe + end +end diff --git a/app/helpers/reports_helper.rb b/app/helpers/reports_helper.rb index a0311278..49688cd1 100644 --- a/app/helpers/reports_helper.rb +++ b/app/helpers/reports_helper.rb @@ -6,6 +6,10 @@ def amount_sought(proposal = @proposal) "Between #{min} and #{max}" end + def created_by(recipient = @proposal.recipient) + recipient.individual? ? 'an individual' : recipient.name + end + def location_description(proposal = @proposal) "#{proposal.geographic_scale.capitalize} - " \ "#{proposal.countries.pluck(:name).to_sentence}" diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 6c41a366..4fc0cfca 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -9,7 +9,7 @@ def markdown(str, plain: false) options = { hard_wrap: true, space_after_headers: true, fenced_code_blocks: true, tables: true, footnotes: true, - link_attributes: { target: '_blank' } } + link_attributes: { target: '_blank', rel: 'noopener' } } extensions = { autolink: true, disable_indented_code_blocks: true } diff --git a/app/models/assessment.rb b/app/models/assessment.rb index 6a0410b8..b54dad9b 100755 --- a/app/models/assessment.rb +++ b/app/models/assessment.rb @@ -29,7 +29,7 @@ class Assessment < ApplicationRecord ]).freeze belongs_to :fund - belongs_to :proposal + belongs_to :proposal, counter_cache: true belongs_to :recipient validates :eligibility_status, inclusion: { @@ -45,6 +45,9 @@ def self.analyse(funds, proposal) def self.analyse_and_update!(funds, proposal) updates = analyse(funds, proposal) Assessment.import!(updates, on_duplicate_key_update: PERMITTED_COLUMNS) + Proposal.update_counters( + proposal.id, assessments_count: proposal.assessments.count + ) end def attributes diff --git a/app/models/fund.rb b/app/models/fund.rb index 371c7e0c..f5b3d987 100644 --- a/app/models/fund.rb +++ b/app/models/fund.rb @@ -58,8 +58,11 @@ class Fund < ApplicationRecord after_save do funder.touch(:opportunities_last_updated_at) themes.each { |t| t.touch(:opportunities_last_updated_at) } + update_counter_caches end + after_destroy :update_counter_caches + def description_html markdown(description) end @@ -93,6 +96,16 @@ def to_param private + def update_counter_caches + funder.active_opportunities_count = funder.funds.active.size + funder.save + + themes.each do |t| + t.active_opportunities_count = t.funds.active.size + t.save + end + end + def validate_integer_rules %i[ proposal_min_amount proposal_max_amount proposal_min_duration diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 85ef13f9..bb59f830 100755 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -122,6 +122,10 @@ def category_name CATEGORIES.values.reduce({}, :merge)[category_code] end + def description_with_default + description || 'No description provided'.html_safe + end + def identifier "##{id}" end @@ -155,6 +159,10 @@ def status end end + def title_with_default + title || 'No title provided'.html_safe + end + private def clear_districts_if_country_wide diff --git a/app/models/recipient.rb b/app/models/recipient.rb index ebc88444..34958134 100644 --- a/app/models/recipient.rb +++ b/app/models/recipient.rb @@ -35,7 +35,6 @@ class Recipient < ApplicationRecord belongs_to :district belongs_to :user, optional: true - has_one :subscription # TODO: remove after v3 has_one :proposal has_many :assessments @@ -69,10 +68,6 @@ class Recipient < ApplicationRecord message: 'enter a valid website address e.g. http://www.example.com' }, if: :website? - def name=(s) - self[:name] = s&.capitalize - end - def charity_number=(s) self[:charity_number] = s&.strip end diff --git a/app/models/subscription.rb b/app/models/subscription.rb deleted file mode 100644 index f5ca568a..00000000 --- a/app/models/subscription.rb +++ /dev/null @@ -1,4 +0,0 @@ -# TODO: remove after v3 -class Subscription < ApplicationRecord - belongs_to :recipient -end diff --git a/app/views/articles/index.html.haml b/app/views/articles/index.html.haml index c5357ea7..3f8a1be8 100644 --- a/app/views/articles/index.html.haml +++ b/app/views/articles/index.html.haml @@ -3,7 +3,7 @@ %main.bg-ice %header = render partial: 'shared/nav', locals: { color: 'blue' } - = cell(:breadcrumb, { 'Blog' => articles_path }, color: 'blue') + = breadcrumbs({ 'Blog' => articles_path }, color: 'blue') %section.col2.mx-auto.mb40.px15 %h1.h2.center Blog diff --git a/app/views/articles/show.html.haml b/app/views/articles/show.html.haml index 53c94863..b84f8611 100644 --- a/app/views/articles/show.html.haml +++ b/app/views/articles/show.html.haml @@ -3,7 +3,7 @@ %main.bg-ice %header = render partial: 'shared/nav', locals: { color: 'blue' } - = cell :breadcrumb, { 'Blog' => articles_path, @article.title => article_path(@article) }, color: 'blue' + = breadcrumbs({ 'Blog' => articles_path, @article.title => article_path(@article) }, color: 'blue') %section.col2.mx-auto.my40.px15 .bg-white.rounded.shadow diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 5d7a44f8..7f322594 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -17,14 +17,16 @@ %iframe{:height => "0", :src => "https://www.googletagmanager.com/ns.html?id=GTM-W3BQHWD", :style => "display:none;visibility:hidden", :width => "0"} - if !session[:read_cookies_notice] - .fs14.lh18.white.bg-night.pt20.px20.flex.items-center.justify-between.flex-wrap{ style: 'position: fixed; bottom: 0; z-index: 9999;' } - .mb20.md.f1 - We use cookies to give you the best experience on our website. In addition to strictly neccesary cookies, third party cookies may track your use of Beehive. If you continue without changing your settings, we'll assume that you are happy to receive all cookies. - = link_to 'More about cookies', 'https://cookiesandyou.com/', class: 'white bold underline', target: '_blank' - - .mb20.md.flex.justify-center - = link_to 'Change settings', privacy_path(anchor: 'cookies', read_cookies_notice: true), class: 'btn-sm white' - = link_to 'Continue', update_cookies_path(functional_cookies: true, performance_cookies: true, read_cookies_notice: true), class: 'btn-sm bg-blue white shadow' + .bg-night.border-bottom.border-slate.fs14.lh18.white + .maxw1050.mx-auto.pt15.px15 + .flex.flex-wrap + .mb15.md.col2 + We use cookies to give you the best experience on our website. In addition to strictly neccesary cookies, third party cookies may track your use of Beehive. If you continue without changing your settings, we'll assume that you are happy to receive all cookies. + = link_to 'More about cookies', 'https://cookiesandyou.com/', class: 'white bold underline', target: '_blank', rel: 'noopener' + + .mb15.md.col1.flex.justify-center.items-center + = link_to 'Change settings', privacy_path(anchor: 'cookies', read_cookies_notice: true), class: 'btn-sm white' + = link_to 'Continue', update_cookies_path(functional_cookies: true, performance_cookies: true, read_cookies_notice: true), class: 'btn-sm bg-blue white shadow' -# TODO: spec - if logged_in? && (@current_user&.update_version != UPDATE_VERSION) diff --git a/app/views/opportunities/index.html.haml b/app/views/opportunities/index.html.haml index 0d07b59d..bbbd436d 100644 --- a/app/views/opportunities/index.html.haml +++ b/app/views/opportunities/index.html.haml @@ -4,7 +4,7 @@ %header.bg-rich-blue = render partial: 'shared/nav', locals: { color: 'white' } - = cell(:breadcrumb, 'Opportunities' => opportunities_path) + = breadcrumbs('Opportunities' => opportunities_path) .maxw1050.mx-auto.px15 %h1.h2.white.mb10 Pick the opportunity you’d like a suitability report for… @@ -19,14 +19,14 @@ %h5.bold.slate Funding or support to offer? .p20.night .mb20 Do you provide grants or offer non- financial support to social sector organisations? Add your latest opportunities here, and we’ll get them listed on the website. - = link_to('Add opportunity', add_opportunity_form_url('opportunities'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank') + = link_to('Add opportunity', add_opportunity_form_url('opportunities'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank', rel: 'noopener') .border.border-mist.rounded.mb30 .p20.border-bottom.border-mist %h5.bold.slate Don’t see the opportunities you’d like a report for? .p20.night .mb20 Let us know which opportunity you’d like to check and we’ll create you a custom report for a small fee. - = link_to('Request custom report', add_opportunity_form_url('custom'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank') + = link_to('Request custom report', add_opportunity_form_url('custom'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank', rel: 'noopener') .col2.px15.grid - @opportunities.each do |opp| @@ -37,8 +37,7 @@ .caps.grey.mb5= opp.class %h3.mb10= opp.name - -# TODO: opportunities count - %p= pluralize(opp.funds.active.size, 'opportunity') + %p= pluralize(opp.active_opportunities_count, 'opportunity') .px20.pb20.flex = link_to 'Get report', new_recipient_path(opp), class: 'btn btn-wide white bg-blue' diff --git a/app/views/opportunities/show.html.haml b/app/views/opportunities/show.html.haml index 02905d5c..0e16f752 100644 --- a/app/views/opportunities/show.html.haml +++ b/app/views/opportunities/show.html.haml @@ -4,7 +4,7 @@ %header.bg-primary = render partial: 'shared/nav', locals: { color: 'white' } - = cell(:breadcrumb, 'Opportunities' => opportunities_path, @collection.name => opportunity_path(@collection)) + = breadcrumbs('Opportunities' => opportunities_path, @collection.name => opportunity_path(@collection)) .maxw1050.mx-auto.pb20 .flex.flex-wrap.white @@ -41,8 +41,7 @@ .f1 - unless report.private? .night.h6.bold.mb5 Proposal - -# TODO: default text for missing title from legacy record - .mb15= report.title + .mb15= report.title_with_default .night.h6.bold.mb5 Recipient .mb20 diff --git a/app/views/pages/add_opportunity.html.haml b/app/views/pages/add_opportunity.html.haml index 91c5a34e..e266619d 100644 --- a/app/views/pages/add_opportunity.html.haml +++ b/app/views/pages/add_opportunity.html.haml @@ -3,7 +3,7 @@ %main.bg-ice %header = render partial: 'shared/nav', locals: { color: 'blue' } - = cell(:breadcrumb, { 'Add an opportunity' => add_opportunity_path }, color: 'blue') + = breadcrumbs({ 'Add an opportunity' => add_opportunity_path }, color: 'blue') %section.col2.mx-auto .center @@ -16,7 +16,7 @@ %h1.bold.mb5 £50 .fs14.mb25.slate Per opportunity .mb20 You submit details about an opportunity and we’ll work with you to make sure it’s added quickly and correctly. - = link_to('Add verified opportunity', add_opportunity_form_url('verified'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank') + = link_to('Add verified opportunity', add_opportunity_form_url('verified'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank', rel: 'noopener') .px20.py25.bg-white.shadow.rounded.flex.flex-column.justify-between %div @@ -24,7 +24,7 @@ %h1.bold.mb5 £199 .fs14.mb25.slate Per opportunity per year .mb20 We gather all the details needed to add an opportunity, then add and manage it for you. - = link_to('Add managed opportunity', add_opportunity_form_url('managed'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank') + = link_to('Add managed opportunity', add_opportunity_form_url('managed'), class: 'btn btn-wide blue bg-light-blue border-pale-blue', target: '_blank', rel: 'noopener') .bg-ice = render partial: 'shared/footer', locals: { color: 'slate' } \ No newline at end of file diff --git a/app/views/pages/home.html.haml b/app/views/pages/home.html.haml index e6a9dc07..afced767 100644 --- a/app/views/pages/home.html.haml +++ b/app/views/pages/home.html.haml @@ -1,9 +1,7 @@ -= content_for :title, 'My reports' - %header.bg-ice = render partial: 'shared/nav', locals: { color: 'blue' } -%main.bg-ice.flex +%main.bg-ice.flex{ style: 'overflow-x: hidden;' } .maxw1050.mx-auto.mt40.flex.flex-wrap.items-center .col2.px15.mb40 %h1.bold.mb20 Save time and avoid wasted effort @@ -20,7 +18,7 @@ The option to click on a few additional questions to rule [funders] in or out was a HUGE bonus for me – it saved me trawling through myriad websites to ascertain whether or not our project was eligible for funding. .mt10.fs16.heading.bold.night Karen, - = link_to "Erb's Palsy Group", 'http://www.erbspalsygroup.co.uk/', target: '_blank' + = link_to "Erb's Palsy Group", 'http://www.erbspalsygroup.co.uk/', target: '_blank', rel: 'noopener' .col2.mb40 .col1.md.px15#hex diff --git a/app/views/pages/pricing.html.haml b/app/views/pages/pricing.html.haml index 4db9781e..204a1ce1 100644 --- a/app/views/pages/pricing.html.haml +++ b/app/views/pages/pricing.html.haml @@ -3,7 +3,7 @@ %main.bg-ice %header = render partial: 'shared/nav', locals: { color: 'blue' } - = cell(:breadcrumb, { 'Pricing' => pricing_path }, color: 'blue') + = breadcrumbs({ 'Pricing' => pricing_path }, color: 'blue') %section.col2.mx-auto.mb40 .center.px15 diff --git a/app/views/pages/privacy.html.haml b/app/views/pages/privacy.html.haml index 4175ba55..55340d2c 100644 --- a/app/views/pages/privacy.html.haml +++ b/app/views/pages/privacy.html.haml @@ -3,7 +3,7 @@ %main.bg-ice %header = render partial: 'shared/nav', locals: { color: 'blue' } - = cell(:breadcrumb, { 'Privacy' => privacy_path }, color: 'blue') + = breadcrumbs({ 'Privacy' => privacy_path }, color: 'blue') %section.col2.mx-auto.mb40.px15 .bg-white.rounded.shadow @@ -65,7 +65,7 @@ %p.mb20 We use cookies to give you the best experience on our website. In addition to strictly neccesary cookies, third party cookies may track your use of Beehive. If you continue without changing your settings (below), we'll assume that you are happy to receive all cookies. - = link_to 'More about cookies', 'https://cookiesandyou.com/', target: '_blank' + = link_to 'More about cookies', 'https://cookiesandyou.com/', target: '_blank', rel: 'noopener' %h4 Strictly Necessary Cookies .my15 diff --git a/app/views/pages/terms.html.haml b/app/views/pages/terms.html.haml index 1b99702e..79bf1fab 100644 --- a/app/views/pages/terms.html.haml +++ b/app/views/pages/terms.html.haml @@ -1,10 +1,9 @@ = content_for :title, 'Terms of Service' - %main.bg-ice %header = render partial: 'shared/nav', locals: { color: 'blue' } - = cell(:breadcrumb, { 'Terms' => terms_path }, color: 'blue') + = breadcrumbs({ 'Terms' => terms_path }, color: 'blue') %section.col2.mx-auto.mb40.px15 .bg-white.rounded.shadow @@ -76,10 +75,10 @@ Purchasing a 'Private' report is non-refundable. %li.mb5 All payments made through Beehive are processed by Stripe. Beehive does not store any of the information you submit while making a purchase. Should you choose to purchase a 'Private' report on Beehive, you understand and acknowledge that the purchase transaction and the collection of your information is governed by the - = link_to 'Stripe Terms of Service', 'https://stripe.com/gb/legal', target: '_blank', class: 'blue' + = link_to 'Stripe Terms of Service', 'https://stripe.com/gb/legal', target: '_blank', rel: 'noopener', class: 'blue' and the = succeed '.' do - = link_to 'Stripe Privacy Policy', 'https://stripe.com/gb/privacy', target: '_blank', class: 'blue' + = link_to 'Stripe Privacy Policy', 'https://stripe.com/gb/privacy', target: '_blank', rel: 'noopener', class: 'blue' %li.mb5 When making a payment you represent and warrant that: (i) you have the legal right to use any credit card(s) or other payment method(s) in connection with any purchase; and that (ii) the information you supply to us is true, correct and complete. %li diff --git a/app/views/proposals/new.html.haml b/app/views/proposals/new.html.haml index a75abf85..3e0274e3 100644 --- a/app/views/proposals/new.html.haml +++ b/app/views/proposals/new.html.haml @@ -6,8 +6,7 @@ .center.mb40 .fs32.px5.white.heading= collection_title(@collection) .fs16.py15.white Avoid wasted effort with a suitability report that helps you decide where to apply - -# TODO: opportunities count - .fs15.white.italic= pluralize(@collection.funds.active.size, 'opportunity') + .fs15.white.italic= pluralize(@collection.active_opportunities_count, 'opportunity') .bg-white.rounded.shadow @@ -119,7 +118,7 @@ .border-top.border-mist.pb10.pt30 .px20 .heading.fs18.bold.night.mb20 Consent - .mb20= u.input :terms_agreed, as: :boolean, label: false, inline_label: "I accept the #{link_to('terms of service', terms_path, target: '_blank')} and #{link_to('privacy policy', privacy_path, target: '_blank')} * ".html_safe + .mb20= u.input :terms_agreed, as: :boolean, label: false, inline_label: "I accept the #{link_to('terms of service', terms_path, target: '_blank', rel: 'noopener')} and #{link_to('privacy policy', privacy_path, target: '_blank', rel: 'noopener')} * ".html_safe .mb20= u.input :marketing_consent, as: :radio_buttons, required: true, label_html: { class: 'private' } .border-top.border-mist.p20 @@ -128,7 +127,7 @@ .mt10.mb20= f.input :public_consent, as: :boolean, label: false, inline_label: 'I understand', hint: false - = f.submit 'Get suitability report', class: 'btn-wide bg-rich-blue white shadow', data: { disable_with: 'Checking...' } + = f.submit 'Get suitability report', class: 'btn-wide bg-rich-blue white shadow', data: { disable_with: 'Creating report...' } .bg-dark-blue = render partial: 'shared/footer', locals: { color: 'white' } diff --git a/app/views/recipients/new.html.haml b/app/views/recipients/new.html.haml index f88e391a..d6255410 100644 --- a/app/views/recipients/new.html.haml +++ b/app/views/recipients/new.html.haml @@ -6,8 +6,7 @@ .center.mb40 .fs32.px5.white.heading= collection_title(@collection) .fs16.py15.white Avoid wasted effort with a suitability report that helps you decide where to apply - -# TODO: opportunities count - .fs15.white.italic= pluralize(@collection.funds.active.size, 'opportunity') + .fs15.white.italic= pluralize(@collection.active_opportunities_count, 'opportunity') .bg-white.rounded.shadow diff --git a/app/views/report_mailer/notify.html.haml b/app/views/report_mailer/notify.html.haml index bb2bd0f1..fdfd0af6 100644 --- a/app/views/report_mailer/notify.html.haml +++ b/app/views/report_mailer/notify.html.haml @@ -14,12 +14,12 @@ is ready. %p - = link_to('View full report', report_url(@proposal, t: @proposal.access_token), target: '_blank') - = link_to('All my reports', sign_in_lookup_url(email: @user.email), target: '_blank') + = link_to('View full report', report_url(@proposal, t: @proposal.access_token), target: '_blank', rel: 'noopener') + = link_to('All my reports', sign_in_lookup_url(email: @user.email), target: '_blank', rel: 'noopener') %p Please note %p Unless you opt to = succeed ',' do - = link_to('keep the report Private', new_charge_url(@proposal), target: '_blank') + = link_to('keep the report Private', new_charge_url(@proposal), target: '_blank', rel: 'noopener') it will be added to a publically viewable directory that others can browse. diff --git a/app/views/reports/index.html.haml b/app/views/reports/index.html.haml index 3647bbc2..17c4ec4d 100644 --- a/app/views/reports/index.html.haml +++ b/app/views/reports/index.html.haml @@ -4,7 +4,7 @@ %header.bg-rich-blue = render partial: 'shared/nav', locals: { color: 'white' } - = cell(:breadcrumb, 'My reports' => reports_path) + = breadcrumbs('My reports' => reports_path) .maxw1050.mx-auto.px15 %h1.h2.white.mb10 My reports @@ -30,14 +30,13 @@ Created = time_ago_in_words(report.created_at) ago - -# • - -# TODO: opportunities count + • + = pluralize(report.assessments_count, 'opportunity') .p20.flex.flex-column.f1 .f1 .night.h6.bold.mb5 Proposal - -# TODO: default text for missing title from legacy record - .mb15= report.title + .mb15= report.title_with_default .night.h6.bold.mb5 Recipient .mb20= recipient_name(report.recipient) diff --git a/app/views/reports/show.html.haml b/app/views/reports/show.html.haml index be10978d..fa45ff7c 100755 --- a/app/views/reports/show.html.haml +++ b/app/views/reports/show.html.haml @@ -6,9 +6,9 @@ = render partial: 'shared/nav', locals: { color: 'white' } -# TODO: spec - if @collection - = cell(:breadcrumb, 'Opportunities' => opportunities_path, @collection.name => opportunity_path(@collection), @proposal.identifier => report_path(@proposal)) + = breadcrumbs('Opportunities' => opportunities_path, @collection.name => opportunity_path(@collection), @proposal.identifier => report_path(@proposal)) - else - = cell(:breadcrumb, 'Opportunities' => opportunities_path, "Report #{@proposal.identifier}" => report_path(@proposal)) + = breadcrumbs('Opportunities' => opportunities_path, "Report #{@proposal.identifier}" => report_path(@proposal)) .maxw1050.mx-auto.px15.pb40 .flex.justify-between.white @@ -20,8 +20,7 @@ -# TODO: status -# .btn.border-white= @proposal.status.capitalize Created for - -# TODO: when individual? - = @proposal.recipient.name + = created_by = time_ago_in_words(@proposal.created_at) ago @@ -35,8 +34,7 @@ .mt40.flex.flex-wrap .col2.px15 %h3.bold.night.mb40 - -# TODO: opportunities count - = pluralize(@proposal.assessments.size, 'opportunity') + = pluralize(@proposal.assessments_count, 'opportunity') checked - @proposal.assessments.includes(fund: [:funder]).each do |a| @@ -54,9 +52,9 @@ -# TODO: truncate .mb15.markdown= raw(a.fund.description_html) -# TODO: size - = link_to 'Website', a.fund.website, target: '_blank', class: 'btn blue border-mist', onclick: "trackOutboundLink('#{a.fund.website}');" + = link_to 'Website', a.fund.website, target: '_blank', rel: 'noopener', class: 'btn blue border-mist', onclick: "trackOutboundLink('#{a.fund.website}');" - a.fund.links.each do |text, href| - = link_to text, href, target: '_blank', class: 'btn blue border-mist', onclick: "trackOutboundLink('#{href}');" + = link_to text, href, target: '_blank', rel: 'noopener', class: 'btn blue border-mist', onclick: "trackOutboundLink('#{href}');" .p20.border-top-thick.border-bottom-thick{ class: a.banner.background } .flex.items-center @@ -79,12 +77,10 @@ %h6.bold.slate Proposal .m20 .fs14.heading.bold.night.mb5 Title - -# TODO: default text for missing title from legacy record - .fs14.lh18.slate= @proposal.title + .fs14.lh18.slate= @proposal.title_with_default .m20 .fs14.heading.bold.night.mb5 Description - -# TODO: default text for missing description from legacy record - .fs14.lh18.slate= @proposal.description + .fs14.lh18.slate= @proposal.description_with_default .m20 .fs14.heading.bold.night.mb5 Support type .fs14.lh18.slate= support_type @@ -131,7 +127,7 @@ - if @proposal.recipient.website.present? .m20 .fs14.heading.bold.night.mb5 Website - = link_to(@proposal.recipient.website, @proposal.recipient.website, target: '_blank', class: 'fs14 slate', onclick: "trackOutboundLink('#{@proposal.recipient.website}');") + = link_to(@proposal.recipient.website, @proposal.recipient.website, target: '_blank', rel: 'noopener', class: 'fs14 slate', onclick: "trackOutboundLink('#{@proposal.recipient.website}');") .bg-ice = render partial: 'shared/footer', locals: { color: 'slate' } diff --git a/app/views/shared/_footer.html.haml b/app/views/shared/_footer.html.haml index 3c7d3357..fd95c2d3 100644 --- a/app/views/shared/_footer.html.haml +++ b/app/views/shared/_footer.html.haml @@ -18,4 +18,4 @@ = link_to('Privacy', privacy_path, class: 'mx10') = link_to('Terms', terms_path, class: 'mx10') - = link_to("© #{Date.today.year} CAST", 'http://www.wearecast.org.uk', class: 'ml10', target: '_blank', onclick: "trackOutboundLink('http://www.wearecast.org.uk');") \ No newline at end of file + = link_to("© #{Date.today.year} CAST", 'http://www.wearecast.org.uk', class: 'ml10', target: '_blank', rel: 'noopener', onclick: "trackOutboundLink('http://www.wearecast.org.uk');") \ No newline at end of file diff --git a/app/views/shared/_head.html.haml b/app/views/shared/_head.html.haml index 75952206..409cd8a7 100644 --- a/app/views/shared/_head.html.haml +++ b/app/views/shared/_head.html.haml @@ -6,8 +6,13 @@ = csrf_meta_tags %meta{ content: 'width=device-width, initial-scale=1', name: 'viewport' } + %meta{ name: 'title', content: 'Beehive - Grant funding suitability checker' } + %meta{ name: 'description', content: 'A free grant funding suitability tool that uses a funders guidelines, priorities and open data to produce a report that helps you decide where to apply.' } + + %meta{ property: 'og:type', content: 'website' } + %meta{ property: 'og:url', content: 'https://www.beehivegiving.org' } %meta{ property: 'og:title', content: 'Beehive - Grant funding suitability checker' } - %meta{ property: 'og:description', content: 'Save time and avoid wasted effort with a free suitability check of 120+ funds before applying' } + %meta{ property: 'og:description', content: 'A free grant funding suitability tool that uses a funders guidelines, priorities and open data to produce a report that helps you decide where to apply.' } %meta{ property: 'og:image', content: asset_url('logo-social-1200x630.png') } - if !allow_functional_cookies? @@ -56,9 +61,6 @@ a.appendChild(r); })(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv='); - - if logged_in? - = intercom_script_tag - -# Mixpanel :javascript (function(e,b){if(!b.__SV){var a,f,i,g;window.mixpanel=b;b._i=[];b.init=function(a,e,d){function f(b,h){var a=h.split(".");2==a.length&&(b=b[a[0]],h=a[1]);b[h]=function(){b.push([h].concat(Array.prototype.slice.call(arguments,0)))}}var c=b;"undefined"!==typeof d?c=b[d]=[]:d="mixpanel";c.people=c.people||[];c.toString=function(b){var a="mixpanel";"mixpanel"!==d&&(a+="."+d);b||(a+=" (stub)");return a};c.people.toString=function(){return c.toString(1)+".people (stub)"};i="disable time_event track track_pageview track_links track_forms register register_once alias unregister identify name_tag set_config people.set people.set_once people.increment people.append people.union people.track_charge people.clear_charges people.delete_user".split(" "); diff --git a/app/views/shared/_nav.html.haml b/app/views/shared/_nav.html.haml index 50f9b29e..4754039a 100644 --- a/app/views/shared/_nav.html.haml +++ b/app/views/shared/_nav.html.haml @@ -1,4 +1,3 @@ --# TODO: responsive .maxw1050.mx-auto.px15 %nav.pt20.mb7.heading.bold.flex.justify-between.items-center = link_to 'Beehive', root_path, id: 'navbar-logo', alt: 'Beehive logo', class: color diff --git a/app/views/sign_in/set/new.html.haml b/app/views/sign_in/set/new.html.haml index d7fbe568..6ef63cb3 100644 --- a/app/views/sign_in/set/new.html.haml +++ b/app/views/sign_in/set/new.html.haml @@ -25,7 +25,7 @@ - if @user.terms_agreed != true .mb20.field_with_errors - = f.input :terms_agreed, as: :boolean, label: false, inline_label: "I accept the #{link_to('terms of service', terms_path, target: '_blank')} and #{link_to('privacy policy', privacy_path, target: '_blank')}".html_safe + = f.input :terms_agreed, as: :boolean, label: false, inline_label: "I accept the #{link_to('terms of service', terms_path, target: '_blank', rel: 'noopener')} and #{link_to('privacy policy', privacy_path, target: '_blank', rel: 'noopener')}".html_safe .error= @user.errors[:terms_agreed][0] = f.submit 'Continue', class: 'btn-wide bg-rich-blue white shadow', data: { disable_with: 'Setting...' } diff --git a/config/initializers/intercom.rb b/config/initializers/intercom.rb deleted file mode 100644 index 28e92291..00000000 --- a/config/initializers/intercom.rb +++ /dev/null @@ -1,92 +0,0 @@ -IntercomRails.config do |config| - # == Intercom app_id - # - config.app_id = ENV['INTERCOM_APP_ID'] || 'i274pwcd' - - # == Intercom secret key - # This is required to enable secure mode, you can find it on your Setup - # guide in the "Secure Mode" step. - # - # config.api_secret = "..." - - # == Enabled Environments - # Which environments is auto inclusion of the Javascript enabled for - # - config.enabled_environments = %w[production] - - # == Current user method/variable - # The method/variable that contains the logged in user in your controllers. - # If it is `current_user` or `@user`, then you can ignore this - # - # config.user.current = Proc.new { current_user } - - # == Include for logged out Users - # If set to true, include the Intercom messenger on all pages, regardless of whether - # The user model class (set below) is present. Only available for Apps on the Acquire plan. - # config.include_for_logged_out_users = true - - # == User model class - # The class which defines your user model - # - # config.user.model = Proc.new { User } - - # == Exclude users - # A Proc that given a user returns true if the user should be excluded - # from imports and Javascript inclusion, false otherwise. - # - # config.user.exclude_if = Proc.new { |user| user.deleted? } - - # == User Custom Data - # A hash of additional data you wish to send about your users. - # You can provide either a method name which will be sent to the current - # user object, or a Proc which will be passed the current user. - # - # config.user.custom_data = { - # :plan => Proc.new { |current_user| current_user.plan.name }, - # :favorite_color => :favorite_color - # } - - # == User -> Company association - # A Proc that given a user returns an array of companies - # that the user belongs to. - # - # config.user.company_association = Proc.new { |user| user.companies.to_a } - # config.user.company_association = Proc.new { |user| [user.company] } - - # == Current company method/variable - # The method/variable that contains the current company for the current user, - # in your controllers. 'Companies' are generic groupings of users, so this - # could be a company, app or group. - # - # config.company.current = Proc.new { current_company } - - # == Company Custom Data - # A hash of additional data you wish to send about a company. - # This works the same as User custom data above. - # - # config.company.custom_data = { - # :number_of_messages => Proc.new { |app| app.messages.count }, - # :is_interesting => :is_interesting? - # } - - # == Company Plan name - # This is the name of the plan a company is currently paying (or not paying) for. - # e.g. Messaging, Free, Pro, etc. - # - # config.company.plan = Proc.new { |current_company| current_company.plan.name } - - # == Company Monthly Spend - # This is the amount the company spends each month on your app. If your company - # has a plan, it will set the 'total value' of that plan appropriately. - # - # config.company.monthly_spend = Proc.new { |current_company| current_company.plan.price } - # config.company.monthly_spend = Proc.new { |current_company| (current_company.plan.price - current_company.subscription.discount) } - - # == Custom Style - # By default, Intercom will add a button that opens the messenger to - # the page. If you'd like to use your own link to open the messenger, - # uncomment this line and clicks on any element with id 'Intercom' will - # open the messenger. - # - # config.inbox.style = :custom -end diff --git a/config/routes.rb b/config/routes.rb index 63ccd8a4..20ec9466 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -75,6 +75,7 @@ get '/fund/:slug', to: redirect('/opportunities') get '/funds', to: redirect('/opportunities') get '/funds/:slug', to: redirect('/opportunities') + get '/funds/theme/:slug', to: redirect('/opportunities') get '/password_resets/new', to: redirect('/sign-in') get '/welcome', to: redirect('/') end diff --git a/db/migrate/20181129165600_drop_status_from_recipients.rb b/db/migrate/20181129165600_drop_status_from_recipients.rb new file mode 100644 index 00000000..6b44bbe0 --- /dev/null +++ b/db/migrate/20181129165600_drop_status_from_recipients.rb @@ -0,0 +1,5 @@ +class DropStatusFromRecipients < ActiveRecord::Migration[5.1] + def change + remove_column :recipients, :status, :string + end +end diff --git a/db/migrate/20181130111331_drop_subscriptions.rb b/db/migrate/20181130111331_drop_subscriptions.rb new file mode 100644 index 00000000..05763804 --- /dev/null +++ b/db/migrate/20181130111331_drop_subscriptions.rb @@ -0,0 +1,5 @@ +class DropSubscriptions < ActiveRecord::Migration[5.1] + def change + drop_table :subscriptions + end +end diff --git a/db/migrate/20181130112454_remove_microsite_column_from_funders.rb b/db/migrate/20181130112454_remove_microsite_column_from_funders.rb new file mode 100644 index 00000000..4eebc6f6 --- /dev/null +++ b/db/migrate/20181130112454_remove_microsite_column_from_funders.rb @@ -0,0 +1,5 @@ +class RemoveMicrositeColumnFromFunders < ActiveRecord::Migration[5.1] + def change + remove_column :funders, :microsite, :boolean + end +end diff --git a/db/migrate/20181130114527_add_assessments_count_to_proposals.rb b/db/migrate/20181130114527_add_assessments_count_to_proposals.rb new file mode 100644 index 00000000..0c3d5225 --- /dev/null +++ b/db/migrate/20181130114527_add_assessments_count_to_proposals.rb @@ -0,0 +1,31 @@ +class AddAssessmentsCountToProposals < ActiveRecord::Migration[5.1] + def down + remove_column :proposals, :assessments_count + remove_column :funders, :active_opportunities_count + remove_column :themes, :active_opportunities_count + end + + def up + add_column :proposals, :assessments_count, :integer, null: false, default: 0 + add_column :funders, :active_opportunities_count, :integer, null: false, default: 0 + add_column :themes, :active_opportunities_count, :integer, null: false, default: 0 + + Proposal.reset_column_information + Proposal.find_each do |p| + Proposal.reset_counters(p.id, :assessments) + print 'p' + end + + Funder.reset_column_information + Funder.find_each do |f| + Funder.update_counters(f.id, active_opportunities_count: f.funds.active.size) + print 'f' + end + + Theme.reset_column_information + Theme.find_each do |t| + Theme.update_counters(t.id, active_opportunities_count: t.funds.active.size) + print 't' + end + end +end diff --git a/db/migrate/20181130143755_remove_unused_fields_from_proposals.rb b/db/migrate/20181130143755_remove_unused_fields_from_proposals.rb new file mode 100644 index 00000000..ee2d2910 --- /dev/null +++ b/db/migrate/20181130143755_remove_unused_fields_from_proposals.rb @@ -0,0 +1,42 @@ +class RemoveUnusedFieldsFromProposals < ActiveRecord::Migration[5.1] + def change + remove_column :proposals, :gender, :string + remove_column :proposals, :outcome1, :string + remove_column :proposals, :outcome2, :string + remove_column :proposals, :outcome3, :string + remove_column :proposals, :outcome4, :string + remove_column :proposals, :outcome5, :string + remove_column :proposals, :beneficiaries_other, :string + remove_column :proposals, :min_age, :integer + remove_column :proposals, :max_age, :integer + remove_column :proposals, :beneficiaries_count, :integer + remove_column :proposals, :activity_costs, :float + remove_column :proposals, :people_costs, :float + remove_column :proposals, :capital_costs, :float + remove_column :proposals, :other_costs, :float + remove_column :proposals, :activity_costs_estimated, :boolean + remove_column :proposals, :people_costs_estimated, :boolean + remove_column :proposals, :capital_costs_estimated, :boolean + remove_column :proposals, :other_costs_estimated, :boolean + remove_column :proposals, :all_funding_required, :boolean + remove_column :proposals, :beneficiaries_other_required, :boolean + remove_column :proposals, :type_of_support, :string + remove_column :proposals, :affect_people, :boolean + remove_column :proposals, :affect_other, :boolean + remove_column :proposals, :affect_geo, :integer + remove_column :proposals, :total_costs_estimated, :boolean + remove_column :proposals, :implementations_other_required, :boolean + remove_column :proposals, :implementations_other, :string + remove_column :proposals, :recommended_funds, :jsonb + remove_column :proposals, :eligibility, :jsonb + remove_column :proposals, :suitability, :jsonb + remove_column :proposals, :legacy, :boolean + + drop_table :age_groups_proposals + drop_table :age_groups + drop_table :beneficiaries_proposals + drop_table :beneficiaries + drop_table :implementations_proposals + drop_table :implementations + end +end diff --git a/db/migrate/20181130152131_tidy_up_schema.rb b/db/migrate/20181130152131_tidy_up_schema.rb new file mode 100644 index 00000000..5c011359 --- /dev/null +++ b/db/migrate/20181130152131_tidy_up_schema.rb @@ -0,0 +1,51 @@ +class TidyUpSchema < ActiveRecord::Migration[5.1] + def change + drop_table :attempts + drop_table :enquiries + drop_table :feedbacks + drop_table :requests + + remove_column :recipients, :contact_number, :string + remove_column :recipients, :street_address, :string + remove_column :recipients, :city, :string + remove_column :recipients, :region, :string + remove_column :recipients, :postal_code, :string + remove_column :recipients, :country_alpha2, :string + remove_column :recipients, :mission, :text + remove_column :recipients, :founded_on, :date + remove_column :recipients, :registered_on, :date + remove_column :recipients, :registered, :boolean + remove_column :recipients, :active_on_beehive, :boolean + remove_column :recipients, :org_type, :boolean + remove_column :recipients, :latitude, :float + remove_column :recipients, :longitude, :float + remove_column :recipients, :contact_email, :string + remove_column :recipients, :charity_name, :string + remove_column :recipients, :charity_status, :string + remove_column :recipients, :charity_income, :float + remove_column :recipients, :charity_spending, :float + remove_column :recipients, :charity_recent_accounts_link, :string + remove_column :recipients, :charity_trustees, :string + remove_column :recipients, :charity_employees, :string + remove_column :recipients, :charity_volunteers, :string + remove_column :recipients, :charity_year_ending, :string + remove_column :recipients, :charity_days_overdue, :string + remove_column :recipients, :charity_registered_date, :string + remove_column :recipients, :company_name, :string + remove_column :recipients, :company_type, :string + remove_column :recipients, :company_status, :string + remove_column :recipients, :company_incorporated_date, :date + remove_column :recipients, :company_last_accounts_date, :date + remove_column :recipients, :company_next_accounts_date, :date + remove_column :recipients, :company_next_returns_date, :date + remove_column :recipients, :company_last_returns_date, :date + remove_column :recipients, :company_sic, :text + remove_column :recipients, :company_recent_accounts_link, :string + remove_column :recipients, :grants_count, :integer + remove_column :recipients, :multi_national, :boolean + remove_column :recipients, :employees, :integer + remove_column :recipients, :volunteers, :integer + remove_column :recipients, :funds_checked, :integer + remove_column :recipients, :income, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 73d0e10d..6a9c5b5f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20181120150620) do +ActiveRecord::Schema.define(version: 20181130152131) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -46,20 +46,6 @@ t.index ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true end - create_table "age_groups", id: :serial, force: :cascade do |t| - t.string "label" - t.integer "age_from" - t.integer "age_to" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "age_groups_proposals", id: :serial, force: :cascade do |t| - t.integer "age_group_id" - t.integer "proposal_id" - t.index ["age_group_id", "proposal_id"], name: "index_age_groups_proposals_on_age_group_id_and_proposal_id" - end - create_table "answers", id: :serial, force: :cascade do |t| t.integer "category_id", null: false t.integer "criterion_id", null: false @@ -105,34 +91,6 @@ t.index ["recipient_id"], name: "index_assessments_on_recipient_id" end - create_table "attempts", force: :cascade do |t| - t.bigint "funder_id" - t.bigint "recipient_id" - t.bigint "proposal_id" - t.string "state", default: "basics", null: false - t.string "access_token" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["funder_id"], name: "index_attempts_on_funder_id" - t.index ["proposal_id"], name: "index_attempts_on_proposal_id" - t.index ["recipient_id"], name: "index_attempts_on_recipient_id" - end - - create_table "beneficiaries", id: :serial, force: :cascade do |t| - t.string "label", limit: 255 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "category" - t.string "sort" - end - - create_table "beneficiaries_proposals", id: :serial, force: :cascade do |t| - t.integer "beneficiary_id" - t.integer "proposal_id" - t.index ["beneficiary_id"], name: "index_beneficiaries_proposals_on_beneficiary_id" - t.index ["proposal_id"], name: "index_beneficiaries_proposals_on_proposal_id" - end - create_table "countries", id: :serial, force: :cascade do |t| t.string "name", limit: 255 t.string "alpha2", limit: 255 @@ -205,33 +163,6 @@ t.index ["proposal_id"], name: "index_districts_proposals_on_proposal_id" end - create_table "enquiries", id: :serial, force: :cascade do |t| - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "approach_funder_count", default: 0 - t.integer "fund_id" - t.integer "proposal_id" - t.index ["fund_id"], name: "index_enquiries_on_fund_id" - t.index ["proposal_id"], name: "index_enquiries_on_proposal_id" - end - - create_table "feedbacks", id: :serial, force: :cascade do |t| - t.integer "user_id" - t.integer "nps" - t.integer "taken_away" - t.integer "informs_decision" - t.text "other" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "application_frequency" - t.string "grant_frequency" - t.string "marketing_frequency" - t.integer "price" - t.string "most_useful" - t.integer "suitable" - t.index ["user_id"], name: "index_feedbacks_on_user_id" - end - create_table "fund_themes", force: :cascade do |t| t.bigint "fund_id" t.bigint "theme_id" @@ -250,10 +181,10 @@ t.boolean "active", default: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.boolean "microsite", default: false, null: false t.string "primary_color" t.string "secondary_color" t.datetime "opportunities_last_updated_at", default: "2018-10-31 00:00:00", null: false + t.integer "active_opportunities_count", default: 0, null: false t.index ["slug"], name: "index_funders_on_slug", unique: true end @@ -292,18 +223,6 @@ t.datetime "updated_at", null: false end - create_table "implementations", id: :serial, force: :cascade do |t| - t.string "label", limit: 255 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "implementations_proposals", id: :serial, force: :cascade do |t| - t.integer "implementation_id" - t.integer "proposal_id" - t.index ["implementation_id", "proposal_id"], name: "index_implementations_proposals" - end - create_table "proposal_themes", force: :cascade do |t| t.bigint "proposal_id" t.bigint "theme_id" @@ -317,42 +236,12 @@ t.integer "recipient_id" t.string "title" t.string "description" - t.string "gender" - t.string "outcome1" - t.string "outcome2" - t.string "outcome3" - t.string "outcome4" - t.string "outcome5" - t.string "beneficiaries_other" - t.integer "min_age" - t.integer "max_age" - t.integer "beneficiaries_count" t.integer "min_duration" - t.float "activity_costs" - t.float "people_costs" - t.float "capital_costs" - t.float "other_costs" t.integer "min_amount" - t.boolean "activity_costs_estimated", default: false - t.boolean "people_costs_estimated", default: false - t.boolean "capital_costs_estimated", default: false - t.boolean "other_costs_estimated", default: false - t.boolean "all_funding_required" - t.boolean "beneficiaries_other_required" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.string "type_of_support" t.string "state", default: "complete" - t.boolean "affect_people" - t.boolean "affect_other" - t.integer "affect_geo" - t.boolean "total_costs_estimated", default: false t.boolean "prevent_funder_verification" - t.boolean "implementations_other_required" - t.string "implementations_other" - t.jsonb "recommended_funds", default: [] - t.jsonb "eligibility", default: {}, null: false - t.jsonb "suitability", default: {}, null: false t.integer "category_code" t.boolean "public_consent" t.string "support_details" @@ -361,12 +250,12 @@ t.string "geographic_scale" t.bigint "user_id" t.string "access_token" - t.boolean "legacy" t.datetime "private" t.bigint "collection_id" t.string "collection_type" t.bigint "duplicate_of" t.datetime "migrated_on" + t.integer "assessments_count", default: 0, null: false t.index ["collection_id"], name: "index_proposals_on_collection_id" t.index ["collection_type"], name: "index_proposals_on_collection_type" t.index ["recipient_id"], name: "index_proposals_on_recipient_id" @@ -386,57 +275,14 @@ create_table "recipients", id: :serial, force: :cascade do |t| t.string "name", limit: 255 - t.string "contact_number", limit: 255 t.string "website", limit: 255 - t.string "street_address", limit: 255 - t.string "city", limit: 255 - t.string "region", limit: 255 - t.string "postal_code", limit: 255 - t.string "country_alpha2", limit: 255 t.string "charity_number", limit: 255 t.string "company_number", limit: 255 t.string "slug", limit: 255 - t.text "mission" - t.string "status", limit: 255, default: "Active - currently operational" - t.date "founded_on" - t.date "registered_on" - t.boolean "registered" - t.boolean "active_on_beehive" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.integer "org_type" - t.float "latitude" - t.float "longitude" - t.string "contact_email" - t.string "charity_name" - t.string "charity_status" - t.float "charity_income" - t.float "charity_spending" - t.string "charity_recent_accounts_link" - t.string "charity_trustees" - t.string "charity_employees" - t.string "charity_volunteers" - t.string "charity_year_ending" - t.string "charity_days_overdue" - t.string "charity_registered_date" - t.string "company_name" - t.string "company_type" - t.string "company_status" - t.date "company_incorporated_date" - t.date "company_last_accounts_date" - t.date "company_next_accounts_date" - t.date "company_next_returns_date" - t.date "company_last_returns_date" - t.text "company_sic", array: true - t.string "company_recent_accounts_link" - t.integer "grants_count", default: 0 t.integer "operating_for" - t.boolean "multi_national" t.integer "income_band" - t.integer "employees" - t.integer "volunteers" - t.integer "funds_checked", default: 0, null: false - t.integer "income" t.jsonb "reveals", default: [], null: false t.integer "category_code" t.string "description" @@ -451,29 +297,6 @@ t.index ["user_id"], name: "index_recipients_on_user_id" end - create_table "requests", force: :cascade do |t| - t.bigint "fund_id" - t.bigint "recipient_id" - t.string "message" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["fund_id"], name: "index_requests_on_fund_id" - t.index ["recipient_id"], name: "index_requests_on_recipient_id" - end - - create_table "subscriptions", id: :serial, force: :cascade do |t| - t.integer "recipient_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "stripe_user_id" - t.boolean "active", default: false, null: false - t.date "expiry_date" - t.integer "percent_off", default: 0, null: false - t.integer "version", default: 1, null: false - t.index ["recipient_id"], name: "index_subscriptions_on_recipient_id" - t.index ["stripe_user_id"], name: "index_subscriptions_on_stripe_user_id", unique: true - end - create_table "themes", force: :cascade do |t| t.string "name", null: false t.integer "parent_id" @@ -483,6 +306,7 @@ t.string "slug" t.string "classes" t.datetime "opportunities_last_updated_at", default: "2018-10-31 00:00:00", null: false + t.integer "active_opportunities_count", default: 0, null: false t.index ["name"], name: "index_themes_on_name", unique: true t.index ["parent_id"], name: "index_themes_on_parent_id" t.index ["slug"], name: "index_themes_on_slug", unique: true @@ -517,11 +341,6 @@ add_foreign_key "assessments", "funds" add_foreign_key "assessments", "proposals" add_foreign_key "assessments", "recipients" - add_foreign_key "attempts", "funders" - add_foreign_key "attempts", "proposals" - add_foreign_key "attempts", "recipients" - add_foreign_key "enquiries", "funds" - add_foreign_key "enquiries", "proposals" add_foreign_key "fund_themes", "funds" add_foreign_key "fund_themes", "themes" add_foreign_key "funds", "geo_areas" diff --git a/lib/tasks/migrate.rake b/lib/tasks/migrate.rake index eca5970c..29cfd232 100644 --- a/lib/tasks/migrate.rake +++ b/lib/tasks/migrate.rake @@ -21,11 +21,7 @@ namespace :migrate do proposals = Proposal.where(recipient_id: recipient.id) users = User.where(organisation_id: recipient.id) - funds = if recipient&.subscription.try(:active) - Fund.active - elsif recipient.reveals.any? - Fund.where(slug: recipient.reveals).active - end + funds = Fund.where(slug: recipient.reveals).active if recipient.reveals.any? return puts ': no Users' unless users.any? diff --git a/spec/cells/breadcrumb_cell_spec.rb b/spec/cells/breadcrumb_cell_spec.rb deleted file mode 100644 index d53d510c..00000000 --- a/spec/cells/breadcrumb_cell_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'rails_helper' - -describe BreadcrumbCell do - controller ApplicationController - - it 'missing path option' do - breadcrumb = cell(:breadcrumb).call(:show) - expect(breadcrumb).not_to(have_css '.bread') - end - - it 'path option empty' do - breadcrumb = cell(:breadcrumb, {}).call(:show) - expect(breadcrumb).not_to(have_css '.bread') - end - - it '#bold' do - breadcrumb = cell(:breadcrumb, 'a' => 'b').call(:show) - expect(breadcrumb).to have_css('.bold', count: 1) - end - - it '#disabled' do - breadcrumb = cell(:breadcrumb, 'a' => nil).call(:show) - expect(breadcrumb).to have_css('.disabled.white', count: 1) - end - - it '#disabled with custom color' do - breadcrumb = cell(:breadcrumb, { 'a' => nil }, color: 'blue').call(:show) - expect(breadcrumb).to have_css('.disabled.blue', count: 1) - end -end diff --git a/spec/helpers/breadcrumbs_helper_spec.rb b/spec/helpers/breadcrumbs_helper_spec.rb new file mode 100644 index 00000000..c6c79407 --- /dev/null +++ b/spec/helpers/breadcrumbs_helper_spec.rb @@ -0,0 +1,35 @@ +require 'rails_helper' + +describe BreadcrumbsHelper do + class BreadcrumbsHelperClass + include ActionView::Helpers + include Rails.application.routes.url_helpers + include BreadcrumbsHelper + end + + subject { BreadcrumbsHelperClass.new } + + it 'hash option missing' do + expect(subject.breadcrumbs).to be_nil + end + + it 'hash option empty' do + expect(subject.breadcrumbs({})).to be_nil + end + + it 'bold' do + opts = { 'a' => 'b' } + expect(subject.breadcrumbs(opts)).to have_css('.bold', count: 1) + end + + it 'disabled' do + opts = { 'a' => nil } + expect(subject.breadcrumbs(opts)).to have_css('.disabled', count: 1) + end + + it 'custom color' do + opts = { 'a' => nil } + expect(subject.breadcrumbs(opts, color: 'blue')) + .to have_css('.blue', count: 3) + end +end diff --git a/spec/helpers/reports_helper_spec.rb b/spec/helpers/reports_helper_spec.rb index df824aad..455c95bd 100644 --- a/spec/helpers/reports_helper_spec.rb +++ b/spec/helpers/reports_helper_spec.rb @@ -10,12 +10,24 @@ class ReportsHelperClass subject { ReportsHelperClass.new } let(:proposal) { create(:proposal) } + let(:recipient) { proposal.recipient } it '#amount_sought' do msg = 'Between £10,000 and £250,000' expect(subject.amount_sought(proposal)).to eq(msg) end + context '#created_by' do + it 'individual' do + recipient.category_code = 101 + expect(subject.created_by(recipient)).to eq('an individual') + end + + it 'organisation' do + expect(subject.created_by(recipient)).to eq(recipient.name) + end + end + it '#location_description' do msg = "Local - #{proposal.countries.last.name}" expect(subject.location_description(proposal)).to eq(msg) @@ -23,22 +35,22 @@ class ReportsHelperClass context '#recipient_type' do it 'individual' do - proposal.recipient.category_code = 101 - proposal.recipient.description = nil - expect(subject.recipient_type(proposal.recipient)).to eq('An individual') + recipient.category_code = 101 + recipient.description = nil + expect(subject.recipient_type(recipient)).to eq('An individual') end it 'organisation' do msg = 'A charitable organisation - Charity registered in England & Wales' - expect(subject.recipient_type(proposal.recipient)).to eq(msg) + expect(subject.recipient_type(recipient)).to eq(msg) end end context '#recipient_name' do it 'individual' do - proposal.recipient.category_code = 101 - proposal.recipient.description = nil - expect(subject.recipient_name(proposal.recipient)).to eq('An individual') + recipient.category_code = 101 + recipient.description = nil + expect(subject.recipient_name(recipient)).to eq('An individual') end it 'organisation' do diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 9876c35a..30721d53 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -28,7 +28,8 @@ it '#body_html returns html' do html = '

    www.beehivegiving.org

    \n" + "target=\"_blank\" rel=\"noopener\">www.beehivegiving.org" \ + "\n" expect(subject.body_html).to eq(html) end end diff --git a/spec/models/funder_spec.rb b/spec/models/funder_spec.rb index c60a995e..c31a6c27 100644 --- a/spec/models/funder_spec.rb +++ b/spec/models/funder_spec.rb @@ -32,4 +32,29 @@ expect(create(:funder, name: 'Funder Name').slug).to eq 'funder-name-2' end end + + context '#active_opportunities_count' do + it 'updated when active opportunity added' do + expect(subject.active_opportunities_count).to eq(0) + expect_opportunity_added + end + + it 'updated when opportunity no longer active' do + expect_opportunity_added + @opportunity.update!(state: 'inactive') + expect(subject.active_opportunities_count).to eq(0) + end + + it 'updated when opportunity destroyed' do + expect_opportunity_added + @opportunity.destroy + expect(subject.active_opportunities_count).to eq(0) + end + end + + def expect_opportunity_added + @opportunity = build(:fund, state: 'active') + subject.update!(funds: [@opportunity]) + expect(subject.active_opportunities_count).to eq(1) + end end diff --git a/spec/models/proposal_spec.rb b/spec/models/proposal_spec.rb index b52d323b..bbe33309 100644 --- a/spec/models/proposal_spec.rb +++ b/spec/models/proposal_spec.rb @@ -250,6 +250,48 @@ end end + context '#description_with_default' do + it 'missing' do + subject.description = nil + msg = 'No description provided' + expect(subject.description_with_default).to eq(msg) + end + + it 'present' do + expect(subject.description_with_default).to eq(subject.description) + end + end + + context '#title_with_default' do + it 'missing' do + subject.title = nil + msg = 'No title provided' + expect(subject.title_with_default).to eq(msg) + end + + it 'present' do + expect(subject.title_with_default).to eq(subject.title) + end + end + + context '#assessments_count' do + it 'updated when assessment added' do + expect(subject.assessments_count).to eq(0) + end + + it 'updated when assessment destroyed' do + expect_assessment_added + @assessment.destroy + expect(subject.assessments_count).to eq(0) + end + end + + def expect_assessment_added + @assessment = build(:assessment) + subject.update!(assessments: [@assessment]) + expect(subject.assessments_count).to eq(1) + end + scenario '#country set' scenario 'countries & districts properly cleared & last selection takes precedence' diff --git a/spec/models/theme_spec.rb b/spec/models/theme_spec.rb index fef976ec..0f54ce57 100644 --- a/spec/models/theme_spec.rb +++ b/spec/models/theme_spec.rb @@ -62,4 +62,28 @@ it('#primary_color') { expect(subject.primary_color).to eq(nil) } it('#secondary_color') { expect(subject.primary_color).to eq(nil) } + + context '#active_opportunities_count' do + it 'updated when active opportunity added' do + expect(subject.active_opportunities_count).to eq(0) + expect_opportunity_added + end + + it 'updated when opportunity no longer active' do + expect_opportunity_added + @opportunity.update!(state: 'inactive') + expect(subject.active_opportunities_count).to eq(0) + end + + it 'updated when opportunity destroyed' do + expect_opportunity_added + @opportunity.destroy + expect(subject.active_opportunities_count).to eq(0) + end + end + + def expect_opportunity_added + @opportunity = create(:fund, state: 'active', themes: [subject]) + expect(subject.active_opportunities_count).to eq(1) + end end