Make storage settings UI env-aware and prevent overrides

pull/603/head
Larron Armstead 3 weeks ago
parent d4e94ac2bc
commit 683056e87b

@ -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

@ -4,9 +4,25 @@
<h1 class="text-4xl font-bold mb-4">
<%= t('storage') %>
</h1>
<% value = @encrypted_config.value || { 'service' => 'disk' } %>
<% value = @storage_value %>
<% configs = value['configs'] || {} %>
<% if @env_storage_service.present? %>
<div class="alert my-4">
<%= svg_icon('info_circle', class: 'stroke-current flex-shrink-0 w-6 h-6') %>
<div>
<p class="font-bold">
<%= t('storage_settings_are_managed_by_environment_variables') %>
</p>
<p class="text-gray-700">
<%= t('storage_provider_is_configured_by_env_var_html', service: @env_storage_service_label, variable: @env_storage_env_var) %>
<br>
<%= t('update_environment_variables_and_restart_the_app_to_change_storage') %>
</p>
</div>
</div>
<% end %>
<%= form_for @encrypted_config, url: settings_storage_index_path, method: :post, html: { autocomplete: 'off', class: 'w-full' } do |f| %>
<fieldset <%= 'disabled' if @env_storage_service.present? %>>
<% options = [%w[Disk disk], %w[AWS aws_s3], %w[GCP google], %w[Azure azure]] %>
<toggle-visible data-element-ids="<%= options.map(&:last).to_json %>" class="block relative">
<ul class="items-center w-full text-sm font-medium text-gray-900 space-y-2 sm:space-y-0 sm:flex sm:space-x-2">
@ -31,8 +47,9 @@
<%= render 'azure_form', f:, configs:, value: %>
</disable-hidden>
<div class="form-control">
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button' %>
<%= f.button button_title(title: t('save'), disabled_with: t('saving')), class: 'base-button', disabled: @env_storage_service.present? %>
</div>
</fieldset>
<% end %>
</div>
<div class="w-0 md:w-52"></div>

@ -395,6 +395,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: <b>%{service}</b> via <code>%{variable}</code>.'
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

@ -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

@ -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

Loading…
Cancel
Save