diff --git a/Gemfile b/Gemfile index 4a90160c3..fbf0a48af 100644 --- a/Gemfile +++ b/Gemfile @@ -43,6 +43,9 @@ gem 'react-rails' gem 'sidekiq' +gem 'diffy' +gem 'paper_trail' + group :production do gem 'rails_12factor' gem 'rack-timeout', '~> 0.5' diff --git a/Gemfile.lock b/Gemfile.lock index ed9282d54..dbe356970 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -112,6 +112,7 @@ GEM responders warden (~> 1.2.3) diff-lcs (1.3) + diffy (3.3.0) dotenv (2.5.0) dotenv-rails (2.5.0) dotenv (= 2.5.0) @@ -252,6 +253,9 @@ GEM omniauth-oauth (~> 1.1) rack orm_adapter (0.5.0) + paper_trail (10.3.1) + activerecord (>= 4.2) + request_store (~> 1.1) pg (1.1.3) pry (0.12.2) coderay (~> 1.1.0) @@ -450,6 +454,7 @@ DEPENDENCIES country_select (~> 1.3.1) database_cleaner (~> 1.6.0) devise (~> 4.7) + diffy dotenv-rails draper (~> 3.0.1) factory_bot_rails @@ -471,6 +476,7 @@ DEPENDENCIES nokogiri (~> 1.10.8) omniauth-github omniauth-twitter + paper_trail pg pry-rails pry-remote diff --git a/app/assets/stylesheets/modules/_proposal.scss b/app/assets/stylesheets/modules/_proposal.scss index dd0de0d17..c996496a8 100644 --- a/app/assets/stylesheets/modules/_proposal.scss +++ b/app/assets/stylesheets/modules/_proposal.scss @@ -267,3 +267,9 @@ div.col-md-4 { padding-bottom: 0; } } + +.diff-view { + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px solid grey; +} diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f232b38cb..c97f32b2c 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,8 +2,6 @@ class ApplicationController < ActionController::Base include Pundit include ActivateNavigation rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized - #after_action :verify_authorized, except: :index - #after_action :verify_policy_scoped, only: :index require "csv" # Prevent CSRF attacks by raising an exception. @@ -18,6 +16,7 @@ class ApplicationController < ActionController::Base helper_method :schedule_mode? helper_method :program_tracks + before_action :set_paper_trail_whodunnit before_action :current_event before_action :configure_permitted_parameters, if: :devise_controller? diff --git a/app/helpers/proposal_helper.rb b/app/helpers/proposal_helper.rb index d803eb528..05ab74d3a 100644 --- a/app/helpers/proposal_helper.rb +++ b/app/helpers/proposal_helper.rb @@ -1,4 +1,11 @@ module ProposalHelper + def diff(content1, content2) + changes = Diffy::Diff.new(content1, content2, + include_plus_and_minus_in_html: true, + include_diff_info: true) + changes.to_s.present? ? changes.to_s(:html).html_safe : 'No Changes' + end + def rating_tooltip <<-HTML

Ratings Guide

diff --git a/app/models/proposal.rb b/app/models/proposal.rb index 40fea7d8e..e850d8fc9 100644 --- a/app/models/proposal.rb +++ b/app/models/proposal.rb @@ -28,6 +28,8 @@ class Proposal < ApplicationRecord serialize :last_change serialize :proposal_data, Hash + has_paper_trail only: [:title, :abstract, :details, :pitch] + attr_accessor :tags, :review_tags, :updating_user accepts_nested_attributes_for :public_comments, reject_if: Proc.new { |comment_attributes| comment_attributes[:body].blank? } @@ -249,6 +251,10 @@ def has_reviewer_activity? ratings.present? || has_reviewer_comments? end + def changeset_fields + versions[1..]&.map(&:changeset)&.flat_map(&:keys)&.uniq + end + private def abstract_length diff --git a/app/views/proposals/_contents.html.haml b/app/views/proposals/_contents.html.haml index e847dc688..bc83da51f 100644 --- a/app/views/proposals/_contents.html.haml +++ b/app/views/proposals/_contents.html.haml @@ -22,3 +22,14 @@ %div = value.capitalize %div + +- unless proposal.changeset_fields.blank? + %h2.fieldset-legend Proposal Diff... + - proposal.versions.each do |version| + #diff-view + - version.changeset.each do |k, (old, new)| + %h3.control-label= k.titleize + %div= diff old, new + +:css + = #{Diffy::CSS} diff --git a/db/migrate/20200223215131_create_versions.rb b/db/migrate/20200223215131_create_versions.rb new file mode 100644 index 000000000..b67cca75e --- /dev/null +++ b/db/migrate/20200223215131_create_versions.rb @@ -0,0 +1,36 @@ +# This migration creates the `versions` table, the only schema PT requires. +# All other migrations PT provides are optional. +class CreateVersions < ActiveRecord::Migration[5.2] + + # The largest text column available in all supported RDBMS is + # 1024^3 - 1 bytes, roughly one gibibyte. We specify a size + # so that MySQL will use `longtext` instead of `text`. Otherwise, + # when serializing very large objects, `text` might not be big enough. + TEXT_BYTES = 1_073_741_823 + + def change + create_table :versions do |t| + t.string :item_type, {:null=>false} + t.integer :item_id, null: false, limit: 8 + t.string :event, null: false + t.string :whodunnit + t.text :object, limit: TEXT_BYTES + + # Known issue in MySQL: fractional second precision + # ------------------------------------------------- + # + # MySQL timestamp columns do not support fractional seconds unless + # defined with "fractional seconds precision". MySQL users should manually + # add fractional seconds precision to this migration, specifically, to + # the `created_at` column. + # (https://dev.mysql.com/doc/refman/5.6/en/fractional-seconds.html) + # + # MySQL users should also upgrade to at least rails 4.2, which is the first + # version of ActiveRecord with support for fractional seconds in MySQL. + # (https://github.com/rails/rails/pull/14359) + # + t.datetime :created_at + end + add_index :versions, %i(item_type item_id) + end +end diff --git a/db/migrate/20200223215132_add_object_changes_to_versions.rb b/db/migrate/20200223215132_add_object_changes_to_versions.rb new file mode 100644 index 000000000..b5f2fb4b6 --- /dev/null +++ b/db/migrate/20200223215132_add_object_changes_to_versions.rb @@ -0,0 +1,12 @@ +# This migration adds the optional `object_changes` column, in which PaperTrail +# will store the `changes` diff for each update event. See the readme for +# details. +class AddObjectChangesToVersions < ActiveRecord::Migration[5.2] + # The largest text column available in all supported RDBMS. + # See `create_versions.rb` for details. + TEXT_BYTES = 1_073_741_823 + + def change + add_column :versions, :object_changes, :text, limit: TEXT_BYTES + end +end diff --git a/db/schema.rb b/db/schema.rb index c1b577861..4f23f2034 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2018_01_11_175100) do +ActiveRecord::Schema.define(version: 2020_02_23_215132) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -250,5 +250,16 @@ t.index ["uid"], name: "index_users_on_uid" end + create_table "versions", force: :cascade do |t| + t.string "item_type", null: false + t.bigint "item_id", null: false + t.string "event", null: false + t.string "whodunnit" + t.text "object" + t.datetime "created_at" + t.text "object_changes" + t.index ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" + end + add_foreign_key "session_formats", "events" end