From 6f6391ff0baa3edde88cff1b6d3d743e77683d4d Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Thu, 2 Jun 2022 16:59:40 +0200 Subject: [PATCH 01/20] basic Redimne 5 support * upgraded gems * fixed asset links in dev mode * fixed Proc.new (Ruby 3 issue) --- Gemfile | 12 ++++++------ app/helpers/hourglass/list_helper.rb | 6 +++--- app/models/hourglass/time_booking.rb | 2 +- config/initializers/assets.rb | 1 + config/initializers/autoload.rb | 2 +- init.rb | 5 ++--- lib/hourglass/assets.rb | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/Gemfile b/Gemfile index 6ab33621..666f14b0 100644 --- a/Gemfile +++ b/Gemfile @@ -11,23 +11,23 @@ gem 'pundit', '~> 1.1.0' # this is useful for unix based systems which don't have a js runtime installed # if you are on windows and this makes problems, simply remove the line -gem 'therubyracer', :platform => :ruby +# gem 'therubyracer', :platform => :ruby # views gem 'slim', '~> 3.0.8' -gem 'js-routes', '~> 1.3' +gem 'js-routes', '~> 2.2.4' gem 'momentjs-rails', '>= 2.10.7' -gem 'rswag', '<2.0' # api docs +gem 'rswag', '~> 2.5.1' # api docs gem 'rspec-core' gem 'rqrcode' unless dependencies.any? { |d| d.name == 'rqrcode' } group :development, :test do - gem 'rspec-rails', '~> 3.5', '>= 3.5.2' - gem 'factory_bot_rails', '< 5.0' + gem 'rspec-rails', '~> 5.1.2' + gem 'factory_bot_rails' gem 'zonebie' gem 'database_cleaner' - gem 'faker', '~> 2.15', '>= 2.15.1' + gem 'faker' end if RUBY_VERSION < "2.1" diff --git a/app/helpers/hourglass/list_helper.rb b/app/helpers/hourglass/list_helper.rb index 8fe3b1e2..3889e3d0 100644 --- a/app/helpers/hourglass/list_helper.rb +++ b/app/helpers/hourglass/list_helper.rb @@ -14,8 +14,8 @@ def column_header(_query, column, options={}) end end - def grouped_entry_list(entries, query) - return entry_list entries, &Proc.new unless query.grouped? + def grouped_entry_list(entries, query, &block) + return entry_list entries, &block unless query.grouped? totals_by_group = query.totals_by_group count_by_group = query.count_by_group @@ -25,7 +25,7 @@ def grouped_entry_list(entries, query) totals: transform_totals(extract_group_value(group, totals_by_group)), count: extract_group_value(group, count_by_group) } - entry_list group_entries, &Proc.new + entry_list group_entries, &block end end diff --git a/app/models/hourglass/time_booking.rb b/app/models/hourglass/time_booking.rb index fed4fa7c..282e63b8 100644 --- a/app/models/hourglass/time_booking.rb +++ b/app/models/hourglass/time_booking.rb @@ -73,7 +73,7 @@ def fix_nil_hours def filter_time_entry_invalid_error self.errors.delete(:time_entry) - self.errors.messages.transform_keys! {|k| k == :'time_entry.base' ? :base : k} + # self.errors.messages.transform_keys! {|k| k == :'time_entry.base' ? :base : k} end def stop_is_valid diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index a7bf161f..8430eda3 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -2,6 +2,7 @@ config.include = [ /#{Hourglass::NAMESPACE}/ ] + config.module_type = nil config.compact = true config.namespace = "#{Hourglass::NAMESPACE}Routes" end diff --git a/config/initializers/autoload.rb b/config/initializers/autoload.rb index 80128cbc..27c683a0 100644 --- a/config/initializers/autoload.rb +++ b/config/initializers/autoload.rb @@ -7,6 +7,6 @@ if Rails.version >= "5" and Rails.configuration.eager_load Dir.glob(File.join(Hourglass::PLUGIN_ROOT, *path, "**/*.rb")).sort.each(&method(:require)) else - ActiveSupport::Dependencies.autoload_paths << File.join(Hourglass::PLUGIN_ROOT, *path) + Rails.autoloaders.main.push_dir File.join(Hourglass::PLUGIN_ROOT, *path) end end diff --git a/init.rb b/init.rb index afde0253..8eea0ac5 100644 --- a/init.rb +++ b/init.rb @@ -1,5 +1,3 @@ -require 'hourglass' - Redmine::Plugin.register Hourglass::PLUGIN_NAME do name 'Hourglass' description 'Track your time and book it on issues and projects' @@ -8,7 +6,7 @@ author_url 'http://www.hicknhack-software.com' version Hourglass::VERSION - requires_redmine version_or_higher: '3.2.0' + requires_redmine version_or_higher: '5.0.0' settings default: Hourglass::SettingsStorage.defaults, :partial => "settings/#{Hourglass::PLUGIN_NAME}" @@ -95,3 +93,4 @@ def allowed_to_see_index? menu.push :hourglass_time_trackers, :hourglass_ui_time_trackers_path, caption: :'hourglass.ui.menu.time_trackers', if: proc { Pundit.policy!(User.current, Hourglass::TimeTracker).view? } end end +ActiveSupport::Reloader.reload! diff --git a/lib/hourglass/assets.rb b/lib/hourglass/assets.rb index e7b2116b..14a261d6 100644 --- a/lib/hourglass/assets.rb +++ b/lib/hourglass/assets.rb @@ -60,7 +60,7 @@ def asset_directory_map def path(path, options = {}) if options[:type].present? - File.join '..', Rails.env.production? ? instance.find_asset(path).digest_path : File.join(asset_directory_map[options[:type]] || '', path) + Rails.env.production? ? instance.find_asset(path).digest_path : File.join('/', assets_directory_path, asset_directory_map[options[:type]] || '', path) else path end From d7eeb1cca88e6d881df5b54299a69f161b3a69a9 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 01:51:37 +0100 Subject: [PATCH 02/20] add lib to load_path --- init.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/init.rb b/init.rb index 8eea0ac5..1c5d4d63 100644 --- a/init.rb +++ b/init.rb @@ -1,3 +1,5 @@ +$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/lib" + Redmine::Plugin.register Hourglass::PLUGIN_NAME do name 'Hourglass' description 'Track your time and book it on issues and projects' From 0e6d311aefc3c58ce260c04cf4582095b813eef1 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 01:52:01 +0100 Subject: [PATCH 03/20] make hourglass_migration zeitwerk compatible --- db/migrate/1418311263_create_hourglass_time_logs.rb | 4 +--- db/migrate/1418311331_create_hourglass_time_bookings.rb | 4 +--- db/migrate/1418914331_create_hourglass_time_trackers.rb | 4 +--- ...20190307074023_change_hourglass_time_log_comments_limit.rb | 4 +--- lib/hourglass/hourglass_migration.rb | 2 -- lib/hourglass/migration.rb | 4 ++++ 6 files changed, 8 insertions(+), 14 deletions(-) delete mode 100644 lib/hourglass/hourglass_migration.rb create mode 100644 lib/hourglass/migration.rb diff --git a/db/migrate/1418311263_create_hourglass_time_logs.rb b/db/migrate/1418311263_create_hourglass_time_logs.rb index 39882bca..88bf2ae9 100644 --- a/db/migrate/1418311263_create_hourglass_time_logs.rb +++ b/db/migrate/1418311263_create_hourglass_time_logs.rb @@ -1,6 +1,4 @@ -require 'hourglass/hourglass_migration' - -class CreateHourglassTimeLogs < HourglassMigration +class CreateHourglassTimeLogs < Hourglass::Migration 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 ba7a5d58..deb19ce3 100644 --- a/db/migrate/1418311331_create_hourglass_time_bookings.rb +++ b/db/migrate/1418311331_create_hourglass_time_bookings.rb @@ -1,6 +1,4 @@ -require 'hourglass/hourglass_migration' - -class CreateHourglassTimeBookings < HourglassMigration +class CreateHourglassTimeBookings < Hourglass::Migration 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 522a9d4d..3f0dc662 100644 --- a/db/migrate/1418914331_create_hourglass_time_trackers.rb +++ b/db/migrate/1418914331_create_hourglass_time_trackers.rb @@ -1,6 +1,4 @@ -require 'hourglass/hourglass_migration' - -class CreateHourglassTimeTrackers < HourglassMigration +class CreateHourglassTimeTrackers < Hourglass::Migration 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 e61427b9..8ae0a76d 100644 --- a/db/migrate/20190307074023_change_hourglass_time_log_comments_limit.rb +++ b/db/migrate/20190307074023_change_hourglass_time_log_comments_limit.rb @@ -1,6 +1,4 @@ -require 'hourglass/hourglass_migration' - -class ChangeHourglassTimeLogCommentsLimit < HourglassMigration +class ChangeHourglassTimeLogCommentsLimit < Hourglass::Migration 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 deleted file mode 100644 index 6d6d0ba1..00000000 --- a/lib/hourglass/hourglass_migration.rb +++ /dev/null @@ -1,2 +0,0 @@ -class HourglassMigration < (Rails::VERSION::MAJOR <= 4 ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]) -end diff --git a/lib/hourglass/migration.rb b/lib/hourglass/migration.rb new file mode 100644 index 00000000..404d4dea --- /dev/null +++ b/lib/hourglass/migration.rb @@ -0,0 +1,4 @@ +module Hourglass + class Migration < (Rails::VERSION::MAJOR <= 4 ? ActiveRecord::Migration : ActiveRecord::Migration[4.2]) + end +end From 09ba55ef198fa64f76185c048e7fb9922a252c8c Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 01:52:20 +0100 Subject: [PATCH 04/20] no longer set data nil --- app/views/hourglass_ui/_time_tracker_control.slim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/hourglass_ui/_time_tracker_control.slim b/app/views/hourglass_ui/_time_tracker_control.slim index 082257f2..079f1c72 100644 --- a/app/views/hourglass_ui/_time_tracker_control.slim +++ b/app/views/hourglass_ui/_time_tracker_control.slim @@ -31,8 +31,8 @@ = form_field :start, f, @time_tracker, disabled: !policy(@time_tracker).change?(:start) .form-field .input - = f.submit t('hourglass.ui.index.time_tracker_control.button_stop'), data: @time_tracker.clamp? ? {confirm: t('hourglass.ui.forms.confirmations.stop_clamping', 'duration': localized_hours_in_units(Hourglass::DateTimeCalculations.in_hours(Hourglass::DateTimeCalculations.clamp_limit(project: @time_tracker.project))))} : nil - = f.submit t('hourglass.ui.index.time_tracker_control.button_stop_new'), class: 'js-stop-new', data: @time_tracker.clamp? ? {confirm: t('hourglass.ui.forms.confirmations.stop_clamping', 'duration': localized_hours_in_units(Hourglass::DateTimeCalculations.in_hours(Hourglass::DateTimeCalculations.clamp_limit(project: @time_tracker.project))))} : nil + = f.submit t('hourglass.ui.index.time_tracker_control.button_stop'), data: @time_tracker.clamp? ? {confirm: t('hourglass.ui.forms.confirmations.stop_clamping', 'duration': localized_hours_in_units(Hourglass::DateTimeCalculations.in_hours(Hourglass::DateTimeCalculations.clamp_limit(project: @time_tracker.project))))} : {} + = f.submit t('hourglass.ui.index.time_tracker_control.button_stop_new'), class: 'js-stop-new', data: @time_tracker.clamp? ? {confirm: t('hourglass.ui.forms.confirmations.stop_clamping', 'duration': localized_hours_in_units(Hourglass::DateTimeCalculations.in_hours(Hourglass::DateTimeCalculations.clamp_limit(project: @time_tracker.project))))} : {} - if policy(@time_tracker).destroy? = link_to hourglass_time_tracker_path(@time_tracker), class: 'js-hourglass-remote', title: t(:button_delete), remote: true, method: :delete, data: {confirm: t(:text_are_you_sure)} do input type='button' value=t(:button_delete) From c26f767effcc8be5410897c17b9848faa191fd26 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 01:52:36 +0100 Subject: [PATCH 05/20] add postgres devcontainer --- .devcontainer/postgres/Dockerfile | 12 +++++ .devcontainer/postgres/Gemfile.local | 14 ++++++ .devcontainer/postgres/database.yml | 13 +++++ .devcontainer/postgres/devcontainer.json | 58 +++++++++++++++++++++++ .devcontainer/postgres/docker-compose.yml | 42 ++++++++++++++++ .devcontainer/postgres/post-create.sh | 26 ++++++++++ 6 files changed, 165 insertions(+) create mode 100644 .devcontainer/postgres/Dockerfile create mode 100644 .devcontainer/postgres/Gemfile.local create mode 100644 .devcontainer/postgres/database.yml create mode 100644 .devcontainer/postgres/devcontainer.json create mode 100644 .devcontainer/postgres/docker-compose.yml create mode 100755 .devcontainer/postgres/post-create.sh diff --git a/.devcontainer/postgres/Dockerfile b/.devcontainer/postgres/Dockerfile new file mode 100644 index 00000000..14d71b4b --- /dev/null +++ b/.devcontainer/postgres/Dockerfile @@ -0,0 +1,12 @@ +ARG RUBY_VERSION=3.1 +ARG REDMINE_VERSION=5-stable + +FROM alpinelab/ruby-dev:${RUBY_VERSION} AS redmine +ARG REDMINE_VERSION +ENV REDMINE_VERSION=${REDMINE_VERSION} + +RUN \ + cd / \ + && mv /app /redmine \ + && chmod ugo+w /redmine +WORKDIR /redmine diff --git a/.devcontainer/postgres/Gemfile.local b/.devcontainer/postgres/Gemfile.local new file mode 100644 index 00000000..e46bb476 --- /dev/null +++ b/.devcontainer/postgres/Gemfile.local @@ -0,0 +1,14 @@ +group :development do + # gem 'better_errors' + # gem 'binding_of_caller' + # gem 'meta_request' # support RailsPanel in Chrome + # + # gem 'pry' + # gem 'pry-byebug' + # gem 'pry-rails' + + # gem "debase", "0.2.5.beta2", require: false + # gem "ruby-debug-ide", "~> 0.7.3" + gem "debug" + gem 'rufo', require: false +end diff --git a/.devcontainer/postgres/database.yml b/.devcontainer/postgres/database.yml new file mode 100644 index 00000000..b46e483d --- /dev/null +++ b/.devcontainer/postgres/database.yml @@ -0,0 +1,13 @@ + +development: &postgres + adapter: postgresql + encoding: utf8 + database: redmine + username: postgres + password: postgres + host: postgres + port: 5432 + +test: + <<: *postgres + database: redmine_test diff --git a/.devcontainer/postgres/devcontainer.json b/.devcontainer/postgres/devcontainer.json new file mode 100644 index 00000000..893d973c --- /dev/null +++ b/.devcontainer/postgres/devcontainer.json @@ -0,0 +1,58 @@ +{ + "name": "Redmine - Postgres", + "dockerComposeFile": "docker-compose.yml", + "service": "redmine", + "workspaceFolder": "/redmine", + "features": { + "ghcr.io/devcontainers/features/common-utils:2": { + "username": "vscode", + "userUid": "1000", + "userGid": "1000" + }, + "ghcr.io/devcontainers/features/ruby:1": "none", + "ghcr.io/devcontainers/features/node:1": "none", + "ghcr.io/devcontainers/features/git:1": { + "version": "latest", + "ppa": "false" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "rebornix.Ruby", + "mtxr.sqltools", + "mtxr.sqltools-driver-pg", + "craigmaslowski.erb", + "hridoy.rails-snippets", + "misogi.ruby-rubocop", + "jnbt.vscode-rufo", + "donjayamanne.git-extension-pack" + ], + "settings": { + "sqltools.connections": [ + { + "name": "Rails Development Database", + "driver": "PostgreSQL", + "previewLimit": 50, + "server": "localhost", + "port": 5432, + "database": "redmine", + "username": "postgres" + }, + { + "name": "Rails Test Database", + "driver": "PostgreSQL", + "previewLimit": 50, + "server": "localhost", + "port": 5432, + "database": "redmine_test", + "username": "postgres" + } + ] + } + } + }, + "forwardPorts": [ 5000 ], + "postCreateCommand": "sh -x /redmine/post-create.sh", + "remoteUser": "vscode" +} diff --git a/.devcontainer/postgres/docker-compose.yml b/.devcontainer/postgres/docker-compose.yml new file mode 100644 index 00000000..9628cca0 --- /dev/null +++ b/.devcontainer/postgres/docker-compose.yml @@ -0,0 +1,42 @@ +version: '3.7' + +services: + redmine: + build: + context: . + target: redmine + args: + RUBY_VERSION: "3.1.3" + REDMINE_VERSION: "5.0-stable" + NODE_VERSION: "lts/*" + volumes: + - redmine-data:/redmine/files + - node_modules:/redmine/node_modules + - bundle:/bundle + - ../..:/redmine/plugins/redmine_hourglass + - ./Gemfile.local:/redmine/Gemfile.local + - ./database.yml:/redmine/config/database.yml + - ./post-create.sh:/redmine/post-create.sh + environment: + RAILS_ENV: development + REDMINE_SECRET_KEY_BASE: supersecretkey + REDMINE_PLUGINS_MIGRATE: 'true' + command: sleep infinity + depends_on: + - postgres + + postgres: + image: postgres:latest + restart: unless-stopped + volumes: + - postgres-data:/var/lib/postgresql/data + environment: + POSTGRES_DB: redmine + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + +volumes: + postgres-data: null + redmine-data: + node_modules: + bundle: diff --git a/.devcontainer/postgres/post-create.sh b/.devcontainer/postgres/post-create.sh new file mode 100755 index 00000000..c5cf960c --- /dev/null +++ b/.devcontainer/postgres/post-create.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +. ${NVM_DIR}/nvm.sh +nvm install --lts + +sudo chown -R vscode:vscode . +sudo chmod ugo+w /bundle + +git config --global --add safe.directory /redmine +git init +git remote add origin https://github.com/redmine/redmine.git +git fetch +git checkout -t origin/${REDMINE_VERSION} -f + +bundle + +bundle exec rake db:create +bundle exec rake db:migrate +bundle exec rake redmine:plugins:migrate +bundle exec rake redmine:plugins + +# bundle exec rake db:drop RAILS_ENV=test +# bundle exec rake db:create RAILS_ENV=test +# bundle exec rake db:migrate RAILS_ENV=test +# bundle exec rake redmine:plugins:migrate RAILS_ENV=test From 8ae3d61d1ffca70005faa08bdfb718ecffaa0f86 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 02:13:05 +0100 Subject: [PATCH 06/20] support Redmine 4 autoload --- config/initializers/autoload.rb | 4 +++- init.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/initializers/autoload.rb b/config/initializers/autoload.rb index 27c683a0..070e98ca 100644 --- a/config/initializers/autoload.rb +++ b/config/initializers/autoload.rb @@ -6,7 +6,9 @@ ].each do |path| if Rails.version >= "5" and Rails.configuration.eager_load Dir.glob(File.join(Hourglass::PLUGIN_ROOT, *path, "**/*.rb")).sort.each(&method(:require)) - else + elsif Rails.version >= "6" Rails.autoloaders.main.push_dir File.join(Hourglass::PLUGIN_ROOT, *path) + else + ActiveSupport::Dependencies.autoload_paths << File.join(Hourglass::PLUGIN_ROOT, *path) end end diff --git a/init.rb b/init.rb index 1c5d4d63..b184ace6 100644 --- a/init.rb +++ b/init.rb @@ -8,7 +8,7 @@ author_url 'http://www.hicknhack-software.com' version Hourglass::VERSION - requires_redmine version_or_higher: '5.0.0' + requires_redmine version_or_higher: '4.0.0' settings default: Hourglass::SettingsStorage.defaults, :partial => "settings/#{Hourglass::PLUGIN_NAME}" From 8e0438c2a404bf85600cf80f62c10a993e78f831 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 04:11:28 +0100 Subject: [PATCH 07/20] simplified swagger model definitions --- spec/support/model_definitions.yml | 291 +++++++++++++++-------------- spec/swagger_helper.rb | 2 +- 2 files changed, 156 insertions(+), 137 deletions(-) diff --git a/spec/support/model_definitions.yml b/spec/support/model_definitions.yml index c6acb602..50e15320 100644 --- a/spec/support/model_definitions.yml +++ b/spec/support/model_definitions.yml @@ -1,140 +1,159 @@ -support: - date_time: &date_time - type: string - format: date-time - id: &id - type: integer - minimum: 0 - attributes: - ids: - activity: &activity_id - <<: *id - project: &project_id - <<: *id - user: &user_id - <<: *id - issue: &issue_id - <<: *id - default: &default +time_tracker_start: + title: Time tracker + type: object + properties: + issue_id: + type: integer + minimum: 0 + comments: + type: string +time_tracker: + title: Time tracker + type: object + properties: id: - <<: *id + type: integer + minimum: 0 created_at: - <<: *date_time + type: string + format: date-time updated_at: - <<: *date_time + type: string + format: date-time user_id: - <<: *user_id - -definitions: - time_tracker_start: - title: Time tracker - type: object - properties: - issue_id: - <<: *issue_id - comments: - type: string - time_tracker: - title: Time tracker - type: object - properties: - <<: *default - start: - <<: *date_time - project_id: - <<: *project_id - activity_id: - <<: *activity_id - issue_id: - <<: *issue_id - comments: - type: string - time_tracker_update: - title: Time tracker - type: object - properties: - start: - <<: *date_time - user_id: - <<: *user_id - project_id: - <<: *project_id - activity_id: - <<: *activity_id - issue_id: - <<: *issue_id - comments: - type: string - time_log: - title: Time log - type: object - properties: - <<: *default - start: - <<: *date_time - stop: - <<: *date_time - comments: - type: string - time_log_update: - title: Time log - type: object - properties: - start: - <<: *date_time - stop: - <<: *date_time - comments: - type: string - time_booking: - title: Time booking - type: object - properties: - id: - <<: *id - created_at: - <<: *date_time - updated_at: - <<: *date_time - start: - <<: *date_time - stop: - <<: *date_time - time_booking_params: - title: Time booking - type: object - properties: - start: - <<: *date_time - stop: - <<: *date_time - user_id: - <<: *user_id - project_id: - <<: *project_id - activity_id: - <<: *activity_id - issue_id: - <<: *issue_id - comments: - type: string - error_msg: - title: Error - type: object - properties: - message: - type: string - index_response: - title: Records - type: object - properties: - count: - type: integer - offset: - type: integer - limit: - type: integer - records: - type: array - items: - type: object + type: integer + minimum: 0 + start: + type: string + format: date-time + project_id: + type: integer + minimum: 0 + activity_id: + type: integer + minimum: 0 + issue_id: + type: integer + minimum: 0 + comments: + type: string +time_tracker_update: + title: Time tracker + type: object + properties: + start: + type: string + format: date-time + user_id: + type: integer + minimum: 0 + project_id: + type: integer + minimum: 0 + activity_id: + type: integer + minimum: 0 + issue_id: + type: integer + minimum: 0 + comments: + type: string +time_log: + title: Time log + type: object + properties: + id: + type: integer + minimum: 0 + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + user_id: + type: integer + minimum: 0 + start: + type: string + format: date-time + stop: + type: string + format: date-time + comments: + type: string +time_log_update: + title: Time log + type: object + properties: + start: + type: string + format: date-time + stop: + type: string + format: date-time + comments: + type: string +time_booking: + title: Time booking + type: object + properties: + id: + type: integer + minimum: 0 + created_at: + type: string + format: date-time + updated_at: + type: string + format: date-time + start: + type: string + format: date-time + stop: + type: string + format: date-time +time_booking_params: + title: Time booking + type: object + properties: + start: + type: string + format: date-time + stop: + type: string + format: date-time + user_id: + type: integer + minimum: 0 + project_id: + type: integer + minimum: 0 + activity_id: + type: integer + minimum: 0 + issue_id: + type: integer + minimum: 0 + comments: + type: string +error_msg: + title: Error + type: object + properties: + message: + type: string +index_response: + title: Records + type: object + properties: + count: + type: integer + offset: + type: integer + limit: + type: integer + records: + type: array + items: + type: object diff --git a/spec/swagger_helper.rb b/spec/swagger_helper.rb index f5daecaf..e6a58480 100644 --- a/spec/swagger_helper.rb +++ b/spec/swagger_helper.rb @@ -34,7 +34,7 @@ security: [ {api_key: []} ], - definitions: YAML.load_file(File.expand_path(File.dirname(__FILE__) + '/support/model_definitions.yml'))['definitions'] + definitions: YAML.load_file(File.expand_path(File.dirname(__FILE__) + '/support/model_definitions.yml')) } } end From f1a7288c98fe69b7deced9912d69036b85944e25 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 04:11:48 +0100 Subject: [PATCH 08/20] fixed Ruby 3 syntax changes --- spec/support/access_rights.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/support/access_rights.rb b/spec/support/access_rights.rb index e0f6bd9c..c6887998 100644 --- a/spec/support/access_rights.rb +++ b/spec/support/access_rights.rb @@ -31,7 +31,7 @@ def test_unauthorized end RSpec.shared_examples 'access rights' do |*permissions, **opts| - test_permissions *permissions, opts - test_forbidden opts.slice :error_code + test_permissions *permissions, **opts + test_forbidden **(opts.slice :error_code) test_unauthorized end From ec611df36e0d2b4246cb2a30c61d3865cb732417 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 04:12:11 +0100 Subject: [PATCH 09/20] fixed bulk time log creation tests --- spec/integration/time_logs_spec.rb | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/spec/integration/time_logs_spec.rb b/spec/integration/time_logs_spec.rb index ebb66ed3..3cd03167 100644 --- a/spec/integration/time_logs_spec.rb +++ b/spec/integration/time_logs_spec.rb @@ -160,7 +160,7 @@ let(:user) { create :user, :as_member, permissions: [:hourglass_track_time] } let(:time_log) { create :time_log, user: user } - let(:split_at) { URI.encode (time_log.start + 10.minutes).utc.to_s } + let(:split_at) { Addressable::URI.encode_component((time_log.start + 10.minutes).utc.to_s, Addressable::URI::CharacterClasses::QUERY) } let(:id) { time_log.id } include_examples 'access rights', :hourglass_track_time, :hourglass_edit_tracked_time, :hourglass_edit_own_tracked_time @@ -329,12 +329,10 @@ 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) - ] - } + t1 = build(:time_log, user: user) + t2 = build(:time_log, user: user, start: t1.stop + 10.minutes, stop: t1.stop + 1.hour) + t3 = build(:time_log, user: user, start: t2.stop + 10.minutes, stop: t2.stop + 1.hour) + { time_logs: [t1, t2, t3] } end include_examples 'access rights', :hourglass_edit_tracked_time, :hourglass_edit_own_tracked_time From 2f7fd6d4b195f270376b54002d47777d8bc6e42c Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Tue, 14 Feb 2023 04:13:08 +0100 Subject: [PATCH 10/20] CI: use Redmine 5 and Ruby 3 --- .github/workflows/main.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9d3b0be5..76369fa8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,10 +7,18 @@ jobs: runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - redmine: [ '4.1.3', '4.2.1' ] - ruby: [ '2.5.9', '2.6.8' ] + redmine: [ '5.0.4', '4.2.9' ] + ruby: [ '2.7.7', '2.6.8' ] database: [ 'sqlite3', 'postgresql', 'mysql2' ] + include: + - redmine: '5.0.4' + ruby: '3.1.3' + database: 'postgresql' + - redmine: '5.0.4' + ruby: '3.1.3' + database: 'mysql2' services: postgresql: From 23b0f3506df86dbabb33280694576e04d85c7ffd Mon Sep 17 00:00:00 2001 From: pavanvo Date: Sun, 19 Feb 2023 18:26:19 +0400 Subject: [PATCH 11/20] fix: put version "6" check first cuz else we never get there --- config/initializers/autoload.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/initializers/autoload.rb b/config/initializers/autoload.rb index 070e98ca..dd13c566 100644 --- a/config/initializers/autoload.rb +++ b/config/initializers/autoload.rb @@ -4,10 +4,10 @@ %w(app policies), %w(app policies concerns) ].each do |path| - if Rails.version >= "5" and Rails.configuration.eager_load - Dir.glob(File.join(Hourglass::PLUGIN_ROOT, *path, "**/*.rb")).sort.each(&method(:require)) - elsif Rails.version >= "6" + if Rails.version >= "6" Rails.autoloaders.main.push_dir File.join(Hourglass::PLUGIN_ROOT, *path) + elsif Rails.version >= "5" and Rails.configuration.eager_load + Dir.glob(File.join(Hourglass::PLUGIN_ROOT, *path, "**/*.rb")).sort.each(&method(:require)) else ActiveSupport::Dependencies.autoload_paths << File.join(Hourglass::PLUGIN_ROOT, *path) end From 6d6e76fe08da1cbbffbdac9f2635d9fe982cbb75 Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Mon, 20 Feb 2023 18:31:58 +0100 Subject: [PATCH 12/20] fixed patch loading --- config/initializers/redmine_integration.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/initializers/redmine_integration.rb b/config/initializers/redmine_integration.rb index 59b40cad..cdf3cee2 100644 --- a/config/initializers/redmine_integration.rb +++ b/config/initializers/redmine_integration.rb @@ -12,7 +12,11 @@ def add_patch(module_to_patch, method: :include) [ProjectsHelper, SettingsController].each { |module_to_patch| add_patch module_to_patch, method: (Rails.version < "5" ? :include : :prepend) } [Query].each { |module_to_patch| add_patch module_to_patch, method: :prepend } - Redmine::Plugin.find(Hourglass::PLUGIN_NAME).extend Hourglass::RedminePatches::MirrorAssetsPatch + if Redmine::VERSION::MAJOR < 5 + Redmine::Plugin.find(Hourglass::PLUGIN_NAME).extend Hourglass::RedminePatches::MirrorAssetsPatch + else + Redmine::PluginLoader.directories.find{|d| d.to_s == File.join(Redmine::PluginLoader.directory, Hourglass::PLUGIN_NAME.to_s)}.extend Hourglass::RedminePatches::MirrorAssetsPatch + end end Hourglass::RedmineHooks.load! From 3d9680ed0f447036bba6a1547169968c97466b7f Mon Sep 17 00:00:00 2001 From: pavanvo Date: Sun, 19 Feb 2023 18:33:48 +0400 Subject: [PATCH 13/20] fix: add ES6 support --- lib/hourglass/assets.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/hourglass/assets.rb b/lib/hourglass/assets.rb index 14a261d6..02812192 100644 --- a/lib/hourglass/assets.rb +++ b/lib/hourglass/assets.rb @@ -13,7 +13,7 @@ def initialize env.append_path path end if Rails.env.production? - env.js_compressor = :uglify + env.js_compressor = Uglifier.new(harmony: true) env.css_compressor = :scss end end From ad6859cb6f4c5600f0274988b7e7f86c06c09a4f Mon Sep 17 00:00:00 2001 From: Andreas Reischuck Date: Mon, 20 Feb 2023 20:24:53 +0100 Subject: [PATCH 14/20] fix swagger ui --- app/assets/javascripts/swagger.coffee | 14 - app/assets/stylesheets/application.scss | 29 + app/assets/stylesheets/swagger-print.scss | 2 - app/assets/stylesheets/swagger.scss | 154 ---- app/views/hourglass_ui/api_docs.slim | 28 +- vendor/assets/images/swagger.png | Bin 0 -> 628 bytes .../javascripts/jquery-migrate-1.4.1.js | 752 ------------------ .../javascripts/jquery-migrate-1.4.1.min.js | 2 - .../assets/javascripts/swagger-ui-bundle.js | 3 + .../swagger-ui-standalone-preset.js | 3 + vendor/assets/stylesheets/swagger-ui.css | 4 + 11 files changed, 47 insertions(+), 944 deletions(-) delete mode 100644 app/assets/javascripts/swagger.coffee delete mode 100644 app/assets/stylesheets/swagger-print.scss delete mode 100644 app/assets/stylesheets/swagger.scss create mode 100644 vendor/assets/images/swagger.png delete mode 100644 vendor/assets/javascripts/jquery-migrate-1.4.1.js delete mode 100644 vendor/assets/javascripts/jquery-migrate-1.4.1.min.js create mode 100644 vendor/assets/javascripts/swagger-ui-bundle.js create mode 100644 vendor/assets/javascripts/swagger-ui-standalone-preset.js create mode 100644 vendor/assets/stylesheets/swagger-ui.css diff --git a/app/assets/javascripts/swagger.coffee b/app/assets/javascripts/swagger.coffee deleted file mode 100644 index 15a37884..00000000 --- a/app/assets/javascripts/swagger.coffee +++ /dev/null @@ -1,14 +0,0 @@ -#= require jquery-migrate-1.4.1.min -#= require swagger-ui/lib/jquery.slideto.min -#= require swagger-ui/lib/jquery.wiggle.min -#= require swagger-ui/lib/jquery.ba-bbq.min -#= require swagger-ui/lib/handlebars-4.0.5 -#= require swagger-ui/lib/lodash.min -#= require swagger-ui/lib/backbone-min -#= require swagger-ui/swagger-ui.min -#= require swagger-ui/lib/object-assign-pollyfill -#= require swagger-ui/lib/highlight.9.1.0.pack -#= require swagger-ui/lib/highlight.9.1.0.pack_extended -#= require swagger-ui/lib/jsoneditor.min -#= require swagger-ui/lib/marked -#= require swagger-ui/lib/swagger-oauth diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 352d1b4f..ea7e5198 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -221,3 +221,32 @@ background: url(/images/link.png) no-repeat 0% 70%; } } + +.swagger-ui { + input, + select, + button { + height: auto; + } +} + +.swagger-note { + margin-top: 10px; + + .swagger-link { + font-size: 1.3em; + font-weight: bold; + text-decoration: none; + + .logo__img { + display: block; + float: left; + margin-top: 2px; + } + + .logo__title { + display: inline-block; + padding: 5px 0 0 10px; + } + } +} diff --git a/app/assets/stylesheets/swagger-print.scss b/app/assets/stylesheets/swagger-print.scss deleted file mode 100644 index 1e14a159..00000000 --- a/app/assets/stylesheets/swagger-print.scss +++ /dev/null @@ -1,2 +0,0 @@ -//= require swagger-ui/css/reset -//= require swagger-ui/css/print diff --git a/app/assets/stylesheets/swagger.scss b/app/assets/stylesheets/swagger.scss deleted file mode 100644 index 73ff13df..00000000 --- a/app/assets/stylesheets/swagger.scss +++ /dev/null @@ -1,154 +0,0 @@ -//= require swagger-ui/css/screen - -.swagger-section { - /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ - html, - body, - div, - span, - applet, - object, - iframe, - h1, - h2, - h3, - h4, - h5, - h6, - p, - blockquote, - pre, - a, - abbr, - acronym, - address, - big, - cite, - code, - del, - dfn, - em, - img, - ins, - kbd, - q, - s, - samp, - small, - strike, - strong, - sub, - sup, - tt, - var, - b, - u, - i, - center, - dl, - dt, - dd, - ol, - ul, - li, - fieldset, - form, - label, - legend, - table, - caption, - tbody, - tfoot, - thead, - tr, - th, - td, - article, - aside, - canvas, - details, - embed, - figure, - figcaption, - footer, - header, - hgroup, - menu, - nav, - output, - ruby, - section, - summary, - time, - mark, - audio, - video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; - } - /* HTML5 display-role reset for older browsers */ - article, - aside, - details, - figcaption, - figure, - footer, - header, - hgroup, - menu, - nav, - section { - display: block; - } - body { - line-height: 1; - } - ol, - ul { - list-style: none; - } - blockquote, - q { - quotes: none; - } - blockquote:before, - blockquote:after, - q:before, - q:after { - content: ''; - content: none; - } - table { - border-collapse: collapse; - border-spacing: 0; - } - .swagger-note { - margin-top: 10px; - .swagger-link { - font-size: 1.3em; - font-weight: bold; - text-decoration: none; - .logo__img { - display: block; - float: left; - margin-top: 2px; - } - .logo__title { - display: inline-block; - padding: 5px 0 0 10px; - } - } - } - - #auth_container { - float: right; - } - - #swagger-ui-container{ - clear: both; - } -} diff --git a/app/views/hourglass_ui/api_docs.slim b/app/views/hourglass_ui/api_docs.slim index e60da7fd..9b4c79a3 100644 --- a/app/views/hourglass_ui/api_docs.slim +++ b/app/views/hourglass_ui/api_docs.slim @@ -1,36 +1,24 @@ - api_enabled = Setting.rest_api_enabled == '1' - content_for :header_tags do - = stylesheet_link_tag 'swagger', plugin: Hourglass::PLUGIN_NAME, media: 'screen' - = stylesheet_link_tag 'swagger-print', plugin: Hourglass::PLUGIN_NAME, media: 'print' - = javascript_include_tag 'swagger', plugin: Hourglass::PLUGIN_NAME + = stylesheet_link_tag 'swagger-ui', plugin: Hourglass::PLUGIN_NAME, media: 'screen' + = javascript_include_tag 'swagger-ui-bundle', plugin: Hourglass::PLUGIN_NAME javascript: $(function () { var initiated = false; - hljs.configure({highlightSizeThreshold: 5000}); - window.swaggerUi = new SwaggerUi({ + window.swaggerUi = new SwaggerUIBundle({ url: "#{hourglass_rswag_api_path}/v1/swagger.json", - dom_id: "swagger-ui-container", + dom_id: "#swagger-ui-container", + presets: [SwaggerUIBundle.presets.apis], supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'], onFailure: function () { hourglass.Utils.showErrorMessage("#{t('hourglass.ui.api_docs.error_json_missing', task: 'redmine:plugins:hourglass:api_docs')}"); }, - onComplete: function () { - if (window.swaggerUi.api.info['x-docsVersion'] !== '#{Hourglass.swagger_docs_version}') { - hourglass.Utils.showErrorMessage("#{t('hourglass.ui.api_docs.error_outdated', task: 'redmine:plugins:hourglass:api_docs')}"); - } - if (!initiated) { - initiated = true; - $('.authorize__btn').click(); - $('.auth_input.input_apiKey_entry').val('#{User.current.api_key}').change(); - $('.auth__button.auth_submit__button').click(); - } + onComplete: function() { + window.swaggerUi.preauthorizeApiKey("api_key", "#{User.current.api_key}"); }, docExpansion: 'list' }); - if (#{api_enabled}) { - window.swaggerUi.load(); - } }); = render layout: 'hourglass_ui/layouts/hourglass' do @@ -49,7 +37,7 @@ | : .swagger-link a href="http://swagger.io" - img.logo__img alt="swagger" height="30" width="30" src=asset_path('swagger-ui/images/logo_small.png') + img.logo__img alt="" height="30" width="30" src=Hourglass::Assets.path('swagger.png', type: 'image') span.logo__title Swagger - else = t('hourglass.ui.api_docs.error_api_disabled') diff --git a/vendor/assets/images/swagger.png b/vendor/assets/images/swagger.png new file mode 100644 index 0000000000000000000000000000000000000000..249737fe44558e679f0b67134e274461d988fa98 GIT binary patch literal 628 zcmV-)0*n2LP)Ma*GM0}OV<074bNCP7P7GVd{iMr*I6y~TMLss@FjvgL~HxU z%Vvj33AwpD(Z4*$Mfx=HaU16axM zt2xG_rloN<$iy9j9I5", { size: 1 } ).attr("size") && jQuery.attrFn, - oldAttr = jQuery.attr, - valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get || - function() { return null; }, - valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set || - function() { return undefined; }, - rnoType = /^(?:input|button)$/i, - rnoAttrNodeType = /^[238]$/, - rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i, - ruseDefault = /^(?:checked|selected)$/i; - -// jQuery.attrFn -migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" ); - -jQuery.attr = function( elem, name, value, pass ) { - var lowerName = name.toLowerCase(), - nType = elem && elem.nodeType; - - if ( pass ) { - // Since pass is used internally, we only warn for new jQuery - // versions where there isn't a pass arg in the formal params - if ( oldAttr.length < 4 ) { - migrateWarn("jQuery.fn.attr( props, pass ) is deprecated"); - } - if ( elem && !rnoAttrNodeType.test( nType ) && - (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) { - return jQuery( elem )[ name ]( value ); - } - } - - // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking - // for disconnected elements we don't warn on $( "