diff --git a/.gitignore b/.gitignore index f71b3c03..85098ddc 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ Gemfile.lock tmp/rubycritic/ /.bundle +.ruby-version diff --git a/.travis.yml b/.travis.yml index 840a5117..24c38467 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ env: - PLUGIN=redmine_hourglass - REDMINE=test_redmine - TRACE=--trace + - RAILS_ENV=test matrix: include: @@ -18,12 +19,10 @@ matrix: rvm: 2.0.0 env: - REDMINE_VERSION=3.2.9 - - DATABASE=SQLITE3 - name: Ruby 2.0 / Redmine 3.3 rvm: 2.0.0 env: - REDMINE_VERSION=3.3.9 - - DATABASE=SQLITE3 - name: Ruby 2.1 / Redmine 3.3 rvm: 2.1.10 @@ -51,31 +50,29 @@ matrix: rvm: 2.3.8 env: - REDMINE_VERSION=3.4.1 - - DATABASE=SQLITE3 - name: Ruby 2.3 / Redmine 3.4.9 rvm: 2.3.8 env: - REDMINE_VERSION=3.4.9 - - DATABASE=SQLITE3 + - name: Ruby 2.3 / Redmine 4 + rvm: 2.3.8 + env: + - REDMINE_VERSION=4.0.2 - name: Ruby 2.5 / Redmine 4 rvm: 2.5.3 env: - REDMINE_VERSION=4.0.2 - - DATABASE=SQLITE3 - name: Ruby 2.6 / Redmine 4 rvm: 2.6.1 env: - REDMINE_VERSION=4.0.2 - - DATABASE=SQLITE3 fast_finish: true allow_failures: - - env: - - REDMINE_VERSION=4.0.2 - - DATABASE=SQLITE3 + - rvm: 2.6.1 before_install: - source .travis/clone_redmine.sh diff --git a/.travis/clone_redmine.sh b/.travis/clone_redmine.sh index a58aa9f8..6b9b78da 100644 --- a/.travis/clone_redmine.sh +++ b/.travis/clone_redmine.sh @@ -48,11 +48,11 @@ fi ln -s "$PATH_TO_PLUGIN" "$PATH_TO_PLUGINS/$PLUGIN" case $DATABASE in - SQLITE3) cp $PATH_TO_PLUGINS/$PLUGIN/.travis/sqlite3_database.yml config/database.yml - ;; MYSQL) cp $PATH_TO_PLUGINS/$PLUGIN/.travis/mysql_database.yml config/database.yml ;; POSTGRESQL) cp $PATH_TO_PLUGINS/$PLUGIN/.travis/postgresql_database.yml config/database.yml ;; + *) cp $PATH_TO_PLUGINS/$PLUGIN/.travis/sqlite3_database.yml config/database.yml + ;; esac diff --git a/app/controllers/concerns/boolean_parsing.rb b/app/controllers/concerns/boolean_parsing.rb index bbd02d31..d15e4513 100644 --- a/app/controllers/concerns/boolean_parsing.rb +++ b/app/controllers/concerns/boolean_parsing.rb @@ -4,7 +4,11 @@ module BooleanParsing def parse_boolean(keys, params) keys = [keys] if keys.is_a? Symbol keys.each do |key| - params[key] = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[key]) + if Rails::VERSION::MAJOR <= 4 + params[key] = ActiveRecord::Type::Boolean.new.type_cast_from_user(params[key]) + else + params[key] = ActiveRecord::Type::Boolean.new.cast(params[key]) + end end params end diff --git a/app/controllers/hourglass/api_base_controller.rb b/app/controllers/hourglass/api_base_controller.rb index c37de604..a30740d5 100644 --- a/app/controllers/hourglass/api_base_controller.rb +++ b/app/controllers/hourglass/api_base_controller.rb @@ -14,6 +14,7 @@ class ApiBaseController < ApplicationController include ::AuthorizationConcern private + # use only these codes: # :ok (200) # :not_modified (304) @@ -24,8 +25,8 @@ class ApiBaseController < ApplicationController # :internal_server_error (500) def respond_with_error(status, message, **options) render json: { - message: message.is_a?(Array) && options[:array_mode] == :sentence ? message.to_sentence : message, - status: Rack::Utils.status_code(status) + message: message.is_a?(Array) && options[:array_mode] == :sentence ? message.to_sentence : message, + status: Rack::Utils.status_code(status) }, status: status throw :halt unless options[:no_halt] @@ -71,18 +72,25 @@ def list_records(klass) scope = @query.results_scope order: sort_clause offset, limit = api_offset_and_limit respond_with_success( - count: scope.count, - offset: offset, - limit: limit, - records: scope.offset(offset).limit(limit).to_a + count: scope.count, + offset: offset, + limit: limit, + records: scope.offset(offset).limit(limit).to_a ) end def bulk(params_key = controller_name, &block) @bulk_success = [] @bulk_errors = [] - params[params_key].each_with_index do |(id, params), index| - id, params = "new#{index}", id if id.is_a?(Hash) + entries = params[params_key] + entries = entries.to_unsafe_h if Rails::VERSION::MAJOR >= 5 && entries.instance_of?(ActionController::Parameters) + entries.each_with_index do |(id, params), index| + if Rails::VERSION::MAJOR <= 4 + id, params = "new#{index}", id if id.is_a?(Hash) + else + id, params = "new#{index}", id if id.instance_of?(ActionController::Parameters) + params = ActionController::Parameters.new(params) if params.is_a?(Hash) + end error_preface = id.start_with?('new') ? bulk_error_preface(index, mode: :create) : bulk_error_preface(id) evaluate_entry bulk_entry(id, params, &block), error_preface end @@ -132,7 +140,7 @@ def internal_server_error(e) end def flash_array(type, messages) - flash[type] = render_to_string partial: 'hourglass_ui/flash_array', locals: {messages: messages} + flash[type] = render_to_string partial: 'hourglass_ui/flash_array', locals: { messages: messages } end def custom_field_keys(params_hash) diff --git a/app/controllers/hourglass/time_logs_controller.rb b/app/controllers/hourglass/time_logs_controller.rb index 329f12d0..c2ec9eef 100644 --- a/app/controllers/hourglass/time_logs_controller.rb +++ b/app/controllers/hourglass/time_logs_controller.rb @@ -107,6 +107,7 @@ def bulk_destroy end private + def time_log_params(params_hash = params.require(:time_log)) parse_boolean :round, params_hash.permit(:start, :stop, :comments, :round, :user_id) end @@ -117,16 +118,16 @@ def create_time_log_params(params_hash = params.require(:time_log)) def split_params parse_boolean [:round, :insert_new_before], - { - split_at: Time.parse(params[:split_at]), - insert_new_before: params[:insert_new_before], - round: params[:round] - } + { + split_at: Time.parse(params[:split_at]), + insert_new_before: params[:insert_new_before], + round: params[:round] + } end def time_booking_params(params_hash = params.require(:time_booking)) parse_boolean :round, params_hash.permit(:comments, :project_id, :issue_id, :activity_id, :round, - custom_field_values: custom_field_keys(params_hash)) + custom_field_values: custom_field_keys(params_hash)) end def time_log_from_id(id = params[:id]) diff --git a/app/models/concerns/hourglass/type_parsing.rb b/app/models/concerns/hourglass/type_parsing.rb new file mode 100644 index 00000000..1d8b09d1 --- /dev/null +++ b/app/models/concerns/hourglass/type_parsing.rb @@ -0,0 +1,23 @@ +module Hourglass::TypeParsing + def parse_type(type, attribute) + if Rails::VERSION::MAJOR <= 4 + case type + when :boolean + ActiveRecord::Type::Boolean.new.type_cast_from_user(attribute) + when :integer + ActiveRecord::Type::Integer.new.type_cast_from_user(attribute) + when :float + ActiveRecord::Type::Float.new.type_cast_from_user(attribute) + end + else + case type + when :boolean + ActiveRecord::Type::Boolean.new.cast(attribute) + when :integer + ActiveRecord::Type::Integer.new.cast(attribute) + when :float + ActiveRecord::Type::Float.new.cast(attribute) + end + end + end +end \ No newline at end of file diff --git a/app/models/hourglass/global_settings.rb b/app/models/hourglass/global_settings.rb index e9072b6e..6bf5bfe4 100644 --- a/app/models/hourglass/global_settings.rb +++ b/app/models/hourglass/global_settings.rb @@ -1,5 +1,6 @@ module Hourglass class GlobalSettings + include TypeParsing include ActiveModel::Model attr_accessor :round_sums_only, @@ -14,8 +15,7 @@ class GlobalSettings validates :round_sums_only, inclusion: { in: ['true', 'false', '1', '0', true, false] } validates :round_minimum, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 24 } - validates :round_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0, - less_than_or_equal_to: 100 } + validates :round_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 100 } validates :round_default, inclusion: { in: ['true', 'false', '1', '0', true, false] } validates :round_carry_over_due, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 24 } validates :report_title, length: { maximum: 23 }, presence: true @@ -68,16 +68,5 @@ def resolve_types self.report_logo_width = parse_type :integer, @report_logo_width self.global_tracker = parse_type :boolean, @global_tracker end - - def parse_type(type, attribute) - case type - when :boolean - ActiveRecord::Type::Boolean.new.type_cast_from_user(attribute) - when :integer - ActiveRecord::Type::Integer.new.type_cast_from_user(attribute) - when :float - ActiveRecord::Type::Float.new.type_cast_from_user(attribute) - end - end end end diff --git a/app/models/hourglass/project_settings.rb b/app/models/hourglass/project_settings.rb index f0934b58..bc59180a 100644 --- a/app/models/hourglass/project_settings.rb +++ b/app/models/hourglass/project_settings.rb @@ -1,5 +1,6 @@ module Hourglass class ProjectSettings + include TypeParsing include ActiveModel::Model attr_accessor :round_sums_only, @@ -9,13 +10,12 @@ class ProjectSettings :round_carry_over_due validates :round_sums_only, inclusion: { in: ['true', 'false', true, false] }, allow_blank: true - validates :round_minimum, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 24 }, - allow_blank: true + validates :round_minimum, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 24 }, allow_blank: true validates :round_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 100 }, allow_blank: true validates :round_default, inclusion: { in: ['true', 'false', true, false] }, allow_blank: true - validates :round_carry_over_due, numericality: { greater_than_or_equal_to: 0, less_than_or_equal_to: 24 }, - allow_blank: true + validates :round_carry_over_due, numericality: { greater_than_or_equal_to: 0, + less_than_or_equal_to: 24 }, allow_blank: true def initialize(project = nil) @project = project @@ -36,6 +36,7 @@ def update(attributes) end private + def from_hash(attributes) self.round_sums_only = attributes[:round_sums_only] self.round_minimum = attributes[:round_minimum] @@ -61,16 +62,5 @@ def resolve_types self.round_default = parse_type :boolean, @round_default self.round_carry_over_due = parse_type :float, @round_carry_over_due end - - def parse_type(type, attribute) - case type - when :boolean - ActiveRecord::Type::Boolean.new.type_cast_from_user(attribute) - when :integer - ActiveRecord::Type::Integer.new.type_cast_from_user(attribute) - when :float - ActiveRecord::Type::Float.new.type_cast_from_user(attribute) - end - end end end diff --git a/app/views/hourglass_ui/forms/fields/_activity.slim b/app/views/hourglass_ui/forms/fields/_activity.slim index bffcc788..b731bb77 100644 --- a/app/views/hourglass_ui/forms/fields/_activity.slim +++ b/app/views/hourglass_ui/forms/fields/_activity.slim @@ -2,4 +2,4 @@ .label = form.label :activity_id .input - = form.collection_select :activity_id, TimeEntryActivity.applicable(entry.project), :id, :name, {include_blank: !local_assigns[:required]}, disabled: local_assigns[:disabled], required: local_assigns[:required] + = form.collection_select :activity_id, TimeEntryActivity.applicable(entry.project), :id, :name, { include_blank: true }, disabled: local_assigns[:disabled], required: local_assigns[:required] diff --git a/app/views/hourglass_ui/forms/fields/_project.slim b/app/views/hourglass_ui/forms/fields/_project.slim index 6af5e777..3da40bd2 100644 --- a/app/views/hourglass_ui/forms/fields/_project.slim +++ b/app/views/hourglass_ui/forms/fields/_project.slim @@ -4,4 +4,4 @@ - if local_assigns[:with_link] = link_to '', project_path(id: entry.project_id || ''), class: css_classes('icon icon-link', ('hidden' unless entry.project)) .input - = form.select :project_id, projects_for_project_select(entry.project), {include_blank: !local_assigns[:required]}, disabled: local_assigns[:disabled], required: local_assigns[:required] + = form.select :project_id, projects_for_project_select(entry.project), { include_blank: true }, disabled: local_assigns[:disabled], required: local_assigns[:required] diff --git a/app/views/hourglass_ui/forms/fields/_user_id.slim b/app/views/hourglass_ui/forms/fields/_user_id.slim index 27fadb1c..569b1cbc 100644 --- a/app/views/hourglass_ui/forms/fields/_user_id.slim +++ b/app/views/hourglass_ui/forms/fields/_user_id.slim @@ -3,4 +3,4 @@ = form.label :user_id .input - project = entry && entry.respond_to?(:project) && entry.project || nil - = form.select :user_id, options_from_collection_for_select(user_collection(project), :id, :name, entry.user_id || User.current.id), {include_blank: !local_assigns[:required]}, disabled: local_assigns[:disabled], required: local_assigns[:required] + = form.select :user_id, options_from_collection_for_select(user_collection(project), :id, :name, entry.user_id || User.current.id), { include_blank: true }, disabled: local_assigns[:disabled], required: local_assigns[:required] diff --git a/app/views/hourglass_ui/time_bookings/context_menu.slim b/app/views/hourglass_ui/time_bookings/context_menu.slim index bbc8be85..f7074692 100644 --- a/app/views/hourglass_ui/time_bookings/context_menu.slim +++ b/app/views/hourglass_ui/time_bookings/context_menu.slim @@ -1,6 +1,6 @@ - ids = @records.map(&:id) ul - li = context_menu_link t(:button_edit), hourglass_ui_bulk_edit_time_bookings_path(ids: ids), class: 'icon-edit js-show-inline-form-multi', title: t(:button_edit), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_booking| policy(time_booking).change? } - li = context_menu_link t(:button_delete), @records.length == 1 ? hourglass_time_booking_path(@records.first) : bulk_destroy_hourglass_time_bookings_path(time_bookings: ids), class: 'icon-del js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !@records.all? { |time_booking| policy(time_booking).destroy? } + li = context_menu_link t(:button_edit), hourglass_ui_bulk_edit_time_bookings_path(ids: ids), class: 'icon icon-edit js-show-inline-form-multi', title: t(:button_edit), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_booking| policy(time_booking).change? } + li = context_menu_link t(:button_delete), @records.length == 1 ? hourglass_time_booking_path(@records.first) : bulk_destroy_hourglass_time_bookings_path(time_bookings: ids), class: 'icon icon-del js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !@records.all? { |time_booking| policy(time_booking).destroy? } diff --git a/app/views/hourglass_ui/time_logs/context_menu.slim b/app/views/hourglass_ui/time_logs/context_menu.slim index a23ab536..0a7d3188 100644 --- a/app/views/hourglass_ui/time_logs/context_menu.slim +++ b/app/views/hourglass_ui/time_logs/context_menu.slim @@ -1,8 +1,8 @@ - ids = @records.map(&:id) ul - li = context_menu_link t('hourglass.ui.lists.button_book'), hourglass_ui_bulk_book_time_logs_path(ids: ids), class: 'icon-time js-show-inline-form-multi', title: t('hourglass.ui.lists.button_book'), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_log| policy(time_log).book? } - li = context_menu_link t(:button_edit), hourglass_ui_bulk_edit_time_logs_path(ids: ids), class: 'icon-edit js-show-inline-form-multi', title: t(:button_edit), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_log| policy(time_log).change? } - li = context_menu_link t(:button_delete), @records.length == 1 ? hourglass_time_log_path(@records.first) : bulk_destroy_hourglass_time_logs_path(time_logs: ids), class: 'icon-del js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !@records.all? { |time_log| policy(time_log).destroy? } - li = context_menu_link t('hourglass.ui.time_logs.button_join'), join_hourglass_time_logs_path(ids: ids), class: 'icon-hourglass-join js-hourglass-remote', title: t('hourglass.ui.time_logs.button_join'), remote: true, data: {method: 'post'}, disabled: ids.length == 1 || !@records.all? { |time_log| policy(time_log).join? } && Hourglass::TimeLog.joinable?(*ids) + li = context_menu_link t('hourglass.ui.lists.button_book'), hourglass_ui_bulk_book_time_logs_path(ids: ids), class: 'icon icon-time js-show-inline-form-multi', title: t('hourglass.ui.lists.button_book'), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_log| policy(time_log).book? } + li = context_menu_link t(:button_edit), hourglass_ui_bulk_edit_time_logs_path(ids: ids), class: 'icon icon-edit js-show-inline-form-multi', title: t(:button_edit), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_log| policy(time_log).change? } + li = context_menu_link t(:button_delete), @records.length == 1 ? hourglass_time_log_path(@records.first) : bulk_destroy_hourglass_time_logs_path(time_logs: ids), class: 'icon icon-del js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !@records.all? { |time_log| policy(time_log).destroy? } + li = context_menu_link t('hourglass.ui.time_logs.button_join'), join_hourglass_time_logs_path(ids: ids), class: 'icon icon-hourglass-join js-hourglass-remote', title: t('hourglass.ui.time_logs.button_join'), remote: true, data: {method: 'post'}, disabled: ids.length == 1 || !@records.all? { |time_log| policy(time_log).join? } && Hourglass::TimeLog.joinable?(*ids) - time_bookings = @records.map(&:time_booking).compact - li = context_menu_link t('hourglass.ui.lists.button_delete_booking'), time_bookings.length == 1 ? hourglass_time_booking_path(time_bookings.first) : bulk_destroy_hourglass_time_bookings_path(time_bookings: time_bookings.map(&:id)), class: 'icon-del js-hourglass-remote', title: t('hourglass.ui.lists.button_delete_booking'), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !time_bookings.present? || !time_bookings.all? { |time_booking| policy(time_booking).destroy? } + li = context_menu_link t('hourglass.ui.lists.button_delete_booking'), time_bookings.length == 1 ? hourglass_time_booking_path(time_bookings.first) : bulk_destroy_hourglass_time_bookings_path(time_bookings: time_bookings.map(&:id)), class: 'icon icon-del js-hourglass-remote', title: t('hourglass.ui.lists.button_delete_booking'), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !time_bookings.present? || !time_bookings.all? { |time_booking| policy(time_booking).destroy? } diff --git a/app/views/hourglass_ui/time_trackers/context_menu.slim b/app/views/hourglass_ui/time_trackers/context_menu.slim index 1bc9fe30..9db28d6f 100644 --- a/app/views/hourglass_ui/time_trackers/context_menu.slim +++ b/app/views/hourglass_ui/time_trackers/context_menu.slim @@ -1,4 +1,4 @@ - ids = @records.map(&:id) ul - li = context_menu_link t(:button_edit), hourglass_ui_bulk_edit_time_trackers_path(ids: ids), class: 'icon-edit js-show-inline-form-multi', title: t(:button_edit), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_tracker| policy(time_tracker).change? } - li = context_menu_link t(:button_delete), @records.length == 1 ? hourglass_time_tracker_path(@records.first) : bulk_destroy_hourglass_time_trackers_path(time_trackers: ids), class: 'icon-del js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !@records.all? { |time_tracker| policy(time_tracker).destroy? } + li = context_menu_link t(:button_edit), hourglass_ui_bulk_edit_time_trackers_path(ids: ids), class: 'icon icon-edit js-show-inline-form-multi', title: t(:button_edit), remote: true, data: {type: 'html'}, disabled: !@records.all? { |time_tracker| policy(time_tracker).change? } + li = context_menu_link t(:button_delete), @records.length == 1 ? hourglass_time_tracker_path(@records.first) : bulk_destroy_hourglass_time_trackers_path(time_trackers: ids), class: 'icon icon-del js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)}, disabled: !@records.all? { |time_tracker| policy(time_tracker).destroy? } diff --git a/config/initializers/autoload.rb b/config/initializers/autoload.rb index 6911ff2f..e73ebf10 100644 --- a/config/initializers/autoload.rb +++ b/config/initializers/autoload.rb @@ -1,8 +1,8 @@ [ - %w(app models concerns), - %w(app controllers concerns), - %w(app policies), - %w(app policies concerns) + %w(app models concerns), + %w(app controllers concerns), + %w(app policies), + %w(app policies concerns) ].each do |path| ActiveSupport::Dependencies.autoload_paths << File.join(Hourglass::PLUGIN_ROOT, *path) end diff --git a/config/initializers/redmine_integration.rb b/config/initializers/redmine_integration.rb index 5033cefc..3bd29dcd 100644 --- a/config/initializers/redmine_integration.rb +++ b/config/initializers/redmine_integration.rb @@ -3,7 +3,11 @@ def add_patch(module_to_patch, method: :include) module_to_patch.send method, patch unless module_to_patch.ancestors.include? patch end -ActionDispatch::Callbacks.to_prepare do +if Rails::VERSION::MAJOR >= 5 + ActiveSupport::Reloader +else + ActionDispatch::Callbacks +end.to_prepare do [Project, TimeEntry, User, ProjectsHelper, SettingsController, UserPreference, TimeEntryActivity].each { |module_to_patch| add_patch module_to_patch } [Query].each { |module_to_patch| add_patch module_to_patch, method: :prepend } diff --git a/db/migrate/1418311263_create_hourglass_time_logs.rb b/db/migrate/1418311263_create_hourglass_time_logs.rb index 870ae6ab..39882bca 100644 --- a/db/migrate/1418311263_create_hourglass_time_logs.rb +++ b/db/migrate/1418311263_create_hourglass_time_logs.rb @@ -1,4 +1,6 @@ -class CreateHourglassTimeLogs < ActiveRecord::Migration +require 'hourglass/hourglass_migration' + +class CreateHourglassTimeLogs < HourglassMigration def change create_table :hourglass_time_logs do |t| t.datetime :start, null: false diff --git a/db/migrate/1418311331_create_hourglass_time_bookings.rb b/db/migrate/1418311331_create_hourglass_time_bookings.rb index dd57d69d..ba7a5d58 100644 --- a/db/migrate/1418311331_create_hourglass_time_bookings.rb +++ b/db/migrate/1418311331_create_hourglass_time_bookings.rb @@ -1,4 +1,6 @@ -class CreateHourglassTimeBookings < ActiveRecord::Migration +require 'hourglass/hourglass_migration' + +class CreateHourglassTimeBookings < HourglassMigration def change create_table :hourglass_time_bookings do |t| t.datetime :start, null: false diff --git a/db/migrate/1418914331_create_hourglass_time_trackers.rb b/db/migrate/1418914331_create_hourglass_time_trackers.rb index a81b3326..522a9d4d 100644 --- a/db/migrate/1418914331_create_hourglass_time_trackers.rb +++ b/db/migrate/1418914331_create_hourglass_time_trackers.rb @@ -1,4 +1,6 @@ -class CreateHourglassTimeTrackers < ActiveRecord::Migration +require 'hourglass/hourglass_migration' + +class CreateHourglassTimeTrackers < HourglassMigration def change create_table :hourglass_time_trackers do |t| t.datetime :start, null: false diff --git a/db/migrate/20190307074023_change_hourglass_time_log_comments_limit.rb b/db/migrate/20190307074023_change_hourglass_time_log_comments_limit.rb index dfe65687..e61427b9 100644 --- a/db/migrate/20190307074023_change_hourglass_time_log_comments_limit.rb +++ b/db/migrate/20190307074023_change_hourglass_time_log_comments_limit.rb @@ -1,4 +1,6 @@ -class ChangeHourglassTimeLogCommentsLimit < ActiveRecord::Migration +require 'hourglass/hourglass_migration' + +class ChangeHourglassTimeLogCommentsLimit < HourglassMigration def up change_column :hourglass_time_logs, :comments, :string, limit: 1024 end diff --git a/lib/hourglass/hourglass_migration.rb b/lib/hourglass/hourglass_migration.rb new file mode 100644 index 00000000..6d6d0ba1 --- /dev/null +++ b/lib/hourglass/hourglass_migration.rb @@ -0,0 +1,2 @@ +class HourglassMigration < (Rails::VERSION::MAJOR <= 4 ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]) +end diff --git a/lib/hourglass/redmine_patches/projects_helper_patch.rb b/lib/hourglass/redmine_patches/projects_helper_patch.rb index 75c8dbb8..7b12b579 100644 --- a/lib/hourglass/redmine_patches/projects_helper_patch.rb +++ b/lib/hourglass/redmine_patches/projects_helper_patch.rb @@ -4,7 +4,8 @@ module ProjectsHelperPatch extend ActiveSupport::Concern included do - alias_method_chain :project_settings_tabs, :hourglass + alias_method :project_settings_tabs_without_hourglass, :project_settings_tabs + alias_method :project_settings_tabs, :project_settings_tabs_with_hourglass end def project_settings_tabs_with_hourglass diff --git a/lib/hourglass/redmine_patches/settings_controller_patch.rb b/lib/hourglass/redmine_patches/settings_controller_patch.rb index e38da7e6..7495fec0 100644 --- a/lib/hourglass/redmine_patches/settings_controller_patch.rb +++ b/lib/hourglass/redmine_patches/settings_controller_patch.rb @@ -4,7 +4,8 @@ module SettingsControllerPatch extend ActiveSupport::Concern included do - alias_method_chain :plugin, :hourglass + alias_method :plugin_without_hourglass, :plugin + alias_method :plugin, :plugin_with_hourglass end def plugin_with_hourglass diff --git a/spec/integration/time_bookings_spec.rb b/spec/integration/time_bookings_spec.rb index 8d7cc855..c773d2a2 100644 --- a/spec/integration/time_bookings_spec.rb +++ b/spec/integration/time_bookings_spec.rb @@ -90,7 +90,7 @@ tags 'Time bookings' parameter name: :id, in: :path, type: :string parameter name: :time_booking, in: :body, schema: { - '$ref' => '#/definitions/time_booking_params' + '$ref' => '#/definitions/time_booking_params' } let(:user) { create :user, :as_member, permissions: [:hourglass_edit_booked_time, :hourglass_view_booked_time] } @@ -98,7 +98,7 @@ time_booking = create :time_booking, project: user.projects.first, user: user time_booking.id end - let(:time_booking) { {time_booking: {comments: 'test2'}} } + let(:time_booking) { { time_booking: { comments: 'test2' } } } include_examples 'access rights', :hourglass_book_time, :hourglass_book_own_time, :hourglass_edit_booked_time, :hourglass_edit_own_booked_time, success_code: '204' @@ -107,7 +107,7 @@ let(:time_booking) do project = create :project create :member, project: project, user: user, permissions: [:hourglass_edit_booked_time, :hourglass_view_booked_time] - {time_booking: {project_id: project.id}} + { time_booking: { project_id: project.id } } end response '204', 'time booking found' do run_test! @@ -123,7 +123,7 @@ path '/time_bookings/bulk_destroy.json' do delete 'Deletes multiple time bookings at once' do tags 'Time bookings' - parameter name: :'time_bookings[]', in: :query, type: :array, items: {type: :string}, collectionFormat: :multi + parameter name: :'time_bookings[]', in: :query, type: :array, items: { type: :string }, collectionFormat: :multi let(:user) { create :user, :as_member, permissions: [:hourglass_edit_booked_time, :hourglass_view_booked_time] } let(:time_booking_ids) do @@ -147,7 +147,7 @@ consumes 'application/json' produces 'application/json' tags 'Time bookings' - parameter name: :time_bookings, in: :body, schema: {type: :object, additionalProperties: {'$ref' => '#/definitions/time_booking'}}, description: 'takes an object of time bookings' + parameter name: :time_bookings, in: :body, schema: { type: :object, additionalProperties: { '$ref' => '#/definitions/time_booking' } }, description: 'takes an object of time bookings' let(:user) { create :user, :as_member, permissions: [:hourglass_edit_booked_time, :hourglass_view_booked_time] } let(:time_booking_ids) do @@ -156,7 +156,7 @@ [tt1.id, tt2.id] end - let(:time_bookings) { {time_bookings: {time_booking_ids[0] => {comments: 'test3'}, time_booking_ids[1] => {comments: 'test4'}}} } + let(:time_bookings) { { time_bookings: { time_booking_ids[0] => { comments: 'test3' }, time_booking_ids[1] => { comments: 'test4' } } } } include_examples 'access rights', :hourglass_book_time, :hourglass_book_own_time, :hourglass_edit_booked_time, :hourglass_edit_own_booked_time @@ -176,17 +176,17 @@ consumes 'application/json' produces 'application/json' tags 'Time bookings' - parameter name: :time_bookings, in: :body, schema: {type: :array, items: {'$ref' => '#/definitions/time_booking'}}, description: 'takes an array of time bookings' + parameter name: :time_bookings, in: :body, schema: { type: :array, items: { '$ref' => '#/definitions/time_booking' } }, description: 'takes an array of time bookings' let(:user) { create :user, :as_member, permissions: [:hourglass_edit_booked_time] } let(:time_bookings) do { - time_bookings: [ - {user_id: user.id, project_id: user.projects.first.id, activity_id: create(:time_entry_activity).id, - start: Faker::Time.between(Date.today, Date.today, :morning), - stop: Faker::Time.between(Date.today, Date.today, :afternoon)} - ] + time_bookings: [ + { user_id: user.id, project_id: user.projects.first.id, activity_id: create(:time_entry_activity).id, + start: Faker::Time.between(Date.today, Date.today, :morning), + stop: Faker::Time.between(Date.today, Date.today, :afternoon) } + ] } end @@ -197,17 +197,17 @@ activity = create :time_entry_activity project = user.projects.first { - time_bookings: [ - {user_id: user.id, project_id: project.id, activity_id: activity.id, - start: Faker::Time.between(Date.today, Date.today, :morning), - stop: Faker::Time.between(Date.today, Date.today, :afternoon)}, - {user_id: create(:user).id, project_id: project.id, activity_id: activity.id, - start: Faker::Time.between(Date.today, Date.today, :morning), - stop: Faker::Time.between(Date.today, Date.today, :afternoon)}, - {user_id: create(:user).id, project_id: project.id, activity_id: activity.id, - start: Faker::Time.between(Date.today, Date.today, :morning), - stop: Faker::Time.between(Date.today, Date.today, :afternoon)} - ] + time_bookings: [ + { user_id: user.id, project_id: project.id, activity_id: activity.id, + start: Faker::Time.between(Date.today, Date.today, :morning), + stop: Faker::Time.between(Date.today, Date.today, :afternoon) }, + { user_id: create(:user).id, project_id: project.id, activity_id: activity.id, + start: Faker::Time.between(Date.today, Date.today, :morning), + stop: Faker::Time.between(Date.today, Date.today, :afternoon) }, + { user_id: create(:user).id, project_id: project.id, activity_id: activity.id, + start: Faker::Time.between(Date.today, Date.today, :morning), + stop: Faker::Time.between(Date.today, Date.today, :afternoon) } + ] } end run_test! diff --git a/spec/integration/time_logs_spec.rb b/spec/integration/time_logs_spec.rb index ed14dfe8..ebb66ed3 100644 --- a/spec/integration/time_logs_spec.rb +++ b/spec/integration/time_logs_spec.rb @@ -89,19 +89,19 @@ tags 'Time logs' parameter name: :id, in: :path, type: :string parameter name: :time_log, in: :body, schema: { - '$ref' => '#/definitions/time_log_update' + '$ref' => '#/definitions/time_log_update' } let(:user) { create :user, :as_member, permissions: [:hourglass_edit_tracked_time] } let(:existing_time_log) { create :time_log, user: user } let(:id) { existing_time_log.id } - let(:time_log) { {time_log: {comments: 'test2'}} } + let(:time_log) { { time_log: { comments: 'test2' } } } include_examples 'access rights', :hourglass_track_time, :hourglass_edit_tracked_time, :hourglass_edit_own_tracked_time, success_code: '204' include_examples 'not found' context do - let(:time_log) { {time_log: {stop: existing_time_log.stop + 1.hour}} } + let(:time_log) { { time_log: { stop: existing_time_log.stop + 1.hour } } } response '204', 'time log found' do run_test! @@ -120,15 +120,15 @@ tags 'Time logs' parameter name: :id, in: :path, type: :string parameter name: :time_booking, in: :body, schema: { - '$ref' => '#/definitions/time_booking_params' + '$ref' => '#/definitions/time_booking_params' } let(:user) { create :user, :as_member, permissions: [:hourglass_book_time] } let(:time_log) { create :time_log, user: user } let(:id) { time_log.id } - let(:time_booking) { {time_booking: { - project_id: user.projects.first.id, activity_id: create(:time_entry_activity).id - }} } + let(:time_booking) { { time_booking: { + project_id: user.projects.first.id, activity_id: create(:time_entry_activity).id + } } } include_examples 'access rights', :hourglass_book_time, :hourglass_book_own_time include_examples 'not found' @@ -169,14 +169,14 @@ response '200', 'time log found' do schema type: 'object', properties: { - time_log: { - '$ref' => '#/definitions/time_log', - required: %w(id start stop user_id created_at updated_at) - }, - new_time_log: { - '$ref' => '#/definitions/time_log', - required: %w(id start stop user_id created_at updated_at) - } + time_log: { + '$ref' => '#/definitions/time_log', + required: %w(id start stop user_id created_at updated_at) + }, + new_time_log: { + '$ref' => '#/definitions/time_log', + required: %w(id start stop user_id created_at updated_at) + } } include_examples 'has a valid response' @@ -195,7 +195,7 @@ post 'Joins multiple time logs' do produces 'application/json' tags 'Time logs' - parameter name: :'ids[]', in: :query, type: :array, items: {type: :integer}, collectionFormat: :multi + parameter name: :'ids[]', in: :query, type: :array, items: { type: :integer }, collectionFormat: :multi let(:user) { create :user, :as_member, permissions: [:hourglass_track_time] } let(:time_log) { create :time_log, user: user } @@ -211,10 +211,10 @@ response '200', 'time logs found' do schema type: 'object', properties: { - time_log: { - '$ref' => '#/definitions/time_log', - required: %w(id start stop user_id created_at updated_at) - } + time_log: { + '$ref' => '#/definitions/time_log', + required: %w(id start stop user_id created_at updated_at) + } } include_examples 'has a valid response' @@ -236,7 +236,7 @@ path '/time_logs/bulk_destroy.json' do delete 'Deletes multiple time logs at once' do tags 'Time logs' - parameter name: :'time_logs[]', in: :query, type: :array, items: {type: :string}, collectionFormat: :multi + parameter name: :'time_logs[]', in: :query, type: :array, items: { type: :string }, collectionFormat: :multi let(:user) { create :user, :as_member, permissions: [:hourglass_edit_tracked_time] } let(:time_log_ids) do @@ -260,7 +260,7 @@ consumes 'application/json' produces 'application/json' tags 'Time logs' - parameter name: :time_logs, in: :body, schema: {type: :object, additionalProperties: {'$ref' => '#/definitions/time_log'}}, description: 'takes an object of time logs' + parameter name: :time_logs, in: :body, schema: { type: :object, additionalProperties: { '$ref' => '#/definitions/time_log' } }, description: 'takes an object of time logs' let(:user) { create :user, :as_member, permissions: [:hourglass_edit_tracked_time, :hourglass_view_tracked_time] } let(:time_log_ids) do @@ -269,7 +269,7 @@ [tt1.id, tt2.id] end - let(:time_logs) { {time_logs: {time_log_ids[0] => {comments: 'test3'}, time_log_ids[1] => {comments: 'test4'}}} } + let(:time_logs) { { time_logs: { time_log_ids[0] => { comments: 'test3' }, time_log_ids[1] => { comments: 'test4' } } } } include_examples 'access rights', :hourglass_track_time, :hourglass_edit_tracked_time, :hourglass_edit_own_tracked_time @@ -289,7 +289,7 @@ consumes 'application/json' produces 'application/json' tags 'Time logs' - parameter name: :time_bookings, in: :body, schema: {type: :object, additionalProperties: {'$ref' => '#/definitions/time_booking'}}, description: 'takes an object of time bookings' + parameter name: :time_bookings, in: :body, schema: { type: :object, additionalProperties: { '$ref' => '#/definitions/time_booking' } }, description: 'takes an object of time bookings' let(:user) { create :user, :as_member, permissions: [:hourglass_book_time, :hourglass_view_tracked_time] } let(:time_logs) do @@ -300,9 +300,9 @@ let(:time_bookings) do tl1, tl2 = time_logs - {time_bookings: { - tl1.id => {project_id: tl1.user.projects.first.id, activity_id: create(:time_entry_activity).id}, - tl2.id => {} + { time_bookings: { + tl1.id => { project_id: tl1.user.projects.first.id, activity_id: create(:time_entry_activity).id }, + tl2.id => {} } } end @@ -324,15 +324,15 @@ consumes 'application/json' produces 'application/json' tags 'Time logs' - parameter name: :time_logs, in: :body, schema: {type: :array, items: {'$ref' => '#/definitions/time_log'}}, description: 'takes an array of time logs' + parameter name: :time_logs, in: :body, schema: { type: :array, items: { '$ref' => '#/definitions/time_log' } }, description: 'takes an array of time logs' let(:user) { create :user, :as_member, permissions: [:hourglass_edit_tracked_time] } let(:time_logs) do - {time_logs: [ - build(:time_log, user: user), - build(:time_log), - build(:time_log) + { time_logs: [ + build(:time_log, user: user), + build(:time_log), + build(:time_log) ] } end