diff --git a/.github/PULL_REQUEST_TEMPLATE b/.github/PULL_REQUEST_TEMPLATE index abb23cf0a..a8c151f5d 100644 --- a/.github/PULL_REQUEST_TEMPLATE +++ b/.github/PULL_REQUEST_TEMPLATE @@ -1,17 +1,17 @@ -References -=================== -> Add references to related Issues/Pull Requests/Travis Builds/Rollbar errors/etc... +## References -Objectives -=================== -> What are the objectives of this changes? (If there is no related Issue with an explanation) +> Related Issues/Pull Requests/Travis Builds/Rollbar errors/etc... + +## Objectives + +> What are the objectives of these changes? + +## Visual Changes -Visual Changes -=================== > Any visual changes? please attach screenshots (or gifs) showing them. > If modified views are public (not the admin panel), try them in mobile display (with your browser's developer console) and add screenshots. -Notes -=================== +## Notes + > Mention rake tasks or actions to be done when deploying this changes to a server (if any). > Explain any caveats, or important things to notice like deprecations (if any). diff --git a/Gemfile b/Gemfile index fcf8adac1..f5c8b3f70 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source 'https://rubygems.org' -gem 'rails', '4.2.10' +gem 'rails', '4.2.11' gem 'acts-as-taggable-on', '~> 5.0.0' gem 'acts_as_votable', '~> 0.11.1' @@ -77,7 +77,7 @@ end group :test do gem 'capybara', '~> 2.17.0' gem 'coveralls', '~> 0.8.22', require: false - gem 'database_cleaner', '~> 1.6.1' + gem 'database_cleaner', '~> 1.7.0' gem 'email_spec', '~> 2.1.0' gem 'rspec-rails', '~> 3.8' gem 'selenium-webdriver', '~> 3.10' diff --git a/Gemfile.lock b/Gemfile.lock index 5673a6c29..64a662dd4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -2,36 +2,36 @@ GEM remote: https://rubygems.org/ remote: https://rails-assets.org/ specs: - actionmailer (4.2.10) - actionpack (= 4.2.10) - actionview (= 4.2.10) - activejob (= 4.2.10) + actionmailer (4.2.11) + actionpack (= 4.2.11) + actionview (= 4.2.11) + activejob (= 4.2.11) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.10) - actionview (= 4.2.10) - activesupport (= 4.2.10) + actionpack (4.2.11) + actionview (= 4.2.11) + activesupport (= 4.2.11) rack (~> 1.6) rack-test (~> 0.6.2) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.10) - activesupport (= 4.2.10) + actionview (4.2.11) + activesupport (= 4.2.11) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 1.0, >= 1.0.5) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (4.2.10) - activesupport (= 4.2.10) + activejob (4.2.11) + activesupport (= 4.2.11) globalid (>= 0.3.0) - activemodel (4.2.10) - activesupport (= 4.2.10) + activemodel (4.2.11) + activesupport (= 4.2.11) builder (~> 3.1) - activerecord (4.2.10) - activemodel (= 4.2.10) - activesupport (= 4.2.10) + activerecord (4.2.11) + activemodel (= 4.2.11) + activesupport (= 4.2.11) arel (~> 6.0) - activesupport (4.2.10) + activesupport (4.2.11) i18n (~> 0.7) minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) @@ -113,7 +113,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.1) + concurrent-ruby (1.1.3) coveralls (0.8.22) json (>= 1.8, < 3) simplecov (~> 0.16.1) @@ -123,7 +123,7 @@ GEM crass (1.0.4) daemons (1.2.6) dalli (2.7.6) - database_cleaner (1.6.2) + database_cleaner (1.7.0) debug_inspector (0.0.3) delayed_job (4.1.5) activesupport (>= 3.0, < 5.3) @@ -247,7 +247,7 @@ GEM loofah (2.2.3) crass (~> 1.0.2) nokogiri (>= 1.5.9) - mail (2.7.0) + mail (2.7.1) mini_mime (>= 0.1.1) mdl (0.5.0) kramdown (~> 1.12, >= 1.12.0) @@ -327,16 +327,16 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rails (4.2.10) - actionmailer (= 4.2.10) - actionpack (= 4.2.10) - actionview (= 4.2.10) - activejob (= 4.2.10) - activemodel (= 4.2.10) - activerecord (= 4.2.10) - activesupport (= 4.2.10) + rails (4.2.11) + actionmailer (= 4.2.11) + actionpack (= 4.2.11) + actionview (= 4.2.11) + activejob (= 4.2.11) + activemodel (= 4.2.11) + activerecord (= 4.2.11) + activesupport (= 4.2.11) bundler (>= 1.3.0, < 2.0) - railties (= 4.2.10) + railties (= 4.2.11) sprockets-rails rails-assets-leaflet (1.1.0) rails-assets-markdown-it (8.2.2) @@ -348,9 +348,9 @@ GEM rails-deprecated_sanitizer (>= 1.0.1) rails-html-sanitizer (1.0.4) loofah (~> 2.2, >= 2.2.2) - railties (4.2.10) - actionpack (= 4.2.10) - activesupport (= 4.2.10) + railties (4.2.11) + actionpack (= 4.2.11) + activesupport (= 4.2.11) rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (3.0.0) @@ -512,7 +512,7 @@ DEPENDENCIES coveralls (~> 0.8.22) daemons (~> 1.2.4) dalli (~> 2.7.6) - database_cleaner (~> 1.6.1) + database_cleaner (~> 1.7.0) delayed_job_active_record (~> 4.1.3) devise (~> 3.5.7) devise-async (~> 0.10.2) @@ -548,7 +548,7 @@ DEPENDENCIES pg (~> 0.21.0) pg_search (~> 2.0.1) quiet_assets (~> 1.1.0) - rails (= 4.2.10) + rails (= 4.2.11) rails-assets-leaflet! rails-assets-markdown-it (~> 8.2.1)! redcarpet (~> 3.4.0) diff --git a/README.md b/README.md index f845ccd0e..9cb539e31 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ Citizen Participation and Open Government Application [![Coverage Status](https://coveralls.io/repos/github/consul/consul/badge.svg)](https://coveralls.io/github/consul/consul?branch=master) [![Crowdin](https://d322cqt584bo4o.cloudfront.net/consul/localized.svg)](https://crowdin.com/project/consul) [![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](http://www.gnu.org/licenses/agpl-3.0) +[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com) [![Accessibility conformance](https://img.shields.io/badge/accessibility-WAI:AA-green.svg)](https://www.w3.org/WAI/eval/Overview) [![A11y issues checked with Rocket Validator](https://rocketvalidator.com/badges/checked_with_rocket_validator.svg?url=https://rocketvalidator.com)](https://rocketvalidator.com/opensource) @@ -78,4 +79,4 @@ Code published under AFFERO GPL v3 (see [LICENSE-AGPLv3.txt](LICENSE-AGPLv3.txt) ## Contributions -See [CONTRIBUTING.md](CONTRIBUTING.md) \ No newline at end of file +See [CONTRIBUTING.md](CONTRIBUTING.md) diff --git a/Rakefile b/Rakefile index 13a99536b..c4d34f626 100644 --- a/Rakefile +++ b/Rakefile @@ -3,5 +3,5 @@ require File.expand_path('../config/application', __FILE__) -Rails.application.load_tasks +Rails.application.load_tasks if Rake::Task.tasks.empty? KnapsackPro.load_tasks if defined?(KnapsackPro) diff --git a/app/assets/images/language_select.png b/app/assets/images/language_select.png deleted file mode 100644 index e0c4e6411..000000000 Binary files a/app/assets/images/language_select.png and /dev/null differ diff --git a/app/assets/stylesheets/layout.scss b/app/assets/stylesheets/layout.scss index c4f90791a..59b851e79 100644 --- a/app/assets/stylesheets/layout.scss +++ b/app/assets/stylesheets/layout.scss @@ -434,6 +434,11 @@ a { text-transform: uppercase; } +.help-text { + line-height: rem-calc(20); + margin-top: 0; +} + // 02. Header // ---------- @@ -450,6 +455,18 @@ header { float: left; height: $line-height * 1.5; margin-left: $line-height / 2; + position: relative; + + &::after { + color: #808080; + content: '\61'; + font-family: "icons" !important; + font-size: $small-font-size; + pointer-events: none; + position: absolute; + right: 2px; + top: 9px; + } } .external-links { @@ -834,6 +851,7 @@ footer { .categories a, .geozone a, .sidebar-links a, +.sidebar-map a, .tags span { background: #ececec; border-radius: rem-calc(6); @@ -941,15 +959,11 @@ footer { label { color: #fff; - font-size: $small-font-size; + font-size: $tiny-font-size; font-weight: normal; } select { - background-image: image-url('language_select.png'); - background-origin: border-box; - background-position: right; - background-size: 24px 24px; option { background: #fff; @@ -960,14 +974,16 @@ footer { } .locale-switcher { - background-color: transparent; + background: #1a1a1a; border: 0; + border-radius: rem-calc(4); color: #fff; font-size: $small-font-size; + height: $line-height; margin-bottom: 0; + margin-top: $line-height / 4; outline: none; - padding-left: rem-calc(3); - padding-right: $line-height; + padding: 0 $line-height / 4; width: auto; &:focus { @@ -2508,7 +2524,7 @@ table { border-radius: rem-calc(5); display: block; margin: $line-height / 2 0; - padding: 0 $line-height / 2; + padding: $line-height / 2; position: relative; .icon-document { diff --git a/app/controllers/admin/budget_headings_controller.rb b/app/controllers/admin/budget_headings_controller.rb index 4e1bf6ed2..6af316eb4 100644 --- a/app/controllers/admin/budget_headings_controller.rb +++ b/app/controllers/admin/budget_headings_controller.rb @@ -33,7 +33,7 @@ class Admin::BudgetHeadingsController < Admin::BaseController private def budget_heading_params - params.require(:budget_heading).permit(:name, :price, :population, :allow_custom_content) + params.require(:budget_heading).permit(:name, :price, :population, :allow_custom_content, :latitude, :longitude) end end diff --git a/app/controllers/admin/budget_investment_milestones_controller.rb b/app/controllers/admin/budget_investment_milestones_controller.rb index f63fee025..f354d42fa 100644 --- a/app/controllers/admin/budget_investment_milestones_controller.rb +++ b/app/controllers/admin/budget_investment_milestones_controller.rb @@ -1,76 +1,8 @@ -class Admin::BudgetInvestmentMilestonesController < Admin::BaseController - include Translatable - - before_action :load_budget_investment, only: [:index, :new, :create, :edit, :update, :destroy] - before_action :load_budget_investment_milestone, only: [:edit, :update, :destroy] - before_action :load_statuses, only: [:index, :new, :create, :edit, :update] - - def index - end - - def new - @milestone = Budget::Investment::Milestone.new - end - - def create - @milestone = Budget::Investment::Milestone.new(milestone_params) - @milestone.investment = @investment - if @milestone.save - redirect_to admin_budget_budget_investment_path(@investment.budget, @investment), - notice: t('admin.milestones.create.notice') - else - render :new - end - end - - def edit - end - - def update - if @milestone.update(milestone_params) - redirect_to admin_budget_budget_investment_path(@investment.budget, @investment), - notice: t('admin.milestones.update.notice') - else - render :edit - end - end - - def destroy - @milestone.destroy - redirect_to admin_budget_budget_investment_path(@investment.budget, @investment), - notice: t('admin.milestones.delete.notice') - end +class Admin::BudgetInvestmentMilestonesController < Admin::MilestonesController private - def milestone_params - image_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] - documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] - attributes = [:publication_date, :budget_investment_id, :status_id, - translation_params(Budget::Investment::Milestone), - image_attributes: image_attributes, documents_attributes: documents_attributes] - - params.require(:budget_investment_milestone).permit(*attributes) + def milestoneable + Budget::Investment.find(params[:budget_investment_id]) end - - def load_budget_investment - @investment = Budget::Investment.find(params[:budget_investment_id]) - end - - def load_budget_investment_milestone - @milestone = get_milestone - end - - def get_milestone - Budget::Investment::Milestone.find(params[:id]) - end - - def resource - get_milestone - end - - def load_statuses - @statuses = Budget::Investment::Status.all - end - end diff --git a/app/controllers/admin/proposals_controller.rb b/app/controllers/admin/hidden_proposals_controller.rb similarity index 84% rename from app/controllers/admin/proposals_controller.rb rename to app/controllers/admin/hidden_proposals_controller.rb index dbc09b3da..48c910c0c 100644 --- a/app/controllers/admin/proposals_controller.rb +++ b/app/controllers/admin/hidden_proposals_controller.rb @@ -1,7 +1,7 @@ -class Admin::ProposalsController < Admin::BaseController +class Admin::HiddenProposalsController < Admin::BaseController include FeatureFlags - has_filters %w{without_confirmed_hide all with_confirmed_hide}, only: :index + has_filters %w[without_confirmed_hide all with_confirmed_hide], only: :index feature_flag :proposals diff --git a/app/controllers/admin/budget_investment_statuses_controller.rb b/app/controllers/admin/milestone_statuses_controller.rb similarity index 52% rename from app/controllers/admin/budget_investment_statuses_controller.rb rename to app/controllers/admin/milestone_statuses_controller.rb index c3d7a4e16..18c573ab3 100644 --- a/app/controllers/admin/budget_investment_statuses_controller.rb +++ b/app/controllers/admin/milestone_statuses_controller.rb @@ -1,20 +1,20 @@ -class Admin::BudgetInvestmentStatusesController < Admin::BaseController +class Admin::MilestoneStatusesController < Admin::BaseController before_action :load_status, only: [:edit, :update, :destroy] def index - @statuses = Budget::Investment::Status.all + @statuses = Milestone::Status.all end def new - @status = Budget::Investment::Status.new + @status = Milestone::Status.new end def create - @status = Budget::Investment::Status.new(status_params) + @status = Milestone::Status.new(status_params) if @status.save - redirect_to admin_budget_investment_statuses_path, + redirect_to admin_milestone_statuses_path, notice: t('admin.statuses.create.notice') else render :new @@ -26,7 +26,7 @@ class Admin::BudgetInvestmentStatusesController < Admin::BaseController def update if @status.update(status_params) - redirect_to admin_budget_investment_statuses_path, + redirect_to admin_milestone_statuses_path, notice: t('admin.statuses.update.notice') else render :edit @@ -35,17 +35,17 @@ class Admin::BudgetInvestmentStatusesController < Admin::BaseController def destroy @status.destroy - redirect_to admin_budget_investment_statuses_path, + redirect_to admin_milestone_statuses_path, notice: t('admin.statuses.delete.notice') end private def load_status - @status = Budget::Investment::Status.find(params[:id]) + @status = Milestone::Status.find(params[:id]) end def status_params - params.require(:budget_investment_status).permit([:name, :description]) + params.require(:milestone_status).permit([:name, :description]) end end diff --git a/app/controllers/admin/milestones_controller.rb b/app/controllers/admin/milestones_controller.rb new file mode 100644 index 000000000..13a277957 --- /dev/null +++ b/app/controllers/admin/milestones_controller.rb @@ -0,0 +1,72 @@ +class Admin::MilestonesController < Admin::BaseController + include Translatable + + before_action :load_milestoneable, only: [:index, :new, :create, :edit, :update, :destroy] + before_action :load_milestone, only: [:edit, :update, :destroy] + before_action :load_statuses, only: [:index, :new, :create, :edit, :update] + helper_method :milestoneable_path + + def index + end + + def new + @milestone = @milestoneable.milestones.new + end + + def create + @milestone = @milestoneable.milestones.new(milestone_params) + if @milestone.save + redirect_to milestoneable_path, notice: t('admin.milestones.create.notice') + else + render :new + end + end + + def edit + end + + def update + if @milestone.update(milestone_params) + redirect_to milestoneable_path, notice: t('admin.milestones.update.notice') + else + render :edit + end + end + + def destroy + @milestone.destroy + redirect_to milestoneable_path, notice: t('admin.milestones.delete.notice') + end + + private + + def milestone_params + image_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] + documents_attributes = [:id, :title, :attachment, :cached_attachment, :user_id, :_destroy] + attributes = [:publication_date, :status_id, + translation_params(Milestone), + image_attributes: image_attributes, documents_attributes: documents_attributes] + + params.require(:milestone).permit(*attributes) + end + + def load_milestoneable + @milestoneable = milestoneable + end + + def milestoneable + raise "Implement in subclass" + end + + def load_milestone + @milestone = @milestoneable.milestones.find(params[:id]) + end + + def load_statuses + @statuses = Milestone::Status.all + end + + def milestoneable_path + polymorphic_path([:admin, *resource_hierarchy_for(@milestone.milestoneable)]) + end +end diff --git a/app/controllers/budgets/executions_controller.rb b/app/controllers/budgets/executions_controller.rb index b321c4377..e17763090 100644 --- a/app/controllers/budgets/executions_controller.rb +++ b/app/controllers/budgets/executions_controller.rb @@ -6,7 +6,7 @@ module Budgets def show authorize! :read_executions, @budget - @statuses = ::Budget::Investment::Status.all + @statuses = Milestone::Status.all if params[:status].present? @investments_by_heading = @budget.investments.winners diff --git a/app/controllers/budgets/investments_controller.rb b/app/controllers/budgets/investments_controller.rb index b048cc4f5..a456ff54e 100644 --- a/app/controllers/budgets/investments_controller.rb +++ b/app/controllers/budgets/investments_controller.rb @@ -1,5 +1,7 @@ module Budgets class InvestmentsController < ApplicationController + OSM_DISTRICT_LEVEL_ZOOM = 12 + include FeatureFlags include CommentableActions include FlagActions @@ -33,13 +35,17 @@ module Budgets respond_to :html, :js def index - if @budget.finished? - @investments = investments.winners.page(params[:page]).per(10).for_render - else - @investments = investments.page(params[:page]).per(10).for_render - end + all_investments = if @budget.finished? + investments.winners + else + investments + end + + @investments = all_investments.page(params[:page]).per(10).for_render @investment_ids = @investments.pluck(:id) + @investments_map_coordinates = MapLocation.where(investment_id: all_investments).map { |l| l.json_data } + load_investment_votes(@investments) @tag_cloud = tag_cloud end @@ -143,6 +149,7 @@ module Budgets if params[:heading_id].present? @heading = @budget.headings.find(params[:heading_id]) @assigned_heading = @ballot.try(:heading_for_group, @heading.try(:group)) + load_map end end @@ -172,6 +179,13 @@ module Budgets end end + def load_map + @map_location = MapLocation.new + @map_location.zoom = OSM_DISTRICT_LEVEL_ZOOM + @map_location.latitude = @heading.latitude.to_f + @map_location.longitude = @heading.longitude.to_f + end + end end diff --git a/app/controllers/legislation/processes_controller.rb b/app/controllers/legislation/processes_controller.rb index c0ac5648e..fd301fb07 100644 --- a/app/controllers/legislation/processes_controller.rb +++ b/app/controllers/legislation/processes_controller.rb @@ -117,13 +117,12 @@ class Legislation::ProcessesController < Legislation::BaseController end def set_random_seed - seed = begin - Float(params[:random_seed] || session[:random_seed] || (rand(99) / 100.0)) - rescue - 0 - end - session[:random_seed], params[:random_seed] = seed + seed = (params[:random_seed] || session[:random_seed] || rand).to_f seed = (-1..1).cover?(seed) ? seed : 1 + + session[:random_seed] = seed + params[:random_seed] = seed + ::Legislation::Proposal.connection.execute "select setseed(#{seed})" end end diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 798aeebf2..fe0599eab 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -44,8 +44,7 @@ class ProposalsController < ApplicationController def index_customization discard_archived load_retired - load_successful_proposals - load_featured unless @proposal_successful_exists + load_featured end def vote @@ -131,10 +130,13 @@ class ProposalsController < ApplicationController def load_featured return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations" - @featured_proposals = Proposal.not_archived.sort_by_confidence_score.limit(3) - if @featured_proposals.present? - set_featured_proposal_votes(@featured_proposals) - @resources = @resources.where('proposals.id NOT IN (?)', @featured_proposals.map(&:id)) + if Setting['feature.featured_proposals'] + @featured_proposals = Proposal.not_archived.unsuccessful + .sort_by_confidence_score.limit(Setting['featured_proposals_number']) + if @featured_proposals.present? + set_featured_proposal_votes(@featured_proposals) + @resources = @resources.where('proposals.id NOT IN (?)', @featured_proposals.map(&:id)) + end end end @@ -142,10 +144,6 @@ class ProposalsController < ApplicationController @view = (params[:view] == "minimal") ? "minimal" : "default" end - def load_successful_proposals - @proposal_successful_exists = Proposal.successful.exists? - end - def destroy_map_location_association map_location = params[:proposal][:map_location_attributes] if map_location && (map_location[:longitude] && map_location[:latitude]).blank? && !map_location[:id].blank? diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index 0856ff87b..afce592a9 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -21,7 +21,12 @@ module AdminHelper end def menu_moderated_content? - ["proposals", "debates", "comments", "hidden_users", "activity", "hidden_budget_investments"].include?(controller_name) && controller.class.parent != Admin::Legislation + moderated_sections.include?(controller_name) && controller.class.parent != Admin::Legislation + end + + def moderated_sections + ["hidden_proposals", "debates", "comments", "hidden_users", "activity", + "hidden_budget_investments"] end def menu_budget? diff --git a/app/helpers/legislation_helper.rb b/app/helpers/legislation_helper.rb index 38eba39ad..b2cd1399c 100644 --- a/app/helpers/legislation_helper.rb +++ b/app/helpers/legislation_helper.rb @@ -26,4 +26,13 @@ module LegislationHelper method: :patch, class: html_class end + + def legislation_process_tabs(process) + { + "info" => edit_admin_legislation_process_path(process), + "questions" => admin_legislation_process_questions_path(process), + "proposals" => admin_legislation_process_proposals_path(process), + "draft_versions" => admin_legislation_process_draft_versions_path(process) + } + end end diff --git a/app/models/budget/heading.rb b/app/models/budget/heading.rb index 555240e6a..20f9aa921 100644 --- a/app/models/budget/heading.rb +++ b/app/models/budget/heading.rb @@ -12,6 +12,10 @@ class Budget validates :price, presence: true validates :slug, presence: true, format: /\A[a-z0-9\-_]+\z/ validates :population, numericality: { greater_than: 0 }, allow_nil: true + validates :latitude, length: { maximum: 22, minimum: 1 }, presence: true, \ + format: /\A(-|\+)?([1-8]?\d(?:\.\d{1,})?|90(?:\.0{1,6})?)\z/ + validates :longitude, length: { maximum: 22, minimum: 1}, presence: true, \ + format: /\A(-|\+)?((?:1[0-7]|[1-9])?\d(?:\.\d{1,})?|180(?:\.0{1,})?)\z/ delegate :budget, :budget_id, to: :group, allow_nil: true diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 486e65052..4143300eb 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -24,6 +24,7 @@ class Budget include Notifiable include Filterable include Flaggable + include Milestoneable belongs_to :author, -> { with_hidden }, class_name: 'User', foreign_key: 'author_id' belongs_to :heading @@ -40,8 +41,6 @@ class Budget has_many :comments, -> {where(valuation: false)}, as: :commentable, class_name: 'Comment' has_many :valuations, -> {where(valuation: true)}, as: :commentable, class_name: 'Comment' - has_many :milestones - validates :title, presence: true validates :author, presence: true validates :description, presence: true diff --git a/app/models/budget/investment/milestone.rb b/app/models/budget/investment/milestone.rb deleted file mode 100644 index f59705ede..000000000 --- a/app/models/budget/investment/milestone.rb +++ /dev/null @@ -1,35 +0,0 @@ -class Budget - class Investment - class Milestone < ActiveRecord::Base - include Imageable - include Documentable - documentable max_documents_allowed: 3, - max_file_size: 3.megabytes, - accepted_content_types: [ "application/pdf" ] - - translates :title, :description, touch: true - include Globalizable - - belongs_to :investment - belongs_to :status, class_name: 'Budget::Investment::Status' - - validates :investment, presence: true - validates :publication_date, presence: true - validate :description_or_status_present? - - scope :order_by_publication_date, -> { order(publication_date: :asc, created_at: :asc) } - scope :published, -> { where("publication_date <= ?", Date.current) } - scope :with_status, -> { where("status_id IS NOT NULL") } - - def self.title_max_length - 80 - end - - def description_or_status_present? - unless description.present? || status_id.present? - errors.add(:description) - end - end - end - end -end diff --git a/app/models/budget/reclassification.rb b/app/models/budget/reclassification.rb index b77dc374a..7eefc0d33 100644 --- a/app/models/budget/reclassification.rb +++ b/app/models/budget/reclassification.rb @@ -30,7 +30,7 @@ class Budget end def store_reclassified_votes(reason) - ballot_lines_for_investment.each do |line| + ballot_lines_for_investment.order(:id).each do |line| attrs = { user: line.ballot.user, investment: self, reason: reason } diff --git a/app/models/concerns/milestoneable.rb b/app/models/concerns/milestoneable.rb new file mode 100644 index 000000000..7bae4a61a --- /dev/null +++ b/app/models/concerns/milestoneable.rb @@ -0,0 +1,7 @@ +module Milestoneable + extend ActiveSupport::Concern + + included do + has_many :milestones, as: :milestoneable, dependent: :destroy + end +end diff --git a/app/models/milestone.rb b/app/models/milestone.rb new file mode 100644 index 000000000..1b4790040 --- /dev/null +++ b/app/models/milestone.rb @@ -0,0 +1,31 @@ +class Milestone < ActiveRecord::Base + include Imageable + include Documentable + documentable max_documents_allowed: 3, + max_file_size: 3.megabytes, + accepted_content_types: [ "application/pdf" ] + + translates :title, :description, touch: true + include Globalizable + + belongs_to :milestoneable, polymorphic: true + belongs_to :status + + validates :milestoneable, presence: true + validates :publication_date, presence: true + validate :description_or_status_present? + + scope :order_by_publication_date, -> { order(publication_date: :asc, created_at: :asc) } + scope :published, -> { where("publication_date <= ?", Date.current) } + scope :with_status, -> { where("status_id IS NOT NULL") } + + def self.title_max_length + 80 + end + + def description_or_status_present? + unless description.present? || status_id.present? + errors.add(:description) + end + end +end diff --git a/app/models/budget/investment/status.rb b/app/models/milestone/status.rb similarity index 65% rename from app/models/budget/investment/status.rb rename to app/models/milestone/status.rb index df2b991ba..51b03427d 100644 --- a/app/models/budget/investment/status.rb +++ b/app/models/milestone/status.rb @@ -1,4 +1,4 @@ -class Budget::Investment::Status < ActiveRecord::Base +class Milestone::Status < ActiveRecord::Base acts_as_paranoid column: :hidden_at has_many :milestones diff --git a/app/models/poll.rb b/app/models/poll.rb index 38c1a7d56..35b888c90 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -90,6 +90,10 @@ class Poll < ActiveRecord::Base Poll::Voter.where(poll: self, user: user, origin: "web").exists? end + def voted_by?(user) + Poll::Voter.where(poll: self, user: user).exists? + end + def date_range unless starts_at.present? && ends_at.present? && starts_at <= ends_at errors.add(:starts_at, I18n.t('errors.messages.invalid_date_range')) diff --git a/app/models/poll/shift.rb b/app/models/poll/shift.rb index e3cfd2280..d9803f237 100644 --- a/app/models/poll/shift.rb +++ b/app/models/poll/shift.rb @@ -24,7 +24,7 @@ class Poll end def create_officer_assignments - booth.booth_assignments.each do |booth_assignment| + booth.booth_assignments.order(:id).each do |booth_assignment| attrs = { officer_id: officer_id, date: date, diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index 911bc0713..5344c06f8 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -57,7 +57,7 @@ <% if feature?(:budgets) %>
  • "> + controller_name == "milestone_statuses" %>"> <%= link_to admin_budgets_path do %> <%= t("admin.menu.budgets") %> @@ -144,8 +144,8 @@