Merge pull request #3811 from consul/investment_changelog
Use audited to track changes in investments
This commit is contained in:
@@ -208,6 +208,7 @@ Rails/CreateTableWithTimestamps:
|
|||||||
Enabled: true
|
Enabled: true
|
||||||
Exclude:
|
Exclude:
|
||||||
- "db/migrate/201[5-8]*"
|
- "db/migrate/201[5-8]*"
|
||||||
|
- "db/migrate/*install_audited.rb"
|
||||||
|
|
||||||
Rails/Date:
|
Rails/Date:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|||||||
1
Gemfile
1
Gemfile
@@ -6,6 +6,7 @@ gem "acts-as-taggable-on", "~> 5.0.0"
|
|||||||
gem "acts_as_votable", "~> 0.11.1"
|
gem "acts_as_votable", "~> 0.11.1"
|
||||||
gem "ahoy_matey", "~> 1.6.0"
|
gem "ahoy_matey", "~> 1.6.0"
|
||||||
gem "ancestry", "~> 3.0.7"
|
gem "ancestry", "~> 3.0.7"
|
||||||
|
gem "audited", "~> 4.9.0"
|
||||||
gem "autoprefixer-rails", "~> 8.2.0"
|
gem "autoprefixer-rails", "~> 8.2.0"
|
||||||
gem "axlsx", "~> 3.0.0.pre"
|
gem "axlsx", "~> 3.0.0.pre"
|
||||||
gem "axlsx_rails", "~> 0.5.2"
|
gem "axlsx_rails", "~> 0.5.2"
|
||||||
|
|||||||
@@ -72,6 +72,8 @@ GEM
|
|||||||
activerecord (>= 3.2.0)
|
activerecord (>= 3.2.0)
|
||||||
arel (7.1.4)
|
arel (7.1.4)
|
||||||
ast (2.4.0)
|
ast (2.4.0)
|
||||||
|
audited (4.9.0)
|
||||||
|
activerecord (>= 4.2, < 6.1)
|
||||||
autoprefixer-rails (8.2.0)
|
autoprefixer-rails (8.2.0)
|
||||||
execjs
|
execjs
|
||||||
axlsx (3.0.0.pre)
|
axlsx (3.0.0.pre)
|
||||||
@@ -588,6 +590,7 @@ DEPENDENCIES
|
|||||||
acts_as_votable (~> 0.11.1)
|
acts_as_votable (~> 0.11.1)
|
||||||
ahoy_matey (~> 1.6.0)
|
ahoy_matey (~> 1.6.0)
|
||||||
ancestry (~> 3.0.7)
|
ancestry (~> 3.0.7)
|
||||||
|
audited (~> 4.9.0)
|
||||||
autoprefixer-rails (~> 8.2.0)
|
autoprefixer-rails (~> 8.2.0)
|
||||||
axlsx (~> 3.0.0.pre)
|
axlsx (~> 3.0.0.pre)
|
||||||
axlsx_rails (~> 0.5.2)
|
axlsx_rails (~> 0.5.2)
|
||||||
|
|||||||
@@ -595,17 +595,6 @@ code {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-value {
|
|
||||||
max-height: rem-calc(65);
|
|
||||||
overflow: hidden;
|
|
||||||
max-width: rem-calc(200);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
max-height: rem-calc(1000);
|
|
||||||
transition: max-height 0.9s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 04. Stats
|
// 04. Stats
|
||||||
// ---------
|
// ---------
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class Admin::BudgetInvestmentAuditsController < Admin::BaseController
|
||||||
|
def show
|
||||||
|
investment = Budget::Investment.find(params[:budget_investment_id])
|
||||||
|
@audit = investment.own_and_associated_audits.find(params[:id])
|
||||||
|
|
||||||
|
render "admin/audits/show"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -2,7 +2,6 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
|
|||||||
include FeatureFlags
|
include FeatureFlags
|
||||||
include CommentableActions
|
include CommentableActions
|
||||||
include DownloadSettingsHelper
|
include DownloadSettingsHelper
|
||||||
include ChangeLogHelper
|
|
||||||
include Translatable
|
include Translatable
|
||||||
|
|
||||||
feature_flag :budgets
|
feature_flag :budgets
|
||||||
@@ -10,12 +9,11 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
|
|||||||
has_orders %w[oldest], only: [:show, :edit]
|
has_orders %w[oldest], only: [:show, :edit]
|
||||||
has_filters %w[all], only: [:index, :toggle_selection]
|
has_filters %w[all], only: [:index, :toggle_selection]
|
||||||
|
|
||||||
before_action :load_budget, except: :show_investment_log
|
before_action :load_budget
|
||||||
before_action :load_investment, only: [:show, :edit, :update, :toggle_selection]
|
before_action :load_investment, only: [:show, :edit, :update, :toggle_selection]
|
||||||
before_action :load_ballot, only: [:show, :index]
|
before_action :load_ballot, only: [:show, :index]
|
||||||
before_action :parse_valuation_filters
|
before_action :parse_valuation_filters
|
||||||
before_action :load_investments, only: [:index, :toggle_selection]
|
before_action :load_investments, only: [:index, :toggle_selection]
|
||||||
before_action :load_change_log, only: [:show]
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
load_tags
|
load_tags
|
||||||
@@ -128,8 +126,4 @@ class Admin::BudgetInvestmentsController < Admin::BaseController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_change_log
|
|
||||||
@logs = Budget::Investment::ChangeLog.by_investment(@investment.id)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ class ApplicationController < ActionController::Base
|
|||||||
before_action :set_locale
|
before_action :set_locale
|
||||||
before_action :track_email_campaign
|
before_action :track_email_campaign
|
||||||
before_action :set_return_url
|
before_action :set_return_url
|
||||||
before_action :set_current_user
|
|
||||||
|
|
||||||
check_authorization unless: :devise_controller?
|
check_authorization unless: :devise_controller?
|
||||||
self.responder = ApplicationResponder
|
self.responder = ApplicationResponder
|
||||||
@@ -121,8 +120,4 @@ class ApplicationController < ActionController::Base
|
|||||||
def current_budget
|
def current_budget
|
||||||
Budget.current
|
Budget.current
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_current_user
|
|
||||||
User.current_user = current_user
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
15
app/helpers/audits_helper.rb
Normal file
15
app/helpers/audits_helper.rb
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
module AuditsHelper
|
||||||
|
def truncate_audit_value(resource, field, value)
|
||||||
|
truncate(audit_value(resource, field, value), length: 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
def audit_value(resource, field, value)
|
||||||
|
if value.is_a?(Array)
|
||||||
|
value.join(",")
|
||||||
|
elsif resource.type_for_attribute(field.to_s).type == :boolean
|
||||||
|
resource.class.human_attribute_name("#{field}_#{value}")
|
||||||
|
else
|
||||||
|
value.to_s
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
module ChangeLogHelper
|
|
||||||
def show_investment_log
|
|
||||||
@log = Budget::Investment::ChangeLog.find_by(id: params[:id])
|
|
||||||
render "admin/change_logs/show"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
2
app/models/audit.rb
Normal file
2
app/models/audit.rb
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
class Audit < Audited::Audit
|
||||||
|
end
|
||||||
@@ -3,7 +3,6 @@ class Budget
|
|||||||
class Investment < ApplicationRecord
|
class Investment < ApplicationRecord
|
||||||
SORTING_OPTIONS = { id: "id", supports: "cached_votes_up" }.freeze
|
SORTING_OPTIONS = { id: "id", supports: "cached_votes_up" }.freeze
|
||||||
|
|
||||||
include ActiveModel::Dirty
|
|
||||||
include Rails.application.routes.url_helpers
|
include Rails.application.routes.url_helpers
|
||||||
include Measurable
|
include Measurable
|
||||||
include Sanitizable
|
include Sanitizable
|
||||||
@@ -33,6 +32,13 @@ class Budget
|
|||||||
translates :description, touch: true
|
translates :description, touch: true
|
||||||
include Globalizable
|
include Globalizable
|
||||||
|
|
||||||
|
audited on: [:update, :destroy]
|
||||||
|
has_associated_audits
|
||||||
|
translation_class.class_eval do
|
||||||
|
audited associated_with: :globalized_model,
|
||||||
|
only: Budget::Investment.translated_attribute_names
|
||||||
|
end
|
||||||
|
|
||||||
belongs_to :author, -> { with_hidden }, class_name: "User", inverse_of: :budget_investments
|
belongs_to :author, -> { with_hidden }, class_name: "User", inverse_of: :budget_investments
|
||||||
belongs_to :heading
|
belongs_to :heading
|
||||||
belongs_to :group
|
belongs_to :group
|
||||||
@@ -115,7 +121,6 @@ class Budget
|
|||||||
after_save :recalculate_heading_winners
|
after_save :recalculate_heading_winners
|
||||||
before_validation :set_responsible_name
|
before_validation :set_responsible_name
|
||||||
before_validation :set_denormalized_ids
|
before_validation :set_denormalized_ids
|
||||||
after_update :change_log
|
|
||||||
|
|
||||||
def comments_count
|
def comments_count
|
||||||
comments.count
|
comments.count
|
||||||
@@ -404,20 +409,6 @@ class Budget
|
|||||||
self.original_heading_id = heading_id
|
self.original_heading_id = heading_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def change_log
|
|
||||||
self.changed.each do |field|
|
|
||||||
unless field == "updated_at"
|
|
||||||
log = Budget::Investment::ChangeLog.new
|
|
||||||
log.field = field
|
|
||||||
log.author_id = User.current_user.id unless User.current_user.nil?
|
|
||||||
log.investment_id = self.id
|
|
||||||
log.new_value = self.send field
|
|
||||||
log.old_value = self.send "#{field}_was"
|
|
||||||
!log.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def searchable_translations_definitions
|
def searchable_translations_definitions
|
||||||
{ title => "A",
|
{ title => "A",
|
||||||
description => "D" }
|
description => "D" }
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
class Budget::Investment::ChangeLog < ApplicationRecord
|
|
||||||
belongs_to :author, -> { with_hidden },
|
|
||||||
class_name: "User",
|
|
||||||
foreign_key: "author_id",
|
|
||||||
inverse_of: :budget_investment_change_logs,
|
|
||||||
required: false
|
|
||||||
|
|
||||||
validates :old_value, presence: true
|
|
||||||
validates :new_value, presence: true
|
|
||||||
validates :field, presence: true
|
|
||||||
|
|
||||||
scope :by_investment, ->(investment_id) { where(investment_id: investment_id) }
|
|
||||||
end
|
|
||||||
@@ -27,10 +27,6 @@ class User < ApplicationRecord
|
|||||||
class_name: "Budget::Investment",
|
class_name: "Budget::Investment",
|
||||||
foreign_key: :author_id,
|
foreign_key: :author_id,
|
||||||
inverse_of: :author
|
inverse_of: :author
|
||||||
has_many :budget_investment_change_logs,
|
|
||||||
foreign_key: :author_id,
|
|
||||||
inverse_of: :author,
|
|
||||||
class_name: "Budget::Investment::ChangeLog"
|
|
||||||
has_many :comments, -> { with_hidden }, inverse_of: :user
|
has_many :comments, -> { with_hidden }, inverse_of: :user
|
||||||
has_many :failed_census_calls
|
has_many :failed_census_calls
|
||||||
has_many :notifications
|
has_many :notifications
|
||||||
@@ -400,14 +396,6 @@ class User < ApplicationRecord
|
|||||||
followables.compact.map { |followable| followable.tags.map(&:name) }.flatten.compact.uniq
|
followables.compact.map { |followable| followable.tags.map(&:name) }.flatten.compact.uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.current_user
|
|
||||||
Thread.current[:user]
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.current_user=(user)
|
|
||||||
Thread.current[:user] = user
|
|
||||||
end
|
|
||||||
|
|
||||||
def send_devise_notification(notification, *args)
|
def send_devise_notification(notification, *args)
|
||||||
devise_mailer.send(notification, self, *args).deliver_later
|
devise_mailer.send(notification, self, *args).deliver_later
|
||||||
end
|
end
|
||||||
|
|||||||
46
app/views/admin/audits/_audits.html.erb
Normal file
46
app/views/admin/audits/_audits.html.erb
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<h2><%= t("admin.audits.title") %></h2>
|
||||||
|
|
||||||
|
<% if resource.audits.empty? %>
|
||||||
|
<p><%= t("admin.audits.empty") %></p>
|
||||||
|
<% else %>
|
||||||
|
<table id="audits">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= t("admin.audits.id") %></th>
|
||||||
|
<th><%= t("admin.audits.field") %></th>
|
||||||
|
<th><%= t("admin.audits.old_value") %></th>
|
||||||
|
<th><%= t("admin.audits.new_value") %></th>
|
||||||
|
<th><%= t("admin.audits.edited_at") %></th>
|
||||||
|
<th><%= t("admin.audits.edited_by") %></th>
|
||||||
|
<th><%= t("admin.audits.actions") %></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% resource.own_and_associated_audits.order(:created_at).each do |audit| %>
|
||||||
|
<% audit.audited_changes.each do |field, (old_value, new_value)| %>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"><%= audit.id %></td>
|
||||||
|
<td class="small"><%= sanitize(resource.class.human_attribute_name(field)) %></td>
|
||||||
|
<td class="small">
|
||||||
|
<div class="audit-value"><%= truncate_audit_value(resource, field, old_value) %></div>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<div class="audit-value"><%= truncate_audit_value(resource, field, new_value) %></div>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= l audit.created_at.to_date %>
|
||||||
|
</td>
|
||||||
|
<td class="small">
|
||||||
|
<%= audit.user&.name %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<%= link_to t("shared.show"),
|
||||||
|
polymorphic_path([:admin, *resource_hierarchy_for(audit)]),
|
||||||
|
class: "button hollow primary" %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<% end %>
|
||||||
20
app/views/admin/audits/show.html.erb
Normal file
20
app/views/admin/audits/show.html.erb
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<% provide(:title) do %>
|
||||||
|
<%= t("admin.audits.title") %>
|
||||||
|
<% end %>
|
||||||
|
<%= back_link_to polymorphic_path([:admin, *resource_hierarchy_for(@audit.associated || @audit.auditable)]) %>
|
||||||
|
|
||||||
|
<h2><%= t("admin.audits.title") %></h2>
|
||||||
|
|
||||||
|
<p><strong><%= t("admin.audits.edited_at") %></strong> <%= l @audit.created_at.to_date %></p>
|
||||||
|
<p><strong><%= t("admin.audits.edited_by") %></strong> <%= @audit.user&.name %></p>
|
||||||
|
|
||||||
|
<h3><%= t("admin.audits.changes") %></h3>
|
||||||
|
|
||||||
|
<% @audit.audited_changes.each do |field, (old_value, new_value)| %>
|
||||||
|
<strong><%= t("admin.audits.field") %></strong>
|
||||||
|
<p><%= sanitize(@audit.auditable.class.human_attribute_name(field)) %></p>
|
||||||
|
<strong><%= t("admin.audits.old_value") %></strong>
|
||||||
|
<p><%= wysiwyg(audit_value(@audit.auditable, field, old_value)) %></p>
|
||||||
|
<strong><%= t("admin.audits.new_value") %></strong>
|
||||||
|
<p><%= wysiwyg(audit_value(@audit.auditable, field, new_value)) %></p>
|
||||||
|
<% end %>
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
<div class="small-12 medium-4 column">
|
<div class="small-12 medium-4 column">
|
||||||
<p>
|
<p>
|
||||||
<strong><%= t("admin.budget_investments.show.selection.title") %></strong>:
|
<strong><%= t("admin.budget_investments.show.selection.title") %></strong>:
|
||||||
<%= t("admin.budget_investments.show.selection.#{@investment.selected?}") %>
|
<%= @investment.class.human_attribute_name("selected_#{@investment.selected?}") %>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="small-12 medium-4 column">
|
<div class="small-12 medium-4 column">
|
||||||
|
|||||||
@@ -66,6 +66,6 @@
|
|||||||
|
|
||||||
<%= render "valuation/budget_investments/valuation_comments" %>
|
<%= render "valuation/budget_investments/valuation_comments" %>
|
||||||
|
|
||||||
<%= render "admin/change_logs/change_log", logs: @logs %>
|
<%= render "admin/audits/audits", resource: @investment %>
|
||||||
|
|
||||||
<%= render "admin/milestones/milestones", milestoneable: @investment %>
|
<%= render "admin/milestones/milestones", milestoneable: @investment %>
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
<h2 class="inline-block"><%= t("admin.change_log.title") %></h2>
|
|
||||||
|
|
||||||
<% if logs.empty? %>
|
|
||||||
<label><%= t("admin.change_log.empty") %></label>
|
|
||||||
<% else %>
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th><%= t("admin.change_log.id") %></th>
|
|
||||||
<th><%= t("admin.change_log.field") %></th>
|
|
||||||
<th><%= t("admin.change_log.old_value") %></th>
|
|
||||||
<th><%= t("admin.change_log.new_value") %></th>
|
|
||||||
<th><%= t("admin.change_log.edited_at") %></th>
|
|
||||||
<th><%= t("admin.change_log.edited_by") %></th>
|
|
||||||
<th><%= t("admin.change_log.actions") %></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<% logs.each do |log| %>
|
|
||||||
<tr id="log_<%= log.id %>">
|
|
||||||
<td class="text-center"><%= log.id %></td>
|
|
||||||
<td class="small"><%= log.field.capitalize %></td>
|
|
||||||
<td class="small">
|
|
||||||
<div class="log-value"><%= log.old_value %></div>
|
|
||||||
</td>
|
|
||||||
<td class="small">
|
|
||||||
<div class="log-value"><%= log.new_value %></div>
|
|
||||||
</td>
|
|
||||||
<td class="small">
|
|
||||||
<%= log.created_at.to_date %>
|
|
||||||
</td>
|
|
||||||
<td class="small">
|
|
||||||
<%= log.author.name unless log.author.nil? %>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<%= link_to admin_change_log_path(id: log) do %>
|
|
||||||
<button class="button hollow primary"><%= t("shared.show") %></button>
|
|
||||||
<% end %>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<% end %>
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<h2 class="inline-block"><%= t("admin.change_log.title") %></h2>
|
|
||||||
|
|
||||||
<label><strong><%= t("admin.change_log.id") %></strong></label>
|
|
||||||
<p><%= @log.id %></p>
|
|
||||||
<label><strong><%= t("admin.change_log.old_value") %></strong></label>
|
|
||||||
<p><%= @log.old_value %></p>
|
|
||||||
<label><strong><%= t("admin.change_log.new_value") %></strong></label>
|
|
||||||
<p><%= @log.new_value %></p>
|
|
||||||
<label><strong><%= t("admin.change_log.edited_at") %></strong></label>
|
|
||||||
<p><%= @log.created_at.to_date %></p>
|
|
||||||
<label><strong><%= t("admin.change_log.edited_by") %></strong></label>
|
|
||||||
<p><%= @log.author.name unless @log.author.nil? %></p>
|
|
||||||
3
config/initializers/audited.rb
Normal file
3
config/initializers/audited.rb
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Audited.config do |config|
|
||||||
|
config.audit_class = ::Audit
|
||||||
|
end
|
||||||
@@ -13,6 +13,8 @@ module ActionDispatch::Routing::UrlFor
|
|||||||
[*resource_hierarchy_for(resource.milestoneable), resource]
|
[*resource_hierarchy_for(resource.milestoneable), resource]
|
||||||
when "ProgressBar"
|
when "ProgressBar"
|
||||||
[*resource_hierarchy_for(resource.progressable), resource]
|
[*resource_hierarchy_for(resource.progressable), resource]
|
||||||
|
when "Audit"
|
||||||
|
[*resource_hierarchy_for(resource.associated || resource.auditable), resource]
|
||||||
when "Legislation::Annotation"
|
when "Legislation::Annotation"
|
||||||
[resource.draft_version.process, resource.draft_version, resource]
|
[resource.draft_version.process, resource.draft_version, resource]
|
||||||
when "Legislation::Proposal", "Legislation::Question", "Legislation::DraftVersion"
|
when "Legislation::Proposal", "Legislation::Question", "Legislation::DraftVersion"
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ en:
|
|||||||
milestone_tag_list: "Milestone tags"
|
milestone_tag_list: "Milestone tags"
|
||||||
price_explanation: "Price explanation"
|
price_explanation: "Price explanation"
|
||||||
selected: "Mark as selected"
|
selected: "Mark as selected"
|
||||||
|
selected_true: "Selected"
|
||||||
|
selected_false: "Not selected"
|
||||||
unfeasibility_explanation: "Feasibility explanation"
|
unfeasibility_explanation: "Feasibility explanation"
|
||||||
valuation_finished: "Valuation finished"
|
valuation_finished: "Valuation finished"
|
||||||
valuator_ids: "Groups"
|
valuator_ids: "Groups"
|
||||||
|
|||||||
@@ -241,8 +241,6 @@ en:
|
|||||||
"false": Compatible
|
"false": Compatible
|
||||||
selection:
|
selection:
|
||||||
title: Selection
|
title: Selection
|
||||||
"true": Selected
|
|
||||||
"false": Not selected
|
|
||||||
winner:
|
winner:
|
||||||
title: Winner
|
title: Winner
|
||||||
"true": "Yes"
|
"true": "Yes"
|
||||||
@@ -1583,8 +1581,9 @@ en:
|
|||||||
submit_header: Save header
|
submit_header: Save header
|
||||||
card_title: Edit card
|
card_title: Edit card
|
||||||
submit_card: Save card
|
submit_card: Save card
|
||||||
change_log:
|
audits:
|
||||||
title: "Change Log"
|
title: "Change Log"
|
||||||
|
changes: "List of changes"
|
||||||
id: "ID"
|
id: "ID"
|
||||||
field: "Field"
|
field: "Field"
|
||||||
new_value: "New Value"
|
new_value: "New Value"
|
||||||
@@ -1592,7 +1591,7 @@ en:
|
|||||||
edited_at: "Edited at"
|
edited_at: "Edited at"
|
||||||
edited_by: "Edited by"
|
edited_by: "Edited by"
|
||||||
actions: "Actions"
|
actions: "Actions"
|
||||||
empty: "There are not changes logged"
|
empty: "There are no changes logged"
|
||||||
local_census_records:
|
local_census_records:
|
||||||
index:
|
index:
|
||||||
title: Manage local census
|
title: Manage local census
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ es:
|
|||||||
milestone_tag_list: "Etiquetas de Seguimiento"
|
milestone_tag_list: "Etiquetas de Seguimiento"
|
||||||
price_explanation: "Informe de coste <small>(opcional, dato público)</small>"
|
price_explanation: "Informe de coste <small>(opcional, dato público)</small>"
|
||||||
selected: "Marcar como seleccionado"
|
selected: "Marcar como seleccionado"
|
||||||
|
selected_true: "Seleccionado"
|
||||||
|
selected_false: "No seleccionado"
|
||||||
unfeasibility_explanation: "Informe de inviabilidad <small>(en caso de que lo sea, dato público)</small>"
|
unfeasibility_explanation: "Informe de inviabilidad <small>(en caso de que lo sea, dato público)</small>"
|
||||||
valuation_finished: "Informe finalizado"
|
valuation_finished: "Informe finalizado"
|
||||||
valuator_ids: "Grupos"
|
valuator_ids: "Grupos"
|
||||||
|
|||||||
@@ -241,8 +241,6 @@ es:
|
|||||||
"false": Compatible
|
"false": Compatible
|
||||||
selection:
|
selection:
|
||||||
title: Selección
|
title: Selección
|
||||||
"true": Seleccionado
|
|
||||||
"false": No seleccionado
|
|
||||||
winner:
|
winner:
|
||||||
title: Ganador
|
title: Ganador
|
||||||
"true": "Si"
|
"true": "Si"
|
||||||
@@ -1582,8 +1580,9 @@ es:
|
|||||||
submit_header: Guardar encabezado
|
submit_header: Guardar encabezado
|
||||||
card_title: Editar tarjeta
|
card_title: Editar tarjeta
|
||||||
submit_card: Guardar tarjeta
|
submit_card: Guardar tarjeta
|
||||||
change_log:
|
audits:
|
||||||
title: "Historial"
|
title: "Historial"
|
||||||
|
changes: "Lista de cambios"
|
||||||
id: "ID"
|
id: "ID"
|
||||||
field: "Campo"
|
field: "Campo"
|
||||||
new_value: "Valor nuevo"
|
new_value: "Valor nuevo"
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ namespace :admin do
|
|||||||
resources :budget_investments, only: [:index, :show, :edit, :update] do
|
resources :budget_investments, only: [:index, :show, :edit, :update] do
|
||||||
member { patch :toggle_selection }
|
member { patch :toggle_selection }
|
||||||
|
|
||||||
|
resources :audits, only: :show, controller: "budget_investment_audits"
|
||||||
resources :milestones, controller: "budget_investment_milestones"
|
resources :milestones, controller: "budget_investment_milestones"
|
||||||
resources :progress_bars, except: :show, controller: "budget_investment_progress_bars"
|
resources :progress_bars, except: :show, controller: "budget_investment_progress_bars"
|
||||||
end
|
end
|
||||||
@@ -250,8 +251,6 @@ namespace :admin do
|
|||||||
get "download_settings/:resource", to: "download_settings#edit", as: "edit_download_settings"
|
get "download_settings/:resource", to: "download_settings#edit", as: "edit_download_settings"
|
||||||
put "download_settings/:resource", to: "download_settings#update", as: "update_download_settings"
|
put "download_settings/:resource", to: "download_settings#update", as: "update_download_settings"
|
||||||
|
|
||||||
get "/change_log/:id", to: "budget_investments#show_investment_log", as: "change_log"
|
|
||||||
|
|
||||||
resources :local_census_records
|
resources :local_census_records
|
||||||
namespace :local_census_records do
|
namespace :local_census_records do
|
||||||
resources :imports, only: [:new, :create, :show]
|
resources :imports, only: [:new, :create, :show]
|
||||||
|
|||||||
@@ -121,13 +121,16 @@ section "Creating Investments" do
|
|||||||
100.times do
|
100.times do
|
||||||
heading = Budget::Heading.all.sample
|
heading = Budget::Heading.all.sample
|
||||||
|
|
||||||
investment = Budget::Investment.create!(
|
translation_attributes = random_locales.each_with_object({}) do |locale, attributes|
|
||||||
|
attributes["title_#{locale.to_s.underscore}"] = "Title for locale #{locale}"
|
||||||
|
attributes["description_#{locale.to_s.underscore}"] = "<p>Description for locale #{locale}</p>"
|
||||||
|
end
|
||||||
|
|
||||||
|
investment = Budget::Investment.create!({
|
||||||
author: User.all.sample,
|
author: User.all.sample,
|
||||||
heading: heading,
|
heading: heading,
|
||||||
group: heading.group,
|
group: heading.group,
|
||||||
budget: heading.group.budget,
|
budget: heading.group.budget,
|
||||||
title: Faker::Lorem.sentence(3).truncate(60),
|
|
||||||
description: "<p>#{Faker::Lorem.paragraphs.join("</p><p>")}</p>",
|
|
||||||
created_at: rand((Time.current - 1.week)..Time.current),
|
created_at: rand((Time.current - 1.week)..Time.current),
|
||||||
feasibility: %w[undecided unfeasible feasible feasible feasible feasible].sample,
|
feasibility: %w[undecided unfeasible feasible feasible feasible feasible].sample,
|
||||||
unfeasibility_explanation: Faker::Lorem.paragraph,
|
unfeasibility_explanation: Faker::Lorem.paragraph,
|
||||||
@@ -136,15 +139,7 @@ section "Creating Investments" do
|
|||||||
price: rand(1..100) * 100000,
|
price: rand(1..100) * 100000,
|
||||||
skip_map: "1",
|
skip_map: "1",
|
||||||
terms_of_service: "1"
|
terms_of_service: "1"
|
||||||
)
|
}.merge(translation_attributes))
|
||||||
|
|
||||||
random_locales.map do |locale|
|
|
||||||
Globalize.with_locale(locale) do
|
|
||||||
investment.title = "Title for locale #{locale}"
|
|
||||||
investment.description = "<p>Description for locale #{locale}</p>"
|
|
||||||
investment.save!
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
add_image_to(investment) if Random.rand > 0.5
|
add_image_to(investment) if Random.rand > 0.5
|
||||||
end
|
end
|
||||||
|
|||||||
26
db/migrate/20191102002206_install_audited.rb
Normal file
26
db/migrate/20191102002206_install_audited.rb
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
class InstallAudited < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
create_table :audits, force: true do |t|
|
||||||
|
t.column :auditable_id, :integer
|
||||||
|
t.column :auditable_type, :string
|
||||||
|
t.column :associated_id, :integer
|
||||||
|
t.column :associated_type, :string
|
||||||
|
t.column :user_id, :integer
|
||||||
|
t.column :user_type, :string
|
||||||
|
t.column :username, :string
|
||||||
|
t.column :action, :string
|
||||||
|
t.column :audited_changes, :jsonb
|
||||||
|
t.column :version, :integer, default: 0
|
||||||
|
t.column :comment, :string
|
||||||
|
t.column :remote_address, :string
|
||||||
|
t.column :request_uuid, :string
|
||||||
|
t.column :created_at, :datetime
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :audits, [:auditable_type, :auditable_id, :version], name: "auditable_index"
|
||||||
|
add_index :audits, [:associated_type, :associated_id], name: "associated_index"
|
||||||
|
add_index :audits, [:user_id, :user_type], name: "user_index"
|
||||||
|
add_index :audits, :request_uuid
|
||||||
|
add_index :audits, :created_at
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
class DropBudgetInvestmentChangeLogs < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
drop_table :budget_investment_change_logs do |t|
|
||||||
|
t.integer :investment_id
|
||||||
|
t.integer :author_id
|
||||||
|
t.string :field
|
||||||
|
t.string :new_value
|
||||||
|
t.string :old_value
|
||||||
|
|
||||||
|
t.timestamps null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
34
db/schema.rb
34
db/schema.rb
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 20191101183155) do
|
ActiveRecord::Schema.define(version: 20191102002238) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
@@ -84,6 +84,28 @@ ActiveRecord::Schema.define(version: 20191101183155) do
|
|||||||
t.index ["visit_id"], name: "index_ahoy_events_on_visit_id", using: :btree
|
t.index ["visit_id"], name: "index_ahoy_events_on_visit_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
|
create_table "audits", force: :cascade do |t|
|
||||||
|
t.integer "auditable_id"
|
||||||
|
t.string "auditable_type"
|
||||||
|
t.integer "associated_id"
|
||||||
|
t.string "associated_type"
|
||||||
|
t.integer "user_id"
|
||||||
|
t.string "user_type"
|
||||||
|
t.string "username"
|
||||||
|
t.string "action"
|
||||||
|
t.jsonb "audited_changes"
|
||||||
|
t.integer "version", default: 0
|
||||||
|
t.string "comment"
|
||||||
|
t.string "remote_address"
|
||||||
|
t.string "request_uuid"
|
||||||
|
t.datetime "created_at"
|
||||||
|
t.index ["associated_type", "associated_id"], name: "associated_index", using: :btree
|
||||||
|
t.index ["auditable_type", "auditable_id", "version"], name: "auditable_index", using: :btree
|
||||||
|
t.index ["created_at"], name: "index_audits_on_created_at", using: :btree
|
||||||
|
t.index ["request_uuid"], name: "index_audits_on_request_uuid", using: :btree
|
||||||
|
t.index ["user_id", "user_type"], name: "user_index", using: :btree
|
||||||
|
end
|
||||||
|
|
||||||
create_table "banner_sections", force: :cascade do |t|
|
create_table "banner_sections", force: :cascade do |t|
|
||||||
t.integer "banner_id"
|
t.integer "banner_id"
|
||||||
t.integer "web_section_id"
|
t.integer "web_section_id"
|
||||||
@@ -203,16 +225,6 @@ ActiveRecord::Schema.define(version: 20191101183155) do
|
|||||||
t.index ["group_id"], name: "index_budget_headings_on_group_id", using: :btree
|
t.index ["group_id"], name: "index_budget_headings_on_group_id", using: :btree
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "budget_investment_change_logs", force: :cascade do |t|
|
|
||||||
t.integer "investment_id"
|
|
||||||
t.integer "author_id"
|
|
||||||
t.string "field"
|
|
||||||
t.string "new_value"
|
|
||||||
t.string "old_value"
|
|
||||||
t.datetime "created_at", null: false
|
|
||||||
t.datetime "updated_at", null: false
|
|
||||||
end
|
|
||||||
|
|
||||||
create_table "budget_investment_milestone_translations", force: :cascade do |t|
|
create_table "budget_investment_milestone_translations", force: :cascade do |t|
|
||||||
t.integer "budget_investment_milestone_id", null: false
|
t.integer "budget_investment_milestone_id", null: false
|
||||||
t.string "locale", null: false
|
t.string "locale", null: false
|
||||||
|
|||||||
38
spec/features/admin/audits_spec.rb
Normal file
38
spec/features/admin/audits_spec.rb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
describe "Admin change log" do
|
||||||
|
let(:administrator) { create(:administrator, user: create(:user, username: "Ana")) }
|
||||||
|
before { login_as(administrator.user) }
|
||||||
|
|
||||||
|
context "Investments Participatory Budgets" do
|
||||||
|
scenario "Changes" do
|
||||||
|
investment = create(:budget_investment, title: "Good old times")
|
||||||
|
|
||||||
|
visit admin_budget_budget_investment_path(investment.budget, investment)
|
||||||
|
|
||||||
|
expect(page).to have_content "There are no changes logged"
|
||||||
|
|
||||||
|
click_link "Edit"
|
||||||
|
fill_in "Title", with: "Modern times"
|
||||||
|
click_button "Update"
|
||||||
|
|
||||||
|
expect(page).not_to have_content "There are no changes logged"
|
||||||
|
expect(page).to have_content "Change Log"
|
||||||
|
|
||||||
|
within("#audits thead") do
|
||||||
|
expect(page).to have_content "Field"
|
||||||
|
expect(page).to have_content "Old Value"
|
||||||
|
expect(page).to have_content "New Value"
|
||||||
|
expect(page).to have_content "Edited at"
|
||||||
|
expect(page).to have_content "Edited by"
|
||||||
|
end
|
||||||
|
|
||||||
|
within("#audits tbody") do
|
||||||
|
expect(page).to have_content "Title"
|
||||||
|
expect(page).to have_content "Good old times"
|
||||||
|
expect(page).to have_content "Modern times"
|
||||||
|
expect(page).to have_content "Ana"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
require "rails_helper"
|
|
||||||
|
|
||||||
describe "Admin change log" do
|
|
||||||
let(:budget) { create(:budget) }
|
|
||||||
let(:administrator) do
|
|
||||||
create(:administrator, user: create(:user, username: "Ana", email: "ana@admins.org"))
|
|
||||||
end
|
|
||||||
|
|
||||||
context "Investments Participatory Budgets" do
|
|
||||||
before do
|
|
||||||
login_as(create(:administrator).user)
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario "No changes" do
|
|
||||||
budget_investment = create(:budget_investment,
|
|
||||||
:unfeasible,
|
|
||||||
unfeasibility_explanation: "It is impossible",
|
|
||||||
price: 1234,
|
|
||||||
price_first_year: 1000,
|
|
||||||
administrator: administrator)
|
|
||||||
|
|
||||||
visit admin_budget_budget_investments_path(budget_investment.budget)
|
|
||||||
|
|
||||||
click_link budget_investment.title
|
|
||||||
|
|
||||||
expect(page).to have_content(budget_investment.title)
|
|
||||||
expect(page).to have_content(budget_investment.description)
|
|
||||||
expect(page).to have_content(budget_investment.author.name)
|
|
||||||
expect(page).to have_content(budget_investment.heading.name)
|
|
||||||
expect(page).to have_content("There are not changes logged")
|
|
||||||
end
|
|
||||||
|
|
||||||
scenario "Changes" do
|
|
||||||
budget_investment = create(:budget_investment,
|
|
||||||
:unfeasible,
|
|
||||||
unfeasibility_explanation: "It is impossible",
|
|
||||||
price: 1234,
|
|
||||||
price_first_year: 1000,
|
|
||||||
administrator: administrator)
|
|
||||||
|
|
||||||
visit admin_budget_budget_investments_path(budget_investment.budget)
|
|
||||||
|
|
||||||
click_link budget_investment.title
|
|
||||||
|
|
||||||
expect(page).to have_content(budget_investment.title)
|
|
||||||
expect(page).to have_content(budget_investment.description)
|
|
||||||
expect(page).to have_content(budget_investment.author.name)
|
|
||||||
expect(page).to have_content(budget_investment.heading.name)
|
|
||||||
expect(page).to have_content("There are not changes logged")
|
|
||||||
|
|
||||||
budget_investment.update!(title: "test")
|
|
||||||
|
|
||||||
visit admin_budget_budget_investments_path(budget_investment.budget)
|
|
||||||
|
|
||||||
click_link budget_investment.title
|
|
||||||
|
|
||||||
expect(page).not_to have_content("There are not changes logged")
|
|
||||||
expect(page).to have_content("Change Log")
|
|
||||||
expect(page).to have_content("Title")
|
|
||||||
expect(page).to have_content("test")
|
|
||||||
expect(page).to have_content("Field")
|
|
||||||
expect(page).to have_content("Old Value")
|
|
||||||
expect(page).to have_content("New Value")
|
|
||||||
expect(page).to have_content("Edited at")
|
|
||||||
expect(page).to have_content("Edited by")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Reference in New Issue
Block a user