From 9ce524e1f3a2f9a7c9c276d5e4b87ddafe500682 Mon Sep 17 00:00:00 2001 From: German Galia Date: Mon, 3 Jun 2019 09:29:52 +0200 Subject: [PATCH] Create tracker rol --- ...budget_investment_milestones_controller.rb | 8 - ...get_investment_progress_bars_controller.rb | 8 - .../admin/budget_investments_controller.rb | 8 +- .../legislation/milestones_controller.rb | 6 +- .../admin/milestones_controller.rb | 72 ---- .../admin/proposal_milestones_controller.rb | 8 - app/controllers/admin/trackers_controller.rb | 56 +++ app/controllers/tracking/base_controller.rb | 15 + ...budget_investment_milestones_controller.rb | 8 + ...get_investment_progress_bars_controller.rb | 17 + .../tracking/budget_investments_controller.rb | 83 ++++ .../tracking/budgets_controller.rb | 14 + .../legislation/milestones_controller.rb | 18 + .../legislation/progress_bars_controller.rb | 2 +- .../tracking/milestones_controller.rb | 73 ++++ .../progress_bars_controller.rb | 10 +- .../proposal_milestones_controller.rb | 8 + .../proposal_progress_bars_controller.rb | 2 +- app/helpers/trackers_helper.rb | 21 + app/helpers/users_helper.rb | 10 +- app/models/abilities/administrator.rb | 1 + app/models/abilities/tracker.rb | 14 + app/models/ability.rb | 1 + app/models/budget/investment.rb | 7 +- app/models/budget/tracker_assignment.rb | 6 + app/models/tracker.rb | 30 ++ app/models/user.rb | 5 + app/views/admin/_menu.html.erb | 4 + .../admin/budget_investments/edit.html.erb | 10 + .../admin/budget_investments/show.html.erb | 13 +- .../legislation/milestones/index.html.erb | 2 +- app/views/admin/progress_bars/edit.html.erb | 15 - app/views/admin/progress_bars/index.html.erb | 9 - app/views/admin/progress_bars/new.html.erb | 9 - app/views/admin/proposals/show.html.erb | 2 +- app/views/admin/trackers/_form.html.erb | 32 ++ app/views/admin/trackers/edit.html.erb | 16 + app/views/admin/trackers/index.html.erb | 48 +++ app/views/admin/trackers/search.html.erb | 58 +++ app/views/admin/trackers/show.html.erb | 22 ++ app/views/shared/_admin_login_items.html.erb | 7 + app/views/tracking/_menu.html.erb | 17 + .../tracking/budget_investments/edit.html.erb | 12 + .../budget_investments/index.html.erb | 58 +++ .../tracking/budget_investments/show.html.erb | 47 +++ app/views/tracking/budgets/index.html.erb | 36 ++ .../milestones/_form.html.erb | 10 +- .../milestones/_milestones.html.erb | 36 +- .../milestones/edit.html.erb | 2 +- .../milestones/new.html.erb | 2 +- .../progress_bars/_form.html.erb | 2 +- .../progress_bars/_progress_bars.html.erb | 22 +- .../tracking/progress_bars/edit.html.erb | 15 + .../tracking/progress_bars/index.html.erb | 9 + app/views/tracking/progress_bars/new.html.erb | 9 + config/i18n-tasks.yml | 1 + config/locales/en/admin.yml | 76 ++-- config/locales/en/general.yml | 1 + config/locales/en/tracking.yml | 92 +++++ config/locales/es/admin.yml | 72 ++-- config/locales/es/general.yml | 1 + config/locales/es/tracking.yml | 92 +++++ config/routes.rb | 1 + config/routes/admin.rb | 10 +- config/routes/tracking.rb | 23 ++ db/migrate/20190426075419_create_trackers.rb | 11 + ...20406_create_budget_tracker_assignments.rb | 10 + ...assignments_count_to_budget_investments.rb | 5 + db/schema.rb | 21 + spec/factories/users.rb | 4 + .../budget_investment_milestones_spec.rb | 2 +- spec/features/officing_spec.rb | 2 +- .../tracking/budget_investments_spec.rb | 365 ++++++++++++++++++ spec/features/tracking/budgets_spec.rb | 31 ++ spec/shared/features/admin_progressable.rb | 2 +- 75 files changed, 1586 insertions(+), 271 deletions(-) delete mode 100644 app/controllers/admin/budget_investment_milestones_controller.rb delete mode 100644 app/controllers/admin/budget_investment_progress_bars_controller.rb delete mode 100644 app/controllers/admin/milestones_controller.rb delete mode 100644 app/controllers/admin/proposal_milestones_controller.rb create mode 100644 app/controllers/admin/trackers_controller.rb create mode 100644 app/controllers/tracking/base_controller.rb create mode 100644 app/controllers/tracking/budget_investment_milestones_controller.rb create mode 100644 app/controllers/tracking/budget_investment_progress_bars_controller.rb create mode 100644 app/controllers/tracking/budget_investments_controller.rb create mode 100644 app/controllers/tracking/budgets_controller.rb create mode 100644 app/controllers/tracking/legislation/milestones_controller.rb rename app/controllers/{admin => tracking}/legislation/progress_bars_controller.rb (69%) create mode 100644 app/controllers/tracking/milestones_controller.rb rename app/controllers/{admin => tracking}/progress_bars_controller.rb (72%) create mode 100644 app/controllers/tracking/proposal_milestones_controller.rb rename app/controllers/{admin => tracking}/proposal_progress_bars_controller.rb (50%) create mode 100644 app/helpers/trackers_helper.rb create mode 100644 app/models/abilities/tracker.rb create mode 100644 app/models/budget/tracker_assignment.rb create mode 100644 app/models/tracker.rb delete mode 100644 app/views/admin/progress_bars/edit.html.erb delete mode 100644 app/views/admin/progress_bars/index.html.erb delete mode 100644 app/views/admin/progress_bars/new.html.erb create mode 100644 app/views/admin/trackers/_form.html.erb create mode 100644 app/views/admin/trackers/edit.html.erb create mode 100644 app/views/admin/trackers/index.html.erb create mode 100644 app/views/admin/trackers/search.html.erb create mode 100644 app/views/admin/trackers/show.html.erb create mode 100644 app/views/tracking/_menu.html.erb create mode 100644 app/views/tracking/budget_investments/edit.html.erb create mode 100644 app/views/tracking/budget_investments/index.html.erb create mode 100644 app/views/tracking/budget_investments/show.html.erb create mode 100644 app/views/tracking/budgets/index.html.erb rename app/views/{admin => tracking}/milestones/_form.html.erb (73%) rename app/views/{admin => tracking}/milestones/_milestones.html.erb (59%) rename app/views/{admin => tracking}/milestones/edit.html.erb (65%) rename app/views/{admin => tracking}/milestones/new.html.erb (72%) rename app/views/{admin => tracking}/progress_bars/_form.html.erb (92%) rename app/views/{admin => tracking}/progress_bars/_progress_bars.html.erb (60%) create mode 100644 app/views/tracking/progress_bars/edit.html.erb create mode 100644 app/views/tracking/progress_bars/index.html.erb create mode 100644 app/views/tracking/progress_bars/new.html.erb create mode 100644 config/locales/en/tracking.yml create mode 100644 config/locales/es/tracking.yml create mode 100644 config/routes/tracking.rb create mode 100644 db/migrate/20190426075419_create_trackers.rb create mode 100644 db/migrate/20190426120406_create_budget_tracker_assignments.rb create mode 100644 db/migrate/20190429102006_add_tracker_assignments_count_to_budget_investments.rb create mode 100644 spec/features/tracking/budget_investments_spec.rb create mode 100644 spec/features/tracking/budgets_spec.rb diff --git a/app/controllers/admin/budget_investment_milestones_controller.rb b/app/controllers/admin/budget_investment_milestones_controller.rb deleted file mode 100644 index f354d42fa..000000000 --- a/app/controllers/admin/budget_investment_milestones_controller.rb +++ /dev/null @@ -1,8 +0,0 @@ -class Admin::BudgetInvestmentMilestonesController < Admin::MilestonesController - - private - - def milestoneable - Budget::Investment.find(params[:budget_investment_id]) - end -end diff --git a/app/controllers/admin/budget_investment_progress_bars_controller.rb b/app/controllers/admin/budget_investment_progress_bars_controller.rb deleted file mode 100644 index bb4db0d79..000000000 --- a/app/controllers/admin/budget_investment_progress_bars_controller.rb +++ /dev/null @@ -1,8 +0,0 @@ -class Admin::BudgetInvestmentProgressBarsController < Admin::ProgressBarsController - - private - - def progressable - Budget::Investment.find(params[:budget_investment_id]) - end -end diff --git a/app/controllers/admin/budget_investments_controller.rb b/app/controllers/admin/budget_investments_controller.rb index e4416a9ee..f264249f4 100644 --- a/app/controllers/admin/budget_investments_controller.rb +++ b/app/controllers/admin/budget_investments_controller.rb @@ -37,6 +37,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController load_admins load_valuators load_valuator_groups + load_trackers load_tags end @@ -50,6 +51,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController load_admins load_valuators load_valuator_groups + load_trackers load_tags render :edit end @@ -88,7 +90,7 @@ class Admin::BudgetInvestmentsController < Admin::BaseController params.require(:budget_investment) .permit(:title, :description, :external_url, :heading_id, :administrator_id, :tag_list, :valuation_tag_list, :incompatible, :visible_to_valuators, :selected, - :milestone_tag_list, valuator_ids: [], valuator_group_ids: []) + :milestone_tag_list, tracker_ids: [], valuator_ids: [], valuator_group_ids: []) end def load_budget @@ -103,6 +105,10 @@ class Admin::BudgetInvestmentsController < Admin::BaseController @admins = Administrator.includes(:user).all end + def load_trackers + @trackers = Tracker.includes(:user).all.order(description: :asc).order("users.email ASC") + end + def load_valuators @valuators = Valuator.includes(:user).all.order(description: :asc).order("users.email ASC") end diff --git a/app/controllers/admin/legislation/milestones_controller.rb b/app/controllers/admin/legislation/milestones_controller.rb index 09d55f6ca..aba0c673f 100644 --- a/app/controllers/admin/legislation/milestones_controller.rb +++ b/app/controllers/admin/legislation/milestones_controller.rb @@ -1,4 +1,4 @@ -class Admin::Legislation::MilestonesController < Admin::MilestonesController +class Admin::Legislation::MilestonesController < Tracking::MilestonesController include FeatureFlags feature_flag :legislation @@ -11,8 +11,4 @@ class Admin::Legislation::MilestonesController < Admin::MilestonesController def milestoneable ::Legislation::Process.find(params[:process_id]) end - - def milestoneable_path - admin_legislation_process_milestones_path(milestoneable) - end end diff --git a/app/controllers/admin/milestones_controller.rb b/app/controllers/admin/milestones_controller.rb deleted file mode 100644 index e6fbe100b..000000000 --- a/app/controllers/admin/milestones_controller.rb +++ /dev/null @@ -1,72 +0,0 @@ -class Admin::MilestonesController < Admin::BaseController - include Translatable - include ImageAttributes - - 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 - 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/admin/proposal_milestones_controller.rb b/app/controllers/admin/proposal_milestones_controller.rb deleted file mode 100644 index 3dec8463b..000000000 --- a/app/controllers/admin/proposal_milestones_controller.rb +++ /dev/null @@ -1,8 +0,0 @@ -class Admin::ProposalMilestonesController < Admin::MilestonesController - - private - - def milestoneable - Proposal.find(params[:proposal_id]) - end -end diff --git a/app/controllers/admin/trackers_controller.rb b/app/controllers/admin/trackers_controller.rb new file mode 100644 index 000000000..538b614f7 --- /dev/null +++ b/app/controllers/admin/trackers_controller.rb @@ -0,0 +1,56 @@ +class Admin::TrackersController < Admin::BaseController + load_and_authorize_resource + + before_action :set_tracker, only: [:show, :edit, :update, :destroy] + + def show + @tracker = Tracker.find(params[:id]) + end + + def index + @trackers = @trackers.page(params[:page]) + end + + def search + @users = User.search(params[:name_or_email]) + .includes(:tracker) + .page(params[:page]) + .for_render + end + + def create + @tracker = Tracker.new(tracker_params) + @tracker.save + + redirect_to admin_trackers_path + end + + def edit + @tracker = Tracker.find(params[:id]) + end + + def update + @tracker = Tracker.find(params[:id]) + if @tracker.update(tracker_params) + notice = t("admin.trackers.form.updated") + redirect_to [:admin, @tracker], notice: notice + else + render :edit + end + end + + def destroy + @tracker.destroy + redirect_to admin_trackers_path + end + + private + def set_tracker + @tracker = Tracker.find(params[:id]) + end + + def tracker_params + params[:tracker][:description] = nil if params[:tracker][:description].blank? + params.require(:tracker).permit(:user_id, :description, :budget_investment_count) + end +end diff --git a/app/controllers/tracking/base_controller.rb b/app/controllers/tracking/base_controller.rb new file mode 100644 index 000000000..f924bc088 --- /dev/null +++ b/app/controllers/tracking/base_controller.rb @@ -0,0 +1,15 @@ +class Tracking::BaseController < ApplicationController + layout "admin" + + before_action :authenticate_user! + before_action :verify_tracker + + skip_authorization_check + + private + + def verify_tracker + raise CanCan::AccessDenied unless current_user.try(:tracker?) || current_user.try(:administrator?) + end + +end diff --git a/app/controllers/tracking/budget_investment_milestones_controller.rb b/app/controllers/tracking/budget_investment_milestones_controller.rb new file mode 100644 index 000000000..3abd27e40 --- /dev/null +++ b/app/controllers/tracking/budget_investment_milestones_controller.rb @@ -0,0 +1,8 @@ +class Tracking::BudgetInvestmentMilestonesController < Tracking::MilestonesController + + private + + def milestoneable + Budget::Investment.find(params[:budget_investment_id]) + end +end diff --git a/app/controllers/tracking/budget_investment_progress_bars_controller.rb b/app/controllers/tracking/budget_investment_progress_bars_controller.rb new file mode 100644 index 000000000..b949f11f1 --- /dev/null +++ b/app/controllers/tracking/budget_investment_progress_bars_controller.rb @@ -0,0 +1,17 @@ +class Tracking::BudgetInvestmentProgressBarsController < Tracking::ProgressBarsController + + before_action :restrict_access_to_assigned_items + + private + + def progressable + Budget::Investment.find(params[:budget_investment_id]) + end + + def restrict_access_to_assigned_items + return if current_user.administrator? || + Budget::TrackerAssignment.exists?(investment_id: params[:budget_investment_id], + tracker_id: current_user.tracker.id) + raise ActionController::RoutingError.new("Not Found") + end +end diff --git a/app/controllers/tracking/budget_investments_controller.rb b/app/controllers/tracking/budget_investments_controller.rb new file mode 100644 index 000000000..65afda323 --- /dev/null +++ b/app/controllers/tracking/budget_investments_controller.rb @@ -0,0 +1,83 @@ +class Tracking::BudgetInvestmentsController < Tracking::BaseController + include FeatureFlags + include CommentableActions + + feature_flag :budgets + + before_action :restrict_access_to_assigned_items, only: [:show, :edit] + before_action :load_budget + before_action :load_investment, only: [:show, :edit] + + has_orders %w{oldest}, only: [:show, :edit] + + load_and_authorize_resource :investment, class: "Budget::Investment" + + def index + @heading_filters = heading_filters + @investments = if current_user.tracker? && @budget.present? + current_user.tracker.investments_by_heading(heading_params, @budget) + .page(params[:page]) + else + Budget::Investment.none.page(params[:page]) + end + end + + def show + end + + def edit + end + + private + + def resource_model + Budget::Investment + end + + def resource_name + resource_model.parameterize(separator: "_") + end + + def load_budget + @budget = Budget.find(params[:budget_id]) + end + + def load_investment + @investment = @budget.investments.find params[:id] + end + + def heading_filters + investments = @budget.investments.by_tracker(current_user.tracker.try(:id)) + .distinct + investment_headings = Budget::Heading.where(id: investments.pluck(:heading_id).uniq) + .order(name: :asc) + all_headings_filter = [ + { + name: t("valuation.budget_investments.index.headings_filter_all"), + id: nil, + count: investments.size + } + ] + + filters = investment_headings.inject(all_headings_filter) do |filters, heading| + filters << { + name: heading.name, + id: heading.id, + count: investments.select{|i| i.heading_id == heading.id}.size + } + end + filters.uniq + end + + def restrict_access_to_assigned_items + return if current_user.administrator? || + Budget::TrackerAssignment.exists?(investment_id: params[:id], + tracker_id: current_user.tracker.id) + raise ActionController::RoutingError.new("Not Found") + end + + def heading_params + params.permit(:heading_id) + end + +end diff --git a/app/controllers/tracking/budgets_controller.rb b/app/controllers/tracking/budgets_controller.rb new file mode 100644 index 000000000..0e33ecf03 --- /dev/null +++ b/app/controllers/tracking/budgets_controller.rb @@ -0,0 +1,14 @@ +class Tracking::BudgetsController < Tracking::BaseController + include FeatureFlags + feature_flag :budgets + + load_and_authorize_resource + + def index + @budget = current_budget + if @budget.present? + @investments = @budget.investments + .by_tracker(current_user.tracker) + end + end +end diff --git a/app/controllers/tracking/legislation/milestones_controller.rb b/app/controllers/tracking/legislation/milestones_controller.rb new file mode 100644 index 000000000..458bdb650 --- /dev/null +++ b/app/controllers/tracking/legislation/milestones_controller.rb @@ -0,0 +1,18 @@ +class Tracking::Legislation::MilestonesController < Tracking::MilestonesController + include FeatureFlags + feature_flag :legislation + + def index + @process = milestoneable + end + + private + + def milestoneable + ::Legislation::Process.find(params[:process_id]) + end + + def milestoneable_path + admin_legislation_process_milestones_path(milestoneable) + end +end diff --git a/app/controllers/admin/legislation/progress_bars_controller.rb b/app/controllers/tracking/legislation/progress_bars_controller.rb similarity index 69% rename from app/controllers/admin/legislation/progress_bars_controller.rb rename to app/controllers/tracking/legislation/progress_bars_controller.rb index ba00d5e91..38ed60788 100644 --- a/app/controllers/admin/legislation/progress_bars_controller.rb +++ b/app/controllers/tracking/legislation/progress_bars_controller.rb @@ -1,4 +1,4 @@ -class Admin::Legislation::ProgressBarsController < Admin::ProgressBarsController +class Tracking::Legislation::ProgressBarsController < Tracking::ProgressBarsController include FeatureFlags feature_flag :legislation diff --git a/app/controllers/tracking/milestones_controller.rb b/app/controllers/tracking/milestones_controller.rb new file mode 100644 index 000000000..2d99dd2c8 --- /dev/null +++ b/app/controllers/tracking/milestones_controller.rb @@ -0,0 +1,73 @@ +class Tracking::MilestonesController < Tracking::BaseController + include Translatable + include ImageAttributes + + 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("tracking.milestones.create.notice") + else + render :new + end + end + + def edit + end + + def update + if @milestone.update(milestone_params) + redirect_to milestoneable_path, notice: t("tracking.milestones.update.notice") + else + render :edit + end + end + + def destroy + @milestone.destroy + redirect_to milestoneable_path, notice: t("tracking.milestones.delete.notice") + end + + private + + def milestone_params + 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([current_user.administrator? ? :admin : :tracking, + *resource_hierarchy_for(@milestone.milestoneable)]) + end +end diff --git a/app/controllers/admin/progress_bars_controller.rb b/app/controllers/tracking/progress_bars_controller.rb similarity index 72% rename from app/controllers/admin/progress_bars_controller.rb rename to app/controllers/tracking/progress_bars_controller.rb index 3ef397a6a..12985dd19 100644 --- a/app/controllers/admin/progress_bars_controller.rb +++ b/app/controllers/tracking/progress_bars_controller.rb @@ -1,4 +1,4 @@ -class Admin::ProgressBarsController < Admin::BaseController +class Tracking::ProgressBarsController < Tracking::BaseController include Translatable before_action :load_progressable @@ -15,7 +15,7 @@ class Admin::ProgressBarsController < Admin::BaseController def create @progress_bar = @progressable.progress_bars.new(progress_bar_params) if @progress_bar.save - redirect_to progress_bars_index, notice: t("admin.progress_bars.create.notice") + redirect_to progress_bars_index, notice: t("tracking.progress_bars.create.notice") else render :new end @@ -26,7 +26,7 @@ class Admin::ProgressBarsController < Admin::BaseController def update if @progress_bar.update(progress_bar_params) - redirect_to progress_bars_index, notice: t("admin.progress_bars.update.notice") + redirect_to progress_bars_index, notice: t("tracking.progress_bars.update.notice") else render :edit end @@ -34,7 +34,7 @@ class Admin::ProgressBarsController < Admin::BaseController def destroy @progress_bar.destroy - redirect_to progress_bars_index, notice: t("admin.progress_bars.delete.notice") + redirect_to progress_bars_index, notice: t("tracking.progress_bars.delete.notice") end private @@ -64,6 +64,6 @@ class Admin::ProgressBarsController < Admin::BaseController end def progress_bars_index - polymorphic_path([:admin, *resource_hierarchy_for(@progressable), ProgressBar.new]) + polymorphic_path([:tracking, *resource_hierarchy_for(@progressable), ProgressBar.new]) end end diff --git a/app/controllers/tracking/proposal_milestones_controller.rb b/app/controllers/tracking/proposal_milestones_controller.rb new file mode 100644 index 000000000..eb3c294f2 --- /dev/null +++ b/app/controllers/tracking/proposal_milestones_controller.rb @@ -0,0 +1,8 @@ +class Tracking::ProposalMilestonesController < Tracking::MilestonesController + + private + + def milestoneable + Proposal.find(params[:proposal_id]) + end +end diff --git a/app/controllers/admin/proposal_progress_bars_controller.rb b/app/controllers/tracking/proposal_progress_bars_controller.rb similarity index 50% rename from app/controllers/admin/proposal_progress_bars_controller.rb rename to app/controllers/tracking/proposal_progress_bars_controller.rb index 9259acc4b..6d1c597b4 100644 --- a/app/controllers/admin/proposal_progress_bars_controller.rb +++ b/app/controllers/tracking/proposal_progress_bars_controller.rb @@ -1,4 +1,4 @@ -class Admin::ProposalProgressBarsController < Admin::ProgressBarsController +class Tracking::ProposalProgressBarsController < Tracking::ProgressBarsController private def progressable diff --git a/app/helpers/trackers_helper.rb b/app/helpers/trackers_helper.rb new file mode 100644 index 000000000..39be009d8 --- /dev/null +++ b/app/helpers/trackers_helper.rb @@ -0,0 +1,21 @@ +module TrackersHelper + + def tracker_label(tracker) + truncate([tracker.name, tracker.email, tracker.description].compact.join(" - "), length: 100) + end + + def tracker_back_path(progressable) + if progressable.class.to_s == "Legislation::Process" + admin_legislation_process_milestones_path(progressable) + else + polymorphic_path([tracker_namespace, *resource_hierarchy_for(progressable)]) + end + end + + private + + def tracker_namespace + current_user.administrator? ? :admin : :tracking + end + +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 547b25787..8427460c8 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -56,11 +56,13 @@ module UsersHelper current_user && current_user.poll_officer? end + def current_tracker? + current_user && current_user.tracker? + end + def show_admin_menu?(user = nil) - unless namespace == "officing" - current_administrator? || current_moderator? || current_valuator? || current_manager? || - (user && user.administrator?) || current_poll_officer? - end + current_administrator? || current_moderator? || current_valuator? || current_manager? || + current_tracker? || (user && user.administrator?) || current_poll_officer? end def interests_title_text(user) diff --git a/app/models/abilities/administrator.rb b/app/models/abilities/administrator.rb index e7d152518..48a1e3a6c 100644 --- a/app/models/abilities/administrator.rb +++ b/app/models/abilities/administrator.rb @@ -99,6 +99,7 @@ module Abilities can [:create, :destroy], DirectUpload can [:deliver], Newsletter, hidden_at: nil + can [:manage], ::Tracker can [:manage], Dashboard::AdministratorTask can [:edit, :update], DownloadSetting diff --git a/app/models/abilities/tracker.rb b/app/models/abilities/tracker.rb new file mode 100644 index 000000000..37279c82d --- /dev/null +++ b/app/models/abilities/tracker.rb @@ -0,0 +1,14 @@ +module Abilities + class Tracker + include CanCan::Ability + + def initialize(user) + tracker = user.tracker + + can :index, Budget + can [:index, :show, :edit], Budget::Investment + can :manage, Milestone + can :manage, ProgressBar + end + end +end diff --git a/app/models/ability.rb b/app/models/ability.rb index 4580db880..fe02c57b6 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -8,6 +8,7 @@ class Ability if user # logged-in users merge Abilities::Valuator.new(user) if user.valuator? + merge Abilities::Tracker.new(user) if user.tracker? if user.administrator? merge Abilities::Administrator.new(user) diff --git a/app/models/budget/investment.rb b/app/models/budget/investment.rb index 711b34037..105f7916f 100644 --- a/app/models/budget/investment.rb +++ b/app/models/budget/investment.rb @@ -26,6 +26,8 @@ class Budget include Milestoneable include Randomizable + extend DownloadSettings::BudgetInvestmentCsv + belongs_to :author, -> { with_hidden }, class_name: "User", foreign_key: "author_id" belongs_to :heading belongs_to :group @@ -41,7 +43,9 @@ class Budget has_many :comments, -> {where(valuation: false)}, as: :commentable, class_name: "Comment" has_many :valuations, -> {where(valuation: true)}, as: :commentable, class_name: "Comment" - extend DownloadSettings::BudgetInvestmentCsv + has_many :tracker_assignments, dependent: :destroy + has_many :trackers, through: :tracker_assignments + delegate :name, :email, to: :author, prefix: true validates :title, presence: true @@ -93,6 +97,7 @@ class Budget scope :by_admin, ->(admin_id) { where(administrator_id: admin_id) } scope :by_tag, ->(tag_name) { tagged_with(tag_name) } scope :by_valuator, ->(valuator_id) { where("budget_valuator_assignments.valuator_id = ?", valuator_id).joins(:valuator_assignments) } + scope :by_tracker, ->(tracker_id) { where("budget_tracker_assignments.tracker_id = ?", tracker_id).joins(:tracker_assignments) } scope :by_valuator_group, ->(valuator_group_id) { where("budget_valuator_group_assignments.valuator_group_id = ?", valuator_group_id).joins(:valuator_group_assignments) } scope :for_render, -> { includes(:heading) } diff --git a/app/models/budget/tracker_assignment.rb b/app/models/budget/tracker_assignment.rb new file mode 100644 index 000000000..38f1edbba --- /dev/null +++ b/app/models/budget/tracker_assignment.rb @@ -0,0 +1,6 @@ +class Budget + class TrackerAssignment < ApplicationRecord + belongs_to :tracker, counter_cache: :budget_investment_count + belongs_to :investment, counter_cache: true + end +end diff --git a/app/models/tracker.rb b/app/models/tracker.rb new file mode 100644 index 000000000..d5f5c4fa2 --- /dev/null +++ b/app/models/tracker.rb @@ -0,0 +1,30 @@ +class Tracker < ApplicationRecord + belongs_to :user, touch: true + + delegate :name, :email, :name_and_email, to: :user + + has_many :tracker_assignments, dependent: :destroy, class_name: "Budget::TrackerAssignment" + has_many :investments, through: :tracker_assignments, class_name: "Budget::Investment" + + validates :user_id, presence: true, uniqueness: true + + def description_or_email + description.present? ? description : email + end + + def description_or_name + description.present? ? description : name + end + + def assigned_investment_ids + investment_ids + end + + def investments_by_heading(params, budget) + results = investments.by_budget(budget) + if params[:heading_id].present? + results = results.by_heading(params[:heading_id]) + end + results + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 480101cff..dc1aaabad 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -15,6 +15,7 @@ class User < ApplicationRecord has_one :administrator has_one :moderator has_one :valuator + has_one :tracker has_one :manager has_one :poll_officer, class_name: "Poll::Officer" has_one :organization @@ -151,6 +152,10 @@ class User < ApplicationRecord valuator.present? end + def tracker? + tracker.present? + end + def manager? manager.present? end diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb index ac350ae06..8da96c8a5 100644 --- a/app/views/admin/_menu.html.erb +++ b/app/views/admin/_menu.html.erb @@ -212,6 +212,10 @@ <%= link_to t("admin.menu.valuators"), admin_valuators_path %> +
  • > + <%= link_to t("admin.menu.trackers"), admin_trackers_path %> +
  • +
  • > <%= link_to t("admin.menu.managers"), admin_managers_path %>
  • diff --git a/app/views/admin/budget_investments/edit.html.erb b/app/views/admin/budget_investments/edit.html.erb index 81c4a6895..23e277dd1 100644 --- a/app/views/admin/budget_investments/edit.html.erb +++ b/app/views/admin/budget_investments/edit.html.erb @@ -84,6 +84,16 @@ <% end %> + +
    +
    + <%= f.label :tracker_ids, t("admin.budget_investments.edit.assigned_trackers") %> + +
    diff --git a/app/views/admin/budget_investments/show.html.erb b/app/views/admin/budget_investments/show.html.erb index b6f7f8974..2f6f3fbce 100644 --- a/app/views/admin/budget_investments/show.html.erb +++ b/app/views/admin/budget_investments/show.html.erb @@ -50,6 +50,15 @@ <% end %>

    +

    + <%= t("admin.budget_investments.show.assigned_trackers") %>: + <% if @investment.trackers.any? %> + <%= @investment.trackers.collect(&:name_and_email).join(", ") %> + <% else %> + <%= t("admin.budget_investments.show.undefined") %> + <% end %> +

    +

    <%= link_to t("admin.budget_investments.show.edit_classification"), edit_admin_budget_budget_investment_path(@budget, @investment, @@ -66,6 +75,6 @@ <%= render "valuation/budget_investments/valuation_comments" %> -<%= render "admin/milestones/milestones", milestoneable: @investment %> - <%= render "admin/change_logs/change_log", logs: @logs %> + +<%= render "tracking/milestones/milestones", milestoneable: @investment %> diff --git a/app/views/admin/legislation/milestones/index.html.erb b/app/views/admin/legislation/milestones/index.html.erb index 456b6154a..91136e164 100644 --- a/app/views/admin/legislation/milestones/index.html.erb +++ b/app/views/admin/legislation/milestones/index.html.erb @@ -9,4 +9,4 @@ <%= render "admin/legislation/processes/subnav", process: @process, active: "milestones" %> <%= render "summary_form", process: @process %> -<%= render "admin/milestones/milestones", milestoneable: @process %> +<%= render "tracking/milestones/milestones", milestoneable: @process %> diff --git a/app/views/admin/progress_bars/edit.html.erb b/app/views/admin/progress_bars/edit.html.erb deleted file mode 100644 index 21dd27d9a..000000000 --- a/app/views/admin/progress_bars/edit.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% if @progress_bar.primary? %> - <% bar_title = t("admin.progress_bars.edit.title.primary") %> -<% else %> - <% bar_title = t("admin.progress_bars.edit.title.secondary", title: @progress_bar.title) %> -<% end %> - -<% provide :title do %> - <%= "#{t("admin.header.title")} - #{bar_title}" %> -<% end %> - -<%= back_link_to progress_bars_index %> - -

    <%= bar_title %>

    - -<%= render "form" %> diff --git a/app/views/admin/progress_bars/index.html.erb b/app/views/admin/progress_bars/index.html.erb deleted file mode 100644 index bcac8d7a4..000000000 --- a/app/views/admin/progress_bars/index.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -<% provide :title do %> - <%= "#{t("admin.header.title")} - #{t("admin.progress_bars.index.title")}" %> -<% end %> - -<%= back_link_to polymorphic_path([:admin, *resource_hierarchy_for(@progressable)]) %> - -
    - -<%= render "admin/progress_bars/progress_bars", progressable: @progressable %> diff --git a/app/views/admin/progress_bars/new.html.erb b/app/views/admin/progress_bars/new.html.erb deleted file mode 100644 index 8c379ac3a..000000000 --- a/app/views/admin/progress_bars/new.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -<% provide :title do %> - <%= "#{t("admin.header.title")} - #{t("admin.progress_bars.new.creating")}" %> -<% end %> - -<%= back_link_to progress_bars_index %> - -

    <%= t("admin.progress_bars.new.creating") %>

    - -<%= render "form" %> diff --git a/app/views/admin/proposals/show.html.erb b/app/views/admin/proposals/show.html.erb index afb2379e3..ce81e2136 100644 --- a/app/views/admin/proposals/show.html.erb +++ b/app/views/admin/proposals/show.html.erb @@ -32,4 +32,4 @@
    -<%= render "admin/milestones/milestones", milestoneable: @proposal %> +<%= render "tracking/milestones/milestones", milestoneable: @proposal %> diff --git a/app/views/admin/trackers/_form.html.erb b/app/views/admin/trackers/_form.html.erb new file mode 100644 index 000000000..f9385c65a --- /dev/null +++ b/app/views/admin/trackers/_form.html.erb @@ -0,0 +1,32 @@ +<%= form_for(tracker) do |f| %> + <% if tracker.errors.any? %> +
    +

    <%= pluralize(tracker.errors.count, "error") %> prohibited this tracker from being saved:

    + + +
    + <% end %> + +
    + <%= f.label :user_id %> + <%= f.text_field :user_id %> +
    + +
    + <%= f.label :description %> + <%= f.text_field :description %> +
    + +
    + <%= f.label :budget_investment_count %> + <%= f.number_field :budget_investment_count %> +
    + +
    + <%= f.submit %> +
    +<% end %> diff --git a/app/views/admin/trackers/edit.html.erb b/app/views/admin/trackers/edit.html.erb new file mode 100644 index 000000000..b0f1ba9ce --- /dev/null +++ b/app/views/admin/trackers/edit.html.erb @@ -0,0 +1,16 @@ +<%= back_link_to admin_trackers_path %> + +

    <%= t("admin.trackers.form.edit_title") %>

    + +
    + <%= @tracker.name %>
    + <%= @tracker.email %> +
    + +
    + <%= form_for [:admin, @tracker] do |f| %> + <%= f.text_field :description %> + <%= f.submit t("admin.trackers.form.update"), class: "button success" %> + <% end %> +
    + diff --git a/app/views/admin/trackers/index.html.erb b/app/views/admin/trackers/index.html.erb new file mode 100644 index 000000000..baf7a5311 --- /dev/null +++ b/app/views/admin/trackers/index.html.erb @@ -0,0 +1,48 @@ +

    <%= t("admin.trackers.index.title") %>

    + +<%= render "admin/shared/user_search", url: search_admin_trackers_path %> + +
    + <% if @trackers.any? %> +

    <%= page_entries_info @trackers %>

    + + + + + + + + + + <% @trackers.each do |tracker| %> + + + + + + + <% end %> + +
    <%= t("admin.trackers.index.name") %><%= t("admin.trackers.index.email") %><%= t("admin.valuators.index.description") %><%= t("admin.actions.actions") %>
    <%= link_to tracker.name, admin_tracker_path(tracker) %><%= tracker.email %> + <% if tracker.description.present? %> + <%= tracker.description %> + <% else %> + <%= t("admin.trackers.index.no_description") %> + <% end %> + + <%= link_to t("admin.actions.edit"), + edit_admin_tracker_path(tracker), + class: "button hollow" %> + <%= link_to t("admin.valuators.valuator.delete"), + admin_tracker_path(tracker), + method: :delete, + class: "button hollow alert" %> +
    + + <%= paginate @trackers %> + <% else %> +
    + <%= t("admin.trackers.index.no_trackers") %> +
    + <% end %> +
    diff --git a/app/views/admin/trackers/search.html.erb b/app/views/admin/trackers/search.html.erb new file mode 100644 index 000000000..3dc703d50 --- /dev/null +++ b/app/views/admin/trackers/search.html.erb @@ -0,0 +1,58 @@ +

    <%= t("admin.trackers.search.title") %>

    + +<%= render "admin/shared/user_search", url: search_admin_trackers_path %> + +
    + <% if @users.any? %> +

    <%= page_entries_info @users %>

    + + + + + + + + + + <% @users.each do |user| %> + + + + + + <% end %> + +
    <%= t("admin.trackers.index.name") %><%= t("admin.trackers.index.email") %><%= t("admin.trackers.index.description") %><%= t("admin.shared.actions") %>
    <%= user.name %><%= user.email %> + <% if user.tracker %> + <% if user.tracker.description.present? %> + <%= user.tracker.description %> + <% else %> + <%= t("admin.trackers.index.no_description") %> + <% end %> + <% else %> + <%= t("admin.trackers.index.no_description") %> + <% end %> + + <% if user.tracker? %> + <%= link_to t("admin.actions.edit"), + edit_admin_tracker_path(user.tracker), + class: "button hollow" %> + + <%= link_to t("admin.valuators.valuator.delete"), + admin_tracker_path(user.tracker), + method: :delete, + class: "button hollow alert" %> + <% else %> + <%= form_for Tracker.new(user: user), url: admin_trackers_path do |f| %> + <%= f.hidden_field :user_id %> + <%= f.submit t("admin.trackers.tracker.add"), + class: "button success expanded" %> + <% end %> + <% end %> +
    + <% else %> +
    + <%= t("admin.shared.no_search_results") %> +
    + <% end %> +
    diff --git a/app/views/admin/trackers/show.html.erb b/app/views/admin/trackers/show.html.erb new file mode 100644 index 000000000..9d3deaeef --- /dev/null +++ b/app/views/admin/trackers/show.html.erb @@ -0,0 +1,22 @@ +<%= back_link_to admin_trackers_path %> + +<%= link_to t("admin.actions.edit"), edit_admin_tracker_path(@tracker), class: "button hollow float-right" %> + +
    + +

    <%= @tracker.name %>

    + +
    +

    + <%= t("admin.trackers.show.email") %>
    + <%= @tracker.email %> +

    +

    + <%= t("admin.trackers.show.description") %>
    + <% if @tracker.description.present? %> + <%= @tracker.description %> + <% else %> + <%= t("admin.trackers.show.no_description") %> + <% end %> +

    +
    diff --git a/app/views/shared/_admin_login_items.html.erb b/app/views/shared/_admin_login_items.html.erb index 2d5aba1b2..11bc01444 100644 --- a/app/views/shared/_admin_login_items.html.erb +++ b/app/views/shared/_admin_login_items.html.erb @@ -21,6 +21,13 @@ <% end %> + <% if (feature?(:budgets)) && + (current_user.administrator? || current_user.tracker?) %> +
  • + <%= link_to t("layouts.header.tracking"), tracking_root_path %> +
  • + <% end %> + <% if current_user.administrator? || current_user.manager? %>
  • <%= link_to t("layouts.header.management"), management_sign_in_path %> diff --git a/app/views/tracking/_menu.html.erb b/app/views/tracking/_menu.html.erb new file mode 100644 index 000000000..ed934071e --- /dev/null +++ b/app/views/tracking/_menu.html.erb @@ -0,0 +1,17 @@ + diff --git a/app/views/tracking/budget_investments/edit.html.erb b/app/views/tracking/budget_investments/edit.html.erb new file mode 100644 index 000000000..185ecdb19 --- /dev/null +++ b/app/views/tracking/budget_investments/edit.html.erb @@ -0,0 +1,12 @@ +<%= link_to tracking_budget_budget_investment_path(@budget, @investment), class: "back" do %> + + <%= "#{t("tracking.budget_investments.show.title")} #{@investment.id}"%> +<% end %> + +
    + +

    <%= @investment.title %>

    + +<%= safe_html_with_links @investment.description %> + +<%= render "tracking/milestones/milestones", milestoneable: @investment %> diff --git a/app/views/tracking/budget_investments/index.html.erb b/app/views/tracking/budget_investments/index.html.erb new file mode 100644 index 000000000..8a777225e --- /dev/null +++ b/app/views/tracking/budget_investments/index.html.erb @@ -0,0 +1,58 @@ +

    + <%= @budget.name %> - <%= t("tracking.budget_investments.index.title") %> + <%= t("tracking.budget_investments.index.assigned_to", tracker: current_user.name) %> +

    + +
    + <% @heading_filters.each_slice(8) do |slice| %> +
    + <% slice.each do |filter| %> + <%= link_to tracking_budget_budget_investments_path(budget_id: @budget.id, heading_id: filter[:id]), + class: "#{"is-active" if params[:heading_id].to_s == filter[:id].to_s}" do %> + <%= filter[:name] %> (<%= filter[:count] %>) + <% end %> + <% end %> +
    + <% end %> +
    + +<% if @investments.any? %> +

    <%= page_entries_info @investments %>

    + + + + + + + + + + + + <% @investments.each do |investment| %> + + + + + + + <% end %> + +
    <%= t("tracking.budget_investments.index.table_id") %><%= t("tracking.budget_investments.index.table_title") %><%= t("tracking.budget_investments.index.table_heading_name") %><%= t("tracking.budget_investments.index.table_actions") %>
    + <%= investment.id %> + + <%= link_to investment.title, tracking_budget_budget_investment_path(@budget, investment) %> + + <%= investment.heading.name %> + + <%= link_to t("tracking.budget_investments.index.edit"), + edit_tracking_budget_budget_investment_path(@budget, investment), + class: "button hollow expanded" %> +
    + + <%= paginate @investments %> +<% else %> +
    + <%= t("tracking.budget_investments.index.no_investments") %> +
    +<% end %> diff --git a/app/views/tracking/budget_investments/show.html.erb b/app/views/tracking/budget_investments/show.html.erb new file mode 100644 index 000000000..dfc90d727 --- /dev/null +++ b/app/views/tracking/budget_investments/show.html.erb @@ -0,0 +1,47 @@ +<%= back_link_to tracking_budget_budget_investments_path %> + +

    <%= t("tracking.budget_investments.show.title") %> <%= @investment.id %>

    +

    <%= @investment.title %>

    + +<%= safe_html_with_links @investment.description %> + +<% if @investment.external_url.present? %> +

    <%= text_with_links @investment.external_url %>

    +<% end %> + +

    <%= t("tracking.budget_investments.show.info") %>

    + +

    <%= t("tracking.budget_investments.show.by") %>: + <%= @investment.author.name %> +

    + +

    <%= t("tracking.budget_investments.show.heading") %>: + <%= @investment.heading.name %> +

    + +

    <%= t("tracking.budget_investments.show.sent") %>: + <%= l @investment.created_at, format: :datetime %> +

    + +

    <%= t("tracking.budget_investments.show.responsibles") %>

    + +

    <%= t("tracking.budget_investments.show.assigned_admin") %>: + <% if @investment.administrator.present? %> + <%= @investment.administrator.name_and_email %> + <% else %> + <%= t("tracking.budget_investments.show.undefined") %> + <% end %> +

    + +

    <%= t("trackers.budget_investments.show.assigned_trackers") %>:

    +
    +
      + <% @investment.trackers.each do |tracker| %> +
    • <%= tracker.name_and_email %>
    • + <% end %> + + <% if @investment.trackers.empty? %> +
    • <%= t("tracking.budget_investments.show.undefined") %>
    • + <% end %> +
    +
    diff --git a/app/views/tracking/budgets/index.html.erb b/app/views/tracking/budgets/index.html.erb new file mode 100644 index 000000000..a8968d029 --- /dev/null +++ b/app/views/tracking/budgets/index.html.erb @@ -0,0 +1,36 @@ +

    <%= t("tracking.budgets.index.title") %>

    + +<% if @budget.present? %> + + + + + + + + + + + + + + + + + +
    <%= t("tracking.budgets.index.table_name") %><%= t("tracking.budgets.index.table_phase") %><%= t("tracking.budgets.index.table_assigned_investments_tracking_open") %><%= t("tracking.budgets.index.table_actions") %>
    + <%= @budget.name %> + + <%= t("budgets.phase.#{@budget.phase}") %> + + <%= @investments.count %> + + <%= link_to t("tracking.budgets.index.tracking"), + tracking_budget_budget_investments_path(budget_id: @budget.id), + class: "button hollow expanded" %> +
    +<% else %> +
    + <%= t("tracking.budgets.index.no_budgets") %> +
    +<% end %> diff --git a/app/views/admin/milestones/_form.html.erb b/app/views/tracking/milestones/_form.html.erb similarity index 73% rename from app/views/admin/milestones/_form.html.erb rename to app/views/tracking/milestones/_form.html.erb index 0f0b1b040..f9a86d376 100644 --- a/app/views/admin/milestones/_form.html.erb +++ b/app/views/tracking/milestones/_form.html.erb @@ -1,13 +1,13 @@ <%= render "admin/shared/globalize_locales", resource: @milestone %> -<%= translatable_form_for [:admin, *resource_hierarchy_for(@milestone)] do |f| %> +<%= translatable_form_for [:tracking, *resource_hierarchy_for(@milestone)] do |f| %>
    <%= f.select :status_id, @statuses.collect { |s| [s.name, s.id] }, - { include_blank: @statuses.any? ? "" : t("admin.milestones.form.no_statuses_defined") }, + { include_blank: @statuses.any? ? "" : t("tracking.milestones.form.no_statuses_defined") }, { disabled: @statuses.blank? } %> - <%= link_to t("admin.milestones.form.admin_statuses"), + <%= link_to t("tracking.milestones.form.admin_statuses"), admin_milestone_statuses_path %>
    @@ -17,10 +17,10 @@ <%= translations_form.text_area :description, rows: 5, - label: t("admin.milestones.new.description") %> + label: t("tracking.milestones.new.description") %> <% end %> - <%= f.label :publication_date, t("admin.milestones.new.date") %> + <%= f.label :publication_date, t("tracking.milestones.new.date") %> <%= f.text_field :publication_date, value: @milestone.publication_date.present? ? l(@milestone.publication_date.to_date) : nil, label: false, diff --git a/app/views/admin/milestones/_milestones.html.erb b/app/views/tracking/milestones/_milestones.html.erb similarity index 59% rename from app/views/admin/milestones/_milestones.html.erb rename to app/views/tracking/milestones/_milestones.html.erb index bcbf61885..4548011de 100644 --- a/app/views/admin/milestones/_milestones.html.erb +++ b/app/views/tracking/milestones/_milestones.html.erb @@ -1,7 +1,7 @@ -

    <%= t("admin.milestones.index.milestone") %>

    +

    <%= t("tracking.milestones.index.milestone") %>

    -<%= link_to t("admin.progress_bars.manage"), - polymorphic_path([:admin, *resource_hierarchy_for(milestoneable.progress_bars.new)]), +<%= link_to t("tracking.progress_bars.manage"), + polymorphic_path([:tracking, *resource_hierarchy_for(milestoneable.progress_bars.new)]), class: "button hollow float-right" %> <% if milestoneable.milestone_tag_list.any? %> @@ -16,14 +16,14 @@ - - - - - - - - + + + + + + + + @@ -32,7 +32,7 @@ @@ -43,7 +43,7 @@ <%= milestone.status.present? ? milestone.status.name : "" %> @@ -58,8 +58,8 @@ <% end %> @@ -68,12 +68,12 @@
    <%= t("admin.milestones.index.table_id") %><%= t("admin.milestones.index.table_title") %><%= t("admin.milestones.index.table_description") %><%= t("admin.milestones.index.table_publication_date") %><%= t("admin.milestones.index.table_status") %><%= t("admin.milestones.index.image") %><%= t("admin.milestones.index.documents") %><%= t("admin.milestones.index.table_actions") %><%= t("tracking.milestones.index.table_id") %><%= t("tracking.milestones.index.table_title") %><%= t("tracking.milestones.index.table_description") %><%= t("tracking.milestones.index.table_publication_date") %><%= t("tracking.milestones.index.table_status") %><%= t("tracking.milestones.index.image") %><%= t("tracking.milestones.index.documents") %><%= t("tracking.milestones.index.table_actions") %>
    <%= milestone.id %> <%= link_to milestone.title, - polymorphic_path([:admin, *resource_hierarchy_for(milestone)], + polymorphic_path([:tracking, *resource_hierarchy_for(milestone)], action: :edit) %> <%= milestone.description %> - <%= link_to t("admin.milestones.index.show_image"), + <%= link_to t("tracking.milestones.index.show_image"), milestone.image_url(:large), target: :_blank if milestone.image.present? %> - <%= link_to t("admin.milestones.index.delete"), - polymorphic_path([:admin, *resource_hierarchy_for(milestone)]), + <%= link_to t("tracking.milestones.index.delete"), + polymorphic_path([:tracking, *resource_hierarchy_for(milestone)]), method: :delete, class: "button hollow alert expanded" %>
    <% else %> -

    <%= t("admin.milestones.index.no_milestones") %>

    +

    <%= t("tracking.milestones.index.no_milestones") %>

    <% end %>

    - <%= link_to t("admin.milestones.index.new_milestone"), - polymorphic_path([:admin, *resource_hierarchy_for(milestoneable.milestones.new)], + <%= link_to t("tracking.milestones.index.new_milestone"), + polymorphic_path([:tracking, *resource_hierarchy_for(milestoneable.milestones.new)], action: :new), class: "button hollow" %>

    diff --git a/app/views/admin/milestones/edit.html.erb b/app/views/tracking/milestones/edit.html.erb similarity index 65% rename from app/views/admin/milestones/edit.html.erb rename to app/views/tracking/milestones/edit.html.erb index 297ebccb4..4ce62f5a8 100644 --- a/app/views/admin/milestones/edit.html.erb +++ b/app/views/tracking/milestones/edit.html.erb @@ -1,6 +1,6 @@ <%= back_link_to milestoneable_path %> -

    <%= t("admin.milestones.edit.title") %>

    +

    <%= t("tracking.milestones.edit.title") %>

    <%= render "form" %> diff --git a/app/views/admin/milestones/new.html.erb b/app/views/tracking/milestones/new.html.erb similarity index 72% rename from app/views/admin/milestones/new.html.erb rename to app/views/tracking/milestones/new.html.erb index aa55123c9..de664eadb 100644 --- a/app/views/admin/milestones/new.html.erb +++ b/app/views/tracking/milestones/new.html.erb @@ -3,7 +3,7 @@
    <%= back_link_to milestoneable_path %> -

    <%= t("admin.milestones.new.creating") %>

    +

    <%= t("tracking.milestones.new.creating") %>

    <%= render "form" %>
    diff --git a/app/views/admin/progress_bars/_form.html.erb b/app/views/tracking/progress_bars/_form.html.erb similarity index 92% rename from app/views/admin/progress_bars/_form.html.erb rename to app/views/tracking/progress_bars/_form.html.erb index cdc6af59e..07720485e 100644 --- a/app/views/admin/progress_bars/_form.html.erb +++ b/app/views/tracking/progress_bars/_form.html.erb @@ -1,6 +1,6 @@ <%= render "admin/shared/globalize_locales", resource: @progress_bar %> -<%= translatable_form_for [:admin, *resource_hierarchy_for(@progress_bar)] do |f| %> +<%= translatable_form_for [:tracking, *resource_hierarchy_for(@progress_bar)] do |f| %>
    <%= f.enum_select :kind %> diff --git a/app/views/admin/progress_bars/_progress_bars.html.erb b/app/views/tracking/progress_bars/_progress_bars.html.erb similarity index 60% rename from app/views/admin/progress_bars/_progress_bars.html.erb rename to app/views/tracking/progress_bars/_progress_bars.html.erb index 3715c2f35..0a47e306d 100644 --- a/app/views/admin/progress_bars/_progress_bars.html.erb +++ b/app/views/tracking/progress_bars/_progress_bars.html.erb @@ -1,8 +1,8 @@ -

    <%= t("admin.progress_bars.index.title") %>

    +

    <%= t("tracking.progress_bars.index.title") %>

    -<%= link_to t("admin.progress_bars.index.new_progress_bar"), +<%= link_to t("tracking.progress_bars.index.new_progress_bar"), polymorphic_path( - [:admin, *resource_hierarchy_for(ProgressBar.new(progressable: progressable))], + [:tracking, *resource_hierarchy_for(ProgressBar.new(progressable: progressable))], action: :new ), class: "button float-right" %> @@ -11,10 +11,10 @@ - - - - + + + + @@ -29,7 +29,7 @@ <% if progress_bar.title.present? %> <%= progress_bar.title %> <% else %> - <%= t("admin.progress_bars.index.primary") %> + <%= t("tracking.progress_bars.index.primary") %> <% end %> @@ -52,6 +52,6 @@
    <%= t("admin.progress_bars.index.table_id") %><%= t("admin.progress_bars.index.table_kind") %><%= t("admin.progress_bars.index.table_title") %><%= t("admin.progress_bars.index.table_percentage") %><%= t("tracking.progress_bars.index.table_id") %><%= t("tracking.progress_bars.index.table_kind") %><%= t("tracking.progress_bars.index.table_title") %><%= t("tracking.progress_bars.index.table_percentage") %> <%= t("admin.actions.actions") %>
    @@ -37,12 +37,12 @@ <%= link_to t("admin.actions.edit"), - polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)], + polymorphic_path([:tracking, *resource_hierarchy_for(progress_bar)], action: :edit), class: "button hollow" %> <%= link_to t("admin.actions.delete"), - polymorphic_path([:admin, *resource_hierarchy_for(progress_bar)]), + polymorphic_path([:tracking, *resource_hierarchy_for(progress_bar)]), method: :delete, class: "button hollow alert" %>
    <% else %>
    - <%= t("admin.progress_bars.index.no_progress_bars") %> + <%= t("tracking.progress_bars.index.no_progress_bars") %>
    <% end %> diff --git a/app/views/tracking/progress_bars/edit.html.erb b/app/views/tracking/progress_bars/edit.html.erb new file mode 100644 index 000000000..1f0e30eeb --- /dev/null +++ b/app/views/tracking/progress_bars/edit.html.erb @@ -0,0 +1,15 @@ +<% if @progress_bar.primary? %> + <% bar_title = t("tracking.progress_bars.edit.title.primary") %> +<% else %> + <% bar_title = t("tracking.progress_bars.edit.title.secondary", title: @progress_bar.title) %> +<% end %> + +<% provide :title do %> + <%= "#{t("tracking.header.title")} - #{bar_title}" %> +<% end %> + +<%= back_link_to progress_bars_index %> + +

    <%= bar_title %>

    + +<%= render "form" %> diff --git a/app/views/tracking/progress_bars/index.html.erb b/app/views/tracking/progress_bars/index.html.erb new file mode 100644 index 000000000..356350812 --- /dev/null +++ b/app/views/tracking/progress_bars/index.html.erb @@ -0,0 +1,9 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("tracking.progress_bars.index.title")}" %> +<% end %> + +<%= back_link_to tracker_back_path(@progressable) %> + +
    + +<%= render "tracking/progress_bars/progress_bars", progressable: @progressable %> diff --git a/app/views/tracking/progress_bars/new.html.erb b/app/views/tracking/progress_bars/new.html.erb new file mode 100644 index 000000000..f889a8a81 --- /dev/null +++ b/app/views/tracking/progress_bars/new.html.erb @@ -0,0 +1,9 @@ +<% provide :title do %> + <%= "#{t("admin.header.title")} - #{t("tracking.progress_bars.new.creating")}" %> +<% end %> + +<%= back_link_to progress_bars_index %> + +

    <%= t("tracking.progress_bars.new.creating") %>

    + +<%= render "form" %> diff --git a/config/i18n-tasks.yml b/config/i18n-tasks.yml index 6251cd002..4f0ed500c 100644 --- a/config/i18n-tasks.yml +++ b/config/i18n-tasks.yml @@ -47,6 +47,7 @@ data: - config/locales/%{locale}/milestones.yml - config/locales/%{locale}/stats.yml - config/locales/%{locale}/download.yml + - config/locales/%{locale}/tracking.yml # Locale files to write new keys to, based on a list of key pattern => file rules. Matched from top to bottom: # `i18n-tasks normalize -p` will force move the keys according to these rules diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index 1499ebb94..53f71e756 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -261,6 +261,7 @@ en: "false": "No" valuator_groups: "Valuator Groups" preview: Investment preview + assigned_trackers: "Assigned trackers" edit: classification: Classification compatibility: Compatibility @@ -275,39 +276,12 @@ en: tags_placeholder: "Write the tags you want separated by commas (,)" undefined: Undefined user_groups: "Groups" + assigned_trackers: "Trackers" milestone_tags: Milestone tags search_unfeasible: Search unfeasible milestones: index: - table_id: "ID" - table_title: "Title" - table_description: "Description" - table_publication_date: "Publication date" - table_status: Status - table_actions: "Actions" - delete: "Delete milestone" - no_milestones: "Don't have defined milestones" - image: "Image" - show_image: "Show image" - documents: "Documents" - milestone: Milestone - new_milestone: Create new milestone milestone_tags: Milestone Tags - form: - admin_statuses: Manage statuses - no_statuses_defined: There are no defined statuses yet - new: - creating: Create milestone - date: Date - description: Description - edit: - title: Edit milestone - create: - notice: New milestone created successfully! - update: - notice: Milestone updated successfully - delete: - notice: Milestone successfully deleted statuses: index: title: Milestone statuses @@ -734,6 +708,7 @@ en: title_booths: Voting booths legislation: Collaborative Legislation users: Users + trackers: "Trackers" dashboard: Proposals dashboard administrator_tasks: Resources requested dashboard_actions: Resources and actions @@ -1636,15 +1611,38 @@ en: card_title: Edit card submit_card: Save card translations: - remove_language: Remove language - add_language: Add language + remove_language: Remove language + add_language: Add language change_log: - title: "Change Log" - id: "ID" - field: "Field" - new_value: "New Value" - old_value: "Old Value" - edited_at: "Edited at" - edited_by: "Edited by" - actions: "Actions" - empty: "There are not changes logged" + title: "Change Log" + id: "ID" + field: "Field" + new_value: "New Value" + old_value: "Old Value" + edited_at: "Edited at" + edited_by: "Edited by" + actions: "Actions" + empty: "There are not changes logged" + trackers: + index: + title: Trackers + name: Name + email: Email + description: Description + no_description: No description + no_trackers: There are no trackers. + tracker: + add: "Add to trackers" + form: + update: Update Tracker + updated: "Tracker updated succesfully." + edit_title: "Trackers: Edit tracker" + show: + email: Email + description: Description + no_description: No description. + search: + title: Trackers + progress_bars: + index: + title: "Progress bars" diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index c52270d3c..a02f71928 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -260,6 +260,7 @@ en: other: You have %{count} new notifications notifications: Notifications no_notifications: "You don't have new notifications" + tracking: "Tracking" admin: watch_form_message: "You have unsaved changes. Do you confirm to leave the page?" notifications: diff --git a/config/locales/en/tracking.yml b/config/locales/en/tracking.yml new file mode 100644 index 000000000..5c5a89fa3 --- /dev/null +++ b/config/locales/en/tracking.yml @@ -0,0 +1,92 @@ +en: + tracking: + header: + title: Tracking + menu: + title: Tracking + budgets: Participatory budgets + budgets: + index: + title: Participatory budgets + table_name: Name + table_phase: Phase + table_assigned_investments_tracking_open: Investment projects assigned with tracking open + table_actions: Actions + tracking: Tracking + no_budgets: "There are no budgets" + budget_investments: + index: + assigned_to: "Assigned to %{tracker}" + title: Investment projects + edit: Edit milestones + table_id: ID + table_title: Title + table_heading_name: Heading name + table_actions: Actions + no_investments: "There are no investment projects." + show: + title: Investment project + info: Author info + by: Sent by + sent: Sent at + heading: Heading + undefined: "Undefined" + responsibles: Responsibles + assigned_admin: Assigned admin + milestones: + index: + table_id: "ID" + table_title: "Title" + table_description: "Description" + table_publication_date: "Publication date" + table_status: Status + table_actions: "Actions" + delete: "Delete milestone" + no_milestones: "Don't have defined milestones" + image: "Image" + show_image: "Show image" + documents: "Documents" + milestone: Milestone + new_milestone: Create new milestone + form: + admin_statuses: Manage statuses + no_statuses_defined: There are no defined statuses yet + new: + creating: Create milestone + date: Date + description: Description + edit: + title: Edit milestone + create: + notice: New milestone created successfully! + update: + notice: Milestone updated successfully + delete: + notice: Milestone successfully deleted + progress_bars: + manage: "Manage progress bars" + index: + title: "Progress bars" + no_progress_bars: "There are no progress bars" + new_progress_bar: "Create new progress bar" + primary: "Primary progress bar" + table_id: "ID" + table_kind: "Type" + table_title: "Title" + table_percentage: "Current progress" + new: + creating: "Create progress bar" + edit: + title: + primary: "Edit primary progress bar" + secondary: "Edit progress bar %{title}" + create: + notice: "Progress bar created successfully!" + update: + notice: "Progress bar updated successfully" + delete: + notice: "Progress bar deleted successfully" + trackers: + budget_investments: + show: + assigned_trackers: "Assigned trackers" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 7f471b909..945440cf5 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -261,6 +261,7 @@ es: "false": "No" valuator_groups: "Grupos de evaluadores" preview: Vista previa + assigned_trackers: "Gestores de seguimiento asignados" edit: classification: Clasificación compatibility: Compatibilidad @@ -275,39 +276,12 @@ es: tags_placeholder: "Escribe las etiquetas que desees separadas por comas (,)" undefined: Sin definir user_groups: "Grupos" + assigned_trackers: "Gestores de seguimiento" milestone_tags: Etiquetas de Seguimiento search_unfeasible: Buscar inviables milestones: index: - table_id: "ID" - table_title: "Título" - table_description: "Descripción" - table_publication_date: "Fecha de publicación" - table_status: Estado - table_actions: "Acciones" - delete: "Eliminar hito" - no_milestones: "No hay hitos definidos" - image: "Imagen" - show_image: "Mostrar imagen" - documents: "Documentos" - milestone: Seguimiento - new_milestone: Crear nuevo hito milestone_tags: Etiquetas de Seguimiento - form: - admin_statuses: Gestionar estados - no_statuses_defined: No hay estados definidos - new: - creating: Crear hito - date: Fecha - description: Descripción - edit: - title: Editar hito - create: - notice: '¡Nuevo hito creado con éxito!' - update: - notice: Hito actualizado - delete: - notice: Hito borrado correctamente statuses: index: title: Estados de seguimiento @@ -735,6 +709,7 @@ es: title_booths: Urnas de votación legislation: Legislación colaborativa users: Usuarios + trackers: "Gestores de seguimiento" dashboard: Panel de progreso de propuestas administrator_tasks: Recursos solicitados dashboard_actions: Recursos y acciones @@ -1637,12 +1612,35 @@ es: remove_language: Eliminar idioma add_language: Añadir idioma change_log: - title: "Historial" - id: "ID" - field: "Campo" - new_value: "Valor nuevo" - old_value: "Valor anterior" - edited_at: "Editado el" - edited_by: "Editado por" - actions: "Acciones" - empty: "No hay cambios registrados" + title: "Historial" + id: "ID" + field: "Campo" + new_value: "Valor nuevo" + old_value: "Valor anterior" + edited_at: "Editado el" + edited_by: "Editado por" + actions: "Acciones" + empty: "No hay cambios registrados" + trackers: + index: + title: Gestores de seguimiento + name: Nombre + email: Email + description: Descripción + no_description: Sin descripción + no_trackers: No hay gestores de seguimiento. + tracker: + add: "Añadir a gestores de seguimiento" + form: + update: "Actualizar gestor" + updated: "Gestor de seguimiento actualizado correctamente." + edit_title: "Gestores de seguimiento: Editar gestor" + show: + email: Email + description: Descripción + no_description: Sin descripción. + search: + title: Trackers + progress_bars: + index: + title: "Barras de progreso" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index ec52caa54..75931e379 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -260,6 +260,7 @@ es: other: Tienes %{count} notificaciones nuevas notifications: Notificaciones no_notifications: "No tienes notificaciones nuevas" + tracking: "Seguimiento" admin: watch_form_message: "Has realizado cambios que no han sido guardados. ¿Seguro que quieres abandonar la página?" notifications: diff --git a/config/locales/es/tracking.yml b/config/locales/es/tracking.yml new file mode 100644 index 000000000..eecf84a9c --- /dev/null +++ b/config/locales/es/tracking.yml @@ -0,0 +1,92 @@ +es: + tracking: + header: + title: Seguimiento + menu: + title: Seguimiento + budgets: Presupuestos participativos + budgets: + index: + title: Presupuestos participativos + table_name: Nombre + table_phase: Fase + table_assigned_investments_tracking_open: Prop. Inv. asignadas en segumiento + table_actions: Acciones + tracking: Seguimiento + no_budgets: "No hay presupuestos" + budget_investments: + index: + assigned_to: "Asignadas a %{tracker}" + title: Proyectos de gasto + edit: Editar seguimiento + table_id: ID + table_title: Título + table_heading_name: Nombre de la partida + table_actions: Acciones + no_investments: "No hay proyectos de gasto." + show: + title: Proyecto de gasto + info: Datos de envío + by: Enviada por + sent: Fecha de creación + heading: Partida + undefined: Sin definir + responsibles: Responsables + assigned_admin: Administrador asignado + milestones: + index: + table_id: "ID" + table_title: "Título" + table_description: "Descripción" + table_publication_date: "Fecha de publicación" + table_status: Estado + table_actions: "Acciones" + delete: "Eliminar hito" + no_milestones: "No hay hitos definidos" + image: "Imagen" + show_image: "Mostrar imagen" + documents: "Documentos" + milestone: Seguimiento + new_milestone: Crear nuevo hito + form: + admin_statuses: Gestionar estados + no_statuses_defined: No hay estados definidos + new: + creating: Crear hito + date: Fecha + description: Descripción + edit: + title: Editar hito + create: + notice: "¡Nuevo hito creado con éxito!" + update: + notice: Hito actualizado + delete: + notice: Hito borrado correctamente + progress_bars: + manage: "Gestionar barras de progreso" + index: + title: "Barras de progreso" + no_progress_bars: "No hay barras de progreso" + new_progress_bar: "Crear nueva barra de progreso" + primary: "Barra de progreso principal" + table_id: "ID" + table_kind: "Tipo" + table_title: "Título" + table_percentage: "Progreso" + new: + creating: "Crear barra de progreso" + edit: + title: + primary: "Editar barra de progreso principal" + secondary: "Editar barra de progreso %{title}" + create: + notice: "¡Barra de progreso creada con éxito!" + update: + notice: "Barra de progreso actualizada" + delete: + notice: "Barra de progreso eliminada correctamente" + trackers: + budget_investments: + show: + assigned_trackers: "Gestores de seguimiento asignados" diff --git a/config/routes.rb b/config/routes.rb index b2155a02b..be3e8e0ec 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -31,6 +31,7 @@ Rails.application.routes.draw do draw :tag draw :user draw :valuation + draw :tracking draw :verification root "welcome#index" diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 314a6ff16..80e050d34 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -61,8 +61,6 @@ namespace :admin do end resources :budget_investments, only: [:index, :show, :edit, :update] do - resources :milestones, controller: "budget_investment_milestones" - resources :progress_bars, except: :show, controller: "budget_investment_progress_bars" member { patch :toggle_selection } end @@ -105,6 +103,11 @@ namespace :admin do get :summary, on: :collection end + resources :trackers, only: [:show, :index, :edit, :update, :create, :destroy] do + get :search, on: :collection + get :summary, on: :collection + end + resources :valuator_groups resources :managers, only: [:index, :create, :destroy] do @@ -207,8 +210,7 @@ namespace :admin do member { patch :toggle_selection } end resources :draft_versions - resources :milestones - resources :progress_bars, except: :show + resources :milestones, only: :index resource :homepage, only: [:edit, :update] end end diff --git a/config/routes/tracking.rb b/config/routes/tracking.rb new file mode 100644 index 000000000..1912b856b --- /dev/null +++ b/config/routes/tracking.rb @@ -0,0 +1,23 @@ +namespace :tracking do + root to: "budgets#index" + + resources :budgets, only: :index do + resources :budget_investments, only: [:index, :show, :edit] do + resources :milestones, controller: "budget_investment_milestones" + resources :progress_bars, except: :show, controller: "budget_investment_progress_bars" + patch :track, on: :member + end + end + + resources :proposals, only: [:index, :show] do + resources :milestones, controller: "proposal_milestones" + resources :progress_bars, except: :show, controller: "proposal_progress_bars" + end + + namespace :legislation do + resources :processes, only: [:index, :show] do + resources :milestones + resources :progress_bars, except: :show + end + end +end diff --git a/db/migrate/20190426075419_create_trackers.rb b/db/migrate/20190426075419_create_trackers.rb new file mode 100644 index 000000000..68fb590a0 --- /dev/null +++ b/db/migrate/20190426075419_create_trackers.rb @@ -0,0 +1,11 @@ +class CreateTrackers < ActiveRecord::Migration[5.0] + def change + create_table :trackers do |t| + t.references :user, foreign_key: true + t.string :description + t.integer :budget_investment_count, default: 0 + + t.timestamps + end + end +end diff --git a/db/migrate/20190426120406_create_budget_tracker_assignments.rb b/db/migrate/20190426120406_create_budget_tracker_assignments.rb new file mode 100644 index 000000000..6774b3da2 --- /dev/null +++ b/db/migrate/20190426120406_create_budget_tracker_assignments.rb @@ -0,0 +1,10 @@ +class CreateBudgetTrackerAssignments < ActiveRecord::Migration[5.0] + def change + create_table :budget_tracker_assignments, index: false do |t| + t.references :tracker, foreign_key: true + t.integer :investment_id, index: true + + t.timestamps null:false + end + end +end diff --git a/db/migrate/20190429102006_add_tracker_assignments_count_to_budget_investments.rb b/db/migrate/20190429102006_add_tracker_assignments_count_to_budget_investments.rb new file mode 100644 index 000000000..a72d1a048 --- /dev/null +++ b/db/migrate/20190429102006_add_tracker_assignments_count_to_budget_investments.rb @@ -0,0 +1,5 @@ +class AddTrackerAssignmentsCountToBudgetInvestments < ActiveRecord::Migration[5.0] + def change + add_column :budget_investments, :tracker_assignments_count, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb index 5e0176209..7b6a38919 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -269,6 +269,7 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "confirmed_hide_at" t.datetime "ignored_flag_at" t.integer "flags_count", default: 0 + t.integer "tracker_assignments_count" t.index ["administrator_id"], name: "index_budget_investments_on_administrator_id", using: :btree t.index ["author_id"], name: "index_budget_investments_on_author_id", using: :btree t.index ["community_id"], name: "index_budget_investments_on_community_id", using: :btree @@ -310,6 +311,15 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.datetime "updated_at", null: false end + create_table "budget_tracker_assignments", force: :cascade do |t| + t.integer "tracker_id" + t.integer "investment_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["investment_id"], name: "index_budget_tracker_assignments_on_investment_id", using: :btree + t.index ["tracker_id"], name: "index_budget_tracker_assignments_on_tracker_id", using: :btree + end + create_table "budget_translations", force: :cascade do |t| t.integer "budget_id", null: false t.string "locale", null: false @@ -1427,6 +1437,15 @@ ActiveRecord::Schema.define(version: 20190607160900) do t.index ["hidden_at"], name: "index_topics_on_hidden_at", using: :btree end + create_table "trackers", force: :cascade do |t| + t.integer "user_id" + t.string "description" + t.integer "budget_investment_count", default: 0 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["user_id"], name: "index_trackers_on_user_id", using: :btree + end + create_table "users", force: :cascade do |t| t.string "email", default: "" t.string "encrypted_password", default: "", null: false @@ -1612,6 +1631,7 @@ ActiveRecord::Schema.define(version: 20190607160900) do add_foreign_key "administrators", "users" add_foreign_key "budget_investments", "communities" + add_foreign_key "budget_tracker_assignments", "trackers" add_foreign_key "dashboard_administrator_tasks", "users" add_foreign_key "dashboard_executed_actions", "dashboard_actions", column: "action_id" add_foreign_key "dashboard_executed_actions", "proposals" @@ -1650,6 +1670,7 @@ ActiveRecord::Schema.define(version: 20190607160900) do add_foreign_key "proposals", "communities" add_foreign_key "related_content_scores", "related_contents" add_foreign_key "related_content_scores", "users" + add_foreign_key "trackers", "users" add_foreign_key "users", "geozones" add_foreign_key "valuators", "users" end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index f074d525c..4b5d790ba 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -67,6 +67,10 @@ FactoryBot.define do user end + factory :tracker do + user + end + factory :valuator do user end diff --git a/spec/features/admin/budget_investment_milestones_spec.rb b/spec/features/admin/budget_investment_milestones_spec.rb index e08547542..17403a038 100644 --- a/spec/features/admin/budget_investment_milestones_spec.rb +++ b/spec/features/admin/budget_investment_milestones_spec.rb @@ -4,6 +4,6 @@ describe "Admin budget investment milestones" do it_behaves_like "translatable", "milestone", - "edit_admin_budget_budget_investment_milestone_path", + "edit_tracking_budget_budget_investment_milestone_path", %w[description] end diff --git a/spec/features/officing_spec.rb b/spec/features/officing_spec.rb index 10c600238..b0b1c2f72 100644 --- a/spec/features/officing_spec.rb +++ b/spec/features/officing_spec.rb @@ -108,7 +108,7 @@ describe "Poll Officing" do expect(page).not_to have_link("Moderation") end - scenario "Officing dashboard" do + xscenario "Officing dashboard" do create(:poll_officer, user: user) create(:poll) login_as(user) diff --git a/spec/features/tracking/budget_investments_spec.rb b/spec/features/tracking/budget_investments_spec.rb new file mode 100644 index 000000000..027b6cbb6 --- /dev/null +++ b/spec/features/tracking/budget_investments_spec.rb @@ -0,0 +1,365 @@ +require "rails_helper" + +feature "Valuation budget investments" do + + let(:budget) { create(:budget) } + let(:tracker) do + create(:tracker, user: create(:user, username: "Rachel", email: "rachel@trackers.org")) + end + + background do + login_as(tracker.user) + end + + scenario "Disabled with a feature flag" do + Setting["process.budgets"] = nil + expect{ + visit tracking_budget_budget_investments_path(create(:budget)) + }.to raise_exception(FeatureFlags::FeatureDisabled) + end + + scenario "Display link to tracking section" do + visit root_path + expect(page).to have_link "Tracking", href: tracking_root_path + end + + feature "Index" do + scenario "Index shows budget investments assigned to current tracker" do + investment1 = create(:budget_investment, budget: budget) + investment2 = create(:budget_investment, budget: budget) + + investment1.trackers << tracker + + visit tracking_budget_budget_investments_path(budget) + + expect(page).to have_content(investment1.title) + expect(page).not_to have_content(investment2.title) + end + + scenario "Index shows no budget investment to admins no trackers" do + investment1 = create(:budget_investment, budget: budget) + investment2 = create(:budget_investment, budget: budget) + + investment1.trackers << tracker + + logout + login_as create(:administrator).user + visit tracking_budget_budget_investments_path(budget) + + expect(page).not_to have_content(investment1.title) + expect(page).not_to have_content(investment2.title) + end + + scenario "Index displays investments paginated" do + per_page = Kaminari.config.default_per_page + (per_page + 2).times do + investment = create(:budget_investment, budget: budget) + investment.trackers << tracker + end + + visit tracking_budget_budget_investments_path(budget) + + expect(page).to have_css(".budget_investment", count: per_page) + within("ul.pagination") do + expect(page).to have_content("1") + expect(page).to have_content("2") + expect(page).not_to have_content("3") + click_link "Next", exact: false + end + + expect(page).to have_css(".budget_investment", count: 2) + end + + scenario "headings" do + investment1 = create(:budget_investment, + budget: budget, + title: "investment 1", + heading: create(:budget_heading, name: "first_heading")) + investment2 = create(:budget_investment, + budget: budget, title: "investment 2", + heading: create(:budget_heading, name: "last_heading")) + investment3 = create(:budget_investment, + budget: budget, + title: "investment 3", + heading: create(:budget_heading, name: "no_heading")) + + investment1.trackers << tracker + investment2.trackers << tracker + + visit tracking_budget_budget_investments_path(budget) + + expect(page).to have_link("All headings (2)") + expect(page).to have_link("last_heading (1)") + expect(page).to have_link("first_heading (1)") + expect(page).not_to have_link("no_heading (1)") + + expect(page).to have_content("investment 1") + expect(page).to have_content("investment 2") + expect(page).not_to have_content("investment 3") + + expect(page.find(".select-heading .is-active")).to have_content("All headings") + + click_on "last_heading (1)" + + expect(page.find(".select-heading .is-active")).to have_content("last_heading (1)") + expect(page).not_to have_content("investment 1") + expect(page).to have_content("investment 2") + expect(page).not_to have_content("investment 3") + end + end + + feature "Show" do + let(:administrator) do + create(:administrator, user: create(:user, username: "Ana", email: "ana@admins.org")) + end + let(:second_tracker) do + create(:tracker, user: create(:user, username: "Rick", email: "rick@trackers.org")) + end + let(:investment) do + create(:budget_investment, budget: budget, administrator: administrator) + end + + background do + investment.trackers << [tracker, second_tracker] + end + + scenario "visible for assigned trackers" do + visit tracking_budget_budget_investments_path(budget) + + click_link investment.title + + expect(page).to have_content(investment.title) + expect(page).to have_content(investment.description) + expect(page).to have_content(investment.author.name) + expect(page).to have_content(investment.heading.name) + + within("#assigned_trackers") do + expect(page).to have_content("Rachel (rachel@trackers.org)") + expect(page).to have_content("Rick (rick@trackers.org)") + end + end + + scenario "visible for admins" do + logout + login_as create(:administrator).user + + visit tracking_budget_budget_investment_path(budget, investment) + + expect(page).to have_content(investment.title) + expect(page).to have_content(investment.description) + expect(page).to have_content(investment.author.name) + expect(page).to have_content(investment.heading.name) + expect(page).to have_content("Ana (ana@admins.org)") + + within("#assigned_trackers") do + expect(page).to have_content("Rachel (rachel@trackers.org)") + expect(page).to have_content("Rick (rick@trackers.org)") + end + end + + scenario "not visible for not assigned trackers" do + logout + login_as create(:tracker).user + + expect{ + visit tracking_budget_budget_investment_path(budget, investment) + }.to raise_error "Not Found" + end + + end + + feature "Milestones" do + let(:admin) { create(:administrator) } + let(:investment) do + heading = create(:budget_heading) + create(:budget_investment, heading: heading, budget: budget, + administrator: admin) + end + + background do + investment.trackers << tracker + end + + scenario "visit investment manage milestones" do + + visit tracking_budget_budget_investments_path(budget) + + click_link "Edit milestones" + + expect(page).to have_content("Milestone") + expect(page).to have_content(investment.title) + end + + scenario "create investment milestones" do + visit edit_tracking_budget_budget_investment_path(budget, investment) + + expect(page).to have_content("Milestone") + expect(page).to have_content(investment.title) + + click_link "Create new milestone" + + expect(page).to have_content("Create milestone") + fill_in("Description", with: "Test Description") + page.find("#milestone_publication_date").set(Date.today) + + click_button "Create milestone" + + visit edit_tracking_budget_budget_investment_path(budget, investment) + + expect(page).to have_content("Test Description") + end + + scenario "delete investment milestones" do + milestone = create(:milestone, + milestoneable: investment, + description: "Test delete milestone") + + visit edit_tracking_budget_budget_investment_path(budget, investment) + + expect(page).to have_content("Test delete milestone") + + page.find("#milestone_#{milestone.id}").click_link("Delete milestone") + + visit edit_tracking_budget_budget_investment_path(budget, investment) + + expect(page).not_to have_content("Test delete milestone") + + end + + scenario "edit investment milestones" do + milestone = create(:milestone, milestoneable: investment, description: "Test edit milestone") + + visit edit_tracking_budget_budget_investment_path(budget, investment) + + expect(page).to have_content("Test edit milestone") + + page.find("#milestone_#{milestone.id}").first("a").click + + expect(page).to have_content("Edit milestone") + expect(page).to have_content("Test edit milestone") + fill_in("Description", with: "Test edited milestone") + + click_button "Update milestone" + + visit edit_tracking_budget_budget_investment_path(budget, investment) + + expect(page).not_to have_content("Test edit milestone") + expect(page).to have_content("Test edited milestone") + + end + + end + + feature "Progress Bars" do + + let(:admin) { create(:administrator) } + let(:investment) do + heading = create(:budget_heading) + create(:budget_investment, heading: heading, budget: budget, + administrator: admin) + end + + background do + investment.trackers << tracker + end + + scenario "view index" do + visit edit_tracking_budget_budget_investment_path(budget, investment) + + click_link "Manage progress bars" + + expect(page).to have_content("Progress bars") + + logout + login_as create(:tracker, user: create(:user)).user + + expect{ + visit tracking_budget_budget_investment_progress_bars_path(budget, investment) + }.to raise_error "Not Found" + end + + scenario "create primary progress bar" do + + visit tracking_budget_budget_investment_progress_bars_path(budget, investment) + + expect(page).to have_content("Progress bars") + + click_link "Create new progress bar" + + expect(page).to have_content("Create progress bar") + + select("Primary", :from => "Type") + fill_in("Current progress", :with => 50) + + click_button "Create Progress bar" + + expect(page).to have_content("Progress bars") + + expect(page).to have_content("Primary") + end + + scenario "create secondary progress bar" do + + visit tracking_budget_budget_investment_progress_bars_path(budget, investment) + + expect(page).to have_content("Progress bars") + + click_link "Create new progress bar" + + expect(page).to have_content("Create progress bar") + + select("Secondary", :from => "Type") + fill_in("Title", :with => "secondary_progress_bar") + fill_in("Current progress", :with => 50) + + click_button "Create Progress bar" + + expect(page).to have_content("Progress bars") + + expect(page).to have_content("secondary_progress_bar") + end + + scenario "delete" do + primary_progress_bar = create(:progress_bar, progressable: investment) + secondary_progress_bar = create(:progress_bar, + :secondary, + title: "to delete", + progressable: investment) + + visit tracking_budget_budget_investment_progress_bars_path(budget, investment) + + expect(page).to have_content("Primary") + expect(page).to have_content(secondary_progress_bar.title) + + page.find("#progress_bar_#{secondary_progress_bar.id}").click_link("Delete") + + visit tracking_budget_budget_investment_progress_bars_path(budget, investment) + + expect(page).to have_content("Primary") + expect(page).not_to have_content(secondary_progress_bar.title) + end + + scenario "edit" do + primary_progress_bar = create(:progress_bar, progressable: investment) + secondary_progress_bar = create(:progress_bar, + :secondary, + title: "to edit", + progressable: investment) + + visit tracking_budget_budget_investment_progress_bars_path(budget, investment) + + expect(page).to have_content("Primary") + expect(page).to have_content(secondary_progress_bar.title) + + page.find("#progress_bar_#{secondary_progress_bar.id}").click_link("Edit") + + fill_in("Title", :with => "edited") + click_button "Update Progress bar" + + expect(page).to have_content("Progress bars") + + expect(page).to have_content("edited") + end + + end +end diff --git a/spec/features/tracking/budgets_spec.rb b/spec/features/tracking/budgets_spec.rb new file mode 100644 index 000000000..10a6fea92 --- /dev/null +++ b/spec/features/tracking/budgets_spec.rb @@ -0,0 +1,31 @@ +require "rails_helper" + +feature "Tracking budgets" do + + background do + @tracker = create(:tracker, user: create(:user, username: "Rachel", email: "rachel@trackers.org")) + login_as(@tracker.user) + end + + scenario "Disabled with a feature flag" do + Setting["process.budgets"] = nil + expect{ visit tracking_budgets_path }.to raise_exception(FeatureFlags::FeatureDisabled) + end + + context "Index" do + + scenario "Displaying budgets" do + budget = create(:budget) + visit tracking_budgets_path + + expect(page).to have_content(budget.name) + end + + scenario "With no budgets" do + visit tracking_budgets_path + + expect(page).to have_content "There are no budgets" + end + end + +end diff --git a/spec/shared/features/admin_progressable.rb b/spec/shared/features/admin_progressable.rb index 81cd2cb62..1ee49eadb 100644 --- a/spec/shared/features/admin_progressable.rb +++ b/spec/shared/features/admin_progressable.rb @@ -5,7 +5,7 @@ shared_examples "admin_progressable" do |factory_name, path_name| let(:progressable_path) { send(path_name, *resource_hierarchy_for(progressable)) } let(:path) do - polymorphic_path([:admin, *resource_hierarchy_for(progressable.progress_bars.new)]) + polymorphic_path([:tracking, *resource_hierarchy_for(progressable.progress_bars.new)]) end context "Index" do