Commit 9141144a authored by Kaspar Vollenweider's avatar Kaspar Vollenweider

Merge branch 'rails-gem-upgrades' into 'develop'

Rails gem upgrades

See merge request !1044
parents a4ed821a 5e291108
Pipeline #77152 failed with stage
in 10 minutes and 41 seconds
app
test
bin
config
node_modules
.bundle
public
.github
lib
db
log
doc
.git
.vscode
tmp
vendor
image: git.panter.ch:5001/open-source/aoz-003/gitlab_ci:2.4.5
image: git.panter.ch:5001/open-source/aoz-003/gitlab_ci:2.6.6
stages:
- test
......@@ -14,6 +14,7 @@ variables:
.push-pull-cache:
cache:
key: aoz-003-ruby-2-6-6
paths:
- tmp/cache/ruby
- tmp/cache/yarn
......@@ -21,6 +22,7 @@ variables:
.pull-cache:
cache:
key: aoz-003-ruby-2-6-6
paths:
- tmp/cache/ruby
- tmp/cache/yarn
......@@ -57,7 +59,6 @@ system:
- .test-extend
- .retry-dropped-runners
script:
- bundle exec chromedriver-update $(cat /chrome_driver_version.txt)
- bundle exec rails test:system
artifacts:
paths:
......
......@@ -15,7 +15,7 @@ AllCops:
DisplayCopNames: true
DisplayStyleGuide: true
ExtraDetails: true
TargetRubyVersion: 2.4
TargetRubyVersion: 2.6
Rails:
Enabled: true
......@@ -23,6 +23,8 @@ Rails/FilePath:
Enabled: false
Rails/HasAndBelongsToMany:
Enabled: false
Rails/RefuteMethods:
Enabled: false
Metrics/AbcSize:
Exclude:
......@@ -49,22 +51,38 @@ Metrics/BlockLength:
- define # for FactoryBot
- factory
Lint/RaiseException:
Enabled: true
Lint/StructNewOverride:
Enabled: true
Layout/FirstArrayElementIndentation:
Enabled: true
EnforcedStyle: consistent
Layout/FirstHashElementIndentation:
Enabled: true
EnforcedStyle: consistent
Layout/FirstParameterIndentation:
Enabled: true
EnforcedStyle: consistent
Layout/HashAlignment:
EnforcedLastArgumentHashStyle: ignore_implicit
EnforcedLastArgumentHashStyle: always_inspect
Layout/MultilineMethodCallIndentation:
Enabled: true
EnforcedStyle: indented
Layout/MultilineOperationIndentation:
Enabled: true
EnforcedStyle: indented
Layout/ParameterAlignment:
EnforcedStyle: with_fixed_indentation
Enabled: true
EnforcedStyle: with_first_parameter
Layout/ArgumentAlignment:
Enabled: true
EnforcedStyle: with_first_argument
Layout/SpaceAroundMethodCallOperator:
Enabled: true
Layout/EmptyLinesAroundAttributeAccessor:
Enabled: true
Layout/LineLength:
Max: 100
# To make it possible to copy or click on URIs in the code, we allow lines
......@@ -119,3 +137,5 @@ Style/HashEachMethods:
Enabled: true
Style/ExponentialNotation:
Enabled: true
Style/SlicingWithRange:
Enabled: true
FROM ruby:2.4.5
FROM ruby:2.6.6
LABEL name=aoz-003-gitlab_ci
LABEL version=0.0.1
LABEL build-date=2020-05-05T11:27:33.118Z
LABEL version=0.3.2
LABEL build-date=2020-05-18T21:39:31+02:00
LABEL vendor=Panter maintainer=vok@panter.ch distribution-scope=private URL=https://git.panter.ch/panter/aoz-003
RUN apt update \
......@@ -30,7 +30,7 @@ RUN apt update \
&& cat /chrome_driver_version.txt \
# install correct bundler version
&& gem uninstall bundler \
&& gem install bundler --version 2.0.2 \
&& gem install bundler --version 2.1.4 \
# Cleanup apt and gem cache files and indexes
&& gem cleanup \
&& rm -rf /var/lib/apt/lists/* \
......
......@@ -5,19 +5,15 @@ git_source(:github) do |repo_name|
"https://github.com/#{repo_name}.git"
end
gem 'rails', '~> 5.1'
gem 'rails', '>= 5.2.0', '< 6.0.0'
gem 'autocomplete_rails'
# FIXME:
# - autoprefixer doesn't run with rubyracer anymore, it would with miniracer
# - installing miniracer ist blocked by panter/panter-rails-deploy rubyracer requirement
# - using Node as Execjs Runtime is not possible, because our hosts don't have node
# gem 'autoprefixer-rails'
gem 'axlsx', github: 'randym/axlsx', ref: '776037c0fc799bb09da8c9ea47980bd3bf296874'
gem 'axlsx_rails'
gem 'bootsnap', require: false
gem 'bootstrap-datepicker-rails'
gem 'bootstrap-sass'
gem 'bootstrap-will_paginate'
gem 'caxlsx'
gem 'caxlsx_rails'
gem 'cocoon'
gem 'coffee-rails'
gem 'combine_pdf'
......@@ -38,11 +34,11 @@ gem 'mdb'
gem 'panter-rails-deploy'
gem 'paperclip'
gem 'paranoia'
gem 'pg', '~> 0.21'
gem 'pg'
gem 'puma'
gem 'pundit'
gem 'rails-i18n'
gem 'ransack', github: 'activerecord-hackery/ransack'
gem 'ransack'
gem 'redcarpet'
gem 'rubyzip', '>= 1.2.2'
gem 'sassc-rails'
......@@ -62,7 +58,7 @@ group :development do
gem 'debride', require: false
gem 'fasterer', require: false
gem 'i18n_yaml_sorter'
gem 'letter_opener_web', '~> 1.0'
gem 'letter_opener_web'
gem 'overcommit', require: false
gem 'rcodetools', require: false
gem 'reek', require: false
......@@ -90,10 +86,10 @@ end
group :test do
gem 'capybara'
gem 'capybara-selenium'
gem 'chromedriver-helper'
gem 'database_cleaner'
gem 'minitest', '~> 5.10.3'
gem 'minitest'
gem 'policy-assertions'
gem 'roo', '~> 2.7.0'
gem 'roo'
gem 'selenium-webdriver'
gem 'webdrivers', '~> 4.0'
end
This diff is collapsed.
function clientForm() {
$('.reserve-client-action-cell').on('click', ({ target }) => {
const cell = $(target).closest('td')
const { clientId } = cell.data()
const data = cell.data()
const clientId = data.clientId || data.client_id
$.ajax({
url: `/clients/${clientId}/reserve`,
type: 'PUT',
}).done(({user_name, btn_text}) => {
}).done(({ user_name, btn_text }) => {
cell.find('button, span').remove()
if (user_name) {
cell.find('button').remove()
cell.append($(`<span>${user_name}</span>`))
cell.append($(`<button class="btn btn-default">${btn_text}</button>`))
} else {
cell.find('span').remove()
cell.find('button').remove()
cell.append($(`<button class="btn btn-default">${btn_text}</button>`))
}
}).fail(error => {
console.log(error)
})
});
})
}
......@@ -28,11 +28,11 @@ fieldset {
flex: 0 0 80%;
font-size: 12px;
line-height: 1.4;
padding: 6px 12px;
outline: none;
padding: 6px 12px;
&:focus {
@extend .form-control:focus;
@extend .form-control, :focus;
}
}
......@@ -45,16 +45,15 @@ fieldset {
flex: 0 0 20%;
&:hover {
@extend .btn:hover;
@extend .btn-default:hover;
@extend .btn, :hover;
@extend .btn-default, :hover;
}
&:active {
@extend .btn-default:active;
@extend .btn:active;
@extend .btn-default, :active;
@extend .btn, :active;
}
}
}
.field-wrapper-inline {
......
......@@ -20,7 +20,12 @@ class DepartmentsController < ApplicationController
def create
@department = Department.new
authorize @department
if @department.update(permitted_attributes(@department))
@department.assign_attributes(permitted_attributes(@department).except(:user_ids))
if @department.save
if permitted_attributes(@department)[:user_ids]&.reject(&:blank?)&.any?
@department.reload.user_ids = permitted_attributes(@department)[:user_ids].reject(&:blank?).map(&:to_i)
@department.save!
end
redirect_to @department, make_notice
else
render :new
......
......@@ -12,7 +12,7 @@ class SemesterProcessVolunteersController < ApplicationController
semester = Semester.parse(params[:semester])
@global_filters = {semester: params[:semester]}
@semester_process = SemesterProcess.find_by_semester(semester).last
@q = SemesterProcessVolunteer.index(@semester_process).ransack(params[:q])
@q = SemesterProcessVolunteer.index_scope(@semester_process).ransack(params[:q])
@q.sorts = ['volunteer_contact_last_name asc'] if @q.sorts.empty?
@spvs = @q.result.paginate(page: params[:page])
set_responsibles
......
......@@ -72,8 +72,11 @@ class UsersController < ApplicationController
if user_params[:password].blank?
@user.update_without_password(user_params)
else
@user.accept_invitation! if @user.invited_to_sign_up? && !@user.invitation_accepted?
@user.update(user_params)
@user.assign_attributes(user_params)
if @user.invited_to_sign_up? && !@user.invitation_accepted?
@user.accept_invitation!
end
@user.save
end
end
......
......@@ -17,6 +17,9 @@ class Assignment < ApplicationRecord
has_many :semester_process_volunteers, through: :semester_process_volunteer_missions
has_many :semester_processes, through: :semester_process_volunteers
has_many :reminder_mailing_volunteers, as: :reminder_mailable, dependent: :destroy
has_many :reminder_mailings, through: :reminder_mailing_volunteers
validates :client_id, uniqueness: {
scope: :volunteer_id, message: I18n.t('assignment_exists')
}
......
......@@ -19,10 +19,10 @@ class BillingExpense < ApplicationRecord
FINAL_AMOUNT_SQL = "CASE WHEN overwritten_amount IS NULL THEN amount ELSE overwritten_amount END".freeze
scope :sort_by_final_amount_asc, lambda {
order("#{FINAL_AMOUNT_SQL} asc")
order(Arel.sql("#{FINAL_AMOUNT_SQL} asc"))
}
scope :sort_by_final_amount_desc, lambda {
order("#{FINAL_AMOUNT_SQL} desc")
order(Arel.sql("#{FINAL_AMOUNT_SQL} desc"))
}
AMOUNT = [50, 100, 150].freeze
......
......@@ -8,9 +8,6 @@ module GroupAssignmentAndAssignmentCommon
belongs_to :volunteer
accepts_nested_attributes_for :volunteer, update_only: true
has_many :reminder_mailing_volunteers, as: :reminder_mailable, dependent: :destroy
has_many :reminder_mailings, through: :reminder_mailing_volunteers
has_one :trial_period, as: :trial_period_mission, inverse_of: :trial_period_mission
accepts_nested_attributes_for :trial_period
......
......@@ -8,6 +8,9 @@ class GroupAssignment < ApplicationRecord
has_many :group_assignment_logs, dependent: :nullify
has_many :hours, ->(object) { where(volunteer: object.volunteer) }, through: :group_offer
has_many :reminder_mailing_volunteers, as: :reminder_mailable, dependent: :destroy
has_many :reminder_mailings, through: :reminder_mailing_volunteers
delegate :title, to: :group_offer
validates :volunteer, uniqueness: {
......
......@@ -5,7 +5,7 @@ class LanguageSkill < ApplicationRecord
LANGUAGE_LEVELS = [:native_speaker, :basic, :fluent, :good].freeze
scope :german_first, (-> { order("CASE WHEN language = 'DE' THEN 1 ELSE 2 END") })
scope :german_first, (-> { order(Arel.sql("CASE WHEN language = 'DE' THEN 1 ELSE 2 END")) })
scope :german, (-> { where(language: 'DE') })
scope :native, (-> { where(level: 'native_speaker') })
......@@ -32,7 +32,7 @@ class LanguageSkill < ApplicationRecord
def native_and_human_readable
german_first.map(&:full_language_skills)
end
end
end
def language_name
......@@ -42,5 +42,5 @@ class LanguageSkill < ApplicationRecord
def full_language_skills
level_human = level? ? I18n.t(level, scope: [:language_level]) : ''
[language_name, level_human].reject(&:blank?).join(', ') if language?
end
end
end
......@@ -45,7 +45,7 @@ class SemesterProcessVolunteer < ApplicationRecord
.references(:assignments, :group_assignments)
}
scope :index, lambda { |semester = nil|
scope :index_scope, lambda { |semester = nil|
active_missions.without_reminders(semester)
}
......@@ -61,8 +61,6 @@ class SemesterProcessVolunteer < ApplicationRecord
joins(:semester_process).where('semester_processes.semester && daterange(?,?)', semester.begin, semester.end)
}
attr_accessor :hours
def hours
missions.map do |m|
m.hours.within_semester(semester)
......
......@@ -116,7 +116,7 @@ class User < ApplicationRecord
has_many :semester_feedbacks, inverse_of: 'author', foreign_key: 'author_id', dependent: :destroy
has_and_belongs_to_many :department
has_and_belongs_to_many :department, -> { order(created_at: :desc) }
# Roles definition
SUPERADMIN = 'superadmin'.freeze
......
......@@ -339,15 +339,16 @@ class Volunteer < ApplicationRecord
}
scope :with_billable_hours_select, lambda {
select(<<-SQL.squish)
select_sql = <<-SQL.squish
SUM(hours.hours) AS total_hours,
contacts.full_name AS full_name,
volunteers.*
SQL
select(Arel.sql(select_sql))
}
scope :with_billable_hours_order, lambda {
order(<<-SQL.squish)
sort_sql = <<-SQL.squish
(CASE
WHEN COALESCE(volunteers.iban, '') = ''
THEN 2
......@@ -355,6 +356,7 @@ class Volunteer < ApplicationRecord
END),
contacts.full_name
SQL
order(Arel.sql(sort_sql))
}
scope :assignable_to_department, -> { undecided.where(department_id: [nil, '']) }
......
......@@ -124,10 +124,6 @@ class ApplicationPolicy
superadmin? || (department_manager? && departments_record?)
end
def superadmin_or_user_in_records_related?
superadmin? || record.user_ids.include?(user.id)
end
def superadmin_or_volunteers_record?
superadmin? || volunteer? && user_owns_record?
end
......
......@@ -12,6 +12,10 @@ class DepartmentPolicy < ApplicationPolicy
alias_method :create?, :superadmin?
alias_method :destroy?, :superadmin?
def superadmin_or_user_in_records_related?
superadmin? || record.user_ids.include?(user.id)
end
alias_method :show?, :superadmin_or_user_in_records_related?
alias_method :edit?, :superadmin_or_user_in_records_related?
alias_method :update?, :superadmin_or_user_in_records_related?
......
h4.label-list
- availability_collection.each do |availability|
- if available.read_attribute(availability)
span.label.label-success>
=> icon_span(:yes)
= t("availability.#{availability}")
- else
span.label.label-danger>
=> icon_span(:no)
= t("availability.#{availability}")
.row
.col-xs-12.availability-label-list
- availability_collection.each do |availability|
- if available.read_attribute(availability)
span.label.label-success>
=> icon_span(:yes)
= t("availability.#{availability}")
- else
span.label.label-danger>
=> icon_span(:no)
= t("availability.#{availability}")
.row
.col-xs-12
......
- tr ||= nil
tr class=(tr)
td= t("performance_reports.values_#{group}.#{value_key}")
tr*{ data: { group: group, key: value_key } } class=(tr)
td.name= t("performance_reports.values_#{group}.#{value_key}")
- columns.each do |category_key|
td
td*{ data: { category: category_key } }
- if @report_content[group.to_s][category_key][value_key.to_s].is_a? Float
= '%g' % ('%.1f' % @report_content[group.to_s][category_key][value_key.to_s])
- else
......
h1.m-b-20 Profil von #{@user.full_name}
.row
.col-md-4
strong= t_attr(:email)
......
#!/usr/bin/env ruby
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
load Gem.bin_path('bundler', 'bundle')
#!/usr/bin/env ruby
require 'pathname'
require 'fileutils'
include FileUtils
# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
......@@ -21,7 +20,6 @@ chdir APP_ROOT do
# Install JavaScript dependencies if using Yarn
# system('bin/yarn')
# puts "\n== Copying sample files =="
# unless File.exist?('config/database.yml')
# cp 'config/database.yml.sample', 'config/database.yml'
......
#!/usr/bin/env ruby
require 'pathname'
require 'fileutils'
include FileUtils
# path to your application root.
APP_ROOT = Pathname.new File.expand_path('../../', __FILE__)
APP_ROOT = File.expand_path('..', __dir__)
def system!(*args)
system(*args) || abort("\n== Command #{args} failed ==")
......@@ -17,6 +16,10 @@ chdir APP_ROOT do
puts '== Installing dependencies =='
system! 'gem install bundler --conservative'
system('bundle check') || system!('bundle install')
# Install JavaScript dependencies if using Yarn
# system('bin/yarn')
puts "\n== Updating database =="
system! 'bin/rails db:migrate'
......
#!/usr/bin/env ruby
VENDOR_PATH = File.expand_path('..', __dir__)
Dir.chdir(VENDOR_PATH) do
APP_ROOT = File.expand_path('..', __dir__)
Dir.chdir(APP_ROOT) do
begin
exec "yarnpkg #{ARGV.join(" ")}"
exec "yarnpkg", *ARGV
rescue Errno::ENOENT
puts "Yarn executable was not detected in the system."
puts "Download Yarn at https://yarnpkg.com/en/docs/install"
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1
end
end
require_relative 'boot'
require File.expand_path('../boot', __FILE__)
ENV['RANSACK_FORM_BUILDER'] = '::SimpleForm::FormBuilder'
require 'rails/all'
......@@ -10,14 +10,15 @@ Bundler.require(*Rails.groups)
module Aoz
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
config.load_defaults 5.2
config.time_zone = 'Zurich'
config.autoload_paths += Dir[config.root.join('lib/access_import/**/')]
config.autoload_paths += Dir[config.root.join('lib/access_import/accessors/**/')]
WillPaginate.per_page = 20
# Settings in config/environments/* take precedence over those specified here.
# Application configuration should go into files in config/initializers
# -- all .rb files in that directory are automatically loaded.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
# the framework and any gems in your application.
end
end
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
# FIXME:
# - autoprefixer doesn't run with rubyracer anymore, it would with miniracer
# - installing miniracer ist blocked by panter/panter-rails-deploy rubyracer requirement
# - using Node as Execjs Runtime is not possible, because our hosts don't have node
# ENV['EXECJS_RUNTIME'] = 'Node'
require 'bundler/setup' # Set up gems listed in the Gemfile.
require 'bootsnap/setup' # Speed up boot time by caching expensive operations.
......@@ -6,5 +6,5 @@ test:
production:
adapter: redis
url: redis://localhost:6379/1
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: aoz_production
......@@ -13,23 +13,26 @@ Rails.application.configure do
config.consider_all_requests_local = true
# Enable/disable caching. By default caching is disabled.
# Run rails dev:cache to toggle caching.
if Rails.root.join('tmp', 'caching-dev.txt').exist?
config.action_controller.perform_caching = true
config.cache_store = :memory_store
config.public_file_server.headers = {
'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}"
'Cache-Control' => "public, max-age=#{2.days.to_i}"
}
else
config.action_controller.perform_caching = false
config.cache_store = :null_store
end
config.sass.inline_source_maps = true
## in order to activate letter_opener uncomment this line
config.action_mailer.delivery_method = :letter_opener_web
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Don't care if the mailer can't send.
config.action_mailer.raise_delivery_errors = false
......@@ -43,6 +46,9 @@ Rails.application.configure do
# Raise an error on page load if there are pending migrations.
config.active_record.migration_error = :page_load
# Highlight code that triggered database queries in logs.
config.active_record.verbose_query_logs = true
# Debug mode disables concatenation and preprocessing of assets.
# This option may cause significant delays in view rendering with a large
# number of complex assets.
......@@ -52,7 +58,7 @@ Rails.application.configure do
config.assets.quiet = true
# Raises error for missing translations
config.action_view.raise_on_missing_translations = true
# config.action_view.raise_on_missing_translations = true
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
......
......@@ -14,10 +14,15 @@ Rails.application.configure do
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Attempt to read encrypted secrets from `config/secrets.yml.enc`.
# Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
# `config/secrets.yml.key`.
config.read_encrypted_secrets = true
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
# or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
# config.require_master_key = true
# Rails 5.1 secrets
# # Attempt to read encrypted secrets from `config/secrets.yml.enc`.
# # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or
# # `config/secrets.yml.key`.
# config.read_encrypted_secrets = true
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
......@@ -39,6 +44,9 @@ Rails.application.configure do
# config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
# Store uploaded files on the local file system (see config/storage.yml for options)
config.active_storage.service = :local
# Mount Action Cable outside main process or domain
# config.action_cable.mount_path = nil
# config.action_cable.url = 'wss://example.com/cable'
......@@ -60,6 +68,7 @@ Rails.application.configure do
# Use a real queuing backend for Active Job (and separate queues per environment)
# config.active_job.queue_adapter = :resque