From f2f5e911cf4d4eda57b20b8614ac0ace98c83c5b Mon Sep 17 00:00:00 2001 From: Michael Kohl Date: Mon, 26 Apr 2021 11:39:19 +0700 Subject: [PATCH] Add Settings::Mascot (#13451) * Add Settings::Mascot * Add DUS * Update usage * Fix e2e test and controller * Fix specs * Fix remaining spec --- .../admin/settings/mascots_controller.rb | 34 ++++++++ app/controllers/chat_channels_controller.rb | 8 +- app/controllers/comments_controller.rb | 2 +- app/controllers/search_controller.rb | 2 +- app/lib/constants/settings/mascot.rb | 32 ++++++++ app/lib/constants/site_config.rb | 24 ------ app/models/article.rb | 6 +- app/models/comment.rb | 4 +- app/models/reaction.rb | 2 +- app/models/settings/mascot.rb | 25 ++++++ app/models/user.rb | 2 +- .../authentication/providers/apple.rb | 2 +- app/services/users/create_mascot_account.rb | 6 +- app/views/admin/configs/show.html.erb | 58 +++++++------- .../feedback_messages/_abuse_reports.html.erb | 2 +- app/views/comments/_comment_avatar.html.erb | 2 +- .../deleted_commentable_comment.html.erb | 2 +- app/views/dashboards/show.html.erb | 6 +- app/views/layouts/_footer.html.erb | 10 +-- config/routes.rb | 1 + .../adminFlows/config/mascotSection.js | 77 +++++++++++++++++++ .../20210420050243_create_settings_mascots.rb | 16 ++++ db/schema.rb | 8 ++ .../20210420050256_move_mascot_settings.rb | 18 +++++ .../move_mascot_settings_spec.rb | 28 +++++++ spec/models/article_spec.rb | 4 +- spec/models/comment_spec.rb | 2 +- spec/models/reaction_spec.rb | 4 +- spec/models/user_spec.rb | 2 +- spec/requests/admin/configs_spec.rb | 74 ++++++++++-------- spec/requests/comments_create_spec.rb | 2 +- spec/requests/registrations_spec.rb | 4 +- .../chat_channel_membership_spec.rb | 6 +- .../users/create_mascot_account_spec.rb | 4 +- spec/views/dashboards/show.html.erb_spec.rb | 2 +- 35 files changed, 353 insertions(+), 128 deletions(-) create mode 100644 app/controllers/admin/settings/mascots_controller.rb create mode 100644 app/lib/constants/settings/mascot.rb create mode 100644 app/models/settings/mascot.rb create mode 100644 cypress/integration/adminFlows/config/mascotSection.js create mode 100644 db/migrate/20210420050243_create_settings_mascots.rb create mode 100644 lib/data_update_scripts/20210420050256_move_mascot_settings.rb create mode 100644 spec/lib/data_update_scripts/move_mascot_settings_spec.rb diff --git a/app/controllers/admin/settings/mascots_controller.rb b/app/controllers/admin/settings/mascots_controller.rb new file mode 100644 index 000000000..cd4e66f0a --- /dev/null +++ b/app/controllers/admin/settings/mascots_controller.rb @@ -0,0 +1,34 @@ +module Admin + module Settings + class MascotsController < Admin::ApplicationController + def create + errors = upsert_config(settings_params) + + if errors.none? + Audit::Logger.log(:internal, current_user, params.dup) + redirect_to admin_config_path, notice: "Site configuration was successfully updated." + else + redirect_to admin_config_path, alert: "😭 #{errors.to_sentence}" + end + end + + def settings_params + params + .require(:settings_mascot) + .permit(*::Settings::Mascot.keys) + end + + def upsert_config(configs) + errors = [] + configs.each do |key, value| + ::Settings::Mascot.public_send("#{key}=", value) if value.present? + rescue ActiveRecord::RecordInvalid => e + errors << e.message + next + end + + errors + end + end + end +end diff --git a/app/controllers/chat_channels_controller.rb b/app/controllers/chat_channels_controller.rb index 9b75d8438..ecc56f786 100644 --- a/app/controllers/chat_channels_controller.rb +++ b/app/controllers/chat_channels_controller.rb @@ -57,10 +57,10 @@ class ChatChannelsController < ApplicationController flash[:error] = chat_channel.errors.full_messages.to_sentence else if chat_channel_params[:discoverable].to_i.zero? - ChatChannelMembership.create(user_id: SiteConfig.mascot_user_id, chat_channel_id: chat_channel.id, + ChatChannelMembership.create(user_id: Settings::Mascot.mascot_user_id, chat_channel_id: chat_channel.id, role: "member", status: "active") else - ChatChannelMembership.find_by(user_id: SiteConfig.mascot_user_id)&.destroy + ChatChannelMembership.find_by(user_id: Settings::Mascot.mascot_user_id)&.destroy end flash[:settings_notice] = "Channel settings updated." end @@ -76,10 +76,10 @@ class ChatChannelsController < ApplicationController message: "Channel settings updation failed. Try again later." }, success: :bad_request else if chat_channel_params[:discoverable] - ChatChannelMembership.create(user_id: SiteConfig.mascot_user_id, chat_channel_id: @chat_channel.id, + ChatChannelMembership.create(user_id: Settings::Mascot.mascot_user_id, chat_channel_id: @chat_channel.id, role: "member", status: "active") else - ChatChannelMembership.find_by(user_id: SiteConfig.mascot_user_id)&.destroy + ChatChannelMembership.find_by(user_id: Settings::Mascot.mascot_user_id)&.destroy end render json: { success: true, message: "Channel settings updated.", data: {} }, success: :ok end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 154626e34..4c009ddfb 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -110,7 +110,7 @@ class CommentsController < ApplicationController response_template = ResponseTemplate.find(params[:response_template][:id]) authorize response_template, :moderator_create? - moderator = User.find(SiteConfig.mascot_user_id) + moderator = User.find(Settings::Mascot.mascot_user_id) @comment = Comment.new(permitted_attributes(Comment)) @comment.user_id = moderator.id @comment.body_markdown = response_template.content diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 501fabc54..e43dc590b 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -73,7 +73,7 @@ class SearchController < ApplicationController def chat_channels user_ids = if chat_channel_params[:user_id].present? - [current_user.id, SiteConfig.mascot_user_id, chat_channel_params[:user_id]].reject(&:blank?) + [current_user.id, Settings::Mascot.mascot_user_id, chat_channel_params[:user_id]].reject(&:blank?) else [current_user.id] end diff --git a/app/lib/constants/settings/mascot.rb b/app/lib/constants/settings/mascot.rb new file mode 100644 index 000000000..4c325a70d --- /dev/null +++ b/app/lib/constants/settings/mascot.rb @@ -0,0 +1,32 @@ +module Constants + module Settings + module Mascot + DETAILS = { + footer_image_url: { + description: "Special cute mascot image used in the footer.", + placeholder: ::Constants::SiteConfig::IMAGE_PLACEHOLDER + }, + footer_image_width: { + description: "The footer mascot width will resized to this value, defaults to 52", + placeholder: "" + }, + footer_image_height: { + description: "The footer mascot height will be resized to this value, defaults to 120", + placeholder: "" + }, + image_description: { + description: "Used as the alt text for the mascot image", + placeholder: "" + }, + image_url: { + description: "Used as the mascot image.", + placeholder: ::Constants::SiteConfig::IMAGE_PLACEHOLDER + }, + mascot_user_id: { + description: "User ID of the Mascot account", + placeholder: "1" + } + }.freeze + end + end +end diff --git a/app/lib/constants/site_config.rb b/app/lib/constants/site_config.rb index a9ff8df5e..b2bdd4c4a 100644 --- a/app/lib/constants/site_config.rb +++ b/app/lib/constants/site_config.rb @@ -118,30 +118,6 @@ module Constants description: "Community Moderators Newsletter ID", placeholder: "" }, - mascot_footer_image_url: { - description: "Special cute mascot image used in the footer.", - placeholder: IMAGE_PLACEHOLDER - }, - mascot_footer_image_width: { - description: "The footer mascot width will resized to this value, defaults to 52", - placeholder: "" - }, - mascot_footer_image_height: { - description: "The footer mascot height will be resized to this value, defaults to 120", - placeholder: "" - }, - mascot_image_description: { - description: "Used as the alt text for the mascot image", - placeholder: "" - }, - mascot_image_url: { - description: "Used as the mascot image.", - placeholder: IMAGE_PLACEHOLDER - }, - mascot_user_id: { - description: "User ID of the Mascot account", - placeholder: "1" - }, meta_keywords: { description: "", placeholder: "List of valid keywords: comma separated, letters only e.g. engineering, development" diff --git a/app/models/article.rb b/app/models/article.rb index 565772369..e1059c896 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -181,7 +181,7 @@ class Article < ApplicationRecord published .where(user_id: User.with_role(:super_admin) .union(User.with_role(:admin)) - .union(id: [SiteConfig.staff_user_id, SiteConfig.mascot_user_id].compact) + .union(id: [SiteConfig.staff_user_id, Settings::Mascot.mascot_user_id].compact) .select(:id)).order(published_at: :desc).tagged_with(tag_name) } @@ -792,7 +792,7 @@ class Article < ApplicationRecord return unless SiteConfig.spam_trigger_terms.any? { |term| Regexp.new(term.downcase).match?(title.downcase) } Reaction.create( - user_id: SiteConfig.mascot_user_id, + user_id: Settings::Mascot.mascot_user_id, reactable_id: id, reactable_type: "Article", category: "vomit", @@ -802,7 +802,7 @@ class Article < ApplicationRecord user.add_role(:suspended) Note.create( - author_id: SiteConfig.mascot_user_id, + author_id: Settings::Mascot.mascot_user_id, noteable_id: user_id, noteable_type: "User", reason: "automatic_suspend", diff --git a/app/models/comment.rb b/app/models/comment.rb index 49e28857c..4d5c0fda6 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -287,7 +287,7 @@ class Comment < ApplicationRecord user.registered_at > 5.days.ago Reaction.create( - user_id: SiteConfig.mascot_user_id, + user_id: Settings::Mascot.mascot_user_id, reactable_id: id, reactable_type: "Comment", category: "vomit", @@ -297,7 +297,7 @@ class Comment < ApplicationRecord user.add_role(:suspended) Note.create( - author_id: SiteConfig.mascot_user_id, + author_id: Settings::Mascot.mascot_user_id, noteable_id: user_id, noteable_type: "User", reason: "automatic_suspend", diff --git a/app/models/reaction.rb b/app/models/reaction.rb index cbba6b6eb..62a95af05 100644 --- a/app/models/reaction.rb +++ b/app/models/reaction.rb @@ -130,7 +130,7 @@ class Reaction < ApplicationRecord end def negative_reaction_from_untrusted_user? - return if user&.any_admin? || user&.id == SiteConfig.mascot_user_id + return if user&.any_admin? || user&.id == Settings::Mascot.mascot_user_id negative? && !user.trusted end diff --git a/app/models/settings/mascot.rb b/app/models/settings/mascot.rb new file mode 100644 index 000000000..42d297915 --- /dev/null +++ b/app/models/settings/mascot.rb @@ -0,0 +1,25 @@ +module Settings + class Mascot < RailsSettings::Base + self.table_name = :settings_mascots + + # The configuration is cached, change this if you want to force update + # the cache, or call Settings::Mascot.clear_cache + cache_prefix { "v1" } + + field :footer_image_height, type: :integer, default: 120 + field :footer_image_url, type: :string, validates: { url: true } + field :footer_image_width, type: :integer, default: 52 + field :image_description, type: :string, default: "The community mascot" + field :image_url, + type: :string, + default: proc { URL.local_image("mascot.png") }, + validates: { url: true } + field :mascot_user_id, type: :integer, default: nil + + # NOTE: @citizen428 - This is duplicated for now, I will refactor once + # all settings models have been extracted. + def self.get_default(field) + get_field(field)[:default] + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index c7dd4945d..365a56cda 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -312,7 +312,7 @@ class User < ApplicationRecord end def self.mascot_account - find_by(id: SiteConfig.mascot_user_id) + find_by(id: Settings::Mascot.mascot_user_id) end def tag_line diff --git a/app/services/authentication/providers/apple.rb b/app/services/authentication/providers/apple.rb index 58812685b..5e5893481 100644 --- a/app/services/authentication/providers/apple.rb +++ b/app/services/authentication/providers/apple.rb @@ -20,7 +20,7 @@ module Authentication } if Rails.env.test? - user_data[:profile_image] = SiteConfig.mascot_image_url + user_data[:profile_image] = Settings::Mascot.image_url else user_data[:remote_profile_image_url] = Users::ProfileImageGenerator.call end diff --git a/app/services/users/create_mascot_account.rb b/app/services/users/create_mascot_account.rb index db1c8f701..4be3bd84f 100644 --- a/app/services/users/create_mascot_account.rb +++ b/app/services/users/create_mascot_account.rb @@ -4,7 +4,7 @@ module Users email: "mascot@forem.com", username: "mascot", name: "Mascot", - profile_image: SiteConfig.mascot_image_url, + profile_image: Settings::Mascot.image_url, confirmed_at: Time.current, registered_at: Time.current, password: SecureRandom.hex @@ -15,10 +15,10 @@ module Users end def call - raise "Mascot already set" if SiteConfig.mascot_user_id + raise "Mascot already set" if Settings::Mascot.mascot_user_id mascot = User.create!(mascot_params) - SiteConfig.mascot_user_id = mascot.id + Settings::Mascot.mascot_user_id = mascot.id end def mascot_params diff --git a/app/views/admin/configs/show.html.erb b/app/views/admin/configs/show.html.erb index b2c7d70d9..b44ca5049 100644 --- a/app/views/admin/configs/show.html.erb +++ b/app/views/admin/configs/show.html.erb @@ -768,7 +768,7 @@ <% end %> - <%= form_for(SiteConfig.new, url: admin_config_path) do |f| %> + <%= form_for(Settings::Mascot.new, url: admin_settings_mascots_path, html: { data: { testid: "mascotSectionForm" } }) do |f| %>
<%= render partial: "admin/shared/card_header", locals: { @@ -780,64 +780,64 @@
- <%= admin_config_label :mascot_user_id, "Mascot user ID" %> - <%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_user_id][:description] %> + <%= admin_config_label :mascot_user_id, "Mascot user ID", model: Settings::Mascot %> + <%= admin_config_description Constants::Settings::Mascot::DETAILS[:mascot_user_id][:description] %> <%= f.text_field :mascot_user_id, class: "crayons-textfield", - value: SiteConfig.mascot_user_id, + value: Settings::Mascot.mascot_user_id, min: 1, - placeholder: Constants::SiteConfig::DETAILS[:mascot_user_id][:placeholder] %> + placeholder: Constants::Settings::Mascot::DETAILS[:mascot_user_id][:placeholder] %>
- <%= admin_config_label :mascot_image_url, "Mascot Image URL" %> - <%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_image_url][:description] %> - <%= f.text_field :mascot_image_url, + <%= admin_config_label :image_url, "Mascot Image URL", model: Settings::Mascot %> + <%= admin_config_description Constants::Settings::Mascot::DETAILS[:image_url][:description] %> + <%= f.text_field :image_url, class: "crayons-textfield", - value: SiteConfig.mascot_image_url, - placeholder: Constants::SiteConfig::DETAILS[:mascot_image_url][:placeholder] %> + value: Settings::Mascot.image_url, + placeholder: Constants::Settings::Mascot::DETAILS[:image_url][:placeholder] %>
- <%= SiteConfig.mascot_image_description %> + <%= Settings::Mascot.image_description %>
- <%= admin_config_label :mascot_footer_image_url %> - <%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_footer_image_url][:description] %> - <%= f.text_field :mascot_footer_image_url, + <%= admin_config_label :footer_image_url, model: Settings::Mascot %> + <%= admin_config_description Constants::Settings::Mascot::DETAILS[:footer_image_url][:description] %> + <%= f.text_field :footer_image_url, class: "crayons-textfield", - value: SiteConfig.mascot_footer_image_url, - placeholder: Constants::SiteConfig::DETAILS[:mascot_footer_image_url][:placeholder] %> + value: Settings::Mascot.footer_image_url, + placeholder: Constants::Settings::Mascot::DETAILS[:footer_image_url][:placeholder] %>
- <%= SiteConfig.mascot_image_description %> + <%= Settings::Mascot.image_description %>
- <%= admin_config_label :mascot_footer_image_width %> - <%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_footer_image_width][:description] %> - <%= f.text_field :mascot_footer_image_width, + <%= admin_config_label :footer_image_width, model: Settings::Mascot %> + <%= admin_config_description Constants::Settings::Mascot::DETAILS[:footer_image_width][:description] %> + <%= f.text_field :footer_image_width, class: "form-control", - value: SiteConfig.mascot_footer_image_width %> + value: Settings::Mascot.footer_image_width %>
- <%= admin_config_label :mascot_footer_image_height %> - <%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_footer_image_height][:description] %> - <%= f.text_field :mascot_footer_image_height, + <%= admin_config_label :footer_image_height, model: Settings::Mascot %> + <%= admin_config_description Constants::Settings::Mascot::DETAILS[:footer_image_height][:description] %> + <%= f.text_field :footer_image_height, class: "form-control", - value: SiteConfig.mascot_footer_image_height %> + value: Settings::Mascot.footer_image_height %>
- <%= admin_config_label :mascot_image_description %> - <%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_image_description][:description] %> - <%= f.text_field :mascot_image_description, + <%= admin_config_label :image_description, model: Settings::Mascot %> + <%= admin_config_description Constants::Settings::Mascot::DETAILS[:image_description][:description] %> + <%= f.text_field :image_description, class: "form-control", - value: SiteConfig.mascot_image_description %> + value: Settings::Mascot.image_description %>
<%= render "form_submission", f: f %> diff --git a/app/views/admin/feedback_messages/_abuse_reports.html.erb b/app/views/admin/feedback_messages/_abuse_reports.html.erb index b3eecf806..ce17b4532 100644 --- a/app/views/admin/feedback_messages/_abuse_reports.html.erb +++ b/app/views/admin/feedback_messages/_abuse_reports.html.erb @@ -31,7 +31,7 @@ data-reaction-url-value="<%= admin_reaction_path(reaction.id) %>"> 🤢 @<%= reaction.user.username %> - <% if reaction.user_id == SiteConfig.mascot_user_id %> + <% if reaction.user_id == Settings::Mascot.mascot_user_id %> (auto-generated) <% end %> diff --git a/app/views/comments/_comment_avatar.html.erb b/app/views/comments/_comment_avatar.html.erb index bd9e77d2e..289838706 100644 --- a/app/views/comments/_comment_avatar.html.erb +++ b/app/views/comments/_comment_avatar.html.erb @@ -1,6 +1,6 @@ <% if comment.deleted %> - <%= image_tag(Images::Optimizer.call(SiteConfig.mascot_image_url, width: 32, height: 32, crop: "imagga_scale"), class: "crayons-avatar__image overflow-hidden", alt: "Sloan, the sloth mascot", loading: "lazy") %> + <%= image_tag(Images::Optimizer.call(Settings::Mascot.image_url, width: 32, height: 32, crop: "imagga_scale"), class: "crayons-avatar__image overflow-hidden", alt: "Sloan, the sloth mascot", loading: "lazy") %> <% else %> diff --git a/app/views/comments/deleted_commentable_comment.html.erb b/app/views/comments/deleted_commentable_comment.html.erb index 795a9b2a1..533f3590d 100644 --- a/app/views/comments/deleted_commentable_comment.html.erb +++ b/app/views/comments/deleted_commentable_comment.html.erb @@ -14,7 +14,7 @@ <% if decorated_comment.low_quality %> <% end %> diff --git a/app/views/dashboards/show.html.erb b/app/views/dashboards/show.html.erb index b995bc56b..da3a539d9 100644 --- a/app/views/dashboards/show.html.erb +++ b/app/views/dashboards/show.html.erb @@ -55,9 +55,9 @@ <% else %>
- <% if SiteConfig.mascot_image_url.present? %> - <% image_url = Images::Optimizer.call(SiteConfig.mascot_image_url, width: 300, crop: "imagga_scale") %> - <%= image_tag(image_url, class: "sloan mb-7", alt: SiteConfig.mascot_image_description.to_s) %> + <% if Settings::Mascot.image_url.present? %> + <% image_url = Images::Optimizer.call(Settings::Mascot.image_url, width: 300, crop: "imagga_scale") %> + <%= image_tag(image_url, class: "sloan mb-7", alt: Settings::Mascot.image_description.to_s) %> <% end %>

