Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add validations to admin settings #10348

Merged
merged 3 commits into from
Mar 23, 2019
Merged
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
73 changes: 9 additions & 64 deletions app/controllers/admin/settings_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,84 +2,29 @@

module Admin
class SettingsController < BaseController
ADMIN_SETTINGS = %w(
site_contact_username
site_contact_email
site_title
site_short_description
site_description
site_extended_description
site_terms
registrations_mode
closed_registrations_message
open_deletion
timeline_preview
show_staff_badge
bootstrap_timeline_accounts
theme
thumbnail
hero
mascot
min_invite_role
activity_api_enabled
peers_api_enabled
show_known_fediverse_at_about_page
preview_sensitive_media
custom_css
profile_directory
).freeze

BOOLEAN_SETTINGS = %w(
open_deletion
timeline_preview
show_staff_badge
activity_api_enabled
peers_api_enabled
show_known_fediverse_at_about_page
preview_sensitive_media
profile_directory
).freeze

UPLOAD_SETTINGS = %w(
thumbnail
hero
mascot
).freeze

def edit
authorize :settings, :show?

@admin_settings = Form::AdminSettings.new
end

def update
authorize :settings, :update?

settings_params.each do |key, value|
if UPLOAD_SETTINGS.include?(key)
upload = SiteUpload.where(var: key).first_or_initialize(var: key)
upload.update(file: value)
else
setting = Setting.where(var: key).first_or_initialize(var: key)
setting.update(value: value_for_update(key, value))
end
end
@admin_settings = Form::AdminSettings.new(settings_params)

flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to edit_admin_settings_path
if @admin_settings.save
flash[:notice] = I18n.t('generic.changes_saved_msg')
redirect_to edit_admin_settings_path
else
render :edit
end
end

private

def settings_params
params.require(:form_admin_settings).permit(ADMIN_SETTINGS)
end

def value_for_update(key, value)
if BOOLEAN_SETTINGS.include?(key)
value == '1'
else
value
end
params.require(:form_admin_settings).permit(*Form::AdminSettings::KEYS)
end
end
end
131 changes: 86 additions & 45 deletions app/models/form/admin_settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,49 +3,90 @@
class Form::AdminSettings
include ActiveModel::Model

delegate(
:site_contact_username,
:site_contact_username=,
:site_contact_email,
:site_contact_email=,
:site_title,
:site_title=,
:site_short_description,
:site_short_description=,
:site_description,
:site_description=,
:site_extended_description,
:site_extended_description=,
:site_terms,
:site_terms=,
:registrations_mode,
:registrations_mode=,
:closed_registrations_message,
:closed_registrations_message=,
:open_deletion,
:open_deletion=,
:timeline_preview,
:timeline_preview=,
:show_staff_badge,
:show_staff_badge=,
:bootstrap_timeline_accounts,
:bootstrap_timeline_accounts=,
:theme,
:theme=,
:min_invite_role,
:min_invite_role=,
:activity_api_enabled,
:activity_api_enabled=,
:peers_api_enabled,
:peers_api_enabled=,
:show_known_fediverse_at_about_page,
:show_known_fediverse_at_about_page=,
:preview_sensitive_media,
:preview_sensitive_media=,
:custom_css,
:custom_css=,
:profile_directory,
:profile_directory=,
to: Setting
)
KEYS = %i(
site_contact_username
site_contact_email
site_title
site_short_description
site_description
site_extended_description
site_terms
registrations_mode
closed_registrations_message
open_deletion
timeline_preview
show_staff_badge
bootstrap_timeline_accounts
theme
min_invite_role
activity_api_enabled
peers_api_enabled
show_known_fediverse_at_about_page
preview_sensitive_media
custom_css
profile_directory
).freeze

BOOLEAN_KEYS = %i(
open_deletion
timeline_preview
show_staff_badge
activity_api_enabled
peers_api_enabled
show_known_fediverse_at_about_page
preview_sensitive_media
profile_directory
).freeze

UPLOAD_KEYS = %i(
thumbnail
hero
mascot
).freeze

attr_accessor(*KEYS)

