Verified Commit 806dbac0 authored by Jiri Strojil's avatar Jiri Strojil 💬 Committed by Kaspar Vollenweider
Browse files

Feat/activestorage migration

parent 053f3638
...@@ -28,6 +28,7 @@ lib/access_import_test/*.xlsx ...@@ -28,6 +28,7 @@ lib/access_import_test/*.xlsx
doc doc
/.idea /.idea
.vscode/ .vscode/
storage/
/public/packs /public/packs
/public/packs-test /public/packs-test
......
...@@ -17,6 +17,7 @@ AllCops: ...@@ -17,6 +17,7 @@ AllCops:
- vendor/**/* - vendor/**/*
- lib/access_import/**/* - lib/access_import/**/*
- 'node_modules/**/*' - 'node_modules/**/*'
- 'lib/tasks/active_storage.rake'
DisplayCopNames: true DisplayCopNames: true
DisplayStyleGuide: true DisplayStyleGuide: true
ExtraDetails: true ExtraDetails: true
......
...@@ -8,6 +8,7 @@ end ...@@ -8,6 +8,7 @@ end
gem 'rails', '>= 6.0.0', '< 6.1.0' gem 'rails', '>= 6.0.0', '< 6.1.0'
gem 'active_storage_validations'
gem 'bootsnap', require: false gem 'bootsnap', require: false
gem 'bootstrap-datepicker-rails' gem 'bootstrap-datepicker-rails'
gem 'bootstrap-sass' gem 'bootstrap-sass'
...@@ -25,8 +26,10 @@ gem 'devise-i18n' ...@@ -25,8 +26,10 @@ gem 'devise-i18n'
gem 'devise_invitable' gem 'devise_invitable'
gem 'factory_bot_rails' gem 'factory_bot_rails'
gem 'ffaker' gem 'ffaker'
gem 'google-cloud-storage', '~> 1.11', require: false
gem 'i18n_data' gem 'i18n_data'
gem 'i18n_rails_helpers' gem 'i18n_rails_helpers'
gem 'image_processing'
gem 'jbuilder' gem 'jbuilder'
gem 'jquery-rails' gem 'jquery-rails'
gem 'jquery-ui-rails' gem 'jquery-ui-rails'
...@@ -74,7 +77,6 @@ group :development do ...@@ -74,7 +77,6 @@ group :development do
end end
group :development, :test do group :development, :test do
gem 'awesome_rails_console'
gem 'better_errors' gem 'better_errors'
gem 'binding_of_callers' gem 'binding_of_callers'
gem 'hirb' gem 'hirb'
......
...@@ -38,6 +38,8 @@ GEM ...@@ -38,6 +38,8 @@ GEM
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_storage_validations (0.8.9)
rails (>= 5.2.0)
activejob (6.0.3.1) activejob (6.0.3.1)
activesupport (= 6.0.3.1) activesupport (= 6.0.3.1)
globalid (>= 0.3.6) globalid (>= 0.3.6)
...@@ -65,11 +67,6 @@ GEM ...@@ -65,11 +67,6 @@ GEM
ast (2.4.0) ast (2.4.0)
autoprefixer-rails (9.7.6) autoprefixer-rails (9.7.6)
execjs execjs
awesome_print (1.8.0)
awesome_rails_console (0.4.4)
awesome_print
pry-rails
railties
babel-source (5.8.35) babel-source (5.8.35)
babel-transpiler (0.7.0) babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6) babel-source (>= 4.0, < 6)
...@@ -164,6 +161,8 @@ GEM ...@@ -164,6 +161,8 @@ GEM
ruby_parser (~> 3.6) ruby_parser (~> 3.6)
sexp_processor (~> 4.5) sexp_processor (~> 4.5)
debug_inspector (0.0.3) debug_inspector (0.0.3)
declarative (0.0.10)
declarative-option (0.1.0)
devise (4.7.1) devise (4.7.1)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
...@@ -175,6 +174,7 @@ GEM ...@@ -175,6 +174,7 @@ GEM
devise_invitable (2.0.2) devise_invitable (2.0.2)
actionmailer (>= 5.0) actionmailer (>= 5.0)
devise (>= 4.6) devise (>= 4.6)
digest-crc (0.5.1)
dotenv (2.7.5) dotenv (2.7.5)
dotenv-rails (2.7.5) dotenv-rails (2.7.5)
dotenv (= 2.7.5) dotenv (= 2.7.5)
...@@ -186,6 +186,8 @@ GEM ...@@ -186,6 +186,8 @@ GEM
factory_bot_rails (5.2.0) factory_bot_rails (5.2.0)
factory_bot (~> 5.2.0) factory_bot (~> 5.2.0)
railties (>= 4.2.0) railties (>= 4.2.0)
faraday (1.0.1)
multipart-post (>= 1.2, < 3)
fasterer (0.8.3) fasterer (0.8.3)
colorize (~> 0.7) colorize (~> 0.7)
ruby_parser (>= 3.14.1) ruby_parser (>= 3.14.1)
...@@ -193,6 +195,34 @@ GEM ...@@ -193,6 +195,34 @@ GEM
ffi (1.12.2) ffi (1.12.2)
globalid (0.4.2) globalid (0.4.2)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
google-api-client (0.39.5)
addressable (~> 2.5, >= 2.5.1)
googleauth (~> 0.9)
httpclient (>= 2.8.1, < 3.0)
mini_mime (~> 1.0)
representable (~> 3.0)
retriable (>= 2.0, < 4.0)
signet (~> 0.12)
google-cloud-core (1.5.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.3.1)
faraday (>= 0.17.3, < 2.0)
google-cloud-errors (1.0.0)
google-cloud-storage (1.26.1)
addressable (~> 2.5)
digest-crc (~> 0.4)
google-api-client (~> 0.33)
google-cloud-core (~> 1.2)
googleauth (~> 0.9)
mini_mime (~> 1.0)
googleauth (0.12.0)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.4, < 3.0)
memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (~> 0.14)
hashery (2.1.2) hashery (2.1.2)
highline (2.0.3) highline (2.0.3)
hirb (0.7.3) hirb (0.7.3)
...@@ -200,12 +230,16 @@ GEM ...@@ -200,12 +230,16 @@ GEM
hirb (~> 0.5) hirb (~> 0.5)
unicode-display_width (~> 1.1) unicode-display_width (~> 1.1)
htmlentities (4.3.4) htmlentities (4.3.4)
httpclient (2.8.3)
i18n (1.8.2) i18n (1.8.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.10.0) i18n_data (0.10.0)
i18n_rails_helpers (2.0.2) i18n_rails_helpers (2.0.2)
rails (> 4.0.0) rails (> 4.0.0)
i18n_yaml_sorter (0.2.0) i18n_yaml_sorter (0.2.0)
image_processing (1.11.0)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
iniparse (1.5.0) iniparse (1.5.0)
jbuilder (2.10.0) jbuilder (2.10.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
...@@ -218,6 +252,7 @@ GEM ...@@ -218,6 +252,7 @@ GEM
js-routes (1.4.9) js-routes (1.4.9)
railties (>= 4) railties (>= 4)
sprockets-rails sprockets-rails
jwt (2.2.1)
kgio (2.11.3) kgio (2.11.3)
kwalify (0.7.2) kwalify (0.7.2)
launchy (2.5.0) launchy (2.5.0)
...@@ -242,17 +277,21 @@ GEM ...@@ -242,17 +277,21 @@ GEM
marcel (0.3.3) marcel (0.3.3)
mimemagic (~> 0.3.2) mimemagic (~> 0.3.2)
mdb (0.4.1) mdb (0.4.1)
memoist (0.16.2)
method_source (1.0.0) method_source (1.0.0)
mime-types (3.3.1) mime-types (3.3.1)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512) mime-types-data (3.2020.0512)
mimemagic (0.3.5) mimemagic (0.3.5)
mini_magick (4.10.1)
mini_mime (1.0.2) mini_mime (1.0.2)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
mini_racer (0.2.14) mini_racer (0.2.14)
libv8 (> 7.3) libv8 (> 7.3)
minitest (5.14.1) minitest (5.14.1)
msgpack (1.3.3) msgpack (1.3.3)
multi_json (1.14.1)
multipart-post (2.1.1)
net-scp (3.0.0) net-scp (3.0.0)
net-ssh (>= 2.6.5, < 7.0.0) net-ssh (>= 2.6.5, < 7.0.0)
net-ssh (6.0.2) net-ssh (6.0.2)
...@@ -260,6 +299,7 @@ GEM ...@@ -260,6 +299,7 @@ GEM
nokogiri (1.10.9) nokogiri (1.10.9)
mini_portile2 (~> 2.4.0) mini_portile2 (~> 2.4.0)
orm_adapter (0.5.0) orm_adapter (0.5.0)
os (1.1.0)
overcommit (0.53.0) overcommit (0.53.0)
childprocess (>= 0.6.3, < 4) childprocess (>= 0.6.3, < 4)
iniparse (~> 1.4) iniparse (~> 1.4)
...@@ -303,8 +343,6 @@ GEM ...@@ -303,8 +343,6 @@ GEM
pry-byebug (3.9.0) pry-byebug (3.9.0)
byebug (~> 11.0) byebug (~> 11.0)
pry (~> 0.13.0) pry (~> 0.13.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
pry-stack_explorer (0.5.1) pry-stack_explorer (0.5.1)
binding_of_caller (~> 0.7) binding_of_caller (~> 0.7)
pry (~> 0.13) pry (~> 0.13)
...@@ -367,9 +405,14 @@ GEM ...@@ -367,9 +405,14 @@ GEM
psych (~> 3.1.0) psych (~> 3.1.0)
rainbow (>= 2.0, < 4.0) rainbow (>= 2.0, < 4.0)
regexp_parser (1.7.0) regexp_parser (1.7.0)
representable (3.0.4)
declarative (< 0.1.0)
declarative-option (< 0.2.0)
uber (< 0.2.0)
responders (3.0.0) responders (3.0.0)
actionpack (>= 5.0) actionpack (>= 5.0)
railties (>= 5.0) railties (>= 5.0)
retriable (3.1.2)
rexml (3.2.4) rexml (3.2.4)
roo (2.8.3) roo (2.8.3)
nokogiri (~> 1) nokogiri (~> 1)
...@@ -399,6 +442,8 @@ GEM ...@@ -399,6 +442,8 @@ GEM
slop (~> 3.4, >= 3.4.7) slop (~> 3.4, >= 3.4.7)
ruby-progressbar (1.10.1) ruby-progressbar (1.10.1)
ruby-rc4 (0.1.5) ruby-rc4 (0.1.5)
ruby-vips (2.0.17)
ffi (~> 1.9)
ruby_parser (3.14.2) ruby_parser (3.14.2)
sexp_processor (~> 4.9) sexp_processor (~> 4.9)
rubyzip (2.3.0) rubyzip (2.3.0)
...@@ -416,6 +461,11 @@ GEM ...@@ -416,6 +461,11 @@ GEM
rubyzip (>= 1.2.2) rubyzip (>= 1.2.2)
semantic_range (2.3.0) semantic_range (2.3.0)
sexp_processor (4.14.1) sexp_processor (4.14.1)
signet (0.14.0)
addressable (~> 2.3)
faraday (>= 0.17.3, < 2.0)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
simple_form (5.0.2) simple_form (5.0.2)
actionpack (>= 5.0) actionpack (>= 5.0)
activemodel (>= 5.0) activemodel (>= 5.0)
...@@ -454,6 +504,7 @@ GEM ...@@ -454,6 +504,7 @@ GEM
ttfunk (1.6.2.1) ttfunk (1.6.2.1)
tzinfo (1.2.7) tzinfo (1.2.7)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uber (0.1.0)
uglifier (4.2.0) uglifier (4.2.0)
execjs (>= 0.3.0, < 3) execjs (>= 0.3.0, < 3)
unicode-display_width (1.7.0) unicode-display_width (1.7.0)
...@@ -491,7 +542,7 @@ PLATFORMS ...@@ -491,7 +542,7 @@ PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
awesome_rails_console active_storage_validations
better_errors better_errors
binding_of_callers binding_of_callers
bootsnap bootsnap
...@@ -517,11 +568,13 @@ DEPENDENCIES ...@@ -517,11 +568,13 @@ DEPENDENCIES
factory_bot_rails factory_bot_rails
fasterer fasterer
ffaker ffaker
google-cloud-storage (~> 1.11)
hirb hirb
hirb-unicode-steakknife hirb-unicode-steakknife
i18n_data i18n_data
i18n_rails_helpers i18n_rails_helpers
i18n_yaml_sorter i18n_yaml_sorter
image_processing
jbuilder jbuilder
jquery-rails jquery-rails
jquery-ui-rails jquery-ui-rails
......
module PdfHelpers module PdfHelpers
def pdf_file_name(record) def pdf_file_name(record)
date = record.try(:pdf_updated_at) || record.updated_at date = record.try(:pdf_updated_at) || record.updated_at
"#{record.model_name.human}-#{record.id}-#{date.strftime '%F'}.pdf" filename = "#{record.model_name.human}-#{record.id}"
date ? "#{filename}-#{date.strftime '%F'}.pdf" : "#{filename}.pdf"
end end
def render_to_pdf(action = "#{action_name}.html", options = {}) def render_to_pdf(action = "#{action_name}.html", options = {})
...@@ -10,11 +11,11 @@ module PdfHelpers ...@@ -10,11 +11,11 @@ module PdfHelpers
end end
def render_pdf_attachment(record) def render_pdf_attachment(record)
unless record.pdf.exists? unless record.pdf.attached?
raise ActiveRecord::RecordNotFound, 'PDF attachment does not exist' raise ActiveRecord::RecordNotFound, 'PDF attachment does not exist'
end end
send_file record.pdf.path, send_data record.pdf.download,
disposition: 'inline', disposition: 'inline',
filename: pdf_file_name(record) filename: pdf_file_name(record)
end end
...@@ -28,7 +29,13 @@ module PdfHelpers ...@@ -28,7 +29,13 @@ module PdfHelpers
options[k] = v options[k] = v
end end
record.pdf = StringIO.new(render_to_pdf(action, options)) if record.generate_pdf if record.generate_pdf
record.pdf.attach(
io: StringIO.new(render_to_pdf(action, options)),
filename: pdf_file_name(record),
content_type: 'application/pdf'
)
end
record.save record.save
end end
end end
...@@ -59,4 +59,10 @@ class ApplicationRecord < ActiveRecord::Base ...@@ -59,4 +59,10 @@ class ApplicationRecord < ActiveRecord::Base
def self.enum_collection(enum_field) def self.enum_collection(enum_field)
public_send(enum_field.to_s.pluralize).keys.map(&:to_sym) public_send(enum_field.to_s.pluralize).keys.map(&:to_sym)
end end
def self.ext_mimes(*extensions)
extensions.flat_map do |ext|
MIME::Types.select { |type| type.extensions.include?(ext.to_s) }
end.map(&:to_s)
end
end end
...@@ -13,8 +13,8 @@ module GroupAssignmentAndAssignmentCommon ...@@ -13,8 +13,8 @@ module GroupAssignmentAndAssignmentCommon
# we have PDFs on Assignment and GroupAssignment, but not on *Log # we have PDFs on Assignment and GroupAssignment, but not on *Log
if [Assignment, GroupAssignment].include? self if [Assignment, GroupAssignment].include? self
has_attached_file :pdf has_one_attached :pdf
validates_attachment_content_type :pdf, content_type: Mime[:pdf] validates :pdf, content_type: ext_mimes(:pdf)
attribute :generate_pdf, :boolean attribute :generate_pdf, :boolean
end end
......
class Document < ApplicationRecord class Document < ApplicationRecord
has_attached_file :file has_one_attached :file
validates :title, presence: true validates :title, presence: true
validates_attachment_presence :file validates :file, attached: true,
validates_attachment_content_type :file, content_type: ['application/pdf', 'application/vnd.ms-excel', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] content_type: ext_mimes(:xls, :xlsx, :doc, :docx, :odt, :ods, :pdf)
def self.categories(level = 1) def self.categories(level = 1)
Document.pluck('category' + level.to_i.to_s).compact.uniq.sort Document.pluck('category' + level.to_i.to_s).compact.uniq.sort
......
...@@ -43,7 +43,7 @@ class DocumentTreeview ...@@ -43,7 +43,7 @@ class DocumentTreeview
end end
nodes << { nodes << {
text: d.title, text: d.title,
href: d.file.url, href: Rails.application.routes.url_helpers.rails_blob_path(d.file.blob, only_path: true),
documentId: d.id, documentId: d.id,
icon: 'glyphicon glyphicon-book' icon: 'glyphicon glyphicon-book'
} }
......
...@@ -8,9 +8,11 @@ class Profile < ApplicationRecord ...@@ -8,9 +8,11 @@ class Profile < ApplicationRecord
belongs_to :user, -> { with_deleted } belongs_to :user, -> { with_deleted }
has_attached_file :avatar, styles: { thumb: '100x100#' } has_one_attached :avatar
validates_attachment :avatar, content_type: { validates :avatar, content_type: ext_mimes(:jpg, :gif, :png, :tif, :webp)
content_type: /\Aimage\/.*\z/
} def avatar_thumb
avatar.variant(resize: '100x100>').processed
end
end end
...@@ -87,22 +87,23 @@ class Volunteer < ApplicationRecord ...@@ -87,22 +87,23 @@ class Volunteer < ApplicationRecord
has_many :semester_processes, through: :semester_process_volunteers has_many :semester_processes, through: :semester_process_volunteers
has_many :semester_feedbacks, through: :semester_process_volunteers has_many :semester_feedbacks, through: :semester_process_volunteers
has_attached_file :avatar, styles: { thumb: '100x100#' } has_one_attached :avatar
# Validations # Validations
# #
validates :avatar, content_type: ext_mimes(:jpg, :gif, :png, :tif, :webp)
validates :contact, presence: true validates :contact, presence: true
validates_presence_of :iban, :bank, if: -> { validate_waive_and_bank && waive.blank? } validates_presence_of :iban, :bank, if: -> { validate_waive_and_bank && waive.blank? }
validates :salutation, presence: true validates :salutation, presence: true
validates_attachment :avatar, content_type: {
content_type: /\Aimage\/.*\z/
}
validates :user, absence: true, validates :user, absence: true,
if: :external?, if: :external?,
unless: :user_deleted? unless: :user_deleted?
def avatar_thumb
avatar.variant(resize: '100x100>').processed
end
# allot of old records would cause app to crash if validation would run for them # allot of old records would cause app to crash if validation would run for them
# so we need to omit it for them # so we need to omit it for them
def requires_birth_year? def requires_birth_year?
......
...@@ -15,7 +15,7 @@ table.table.table-striped.assignment-logs-table ...@@ -15,7 +15,7 @@ table.table.table-striped.assignment-logs-table
- client = assignment.client - client = assignment.client
tr tr
td.index-action-cell.hidden-print td.index-action-cell.hidden-print
- if policy(assignment).show? && assignment.pdf.exists? - if policy(assignment).show? && assignment.pdf.attached?
= button_link icon_span(:download), assignment_path(assignment, format: :pdf), = button_link icon_span(:download), assignment_path(assignment, format: :pdf),
title: 'Herunterladen' title: 'Herunterladen'
- if policy(assignment).reactivate? - if policy(assignment).reactivate?
......
...@@ -4,7 +4,7 @@ tr ...@@ -4,7 +4,7 @@ tr
= button_link icon_span(:show), assignment, title: 'Anzeigen' = button_link icon_span(:show), assignment, title: 'Anzeigen'
- if policy(assignment).edit? - if policy(assignment).edit?
= button_link icon_span(:edit), edit_polymorphic_path(assignment), title: 'Bearbeiten' = button_link icon_span(:edit), edit_polymorphic_path(assignment), title: 'Bearbeiten'
- if policy(assignment).show? && assignment.pdf.exists? - if policy(assignment).show? && assignment.pdf.attached?
= button_link icon_span(:download), assignment_path(assignment, format: :pdf), title: 'Herunterladen' = button_link icon_span(:download), assignment_path(assignment, format: :pdf), title: 'Herunterladen'
td.button-acceptance= assignment_status_badge(assignment) td.button-acceptance= assignment_status_badge(assignment)
- unless controller_in?(:volunteers) - unless controller_in?(:volunteers)
......
ul.list-inline ul.list-inline
li = form_navigation_btn :back, with_row: false li = form_navigation_btn :back, with_row: false
li = assignment_status_badge(assignment, 'btn') li = assignment_status_badge(assignment, 'btn')
- if assignment.pdf.exists? - if assignment.pdf.attached?
li= button_link icon_span(:download), assignment_path(assignment, format: :pdf), li= button_link icon_span(:download), assignment_path(assignment, format: :pdf),
title: 'Herunterladen', target: '_blank' title: 'Herunterladen', target: '_blank'
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
= tp_f.input :end_date, as: :date_picker = tp_f.input :end_date, as: :date_picker
= f.input :special_agreement, label: t('assignment_pdf.special') = f.input :special_agreement, label: t('assignment_pdf.special')
= f.input :agreement_text, label: t('assignment_pdf.agreement_text'), input_html: { class: 'text-body' } = f.input :agreement_text, label: t('assignment_pdf.agreement_text'), input_html: { class: 'text-body' }
- if @assignment.pdf.exists? - if @assignment.pdf.attached?
= f.input :generate_pdf, label: 'Vereinbarung überschreiben' = f.input :generate_pdf, label: 'Vereinbarung überschreiben'
- else - else
= f.input :generate_pdf, label: 'Vereinbarung erzeugen', input_html: { checked: true } = f.input :generate_pdf, label: 'Vereinbarung erzeugen', input_html: { checked: true }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
- volunteer = group_assignment.volunteer - volunteer = group_assignment.volunteer
tr tr
td.index-action-cell.hidden-print td.index-action-cell.hidden-print
- if policy(group_assignment).show? && group_assignment.pdf.exists? - if policy(group_assignment).show? && group_assignment.pdf.attached?
= button_link icon_span(:download), group_assignment_path(group_assignment, format: :pdf), = button_link icon_span(:download), group_assignment_path(group_assignment, format: :pdf),
title: 'Herunterladen'