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") %>
+
+ <%= f.collection_check_boxes :tracker_ids, @trackers, :id, :email do |b| %>
+ - <%= b.label(title: tracker_label(b.object)) { b.check_box + truncate(b.object.description_or_email, length: 60) } %>
+ <% end %>
+
+
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:
+
+
+ <% tracker.errors.full_messages.each do |message| %>
+ - <%= message %>
+ <% end %>
+
+
+ <% 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 %>
+
+
+
+ | <%= t("admin.trackers.index.name") %> |
+ <%= t("admin.trackers.index.email") %> |
+ <%= t("admin.valuators.index.description") %> |
+ <%= t("admin.actions.actions") %> |
+
+
+ <% @trackers.each do |tracker| %>
+
+ | <%= 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" %>
+ |
+
+ <% end %>
+
+
+
+ <%= 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 %>
+
+
+
+ | <%= t("admin.trackers.index.name") %> |
+ <%= t("admin.trackers.index.email") %> |
+ <%= t("admin.trackers.index.description") %> |
+ <%= t("admin.shared.actions") %> |
+
+
+ <% @users.each do |user| %>
+
+ | <%= 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 %>
+ |
+
+ <% 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 %>
+
+
+
+
+ | <%= 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") %> |
+
+
+
+ <% @investments.each do |investment| %>
+
+ |
+ <%= 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" %>
+ |
+
+ <% end %>
+
+
+
+ <%= 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 @@
- | <%= 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") %> |
@@ -32,7 +32,7 @@
<%= milestone.id %> |
<%= link_to milestone.title,
- polymorphic_path([:admin, *resource_hierarchy_for(milestone)],
+ polymorphic_path([:tracking, *resource_hierarchy_for(milestone)],
action: :edit) %>
|
<%= milestone.description %> |
@@ -43,7 +43,7 @@
<%= milestone.status.present? ? milestone.status.name : "" %>
- <%= 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? %>
|
@@ -58,8 +58,8 @@
<% end %>
- <%= 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" %>
|
@@ -68,12 +68,12 @@
<% 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 @@
- | <%= 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") %> |
@@ -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 %>
@@ -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" %>
|
@@ -52,6 +52,6 @@
<% 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