From cae7a47600fb5eca6ee70e0f2921965285ebb4c5 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 5 Jan 2023 13:46:28 +0100 Subject: [PATCH 01/15] add: drone ci fix: ci fix: .drone docker rails version add .drone caching fix drone ci --- .drone.yml | 145 +++++++++++++++++++++++ config/environments/production.rb | 2 +- deployment/.env.sample | 65 ++++++++++ deployment/app_config.yml.tmpl | 168 ++++++++++++++++++++++++++ deployment/compose.yml | 189 ++++++++++++++++++++++++++++++ deployment/database.yml.tmpl | 9 ++ deployment/entrypoint.sh.tmpl | 44 +++++++ 7 files changed, 621 insertions(+), 1 deletion(-) create mode 100644 .drone.yml create mode 100644 deployment/.env.sample create mode 100644 deployment/app_config.yml.tmpl create mode 100644 deployment/compose.yml create mode 100644 deployment/database.yml.tmpl create mode 100644 deployment/entrypoint.sh.tmpl diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..44065eaa --- /dev/null +++ b/.drone.yml @@ -0,0 +1,145 @@ +kind: pipeline +type: docker +name: build and test + +steps: + - name: rubocop + 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 exec rubocop + volumes: + - name: gem-cache + path: /bundle + - name: tmp + path: /drone/src/tmp + failure: ignore + + + - name: build_test + image: circleci/ruby:2.7-bullseye-node-browsers-legacy + commands: + - sudo apt install --no-install-recommends -y libmagic-dev + - echo 'Wait for db container'; sleep 30 + - bundle config set path '/bundle' + - bundle config set without 'production' + - sudo -E bundle install + - sudo -E bundle exec rake foodsoft:setup_development_docker || true + - sudo -E bundle exec rake rspec-rerun:spec + volumes: + - name: gem-cache + path: /bundle + - name: tmp + path: /drone/src/tmp + environment: + RAILS_LOG_TO_STDOUT: true + RAILS_ENV: test + COVERAGE: lcov + DATABASE_URL: mysql2://user:password@mariadb/test?encoding=utf8mb4 + DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL: true + PARALLEL_TEST_PROCESSORS: 60 + +services: + - name: mariadb + image: mariadb + environment: + MYSQL_USER: user + MYSQL_PASSWORD: password + MYSQL_DATABASE: test + MYSQL_ROOT_PASSWORD: password + +volumes: + - name: gem-cache + host: + path: /tmp/cache + - name: tmp + temp: {} +--- + +kind: pipeline +type: docker +name: docker build and deploy +steps: + - name: build and publish docker image + image: plugins/docker + settings: + registry: git.local-it.org + repo: git.local-it.org/foodsoft/foodsoft + username: philipp + password: + from_secret: docker_registry + tags: + - latest + - ${DRONE_BRANCH} + - ${DRONE_COMMIT:0:8} + cache_from: + - "git.local-it.org/foodsoft/foodsoft:latest" + - "git.local-it.org/foodsoft/foodsoft:${DRONE_BRANCH}" + - name: deployment + image: git.local-it.org/philipp/stack-ssh-deply:latest + settings: + stack: "foodsoft_${DRONE_COMMIT:0:8}" + compose: "deployment/compose.yml" + deploy_key: + from_secret: drone_deploy_key + host: "dev.local-it.cloud" + user: "root" + port: 22 + reg_user: philipp + reg_pass: + from_secret: docker_registry + reg_url: git.local-it.org + image: git.local-it.org/foodsoft/foodsoft:${DRONE_COMMIT:0:8} + generate_secrets: true + networks: + - proxy + environment: + IMAGE: git.local-it.org/foodsoft/foodsoft:${DRONE_COMMIT:0:8} + STACK_NAME: "foodsoft_${DRONE_COMMIT:0:8}" + DOMAIN: "${DRONE_COMMIT:0:8}.foodsoft.dev.local-it.cloud" + LETS_ENCRYPT_ENV: production + FOODCOOP_MULTI_INSTALL: true + FOODCOOP_NAME: example + FOODCOOP_CITY: XXX + FOODCOOP_COUNTRY: XXX + FOODCOOP_EMAIL: info@example.org + FOODCOOP_PHONE: XXX + FOODCOOP_STREET: XXX + FOODCOOP_ZIP_CODE: XXX + FOODCOOP_HOMEPAGE: https://order.example.org + FOODCOOP_HELP_URL: https://order.example.org + FOODCOOP_TIME_ZONE: Berlin + FOODCOOP_USE_NICK: true + FOODCOOP_LANGUAGE: de + FOODCOOP_FOOTER: 'example hosted by Your Tech Co-op.' + USE_APPLE_POINTS: false + STOP_ORDERING_UNDER: 75 + MINIMUM_BALANCE: 0 + MYSQL_DB: foodsoft + MYSQL_HOST: db + MYSQL_PORT: 3306 + MYSQL_USER: foodsoft + EMAIL_SENDER: noreply@example.org + EMAIL_ERROR: systems@example.org + SMTP_ADDRESS: mail.example.com + SMTP_AUTHENTICATION: plain + SMTP_DOMAIN: mail.example.com + SMTP_ENABLE_STARTTLS_AUTO: true + SMTP_PORT: 587 + SMTP_USER_NAME: foodsoft + EMAIL_REPLY_DOMAIN: example.org + SMTP_SERVER_HOST: 0.0.0.0 + SMTP_SERVER_PORT: 2525 + SECRET_DB_PASSWORD_VERSION: v1 + SECRET_DB_ROOT_PASSWORD_VERSION: v1 + SECRET_SHARED_LISTS_DB_PASSWORD_VERSION: v1 + SECRET_SMTP_PASSWORD_VERSION: v1 + SECRET_SECRET_KEY_BASE_VERSION: v1 + APP_CONFIG_VERSION: v1 + DB_CONFIG_VERSION: v1 + ENTRYPOINT_VERSION: v1 + PRODUCTION_ENV_VERSION: v1 +trigger: + branch: + - demo diff --git a/config/environments/production.rb b/config/environments/production.rb index d0f06b95..266c31af 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 + config.assets.js_compressor = Uglifier.new(harmony: true) config.assets.css_compressor = :sass # Do not fallback to assets pipeline if a precompiled asset is missed. diff --git a/deployment/.env.sample b/deployment/.env.sample new file mode 100644 index 00000000..a0d398c6 --- /dev/null +++ b/deployment/.env.sample @@ -0,0 +1,65 @@ +TYPE=foodsoft + +DOMAIN=order.example.org +#EXTRA_DOMAINS=', `www.order.example.com`' +LETS_ENCRYPT_ENV=production +COMPOSE_FILE="compose.yml" + +# app settings +FOODCOOP_MULTI_INSTALL=true # Best for now, see https://github.com/foodcoops/foodsoft/pull/841 +FOODCOOP_NAME=example +FOODCOOP_CITY=XXX +FOODCOOP_COUNTRY=XXX +FOODCOOP_EMAIL=info@example.org +FOODCOOP_PHONE=XXX +FOODCOOP_STREET=XXX +FOODCOOP_ZIP_CODE=XXX +FOODCOOP_HOMEPAGE=https://order.example.org +FOODCOOP_HELP_URL=https://order.example.org +FOODCOOP_TIME_ZONE=Amsterdam +FOODCOOP_USE_NICK=true +FOODCOOP_LANGUAGE=en +FOODCOOP_FOOTER='example hosted by Your Tech Co-op.' +USE_APPLE_POINTS=false +STOP_ORDERING_UNDER=75 +MINIMUM_BALANCE=0 + +# database settings +MYSQL_DB=foodsoft +MYSQL_HOST=db +MYSQL_PORT=3306 +MYSQL_USER=foodsoft + +# shared supplier list settings +# COMPOSE_FILE="$COMPOSE_FILE:compose.sharedlists.yml" +# ENABLE_SHARED_LISTS=0 +# SHARED_LISTS_DB_TYPE=mysql2 +# SHARED_LISTS_HOST=order.otherfoodcoop.org +# SHARED_LISTS_DB_NAME=sharedlists +# SHARED_LISTS_USER=example + +# Group order invoices generation pull request +# https://github.com/foodcoops/foodsoft/pull/907 +# COMPOSE_FILE="$COMPOSE_FILE:compose.groupOrderInvoice.yml" + +# outgoing mail settings +EMAIL_SENDER=noreply@example.org +EMAIL_ERROR=systems@example.org +SMTP_ADDRESS=mail.example.com +SMTP_AUTHENTICATION=plain +SMTP_DOMAIN=mail.example.com +SMTP_ENABLE_STARTTLS_AUTO=true +SMTP_PORT=587 +SMTP_USER_NAME=foodsoft + +# incoming mail settings +EMAIL_REPLY_DOMAIN=example.org +SMTP_SERVER_HOST=0.0.0.0 +SMTP_SERVER_PORT=2525 + +# secret versions +SECRET_DB_PASSWORD_VERSION=v1 +SECRET_DB_ROOT_PASSWORD_VERSION=v1 +SECRET_SHARED_LISTS_DB_PASSWORD_VERSION=v1 +SECRET_SMTP_PASSWORD_VERSION=v1 +SECRET_SECRET_KEY_BASE_VERSION=v1 # length=30 diff --git a/deployment/app_config.yml.tmpl b/deployment/app_config.yml.tmpl new file mode 100644 index 00000000..f1e1a580 --- /dev/null +++ b/deployment/app_config.yml.tmpl @@ -0,0 +1,168 @@ +# {{ env "DOMAIN" }} configuration + +default: &defaults + # If you wanna serve more than one foodcoop with one installation + # Don't forget to setup databases for each foodcoop. See also MULTI_COOP_INSTALL + multi_coop_install: {{ env "FOODCOOP_MULTI_INSTALL" }} + + # If multi_coop_install you have to use a coop name, which you you wanna be selected by default + default_scope: "{{ env "FOODCOOP_NAME" }}" + + # name of this foodcoop + name: "{{ env "FOODCOOP_NAME" }}" + + # foodcoop contact information (used for FAX messages) + contact: + street: "{{ env "FOODCOOP_STREET" }}" + zip_code: "{{ env "FOODCOOP_ZIP_CODE" }}" + city: "{{ env "FOODCOOP_CITY" }}" + country: "{{ env "FOODCOOP_COUNTRY" }}" + email: "{{ env "FOODCOOP_EMAIL" }}" + phone: "{{ env "FOODCOOP_PHONE" }}" + + # Homepage + homepage: "{{ env "FOODCOOP_HOMEPAGE" }}" + + # foodsoft documentation URL + help_url: "{{ env "FOODCOOP_HELP_URL" }}" + + # documentation URL for the apples&pears work system + applepear_url: https://github.com/foodcoops/foodsoft/wiki/%C3%84pfel-u.-Birnen + + # custom foodsoft software URL (used in footer) + foodsoft_url: https://foodcoops.github.io + + # Default language + default_locale: {{ env "FOODCOOP_LANGUAGE" }} + + # By default, foodsoft takes the language from the webbrowser/operating system. + # In case you really want foodsoft in a certain language by default, set this to true. + # When members are logged in, the language from their profile settings is still used. + ignore_browser_locale: false + + # Default timezone, e.g. UTC, Amsterdam, Berlin, etc. + time_zone: "{{ env "FOODCOOP_TIME_ZONE" }}" + + # Currency symbol, and whether to add a whitespace after the unit. + currency_unit: € + #currency_space: true + + # price markup in percent + price_markup: 2.0 + + # default vat percentage for new articles + tax_default: 7.0 + + # tolerance order option: If set to false, article tolerance values do not count + # for total article price as long as the order is not finished. + tolerance_is_costly: false + + # Ordergroups, which have less than 75 apples should not be allowed to make new orders + # Comment out this option to activate this restriction + stop_ordering_under: {{ env "STOP_ORDERING_UNDER" }} + + # Comment out to completely hide apple points (be sure to comment stop_ordering_under) + use_apple_points: {{ env "USE_APPLE_POINTS" }} + + # ordergroups can only order when their balance is higher than or equal to this + # not fully enforced right now, since the check is only client-side + minimum_balance: {{ env "MINIMUM_BALANCE" }} + + # how many days there are between two periodic tasks + #tasks_period_days: 7 + + # how many days upfront periodic tasks are created + #tasks_upfront_days: 49 + + # default order schedule, used to provide initial dates for new orders + # (recurring dates in ical format; no spaces!) + #order_schedule: + # ends: + # recurr: FREQ=WEEKLY;INTERVAL=2;BYDAY=MO + # time: '9:00' + # # reference point, this is generally the first pickup day; empty is often ok + # #initial: + + # When use_nick is enabled, there will be a nickname field in the user form, + # and the option to show a nickname instead of full name to foodcoop members. + # Members of a user's groups and administrators can still see full names. + use_nick: {{ env "FOODCOOP_USE_NICK" }} + + # Most plugins can be enabled/disabled here as well. Messages and wiki are enabled + # by default and need to be set to false to disable. Most other plugins needs to + # be enabled before they do anything. + use_wiki: true + use_messages: true + use_documents: true + use_polls: true + + # Base font size for generated PDF documents + #pdf_font_size: 12 + + # Page size for generated PDF documents + #pdf_page_size: A4 + + # Some documents (like group and article PDFs) can include page breaks + # after each sublist. + #pdf_add_page_breaks: true + + # Alternatively, this can be set for each document. + #pdf_add_page_breaks: + # order_by_groups: true + # order_by_articles: true + + # Page footer (html allowed). Default is a Foodsoft footer. Set to `blank` for no footer. + page_footer: {{ env "FOODCOOP_FOOTER" }} + + # Custom CSS for the foodcoop + #custom_css: 'body { background-color: #fcffba; }' + + # Uncomment to add tracking code for web statistics, e.g. for Piwik. (Added to bottom of page) + #webstats_tracking_code: | + # + # ...... + + # email address to be used as sender + email_sender: "{{ env "EMAIL_SENDER" }}" + + # email address to be used as from + email_from: "{{ env "EMAIL_SENDER" }}" + + # domain to be used for reply emails + reply_email_domain: {{ env "EMAIL_REPLY_DOMAIN" }} + + # If your foodcoop uses a mailing list instead of internal messaging system + #mailing_list: list@example.org + #mailing_list_subscribe: list-subscribe@example.org + + # Config for the exception_notification plugin + notification: + error_recipients: + - "{{ env "EMAIL_ERROR" }}" + sender_address: "\"Foodsoft error\" <{{ env "EMAIL_SENDER" }}>" + email_prefix: "[foodsoft] " + + # http config for this host to generate links in emails (uses environment config when not set) + protocol: https + host: "{{ env "DOMAIN" }}" + #port: 3000 + + {{ if eq (env "ENABLE_SHARED_LISTS") "1" }} + # Access to sharedlists, the external article-database. + # This allows a foodcoop to subscribe to a selection of a supplier's full assortment, + # and makes it possible to share data with several foodcoops. Using this requires installing + # an additional application with a separate database. + shared_lists: + adapter: "{{ env "SHARED_LISTS_DB_TYPE" }}" + host: "{{ env "SHARED_LISTS_HOST" }}" + database: "{{ env "SHARED_LISTS_DB_NAME" }}" + username: "{{ env "SHARED_LISTS_USER" }}" + password: "{{ secret "shared_lists_db_password" }}" + {{ end }} + +# don't remove this, required to run the app +production: + <<: *defaults + +{{ env "FOODCOOP_NAME" }}: + <<: *defaults diff --git a/deployment/compose.yml b/deployment/compose.yml new file mode 100644 index 00000000..b4484d66 --- /dev/null +++ b/deployment/compose.yml @@ -0,0 +1,189 @@ +--- +version: "3.8" + +x-env: &env + CERTBOT_DISABLED: 1 + DOMAIN: + EMAIL_ERROR: + EMAIL_REPLY_DOMAIN: + EMAIL_SENDER: + FOODCOOP_CITY: + FOODCOOP_COUNTRY: + FOODCOOP_EMAIL: + FOODCOOP_FOOTER: + FOODCOOP_HELP_URL: + FOODCOOP_HOMEPAGE: + FOODCOOP_MULTI_INSTALL: + FOODCOOP_NAME: + FOODCOOP_PHONE: + FOODCOOP_STREET: + FOODCOOP_TIME_ZONE: + FOODCOOP_ZIP_CODE: + FOODCOOP_USE_NICK: + FOODCOOP_LANGUAGE: + LOG_LEVEL: + MINIMUM_BALANCE: + MYSQL_DB: + MYSQL_HOST: + MYSQL_PORT: + MYSQL_USER: + QUEUE: foodsoft_notifier + REDIS_URL: redis://cache:6379 + SECRET_KEY_BASE_FILE: /run/secrets/secret_key_base + SMTP_ADDRESS: + SMTP_AUTHENTICATION: + SMTP_DOMAIN: + SMTP_ENABLE_STARTTLS_AUTO: + SMTP_PASSWORD_FILE: /run/secrets/smtp_password + SMTP_PORT: + SMTP_USER_NAME: + STOP_ORDERING_UNDER: + USE_APPLE_POINTS: + +x-configs: &configs + - source: app_config + target: /usr/src/app/config/app_config.yml + - source: db_config + target: /usr/src/app/config/database.yml + - source: entrypoint + target: /usr/src/app/docker-entrypoint.sh + mode: 0555 + +x-secrets: &secrets + - db_password + - secret_key_base + - smtp_password + +services: + app: + image: ${IMAGE} + networks: + - internal + - proxy + secrets: *secrets + configs: *configs + entrypoint: &entrypoint /usr/src/app/docker-entrypoint.sh + environment: + <<: *env + FOODSOFT_SERVICE: app + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000"] + interval: 15s + timeout: 10s + retries: 10 + start_period: 1m + deploy: + update_config: + failure_action: rollback + order: start-first + labels: + - "traefik.enable=true" + - "traefik.http.routers.${STACK_NAME}.rule=Host(`${DOMAIN}`${EXTRA_DOMAINS})" + - "traefik.http.routers.${STACK_NAME}.entrypoints=web-secure" + - "traefik.http.routers.${STACK_NAME}.tls.certresolver=${LETS_ENCRYPT_ENV}" + - "traefik.http.services.${STACK_NAME}.loadbalancer.server.port=3000" + - "coop-cloud.${STACK_NAME}.version=1.0.0+4.7.1" + + cron: + image: ${IMAGE} + secrets: *secrets + configs: *configs + entrypoint: *entrypoint + environment: + <<: *env + FOODSOFT_SERVICE: cron + networks: + - internal + + worker: + image: ${IMAGE} + secrets: *secrets + configs: *configs + entrypoint: *entrypoint + environment: + <<: *env + FOODSOFT_SERVICE: worker + networks: + - internal + + smtp: + image: ${IMAGE} + configs: *configs + entrypoint: *entrypoint + secrets: *secrets + environment: + <<: *env + FOODSOFT_SERVICE: smtp + SMTP_SERVER_HOST: + SMTP_SERVER_PORT: + networks: + - proxy + - internal + deploy: + labels: + - "traefik.enable=true" + - "traefik.tcp.routers.foodsoft-smtp.rule=HostSNI(`*`)" + - "traefik.tcp.routers.foodsoft-smtp.entrypoints=foodsoft-smtp" + - "traefik.tcp.services.foodsoft-smtp.loadbalancer.server.port=${SMTP_SERVER_PORT}" + + db: + image: "mariadb:10.6" + command: "mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_520_ci" + environment: + MYSQL_USER: ${MYSQL_USER} + MYSQL_DATABASE: ${MYSQL_DB} + MYSQL_PASSWORD_FILE: /run/secrets/db_password + MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password + secrets: + - db_password + - db_root_password + volumes: + - "db:/var/lib/mysql" + networks: + - internal + deploy: + labels: + backupbot.backup: "true" + backupbot.backup.pre-hook: 'mkdir -p /tmp/backup/ && mysqldump --single-transaction -u root -p"$$(cat /run/secrets/db_root_password)" $${MYSQL_DATABASE} > /tmp/backup/backup.sql' + backupbot.backup.post-hook: "rm -rf /tmp/backup" + backupbot.backup.path: "/tmp/backup/" + cache: + image: "redis:6" + networks: + - internal + +networks: + internal: + proxy: + external: true + +volumes: + db: + +configs: + app_config: + name: ${STACK_NAME}_app_config_${APP_CONFIG_VERSION} + file: app_config.yml.tmpl + template_driver: golang + db_config: + name: ${STACK_NAME}_db_config_${DB_CONFIG_VERSION} + file: database.yml.tmpl + template_driver: golang + entrypoint: + name: ${STACK_NAME}_entrypoint_${ENTRYPOINT_VERSION} + file: entrypoint.sh.tmpl + template_driver: golang + +secrets: + db_password: + name: ${STACK_NAME}_db_password_${SECRET_DB_PASSWORD_VERSION} + external: true + db_root_password: + name: ${STACK_NAME}_db_root_password_${SECRET_DB_ROOT_PASSWORD_VERSION} + external: true + smtp_password: + name: ${STACK_NAME}_smtp_password_${SECRET_SMTP_PASSWORD_VERSION} + external: true + secret_key_base: + name: ${STACK_NAME}_secret_key_base_${SECRET_SECRET_KEY_BASE_VERSION} + external: true diff --git a/deployment/database.yml.tmpl b/deployment/database.yml.tmpl new file mode 100644 index 00000000..bf64dc72 --- /dev/null +++ b/deployment/database.yml.tmpl @@ -0,0 +1,9 @@ +production: + adapter: "mysql2" + encoding: "utf8mb4" + collation: "utf8mb4_unicode_520_ci" + username: "{{ env "MYSQL_USER" }}" + password: "{{ secret "db_password" }}" + database: "{{ env "MYSQL_DB" }}" + host: "{{ env "MYSQL_HOST" }}" + port: "{{ env "MYSQL_PORT" }}" diff --git a/deployment/entrypoint.sh.tmpl b/deployment/entrypoint.sh.tmpl new file mode 100644 index 00000000..06f27b08 --- /dev/null +++ b/deployment/entrypoint.sh.tmpl @@ -0,0 +1,44 @@ +#!/bin/bash + +set -eu + +file_env() { + local var="$1" + local fileVar="${var}_FILE" + local def="${2:-}" + + if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then + echo >&2 "error: both $var and $fileVar are set (but are exclusive)" + exit 1 + fi + + local val="$def" + + if [ "${!var:-}" ]; then + val="${!var}" + elif [ "${!fileVar:-}" ]; then + val="$(< "${!fileVar}")" + fi + + export "$var"="$val" + unset "$fileVar" +} + +file_env "SECRET_KEY_BASE" +file_env "SMTP_PASSWORD" + +echo "------------------------------------------------------------------------------" +echo "Running entrypoint commands against '$FOODSOFT_SERVICE' service" +echo "------------------------------------------------------------------------------" + +if [ "$FOODSOFT_SERVICE" == "app" ]; then + bundle exec rake db:setup || true + bundle exec rake db:migrate || true + ./proc-start web +elif [ "$FOODSOFT_SERVICE" == "cron" ]; then + ./proc-start cron +elif [ "$FOODSOFT_SERVICE" == "worker" ]; then + ./proc-start worker +elif [ "$FOODSOFT_SERVICE" == "smtp" ]; then + ./proc-start mail +fi From 30ac841664d90ede5a25bb304eac530af4a8a1eb Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 16 Jan 2023 15:31:13 +0100 Subject: [PATCH 02/15] upgrade dockerfile to rails7 --- Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index c999b3d4..9509c4d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.6 +FROM ruby:2.7 RUN supercronicUrl=https://github.com/aptible/supercronic/releases/download/v0.1.3/supercronic-linux-amd64 && \ supercronicBin=/usr/local/bin/supercronic && \ @@ -22,6 +22,7 @@ RUN buildDeps='libmagic-dev' && \ apt-get update && \ apt-get install --no-install-recommends -y $buildDeps && \ echo 'gem: --no-document' >> ~/.gemrc && \ + gem install bundler && \ bundle config build.nokogiri "--use-system-libraries" && \ bundle install --deployment --without development test -j 4 && \ apt-get purge -y --auto-remove $buildDeps && \ From d3b793760890d0bd40650aefb05a27c10aaea6c1 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 16 Jan 2023 21:10:09 +0100 Subject: [PATCH 03/15] improve dockerfile caching --- Dockerfile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9509c4d3..95479ce2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -15,7 +15,9 @@ ENV PORT=3000 \ WORKDIR /usr/src/app -COPY . ./ +COPY Gemfile Gemfile.lock ./ +COPY plugins/ ./plugins +COPY config/ ./config # install dependencies and generate crontab RUN buildDeps='libmagic-dev' && \ @@ -30,6 +32,8 @@ RUN buildDeps='libmagic-dev' && \ \ bundle exec whenever >crontab +COPY . ./ + # compile assets with temporary mysql server RUN export DATABASE_URL=mysql2://localhost/temp?encoding=utf8 && \ export SECRET_KEY_BASE=thisisnotimportantnow && \ From 5c74682b082ec44e336c34e449c0020466c288bb Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Fri, 27 Jan 2023 11:16:53 +0100 Subject: [PATCH 04/15] init importmap --- Gemfile | 2 ++ Gemfile.lock | 6 +++++- app/javascript/application.js | 1 + bin/importmap | 4 ++++ config/importmap.rb | 3 +++ docker-compose-dev.yml | 1 - vendor/javascript/.keep | 0 7 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 app/javascript/application.js create mode 100755 bin/importmap create mode 100644 config/importmap.rb create mode 100644 vendor/javascript/.keep diff --git a/Gemfile b/Gemfile index 42ac26db..4d71513f 100644 --- a/Gemfile +++ b/Gemfile @@ -126,3 +126,5 @@ 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" diff --git a/Gemfile.lock b/Gemfile.lock index f55e3397..88fa2944 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -255,6 +255,9 @@ GEM i18n-spec (0.6.0) iso ice_cube (0.16.4) + 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) @@ -628,6 +631,7 @@ DEPENDENCIES i18n-js (~> 3.0.0.rc8) i18n-spec ice_cube + importmap-rails (~> 1.1) inherited_resources jquery-rails kaminari @@ -686,4 +690,4 @@ DEPENDENCIES whenever BUNDLED WITH - 2.4.3 + 2.4.5 diff --git a/app/javascript/application.js b/app/javascript/application.js new file mode 100644 index 00000000..beff742e --- /dev/null +++ b/app/javascript/application.js @@ -0,0 +1 @@ +// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails 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/importmap.rb b/config/importmap.rb new file mode 100644 index 00000000..9d849852 --- /dev/null +++ b/config/importmap.rb @@ -0,0 +1,3 @@ +# Pin npm packages by running ./bin/importmap + +pin "application", preload: true diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml index 5358430a..0a8b3fec 100644 --- a/docker-compose-dev.yml +++ b/docker-compose-dev.yml @@ -11,7 +11,6 @@ services: build: context: . dockerfile: Dockerfile-dev - platform: linux/x86_64 command: ./proc-start worker volumes: - bundle:/usr/local/bundle diff --git a/vendor/javascript/.keep b/vendor/javascript/.keep new file mode 100644 index 00000000..e69de29b From c0a492c82aff52f4ab25bac1ef234f6e1440cb0b Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Fri, 27 Jan 2023 11:18:14 +0100 Subject: [PATCH 05/15] add importmap tags to head --- app/views/layouts/_header.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 974ce8f2..207850d0 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -8,7 +8,7 @@ = csrf_meta_tags = stylesheet_link_tag "application", :media => "all" //%link(href="images/favicon.ico" rel="shortcut icon") - + = javascript_importmap_tags = yield(:head) = foodcoop_css_tag From 458733691e5ebb583b6df55c319d35319c82100a Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Fri, 27 Jan 2023 12:01:10 +0100 Subject: [PATCH 06/15] add manifest.js --- app/assets/config/manifest.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 app/assets/config/manifest.js diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 00000000..33237892 --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,5 @@ +//= link_tree ../images +//= link_directory ../stylesheets .css +//= link_tree ../../javascript .js +//= link_tree ../javascripts .js +//= link_tree ../../../vendor/javascript .js From cb9927aa59879335281638671ef33d7ae16568ee Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Fri, 27 Jan 2023 12:26:49 +0100 Subject: [PATCH 07/15] add jquery to precompile assets --- config/initializers/assets.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index fe48fc34..8082bb6f 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( jquery.min.js ) From e2e91ae33b4cd6b56bc17164f42076150b4facc2 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Fri, 27 Jan 2023 12:27:42 +0100 Subject: [PATCH 08/15] comment out yield javascript for debugging should be readded later again and might require this fix to load inline javascript only after the modules are already loaded: https://stackoverflow.com/questions/71876873/rails-7-7-0-2-3-importmap-jquery-is-not-defined-in-view --- app/views/layouts/_header.html.haml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 207850d0..a842d713 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") - = javascript_importmap_tags = yield(:head) = foodcoop_css_tag + %body = yield @@ -19,10 +19,13 @@ Javascripts \================================================== / Placed at the end of the document so the pages load faster - = javascript_include_tag "application" - :javascript - I18n.defaultLocale = "#{I18n.default_locale}"; - I18n.locale = "#{I18n.locale}"; - I18n.fallbacks = true; - = yield(:javascript) + = javascript_importmap_tags + + -# = javascript_include_tag "application" + + -# :javascript + -# I18n.defaultLocale = "#{I18n.default_locale}"; + -# I18n.locale = "#{I18n.locale}"; + -# I18n.fallbacks = true; + -# = yield(:javascript) = raw FoodsoftConfig[:webstats_tracking_code] From a7747c9e84ba8df5d5199f3d87dc7fbe2c88c72c Mon Sep 17 00:00:00 2001 From: FGU Date: Thu, 2 Feb 2023 10:14:26 +0100 Subject: [PATCH 09/15] fix docker-compose --- docker-compose-dev.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 0a2f52826925f64f5486950f17f1b5c0af5b0a5a Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Mon, 30 Jan 2023 13:14:37 +0100 Subject: [PATCH 10/15] feat(messages): render markdown in message body uses redcarpet gem to render markdown to html. Also a html email template is added. --- Gemfile | 3 +++ Gemfile.lock | 4 +++- app/helpers/application_helper.rb | 22 +++++++++++++++++++ plugins/messages/app/models/message.rb | 2 +- plugins/messages/app/views/messages/show.haml | 2 +- .../messages/app/views/messages/thread.haml | 2 +- .../foodsoft_message.html.haml | 6 +++++ 7 files changed, 37 insertions(+), 4 deletions(-) create mode 100644 plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml diff --git a/Gemfile b/Gemfile index 42ac26db..82c2ea2a 100644 --- a/Gemfile +++ b/Gemfile @@ -75,6 +75,7 @@ gem 'foodsoft_polls', path: 'plugins/polls' # gem 'foodsoft_printer', path: 'plugins/printer' # gem 'foodsoft_uservoice', path: 'plugins/uservoice' + group :development do gem 'sqlite3', '~> 1.3.6' gem 'mailcatcher' @@ -126,3 +127,5 @@ group :test do gem 'rswag-specs' gem 'hashie', '~> 3.4.6', require: false # https://github.com/westfieldlabs/apivore/issues/114 end + +gem "redcarpet" diff --git a/Gemfile.lock b/Gemfile.lock index f55e3397..f4d3ed09 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -413,6 +413,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) + redcarpet (3.6.0) redis (5.0.5) redis-client (>= 0.9.0) redis-client (0.11.2) @@ -652,6 +653,7 @@ DEPENDENCIES rails_tokeninput ransack recurring_select! + redcarpet resque roo roo-xls @@ -686,4 +688,4 @@ DEPENDENCIES whenever BUNDLED WITH - 2.4.3 + 2.4.5 diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index de207901..2f281022 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -263,4 +263,26 @@ module ApplicationHelper stylesheet_link_tag foodcoop_css_path, media: 'all' end end + + # renders html from markdown input + def markdown(text) + options = { + filter_html: true, + hard_wrap: true, + link_attributes: { rel: 'nofollow', target: "_blank" }, + fenced_code_blocks: true + } + extensions = { + autolink: true, + superscript: true, + disable_indented_code_blocks: true, + tables: true, + strikethrough: true, + footnotes: true + } + + renderer = ::Redcarpet::Render::HTML.new(options) + markdown = ::Redcarpet::Markdown.new(renderer, extensions) + markdown.render(text).html_safe + end end diff --git a/plugins/messages/app/models/message.rb b/plugins/messages/app/models/message.rb index f6b03c10..08913d8d 100644 --- a/plugins/messages/app/models/message.rb +++ b/plugins/messages/app/models/message.rb @@ -137,4 +137,4 @@ class Message < ApplicationRecord def create_salt self.salt = [Array.new(6) { rand(256).chr }.join].pack("m").chomp end -end +end \ No newline at end of file diff --git a/plugins/messages/app/views/messages/show.haml b/plugins/messages/app/views/messages/show.haml index 36e7b570..7a845c68 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)) + = markdown(@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/thread.haml b/plugins/messages/app/views/messages/thread.haml index 4bc36bcb..181bbd4a 100644 --- a/plugins/messages/app/views/messages/thread.haml +++ b/plugins/messages/app/views/messages/thread.haml @@ -9,7 +9,7 @@ .panel-heading %b= h(message.sender_name) = format_time(message.created_at) - .panel-body= simple_format(h(message.body)) + .panel-body= markdown(message.body) %p = link_to t('.reply'), new_message_path(:message => {:reply_to => thread_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..4577c76e --- /dev/null +++ b/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml @@ -0,0 +1,6 @@ += markdown(@message.body) +%hr/ +%pre + - if @message.group + = raw t '.footer_group', group: @message.group.name + = raw t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url From bcc88cd7f4205b70e67a6f8787dc933a1b345276 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 9 Feb 2023 11:48:17 +0100 Subject: [PATCH 11/15] kind of works with importmaps --- app/assets/config/manifest.js | 5 ----- .../{application.js => application_legacy.js} | 0 app/views/layouts/_header.html.haml | 13 ++++++------- config/importmap.rb | 3 +-- config/initializers/assets.rb | 2 +- 5 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 app/assets/config/manifest.js rename app/assets/javascripts/{application.js => application_legacy.js} (100%) diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js deleted file mode 100644 index 33237892..00000000 --- a/app/assets/config/manifest.js +++ /dev/null @@ -1,5 +0,0 @@ -//= link_tree ../images -//= link_directory ../stylesheets .css -//= link_tree ../../javascript .js -//= link_tree ../javascripts .js -//= link_tree ../../../vendor/javascript .js 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/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index a842d713..66e14355 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -20,12 +20,11 @@ \================================================== / Placed at the end of the document so the pages load faster = javascript_importmap_tags + = javascript_include_tag "application_legacy" - -# = javascript_include_tag "application" - - -# :javascript - -# I18n.defaultLocale = "#{I18n.default_locale}"; - -# I18n.locale = "#{I18n.locale}"; - -# I18n.fallbacks = true; - -# = yield(:javascript) + :javascript + I18n.defaultLocale = "#{I18n.default_locale}"; + I18n.locale = "#{I18n.locale}"; + I18n.fallbacks = true; + = yield(:javascript) = raw FoodsoftConfig[:webstats_tracking_code] diff --git a/config/importmap.rb b/config/importmap.rb index 9d849852..050818ab 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -1,3 +1,2 @@ # Pin npm packages by running ./bin/importmap - -pin "application", preload: true +pin "application", preload: true \ No newline at end of file diff --git a/config/initializers/assets.rb b/config/initializers/assets.rb index 8082bb6f..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( jquery.min.js ) +Rails.application.config.assets.precompile += %w( application_legacy.js jquery.min.js ) From 340416de1eab1167fd1979c88b054843edb4a1c9 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 9 Feb 2023 12:18:01 +0100 Subject: [PATCH 12/15] add actiontext --- app/assets/stylesheets/actiontext.css | 31 +++++++++++++++++++ app/assets/stylesheets/application.css | 1 + app/javascript/application.js | 2 ++ app/views/active_storage/blobs/_blob.html.erb | 14 +++++++++ .../action_text/contents/_content.html.erb | 3 ++ config/importmap.rb | 4 ++- ...6_create_action_text_tables.action_text.rb | 26 ++++++++++++++++ db/schema.rb | 12 ++++++- 8 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 app/assets/stylesheets/actiontext.css create mode 100644 app/views/active_storage/blobs/_blob.html.erb create mode 100644 app/views/layouts/action_text/contents/_content.html.erb create mode 100644 db/migrate/20230209105256_create_action_text_tables.action_text.rb 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 index beff742e..ed5cae66 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -1 +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/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/config/importmap.rb b/config/importmap.rb index 050818ab..f882664b 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -1,2 +1,4 @@ # Pin npm packages by running ./bin/importmap -pin "application", preload: true \ No newline at end of file +pin "application", preload: true +pin "trix" +pin "@rails/actiontext", to: "actiontext.js" 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 50c24c41..9ba8eaf3 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 From cc99b4d99fc7fe6b4a2347ebfcaa7ca68c0d0289 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 9 Feb 2023 12:18:18 +0100 Subject: [PATCH 13/15] add richtext field to messages --- plugins/messages/app/controllers/messages_controller.rb | 8 +++++--- plugins/messages/app/helpers/messages_helper.rb | 2 +- plugins/messages/app/models/message.rb | 2 ++ plugins/messages/app/views/messages/new.haml | 2 +- plugins/messages/app/views/messages/show.haml | 2 +- .../app/views/messages_mailer/foodsoft_message.html.haml | 6 ++++++ 6 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml diff --git a/plugins/messages/app/controllers/messages_controller.rb b/plugins/messages/app/controllers/messages_controller.rb index 628f145b..7807b67f 100644 --- a/plugins/messages/app/controllers/messages_controller.rb +++ b/plugins/messages/app/controllers/messages_controller.rb @@ -20,11 +20,13 @@ 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 + "
" + + # .each_line { |l| @message.body += I18n.t('messages.model.reply_indent', :line => l) } else redirect_to new_message_url, alert: I18n.t('messages.new.error_private') - end + end end 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..8c81d380 --- /dev/null +++ b/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml @@ -0,0 +1,6 @@ += @message.body +%hr/ +%pre + - if @message.group + = raw t '.footer_group', group: @message.group.name + = raw t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url \ No newline at end of file From 32c765d2aa5a25e72f7837f11ad7c0149fad1812 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 9 Feb 2023 17:10:17 +0100 Subject: [PATCH 14/15] add imageprocessing for message attachements --- Gemfile | 2 ++ Gemfile.lock | 7 +++++++ config/application.rb | 2 ++ 3 files changed, 11 insertions(+) diff --git a/Gemfile b/Gemfile index 4d71513f..cf5c631a 100644 --- a/Gemfile +++ b/Gemfile @@ -128,3 +128,5 @@ group :test do end gem "importmap-rails", "~> 1.1" + +gem "image_processing", "~> 1.12" diff --git a/Gemfile.lock b/Gemfile.lock index 88fa2944..b7a61156 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -255,6 +255,9 @@ 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) @@ -318,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) @@ -496,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) @@ -631,6 +637,7 @@ DEPENDENCIES i18n-js (~> 3.0.0.rc8) i18n-spec ice_cube + image_processing (~> 1.12) importmap-rails (~> 1.1) inherited_resources jquery-rails 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 From 14f2d5ca32299bb6fb0106748f8b383b53cfc5c0 Mon Sep 17 00:00:00 2001 From: Philipp Rothmann Date: Thu, 9 Feb 2023 17:11:59 +0100 Subject: [PATCH 15/15] add html email layout and adjust translations for urls --- app/views/layouts/email.html.haml | 12 ++++++++++++ app/views/layouts/email.text.haml | 2 +- config/locales/de.yml | 1 + config/locales/en.yml | 1 + config/locales/es.yml | 13 +++++++------ config/locales/fr.yml | 11 ++++++----- config/locales/nl.yml | 1 + .../messages_mailer/foodsoft_message.html.haml | 15 ++++++++++----- .../messages_mailer/foodsoft_message.text.haml | 2 +- plugins/messages/config/locales/de.yml | 3 +++ plugins/messages/config/locales/en.yml | 3 +++ plugins/messages/config/locales/fr.yml | 3 +++ plugins/messages/config/locales/nl.yml | 3 +++ 13 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 app/views/layouts/email.html.haml 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/app/views/layouts/email.text.haml b/app/views/layouts/email.text.haml index 94b0cd6c..b6f6171f 100644 --- a/app/views/layouts/email.text.haml +++ b/app/views/layouts/email.text.haml @@ -3,4 +3,4 @@ = t '.footer_1_separator' = t '.footer_2_foodsoft', url: root_url = t '.footer_3_homepage', url: FoodsoftConfig[:homepage] if FoodsoftConfig[:homepage] -= t '.footer_4_help', url: FoodsoftConfig[:help_url] if FoodsoftConfig[:help_url] += t '.footer_4_help', url: FoodsoftConfig[:help_url] if FoodsoftConfig[:help_url] \ No newline at end of file diff --git a/config/locales/de.yml b/config/locales/de.yml index 5a1a5b35..777244c1 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -1221,6 +1221,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 59e94385..bf75a895 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1224,6 +1224,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..8dbe75dd 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -268,7 +268,7 @@ es: all_ordergroups: Todos los grupos de pedido all_users: Todos los usuarios all_workgroups: Todos los grupos de trabajo - created_at: creado + created_at: creado first_paragraph: Aquí puedes administrar grupos y usuarios de Foodsoft. groupname: nombre del grupo members: miembros @@ -513,7 +513,7 @@ es: status: Estado (x=saltar) file_label: Por favor elige un archivo compatible options: - convert_units: Mantener unidades actuales, recomputar la cantidad y precio de unidades (como sincronizar). + convert_units: Mantener unidades actuales, recomputar la cantidad y precio de unidades (como sincronizar). outlist_absent: Borrar artículos que no están en el archivo subido. sample: juices: Jugos @@ -1014,7 +1014,7 @@ es: changes_saved: Guarda los cambios. index: my_ordergroup: - last_update: La última actualización fue hace %{when} + last_update: La última actualización fue hace %{when} title: Mi grupo de pedido transactions: title: Últimas transacciones @@ -1082,6 +1082,7 @@ es: layouts: email: footer_4_help: 'Ayuda: %{url}' + help: 'Ayuda' footer: revision: revisión %{revision} header: @@ -1103,7 +1104,7 @@ es: error_invite_invalid: Tu invitación no es válida. error_token_invalid: La sesión ha expirado o no es válida. Prueba de nuevo. reset_password: - notice: Si tu email está ya registrado aquí, recibirás un mensaje con un enlace para + notice: Si tu email está ya registrado aquí, recibirás un mensaje con un enlace para update_password: notice: Tu contraseña ha sido actualizada. Prueba a conectarte ahora. forgot_password: @@ -1469,7 +1470,7 @@ es: copy: title: Copia artículo de stock create: - notice: Se ha creado el nuevo producto en stock "%{name}" + notice: Se ha creado el nuevo producto en stock "%{name}" derive: title: Añade un artículo en stock desde plantilla destroy: @@ -1577,7 +1578,7 @@ es: accept_task: Aceptar tarea confirm_delete_group: Estás seguro/a de que quieres borrar esta tarea y todas las tareas subsecuentes? confirm_delete_single: Estás seguro/a de que quieres borrar esta tarea? - confirm_delete_single_from_group: Estás seguro/a de que quieres borrar esta tarea (y mantener las tareas recurrentes relacionadas)? + confirm_delete_single_from_group: Estás seguro/a de que quieres borrar esta tarea (y mantener las tareas recurrentes relacionadas)? delete_group: Borrar esta tarea y las subsecuentes edit_group: Edita recurrencia mark_done: Marca tarea como hecha diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 4dbdb864..53ab8835 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -14,7 +14,7 @@ fr: gross_price: Prix TTC manufacturer: Product-rice-eur name: Nom - order_number: Numéro + order_number: Numéro order_number_short: Numéro origin: Lieu de production price: Prix HT @@ -834,6 +834,7 @@ fr: email: footer_3_homepage: 'Boufcoop: %{url}' footer_4_help: 'Aide: %{url}' + help: 'Aide' footer: revision: révision %{revision} header: @@ -860,7 +861,7 @@ fr: error_invite_invalid: Ton invitation n'est pas ou plus valide. error_token_invalid: Ton jeton de connexion n'est pas ou plus valide, essaie de cliquer à nouveau sur le lien. reset_password: - notice: Tu vas maintenant recevoir un message contenant un lien qui te permettra de réinitialiser ton mot de passe. + notice: Tu vas maintenant recevoir un message contenant un lien qui te permettra de réinitialiser ton mot de passe. update_password: notice: Ton mot de passe a été mis à jour. Tu peux maintenant de connecter. forgot_password: @@ -1093,7 +1094,7 @@ fr: closed: décomptée finished: clôturée open: en cours - received: reçu + received: reçu update: notice: La commande a été mise à jour. update_order_amounts: @@ -1344,7 +1345,7 @@ fr: notice: La description du boulot a été mise à jour. notice_converted: Le boulot a été converti en boulot ordinaire (sans répétition). user: - more: Tu t'ennuies en ce moment? Il y aura sûrement du boulot pour toi %{tasks_link}. + more: Tu t'ennuies en ce moment? Il y aura sûrement du boulot pour toi %{tasks_link}. tasks_link: par là-bas title: Ton boulot title_accepted: Boulots acceptés @@ -1369,7 +1370,7 @@ fr: edit: title: Modifier l'équipe error_last_admin_group: Impossible de supprimer la dernière cellule avec privilèges administratrices. - error_last_admin_role: Les privilèges administratrices ne peuvent pas être retirés à la dernière cellule qui les possède. + error_last_admin_role: Les privilèges administratrices ne peuvent pas être retirés à la dernière cellule qui les possède. index: title: Équipes update: 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/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml b/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml index 8c81d380..7ca572f3 100644 --- a/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml +++ b/plugins/messages/app/views/messages_mailer/foodsoft_message.html.haml @@ -1,6 +1,11 @@ -= @message.body -%hr/ -%pre += raw @message.body +%hr +%ul - if @message.group - = raw t '.footer_group', group: @message.group.name - = raw t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url \ No newline at end of file + %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/app/views/messages_mailer/foodsoft_message.text.haml b/plugins/messages/app/views/messages_mailer/foodsoft_message.text.haml index 85b0436d..cad65998 100644 --- a/plugins/messages/app/views/messages_mailer/foodsoft_message.text.haml +++ b/plugins/messages/app/views/messages_mailer/foodsoft_message.text.haml @@ -3,4 +3,4 @@ \ - if @message.group = raw t '.footer_group', group: @message.group.name -= raw t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url += raw t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url \ No newline at end of file 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: