Rename SiteConfig to Settings::General (#13573)

* Rename SiteConfig

* More renaming

* Update spec

* Update mandatory settings mapping

* More renaming

* e2e test fixes

* You have a rename, and you have a rename

* Spec fix

* More changes

* Temporarily disable specs

* After-merge update

* Undo rename for migration

* undo rename of DUS

* Fix DUS

* Fix merge problem

* Remove redundant DUS

* Fix specs

* Remove unused code

* Change wrong class name

* More cleanup

* Re-add missing values to constant

* Fix constant

* Fix spec

* Remove obsolete fields

* Add accidentally removed field

* Update spec

* Move methods from Settings::General to ForemInstance

* Remove unneeded model

* Change mentions of 'site config'
This commit is contained in:
Michael Kohl 2021-05-21 19:45:37 +07:00 committed by GitHub
parent b3e5533142
commit 6dfabd578f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
224 changed files with 1299 additions and 1293 deletions

1
.gitignore vendored
View file

@ -100,3 +100,4 @@ postcss_error.log
# ripgrep ignore file
.rgignore
config/definitions.rb

View file

@ -7,7 +7,7 @@ module Admin
if result.success?
Audit::Logger.log(:internal, current_user, params.dup)
bust_content_change_caches
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{result.errors.to_sentence}"
end

View file

@ -6,7 +6,7 @@ module Admin
if result.success?
Audit::Logger.log(:internal, current_user, params.dup)
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{result.errors.to_sentence}"
end

View file

@ -6,7 +6,7 @@ module Admin
if result.success?
Audit::Logger.log(:internal, current_user, params.dup)
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{result.errors.to_sentence}"
end

View file

@ -6,7 +6,7 @@ module Admin
if errors.none?
Audit::Logger.log(:internal, current_user, params.dup)
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{errors.to_sentence}"
end

View file

@ -6,7 +6,7 @@ module Admin
if errors.none?
Audit::Logger.log(:internal, current_user, params.dup)
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{errors.to_sentence}"
end

View file

@ -6,7 +6,7 @@ module Admin
if result.success?
Audit::Logger.log(:internal, current_user, params.dup)
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{result.errors.to_sentence}"
end

View file

@ -6,7 +6,7 @@ module Admin
if errors.none?
Audit::Logger.log(:internal, current_user, params.dup)
redirect_to admin_config_path, notice: "Site configuration was successfully updated."
redirect_to admin_config_path, notice: "Successfully updated settings."
else
redirect_to admin_config_path, alert: "😭 #{errors.to_sentence}"
end

View file

@ -73,7 +73,7 @@ module Admin
user = User.find(params[:id])
send_to_admin = params[:send_to_admin].to_boolean
if send_to_admin
email = SiteConfig.email_addresses[:contact]
email = ::Settings::General.email_addresses[:contact]
receiver = "admin"
else
email = user.email

View file

@ -9,7 +9,14 @@ module Api
skip_before_action :verify_authenticity_token, only: %i[update]
def show
@site_configs = SiteConfig.all
@settings =
Settings::Authentication.all +
Settings::Campaign.all +
Settings::Community.all +
Settings::General.all +
Settings::Mascot.all +
Settings::RateLimit.all +
Settings::UserExperience.all
end
def update
@ -20,7 +27,7 @@ module Api
auth_settings_result = ::Authentication::SettingsUpsert.call(auth_settings_params)
if settings_result.success? && auth_settings_result.success?
@site_configs = SiteConfig.all + Settings::Authentication.all
@settings = Settings::General.all + Settings::Authentication.all
Audit::Logger.log(:internal, @user, params.dup)
bust_content_change_caches
render "show"

View file

@ -30,7 +30,7 @@ module Api
key = request.headers["health-check-token"]
return if key == SiteConfig.health_check_token
return if key == Settings::General.health_check_token
error_unauthorized
end

View file

@ -23,7 +23,8 @@ class ApiSecretsController < ApplicationController
if @secret.destroy
flash[:notice] = "Your API Key has been revoked."
else
flash[:error] = "An error occurred. Please try again or send an email to: #{SiteConfig.email_addresses[:contact]}"
flash[:error] =
"An error occurred. Please try again or send an email to: #{Settings::General.email_addresses[:contact]}"
end
redirect_back(fallback_location: root_path)

View file

@ -168,7 +168,7 @@ class ApplicationController < ActionController::Base
end
def initialize_stripe
Stripe.api_key = SiteConfig.stripe_api_key
Stripe.api_key = Settings::General.stripe_api_key
return unless Rails.env.development? && Stripe.api_key.present?
@ -186,16 +186,19 @@ class ApplicationController < ActionController::Base
end
def forward_to_app_config_domain
return unless request.get? && # Let's only redirect get requests for this purpose.
request.host == ENV["APP_DOMAIN"] && # If the request equals the original set domain, e.g. forem-x.forem.cloud.
ENV["APP_DOMAIN"] != SiteConfig.app_domain # If the app domain config has now been set, let's go there instead.
# Let's only redirect get requests for this purpose.
return unless request.get? &&
# If the request equals the original set domain, e.g. forem-x.forem.cloud.
request.host == ENV["APP_DOMAIN"] &&
# If the app domain config has now been set, let's go there instead.
ENV["APP_DOMAIN"] != Settings::General.app_domain
redirect_to URL.url(request.fullpath)
end
def bust_content_change_caches
EdgeCache::Bust.call(CONTENT_CHANGE_PATHS)
SiteConfig.admin_action_taken_at = Time.current # Used as cache key
Settings::General.admin_action_taken_at = Time.current # Used as cache key
end
protected

View file

@ -31,7 +31,7 @@ class AsyncInfoController < ApplicationController
set_surrogate_key_header "shell-version-endpoint"
# shell_version will change on every deploy.
# *Technically* could be only on changes to assets and shell, but this is more fool-proof.
shell_version = ForemInstance.deployed_at.to_s + SiteConfig.admin_action_taken_at.to_s
shell_version = ForemInstance.deployed_at.to_s + Settings::General.admin_action_taken_at.to_s
render json: { version: shell_version }.to_json
end

View file

@ -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::General.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::General.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::General.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::General.mascot_user_id)&.destroy
end
render json: { success: true, message: "Channel settings updated.", data: {} }, success: :ok
end

View file

@ -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::General.mascot_user_id)
@comment = Comment.new(permitted_attributes(Comment))
@comment.user_id = moderator.id
@comment.body_markdown = response_template.content

View file

