diff --git a/.gitignore b/.gitignore index c9c85604..185b2f74 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ tmp public/assets public/system public/uploads +storage vendor/bundle # no configuration diff --git a/.ruby-version b/.ruby-version index 338a5b5d..d48d3702 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.6.6 +2.6.9 diff --git a/Dockerfile b/Dockerfile index 0b4f9aa1..49180276 100644 --- a/Dockerfile +++ b/Dockerfile @@ -39,6 +39,7 @@ RUN export DATABASE_URL=mysql2://localhost/temp?encoding=utf8 && \ mariadb -e "CREATE DATABASE temp" && \ cp config/app_config.yml.SAMPLE config/app_config.yml && \ cp config/database.yml.MySQL_SAMPLE config/database.yml && \ + cp config/storage.yml.SAMPLE config/storage.yml && \ bundle exec rake db:setup assets:precompile && \ rm -Rf tmp/* && \ /etc/init.d/mysql stop && \ @@ -56,6 +57,8 @@ USER nobody EXPOSE 3000 +VOLUME /usr/src/app/storage + # cleanup, and by default start web process from Procfile ENTRYPOINT ["./docker-entrypoint.sh"] CMD ["./proc-start", "web"] diff --git a/README.md b/README.md index d5265e77..9facbdac 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Deploying --------- Setup foodsoft to [run in production](doc/SETUP_PRODUCTION.md), or join an existing -[hosting platform](https://foodcoops.github.io/foodsoft-hosting/). +[hosting platform](https://foodcoops.net/foodsoft-hosting/). License @@ -52,7 +52,7 @@ files are marked as public domain in the file header. If you have any remaining questions, please [open an issue](https://github.com/foodcoops/foodsoft/issues/new) or contact -the [mailing list](http://foodsoft.51229.x6.nabble.com/foodsoft-discuss-f5.html). +the [mailing list](http://foodsoft.274.s1.nabble.com/foodsoft-discuss-f5.html). Please see [LICENSE](LICENSE.md) for the full and authoritative text. Some bundled third-party components have [other licenses](vendor/README.md). diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb index 48367f17..9f26ceb4 100644 --- a/app/mailers/mailer.rb +++ b/app/mailers/mailer.rb @@ -115,7 +115,7 @@ class Mailer < ActionMailer::Base @user = user @feedback = feedback - mail to: FoodsoftConfig[:notification][:error_recipients], + mail to: feedback_recipients, from: user, subject: I18n.t('mailer.feedback.subject') end @@ -196,4 +196,9 @@ class Mailer < ActionMailer::Base address.display_name = name address.format end + + # use the (new) feedback_recipients option, but fallback to error_recipients for backwards compatibility + def feedback_recipients + FoodsoftConfig[:notification][:feedback_recipients] || FoodsoftConfig[:notification][:error_recipients] + end end diff --git a/app/models/article.rb b/app/models/article.rb index 8e441c36..f8c129b6 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -62,6 +62,10 @@ class Article < ApplicationRecord validates_presence_of :name, :unit, :price, :tax, :deposit, :unit_quantity, :supplier_id, :article_category validates_length_of :name, :in => 4..60 validates_length_of :unit, :in => 1..15 + validates_length_of :note, :maximum => 255 + validates_length_of :origin, :maximum => 255 + validates_length_of :manufacturer, :maximum => 255 + validates_length_of :order_number, :maximum => 255 validates_numericality_of :price, :greater_than_or_equal_to => 0 validates_numericality_of :unit_quantity, :greater_than => 0 validates_numericality_of :deposit, :tax diff --git a/config/app_config.yml.SAMPLE b/config/app_config.yml.SAMPLE index 1000683a..e43705b6 100644 --- a/config/app_config.yml.SAMPLE +++ b/config/app_config.yml.SAMPLE @@ -118,9 +118,9 @@ default: &defaults # label: Birthday # as: date_picker - # Uncomment to add tracking code for web statistics, e.g. for Piwik. (Added to bottom of page) + # Uncomment to add tracking code for web statistics, e.g. for Matomo. (Added to bottom of page) #webstats_tracking_code: | - # + # # ...... # email address to be used as sender @@ -137,6 +137,8 @@ default: &defaults notification: error_recipients: - admin@foodcoop.test + feedback_recipients: + - support@foodcoop.test sender_address: "\"Foodsoft Error\" " email_prefix: "[Foodsoft]" diff --git a/config/environments/development.rb.SAMPLE b/config/environments/development.rb.SAMPLE index 035a7e86..50787eca 100644 --- a/config/environments/development.rb.SAMPLE +++ b/config/environments/development.rb.SAMPLE @@ -31,6 +31,9 @@ Rails.application.configure do config.cache_store = :null_store end + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/production.rb b/config/environments/production.rb index 8e8dcf25..0560b38d 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -40,6 +40,9 @@ Rails.application.configure do # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + # Store uploaded files on the local file system (see config/storage.yml for options) + config.active_storage.service = :local + # Mount Action Cable outside main process or domain # config.action_cable.mount_path = nil # config.action_cable.url = 'wss://example.com/cable' diff --git a/config/environments/test.rb b/config/environments/test.rb index b10aeee0..ccf3767f 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -31,6 +31,10 @@ Rails.application.configure do # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + + # Store uploaded files on the local file system in a temporary directory + config.active_storage.service = :test + config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. diff --git a/config/initializers/active_storage_foodcoop_path.rb b/config/initializers/active_storage_foodcoop_path.rb new file mode 100644 index 00000000..bebb33d2 --- /dev/null +++ b/config/initializers/active_storage_foodcoop_path.rb @@ -0,0 +1,15 @@ +require 'active_storage/service/disk_service' + +module FoodsoftActiveStorageDiskService + def self.included(base) # :nodoc: + base.class_eval do + def path_for(key) + File.join root, FoodsoftConfig.scope, folder_for(key), key + end + end + end +end + +ActiveSupport.on_load(:after_initialize) do + ActiveStorage::Service::DiskService.include FoodsoftActiveStorageDiskService +end diff --git a/config/storage.yml.SAMPLE b/config/storage.yml.SAMPLE new file mode 100644 index 00000000..d32f76e8 --- /dev/null +++ b/config/storage.yml.SAMPLE @@ -0,0 +1,34 @@ +test: + service: Disk + root: <%= Rails.root.join("tmp/storage") %> + +local: + service: Disk + root: <%= Rails.root.join("storage") %> + +# Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) +# amazon: +# service: S3 +# access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> +# secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> +# region: us-east-1 +# bucket: your_own_bucket + +# Remember not to checkin your GCS keyfile to a repository +# google: +# service: GCS +# project: your_project +# credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> +# bucket: your_own_bucket + +# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) +# microsoft: +# service: AzureStorage +# storage_account_name: your_account_name +# storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> +# container: your_container_name + +# mirror: +# service: Mirror +# primary: local +# mirrors: [ amazon, google, microsoft ] diff --git a/db/migrate/20190101000000_create_active_storage_tables.active_storage.rb b/db/migrate/20190101000000_create_active_storage_tables.active_storage.rb new file mode 100644 index 00000000..3739c2e8 --- /dev/null +++ b/db/migrate/20190101000000_create_active_storage_tables.active_storage.rb @@ -0,0 +1,27 @@ +# This migration comes from active_storage (originally 20170806125915) +class CreateActiveStorageTables < ActiveRecord::Migration[4.2][5.2] + def change + create_table :active_storage_blobs do |t| + t.string :key, null: false + t.string :filename, null: false + t.string :content_type + t.text :metadata + t.bigint :byte_size, null: false + t.string :checksum, null: false + t.datetime :created_at, null: false + + t.index [:key], unique: true + end + + create_table :active_storage_attachments do |t| + t.string :name, null: false + t.references :record, null: false, polymorphic: true, index: false + t.references :blob, null: false + + t.datetime :created_at, null: false + + t.index [:record_type, :record_id, :name, :blob_id], name: "index_active_storage_attachments_uniqueness", unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 11e4a4ce..0fcc5161 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,15 +10,36 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2021_12_08_142719) do +ActiveRecord::Schema.define(version: 2021_02_05_090257) do - create_table "article_categories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "active_storage_attachments", id: :integer, force: :cascade do |t| + t.string "name", null: false + t.string "record_type", null: false + t.bigint "record_id", null: false + t.bigint "blob_id", null: false + t.datetime "created_at", null: false + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + end + + create_table "active_storage_blobs", id: :integer, force: :cascade do |t| + t.string "key", null: false + t.string "filename", null: false + t.string "content_type" + t.text "metadata" + t.bigint "byte_size", null: false + t.string "checksum", null: false + t.datetime "created_at", null: false + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + end + + create_table "article_categories", id: :integer, force: :cascade do |t| t.string "name", default: "", null: false t.string "description" t.index ["name"], name: "index_article_categories_on_name", unique: true end - create_table "article_prices", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "article_prices", id: :integer, force: :cascade do |t| t.integer "article_id", null: false t.decimal "price", precision: 8, scale: 2, default: "0.0", null: false t.decimal "tax", precision: 8, scale: 2, default: "0.0", null: false @@ -28,7 +49,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["article_id"], name: "index_article_prices_on_article_id" end - create_table "articles", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "articles", id: :integer, force: :cascade do |t| t.string "name", default: "", null: false t.integer "supplier_id", default: 0, null: false t.integer "article_category_id", default: 0, null: false @@ -54,14 +75,14 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["type"], name: "index_articles_on_type" end - create_table "assignments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "assignments", id: :integer, force: :cascade do |t| t.integer "user_id", default: 0, null: false t.integer "task_id", default: 0, null: false t.boolean "accepted", default: false t.index ["user_id", "task_id"], name: "index_assignments_on_user_id_and_task_id", unique: true end - create_table "bank_accounts", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "bank_accounts", id: :integer, force: :cascade do |t| t.string "name", null: false t.string "iban" t.string "description" @@ -70,7 +91,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.string "import_continuation_point" end - create_table "bank_transactions", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "bank_transactions", id: :integer, force: :cascade do |t| t.integer "bank_account_id", null: false t.string "external_id" t.date "date" @@ -84,7 +105,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["financial_link_id"], name: "index_bank_transactions_on_financial_link_id" end - create_table "documents", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "documents", id: :integer, force: :cascade do |t| t.string "name" t.string "mime" t.binary "data", limit: 4294967295 @@ -95,16 +116,16 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["parent_id"], name: "index_documents_on_parent_id" end - create_table "financial_links", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "financial_links", id: :integer, force: :cascade do |t| t.text "note" end - create_table "financial_transaction_classes", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "financial_transaction_classes", id: :integer, force: :cascade do |t| t.string "name", null: false t.boolean "ignore_for_account_balance", default: false, null: false end - create_table "financial_transaction_types", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "financial_transaction_types", id: :integer, force: :cascade do |t| t.string "name", null: false t.integer "financial_transaction_class_id", null: false t.string "name_short" @@ -112,7 +133,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["name_short"], name: "index_financial_transaction_types_on_name_short" end - create_table "financial_transactions", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "financial_transactions", id: :integer, force: :cascade do |t| t.integer "ordergroup_id" t.decimal "amount", precision: 8, scale: 2, default: "0.0", null: false t.text "note", null: false @@ -126,7 +147,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["reverts_id"], name: "index_financial_transactions_on_reverts_id", unique: true end - create_table "group_order_article_quantities", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "group_order_article_quantities", id: :integer, force: :cascade do |t| t.integer "group_order_article_id", default: 0, null: false t.integer "quantity", default: 0 t.integer "tolerance", default: 0 @@ -134,7 +155,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["group_order_article_id"], name: "index_group_order_article_quantities_on_group_order_article_id" end - create_table "group_order_articles", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "group_order_articles", id: :integer, force: :cascade do |t| t.integer "group_order_id", default: 0, null: false t.integer "order_article_id", default: 0, null: false t.integer "quantity", default: 0, null: false @@ -147,17 +168,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["order_article_id"], name: "index_group_order_articles_on_order_article_id" end - create_table "group_order_invoices", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| - t.integer "group_order_id" - t.bigint "invoice_number" - t.date "invoice_date" - t.string "payment_method" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["group_order_id"], name: "index_group_order_invoices_on_group_order_id", unique: true - end - - create_table "group_orders", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "group_orders", id: :integer, force: :cascade do |t| t.integer "ordergroup_id" t.integer "order_id", default: 0, null: false t.decimal "price", precision: 8, scale: 2, default: "0.0", null: false @@ -170,7 +181,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["ordergroup_id"], name: "index_group_orders_on_ordergroup_id" end - create_table "groups", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "groups", id: :integer, force: :cascade do |t| t.string "type", default: "", null: false t.string "name", default: "", null: false t.string "description" @@ -195,7 +206,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["name"], name: "index_groups_on_name", unique: true end - create_table "invites", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "invites", id: :integer, force: :cascade do |t| t.string "token", default: "", null: false t.datetime "expires_at", null: false t.integer "group_id", default: 0, null: false @@ -204,7 +215,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["token"], name: "index_invites_on_token" end - create_table "invoices", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "invoices", id: :integer, force: :cascade do |t| t.integer "supplier_id" t.string "number" t.date "date" @@ -222,7 +233,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["supplier_id"], name: "index_invoices_on_supplier_id" end - create_table "links", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "links", id: :integer, force: :cascade do |t| t.string "name", null: false t.string "url", null: false t.integer "workgroup_id" @@ -230,7 +241,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.string "authorization" end - create_table "mail_delivery_status", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "mail_delivery_status", id: :integer, force: :cascade do |t| t.datetime "created_at" t.string "email", null: false t.string "message", null: false @@ -239,13 +250,13 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["email"], name: "index_mail_delivery_status_on_email" end - create_table "memberships", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "memberships", id: :integer, force: :cascade do |t| t.integer "group_id", default: 0, null: false t.integer "user_id", default: 0, null: false t.index ["user_id", "group_id"], name: "index_memberships_on_user_id_and_group_id", unique: true end - create_table "message_recipients", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "message_recipients", id: :integer, force: :cascade do |t| t.integer "message_id", null: false t.integer "user_id", null: false t.integer "email_state", default: 0, null: false @@ -254,7 +265,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["user_id", "read_at"], name: "index_message_recipients_on_user_id_and_read_at" end - create_table "messages", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "messages", id: :integer, force: :cascade do |t| t.integer "sender_id" t.string "subject", null: false t.text "body" @@ -266,7 +277,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.binary "received_email", limit: 16777215 end - create_table "oauth_access_grants", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "oauth_access_grants", id: :integer, force: :cascade do |t| t.integer "resource_owner_id", null: false t.integer "application_id", null: false t.string "token", null: false @@ -278,7 +289,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["token"], name: "index_oauth_access_grants_on_token", unique: true end - create_table "oauth_access_tokens", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "oauth_access_tokens", id: :integer, force: :cascade do |t| t.integer "resource_owner_id" t.integer "application_id" t.string "token", null: false @@ -292,7 +303,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["token"], name: "index_oauth_access_tokens_on_token", unique: true end - create_table "oauth_applications", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "oauth_applications", id: :integer, force: :cascade do |t| t.string "name", null: false t.string "uid", null: false t.string "secret", null: false @@ -304,7 +315,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true end - create_table "order_articles", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "order_articles", id: :integer, force: :cascade do |t| t.integer "order_id", default: 0, null: false t.integer "article_id", default: 0, null: false t.integer "quantity", default: 0, null: false @@ -318,7 +329,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["order_id"], name: "index_order_articles_on_order_id" end - create_table "order_comments", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "order_comments", id: :integer, force: :cascade do |t| t.integer "order_id" t.integer "user_id" t.text "text" @@ -326,7 +337,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["order_id"], name: "index_order_comments_on_order_id" end - create_table "orders", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "orders", id: :integer, force: :cascade do |t| t.integer "supplier_id" t.text "note" t.datetime "starts" @@ -345,7 +356,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["state"], name: "index_orders_on_state" end - create_table "page_versions", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "page_versions", id: :integer, force: :cascade do |t| t.integer "page_id" t.integer "lock_version" t.text "body" @@ -356,7 +367,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["page_id"], name: "index_page_versions_on_page_id" end - create_table "pages", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "pages", id: :integer, force: :cascade do |t| t.string "title" t.text "body" t.string "permalink" @@ -370,20 +381,20 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["title"], name: "index_pages_on_title" end - create_table "periodic_task_groups", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "periodic_task_groups", id: :integer, force: :cascade do |t| t.date "next_task_date" t.datetime "created_at", null: false t.datetime "updated_at", null: false end - create_table "poll_choices", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "poll_choices", id: :integer, force: :cascade do |t| t.integer "poll_vote_id", null: false t.integer "choice", null: false t.integer "value", null: false t.index ["poll_vote_id", "choice"], name: "index_poll_choices_on_poll_vote_id_and_choice", unique: true end - create_table "poll_votes", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "poll_votes", id: :integer, force: :cascade do |t| t.integer "poll_id", null: false t.integer "user_id", null: false t.integer "ordergroup_id" @@ -393,7 +404,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["poll_id", "user_id", "ordergroup_id"], name: "index_poll_votes_on_poll_id_and_user_id_and_ordergroup_id", unique: true end - create_table "polls", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "polls", id: :integer, force: :cascade do |t| t.integer "created_by_user_id", null: false t.string "name", null: false t.text "description" @@ -413,7 +424,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["final_choice"], name: "index_polls_on_final_choice" end - create_table "printer_job_updates", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "printer_job_updates", id: :integer, force: :cascade do |t| t.integer "printer_job_id", null: false t.datetime "created_at", null: false t.string "state", null: false @@ -421,7 +432,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["printer_job_id", "created_at"], name: "index_printer_job_updates_on_printer_job_id_and_created_at" end - create_table "printer_jobs", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "printer_jobs", id: :integer, force: :cascade do |t| t.integer "order_id" t.string "document", null: false t.integer "created_by_user_id", null: false @@ -430,7 +441,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["finished_at"], name: "index_printer_jobs_on_finished_at" end - create_table "settings", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "settings", id: :integer, force: :cascade do |t| t.string "var", null: false t.text "value" t.integer "thing_id" @@ -440,7 +451,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["thing_type", "thing_id", "var"], name: "index_settings_on_thing_type_and_thing_id_and_var", unique: true end - create_table "stock_changes", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "stock_changes", id: :integer, force: :cascade do |t| t.integer "stock_event_id" t.integer "order_id" t.integer "stock_article_id" @@ -450,7 +461,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["stock_event_id"], name: "index_stock_changes_on_stock_event_id" end - create_table "stock_events", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "stock_events", id: :integer, force: :cascade do |t| t.integer "supplier_id" t.date "date" t.datetime "created_at" @@ -460,13 +471,13 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["supplier_id"], name: "index_stock_events_on_supplier_id" end - create_table "supplier_categories", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "supplier_categories", id: :integer, force: :cascade do |t| t.string "name", null: false t.string "description" t.integer "financial_transaction_class_id" end - create_table "suppliers", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "suppliers", id: :integer, force: :cascade do |t| t.string "name", default: "", null: false t.string "address", default: "", null: false t.string "phone", default: "", null: false @@ -488,7 +499,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["name"], name: "index_suppliers_on_name", unique: true end - create_table "tasks", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "tasks", id: :integer, force: :cascade do |t| t.string "name", default: "", null: false t.text "description" t.date "due_date" @@ -505,7 +516,7 @@ ActiveRecord::Schema.define(version: 2021_12_08_142719) do t.index ["workgroup_id"], name: "index_tasks_on_workgroup_id" end - create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t| + create_table "users", id: :integer, force: :cascade do |t| t.string "nick" t.string "password_hash", default: "", null: false t.string "password_salt", default: "", null: false diff --git a/doc/SETUP_DEVELOPMENT.md b/doc/SETUP_DEVELOPMENT.md index 51a4e3c2..319c2787 100644 --- a/doc/SETUP_DEVELOPMENT.md +++ b/doc/SETUP_DEVELOPMENT.md @@ -11,132 +11,121 @@ If instead you just want to run Foodsoft without changing its code, please refer [deployment](https://github.com/foodcoops/foodsoft/wiki/Deployment-notes). **System requirements**: -[RVM](https://rvm.io/rvm/install), -[Ruby 2+](https://www.ruby-lang.org/en/downloads/), +[rbenv](https://github.com/rbenv/rbenv), +[Ruby 2.6+](https://www.ruby-lang.org/en/downloads/), [Bundler](http://bundler.io/), -[MySQL](http://mysql.com/)/[PostgreSQL](http://www.postgresql.org/)/[SQLite](http://sqlite.org/). - -**Optional**: -[Redis](http://redis.io/). +[MySQL](http://mysql.com/) / [SQLite](http://sqlite.org/), +[Redis](http://redis.io/) (optional). ### Getting started -0. Clone the repository from GitHub: +1. Clone the repository from GitHub: git clone https://github.com/foodcoops/foodsoft.git - This brings up the bleeding-edge development version, which might contain some - unfinished parts. If you want to be safe, choose the last release: - `git checkout $(git tag -l | grep ^v | sort -rn | head -n1)` + This brings up the bleeding-edge development version, which might contain some unfinished parts. + If you want to be safe, choose the last release: - *Note:* When developing on Windows you might run into issues with shell scripts - because of Git auto-crlf. Have a look how to avoid that in the - [Docker Development Setup](./SETUP_DEVELOPMENT_DOCKER.md#prerequisites-windows-only) - instructions. + git checkout $(git tag -l | grep ^v | sort -rn | head -n1) -1. Install RVM and Ruby 2.6+ (if you have not done so before): + *Note:* When developing on Windows you might run into issues with shell scripts because of Git auto-crlf. + Have a look how to avoid that in the [Docker Development Setup](./SETUP_DEVELOPMENT_DOCKER.md#prerequisites-windows-only) + instructions. - \curl -L https://get.rvm.io | bash - source ~/.rvm/scripts/rvm - rvm install 2.6 +1. Install and setup rbenv and Bundler. For Debian/Ubuntu: - We try to keep Foodsoft compatible with Ruby 2.6 as well as any later versions, - so if you use this and don't want to use RVM, that might actually work. + sudo apt install rbenv + + For other distributions have a look at the rbenv [documentation](https://github.com/rbenv/rbenv). -2. Install system dependencies. + Add the following line to your `.bashrc`: - For Debian/Ubuntu, that's - [libv8-dev](https://packages.debian.org/stable/libv8-dev) - [libmysqlclient-dev](https://packages.debian.org/stable/libmysqlclient-dev) - [libxml2-dev](https://packages.debian.org/stable/libxml2-dev) - [libxslt1-dev](https://packages.debian.org/stable/libxslt1-dev) - [libffi-dev](https://packages.debian.org/stable/libffi-dev) - [libreadline-dev](https://packages.debian.org/stable/libreadline-dev) - [libmagic-dev](https://packages.debian.org/stable/libmagic-dev): + eval "$(rbenv init -)" - # Debian/Ubuntu - sudo apt-get install libv8-dev libmysqlclient-dev libxml2-dev libxslt1-dev libffi-dev libreadline-dev libmagic-dev + Install [ruby-build](https://github.com/rbenv/ruby-build): - For CentOS/Redhat you need - [v8](https://apps.fedoraproject.org/packages/v8) - [community-mysql-devel](https://apps.fedoraproject.org/packages/community-mysql-devel) - [libxml2-devel](https://apps.fedoraproject.org/packages/libxml2-devel) - [libxslt-devel](https://apps.fedoraproject.org/packages/libxslt-devel) - [libffi-devel](https://apps.fedoraproject.org/packages/libffi-devel) - [readline-devel](https://apps.fedoraproject.org/packages/readline-devel) - [file-devel](https://apps.fedoraproject.org/packages/file-devel): + mkdir -p "$(rbenv root)"/plugins + git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build + + Change to the Foodsoft directory and install the [recommended](https://github.com/foodcoops/foodsoft/blob/master/.ruby-version) + Ruby version: + + rbenv install "$(cat .ruby-version)" + + Now you can install [Bundler](https://bundler.io/): + + rbenv exec gem install bundler + +1. Install system dependencies. + + For Debian/Ubuntu, that's: + + sudo apt install libv8-dev default-libmysqlclient-dev libxml2-dev libxslt1-dev libffi-dev libreadline-dev libmagic-dev + + For CentOS/Redhat you need: - # CentOS/Redhat sudo yum install v8 community-mysql-devel libxml2-devel libxslt-devel libffi-devel readline-devel file-devel -3. Install Ruby dependencies: +1. Install Ruby dependencies: - bundle install + rbenv exec bundle install -4. Setup your development environment: +1. Setup your development environment: - rake foodsoft:setup_development + rbenv exec rails foodsoft:setup_development This will interactively prompt with several questions relating to your required environment. - **Important**: After selecting your database type, `rake` will create the file `config/database.yml`, + **Important**: After selecting your database type, `rails` will create the file `config/database.yml`, which then then be edited with working `username` and `password` credentials for the database. These fields - must be added for *development* AND (temporary) *test* databases. Then continue with confirmation in rake dialogue. + must be added for *development* AND (temporary) *test* databases. Then continue with confirmation in rails dialogue. -5. Start rails by running: +1. Start rails by running: - bundle exec rails s + rbenv exec rails s -6. Open your favorite browser and open the web application at: +1. Open your favorite browser and open the web browser at: http://localhost:3000/ - You might want to watch a - [kitten video](https://www.youtube.com/watch?v=9Iq5yCoHp4o) - while it's loading. + You might want to watch a [kitten video](https://www.youtube.com/watch?v=9Iq5yCoHp4o) while it's loading. -7. Login using the default credentials: `admin/secret` +1. Login using the default credentials: `admin/secret` -8. Change the admin password, just in case. +1. Change the admin password, just in case. -9. Have phun! +1. Have phun! For running integration tests, you also need the Chromium/Chrome web browser. -On Debian that would be `sudo apt-get install chromium`, on Ubuntu +On Debian that would be `apt-get install chromium`, on Ubuntu `sudo apt-get install chromium-browser`. ### Manual configuration -The rake task `foodsoft:setup_development` helps you to setup foodsoft. -If you want to have more control, you can do these steps manually as -explained here. - +The rails task `foodsoft:setup_development` helps you to setup foodsoft. +If you want to have more control, you can do these steps manually as explained here. 1. **Configure database** - Create the database configuration from the default: + Create the database configuration from the default: cp config/database.yml.SQLite_SAMPLE config/database.yml - If you are fine with using a file-based sqlite database you are all set. - The sqlite files (`development/test/production`) will reside in the `db` - directory. Otherwise you would want to copy one of the other - `database.yml.*_SAMPLE` files and edit `database.yml` to suit your needs. + If you are fine with using a file-based sqlite database you are all set. + The sqlite files (`development/test/production`) will reside in the `db` directory. Otherwise you would want to copy one + of the other `database.yml.*_SAMPLE` files and edit `database.yml` to suit your needs. +1. **Configure development environment** -2. **Configure development environment** - - Again, you need to create your own copy of the default configuration: + Again, you need to create your own copy of the default configuration: cp config/environments/development.rb.SAMPLE config/environments/development.rb - Edit development.rb to specify your settings (at least the ActionMailer SMTP - settings). If you just leave the file as is, emails will not work but - everything else should be okay. + Edit development.rb to specify your settings (at least the ActionMailer SMTP settings). If you just leave the file as is, + emails will not work but everything else should be okay. - -3. **Foodsoft settings** +1. **Foodsoft settings** You need to create your own copy of the foodsoft configuration settings: @@ -144,37 +133,36 @@ explained here. Edit `app_config.yml` to suit your needs or just keep the defaults for now. +1. **Create database (schema) and load defaults** -4. **Create database (schema) and load defaults** + rbenv exec rails db:setup - rake db:setup + With this, you also get a ready to go user with username 'admin' and password 'secret'. - With this, you also get a ready to go user with username 'admin' and - password 'secret'. +1. (optional) Get **background jobs** done - -5. (optional) Get **background jobs** done - - Time intensive tasks may block the web request. To run these in a separate - task, you can install Redis and enable Resque: + Time intensive tasks may block the web request. To run these in a separate task, you can install Redis and enable Resque: * Comment `Resque.inline = true` in `config/environments/development.rb` - * Install [Redis](http://redis.io/) (Ubuntu package `redis-server`) - * Run the worker: `rake resque:work QUEUE=foodsoft_notifier` + * Install [Redis](http://redis.io/) (Debian/Ubuntu package `redis-server`) + * Run the worker: + + ``` + rbenv exec rails resque:work QUEUE=* + ``` To have look on the current queue, failed jobs etc start the resque server with `resque-web`. - -6. (optional) **View mails in browser** instead in your logs +1. (optional) **View mails in browser** instead in your logs We use mailcatcher in development mode to view all delivered mails in a - browser interface. Just install mailcatcher with gem install mailcatcher - and start the service with + browser interface. Just install mailcatcher with `rbenv exec gem install mailcatcher` + and start the service with: mailcatcher - From now on you have a smtp server listening on 1025. To see the emails go to + From now on you have a smtp server listening on 1025. To see the emails go to: http://localhost:1080 @@ -187,4 +175,4 @@ within a docker image. While the default [`Dockerfile`](../Dockerfile) is setup use docker-compose (using [`docker-compose-dev.yml`](../docker-compose-dev.yml)) to setup the whole stack at once. -See [Setup Development Docker](./SETUP_DEVELOPMENT_DOCKER.md) for a detailed description. +See [Setup Development Docker](./SETUP_DEVELOPMENT_DOCKER.md) for a detailed description. \ No newline at end of file diff --git a/doc/SETUP_PRODUCTION.md b/doc/SETUP_PRODUCTION.md index 929c1558..02833211 100644 --- a/doc/SETUP_PRODUCTION.md +++ b/doc/SETUP_PRODUCTION.md @@ -2,7 +2,7 @@ The recommended way to run Foodsoft in production is using docker. Alternative options are discussed [in the wiki](https://github.com/foodcoops/foodsoft/wiki/Deployment-notes). If you -have any questions, please contact the mailing list [foodsoft-discuss](http://foodsoft.51229.x6.nabble.com/foodsoft-discuss-f5.html). +have any questions, please contact the mailing list [foodsoft-discuss](http://foodsoft.274.s1.nabble.com/foodsoft-discuss-f5.html). ## Docker diff --git a/lib/foodsoft_config.rb b/lib/foodsoft_config.rb index 052c1d68..33fa9e45 100644 --- a/lib/foodsoft_config.rb +++ b/lib/foodsoft_config.rb @@ -257,6 +257,7 @@ class FoodsoftConfig use_apple_points: true, # English is the default language, and this makes it show up as default. default_locale: 'en', + time_zone: 'Berlin', currency_unit: '€', currency_space: true, foodsoft_url: 'https://github.com/foodcoops/foodsoft', diff --git a/lib/tasks/foodsoft_setup.rake b/lib/tasks/foodsoft_setup.rake index 9dc2c7d0..baa483d1 100644 --- a/lib/tasks/foodsoft_setup.rake +++ b/lib/tasks/foodsoft_setup.rake @@ -33,6 +33,7 @@ namespace :foodsoft do setup_app_config setup_development setup_database + setup_storage start_mailcatcher puts yellow "All done! Your foodsoft setup should be running smoothly." start_server @@ -43,6 +44,7 @@ namespace :foodsoft do puts yellow "This task will help you get your foodcoop running in development via docker." setup_app_config setup_development + setup_storage setup_run_rake_db_setup puts yellow "All done! Your foodsoft setup should be running smoothly via docker." end @@ -112,6 +114,15 @@ def setup_development reminder(file) end +def setup_storage + file = 'config/storage.yml' + return nil if skip?(file) + + puts yellow "Copying #{file}..." + %x(cp -p #{Rails.root.join("#{file}.SAMPLE")} #{Rails.root.join(file)}) + reminder(file) +end + def start_mailcatcher return nil if ENV['MAILCATCHER_PORT'] # skip when it has an existing Docker container diff --git a/public/apple-touch-icon-114x114.png b/public/apple-touch-icon-114x114.png new file mode 100644 index 00000000..781d4848 Binary files /dev/null and b/public/apple-touch-icon-114x114.png differ diff --git a/public/apple-touch-icon-120x120.png b/public/apple-touch-icon-120x120.png new file mode 100644 index 00000000..ba5827fa Binary files /dev/null and b/public/apple-touch-icon-120x120.png differ diff --git a/public/apple-touch-icon-144x144.png b/public/apple-touch-icon-144x144.png new file mode 100644 index 00000000..6e4e5d3d Binary files /dev/null and b/public/apple-touch-icon-144x144.png differ diff --git a/public/apple-touch-icon-152x152.png b/public/apple-touch-icon-152x152.png new file mode 100644 index 00000000..f2048cdf Binary files /dev/null and b/public/apple-touch-icon-152x152.png differ diff --git a/public/apple-touch-icon-180x180.png b/public/apple-touch-icon-180x180.png new file mode 100644 index 00000000..424b4d84 Binary files /dev/null and b/public/apple-touch-icon-180x180.png differ diff --git a/public/apple-touch-icon-57x57.png b/public/apple-touch-icon-57x57.png new file mode 100644 index 00000000..a15ca67d Binary files /dev/null and b/public/apple-touch-icon-57x57.png differ diff --git a/public/apple-touch-icon-72x72.png b/public/apple-touch-icon-72x72.png new file mode 100644 index 00000000..d9cbc99c Binary files /dev/null and b/public/apple-touch-icon-72x72.png differ diff --git a/public/apple-touch-icon-76x76.png b/public/apple-touch-icon-76x76.png new file mode 100644 index 00000000..d4d30882 Binary files /dev/null and b/public/apple-touch-icon-76x76.png differ diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png new file mode 100644 index 00000000..a15ca67d Binary files /dev/null and b/public/apple-touch-icon.png differ