diff --git a/CHANGELOG.md b/CHANGELOG.md index 2784e45b1..63c1a109f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Prevent event reservation in the past [Taiga#127] - Handle Ctrl^C in upgrade scripts - Updated moment-timezone +- Added the a "cron" tab in Sidekiq web-ui to watch scheduled tasks - Integration of Crowdin "in-context" translation management system - Added freeCAD files as default allowed extensions - Rake task to sync local users with Stripe diff --git a/app/controllers/health_controller.rb b/app/controllers/health_controller.rb new file mode 100644 index 000000000..b5db4cc21 --- /dev/null +++ b/app/controllers/health_controller.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Controller for the application status, useful for debugging +class HealthController < ActionController::Base + respond_to :json + + def status + render json: { + name: 'Fab-Manager', + status: 'running', + dependencies: { + postgresql: HealthService.database?, + redis: HealthService.redis?, + elasticsearch: HealthService.elasticsearch? + }, + stats: HealthService.stats + } + end +end \ No newline at end of file diff --git a/app/models/setting.rb b/app/models/setting.rb index a7b676e7b..32c1b21a9 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -61,7 +61,9 @@ class Setting < ActiveRecord::Base accounting_Event_code accounting_Event_label accounting_Space_code - accounting_Space_label] } + accounting_Space_label + hub_last_version + hub_public_key] } after_update :update_stylesheet, :notify_privacy_policy_changed if :value_changed? diff --git a/app/services/health_service.rb b/app/services/health_service.rb new file mode 100644 index 000000000..0eaf21697 --- /dev/null +++ b/app/services/health_service.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +# Various methods to check the application status +class HealthService + def self.database? + ActiveRecord::Base.establish_connection + ActiveRecord::Base.connection + + ActiveRecord::Base.connected? + rescue ActiveRecord::ActiveRecordError + false + end + + def self.redis? + !!Sidekiq.redis(&:info) # rubocop:disable Style/DoubleNegation + rescue Redis::CannotConnectError + false + end + + def self.elasticsearch? + require 'elasticsearch/transport' + + client = Elasticsearch::Client.new host: "http://#{Rails.application.secrets.elaticsearch_host}:9200" + response = client.perform_request 'GET', '_cluster/health' + !!response.body # rubocop:disable Style/DoubleNegation + rescue Elasticsearch::Transport::Transport::Error + false + end + + def self.stats + # TODO + '651ad6a5z1daz65d1az65d156d1fz16' + end +end + diff --git a/app/workers/version_check_worker.rb b/app/workers/version_check_worker.rb new file mode 100644 index 000000000..11d5cd0a9 --- /dev/null +++ b/app/workers/version_check_worker.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +# Will check the application version to ensure it is up-to-date +class VersionCheckWorker + include Sidekiq::Worker + + def perform + require 'fab_hub' + res = FabHub.fab_manager_version_check + + setting_ver = Setting.find_or_initialize_by(name: 'hub_last_version') + setting_ver.value = { version: res['semver'], security: res['security'], status: res['up_to_date'] }.to_json.to_s + setting_ver.save! + + setting_key = Setting.find_or_initialize_by(name: 'hub_public_key') + setting_key.value = res['key'] + setting_key.save! + end +end diff --git a/config/environment.rb b/config/environment.rb index ee8d90dc6..3fa662183 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Load the Rails application. require File.expand_path('../application', __FILE__) diff --git a/config/routes.rb b/config/routes.rb index f3f505121..8894a62a3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'sidekiq/web' +require 'sidekiq/cron/web' Rails.application.routes.draw do post 'webhooks' => 'webhooks#create' @@ -207,5 +208,7 @@ Rails.application.routes.draw do mount Sidekiq::Web => '/admin/sidekiq' end + get 'health' => 'health#status' + apipie end diff --git a/config/schedule.yml b/config/schedule.yml index d89fe27cf..512538480 100644 --- a/config/schedule.yml +++ b/config/schedule.yml @@ -39,4 +39,8 @@ free_disk_space: class: "FreeDiskSpaceWorker" queue: default +version_check: + cron: "15 1 * * 0" # every sunday at 1:15am + class: "VersionCheckWorker" + <%= PluginRegistry.insert_code('yml.schedule') %> diff --git a/db/migrate/20191202135507_create_i_calendar_events.rb b/db/migrate/20191202135507_create_i_calendar_events.rb index 748349cd5..68958c26c 100644 --- a/db/migrate/20191202135507_create_i_calendar_events.rb +++ b/db/migrate/20191202135507_create_i_calendar_events.rb @@ -1,3 +1,6 @@ +# frozen_string_literal: true + +# From this migration, we are able to store events from an external calendar (using the iCalendar standard format) class CreateICalendarEvents < ActiveRecord::Migration def change create_table :i_calendar_events do |t| diff --git a/db/schema.rb b/db/schema.rb index 0a5705763..1d370074c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -15,8 +15,8 @@ ActiveRecord::Schema.define(version: 20191202135507) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" - enable_extension "unaccent" enable_extension "pg_trgm" + enable_extension "unaccent" create_table "abuses", force: :cascade do |t| t.integer "signaled_id" diff --git a/doc/environment.md b/doc/environment.md index 95cccf7ce..07252f308 100644 --- a/doc/environment.md +++ b/doc/environment.md @@ -10,7 +10,7 @@ ## Introduction -The following environment variables configure the addresses of the databases, some credentials, some application behaviours and the localization preferences. +The following environment variables configure the addresses of the databases, some credentials, some application behaviours and the localization preferences. If you are in a development environment, your can keep most of the default values, otherwise, in production, values must be configured carefully. The settings in [config/application.yml](../config/application.yml.default) configure the environment variables when the application run in development mode. @@ -58,9 +58,9 @@ You can generate such a random key by running `rake secret`. Key and secret used to identify you Stripe account through the API. Retrieve them from https://dashboard.stripe.com/account/apikeys. -**MANDATORY**: Even if you don't want to charge your customers, you must fill this settings. +**MANDATORY**: Even if you don't want to charge your customers, you must fill this settings. For this purpose, you can use a stripe account in test mode, which will provide you test keys. -If you change these keys during the application lifecycle, you must run `rake fablab:stripe:sync_members`, otherwise your users won't be able to do card payments. +If you change these keys during the application lifecycle, you must run `rake fablab:stripe:sync_members`, otherwise your users won't be able to do card payments. STRIPE_CURRENCY @@ -125,7 +125,7 @@ If set to 'true', the admin calendar will display the scheduled events in the cu Machine and space availabilities are divided in multiple slots of the duration set by this variable. Default value is 60 minutes (1 hour). -⚠ Changing this value during the application life may cause serious issues. +⚠ Changing this value during the application life may cause serious issues. Please ensure there's no machine/space availabilities opened to reservation or already reserved **in the future** when you change this value. @@ -155,7 +155,7 @@ Identifier of your Google Analytics account. RECAPTCHA_SITE_KEY, RECAPTCHA_SECRET_KEY Configuration keys of Google ReCaptcha V2 (Checkbox). -This is optional, the captcha will be displayed on the sign-up form, only if these keys are provided. . +This is optional, the captcha will be displayed on the sign-up form, only if these keys are provided. DISQUS_SHORTNAME @@ -222,7 +222,7 @@ If this parameter is not specified, the maximum size allowed will be 5MB. MAX_IMPORT_SIZE Maximum size (in bytes) allowed for import files uploaded on the platform. -Currently, this is only used to import users from a CSV file. +Currently, this is only used to import users from a CSV file. If this parameter is not specified, the maximum size allowed will be 5MB. @@ -234,15 +234,15 @@ The check will run every weeks and if the threshold is exceeded, an alert will b ADMIN_EMAIL, ADMIN_PASSWORD -Credentials for the first admin user created when seeding the project. +Credentials for the first admin user created when seeding the project. By default, theses variables are not present in application.yml because they are only used once, when running the database seed with the command `rake db:seed`. SUPERADMIN_EMAIL -Optional email of the administrator account in charge of the system administration. +Optional email of the administrator account in charge of the system administration. If specified, it will be hidden from the administrators list and it will exclusively receive the notifications related to the system administration. -If not specified, every admins will receive system administration notifications. +If not specified, every admins will receive system administration notifications. ## Internationalization setting. diff --git a/lib/fab_hub.rb b/lib/fab_hub.rb new file mode 100644 index 000000000..f04c176fc --- /dev/null +++ b/lib/fab_hub.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +# Fab-Manager central hub (remote host) +class FabHub + def self.version_check_payload + { + origin: "#{Rails.application.secrets.default_protocol}://#{Rails.application.secrets.default_host}", + version: Version.current, + lang: I18n.default_locale.to_s + } + end + + def self.fab_manager_version_check + get('/api/versions/check', version_check_payload) + end + + def self.get(rel_url, payload) + require 'uri' + require 'net/http' + require 'json' + + uri = URI.join(hub_base_url, rel_url) + uri.query = URI.encode_www_form(payload) + + res = Net::HTTP.get_response(uri, read_timeout: 20) + JSON.parse(res.body) if res.is_a?(Net::HTTPSuccess) + end + + def self.hub_base_url + if Rails.env.production? + ENV['HUB_BASE_URL'] || 'https://hub.fab-manager.com/api' + else + ENV['HUB_BASE_URL'] || 'http://localhost:3000/api' + end + end +end \ No newline at end of file diff --git a/setup/setup.sh b/setup/setup.sh index 1eff43e57..b43076403 100755 --- a/setup/setup.sh +++ b/setup/setup.sh @@ -215,7 +215,7 @@ configure_env_file() SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS GA_ID RECAPTCHA_SITE_KEY RECAPTCHA_SECRET_KEY DISQUS_SHORTNAME TWITTER_NAME TWITTER_CONSUMER_KEY TWITTER_CONSUMER_SECRET \ TWITTER_ACCESS_TOKEN TWITTER_ACCESS_TOKEN_SECRET FACEBOOK_APP_ID LOG_LEVEL ALLOWED_EXTENSIONS ALLOWED_MIME_TYPES MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT \ SUPERADMIN_EMAIL APP_LOCALE RAILS_LOCALE MOMENT_LOCALE SUMMERNOTE_LOCALE ANGULAR_LOCALE MESSAGEFORMAT_LOCALE FULLCALENDAR_LOCALE ELASTICSEARCH_LANGUAGE_ANALYZER TIME_ZONE \ - WEEK_STARTING_DAY D3_DATE_FORMAT UIB_DATE_FORMAT EXCEL_DATE_FORMAT OPENLAB_APP_ID OPENLAB_APP_SECRET OPENLAB_DEFAULT OPENLAB_BASE_URI) + WEEK_STARTING_DAY D3_DATE_FORMAT UIB_DATE_FORMAT EXCEL_DATE_FORMAT OPENLAB_APP_ID OPENLAB_APP_SECRET OPENLAB_DEFAULT) for variable in "${variables[@]}"; do local var_doc current var_doc=$(get_md_anchor "$doc" "$variable")