diff --git a/app/controllers/storage_settings_controller.rb b/app/controllers/storage_settings_controller.rb index 4b3a8390..30e73572 100644 --- a/app/controllers/storage_settings_controller.rb +++ b/app/controllers/storage_settings_controller.rb @@ -1,6 +1,12 @@ # frozen_string_literal: true class StorageSettingsController < ApplicationController + ENV_STORAGE_SERVICES = { + 'S3_ATTACHMENTS_BUCKET' => ['aws_s3', 'AWS S3'], + 'GCS_BUCKET' => ['google', 'GCP'], + 'AZURE_CONTAINER' => ['azure', 'Azure'] + }.freeze + before_action :load_encrypted_config authorize_resource :encrypted_config, only: :index authorize_resource :encrypted_config, parent: false, only: :create @@ -8,6 +14,12 @@ class StorageSettingsController < ApplicationController def index; end def create + if @env_storage_service.present? + redirect_to settings_storage_index_path, alert: I18n.t('storage_settings_are_managed_by_environment_variables') + + return + end + if @encrypted_config.update(storage_configs) LoadActiveStorageConfigs.reload @@ -22,6 +34,13 @@ class StorageSettingsController < ApplicationController def load_encrypted_config @encrypted_config = EncryptedConfig.find_or_initialize_by(account: current_account, key: EncryptedConfig::FILES_STORAGE_KEY) + @env_storage_env_var, @env_storage_service, @env_storage_service_label = env_storage_service + @storage_value = + if @env_storage_service.present? + { 'service' => @env_storage_service } + else + @encrypted_config.value || { 'service' => 'disk' } + end end def storage_configs @@ -31,4 +50,12 @@ class StorageSettingsController < ApplicationController e.dig(:value, :configs)&.compact_blank! end end + + def env_storage_service + ENV_STORAGE_SERVICES.each do |env_var, (service, label)| + return [env_var, service, label] if ENV[env_var].present? + end + + nil + end end diff --git a/app/views/storage_settings/index.html.erb b/app/views/storage_settings/index.html.erb index 9a53e79a..3441b401 100644 --- a/app/views/storage_settings/index.html.erb +++ b/app/views/storage_settings/index.html.erb @@ -4,9 +4,25 @@

<%= t('storage') %>

- <% value = @encrypted_config.value || { 'service' => 'disk' } %> + <% value = @storage_value %> <% configs = value['configs'] || {} %> + <% if @env_storage_service.present? %> +
+ <%= svg_icon('info_circle', class: 'stroke-current flex-shrink-0 w-6 h-6') %> +
+

+ <%= t('storage_settings_are_managed_by_environment_variables') %> +

+

+ <%= t('storage_provider_is_configured_by_env_var_html', service: @env_storage_service_label, variable: @env_storage_env_var) %> +
+ <%= t('update_environment_variables_and_restart_the_app_to_change_storage') %> +

+
+
+ <% end %> <%= form_for @encrypted_config, url: settings_storage_index_path, method: :post, html: { autocomplete: 'off', class: 'w-full' } do |f| %> +
> <% options = [%w[Disk disk], %w[AWS aws_s3], %w[GCP google], %w[Azure azure]] %>
<% end %>
diff --git a/config/locales/i18n.yml b/config/locales/i18n.yml index d40fc480..81ff78e0 100644 --- a/config/locales/i18n.yml +++ b/config/locales/i18n.yml @@ -396,6 +396,9 @@ en: &en for_aws_s3_compatible_apis_like_minio: For AWS S3 compatible APIs like Minio. store_all_files_on_disk: Store all files on disk no_configs_are_needed_but_make_sure_your_disk_is_persistent: No configs are needed but make sure your disk is persistent + storage_settings_are_managed_by_environment_variables: Storage settings are managed by environment variables. + storage_provider_is_configured_by_env_var_html: 'Current provider: %{service} via %{variable}.' + update_environment_variables_and_restart_the_app_to_change_storage: Update environment variables and restart the app to change storage. not_suitable_for_heroku_and_other_paas: Not suitable for Heroku and other PaaS bulk_send_from_excel_xlsx_or_csv: Bulk send from Excel XLSX or CSV add_new: Add New diff --git a/spec/requests/storage_settings_controller_spec.rb b/spec/requests/storage_settings_controller_spec.rb new file mode 100644 index 00000000..3de679de --- /dev/null +++ b/spec/requests/storage_settings_controller_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +RSpec.describe 'StorageSettingsController', type: :request do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + + def with_env(overrides) + previous_values = {} + overrides.each_key { |key| previous_values[key] = ENV[key] } + overrides.each { |key, value| ENV[key] = value } + yield + ensure + previous_values.each do |key, value| + value.nil? ? ENV.delete(key) : ENV[key] = value + end + end + + before do + sign_in(user) + end + + describe 'POST /settings/storage' do + it 'does not update storage settings when environment variables manage storage' do + encrypted_config = create(:encrypted_config, account:, key: EncryptedConfig::FILES_STORAGE_KEY, value: { + service: 'aws_s3', + configs: { + access_key_id: 'db_access_key', + secret_access_key: 'db_secret_key', + region: 'us-east-1', + bucket: 'db-bucket' + } + }) + + with_env('S3_ATTACHMENTS_BUCKET' => 'env-bucket') do + expect do + post settings_storage_index_path, params: { + encrypted_config: { + value: { + service: 'disk', + configs: {} + } + } + } + end.not_to(change { encrypted_config.reload.value }) + + expect(response).to redirect_to(settings_storage_index_path) + end + end + end +end diff --git a/spec/system/storage_settings_spec.rb b/spec/system/storage_settings_spec.rb index c11d0ea0..97a4f939 100644 --- a/spec/system/storage_settings_spec.rb +++ b/spec/system/storage_settings_spec.rb @@ -8,6 +8,17 @@ RSpec.describe 'Storage Settings' do sign_in(user) end + def with_env(overrides) + previous_values = {} + overrides.each_key { |key| previous_values[key] = ENV[key] } + overrides.each { |key, value| ENV[key] = value } + yield + ensure + previous_values.each do |key, value| + value.nil? ? ENV.delete(key) : ENV[key] = value + end + end + context 'when storage settings are not set' do before do visit settings_storage_index_path @@ -93,6 +104,19 @@ RSpec.describe 'Storage Settings' do end end + context 'when storage is configured via environment variables' do + it 'shows the env-managed provider and disables updates' do + with_env('S3_ATTACHMENTS_BUCKET' => 'env-bucket') do + visit settings_storage_index_path + + expect(page).to have_content('Storage settings are managed by environment variables.') + expect(page).to have_content('Current provider: AWS S3 via S3_ATTACHMENTS_BUCKET.') + expect(page).to have_checked_field('AWS') + expect(page).to have_button('Save', disabled: true) + end + end + end + context 'when storage settings are set' do context 'when updates the same storage settings' do context 'when AWS S3' do