This is where you can manage your posts, but you haven't written anything yet.

Write your first post now

diff --git a/app/views/layouts/_footer.html.erb b/app/views/layouts/_footer.html.erb index 7a2f442fb..9f328fa7a 100644 --- a/app/views/layouts/_footer.html.erb +++ b/app/views/layouts/_footer.html.erb @@ -25,12 +25,12 @@
- <% if SiteConfig.mascot_footer_image_url.present? %> - <%= image_tag(Images::Optimizer.call(SiteConfig.mascot_footer_image_url, width: 100), + <% if Settings::Mascot.footer_image_url.present? %> + <%= image_tag(Images::Optimizer.call(Settings::Mascot.footer_image_url, width: 100), class: "crayons-footer__mascot", - alt: SiteConfig.mascot_image_description, - width: SiteConfig.mascot_footer_image_width, - height: SiteConfig.mascot_footer_image_height, + alt: Settings::Mascot.image_description, + width: Settings::Mascot.footer_image_width, + height: Settings::Mascot.footer_image_height, loading: "lazy") %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 0bd58d662..e7998672f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -61,6 +61,7 @@ Rails.application.routes.draw do namespace :settings do resources :authentications, only: [:create] resources :campaigns, only: [:create] + resources :mascots, only: [:create] resources :rate_limits, only: [:create] end namespace :users do diff --git a/cypress/integration/adminFlows/config/mascotSection.js b/cypress/integration/adminFlows/config/mascotSection.js new file mode 100644 index 000000000..93ee21b3e --- /dev/null +++ b/cypress/integration/adminFlows/config/mascotSection.js @@ -0,0 +1,77 @@ +describe('Mascot Section', () => { + beforeEach(() => { + cy.testSetup(); + cy.fixture('users/adminUser.json').as('user'); + + cy.get('@user').then((user) => { + cy.loginUser(user); + }); + }); + + describe('mascot image setting', () => { + it('rejects an invalid image URL', () => { + cy.get('@user').then(({ username }) => { + cy.visit('/admin/config'); + cy.findByTestId('mascotSectionForm').as('mascotSectionForm'); + + cy.get('@mascotSectionForm').findByText('Mascot').click(); + cy.get('@mascotSectionForm') + .get('#settings_mascot_image_url') + .clear() + .type('example.com/image.png'); + + cy.get('@mascotSectionForm') + .findByPlaceholderText('Confirmation text') + .type( + `My username is @${username} and this action is 100% safe and appropriate.`, + ); + + cy.get('@mascotSectionForm') + .findByText('Update Site Configuration') + .click(); + + cy.url().should('contains', '/admin/config'); + + cy.findByText( + '😭 Validation failed: Image url is not a valid URL', + ).should('be.visible'); + }); + }); + + it('accepts a valid image URL', () => { + cy.get('@user').then(({ username }) => { + cy.visit('/admin/config'); + cy.findByTestId('mascotSectionForm').as('mascotSectionForm'); + + cy.get('@mascotSectionForm').findByText('Mascot').click(); + cy.get('@mascotSectionForm') + .get('#settings_mascot_image_url') + .clear() + .type('https://example.com/image.png'); + + cy.get('@mascotSectionForm') + .findByPlaceholderText('Confirmation text') + .type( + `My username is @${username} and this action is 100% safe and appropriate.`, + ); + + cy.get('@mascotSectionForm') + .findByText('Update Site Configuration') + .click(); + + cy.url().should('contains', '/admin/config'); + + cy.findByText('Site configuration was successfully updated.').should( + 'be.visible', + ); + + // Page reloaded so need to get a new reference to the form. + cy.get('#new_settings_mascot').as('mascotSectionForm'); + cy.get('#settings_mascot_image_url').should( + 'have.value', + 'https://example.com/image.png', + ); + }); + }); + }); +}); diff --git a/db/migrate/20210420050243_create_settings_mascots.rb b/db/migrate/20210420050243_create_settings_mascots.rb new file mode 100644 index 000000000..1f8e62af5 --- /dev/null +++ b/db/migrate/20210420050243_create_settings_mascots.rb @@ -0,0 +1,16 @@ +class CreateSettingsMascots < ActiveRecord::Migration[6.1] + def self.up + create_table :settings_mascots do |t| + t.string :var, null: false + t.text :value, null: true + + t.timestamps + end + + add_index :settings_mascots, :var, unique: true + end + + def self.down + drop_table :settings_mascots + end +end diff --git a/db/schema.rb b/db/schema.rb index 7519cfda1..7d44620f4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1082,6 +1082,14 @@ ActiveRecord::Schema.define(version: 2021_04_23_162847) do t.index ["var"], name: "index_settings_campaigns_on_var", unique: true end + create_table "settings_mascots", force: :cascade do |t| + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.text "value" + t.string "var", null: false + t.index ["var"], name: "index_settings_mascots_on_var", unique: true + end + create_table "settings_rate_limits", force: :cascade do |t| t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false diff --git a/lib/data_update_scripts/20210420050256_move_mascot_settings.rb b/lib/data_update_scripts/20210420050256_move_mascot_settings.rb new file mode 100644 index 000000000..41e96133a --- /dev/null +++ b/lib/data_update_scripts/20210420050256_move_mascot_settings.rb @@ -0,0 +1,18 @@ +module DataUpdateScripts + class MoveMascotSettings + SETTINGS = %w[ + footer_image_height + footer_image_url + footer_image_width + image_description + image_url + ].freeze + + def run + SETTINGS.each do |setting| + Settings::Mascot.public_send("#{setting}=", SiteConfig.public_send("mascot_#{setting}")) + end + Settings::Mascot.mascot_user_id = SiteConfig.mascot_user_id + end + end +end diff --git a/spec/lib/data_update_scripts/move_mascot_settings_spec.rb b/spec/lib/data_update_scripts/move_mascot_settings_spec.rb new file mode 100644 index 000000000..5b12ceaf4 --- /dev/null +++ b/spec/lib/data_update_scripts/move_mascot_settings_spec.rb @@ -0,0 +1,28 @@ +require "rails_helper" +require Rails.root.join( + "lib/data_update_scripts/20210420050256_move_mascot_settings.rb", +) + +describe DataUpdateScripts::MoveMascotSettings do + before do + allow(SiteConfig).to receive(:mascot_footer_image_url) + .and_return("https://example.com/mascot.png") + end + + it "moves renamed settings" do + allow(SiteConfig).to receive(:mascot_image_description).and_return("Bla") + + expect do + described_class.new.run + end + .to change(Settings::Mascot, :image_description) + .and change(Settings::Mascot, :footer_image_url) + end + + it "moves the non-renamed./spec/lib/data_update_scripts/move_mascot_settings_spec.rb setting" do + allow(SiteConfig).to receive(:mascot_user_id).and_return(42) + expect do + described_class.new.run + end.to change(Settings::Mascot, :mascot_user_id).to(42) + end +end diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index 95f04a804..4dd94f568 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -55,7 +55,7 @@ RSpec.describe Article, type: :model do describe "::admin_published_with" do it "includes mascot-published articles" do - allow(SiteConfig).to receive(:mascot_user_id).and_return(3) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(3) user = create(:user, id: 3) create(:article, user: user, tags: "challenge") expect(described_class.admin_published_with("challenge").count).to eq(1) @@ -908,7 +908,7 @@ RSpec.describe Article, type: :model do describe "spam" do before do - allow(SiteConfig).to receive(:mascot_user_id).and_return(user.id) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(user.id) allow(SiteConfig).to receive(:spam_trigger_terms).and_return( ["yahoomagoo gogo", "testtestetest", "magoo.+magee"], ) diff --git a/spec/models/comment_spec.rb b/spec/models/comment_spec.rb index ed85829fd..b5063531e 100644 --- a/spec/models/comment_spec.rb +++ b/spec/models/comment_spec.rb @@ -431,7 +431,7 @@ RSpec.describe Comment, type: :model do describe "spam" do before do - allow(SiteConfig).to receive(:mascot_user_id).and_return(user.id) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(user.id) allow(SiteConfig).to receive(:spam_trigger_terms).and_return(["yahoomagoo gogo", "anothertestterm"]) end diff --git a/spec/models/reaction_spec.rb b/spec/models/reaction_spec.rb index 96216f1fe..d5dfe6a9a 100644 --- a/spec/models/reaction_spec.rb +++ b/spec/models/reaction_spec.rb @@ -44,13 +44,13 @@ RSpec.describe Reaction, type: :model do end it "does not allow vomit reaction for users without trusted role" do - allow(SiteConfig).to receive(:mascot_user_id).and_return(user.id + 1) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(user.id + 1) reaction.category = "vomit" expect(reaction).not_to be_valid end it "does not allow thumbsdown reaction for users without trusted role" do - allow(SiteConfig).to receive(:mascot_user_id).and_return(user.id + 1) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(user.id + 1) reaction.category = "thumbsdown" expect(reaction).not_to be_valid end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index c9b2e2be9..12251ce6b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -839,7 +839,7 @@ RSpec.describe User, type: :model do end it "returns the user if the account exists" do - allow(SiteConfig).to receive(:mascot_user_id).and_return(user.id) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(user.id) expect(described_class.mascot_account).to eq(user) end diff --git a/spec/requests/admin/configs_spec.rb b/spec/requests/admin/configs_spec.rb index 1b6e9e1ae..d4344badf 100644 --- a/spec/requests/admin/configs_spec.rb +++ b/spec/requests/admin/configs_spec.rb @@ -424,56 +424,66 @@ RSpec.describe "/admin/config", type: :request do describe "Mascot" do it "updates the mascot_user_id" do expected_mascot_user_id = 2 - post "/admin/config", params: { site_config: { mascot_user_id: expected_mascot_user_id }, - confirmation: confirmation_message } - expect(SiteConfig.mascot_user_id).to eq(expected_mascot_user_id) + post admin_settings_mascots_path, params: { + settings_mascot: { mascot_user_id: expected_mascot_user_id }, + confirmation: confirmation_message + } + expect(Settings::Mascot.mascot_user_id).to eq(expected_mascot_user_id) end - it "updates mascot_image_url" do - expected_default_image_url = SiteConfig.get_default(:mascot_image_url) + it "updates image_url" do + expected_default_image_url = Settings::Mascot.get_default(:image_url) expected_image_url = "https://dummyimage.com/300x300.png" expect do - post "/admin/config", params: { site_config: { mascot_image_url: expected_image_url }, - confirmation: confirmation_message } - end.to change(SiteConfig, :mascot_image_url).from(expected_default_image_url).to(expected_image_url) + post admin_settings_mascots_path, params: { + settings_mascot: { image_url: expected_image_url }, + confirmation: confirmation_message + } + end.to change(Settings::Mascot, :image_url).from(expected_default_image_url).to(expected_image_url) end - it "updates mascot_footer_image_url" do + it "updates footer_image_url" do expected_image_url = "https://dummyimage.com/300x300.png" - post "/admin/config", params: { site_config: { mascot_footer_image_url: expected_image_url }, - confirmation: confirmation_message } - expect(SiteConfig.mascot_footer_image_url).to eq(expected_image_url) + post admin_settings_mascots_path, params: { + settings_mascot: { footer_image_url: expected_image_url }, + confirmation: confirmation_message + } + expect(Settings::Mascot.footer_image_url).to eq(expected_image_url) end - it "updates the mascot_footer_image_width" do - expected_default_mascot_footer_image_width = SiteConfig.get_default(:mascot_footer_image_width) - expected_mascot_footer_image_width = 1002 + it "updates the footer_image_width" do + expected_default_footer_image_width = Settings::Mascot.get_default(:footer_image_width) + expected_footer_image_width = 1002 - expect(SiteConfig.mascot_footer_image_width).to eq(expected_default_mascot_footer_image_width) + expect(Settings::Mascot.footer_image_width).to eq(expected_default_footer_image_width) - post "/admin/config", params: { site_config: - { mascot_footer_image_width: expected_mascot_footer_image_width }, - confirmation: confirmation_message } - expect(SiteConfig.mascot_footer_image_width).to eq(expected_mascot_footer_image_width) + post admin_settings_mascots_path, params: { + settings_mascot: { footer_image_width: expected_footer_image_width }, + confirmation: confirmation_message + } + expect(Settings::Mascot.footer_image_width).to eq(expected_footer_image_width) end - it "updates the mascot_footer_image_height" do - expected_default_mascot_footer_image_height = SiteConfig.get_default(:mascot_footer_image_height) - expected_mascot_footer_image_height = 3002 + it "updates the footer_image_height" do + expected_default_footer_image_height = Settings::Mascot.get_default(:footer_image_height) + expected_footer_image_height = 3002 - expect(SiteConfig.mascot_footer_image_height).to eq(expected_default_mascot_footer_image_height) + expect(Settings::Mascot.footer_image_height).to eq(expected_default_footer_image_height) - post "/admin/config", params: { site_config: - { mascot_footer_image_height: expected_mascot_footer_image_height }, - confirmation: confirmation_message } - expect(SiteConfig.mascot_footer_image_height).to eq(expected_mascot_footer_image_height) + post admin_settings_mascots_path, params: { + settings_mascot: { footer_image_height: expected_footer_image_height }, + confirmation: confirmation_message + } + expect(Settings::Mascot.footer_image_height).to eq(expected_footer_image_height) end - it "updates mascot_image_description" do + it "updates image_description" do description = "Hey hey #{rand(100)}" - post "/admin/config", params: { site_config: { mascot_image_description: description }, - confirmation: confirmation_message } - expect(SiteConfig.mascot_image_description).to eq(description) + post admin_settings_mascots_path, params: { + settings_mascot: { image_description: description }, + confirmation: confirmation_message + } + expect(Settings::Mascot.image_description).to eq(description) end end diff --git a/spec/requests/comments_create_spec.rb b/spec/requests/comments_create_spec.rb index e86527902..d77db3ddd 100644 --- a/spec/requests/comments_create_spec.rb +++ b/spec/requests/comments_create_spec.rb @@ -161,7 +161,7 @@ RSpec.describe "CommentsCreate", type: :request do end def reply_and_mention_comment_author_as_moderator(comment) - allow(SiteConfig).to receive(:mascot_user_id) + allow(Settings::Mascot).to receive(:mascot_user_id) .and_return(moderator_replier.id) sign_in moderator_replier diff --git a/spec/requests/registrations_spec.rb b/spec/requests/registrations_spec.rb index 7d039ac70..95e06aa2f 100644 --- a/spec/requests/registrations_spec.rb +++ b/spec/requests/registrations_spec.rb @@ -345,14 +345,14 @@ RSpec.describe "Registrations", type: :request do end it "creates mascot user" do - expect(SiteConfig.mascot_user_id).to be_nil + expect(Settings::Mascot.mascot_user_id).to be_nil post "/users", params: { user: { name: "test #{rand(10)}", username: "haha_#{rand(10)}", email: "yoooo#{rand(100)}@yo.co", password: "PaSSw0rd_yo000", password_confirmation: "PaSSw0rd_yo000" } } - expect(SiteConfig.mascot_user_id).to eq User.last.id + expect(Settings::Mascot.mascot_user_id).to eq User.last.id mascot_account = User.mascot_account expect(mascot_account.username).to eq Users::CreateMascotAccount::MASCOT_PARAMS[:username] diff --git a/spec/services/search/query_builders/chat_channel_membership_spec.rb b/spec/services/search/query_builders/chat_channel_membership_spec.rb index 8d5e80471..26afaaeda 100644 --- a/spec/services/search/query_builders/chat_channel_membership_spec.rb +++ b/spec/services/search/query_builders/chat_channel_membership_spec.rb @@ -66,13 +66,13 @@ RSpec.describe Search::QueryBuilders::ChatChannelMembership, type: :service do end it "always applies channel discoverable and status params" do - allow(SiteConfig).to receive(:mascot_user_id).and_return(2) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(2) - params = { user_id: SiteConfig.mascot_user_id } + params = { user_id: Settings::Mascot.mascot_user_id } filter = described_class.new(params: params) expected_filters = [ { "terms" => { "status" => %w[active joining_request] } }, - { "terms" => { "viewable_by" => SiteConfig.mascot_user_id } }, + { "terms" => { "viewable_by" => Settings::Mascot.mascot_user_id } }, ] expect(filter.as_hash.dig("query", "bool", "filter")).to match_array(expected_filters) end diff --git a/spec/services/users/create_mascot_account_spec.rb b/spec/services/users/create_mascot_account_spec.rb index 02621a532..a0f7280b9 100644 --- a/spec/services/users/create_mascot_account_spec.rb +++ b/spec/services/users/create_mascot_account_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Users::CreateMascotAccount, type: :service do end context "when a mascot user doesn't exist" do - before { allow(SiteConfig).to receive(:mascot_user_id).and_return(nil) } + before { allow(Settings::Mascot).to receive(:mascot_user_id).and_return(nil) } it "creates a mascot account" do expect do @@ -21,7 +21,7 @@ RSpec.describe Users::CreateMascotAccount, type: :service do context "when a mascot user already exists" do before do - allow(SiteConfig).to receive(:mascot_user_id).and_return(2) + allow(Settings::Mascot).to receive(:mascot_user_id).and_return(2) allow(User).to receive(:create) end diff --git a/spec/views/dashboards/show.html.erb_spec.rb b/spec/views/dashboards/show.html.erb_spec.rb index e5ed8eff6..cbb118d16 100644 --- a/spec/views/dashboards/show.html.erb_spec.rb +++ b/spec/views/dashboards/show.html.erb_spec.rb @@ -7,7 +7,7 @@ RSpec.describe "dashboards/show.html.erb", type: :view do stub_template "dashboards/_actions.html.erb" => "stubbed content" allow(Images::Optimizer).to receive(:imgproxy_enabled?).and_return(true) - allow(SiteConfig).to receive(:mascot_image_url).and_return("https://i.imgur.com/fKYKgo4.png") + allow(Settings::Mascot).to receive(:image_url).and_return("https://i.imgur.com/fKYKgo4.png") end context "when using Imgproxy" do