Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions app/controllers/storage_settings_controller.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
# 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

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

Expand All @@ -22,6 +34,13 @@ def create
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
Expand All @@ -31,4 +50,12 @@ def storage_configs
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
21 changes: 19 additions & 2 deletions app/views/storage_settings/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -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">
Expand All @@ -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>
Expand Down
3 changes: 3 additions & 0 deletions config/locales/i18n.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
50 changes: 50 additions & 0 deletions spec/requests/storage_settings_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions spec/system/storage_settings_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@
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
Expand Down Expand Up @@ -93,6 +104,19 @@
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
Expand Down