mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
DEV: stop mutating inputs as a side effect
We had quite a few cases in core where inputs are being mutated as a side effect of calling a method. This handles all the cases where specs caught this. Mutating inputs makes code harder to reason about. Eg: ``` frog = "frog" jump(frog) puts frog "fly" # ????? ``` This commit is part of a followup commit that adds # frozen_string_literal to all our specs.
This commit is contained in:
parent
442111af91
commit
0a5a6dfded
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_dependency 'trust_level'
|
require_dependency 'trust_level'
|
||||||
|
|
||||||
class AdminUserIndexQuery
|
class AdminUserIndexQuery
|
||||||
|
@ -108,7 +110,7 @@ class AdminUserIndexQuery
|
||||||
|
|
||||||
filter = params[:filter]
|
filter = params[:filter]
|
||||||
if filter.present?
|
if filter.present?
|
||||||
filter.strip!
|
filter = filter.strip
|
||||||
if ip = IPAddr.new(filter) rescue nil
|
if ip = IPAddr.new(filter) rescue nil
|
||||||
@query.where('ip_address <<= :ip OR registration_ip_address <<= :ip', ip: ip.to_cidr_s)
|
@query.where('ip_address <<= :ip OR registration_ip_address <<= :ip', ip: ip.to_cidr_s)
|
||||||
else
|
else
|
||||||
|
|
|
@ -111,8 +111,9 @@ module DiscourseTagging
|
||||||
|
|
||||||
term = opts[:term]
|
term = opts[:term]
|
||||||
if term.present?
|
if term.present?
|
||||||
term.gsub!("_", "\\_")
|
term = term.gsub("_", "\\_")
|
||||||
term = clean_tag(term).downcase
|
clean_tag(term)
|
||||||
|
term.downcase!
|
||||||
query = query.where('lower(tags.name) like ?', "%#{term}%")
|
query = query.where('lower(tags.name) like ?', "%#{term}%")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -118,8 +118,13 @@ module Email
|
||||||
end
|
end
|
||||||
|
|
||||||
def body
|
def body
|
||||||
body = @opts[:body]
|
body = nil
|
||||||
body = I18n.t("#{@opts[:template]}.text_body_template", template_args).dup if @opts[:template]
|
|
||||||
|
if @opts[:template]
|
||||||
|
body = I18n.t("#{@opts[:template]}.text_body_template", template_args).dup
|
||||||
|
else
|
||||||
|
body = @opts[:body].dup
|
||||||
|
end
|
||||||
|
|
||||||
if @template_args[:unsubscribe_instructions].present?
|
if @template_args[:unsubscribe_instructions].present?
|
||||||
body << "\n"
|
body << "\n"
|
||||||
|
|
|
@ -382,7 +382,7 @@ module SiteSettingExtension
|
||||||
|
|
||||||
def filter_value(name, value)
|
def filter_value(name, value)
|
||||||
if HOSTNAME_SETTINGS.include?(name)
|
if HOSTNAME_SETTINGS.include?(name)
|
||||||
value.split("|").map { |url| get_hostname(url) }.compact.uniq.join("|")
|
value.split("|").map { |url| url.strip!; get_hostname(url) }.compact.uniq.join("|")
|
||||||
else
|
else
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
@ -488,7 +488,6 @@ module SiteSettingExtension
|
||||||
end
|
end
|
||||||
|
|
||||||
def get_hostname(url)
|
def get_hostname(url)
|
||||||
url.strip!
|
|
||||||
|
|
||||||
host = begin
|
host = begin
|
||||||
URI.parse(url)&.host
|
URI.parse(url)&.host
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
#
|
#
|
||||||
# Clean up a text
|
# Clean up a text
|
||||||
#
|
#
|
||||||
|
@ -27,6 +29,8 @@ class TextCleaner
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.clean(text, opts = {})
|
def self.clean(text, opts = {})
|
||||||
|
text = text.dup
|
||||||
|
|
||||||
# Remove invalid byte sequences
|
# Remove invalid byte sequences
|
||||||
text.scrub!("")
|
text.scrub!("")
|
||||||
# Replace !!!!! with a single !
|
# Replace !!!!! with a single !
|
||||||
|
@ -38,7 +42,7 @@ class TextCleaner
|
||||||
# Capitalize first letter, but only when entire first word is lowercase
|
# Capitalize first letter, but only when entire first word is lowercase
|
||||||
first, rest = text.split(' ', 2)
|
first, rest = text.split(' ', 2)
|
||||||
if first && opts[:capitalize_first_letter] && first == first.mb_chars.downcase
|
if first && opts[:capitalize_first_letter] && first == first.mb_chars.downcase
|
||||||
text = "#{first.mb_chars.capitalize}#{rest ? ' ' + rest : ''}"
|
text = +"#{first.mb_chars.capitalize}#{rest ? ' ' + rest : ''}"
|
||||||
end
|
end
|
||||||
# Remove unnecessary periods at the end
|
# Remove unnecessary periods at the end
|
||||||
text.sub!(/([^.])\.+(\s*)\z/, '\1\2') if opts[:remove_all_periods_from_the_end]
|
text.sub!(/([^.])\.+(\s*)\z/, '\1\2') if opts[:remove_all_periods_from_the_end]
|
||||||
|
|
|
@ -685,17 +685,26 @@ class TopicQuery
|
||||||
if SiteSetting.tagging_enabled
|
if SiteSetting.tagging_enabled
|
||||||
result = result.preload(:tags)
|
result = result.preload(:tags)
|
||||||
|
|
||||||
if @options[:tags] && @options[:tags].size > 0
|
tags = @options[:tags]
|
||||||
@options[:tags] = @options[:tags].split unless @options[:tags].respond_to?('each')
|
|
||||||
@options[:tags].each { |t| t.downcase! if t.is_a? String }
|
if tags && tags.size > 0
|
||||||
|
tags = tags.split if String === tags
|
||||||
|
|
||||||
|
tags = tags.map do |t|
|
||||||
|
if String === t
|
||||||
|
t.downcase
|
||||||
|
else
|
||||||
|
t
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if @options[:match_all_tags]
|
if @options[:match_all_tags]
|
||||||
# ALL of the given tags:
|
# ALL of the given tags:
|
||||||
tags_count = @options[:tags].length
|
tags_count = tags.length
|
||||||
@options[:tags] = Tag.where_name(@options[:tags]).pluck(:id) unless @options[:tags][0].is_a?(Integer)
|
tags = Tag.where_name(tags).pluck(:id) unless Integer === tags[0]
|
||||||
|
|
||||||
if tags_count == @options[:tags].length
|
if tags_count == tags.length
|
||||||
@options[:tags].each_with_index do |tag, index|
|
tags.each_with_index do |tag, index|
|
||||||
sql_alias = ['t', index].join
|
sql_alias = ['t', index].join
|
||||||
result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
|
result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
|
||||||
end
|
end
|
||||||
|
@ -705,12 +714,17 @@ class TopicQuery
|
||||||
else
|
else
|
||||||
# ANY of the given tags:
|
# ANY of the given tags:
|
||||||
result = result.joins(:tags)
|
result = result.joins(:tags)
|
||||||
if @options[:tags][0].is_a?(Integer)
|
if Integer === tags[0]
|
||||||
result = result.where("tags.id in (?)", @options[:tags])
|
result = result.where("tags.id in (?)", tags)
|
||||||
else
|
else
|
||||||
result = result.where("lower(tags.name) in (?)", @options[:tags])
|
result = result.where("lower(tags.name) in (?)", tags)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: this is very side-effecty and should be changed
|
||||||
|
# It is done cause further up we expect normalized tags
|
||||||
|
@options[:tags] = tags
|
||||||
|
|
||||||
elsif @options[:no_tags]
|
elsif @options[:no_tags]
|
||||||
# the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags"))
|
# the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags"))
|
||||||
result = result.where.not(id: TopicTag.distinct.pluck(:topic_id))
|
result = result.where.not(id: TopicTag.distinct.pluck(:topic_id))
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module UserNameSuggester
|
module UserNameSuggester
|
||||||
GENERIC_NAMES = ['i', 'me', 'info', 'support', 'admin', 'webmaster', 'hello', 'mail', 'office', 'contact', 'team']
|
GENERIC_NAMES = ['i', 'me', 'info', 'support', 'admin', 'webmaster', 'hello', 'mail', 'office', 'contact', 'team']
|
||||||
|
|
||||||
|
@ -41,7 +43,7 @@ module UserNameSuggester
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.sanitize_username(name)
|
def self.sanitize_username(name)
|
||||||
name = name.to_s
|
name = name.to_s.dup
|
||||||
|
|
||||||
if SiteSetting.unicode_usernames
|
if SiteSetting.unicode_usernames
|
||||||
name.unicode_normalize!
|
name.unicode_normalize!
|
||||||
|
|
|
@ -1,15 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ReplyByEmailAddressValidator
|
class ReplyByEmailAddressValidator
|
||||||
def initialize(opts = {})
|
def initialize(opts = {})
|
||||||
@opts = opts
|
@opts = opts
|
||||||
end
|
end
|
||||||
|
|
||||||
def valid_value?(val)
|
def valid_value?(val)
|
||||||
val&.strip!
|
|
||||||
|
|
||||||
return true if val.blank?
|
return true if val.blank?
|
||||||
return false if !val.include?("@")
|
return false if !val.include?("@")
|
||||||
|
|
||||||
value = val.dup
|
value = val.dup
|
||||||
|
value.strip!
|
||||||
|
|
||||||
if SiteSetting.find_related_post_with_key
|
if SiteSetting.find_related_post_with_key
|
||||||
return false if !value.include?("%{reply_key}")
|
return false if !value.include?("%{reply_key}")
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Wizard
|
class Wizard
|
||||||
class StepUpdater
|
class StepUpdater
|
||||||
include ActiveModel::Model
|
include ActiveModel::Model
|
||||||
|
@ -29,7 +31,7 @@ class Wizard
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_setting(id, value)
|
def update_setting(id, value)
|
||||||
value.strip! if value.is_a?(String)
|
value = value.strip if value.is_a?(String)
|
||||||
|
|
||||||
if !value.is_a?(Upload) && SiteSetting.type_supervisor.get_type(id) == :upload
|
if !value.is_a?(Upload) && SiteSetting.type_supervisor.get_type(id) == :upload
|
||||||
value = Upload.get_from_url(value) || ''
|
value = Upload.get_from_url(value) || ''
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
require_dependency 'site_setting_extension'
|
require_dependency 'site_setting_extension'
|
||||||
require_dependency 'site_settings/local_process_provider'
|
require_dependency 'site_settings/local_process_provider'
|
||||||
|
@ -776,7 +778,7 @@ describe SiteSettingExtension do
|
||||||
describe "get_hostname" do
|
describe "get_hostname" do
|
||||||
|
|
||||||
it "properly extracts the hostname" do
|
it "properly extracts the hostname" do
|
||||||
expect(settings.send(:get_hostname, "discourse.org")).to eq("discourse.org")
|
# consider testing this through a public interface, this tests implementation details
|
||||||
expect(settings.send(:get_hostname, "discourse.org")).to eq("discourse.org")
|
expect(settings.send(:get_hostname, "discourse.org")).to eq("discourse.org")
|
||||||
expect(settings.send(:get_hostname, "@discourse.org")).to eq("discourse.org")
|
expect(settings.send(:get_hostname, "@discourse.org")).to eq("discourse.org")
|
||||||
expect(settings.send(:get_hostname, "https://discourse.org")).to eq("discourse.org")
|
expect(settings.send(:get_hostname, "https://discourse.org")).to eq("discourse.org")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user