@ -1,4 +1,4 @@
# Helper method for controllers interacting with SiteConfig
# Helper method for controllers interacting with Settings::General
module SettingsParams
SPECIAL_PARAMS_TO_ADD = %w[
credit_prices_in_cents
@ -7,21 +7,21 @@ module SettingsParams
].freeze
def settings_params
has_emails = params.dig(:site_config, :email_addresses).present?
params[:site_config][:email_addresses][:default] = ApplicationConfig["DEFAULT_EMAIL"] if has_emails
has_emails = params.dig(:settings_general, :email_addresses).present?
params[:settings_general][:email_addresses][:default] = ApplicationConfig["DEFAULT_EMAIL"] if has_emails
params.require(:site_config)&.permit(
params.require(:settings_general)&.permit(
settings_keys.map(&:to_sym),
social_media_handles: SiteConfig.social_media_handles.keys,
email_addresses: SiteConfig.email_addresses.keys,
meta_keywords: SiteConfig.meta_keywords.keys,
credit_prices_in_cents: SiteConfig.credit_prices_in_cents.keys,
social_media_handles: Settings::General.social_media_handles.keys,
email_addresses: Settings::General.email_addresses.keys,
meta_keywords: Settings::General.meta_keywords.keys,
credit_prices_in_cents: Settings::General.credit_prices_in_cents.keys,
)
end
private
def settings_keys
SiteConfig.keys + SPECIAL_PARAMS_TO_ADD
Settings::General.keys + SPECIAL_PARAMS_TO_ADD
end
end

View file

@ -29,7 +29,7 @@ module VerifySetupCompleted
# This is the only flash in our application layout, don't override it if
# there's already another message.
return if flash[:global_notice].present?
return if config_path? || setup_completed? || SiteConfig.waiting_on_first_user
return if config_path? || setup_completed? || Settings::General.waiting_on_first_user
link = helpers.tag.a("the configuration page", href: admin_config_path, data: { "no-instant" => true })

View file

@ -6,7 +6,7 @@ class ConfirmationsController < Devise::ConfirmationsController
self.resource = resource_class.send_confirmation_instructions(resource_params)
resource.errors.clear # Don't leak user information, like paranoid mode.
message = format(FLASH_MESSAGE, email: SiteConfig.email_addresses[:members])
message = format(FLASH_MESSAGE, email: Settings::General.email_addresses[:members])
flash.now[:global_notice] = message
render :new
end

View file

@ -100,7 +100,7 @@ class CreditsController < ApplicationController
end
def cost_per_credit
prices = SiteConfig.credit_prices_in_cents
prices = Settings::General.credit_prices_in_cents
case @number_to_purchase
when ..9

View file

@ -7,7 +7,7 @@ class DeepLinksController < ApplicationController
# TODO: [@fdoxyz] Replace these hardcoded identifiers with configurations
# creators can use to customize their Forems - `/admin/consumer_apps`
supported_apps = ["R9SWHSQNV8.com.forem.app"]
supported_apps << "R9SWHSQNV8.to.dev.ios" if SiteConfig.dev_to?
supported_apps << "R9SWHSQNV8.to.dev.ios" if ForemInstance.dev_to?
render json: {
applinks: {
apps: [],

View file

@ -9,7 +9,7 @@ class GaEventsController < ApplicationController
json = JSON.parse(request.raw_post)
user_id = user_signed_in? ? current_user.id : nil
client_id = "#{scrambled_ip[0..12]}_#{json['user_agent']}_#{user_id}"
tracker = Staccato.tracker(SiteConfig.ga_tracking_id, client_id)
tracker = Staccato.tracker(Settings::General.ga_tracking_id, client_id)
tracker.pageview(
path: json["path"],
user_id: user_id,

View file

@ -24,12 +24,12 @@ module IncomingWebhooks
private
def valid_secret?
params[:secret] == SiteConfig.mailchimp_incoming_webhook_secret
params[:secret] == Settings::General.mailchimp_incoming_webhook_secret
end
def email_type
list_id = params.dig(:data, :list_id)
key = LIST_MAPPINGS.keys.detect { |k| SiteConfig.public_send(k) == list_id }
key = LIST_MAPPINGS.keys.detect { |k| Settings::General.public_send(k) == list_id }
raise InvalidListID unless key
LIST_MAPPINGS[key]

View file

@ -16,8 +16,8 @@ class RegistrationsController < Devise::RegistrationsController
# rubocop:disable Metrics/PerceivedComplexity
def create
not_authorized unless Settings::Authentication.allow_email_password_registration ||
SiteConfig.waiting_on_first_user
not_authorized if SiteConfig.waiting_on_first_user && ENV["FOREM_OWNER_SECRET"].present? &&
Settings::General.waiting_on_first_user
not_authorized if Settings::General.waiting_on_first_user && ENV["FOREM_OWNER_SECRET"].present? &&
ENV["FOREM_OWNER_SECRET"] != params[:user][:forem_owner_secret]
resolve_profile_field_issues
@ -33,7 +33,7 @@ class RegistrationsController < Devise::RegistrationsController
yield resource if block_given?
if resource.persisted?
update_first_user_permissions(resource)
if SiteConfig.smtp_enabled?
if ForemInstance.smtp_enabled?
redirect_to confirm_email_path(email: resource.email)
else
sign_in(resource)
@ -53,11 +53,11 @@ class RegistrationsController < Devise::RegistrationsController
private
def update_first_user_permissions(resource)
return unless SiteConfig.waiting_on_first_user
return unless Settings::General.waiting_on_first_user
resource.add_role(:super_admin)
resource.add_role(:trusted)
SiteConfig.waiting_on_first_user = false
Settings::General.waiting_on_first_user = false
Users::CreateMascotAccount.call
end
@ -79,7 +79,7 @@ class RegistrationsController < Devise::RegistrationsController
# Run this data update script when in a state of "first user" in the event
# that we are in a state where this was not already run.
# This is likely only temporarily needed.
return unless SiteConfig.waiting_on_first_user
return unless Settings::General.waiting_on_first_user
csv = Rails.root.join("lib/data/dev_profile_fields.csv")
ProfileFields::ImportFromCsv.call(csv)

View file

@ -68,7 +68,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::General.mascot_user_id, chat_channel_params[:user_id]].reject(&:blank?)
else
[current_user.id]
end

View file

@ -414,8 +414,8 @@ class StoriesController < ApplicationController
logo: {
"@context": "http://schema.org",
"@type": "ImageObject",
url: ApplicationController.helpers.optimized_image_url(SiteConfig.logo_png, width: 192,
fetch_format: "png"),
url: ApplicationController.helpers.optimized_image_url(Settings::General.logo_png, width: 192,
fetch_format: "png"),
width: "192",
height: "192"
}

View file

@ -37,7 +37,7 @@ class TagsController < ApplicationController
def onboarding
skip_authorization
@tags = Tag.where(name: SiteConfig.suggested_tags)
@tags = Tag.where(name: Settings::General.suggested_tags)
.select(ATTRIBUTES_FOR_SERIALIZATION)
set_surrogate_key_header Tag.table_key, @tags.map(&:record_key)

View file

@ -13,6 +13,8 @@ class UsersController < ApplicationController
ALLOWED_USER_PARAMS = %i[last_onboarding_page username].freeze
INDEX_ATTRIBUTES_FOR_SERIALIZATION = %i[id name username summary profile_image].freeze
private_constant :INDEX_ATTRIBUTES_FOR_SERIALIZATION
REMOVE_IDENTITY_ERROR = "An error occurred. Please try again or send an email to: %<email>s".freeze
private_constant :REMOVE_IDENTITY_ERROR
def index
@users =
@ -132,7 +134,7 @@ class UsersController < ApplicationController
def remove_identity
set_current_tab("account")
error_message = "An error occurred. Please try again or send an email to: #{SiteConfig.email_addresses[:contact]}"
error_message = format(REMOVE_IDENTITY_ERROR, email: Settings::General.email_addresses[:contact])
unless Authentication::Providers.enabled?(params[:provider])
flash[:error] = error_message
redirect_to user_settings_path(@tab)
@ -296,7 +298,7 @@ class UsersController < ApplicationController
end
def set_suggested_users
@suggested_users = SiteConfig.suggested_users
@suggested_users = Settings::General.suggested_users
end
def default_suggested_users
@ -304,7 +306,7 @@ class UsersController < ApplicationController
end
def determine_follow_suggestions(current_user)
return default_suggested_users if SiteConfig.prefer_manual_suggested_users? && default_suggested_users
return default_suggested_users if Settings::General.prefer_manual_suggested_users? && default_suggested_users
recent_suggestions = Users::SuggestRecent.call(
current_user,

View file

@ -30,6 +30,6 @@ class VideoStatesController < ApplicationController
private
def valid_key
params[:key] == SiteConfig.video_encoder_key
params[:key] == Settings::General.video_encoder_key
end
end

View file

@ -19,7 +19,7 @@ module Authentication
def message
format(PREVIOUSLY_SUSPENDED_MESSAGE,
community_name: Settings::Community.community_name,
community_email: SiteConfig.email_addresses[:contact])
community_email: Settings::General.email_addresses[:contact])
end
end
end

View file

@ -156,8 +156,8 @@ module ApplicationHelper
end
def logo_svg
if SiteConfig.logo_svg.present?
SiteConfig.logo_svg.html_safe # rubocop:disable Rails/OutputSafety
if Settings::General.logo_svg.present?
Settings::General.logo_svg.html_safe # rubocop:disable Rails/OutputSafety
else
inline_svg_tag("devplain.svg", class: "logo", size: "20% * 20%", aria: true, title: "App logo")
end
@ -175,7 +175,7 @@ module ApplicationHelper
release_footprint = ForemInstance.deployed_at
return path if release_footprint.blank?
"#{path}-#{params[:locale]}-#{release_footprint}-#{SiteConfig.admin_action_taken_at.rfc3339}"
"#{path}-#{params[:locale]}-#{release_footprint}-#{Settings::General.admin_action_taken_at.rfc3339}"
end
def copyright_notice
@ -195,9 +195,9 @@ module ApplicationHelper
end
def email_link(type = :contact, text: nil, additional_info: nil)
# The allowed types for type are the keys of `SiteConfig.email_addresses`
# The allowed types for type are the keys of `Settings::General.email_addresses`
# :default, :contact, :business, :privacy, :members
email = SiteConfig.email_addresses[type] || SiteConfig.email_addresses[:contact]
email = Settings::General.email_addresses[type] || Settings::General.email_addresses[:contact]
mail_to email, text || email, additional_info
end
@ -206,27 +206,27 @@ module ApplicationHelper
end
def meta_keywords_default
return if SiteConfig.meta_keywords[:default].blank?
return if Settings::General.meta_keywords[:default].blank?
tag.meta name: "keywords", content: SiteConfig.meta_keywords[:default]
tag.meta name: "keywords", content: Settings::General.meta_keywords[:default]
end
def meta_keywords_article(article_tags = nil)
return if SiteConfig.meta_keywords[:article].blank?
return if Settings::General.meta_keywords[:article].blank?
content = if article_tags.present?
"#{article_tags}, #{SiteConfig.meta_keywords[:article]}"
"#{article_tags}, #{Settings::General.meta_keywords[:article]}"
else
SiteConfig.meta_keywords[:article]
Settings::General.meta_keywords[:article]
end
tag.meta name: "keywords", content: content
end
def meta_keywords_tag(tag_name)
return if SiteConfig.meta_keywords[:tag].blank?
return if Settings::General.meta_keywords[:tag].blank?
tag.meta name: "keywords", content: "#{SiteConfig.meta_keywords[:tag]}, #{tag_name}"
tag.meta name: "keywords", content: "#{Settings::General.meta_keywords[:tag]}, #{tag_name}"
end
def app_url(uri = nil)
@ -270,7 +270,7 @@ module ApplicationHelper
estimated_user_count > LARGE_USERBASE_THRESHOLD
end
def admin_config_label(method, content = nil, model: SiteConfig)
def admin_config_label(method, content = nil, model: Settings::General)
content ||= tag.span(method.to_s.humanize)
if method.to_sym.in?(Settings::Mandatory.keys)

View file

@ -42,7 +42,7 @@ module AuthenticationHelper
end
def waiting_on_first_user?
SiteConfig.waiting_on_first_user
Settings::General.waiting_on_first_user
end
def invite_only_mode_or_no_enabled_auth_options

View file

@ -10,12 +10,11 @@ const emailAuthSettingsSection = document.getElementById(
'email-auth-settings-section',
);
const emailAuthModalTitle = 'Disable Email address registration';
// TODO: Remove the sentence "You must update site config to save this action!"
// once we build more robust flow for Admin/Config
// TODO: Remove the "You mut confirm..." warning once we build more robust flow for Admin/Config
const emailAuthModalBody = `
<p>If you disable Email address as a registration option, people cannot create an account with their email address.</p>
<p>However, people who have already created an account using their email address can continue to login.</p>
<p><strong>You must confirm and update site config to save below this action.</strong></p>`;
<p><strong>You must confirm and update the settings below to complete this action.</strong></p>`;
export default class ConfigController extends Controller {
static targets = [
@ -63,14 +62,14 @@ export default class ConfigController extends Controller {
(letter) => `_${letter.toLowerCase()}`,
);
document.querySelector(
`button[data-id=site_config_${snakeCaseName}]`,
`button[data-id=settings_${snakeCaseName}]`,
).disabled = newValue;
}
}
closeAdminModal() {
// per forem/internalEngineering#336, need to short-circuit the
// "Update Site Configuration" button submit action; chose not to
// "Update Settings" button submit action; chose not to
// define Target on actual "Update" button (since it's a partial).
// The Target is defined on the Authentication form, and that section's
// "Update" button is queried.
@ -159,7 +158,7 @@ export default class ConfigController extends Controller {
enableOrEditAuthProvider(event) {
event.preventDefault();
const providerName = event.target.dataset.providerName;
const {providerName} = event.target.dataset;
const enabledIndicator = document.getElementById(
`${providerName}-enabled-indicator`,
);
@ -178,7 +177,7 @@ export default class ConfigController extends Controller {
disableAuthProvider(event) {
event.preventDefault();
const providerName = event.target.dataset.providerName;
const {providerName} = event.target.dataset;
const enabledIndicator = document.getElementById(
`${providerName}-enabled-indicator`,
);
@ -196,13 +195,13 @@ export default class ConfigController extends Controller {
}
authProviderModalBody(provider) {
return `<p>If you disable ${provider} as a login option, people cannot authenticate with ${provider}.</p><p><strong>You must update Site Config to save this action!</strong></p>`;
return `<p>If you disable ${provider} as a login option, people cannot authenticate with ${provider}.</p><p><strong>You must update Settings to save this action!</strong></p>`;
}
activateAuthProviderModal(event) {
event.preventDefault();
const providerName = event.target.dataset.providerName;
const providerOfficialName = event.target.dataset.providerOfficialName;
const {providerName} = event.target.dataset;
const {providerOfficialName} = event.target.dataset;
this.configModalAnchorTarget.innerHTML = adminModal({
title: this.authProviderModalTitle(providerOfficialName),
body: this.authProviderModalBody(providerOfficialName),
@ -219,7 +218,7 @@ export default class ConfigController extends Controller {
disableAuthProviderFromModal(event) {
event.preventDefault();
const providerName = event.target.dataset.providerName;
const {providerName} = event.target.dataset;
const authEnableButton = document.getElementById(
`${providerName}-auth-btn`,
);
@ -255,7 +254,7 @@ export default class ConfigController extends Controller {
hideAuthProviderSettings(event) {
event.preventDefault();
const providerName = event.target.dataset.providerName;
const {providerName} = event.target.dataset;
document
.getElementById(`${providerName}-auth-settings`)
.classList.add('hidden');
@ -271,9 +270,8 @@ export default class ConfigController extends Controller {
.forEach((provider) => {
enabledProviderArray.push(provider.dataset.providerName);
});
document.getElementById(
'auth_providers_to_enable',
).value = enabledProviderArray;
document.getElementById('auth_providers_to_enable').value =
enabledProviderArray;
}
adjustAuthenticationOptions() {

View file

@ -143,6 +143,7 @@ export class FollowTags extends Component {
: `inset 0 0 0 2px ${tag.bg_color_hex}`,
color: selected ? tag.text_color_hex : '',
}}
key={tag.id}
>
<div className="onboarding-tags__item__inner">
#{tag.name}
@ -150,7 +151,8 @@ export class FollowTags extends Component {
type="button"
onClick={() => this.handleClick(tag)}
className={`onboarding-tags__button ${
selected && 'onboarding-tags__button--selected crayons-btn--icon-left'
selected &&
'onboarding-tags__button--selected crayons-btn--icon-left'
}`}
aria-pressed={selected}
aria-label={`Follow ${tag.name}`}
@ -163,14 +165,16 @@ export class FollowTags extends Component {
: tag.text_color_hex,
}}
>
{ selected && (<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
className="crayons-icon"
>
<path d="M9.99999 15.172L19.192 5.979L20.607 7.393L9.99999 18L3.63599 11.636L5.04999 10.222L9.99999 15.172Z" />
</svg>)}
{selected && (
<svg
width="24"
height="24"
xmlns="http://www.w3.org/2000/svg"
className="crayons-icon"
>
<path d="M9.99999 15.172L19.192 5.979L20.607 7.393L9.99999 18L3.63599 11.636L5.04999 10.222L9.99999 15.172Z" />
</svg>
)}
{selected ? 'Following' : 'Follow'}
</button>
</div>

View file

@ -27,7 +27,7 @@ module Constants
placeholder: "Campaign sidebar enabled or not"
},
sidebar_image: {
description: ::Constants::SiteConfig::IMAGE_PLACEHOLDER,
description: ::Constants::Settings::General::IMAGE_PLACEHOLDER,
placeholder: "Used at the top of the campaign sidebar"
},
url: {

View file

@ -0,0 +1,146 @@
module Constants
module Settings
module General
IMAGE_PLACEHOLDER = "https://url/image.png".freeze
SVG_PLACEHOLDER = "<svg ...></svg>".freeze
DETAILS = {
credit_prices_in_cents: {
small: {
description: "Price for small credit purchase (<10 credits).",
placeholder: ""
},
medium: {
description: "Price for medium credit purchase (10 - 99 credits).",
placeholder: ""
},
large: {
description: "Price for large credit purchase (100 - 999 credits).",
placeholder: ""
},
xlarge: {
description: "Price for extra large credit purchase (1000 credits or more).",
placeholder: ""
}
},
email_addresses: {
description: "Email address",
placeholder: ""
},
favicon_url: {
description: "Used as the site favicon",
placeholder: IMAGE_PLACEHOLDER
},
ga_tracking_id: {
description: "Google Analytics Tracking ID, e.g. UA-71991000-1",
placeholder: ""
},
health_check_token: {
description: "Used to authenticate with your health check endpoints.",
placeholder: "a secure token"
},
logo_png: {
description: "Used as a fallback to the SVG. Recommended minimum of 512x512px for PWA support",
placeholder: IMAGE_PLACEHOLDER
},
logo_svg: {
description: "Used as the SVG logo of the community",
placeholder: SVG_PLACEHOLDER
},
main_social_image: {
description: "Used as the main image in social networks and OpenGraph. Recommended aspect ratio " \
"of 16:9 (600x337px,1200x675px)",
placeholder: IMAGE_PLACEHOLDER
},
mailchimp_api_key: {
description: "API key used to connect Mailchimp account. Found in Mailchimp backend",
placeholder: ""
},
mailchimp_newsletter_id: {
description: "Main Newsletter ID, also known as Audience ID",
placeholder: ""
},
mailchimp_sustaining_members_id: {
description: "Sustaining Members Newsletter ID",
placeholder: ""
},
mailchimp_tag_moderators_id: {
description: "Tag Moderators Newsletter ID",
placeholder: ""
},
mailchimp_community_moderators_id: {
description: "Community Moderators Newsletter ID",
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"
},
onboarding_background_image: {
description: "Background for onboarding splash page",
placeholder: IMAGE_PLACEHOLDER
},
payment_pointer: {
description: "Used for site-wide web monetization. " \
"See: https://github.com/thepracticaldev/dev.to/pull/6345",
placeholder: "$pay.somethinglikethis.co/value"
},
periodic_email_digest: {
description: "Determines how often periodic email digests are sent",
placeholder: 2
},
sidebar_tags: {
description: "Determines which tags are shown on the homepage righthand sidebar",
placeholder: "List of valid, comma-separated tags e.g. help,discuss,explainlikeimfive,meta"
},
sponsor_headline: {
description: "Determines the heading text of the main sponsors sidebar above the list of sponsors.",
placeholder: "Community Sponsors"
},
stripe_api_key: {
description: "Secret Stripe key for receiving payments. " \
"See: https://stripe.com/docs/keys",
placeholder: "sk_live_...."
},
stripe_publishable_key: {
description: "Public Stripe key for receiving payments. " \
"See: https://stripe.com/docs/keys",
placeholder: "pk_live_...."
},
suggested_tags: {
description: "Determines which tags are suggested to new users during onboarding (comma
separated, letters only)",
placeholder: "List of valid tags: comma separated, letters only e.g. beginners,javascript,ruby,swift,kotlin"
},
suggested_users: {
description: "Determines which users are suggested to follow to new users during onboarding (comma " \
"separated, letters only). Please note that these users will be shown as a fallback if no " \
"recently-active commenters or producers can be suggested",
placeholder: "List of valid usernames: comma separated, letters only e.g. " \
"ben,jess,peter,maestromac,andy,liana"
},
prefer_manual_suggested_users: {
description: "Always show suggested users as suggested people to follow even when " \
"auto-suggestion is available"
},
twitter_hashtag: {
description: "Used as the twitter hashtag of the community",
placeholder: "#DEVCommunity"
},
video_encoder_key: {
description: "Secret key used to allow AWS video encoding through the VideoStatesController",
placeholder: ""
}
# Dynamic values ommitted: configurable_rate_limits and social_media_handles
}.freeze
end
end
end

View file

@ -1,142 +0,0 @@
module Constants
module SiteConfig
IMAGE_PLACEHOLDER = "https://url/image.png".freeze
SVG_PLACEHOLDER = "<svg ...></svg>".freeze
DETAILS = {
credit_prices_in_cents: {
small: {
description: "Price for small credit purchase (<10 credits).",
placeholder: ""
},
medium: {
description: "Price for medium credit purchase (10 - 99 credits).",
placeholder: ""
},
large: {
description: "Price for large credit purchase (100 - 999 credits).",
placeholder: ""
},
xlarge: {
description: "Price for extra large credit purchase (1000 credits or more).",
placeholder: ""
}
},
email_addresses: {
description: "Email address",
placeholder: ""
},
favicon_url: {
description: "Used as the site favicon",
placeholder: IMAGE_PLACEHOLDER
},
ga_tracking_id: {
description: "Google Analytics Tracking ID, e.g. UA-71991000-1",
placeholder: ""
},
health_check_token: {
description: "Used to authenticate with your health check endpoints.",
placeholder: "a secure token"
},
logo_png: {
description: "Used as a fallback to the SVG. Recommended minimum of 512x512px for PWA support",
placeholder: IMAGE_PLACEHOLDER
},
logo_svg: {
description: "Used as the SVG logo of the community",
placeholder: SVG_PLACEHOLDER
},
main_social_image: {
description: "Used as the main image in social networks and OpenGraph. Recommended aspect ratio of 16:9 (600x337px,1200x675px)",
placeholder: IMAGE_PLACEHOLDER
},
mailchimp_api_key: {
description: "API key used to connect Mailchimp account. Found in Mailchimp backend",
placeholder: ""
},
mailchimp_newsletter_id: {
description: "Main Newsletter ID, also known as Audience ID",
placeholder: ""
},
mailchimp_sustaining_members_id: {
description: "Sustaining Members Newsletter ID",
placeholder: ""
},
mailchimp_tag_moderators_id: {
description: "Tag Moderators Newsletter ID",
placeholder: ""
},
mailchimp_community_moderators_id: {
description: "Community Moderators Newsletter ID",
placeholder: ""
},
mascot_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"
},
meta_keywords: {
description: "",
placeholder: "List of valid keywords: comma separated, letters only e.g. engineering, development"
},
onboarding_background_image: {
description: "Background for onboarding splash page",
placeholder: IMAGE_PLACEHOLDER
},
payment_pointer: {
description: "Used for site-wide web monetization. " \
"See: https://github.com/thepracticaldev/dev.to/pull/6345",
placeholder: "$pay.somethinglikethis.co/value"
},
periodic_email_digest: {
description: "Determines how often periodic email digests are sent",
placeholder: 2
},
sidebar_tags: {
description: "Determines which tags are shown on the homepage righthand sidebar",
placeholder: "List of valid, comma-separated tags e.g. help,discuss,explainlikeimfive,meta"
},
sponsor_headline: {
description: "Determines the heading text of the main sponsors sidebar above the list of sponsors.",
placeholder: "Community Sponsors"
},
stripe_api_key: {
description: "Secret Stripe key for receiving payments. " \
"See: https://stripe.com/docs/keys",
placeholder: "sk_live_...."
},
stripe_publishable_key: {
description: "Public Stripe key for receiving payments. " \
"See: https://stripe.com/docs/keys",
placeholder: "pk_live_...."
},
suggested_tags: {
description: "Determines which tags are suggested to new users during onboarding (comma
separated, letters only)",
placeholder: "List of valid tags: comma separated, letters only e.g. beginners,javascript,ruby,swift,kotlin"
},
suggested_users: {
description: "Determines which users are suggested to follow to new users during onboarding (comma " \
"separated, letters only). Please note that these users will be shown as a fallback if no " \
"recently-active commenters or producers can be suggested",
placeholder: "List of valid usernames: comma separated, letters only e.g. ben,jess,peter,maestromac,andy,liana"
},
prefer_manual_suggested_users: {
description: "Always show suggested users as suggested people to follow even when " \
"auto-suggestion is available"
},
twitter_hashtag: {
description: "Used as the twitter hashtag of the community",
placeholder: "#DEVCommunity"
},
video_encoder_key: {
description: "Secret key used to allow AWS video encoding through the VideoStatesController",
placeholder: ""
}
# Dynamic values ommitted: configurable_rate_limits and social_media_handles
}.freeze
end
end

View file

@ -27,6 +27,6 @@ module HtmlCssToImage
end
def self.fallback_image
SiteConfig.main_social_image.to_s
Settings::General.main_social_image.to_s
end
end

View file

@ -7,7 +7,7 @@ module Middlewares
end
def call(env)
env["rack.session.options"][:domain] = ".#{SiteConfig.app_domain}"
env["rack.session.options"][:domain] = ".#{Settings::General.app_domain}"
@app.call(env)
end

View file

@ -50,7 +50,7 @@ module Redcarpet
end
def app_domain
SiteConfig.app_domain
Settings::General.app_domain
end
def slugify(string)

View file

@ -5,8 +5,8 @@ module URL
end
def self.domain
if Rails.application&.initialized? && SiteConfig.respond_to?(:app_domain)
SiteConfig.app_domain
if Rails.application&.initialized? && Settings::General.respond_to?(:app_domain)
Settings::General.app_domain
else
ApplicationConfig["APP_DOMAIN"]
end

View file

@ -26,7 +26,7 @@ class LinkTag < LiquidTagBase
path = url.path
# If domain is present in url check if it belongs to the app
unless domain.blank? || domain&.casecmp?(SiteConfig.app_domain)
unless domain.blank? || domain&.casecmp?(Settings::General.app_domain)
raise StandardError, "The article you're looking for does not exist: {% link #{slug} %}"
end

View file

@ -3,7 +3,7 @@ class TwitchTag < LiquidTagBase
def initialize(_tag_name, slug, _parse_context)
super
@url = parsed_url(SiteConfig.app_domain)
@url = parsed_url(Settings::General.app_domain)
@slug = parsed_slug(slug)
@width = 710
@height = 399

View file

@ -21,7 +21,7 @@ class ApplicationMailer < ActionMailer::Base
Settings::Community.community_name
end
"#{community_name} <#{SiteConfig.email_addresses[:default]}>"
"#{community_name} <#{Settings::General.email_addresses[:default]}>"
end
def generate_unsubscribe_token(id, email_type)
@ -33,6 +33,6 @@ class ApplicationMailer < ActionMailer::Base
end
def use_custom_host
ActionMailer::Base.default_url_options[:host] = SiteConfig.app_domain
ActionMailer::Base.default_url_options[:host] = Settings::General.app_domain
end
end

View file

@ -1,9 +1,9 @@
class DeviseMailer < Devise::Mailer
before_action :use_site_config_values
before_action :use_settings_general_values
def use_site_config_values
def use_settings_general_values
Devise.mailer_sender =
"#{Settings::Community.community_name} <#{SiteConfig.email_addresses[:default]}>"
ActionMailer::Base.default_url_options[:host] = SiteConfig.app_domain
"#{Settings::Community.community_name} <#{Settings::General.email_addresses[:default]}>"
ActionMailer::Base.default_url_options[:host] = Settings::General.app_domain
end
end

View file

@ -1,6 +1,6 @@
class VerificationMailer < ApplicationMailer
default from: lambda {
"#{Settings::Community.community_name} Email Verification <#{SiteConfig.email_addresses[:default]}>"
"#{Settings::Community.community_name} Email Verification <#{Settings::General.email_addresses[:default]}>"
}
def account_ownership_verification_email

View file

@ -176,7 +176,7 @@ class Article < ApplicationRecord
.where(user_id: User.with_role(:super_admin)
.union(User.with_role(:admin))
.union(id: [Settings::Community.staff_user_id,
SiteConfig.mascot_user_id].compact)
Settings::General.mascot_user_id].compact)
.select(:id)).order(published_at: :desc).tagged_with(tag_name)
}
@ -788,7 +788,7 @@ class Article < ApplicationRecord
end
Reaction.create(
user_id: SiteConfig.mascot_user_id,
user_id: Settings::General.mascot_user_id,
reactable_id: id,
reactable_type: "Article",
category: "vomit",
@ -798,7 +798,7 @@ class Article < ApplicationRecord
user.add_role(:suspended)
Note.create(
author_id: SiteConfig.mascot_user_id,
author_id: Settings::General.mascot_user_id,
noteable_id: user_id,
noteable_type: "User",
reason: "automatic_suspend",

View file

@ -271,7 +271,7 @@ class Comment < ApplicationRecord
user.registered_at > 5.days.ago
Reaction.create(
user_id: SiteConfig.mascot_user_id,
user_id: Settings::General.mascot_user_id,
reactable_id: id,
reactable_type: "Comment",
category: "vomit",
@ -281,7 +281,7 @@ class Comment < ApplicationRecord
user.add_role(:suspended)
Note.create(
author_id: SiteConfig.mascot_user_id,
author_id: Settings::General.mascot_user_id,
noteable_id: user_id,
noteable_type: "User",
reason: "automatic_suspend",

View file

@ -8,4 +8,19 @@ class ForemInstance
def self.latest_commit_id
@latest_commit_id ||= ApplicationConfig["FOREM_BUILD_SHA"].presence || ENV["HEROKU_SLUG_COMMIT"].presence
end
# Return true if we are operating on a local installation, false otherwise
def self.local?
Settings::General.app_domain.include?("localhost")
end
# Used where we need to keep old DEV features around but don't want to/cannot
# expose them to other communities.
def self.dev_to?
Settings::General.app_domain == "dev.to"
end
def self.smtp_enabled?
Rails.configuration.action_mailer.perform_deliveries
end
end

View file

@ -193,19 +193,19 @@ class Message < ApplicationRecord
end
def rich_link_article(link)
return unless link["href"].include?("//#{SiteConfig.app_domain}/") && link["href"].split("/")[4]
return unless link["href"].include?("//#{Settings::General.app_domain}/") && link["href"].split("/")[4]
Article.find_by(slug: link["href"].split("/")[4].split("?")[0])
end
def rich_link_tag(link)
return unless link["href"].include?("//#{SiteConfig.app_domain}/t/")
return unless link["href"].include?("//#{Settings::General.app_domain}/t/")
Tag.find_by(name: link["href"].split("/t/")[1].split("/")[0])
end
def rich_user_link(link)
return unless link["href"].include?("//#{SiteConfig.app_domain}/")
return unless link["href"].include?("//#{Settings::General.app_domain}/")
User.find_by(username: link["href"].split("/")[3].split("/")[0])
end

View file

@ -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::General.mascot_user_id
negative? && !user.trusted
end

View file

@ -0,0 +1,136 @@
# Settings based on RailsSettings models,
# see <https://github.com/huacnlee/rails-settings-cached> for further info
module Settings
class General < RailsSettings::Base
self.table_name = "site_configs"
# the configuration is cached, change this if you want to force update
# the cache, or call Settings::General.clear_cache
cache_prefix { "v1" }
HEX_COLOR_REGEX = /\A#(\h{6}|\h{3})\z/.freeze
LIGHTNING_ICON = File.read(Rails.root.join("app/assets/images/lightning.svg")).freeze
STACK_ICON = File.read(Rails.root.join("app/assets/images/stack.svg")).freeze
# Forem Team
# [forem-fix] Remove channel name from Settings::General
field :article_published_slack_channel, type: :string, default: "activity"
# Meta
field :admin_action_taken_at, type: :datetime, default: Time.current
# Core setup
field :waiting_on_first_user, type: :boolean, default: !User.exists?
field :app_domain, type: :string, default: ApplicationConfig["APP_DOMAIN"]
# API Tokens
field :health_check_token, type: :string
field :video_encoder_key, type: :string
# Emails
field :email_addresses, type: :hash, default: {
default: ApplicationConfig["DEFAULT_EMAIL"],
contact: ApplicationConfig["DEFAULT_EMAIL"],
business: ApplicationConfig["DEFAULT_EMAIL"],
privacy: ApplicationConfig["DEFAULT_EMAIL"],
members: ApplicationConfig["DEFAULT_EMAIL"]
}
# Email digest frequency
field :periodic_email_digest, type: :integer, default: 2
# Google Analytics Tracking ID, e.g. UA-71991000-1
field :ga_tracking_id, type: :string, default: ApplicationConfig["GA_TRACKING_ID"]
# Images
field :main_social_image,
type: :string,
default: proc { URL.local_image("social-media-cover.png") },
validates: { url: true }
field :favicon_url, type: :string, default: proc { URL.local_image("favicon.ico") }
field :logo_png,
type: :string,
default: proc { URL.local_image("icon.png") },
validates: { url: true }
field :logo_svg, type: :string
field :enable_video_upload, type: :boolean, default: false
# Mascot
field :mascot_user_id, type: :integer, default: nil
field :mascot_image_url,
type: :string,
default: proc { URL.local_image("mascot.png") },
validates: { url: true }
field :mascot_image_description, type: :string, default: "The community mascot"
field :mascot_footer_image_url, type: :string, validates: { url: true }
field :mascot_footer_image_width, type: :integer, default: 52
field :mascot_footer_image_height, type: :integer, default: 120
# Meta keywords
field :meta_keywords, type: :hash, default: {
default: nil,
article: nil,
tag: nil
}
# Monetization
field :payment_pointer, type: :string
field :stripe_api_key, type: :string, default: ApplicationConfig["STRIPE_SECRET_KEY"]
field :stripe_publishable_key, type: :string, default: ApplicationConfig["STRIPE_PUBLISHABLE_KEY"]
# Newsletter
# <https://mailchimp.com/developer/>
field :mailchimp_api_key, type: :string, default: ApplicationConfig["MAILCHIMP_API_KEY"]
field :mailchimp_newsletter_id, type: :string, default: ""
field :mailchimp_sustaining_members_id, type: :string, default: ""
field :mailchimp_tag_moderators_id, type: :string, default: ""
field :mailchimp_community_moderators_id, type: :string, default: ""
# Mailchimp webhook secret. Part of the callback URL in the Mailchimp settings.
# <https://mailchimp.com/developer/guides/about-webhooks/#Webhooks_security>
field :mailchimp_incoming_webhook_secret, type: :string, default: ""
# Onboarding
field :onboarding_background_image, type: :string, validates: { url: true }
field :suggested_tags, type: :array, default: %w[]
field :suggested_users, type: :array, default: %w[]
field :prefer_manual_suggested_users, type: :boolean, default: false
# Social Media
field :social_media_handles, type: :hash, default: {
twitter: nil,
facebook: nil,
github: nil,
instagram: nil,
twitch: nil
}
field :twitter_hashtag, type: :string
# Sponsors
field :sponsor_headline, default: "Community Sponsors"
# Tags
field :sidebar_tags, type: :array, default: %w[]
# Broadcast
field :welcome_notifications_live_at, type: :date
# Credits
field :credit_prices_in_cents, type: :hash, default: {
small: 500,
medium: 400,
large: 300,
xlarge: 250
}
# Push Notifications
field :push_notifications_ios_pem, type: :string
# To get default values
def self.get_default(field)
get_field(field)[:default]
end
end
end

View file

@ -7,8 +7,8 @@ module Settings
community_name: Settings::Community,
community_description: Settings::Community,
suggested_tags: SiteConfig,
suggested_users: SiteConfig
suggested_tags: Settings::General,
suggested_users: Settings::General
}.freeze
MAPPINGS.each do |setting, settings_model|

View file

@ -1,21 +0,0 @@
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 :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

View file

@ -1,146 +0,0 @@
# Site configuration based on RailsSettings models,
# see <https://github.com/huacnlee/rails-settings-cached> for further info
class SiteConfig < RailsSettings::Base
self.table_name = "site_configs"
# the site configuration is cached, change this if you want to force update
# the cache, or call SiteConfig.clear_cache
cache_prefix { "v1" }
HEX_COLOR_REGEX = /\A#(\h{6}|\h{3})\z/.freeze
LIGHTNING_ICON = File.read(Rails.root.join("app/assets/images/lightning.svg")).freeze
STACK_ICON = File.read(Rails.root.join("app/assets/images/stack.svg")).freeze
# Forem Team
# [forem-fix] Remove channel name from SiteConfig
field :article_published_slack_channel, type: :string, default: "activity"
# Meta
field :admin_action_taken_at, type: :datetime, default: Time.current
# Core setup
field :waiting_on_first_user, type: :boolean, default: !User.exists?
field :app_domain, type: :string, default: ApplicationConfig["APP_DOMAIN"]
# API Tokens
field :health_check_token, type: :string
field :video_encoder_key, type: :string
# Emails
field :email_addresses, type: :hash, default: {
default: ApplicationConfig["DEFAULT_EMAIL"],
contact: ApplicationConfig["DEFAULT_EMAIL"],
business: ApplicationConfig["DEFAULT_EMAIL"],
privacy: ApplicationConfig["DEFAULT_EMAIL"],
members: ApplicationConfig["DEFAULT_EMAIL"]
}
# Email digest frequency
field :periodic_email_digest, type: :integer, default: 2
# Google Analytics Tracking ID, e.g. UA-71991000-1
field :ga_tracking_id, type: :string, default: ApplicationConfig["GA_TRACKING_ID"]
# Images
field :main_social_image,
type: :string,
default: proc { URL.local_image("social-media-cover.png") },
validates: { url: true }
field :favicon_url, type: :string, default: proc { URL.local_image("favicon.ico") }
field :logo_png,
type: :string,
default: proc { URL.local_image("icon.png") },
validates: { url: true }
field :logo_svg, type: :string
field :enable_video_upload, type: :boolean, default: false
# Mascot
field :mascot_user_id, type: :integer, default: nil
field :mascot_image_url,
type: :string,
default: proc { URL.local_image("mascot.png") },
validates: { url: true }
# Meta keywords
field :meta_keywords, type: :hash, default: {
default: nil,
article: nil,
tag: nil
}
# Monetization
field :payment_pointer, type: :string
field :stripe_api_key, type: :string, default: ApplicationConfig["STRIPE_SECRET_KEY"]
field :stripe_publishable_key, type: :string, default: ApplicationConfig["STRIPE_PUBLISHABLE_KEY"]
# Newsletter
# <https://mailchimp.com/developer/>
field :mailchimp_api_key, type: :string, default: ApplicationConfig["MAILCHIMP_API_KEY"]
field :mailchimp_newsletter_id, type: :string, default: ""
field :mailchimp_sustaining_members_id, type: :string, default: ""
field :mailchimp_tag_moderators_id, type: :string, default: ""
field :mailchimp_community_moderators_id, type: :string, default: ""
# Mailchimp webhook secret. Part of the callback URL in the Mailchimp settings.
# <https://mailchimp.com/developer/guides/about-webhooks/#Webhooks_security>
field :mailchimp_incoming_webhook_secret, type: :string, default: ""
# Onboarding
field :onboarding_background_image, type: :string, validates: { url: true }
field :suggested_tags, type: :array, default: %w[]
field :suggested_users, type: :array, default: %w[]
field :prefer_manual_suggested_users, type: :boolean, default: false
# Social Media
field :social_media_handles, type: :hash, default: {
twitter: nil,
facebook: nil,
github: nil,
instagram: nil,
twitch: nil
}
field :twitter_hashtag, type: :string
# Sponsors
field :sponsor_headline, default: "Community Sponsors"
# Tags
field :sidebar_tags, type: :array, default: %w[]
# Broadcast
field :welcome_notifications_live_at, type: :date
# Credits
field :credit_prices_in_cents, type: :hash, default: {
small: 500,
medium: 400,
large: 300,
xlarge: 250
}
# Push Notifications
field :push_notifications_ios_pem, type: :string
# Returns true if we are operating on a local installation, false otherwise
def self.local?
app_domain.include?("localhost")
end
# Used where we need to keep old DEV features around but don't want to/cannot
# expose them to other communities.
def self.dev_to?
app_domain == "dev.to"
end
# To get default values
def self.get_default(field)
get_field(field)[:default]
end
def self.smtp_enabled?
Rails.configuration.action_mailer.perform_deliveries
end
end

View file

@ -310,7 +310,7 @@ class User < ApplicationRecord
end
def self.mascot_account
find_by(id: SiteConfig.mascot_user_id)
find_by(id: Settings::General.mascot_user_id)
end
def tag_line
@ -498,7 +498,7 @@ class User < ApplicationRecord
def subscribe_to_mailchimp_newsletter
return unless registered && email.present?
return if SiteConfig.mailchimp_api_key.blank? && SiteConfig.mailchimp_newsletter_id.blank?
return if Settings::General.mailchimp_api_key.blank? && Settings::General.mailchimp_newsletter_id.blank?
return if saved_changes.key?(:unconfirmed_email) && saved_changes.key?(:confirmation_sent_at)
return unless saved_changes.key?(:email) || saved_changes.key?(:email_newsletter)
@ -526,7 +526,7 @@ class User < ApplicationRecord
def unsubscribe_from_newsletters
return if email.blank?
return if SiteConfig.mailchimp_api_key.blank? && SiteConfig.mailchimp_newsletter_id.blank?
return if Settings::General.mailchimp_api_key.blank? && Settings::General.mailchimp_newsletter_id.blank?
Mailchimp::Bot.new(self).unsubscribe_all_newsletters
end
@ -696,6 +696,6 @@ class User < ApplicationRecord
end
def confirmation_required?
SiteConfig.smtp_enabled?
ForemInstance.smtp_enabled?
end
end

View file

@ -8,6 +8,6 @@ class VideoPolicy < ApplicationPolicy
end
def enabled?
SiteConfig.enable_video_upload
Settings::General.enable_video_upload
end
end

View file

@ -18,7 +18,7 @@ module Authentication
}
if Rails.env.test?
user_data[:profile_image] = SiteConfig.mascot_image_url
user_data[:profile_image] = Settings::General.mascot_image_url
else
user_data[:remote_profile_image_url] = Users::ProfileImageGenerator.call
end

View file

@ -13,7 +13,7 @@ class EmailDigest
# Temporary
# @sre:mstruve This is temporary until we have an efficient way to handle this job
# for our large DEV community. Smaller Forems should be able to handle it no problem
if SiteConfig.dev_to?
if ForemInstance.dev_to?
Emails::SendUserDigestWorker.new.perform(user.id)
else
Emails::SendUserDigestWorker.perform_async(user.id)

View file

@ -50,7 +50,7 @@ class EmailDigestArticleCollector
return true unless last_email_sent_at
# Has it been at least x days since @user received an email?
Time.current - last_email_sent_at >= SiteConfig.periodic_email_digest
Time.current - last_email_sent_at >= Settings::General.periodic_email_digest
end
def last_email_sent_at

View file

@ -9,7 +9,7 @@ module ErrorMessages
def self.call(error_message)
return error_message unless error_message.match?(FRONTMATTER_ERROR)
format(REPLACEMENT_ERROR, SiteConfig.email_addresses[:contact])
format(REPLACEMENT_ERROR, Settings::General.email_addresses[:contact])
end
end
end

View file

@ -274,7 +274,7 @@ module Html
username = mention.delete("@").downcase
if User.find_by(username: username)
<<~HTML
<a class='mentioned-user' href='#{ApplicationConfig['APP_PROTOCOL']}#{SiteConfig.app_domain}/#{username}'>@#{username}</a>
<a class='mentioned-user' href='#{ApplicationConfig['APP_PROTOCOL']}#{Settings::General.app_domain}/#{username}'>@#{username}</a>
HTML
else
mention

View file

@ -5,7 +5,7 @@ module Mailchimp
def initialize(user)
@user = user
@saved_changes = user.saved_changes
Gibbon::Request.api_key = SiteConfig.mailchimp_api_key
Gibbon::Request.api_key = Settings::General.mailchimp_api_key
Gibbon::Request.timeout = 15
@gibbon = Gibbon::Request.new
end
@ -22,7 +22,7 @@ module Mailchimp
# attempt to update email if user changed email addresses
success = false
begin
gibbon.lists(SiteConfig.mailchimp_newsletter_id).members(target_md5_email).upsert(
gibbon.lists(Settings::General.mailchimp_newsletter_id).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: user.email_newsletter ? "subscribed" : "unsubscribed",
@ -54,7 +54,7 @@ module Mailchimp
success = false
begin
gibbon.lists(SiteConfig.mailchimp_newsletter_id).members(target_md5_email).upsert(
gibbon.lists(Settings::General.mailchimp_newsletter_id).members(target_md5_email).upsert(
body: { status: "pending" },
)
success = true
@ -65,12 +65,12 @@ module Mailchimp
end
def manage_community_moderator_list
return false unless SiteConfig.mailchimp_community_moderators_id.present? && user.has_role?(:trusted)
return false unless Settings::General.mailchimp_community_moderators_id.present? && user.has_role?(:trusted)
success = false
status = user.email_community_mod_newsletter ? "subscribed" : "unsubscribed"
begin
gibbon.lists(SiteConfig.mailchimp_community_moderators_id).members(target_md5_email).upsert(
gibbon.lists(Settings::General.mailchimp_community_moderators_id).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: status,
@ -91,7 +91,7 @@ module Mailchimp
end
def manage_tag_moderator_list
return false unless SiteConfig.mailchimp_tag_moderators_id.present? && user.tag_moderator?
return false unless Settings::General.mailchimp_tag_moderators_id.present? && user.tag_moderator?
success = false
@ -101,7 +101,7 @@ module Mailchimp
status = user.email_tag_mod_newsletter ? "subscribed" : "unsubscribed"
begin
gibbon.lists(SiteConfig.mailchimp_tag_moderators_id).members(target_md5_email).upsert(
gibbon.lists(Settings::General.mailchimp_tag_moderators_id).members(target_md5_email).upsert(
body: {
email_address: user.email,
status: status,
@ -123,9 +123,9 @@ module Mailchimp
end
def unsub_sustaining_member
return unless SiteConfig.mailchimp_sustaining_members_id.present? && a_sustaining_member?
return unless Settings::General.mailchimp_sustaining_members_id.present? && a_sustaining_member?
gibbon.lists(SiteConfig.mailchimp_sustaining_members_id).members(target_md5_email).update(
gibbon.lists(Settings::General.mailchimp_sustaining_members_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
@ -133,9 +133,9 @@ module Mailchimp
end
def unsub_community_mod
return unless SiteConfig.mailchimp_community_moderators_id.present? && user.trusted
return unless Settings::General.mailchimp_community_moderators_id.present? && user.trusted
gibbon.lists(SiteConfig.mailchimp_community_moderators_id).members(target_md5_email).update(
gibbon.lists(Settings::General.mailchimp_community_moderators_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
@ -143,9 +143,9 @@ module Mailchimp
end
def unsub_tag_mod
return unless SiteConfig.mailchimp_tag_moderators_id.present? && user.tag_moderator?
return unless Settings::General.mailchimp_tag_moderators_id.present? && user.tag_moderator?
gibbon.lists(SiteConfig.mailchimp_tag_moderators_id).members(target_md5_email).update(
gibbon.lists(Settings::General.mailchimp_tag_moderators_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},
@ -155,7 +155,7 @@ module Mailchimp
def unsubscribe_all_newsletters
success = false
begin
gibbon.lists(SiteConfig.mailchimp_newsletter_id).members(target_md5_email).update(
gibbon.lists(Settings::General.mailchimp_newsletter_id).members(target_md5_email).update(
body: {
status: "unsubscribed"
},

View file

@ -1,6 +1,6 @@
# This service encapsulates the logic related to validating if reCAPTCHA is
# enabled in the current Forem instance. The decision is based on making
# sure the necessary SiteConfig keys are available and also on the user
# sure the necessary Settings::General keys are available and also on the user
# object passed in.
#
# Example use: ReCaptcha::CheckEnabled.call(current_user) => true/false

View file

@ -2,7 +2,7 @@ module ReCaptcha
class CheckRegistrationEnabled
def self.call
# ReCaptcha::CheckEnabled.call without a user parameter will return `true`
# if the ReCaptcha SiteConfig keys are configured, and `false` otherwise
# if the ReCaptcha Settings::General keys are configured, and `false` otherwise
ReCaptcha::CheckEnabled.call &&
Settings::Authentication.require_captcha_for_email_password_registration
end

View file

@ -34,11 +34,11 @@ module Settings
def upsert_configs
@configs.each do |key, value|
if value.is_a?(Array)
SiteConfig.public_send("#{key}=", value.reject(&:blank?)) unless value.empty?
Settings::General.public_send("#{key}=", value.reject(&:blank?)) unless value.empty?
elsif value.respond_to?(:to_h)
SiteConfig.public_send("#{key}=", value.to_h) unless value.empty?
Settings::General.public_send("#{key}=", value.to_h) unless value.empty?
else
SiteConfig.public_send("#{key}=", value.strip) unless value.nil?
Settings::General.public_send("#{key}=", value.strip) unless value.nil?
end
rescue ActiveRecord::RecordInvalid => e
@errors << e.message
@ -62,7 +62,7 @@ module Settings
# This is an acts-as-taggable-on as used on saving of an Article, etc.
return unless (@configs.keys & %w[suggested_tags sidebar_tags]).any?
Tag.find_or_create_all_with_like_by_name(SiteConfig.suggested_tags + SiteConfig.sidebar_tags)
Tag.find_or_create_all_with_like_by_name(Settings::General.suggested_tags + Settings::General.sidebar_tags)
end
end
end

View file

@ -23,10 +23,10 @@ module Slack
url: URL.article(article),
)
# [forem-fix] Remove channel name from SiteConfig
# [forem-fix] Remove channel name from Settings::General
Slack::Messengers::Worker.perform_async(
message: message,
channel: SiteConfig.article_published_slack_channel,
channel: Settings::General.article_published_slack_channel,
username: "article_bot",
icon_emoji: ":writing_hand:",
)

View file

@ -58,8 +58,8 @@ module TagModerators
end
def tag_mod_newsletter_enabled?
SiteConfig.mailchimp_api_key.present? &&
SiteConfig.mailchimp_tag_moderators_id.present?
Settings::General.mailchimp_api_key.present? &&
Settings::General.mailchimp_tag_moderators_id.present?
end
def chat_channel_slug(tag)

View file

@ -13,8 +13,8 @@ module TagModerators
end
def self.community_mod_newsletter_enabled?
SiteConfig.mailchimp_api_key.present? &&
SiteConfig.mailchimp_community_moderators_id.present?
Settings::General.mailchimp_api_key.present? &&
Settings::General.mailchimp_community_moderators_id.present?
end
private_class_method :community_mod_newsletter_enabled?
end

View file

@ -10,8 +10,8 @@ module TagModerators
end
def self.tag_mod_newsletter_enabled?
SiteConfig.mailchimp_api_key.present? &&
SiteConfig.mailchimp_tag_moderators_id.present?
Settings::General.mailchimp_api_key.present? &&
Settings::General.mailchimp_tag_moderators_id.present?
end
private_class_method :tag_mod_newsletter_enabled?
end

View file

@ -4,7 +4,7 @@ module Users
email: "mascot@forem.com",
username: "mascot",
name: "Mascot",
profile_image: SiteConfig.mascot_image_url,
profile_image: Settings::General.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::General.mascot_user_id
mascot = User.create!(mascot_params)
SiteConfig.mascot_user_id = mascot.id
Settings::General.mascot_user_id = mascot.id
end
def mascot_params

View file

@ -18,7 +18,7 @@ module Articles
end
return legacy_article_social_image unless use_new_social_url?
article_social_preview_url(article, format: :png, host: SiteConfig.app_domain)
article_social_preview_url(article, format: :png, host: Settings::General.app_domain)
end
private

View file

@ -5,7 +5,7 @@
<p class="crayons-field__description">Type the sentence: <strong><%= @confirmation_text %></strong></p>
<div class="flex">
<%= text_field_tag :confirmation, nil, class: "crayons-textfield flex-1 mr-2", placeholder: "Confirmation text", autocomplete: "off", required: true, pattern: @confirmation_text %>
<%= f.submit "Update Site Configuration", class: "crayons-btn align-self-start" %>
<%= f.submit "Update Settings", class: "crayons-btn align-self-start" %>
</div>
</div>
</div>

View file

@ -83,7 +83,7 @@
<p class="crayons-field__description">Type the sentence: <strong><%= @confirmation_text %></strong></p>
<div class="flex">
<%= text_field_tag :confirmation, nil, class: "crayons-textfield flex-1 mr-2", placeholder: "Confirmation text", autocomplete: "off", required: true, pattern: @confirmation_text %>
<%= f.submit "Update Site Configuration", class: "crayons-btn align-self-start" %>
<%= f.submit "Update Settings", class: "crayons-btn align-self-start" %>
</div>
</div>
</div>
@ -94,28 +94,28 @@
</div>
</div>
<div id="siteConfig">
<div id="settings">
<div class="card w-100">
<div
id="siteConfigHeader"
id="settingsHeader"
class="card-header"
data-toggle="collapse"
data-target="#siteConfigBodyContainer"
data-target="#settingsBodyContainer"
aria-expanded="true"
aria-controls="siteConfigBodyContainer">
aria-controls="settingsBodyContainer">
<h2 class="d-inline">All Site Configuration</h2>
<h2 class="d-inline">All Settings</h2>
<button
class="crayons-btn crayons-btn--secondary float-right"
type="button"
data-action="click->config#toggleAccordionButtonLabel">
Hide Site Configuration
Hide Settings
</button>
</div>
<div id="siteConfigBodyContainer" class="show expand p-3" aria-labelledby="siteConfigHeader">
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<div id="settingsBodyContainer" class="show expand p-3" aria-labelledby="settingsHeader">
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -128,19 +128,19 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :health_check_token %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:health_check_token][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:health_check_token][:description] %>
<%= f.text_field :health_check_token,
class: "crayons-textfield",
value: SiteConfig.health_check_token,
placeholder: Constants::SiteConfig::DETAILS[:health_check_token][:placeholder] %>
value: Settings::General.health_check_token,
placeholder: Constants::Settings::General::DETAILS[:health_check_token][:placeholder] %>
</div>
<div class="crayons-field">
<%= admin_config_label :video_encoder_key %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:video_encoder_key][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:video_encoder_key][:description] %>
<%= f.text_field :video_encoder_key,
class: "crayons-textfield",
value: SiteConfig.video_encoder_key,
placeholder: Constants::SiteConfig::DETAILS[:video_encoder_key][:placeholder] %>
value: Settings::General.video_encoder_key,
placeholder: Constants::Settings::General::DETAILS[:video_encoder_key][:placeholder] %>
</div>
<%= render "form_submission", f: f %>
</fieldset>
@ -533,7 +533,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -548,33 +548,33 @@
<%= f.fields_for :credit_prices_in_cents do |price_field| %>
<div class="crayons-field">
<%= admin_config_label "Credit price in cents (S)" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:credit_prices_in_cents][:small][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:credit_prices_in_cents][:small][:description] %>
<%= price_field.number_field :small,
class: "crayons-textfield",
value: SiteConfig.credit_prices_in_cents[:small] %>
value: Settings::General.credit_prices_in_cents[:small] %>
</div>
<div class="crayons-field">
<%= admin_config_label "Credit price in cents (M)" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:credit_prices_in_cents][:medium][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:credit_prices_in_cents][:medium][:description] %>
<%= price_field.number_field :medium,
class: "crayons-textfield",
value: SiteConfig.credit_prices_in_cents[:medium] %>
value: Settings::General.credit_prices_in_cents[:medium] %>
</div>
<div class="crayons-field">
<%= admin_config_label "Credit price in cents (L)" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:credit_prices_in_cents][:large][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:credit_prices_in_cents][:large][:description] %>
<%= price_field.number_field :large,
class: "crayons-textfield",
value: SiteConfig.credit_prices_in_cents[:large] %>
value: Settings::General.credit_prices_in_cents[:large] %>
</div>
<div class="crayons-field">
<%= admin_config_label "Credit price in cents (XL)" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:credit_prices_in_cents][:xlarge][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:credit_prices_in_cents][:xlarge][:description] %>
<%= price_field.number_field :xlarge,
class: "crayons-textfield",
value: SiteConfig.credit_prices_in_cents[:xlarge] %>
value: Settings::General.credit_prices_in_cents[:xlarge] %>
</div>
<% end %>
@ -584,7 +584,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -596,7 +596,7 @@
<div id="emailBodyContainer" class="card-body collapse hide" aria-labelledby="emailBodyContainer">
<fieldset class="grid gap-4">
<div class="crayons-field">
<label for="site_config_email_addresses_default" class="crayons-field__label">
<label for="settings_general_email_addresses_default" class="crayons-field__label">
Default
</label>
<div class="crayons-field__description">
@ -605,14 +605,14 @@
<input type="text" value="<%= ApplicationConfig["DEFAULT_EMAIL"] %>" class="form-control" readonly>
</div>
<%= f.fields_for :email_addresses do |email_field| %>
<% SiteConfig.email_addresses.except(:default).each do |type, address| %>
<% Settings::General.email_addresses.except(:default).each do |type, address| %>
<div class="crayons-field">
<%= admin_config_label type %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:email_addresses][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:email_addresses][:description] %>
<%= email_field.text_field type,
class: "crayons-textfield",
value: SiteConfig.email_addresses[type],
placeholder: Constants::SiteConfig::DETAILS[:email_addresses][:placeholder] %>
value: Settings::General.email_addresses[type],
placeholder: Constants::Settings::General::DETAILS[:email_addresses][:placeholder] %>
</div>
<% end %>
<% end %>
@ -622,7 +622,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path, html: { data: { testid: "emailDigestSectionForm" } }) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path, html: { data: { testid: "emailDigestSectionForm" } }) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -635,11 +635,11 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :periodic_email_digest %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:periodic_email_digest][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:periodic_email_digest][:description] %>
<%= f.number_field :periodic_email_digest,
class: "crayons-textfield",
value: SiteConfig.periodic_email_digest,
placeholder: Constants::SiteConfig::DETAILS[:periodic_email_digest][:placeholder] %>
value: Settings::General.periodic_email_digest,
placeholder: Constants::Settings::General::DETAILS[:periodic_email_digest][:placeholder] %>
</div>
<%= render "form_submission", f: f %>
@ -648,7 +648,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -661,10 +661,10 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :ga_tracking_id, "View ID" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:ga_tracking_id][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:ga_tracking_id][:description] %>
<%= f.text_field :ga_tracking_id,
class: "crayons-textfield",
value: SiteConfig.ga_tracking_id %>
value: Settings::General.ga_tracking_id %>
</div>
<%= render "form_submission", f: f %>
@ -673,7 +673,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -686,49 +686,49 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :main_social_image %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:main_social_image][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:main_social_image][:description] %>
<%= f.text_field :main_social_image,
class: "crayons-textfield",
value: SiteConfig.main_social_image,
placeholder: Constants::SiteConfig::DETAILS[:main_social_image][:placeholder] %>
<% if SiteConfig.main_social_image.present? %>
<img alt="main social image" class="img-fluid" src="<%= SiteConfig.main_social_image %>" width="600px" height="337px" />
value: Settings::General.main_social_image,
placeholder: Constants::Settings::General::DETAILS[:main_social_image][:placeholder] %>
<% if Settings::General.main_social_image.present? %>
<img alt="main social image" class="img-fluid" src="<%= Settings::General.main_social_image %>" width="600px" height="337px" />
<% end %>
</div>
<div class="crayons-field">
<%= admin_config_label :favicon_url, "Favicon URL" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:favicon_url][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:favicon_url][:description] %>
<%= f.text_field :favicon_url,
class: "form-control",
value: SiteConfig.favicon_url,
placeholder: Constants::SiteConfig::DETAILS[:favicon_url][:placeholder] %>
<img alt="favicon" class="preview" src="<%= Images::Optimizer.call(SiteConfig.favicon_url, width: 32) %>" width="32px" height="32px" />
value: Settings::General.favicon_url,
placeholder: Constants::Settings::General::DETAILS[:favicon_url][:placeholder] %>
<img alt="favicon" class="preview" src="<%= Images::Optimizer.call(Settings::General.favicon_url, width: 32) %>" width="32px" height="32px" />
</div>
<div class="crayons-field">
<%= admin_config_label :logo_png %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:logo_png][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:logo_png][:description] %>
<%= f.text_field :logo_png,
class: "crayons-textfield",
value: SiteConfig.logo_png,
placeholder: Constants::SiteConfig::DETAILS[:logo_png][:placeholder] %>
<% if SiteConfig.logo_png.present? %>
<img src="<%= Images::Optimizer.call(SiteConfig.logo_png, width: 128) %>" width="128px" height="128px" />
value: Settings::General.logo_png,
placeholder: Constants::Settings::General::DETAILS[:logo_png][:placeholder] %>
<% if Settings::General.logo_png.present? %>
<img src="<%= Images::Optimizer.call(Settings::General.logo_png, width: 128) %>" width="128px" height="128px" />
<% end %>
</div>
<div class="crayons-field">
<%= admin_config_label :logo_svg %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:logo_svg][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:logo_svg][:description] %>
<%= f.text_area :logo_svg,
class: "crayons-textfield",
value: SiteConfig.logo_svg,
value: Settings::General.logo_svg,
rows: 6,
placeholder: Constants::SiteConfig::DETAILS[:logo_svg][:placeholder] %>
<% if SiteConfig.logo_svg.present? %>
placeholder: Constants::Settings::General::DETAILS[:logo_svg][:placeholder] %>
<% if Settings::General.logo_svg.present? %>
<div class="site-logo">
<%= SiteConfig.logo_svg.html_safe %>
<%= Settings::General.logo_svg.html_safe %>
</div>
<% end %>
</div>
@ -739,7 +739,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path, html: { data: { testid: "mascotSectionForm" } }) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path, html: { data: { testid: "mascotSectionForm" } }) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -752,24 +752,24 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :mascot_user_id, "Mascot user ID" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_user_id][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mascot_user_id][:description] %>
<%= f.text_field :mascot_user_id,
class: "crayons-textfield",
value: SiteConfig.mascot_user_id,
value: Settings::General.mascot_user_id,
min: 1,
placeholder: Constants::SiteConfig::DETAILS[:mascot_user_id][:placeholder] %>
placeholder: Constants::Settings::General::DETAILS[:mascot_user_id][:placeholder] %>
</div>
<div class="crayons-field">
<%= admin_config_label :mascot_image_url, "Mascot Image URL" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mascot_image_url][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mascot_image_url][:description] %>
<%= f.text_field :mascot_image_url,
class: "crayons-textfield",
value: SiteConfig.mascot_image_url,
placeholder: Constants::SiteConfig::DETAILS[:mascot_image_url][:placeholder] %>
value: Settings::General.mascot_image_url,
placeholder: Constants::Settings::General::DETAILS[:mascot_image_url][:placeholder] %>
<div class="col-12">
<img alt="Mascot image" class="img-fluid" src="<%= SiteConfig.mascot_image_url %>" />
<img alt="Mascot image" class="img-fluid" src="<%= Settings::General.mascot_image_url %>" />
</div>
</div>
@ -779,7 +779,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -791,7 +791,7 @@
<div id="metaKeywordsBodyContainer" class="card-body collapse hide" aria-labelledby="metaKeywordsBodyContainer">
<fieldset class="grid gap-4">
<%= f.fields_for :meta_keywords do |meta_keywords_field| %>
<% SiteConfig.meta_keywords.each do |area, keywords| %>
<% Settings::General.meta_keywords.each do |area, keywords| %>
<div class="crayons-field">
<%= admin_config_label area.to_s %>
<p class="crayons-field__description">
@ -799,8 +799,8 @@
</p>
<%= meta_keywords_field.text_field area,
class: "crayons-textfield",
value: SiteConfig.meta_keywords[area],
placeholder: Constants::SiteConfig::DETAILS[:meta_keywords][:placeholder] %>
value: Settings::General.meta_keywords[area],
placeholder: Constants::Settings::General::DETAILS[:meta_keywords][:placeholder] %>
</div>
<% end %>
<% end %>
@ -811,7 +811,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -825,29 +825,29 @@
<div class="crayons-field">
<%= admin_config_label :stripe_api_key, "Stripe API key" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:stripe_api_key][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:stripe_api_key][:description] %>
<%= f.text_field :stripe_api_key,
class: "crayons-textfield",
value: SiteConfig.stripe_api_key,
placeholder: Constants::SiteConfig::DETAILS[:stripe_api_key][:placeholder] %>
value: Settings::General.stripe_api_key,
placeholder: Constants::Settings::General::DETAILS[:stripe_api_key][:placeholder] %>
</div>
<div class="crayons-field">
<%= admin_config_label :stripe_publishable_key %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:stripe_publishable_key][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:stripe_publishable_key][:description] %>
<%= f.text_field :stripe_publishable_key,
class: "crayons-textfield",
value: SiteConfig.stripe_publishable_key,
placeholder: Constants::SiteConfig::DETAILS[:stripe_publishable_key][:placeholder] %>
value: Settings::General.stripe_publishable_key,
placeholder: Constants::Settings::General::DETAILS[:stripe_publishable_key][:placeholder] %>
</div>
<div class="crayons-field">
<%= admin_config_label :payment_pointer %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:payment_pointer][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:payment_pointer][:description] %>
<%= f.text_field :payment_pointer,
class: "crayons-textfield",
value: SiteConfig.payment_pointer,
placeholder: Constants::SiteConfig::DETAILS[:payment_pointer][:placeholder] %>
value: Settings::General.payment_pointer,
placeholder: Constants::Settings::General::DETAILS[:payment_pointer][:placeholder] %>
</div>
<%= render "form_submission", f: f %>
@ -856,7 +856,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -869,42 +869,42 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :mailchimp_api_key, "Mailchimp API Key" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mailchimp_api_key][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mailchimp_api_key][:description] %>
<%= f.text_field :mailchimp_api_key,
class: "crayons-textfield",
value: SiteConfig.mailchimp_api_key %>
value: Settings::General.mailchimp_api_key %>
</div>
<div class="crayons-field">
<%= admin_config_label :mailchimp_newsletter_id, "Main Newsletter" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mailchimp_newsletter_id][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mailchimp_newsletter_id][:description] %>
<%= f.text_field :mailchimp_newsletter_id,
class: "crayons-textfield",
value: SiteConfig.mailchimp_newsletter_id %>
value: Settings::General.mailchimp_newsletter_id %>
</div>
<div class="crayons-field">
<%= admin_config_label :mailchimp_sustaining_members_id, "Sustaining Members Newsletter" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mailchimp_sustaining_members_id][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mailchimp_sustaining_members_id][:description] %>
<%= f.text_field :mailchimp_sustaining_members_id,
class: "crayons-textfield",
value: SiteConfig.mailchimp_sustaining_members_id %>
value: Settings::General.mailchimp_sustaining_members_id %>
</div>
<div class="crayons-field">
<%= admin_config_label :mailchimp_tag_moderators_id, "Tag Moderators Newsletter" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mailchimp_tag_moderators_id][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mailchimp_tag_moderators_id][:description] %>
<%= f.text_field :mailchimp_tag_moderators_id,
class: "crayons-textfield",
value: SiteConfig.mailchimp_tag_moderators_id %>
value: Settings::General.mailchimp_tag_moderators_id %>
</div>
<div class="crayons-field">
<%= admin_config_label :mailchimp_community_moderators_id, "Community Moderators Newsletter" %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:mailchimp_community_moderators_id][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:mailchimp_community_moderators_id][:description] %>
<%= f.text_field :mailchimp_community_moderators_id,
class: "crayons-textfield",
value: SiteConfig.mailchimp_community_moderators_id %>
value: Settings::General.mailchimp_community_moderators_id %>
</div>
<%= render "form_submission", f: f %>
@ -913,7 +913,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -926,33 +926,33 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :onboarding_background_image %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:onboarding_background_image][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:onboarding_background_image][:description] %>
<%= f.text_field :onboarding_background_image,
class: "crayons-textfield",
value: SiteConfig.onboarding_background_image,
placeholder: Constants::SiteConfig::DETAILS[:onboarding_background_image][:placeholder] %>
value: Settings::General.onboarding_background_image,
placeholder: Constants::Settings::General::DETAILS[:onboarding_background_image][:placeholder] %>
<div class="row mt-2">
<div class="col-12">
<img alt="onboarding background image" class="img-fluid" src="<%= SiteConfig.onboarding_background_image %>" />
<img alt="onboarding background image" class="img-fluid" src="<%= Settings::General.onboarding_background_image %>" />
</div>
</div>
</div>
<div class="crayons-field">
<%= admin_config_label :suggested_users %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:suggested_users][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:suggested_users][:description] %>
<%= f.text_field :suggested_users,
class: "crayons-textfield",
value: SiteConfig.suggested_users.join(","),
placeholder: Constants::SiteConfig::DETAILS[:suggested_users][:placeholder] %>
value: Settings::General.suggested_users.join(","),
placeholder: Constants::Settings::General::DETAILS[:suggested_users][:placeholder] %>
</div>
<div class="crayons-field crayons-field--checkbox">
<%= f.check_box :prefer_manual_suggested_users, checked: SiteConfig.prefer_manual_suggested_users, class: "crayons-checkbox" %>
<%= f.check_box :prefer_manual_suggested_users, checked: Settings::General.prefer_manual_suggested_users, class: "crayons-checkbox" %>
<div class="mt-0">
<%= admin_config_label :prefer_manual_suggested_users %>
<p class="crayons-field__description">
<%= Constants::SiteConfig::DETAILS[:prefer_manual_suggested_users][:description] %>
<%= Constants::Settings::General::DETAILS[:prefer_manual_suggested_users][:description] %>
</p>
</div>
</div>
@ -1011,7 +1011,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -1024,14 +1024,14 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :twitter_hashtag %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:twitter_hashtag][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:twitter_hashtag][:description] %>
<%= f.text_field :twitter_hashtag,
class: "crayons-textfield",
value: SiteConfig.twitter_hashtag.to_s,
placeholder: Constants::SiteConfig::DETAILS[:twitter_hashtag][:placeholder] %>
value: Settings::General.twitter_hashtag.to_s,
placeholder: Constants::Settings::General::DETAILS[:twitter_hashtag][:placeholder] %>
</div>
<%= f.fields_for :social_media_handles do |social_media_field| %>
<% SiteConfig.social_media_handles.each do |platform, username| %>
<% Settings::General.social_media_handles.each do |platform, username| %>
<div class="crayons-field">
<%= admin_config_label platform %>
<p class="crayons-field__description">
@ -1039,7 +1039,7 @@
</p>
<%= social_media_field.text_field platform,
class: "crayons-textfield",
value: SiteConfig.social_media_handles[platform],
value: Settings::General.social_media_handles[platform],
placeholder: "" %>
</div>
<% end %>
@ -1051,7 +1051,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -1064,11 +1064,11 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :sponsor_headline %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:sponsor_headline][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:sponsor_headline][:description] %>
<%= f.text_field :sponsor_headline,
class: "crayons-textfield",
value: SiteConfig.sponsor_headline,
placeholder: Constants::SiteConfig::DETAILS[:sponsor_headline][:placeholder] %>
value: Settings::General.sponsor_headline,
placeholder: Constants::Settings::General::DETAILS[:sponsor_headline][:placeholder] %>
</div>
<%= render "form_submission", f: f %>
@ -1077,7 +1077,7 @@
</div>
<% end %>
<%= form_for(SiteConfig.new, url: admin_config_path) do |f| %>
<%= form_for(Settings::General.new, url: admin_config_path) do |f| %>
<div class="card mt-3">
<%= render partial: "admin/shared/card_header",
locals: {
@ -1090,11 +1090,11 @@
<fieldset class="grid gap-4">
<div class="crayons-field">
<%= admin_config_label :sidebar_tags %>
<%= admin_config_description Constants::SiteConfig::DETAILS[:sidebar_tags][:description] %>
<%= admin_config_description Constants::Settings::General::DETAILS[:sidebar_tags][:description] %>
<%= f.text_field :sidebar_tags,
class: "crayons-textfield",
value: SiteConfig.sidebar_tags.join(","),
placeholder: Constants::SiteConfig::DETAILS[:sidebar_tags][:placeholder],
value: Settings::General.sidebar_tags.join(","),
placeholder: Constants::Settings::General::DETAILS[:sidebar_tags][:placeholder],
pattern: "[a-z0-9,]+" %>
</div>

View file

@ -31,7 +31,7 @@
data-reaction-url-value="<%= admin_reaction_path(reaction.id) %>">
<span>
🤢 <a href="<%= reaction.user.path %>" target="_blank" rel="noopener">@<%= reaction.user.username %></a>
<% if reaction.user_id == SiteConfig.mascot_user_id %>
<% if reaction.user_id == Settings::General.mascot_user_id %>
<strong>(auto-generated)</strong>
<% end %>
</span>

View file

@ -12,7 +12,7 @@
</p>
<p>
Exporting the data to your admin account will send it to your contact
admin email (<%= SiteConfig.email_addresses[:contact] %>),
admin email (<%= Settings::General.email_addresses[:contact] %>),
and exporting to the user will send it to their email (<%= @user.email %>).
</p>
<div style="display: flex;">

View file

@ -1,3 +1,3 @@
@site_configs.each do |config|
@settings.each do |config|
json.set! config.var, config.value
end

View file

@ -45,7 +45,7 @@
target="_blank"
class="dropdown-link-row crayons-link crayons-link--block"
rel="noopener"
href='https://twitter.com/intent/tweet?text="<%= u @article.title.strip %>" by <%= @article.user.twitter_username ? "@#{@article.user.twitter_username}" : @article.user.name %> <%= u SiteConfig.twitter_hashtag %> <%= article_url(@article) %>'>
href='https://twitter.com/intent/tweet?text="<%= u @article.title.strip %>" by <%= @article.user.twitter_username ? "@#{@article.user.twitter_username}" : @article.user.name %> <%= u Settings::General.twitter_hashtag %> <%= article_url(@article) %>'>
Share to Twitter
</a>
<a

View file

@ -9,7 +9,7 @@
<% if @sponsorships.present? %>
<div class="<%= "hidden" if user_signed_in? %> px-1" id="sponsorship-widget">
<h4 class="flex align-center fs-s ff-monospace fw-bold tt-uppercase mb-4">
<%= SiteConfig.sponsor_headline %>
<%= Settings::General.sponsor_headline %>
<%= inline_svg_tag("twemoji/heart.svg", aria: true, class: "crayons-icon crayons-icon--default ml-1", title: "Love") %>
</h4>
<div class="grid grid-cols-1 gap-6">

View file

@ -12,14 +12,14 @@
<meta property="og:type" content="website" />
<meta property="og:url" content="<%= app_url(request.path) %>" />
<meta property="og:title" content="<%= title_with_timeframe(page_title: community_name, timeframe: params[:timeframe]) %>" />
<meta property="og:image" content="<%= SiteConfig.main_social_image %>">
<meta property="og:image" content="<%= Settings::General.main_social_image %>">
<meta property="og:description" content="<%= Settings::Community.community_description %>" />
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:title" content="<%= title_with_timeframe(page_title: community_name, timeframe: params[:timeframe]) %>">
<meta name="twitter:description" content="<%= Settings::Community.community_description %>">
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">
<meta name="twitter:card" content="summary_large_image">
<%= auto_discovery_link_tag(:rss, app_url("feed"), title: "#{community_name} RSS Feed") %>
<% end %>

View file

@ -6,12 +6,12 @@
<meta property="og:type" content="website" />
<meta property="og:url" content="<%= community_name %> => Search Results" />
<meta property="og:title" content="<%= community_name %>" />
<meta property="og:image" content="<%= SiteConfig.main_social_image %>">
<meta property="og:image" content="<%= Settings::General.main_social_image %>">
<meta property="og:description" content="<%= Settings::Community.community_description %>">
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:title" content="<%= community_name %> => Search Results">
<meta name="twitter:description" content="<%= Settings::Community.community_description %>">
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">
<meta name="twitter:card" content="summary_large_image">

View file

@ -66,7 +66,7 @@
<meta property="og:title" content="<%= @article.title %>" />
<meta property="og:description" content="<%= @article.description || "An article from the community" %>" />
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:creator" content="@<%= @user.twitter_username %>">
<meta name="twitter:title" content="<%= @article.title %>">
<meta name="twitter:description" content="<%= @article.description || "An article from the community" %>">

View file

@ -14,7 +14,7 @@
<meta property="og:description" content="<%= @tag.capitalize %> content on <%= community_name %>" />
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:creator" content="@<%= @tag.capitalize %>">
<meta name="twitter:title" content="<%= title_with_timeframe(page_title: @tag.capitalize, timeframe: params[:timeframe]) %>">
<meta name="twitter:description" content="<%= @tag.capitalize %> content on <%= community_name %>">
@ -24,7 +24,7 @@
<meta property="og:image" content="<%= tag_social_preview_url(@tag_model, format: :png) %>">
<meta name="twitter:image:src" content="<%= tag_social_preview_url(@tag_model, format: :png) %>">
<% else %>
<meta property="og:image" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta property="og:image" content="<%= Settings::General.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">
<meta name="twitter:card" content="summary_large_image">
<% end %>

View file

@ -6,12 +6,12 @@
<meta property="og:type" content="article" />
<meta property="og:url" content="<%= app_url("/about") %>" />
<meta property="og:title" content="About <%= community_name %>" />
<meta property="og:image" content="<%= SiteConfig.main_social_image %>" />
<meta property="og:image" content="<%= Settings::General.main_social_image %>" />
<meta property="og:description" content="<%= community_name %> is great!" />
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:title" content="About <%= community_name %>">
<meta name="twitter:description" content="<%= community_name %> is great!">
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">

View file

@ -1,6 +1,6 @@
<% if comment.deleted %>
<span class="shrink-0 crayons-avatar <% if comment.depth == 0 %>m:crayons-avatar--l mt-4 m:mt-3<% else %>mt-4<% end %>">
<%= 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::General.mascot_image_url, width: 32, height: 32, crop: "imagga_scale"), class: "crayons-avatar__image overflow-hidden", alt: "Sloan, the sloth mascot", loading: "lazy") %>
</span>
<% else %>
<a href="<%= URL.user(comment.user) %>" class="shrink-0 crayons-avatar <% if comment.depth == 0 %>m:crayons-avatar--l mt-4 m:mt-3<% else %>mt-4<% end %>">

View file

@ -29,7 +29,7 @@
<% end %>
<span class="crayons-avatar m:crayons-avatar--l mr-2 shrink-0">
<img src="<%= Images::Optimizer.call(SiteConfig.logo_png, width: 256) %>" width="32" height="32" alt="pic" class="crayons-avatar__image overflow-hidden" id="comment-primary-user-profile--avatar">
<img src="<%= Images::Optimizer.call(Settings::General.logo_png, width: 256) %>" width="32" height="32" alt="pic" class="crayons-avatar__image overflow-hidden" id="comment-primary-user-profile--avatar">
</span>
<div class="comment-form__inner">
<div class="comment-form__field">

View file

@ -14,7 +14,7 @@
<% if decorated_comment.low_quality %>
<div class="crayons-notice crayons-notice--warning low-quality-comment-marker">
<%= image_tag(Images::Optimizer.call(SiteConfig.mascot_image_url, width: 50, height: 50, crop: "imagga_scale"), class: "sloan", alt: "Sloan, the sloth mascot", loading: "lazy") %>
<%= image_tag(Images::Optimizer.call(Settings::General.mascot_image_url, width: 50, height: 50, crop: "imagga_scale"), class: "sloan", alt: "Sloan, the sloth mascot", loading: "lazy") %>
Comment marked as low quality/non-constructive by the community. <a href="/code-of-conduct">View Code of Conduct</a>
</div>
<% end %>

View file

@ -13,7 +13,7 @@
<meta property="og:description" content="<%= @commentable.description || "#{community_name} Comment" %>" />
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:creator" content="@<%= @user.twitter_username %>">
<meta name="twitter:title" content="<%= @commentable.title %>">
<meta name="twitter:description" content="<%= @commentable.description || "#{community_name} Comment" %>">

View file

@ -154,7 +154,7 @@
changeSubmitButton({ text: 'Submitting...', active: false })
}
var stripe = Stripe('<%= SiteConfig.stripe_publishable_key %>');
var stripe = Stripe('<%= Settings::General.stripe_publishable_key %>');
var elements = stripe.elements();
<% if current_user.decorate.dark_theme? %>

View file

@ -55,8 +55,8 @@
<% else %>
<div class="p-6 m:p-9 crayons-card crayons-card--secondary align-center fs-l h-100 flex items-center justify-center flex-1">
<div>
<% if SiteConfig.mascot_image_url.present? %>
<% image_url = Images::Optimizer.call(SiteConfig.mascot_image_url, width: 300, crop: "imagga_scale") %>
<% if Settings::General.mascot_image_url.present? %>
<% image_url = Images::Optimizer.call(Settings::General.mascot_image_url, width: 300, crop: "imagga_scale") %>
<%= image_tag(image_url, class: "sloan mb-7", alt: "Mascot image") %>
<% end %>
<p class="mb-6">This is where you can manage your posts, but you haven't written anything yet.</p>

View file

@ -9,7 +9,7 @@
Whoops! Did you get stuck trying to open the mobile app?
</p>
<p class="mt-5">
Make sure it's installed and try again. If the problem persists contact <a href="mailto:<%= SiteConfig.email_addresses[:contact] %>"><%= SiteConfig.email_addresses[:contact] %></a>
Make sure it's installed and try again. If the problem persists contact <a href="mailto:<%= Settings::General.email_addresses[:contact] %>"><%= Settings::General.email_addresses[:contact] %></a>
</p>
</div>

View file

@ -75,7 +75,7 @@
<span class="timezone">America/New_York</span>
<span class="title"><%= event.title %></span>
<span class="organizer"><%= community_name %></span>
<span class="organizer_email"><%= SiteConfig.email_addresses[:members] %></span>
<span class="organizer_email"><%= Settings::General.email_addresses[:members] %></span>
<span class="calname">dev-event</span>
<span class="location"><%= event.location_url %></span>
<span class="alarm_reminder">15</span>

View file

@ -9,11 +9,11 @@
<meta property="og:title" content="<%= community_name %> Events" />
<meta property="og:description" content="Community events." />
<meta property="og:site_name" content="<%= community_name %>" />
<meta property="og:image" content="<%= SiteConfig.main_social_image %>">
<meta property="og:image" content="<%= Settings::General.main_social_image %>">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:title" content="<%= community_name %> Events">
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">
<% end %>
<script type="text/javascript" src="https://addevent.com/libs/atc/1.6.1/atc.min.js" async defer></script>

View file

@ -10,19 +10,19 @@
<% if @event.cover_image.present? %>
<meta property="og:image" content="<%= @event.cover_image_url %>" />
<% else %>
<meta property="og:image" content="<%= SiteConfig.main_social_image %>" />
<meta property="og:image" content="<%= Settings::General.main_social_image %>" />
<% end %>
<meta property="og:description" content="<%= truncate(strip_tags(@event.description_html), length: 140) %>" />
<meta property="og:site_name" content="<%= community_name %>" />
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:title" content="<%= truncate(strip_tags(@event.title), length: 70) %>">
<meta property="og:description" content="<%= truncate(strip_tags(@event.description_html), length: 140) %>" />
<% if @event.cover_image.present? %>
<meta name="twitter:image:src" content="<%= @event.cover_image_url %>">
<% else %>
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">
<% end %>
<% end %>

View file

@ -1,5 +1,5 @@
<a href="/" class="site-logo" aria-label="<%= community_name %> Home">
<% if SiteConfig.logo_svg.present? %>
<% if Settings::General.logo_svg.present? %>
<%= logo_svg %>
<% else %>
<span class="truncate-at-2">

View file

@ -1,7 +1,7 @@
<div id="global-signup-modal" class="authentication-modal hidden">
<div class="authentication-modal__container">
<figure class="authentication-modal__image-container">
<img class="authentication-modal__image" src="<%= optimized_image_url(SiteConfig.logo_png, width: 190) %>"
<img class="authentication-modal__image" src="<%= optimized_image_url(Settings::General.logo_png, width: 190) %>"
alt="<%= community_name %>" />
</figure>
<div class="authentication-modal__content">

View file

@ -1,4 +1,4 @@
<% SiteConfig.social_media_handles.each do |social_media_type, handle| %>
<% Settings::General.social_media_handles.each do |social_media_type, handle| %>
<% next if handle.blank? %>
<a
href="<%= "https://#{social_media_type}.com/#{handle}" %>"

View file

@ -8,7 +8,7 @@
<meta name="description" content="">
<meta name="author" content="">
<%= csrf_meta_tags %>
<%= favicon_link_tag Images::Optimizer.call(SiteConfig.favicon_url, width: 32) %>
<%= favicon_link_tag Images::Optimizer.call(Settings::General.favicon_url, width: 32) %>
<title><%= controller_name.titleize %></title>
<!-- StimulusJS -->
@ -28,7 +28,7 @@
data-honeybadger-key="<%= ApplicationConfig["HONEYBADGER_JS_API_KEY"] %>"
data-deployed-at="<%= ForemInstance.deployed_at %>"
data-latest-commit-id="<%= ForemInstance.latest_commit_id %>"
data-ga-tracking="<%= SiteConfig.ga_tracking_id %>">
data-ga-tracking="<%= Settings::General.ga_tracking_id %>">
<header class="crayons-header">
<div class="crayons-header__container">
<%= render "layouts/logo" %>

View file

@ -8,13 +8,13 @@
<meta name="last-updated" content="<%= Time.current %>">
<meta name="user-signed-in" content="<%= user_signed_in? %>">
<meta name="head-cached-at" content="<%= Time.current.to_i %>">
<% if SiteConfig.payment_pointer.present? %>
<% if Settings::General.payment_pointer.present? %>
<!-- Experimental web monetization payment pointer for micropayments -->
<!-- It lets readers make micropayments to websites they visit. -->
<!-- This is step 1: Get live in production to test for platform-wide payment pointer. -->
<!-- Step 2: Allow authors to set their payment pointer so they can directly monetize their content based on visitors. -->
<!-- Step 3: Enable further functionality based on what we learn from this experimentation and how the ecosystem evolves. -->
<meta name="monetization" content="<%= SiteConfig.payment_pointer %>">
<meta name="monetization" content="<%= Settings::General.payment_pointer %>">
<% end %>
<meta name="environment" content="<%= Rails.env %>">
<%= render "layouts/styles", qualifier: "main" %>
@ -27,21 +27,21 @@
<% end %>
<%= yield(:page_meta) %>
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<%= favicon_link_tag Images::Optimizer.call(SiteConfig.favicon_url, width: 32) %>
<link rel="apple-touch-icon" href="<%= optimized_image_url(SiteConfig.logo_png, width: 180, fetch_format: "png") %>">
<link rel="apple-touch-icon" sizes="152x152" href="<%= optimized_image_url(SiteConfig.logo_png, width: 152, fetch_format: "png") %>">
<link rel="apple-touch-icon" sizes="180x180" href="<%= optimized_image_url(SiteConfig.logo_png, width: 180, fetch_format: "png") %>">
<link rel="apple-touch-icon" sizes="167x167" href="<%= optimized_image_url(SiteConfig.logo_png, width: 167, fetch_format: "png") %>">
<link href="<%= optimized_image_url(SiteConfig.logo_png, width: 192, fetch_format: "png") %>" rel="icon" sizes="192x192" />
<link href="<%= optimized_image_url(SiteConfig.logo_png, width: 128, fetch_format: "png") %>" rel="icon" sizes="128x128" />
<meta name="apple-mobile-web-app-title" content="<%= SiteConfig.app_domain %>">
<meta name="application-name" content="<%= SiteConfig.app_domain %>">
<%= favicon_link_tag Images::Optimizer.call(Settings::General.favicon_url, width: 32) %>
<link rel="apple-touch-icon" href="<%= optimized_image_url(Settings::General.logo_png, width: 180, fetch_format: "png") %>">
<link rel="apple-touch-icon" sizes="152x152" href="<%= optimized_image_url(Settings::General.logo_png, width: 152, fetch_format: "png") %>">
<link rel="apple-touch-icon" sizes="180x180" href="<%= optimized_image_url(Settings::General.logo_png, width: 180, fetch_format: "png") %>">
<link rel="apple-touch-icon" sizes="167x167" href="<%= optimized_image_url(Settings::General.logo_png, width: 167, fetch_format: "png") %>">
<link href="<%= optimized_image_url(Settings::General.logo_png, width: 192, fetch_format: "png") %>" rel="icon" sizes="192x192" />
<link href="<%= optimized_image_url(Settings::General.logo_png, width: 128, fetch_format: "png") %>" rel="icon" sizes="128x128" />
<meta name="apple-mobile-web-app-title" content="<%= Settings::General.app_domain %>">
<meta name="application-name" content="<%= Settings::General.app_domain %>">
<meta name="theme-color" content="#000000" />
<link rel="search" href="<%= URL.url("open-search.xml") %>" type="application/opensearchdescription+xml" title="<%= community_name %>" />
<meta property="forem:name" content="<%= community_name %>" />
<meta property="forem:logo" content="<%= optimized_image_url(SiteConfig.logo_png, width: 512, fetch_format: "png") %>" />
<meta property="forem:domain" content="<%= SiteConfig.app_domain %>" />
<meta property="forem:logo" content="<%= optimized_image_url(Settings::General.logo_png, width: 512, fetch_format: "png") %>" />
<meta property="forem:domain" content="<%= Settings::General.app_domain %>" />
<% end %>
</head>
<% unless internal_navigation? %>
@ -54,7 +54,7 @@
data-honeybadger-key="<%= ApplicationConfig["HONEYBADGER_JS_API_KEY"] %>"
data-deployed-at="<%= ForemInstance.deployed_at %>"
data-latest-commit-id="<%= ForemInstance.latest_commit_id %>"
data-ga-tracking="<%= SiteConfig.ga_tracking_id %>">
data-ga-tracking="<%= Settings::General.ga_tracking_id %>">
<%# Repeat of stylesheets in <head> to fix rendering glitch: https://github.com/forem/forem/issues/12377 %>
<%= render "layouts/styles", qualifier: "secondary" %>
<div id="body-styles">
@ -81,8 +81,8 @@
</div>
<% end %>
<% end %>
<% if SiteConfig.payment_pointer.present? %>
<div id="base-payment-pointer" data-payment-pointer="<%= SiteConfig.payment_pointer %>"></div>
<% if Settings::General.payment_pointer.present? %>
<div id="base-payment-pointer" data-payment-pointer="<%= Settings::General.payment_pointer %>"></div>
<% end %>
<style>.app-shell-loader {display: none;}</style>
<div id="page-content" class="wrapper <%= view_class %>" data-current-page="<%= current_page %>">
@ -120,7 +120,7 @@
</div>
</div>
<% unless internal_navigation? %>
<% cache("footer-and-signup-modal-#{user_signed_in?}-#{ForemInstance.deployed_at}-#{SiteConfig.admin_action_taken_at&.rfc3339}", expires_in: 24.hours) do %>
<% cache("footer-and-signup-modal-#{user_signed_in?}-#{ForemInstance.deployed_at}-#{Settings::General.admin_action_taken_at&.rfc3339}", expires_in: 24.hours) do %>
<%= render "layouts/footer" %>
<%= render "layouts/signup_modal" unless user_signed_in? %>
<% end %>

View file

@ -18,12 +18,12 @@
<% else %>
<meta property="og:title" content="Listings" />
<meta property="og:description" content="<%= Settings::Community.community_description %>" />
<meta property="og:image" content="<%= SiteConfig.main_social_image %>">
<meta property="og:image" content="<%= Settings::General.main_social_image %>">
<meta name="twitter:title" content="Listings">
<meta name="twitter:description" content="<%= Settings::Community.community_description %>">
<meta name="twitter:image:src" content="<%= SiteConfig.main_social_image %>">
<meta name="twitter:image:src" content="<%= Settings::General.main_social_image %>">
<% end %>
<meta name="twitter:site" content="@<%= SiteConfig.social_media_handles["twitter"] %>">
<meta name="twitter:site" content="@<%= Settings::General.social_media_handles["twitter"] %>">
<meta name="twitter:card" content="summary_large_image">
<% end %>

Some files were not shown because too many files have changed in this diff Show more