validates :site_short_description, :site_description, :site_extended_description, :site_terms, :closed_registrations_message, html: true
validates :registrations_mode, inclusion: { in: %w(open approved none) }
validates :min_invite_role, inclusion: { in: %w(disabled user moderator admin) }
validates :site_contact_email, :site_contact_username, presence: true
validates :site_contact_username, existing_username: true
validates :bootstrap_timeline_accounts, existing_username: { multiple: true }

def initialize(_attributes = {})
super
initialize_attributes
end

def save
return false unless valid?

KEYS.each do |key|
value = instance_variable_get("@#{key}")

if UPLOAD_KEYS.include?(key)
upload = SiteUpload.where(var: key).first_or_initialize(var: key)
upload.update(file: value)
else
setting = Setting.where(var: key).first_or_initialize(var: key)
setting.update(value: typecast_value(key, value))
end
end
end

private

def initialize_attributes
KEYS.each do |key|
instance_variable_set("@#{key}", Setting.public_send(key)) if instance_variable_get("@#{key}").nil?
end
end

def typecast_value(key, value)
if BOOLEAN_KEYS.include?(key)
value == '1'
else
value
end
end
end
20 changes: 20 additions & 0 deletions app/validators/existing_username_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# frozen_string_literal: true

class ExistingUsernameValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.blank?

if options[:multiple]
missing_usernames = value.split(',').map { |username| username unless Account.find_local(username) }.compact
record.errors.add(attribute, I18n.t('existing_username_validator.not_found_multiple', usernames: missing_usernames.join(', '))) if missing_usernames.any?
else
record.errors.add(attribute, I18n.t('existing_username_validator.not_found')) unless Account.find_local(value)
end
end

private

def valid_html?(str)
Nokogiri::HTML.fragment(str).to_s == str
end
end
14 changes: 14 additions & 0 deletions app/validators/html_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

class HtmlValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
return if value.blank?
record.errors.add(attribute, I18n.t('html_validator.invalid_markup')) unless valid_html?(value)
end

private

def valid_html?(str)
Nokogiri::HTML.fragment(str).to_s == str
end
end
1 change: 1 addition & 0 deletions app/views/admin/settings/edit.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
= t('admin.settings.title')

= simple_form_for @admin_settings, url: admin_settings_path, html: { method: :patch } do |f|
= render 'shared/error_messages', object: @admin_settings

.fields-group
= f.input :site_title, wrapper: :with_label, label: t('admin.settings.site_title')
Expand Down
5 changes: 5 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,9 @@ en:
content: We're sorry, but something went wrong on our end.
title: This page is not correct
noscript_html: To use the Mastodon web application, please enable JavaScript. Alternatively, try one of the <a href="%{apps_path}">native apps</a> for Mastodon for your platform.
existing_username_validator:
not_found: could not find a local user with that username
not_found_multiple: could not find %{usernames}
exports:
archive_takeout:
date: Date
Expand Down Expand Up @@ -633,6 +636,8 @@ en:
validation_errors:
one: Something isn't quite right yet! Please review the error below
other: Something isn't quite right yet! Please review %{count} errors below
html_validator:
invalid_markup: contains invalid HTML markup
identity_proofs:
active: Active
authorize: Yes, authorize
Expand Down
2 changes: 1 addition & 1 deletion config/navigation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

primary.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), admin_dashboard_url, if: proc { current_user.staff? } do |admin|
admin.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_url
admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }
admin.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), edit_admin_settings_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/settings}
admin.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_url, highlights_on: %r{/admin/custom_emojis}
admin.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_url, if: -> { current_user.admin? }, highlights_on: %r{/admin/relays}
admin.item :subscriptions, safe_join([fa_icon('paper-plane-o fw'), t('admin.subscriptions.title')]), admin_subscriptions_url, if: -> { current_user.admin? }
Expand Down
4 changes: 4 additions & 0 deletions spec/controllers/admin/settings_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
end

describe 'PUT #update' do
before do
allow_any_instance_of(Form::AdminSettings).to receive(:valid?).and_return(true)
end

describe 'for a record that doesnt exist' do
around do |example|
before = Setting.site_extended_description
Expand Down