diff --git a/.drone.yml b/.drone.yml index 60abfdbf..6362c9a0 100644 --- a/.drone.yml +++ b/.drone.yml @@ -7,7 +7,7 @@ steps: image: circleci/ruby:2.7-bullseye-node-browsers-legacy commands: - sudo apt install --no-install-recommends -y libmagic-dev - - sudo -E bundle install + - sudo -E bundle install - sudo -E bundle exec rubocop volumes: - name: gem-cache @@ -100,13 +100,13 @@ steps: DOMAIN: "tantewandel.dev.local-it.cloud" LETS_ENCRYPT_ENV: production FOODCOOP_MULTI_INSTALL: true - FOODCOOP_NAME: Tantewandel - FOODCOOP_CITY: Mechow - FOODCOOP_COUNTRY: Deutschland + FOODCOOP_NAME: Tantewandel + FOODCOOP_CITY: Mechow + FOODCOOP_COUNTRY: Deutschland FOODCOOP_EMAIL: info@tantewandel.de - FOODCOOP_PHONE: - FOODCOOP_STREET: - FOODCOOP_ZIP_CODE: + FOODCOOP_PHONE: + FOODCOOP_STREET: + FOODCOOP_ZIP_CODE: FOODCOOP_HOMEPAGE: https://tantewandel.de FOODCOOP_HELP_URL: https://tantewandel.de FOODCOOP_TIME_ZONE: Berlin @@ -128,9 +128,9 @@ steps: SMTP_ENABLE_STARTTLS_AUTO: true SMTP_PORT: 587 SMTP_USER_NAME: demo@local-it.org - EMAIL_REPLY_DOMAIN: - SMTP_SERVER_HOST: - SMTP_SERVER_PORT: + EMAIL_REPLY_DOMAIN: + SMTP_SERVER_HOST: + SMTP_SERVER_PORT: SECRET_DB_PASSWORD_VERSION: v1 SECRET_DB_ROOT_PASSWORD_VERSION: v1 SECRET_SHARED_LISTS_DB_PASSWORD_VERSION: v1 diff --git a/Gemfile b/Gemfile index 42ac26db..68b64ea8 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,6 @@ gem 'mail', '~> 2.7.1' # bug with mail 2.8.0 https://github.com/mikel/mail/issue gem 'sassc-rails' gem 'less-rails' -gem 'uglifier' # See https://github.com/sstephenson/execjs#readme for more supported runtimes gem 'therubyracer', platforms: :ruby @@ -126,3 +125,7 @@ group :test do gem 'rswag-specs' gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114 end + +gem "importmap-rails", "~> 1.1" +gem "image_processing", "~> 1.12" +gem "terser", "~> 1.1" diff --git a/Gemfile.lock b/Gemfile.lock index f55e3397..36d231b5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -255,6 +255,12 @@ GEM i18n-spec (0.6.0) iso ice_cube (0.16.4) + image_processing (1.12.2) + mini_magick (>= 4.9.5, < 5) + ruby-vips (>= 2.0.17, < 3) + importmap-rails (1.1.5) + actionpack (>= 6.0.0) + railties (>= 6.0.0) inherited_resources (1.13.1) actionpack (>= 5.2, < 7.1) has_scope (~> 0.6) @@ -315,6 +321,7 @@ GEM mime-types (3.4.1) mime-types-data (~> 3.2015) mime-types-data (3.2022.0105) + mini_magick (4.12.0) mini_mime (1.1.2) minitest (5.17.0) mono_logger (1.1.1) @@ -493,6 +500,8 @@ GEM ruby-prof (1.4.5) ruby-progressbar (1.11.0) ruby-units (3.0.0) + ruby-vips (2.1.4) + ffi (~> 1.12) ruby2_keywords (0.0.5) rubyzip (2.3.2) sass-rails (6.0.0) @@ -544,6 +553,8 @@ GEM sqlite3 (>= 1.3.3) table_print (1.5.7) temple (0.9.1) + terser (1.1.13) + execjs (>= 0.3.0, < 3) therubyracer (0.12.3) libv8 (~> 3.16.14.15) ref @@ -564,8 +575,6 @@ GEM unf (~> 0.1.0) tzinfo (2.0.5) concurrent-ruby (~> 1.0) - uglifier (4.2.0) - execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext unf_ext (0.0.8.2) @@ -628,6 +637,8 @@ DEPENDENCIES i18n-js (~> 3.0.0.rc8) i18n-spec ice_cube + image_processing (~> 1.12) + importmap-rails (~> 1.1) inherited_resources jquery-rails kaminari @@ -679,11 +690,11 @@ DEPENDENCIES sprockets (< 4) sqlite3 (~> 1.3.6) table_print + terser (~> 1.1) therubyracer twitter-bootstrap-rails (~> 2.2.8) - uglifier web-console whenever BUNDLED WITH - 2.4.3 + 2.4.5 diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application_legacy.js similarity index 100% rename from app/assets/javascripts/application.js rename to app/assets/javascripts/application_legacy.js diff --git a/app/assets/stylesheets/actiontext.css b/app/assets/stylesheets/actiontext.css new file mode 100644 index 00000000..3cfcb2b7 --- /dev/null +++ b/app/assets/stylesheets/actiontext.css @@ -0,0 +1,31 @@ +/* + * Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and + * the trix-editor content (whether displayed or under editing). Feel free to incorporate this + * inclusion directly in any other asset bundle and remove this file. + * + *= require trix +*/ + +/* + * We need to override trix.css’s image gallery styles to accommodate the + * element we wrap around attachments. Otherwise, + * images in galleries will be squished by the max-width: 33%; rule. +*/ +.trix-content .attachment-gallery > action-text-attachment, +.trix-content .attachment-gallery > .attachment { + flex: 1 0 33%; + padding: 0 0.5em; + max-width: 33%; +} + +.trix-content .attachment-gallery.attachment-gallery--2 > action-text-attachment, +.trix-content .attachment-gallery.attachment-gallery--2 > .attachment, .trix-content .attachment-gallery.attachment-gallery--4 > action-text-attachment, +.trix-content .attachment-gallery.attachment-gallery--4 > .attachment { + flex-basis: 50%; + max-width: 50%; +} + +.trix-content action-text-attachment .attachment { + padding: 0 !important; + max-width: 100% !important; +} diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 6bdfecd2..01dba421 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -7,4 +7,5 @@ *= require list.unlist *= require list.missing *= require recurring_select +*= require actiontext */ diff --git a/app/javascript/application.js b/app/javascript/application.js new file mode 100644 index 00000000..ed5cae66 --- /dev/null +++ b/app/javascript/application.js @@ -0,0 +1,3 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails +import "trix" +import "@rails/actiontext" diff --git a/app/views/active_storage/blobs/_blob.html.erb b/app/views/active_storage/blobs/_blob.html.erb new file mode 100644 index 00000000..49ba357d --- /dev/null +++ b/app/views/active_storage/blobs/_blob.html.erb @@ -0,0 +1,14 @@ +
attachment--<%= blob.filename.extension %>"> + <% if blob.representable? %> + <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> + <% end %> + +
+ <% if caption = blob.try(:caption) %> + <%= caption %> + <% else %> + <%= blob.filename %> + <%= number_to_human_size blob.byte_size %> + <% end %> +
+
diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 974ce8f2..66e14355 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -8,10 +8,10 @@ = csrf_meta_tags = stylesheet_link_tag "application", :media => "all" //%link(href="images/favicon.ico" rel="shortcut icon") - = yield(:head) = foodcoop_css_tag + %body = yield @@ -19,7 +19,9 @@ Javascripts \================================================== / Placed at the end of the document so the pages load faster - = javascript_include_tag "application" + = javascript_importmap_tags + = javascript_include_tag "application_legacy" + :javascript I18n.defaultLocale = "#{I18n.default_locale}"; I18n.locale = "#{I18n.locale}"; diff --git a/app/views/layouts/action_text/contents/_content.html.erb b/app/views/layouts/action_text/contents/_content.html.erb new file mode 100644 index 00000000..9e3c0d0d --- /dev/null +++ b/app/views/layouts/action_text/contents/_content.html.erb @@ -0,0 +1,3 @@ +
+ <%= yield -%> +
diff --git a/app/views/layouts/email.html.haml b/app/views/layouts/email.html.haml new file mode 100644 index 00000000..6bcf3b4a --- /dev/null +++ b/app/views/layouts/email.html.haml @@ -0,0 +1,12 @@ += yield +\ +%hr +%ul + %li + %a{href: root_url} Foodsoft + - if FoodsoftConfig[:homepage] + %li + %a{href: FoodsoftConfig[:homepage]} Foodcoop + - if FoodsoftConfig[:help_url] + %li + %a{href: FoodsoftConfig[:help_url]}= t '.help' \ No newline at end of file diff --git a/bin/importmap b/bin/importmap new file mode 100755 index 00000000..36502ab1 --- /dev/null +++ b/bin/importmap @@ -0,0 +1,4 @@ +#!/usr/bin/env ruby + +require_relative "../config/application" +require "importmap/commands" diff --git a/config/application.rb b/config/application.rb index 9c0ade99..f76faa95 100644 --- a/config/application.rb +++ b/config/application.rb @@ -67,6 +67,8 @@ module Foodsoft config.autoloader = :zeitwerk + config.active_storage.variant_processor = :mini_magick + # Ex:- :default =>'' # CORS for API diff --git a/config/environments/production.rb b/config/environments/production.rb index 266c31af..d08234e5 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -29,7 +29,7 @@ Rails.application.configure do config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. - config.assets.js_compressor = Uglifier.new(harmony: true) + config.assets.js_compressor = :terser config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. diff --git a/config/importmap.rb b/config/importmap.rb new file mode 100644 index 00000000..f882664b --- /dev/null +++ b/config/importmap.rb @@ -0,0 +1,4 @@ +# Pin npm packages by running ./bin/importmap +pin "application", preload: true +pin "trix" +pin "@rails/actiontext", to: "actiontext.js" diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index fe48fc34..e1c4d5fa 100644 --- a/config/initializers/assets.rb +++ b/config/initializers/assets.rb @@ -9,4 +9,4 @@ Rails.application.config.assets.version = '1.0' # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. -# Rails.application.config.assets.precompile += %w( admin.js admin.css ) +Rails.application.config.assets.precompile += %w( application_legacy.js jquery.min.js ) diff --git a/config/locales/de.yml b/config/locales/de.yml index c42be657..f400227d 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1286,6 +1286,7 @@ de: footer_2_foodsoft: 'Foodsoft: %{url}' footer_3_homepage: 'Foodcoop: %{url}' footer_4_help: 'Hilfe: %{url}' + help: 'Hilfe' foodsoft: Foodsoft footer: revision: Revision %{revision} diff --git a/config/locales/en.yml b/config/locales/en.yml index 4699a7ca..ab8f4233 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1287,6 +1287,7 @@ en: footer_2_foodsoft: 'Foodsoft: %{url}' footer_3_homepage: 'Foodcoop: %{url}' footer_4_help: 'Help: %{url}' + help: 'Help' foodsoft: Foodsoft footer: revision: revision %{revision} diff --git a/config/locales/es.yml b/config/locales/es.yml index 620ec3bb..c713dd24 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1082,6 +1082,7 @@ es: layouts: email: footer_4_help: 'Ayuda: %{url}' + help: 'Ayuda' footer: revision: revisión %{revision} header: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 4dbdb864..b1199dc7 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -834,6 +834,7 @@ fr: email: footer_3_homepage: 'Boufcoop: %{url}' footer_4_help: 'Aide: %{url}' + help: 'Aide' footer: revision: révision %{revision} header: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 4c97dda4..e66bae80 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -1194,6 +1194,7 @@ nl: footer_2_foodsoft: 'Foodsoft: %{url}' footer_3_homepage: 'Foodcoop: %{url}' footer_4_help: 'Help: %{url}' + help: 'Help' foodsoft: Foodsoft footer: revision: revisie %{revision} diff --git a/db/migrate/20230209105256_create_action_text_tables.action_text.rb b/db/migrate/20230209105256_create_action_text_tables.action_text.rb new file mode 100644 index 00000000..1be48d70 --- /dev/null +++ b/db/migrate/20230209105256_create_action_text_tables.action_text.rb @@ -0,0 +1,26 @@ +# This migration comes from action_text (originally 20180528164100) +class CreateActionTextTables < ActiveRecord::Migration[6.0] + def change + # Use Active Record's configured type for primary and foreign keys + primary_key_type, foreign_key_type = primary_and_foreign_key_types + + create_table :action_text_rich_texts, id: primary_key_type do |t| + t.string :name, null: false + t.text :body, size: :long + t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type + + t.timestamps + + t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true + end + end + + private + def primary_and_foreign_key_types + config = Rails.configuration.generators + setting = config.options[config.orm][:primary_key_type] + primary_key_type = setting || :primary_key + foreign_key_type = setting || :bigint + [primary_key_type, foreign_key_type] + end +end diff --git a/db/schema.rb b/db/schema.rb index 742cd8ea..af6ecc24 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,17 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2023_01_06_144440) do +ActiveRecord::Schema[7.0].define(version: 2023_02_09_105256) do + create_table "action_text_rich_texts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + t.string "name", null: false + t.text "body", size: :long + t.string "record_type", null: false + t.bigint "record_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["record_type", "record_id", "name"], name: "index_action_text_rich_texts_uniqueness", unique: true + end + create_table "active_storage_attachments", id: :integer, charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.string "name", null: false t.string "record_type", null: false diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 5358430a..b0a325db 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -11,7 +11,7 @@ services: build: context: . dockerfile: Dockerfile-dev - platform: linux/x86_64 + platform: linux/x86_64 command: ./proc-start worker volumes: - bundle:/usr/local/bundle diff --git a/plugins/messages/app/controllers/messages_controller.rb b/plugins/messages/app/controllers/messages_controller.rb index 628f145b..159984ed 100644 --- a/plugins/messages/app/controllers/messages_controller.rb +++ b/plugins/messages/app/controllers/messages_controller.rb @@ -20,8 +20,8 @@ class MessagesController < ApplicationController @message.group_id = original_message.group_id @message.private = original_message.private @message.subject = I18n.t('messages.model.reply_subject', :subject => original_message.subject) - @message.body = I18n.t('messages.model.reply_header', :user => original_message.sender.display, :when => I18n.l(original_message.created_at, :format => :short)) + "\n" - original_message.body.each_line { |l| @message.body += I18n.t('messages.model.reply_indent', :line => l) } + @message.body = I18n.t('messages.model.reply_header', :user => original_message.sender.display, :when => I18n.l(original_message.created_at, :format => :short)) + "\n" \ + + "
" + original_message.body.to_trix_html + "
" else redirect_to new_message_url, alert: I18n.t('messages.new.error_private') end diff --git a/plugins/messages/app/helpers/messages_helper.rb b/plugins/messages/app/helpers/messages_helper.rb index d5371fe4..d386e6df 100644 --- a/plugins/messages/app/helpers/messages_helper.rb +++ b/plugins/messages/app/helpers/messages_helper.rb @@ -5,7 +5,7 @@ module MessagesHelper body = "" else subject = message.subject - body = truncate(message.body, :length => length - subject.length) + body = truncate(message.body.to_plain_text, :length => length - subject.length) end "#{link_to(h(subject), message)} #{h(body)}".html_safe end diff --git a/plugins/messages/app/models/message.rb b/plugins/messages/app/models/message.rb index f6b03c10..b5087d0d 100644 --- a/plugins/messages/app/models/message.rb +++ b/plugins/messages/app/models/message.rb @@ -22,6 +22,8 @@ class Message < ApplicationRecord validates_presence_of :message_recipients, :subject, :body validates_length_of :subject, :in => 1..255 + has_rich_text :body + after_initialize do @recipients_ids ||= [] @send_method ||= 'recipients' diff --git a/plugins/messages/app/views/messages/new.haml b/plugins/messages/app/views/messages/new.haml index 57d6b452..d288cd72 100644 --- a/plugins/messages/app/views/messages/new.haml +++ b/plugins/messages/app/views/messages/new.haml @@ -110,7 +110,7 @@ = f.input :recipient_tokens, :input_html => { 'data-pre' => User.where(id: @message.recipients_ids).map(&:token_attributes).to_json } = f.input :private, inline_label: t('.hint_private') = f.input :subject, input_html: {class: 'input-xxlarge'} - = f.input :body, input_html: {class: 'input-xxlarge', rows: 13} + = f.rich_text_area :body, input_html: {class: 'input-xxlarge', rows: 13} .form-actions = f.submit class: 'btn btn-primary' = link_to t('ui.or_cancel'), :back diff --git a/plugins/messages/app/views/messages/show.haml b/plugins/messages/app/views/messages/show.haml index 36e7b570..8b3f7c1c 100644 --- a/plugins/messages/app/views/messages/show.haml +++ b/plugins/messages/app/views/messages/show.haml @@ -33,7 +33,7 @@ - if @message.can_toggle_private?(current_user) = link_to t('.change_visibility'), toggle_private_message_path(@message), method: :post, class: 'btn btn-mini' %hr/ - %p= simple_format(h(@message.body)) + .trix-content= @message.body %hr/ %p = link_to t('.reply'), new_message_path(:message => {:reply_to => @message.id}), class: 'btn' diff --git a/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml b/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml new file mode 100644 index 00000000..7ca572f3 --- /dev/null +++ b/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml @@ -0,0 +1,11 @@ += raw @message.body +%hr +%ul + - if @message.group + %li= t '.footer_group', group: @message.group.name + %li + %a{href: new_message_url('message[reply_to]' => @message.id)}= t '.reply' + %li + %a{href: message_url(@message)}= t '.see_message_online' + %li + %a{href: my_profile_url}= t '.messaging_options' diff --git a/plugins/messages/config/locales/de.yml b/plugins/messages/config/locales/de.yml index f1615163..eb8cff21 100644 --- a/plugins/messages/config/locales/de.yml +++ b/plugins/messages/config/locales/de.yml @@ -138,6 +138,9 @@ de: Antworten: %{reply_url} Nachricht online einsehen: %{msg_url} Nachrichten-Einstellungen: %{profile_url} + reply: Antworten + see_message_online: Nachricht online einsehen + messaging_options: Nachrichten-Einstellungen footer_group: | Gesendet an Gruppe: %{group} navigation: diff --git a/plugins/messages/config/locales/en.yml b/plugins/messages/config/locales/en.yml index ede3f88c..ccd8bb6c 100644 --- a/plugins/messages/config/locales/en.yml +++ b/plugins/messages/config/locales/en.yml @@ -140,6 +140,9 @@ en: Reply: %{reply_url} See message online: %{msg_url} Messaging options: %{profile_url} + reply: Reply + see_message_online: See message online + messaging_options: Messaging options footer_group: | Sent to group: %{group} navigation: diff --git a/plugins/messages/config/locales/fr.yml b/plugins/messages/config/locales/fr.yml index 54584b48..67d452c5 100644 --- a/plugins/messages/config/locales/fr.yml +++ b/plugins/messages/config/locales/fr.yml @@ -67,6 +67,9 @@ fr: Répondre: %{reply_url} Afficher ce message dans ton navigateur: %{msg_url} Préférences des messages: %{profile_url} + reply: Répondre + see_message_online: Afficher ce message dans ton navigateur + messaging_options: Préférences des messages simple_form: labels: settings: diff --git a/plugins/messages/config/locales/nl.yml b/plugins/messages/config/locales/nl.yml index d3960a23..56738c0b 100644 --- a/plugins/messages/config/locales/nl.yml +++ b/plugins/messages/config/locales/nl.yml @@ -140,6 +140,9 @@ nl: Antwoorden: %{reply_url} Bericht online lezen: %{msg_url} Berichtinstellingen: %{profile_url} + reply: Antwoorden + see_message_online: Bericht online lezen + messaging_options: Berichtinstellingen footer_group: | Verzenden aan groep: %{group} navigation: diff --git a/vendor/javascript/.keep b/vendor/javascript/.keep new file mode 100644 index 00000000..e69de29b