DEV: Prefer \A and \z over ^ and $ in regexes (#19936)
This commit is contained in:
parent
f7907a3645
commit
666536cbd1
|
@ -238,11 +238,11 @@ class Admin::BackupsController < Admin::AdminController
|
|||
end
|
||||
|
||||
def valid_extension?(filename)
|
||||
/\.(tar\.gz|t?gz)$/i =~ filename
|
||||
/\.(tar\.gz|t?gz)\z/i =~ filename
|
||||
end
|
||||
|
||||
def valid_filename?(filename)
|
||||
!!(/^[a-zA-Z0-9\._\-]+$/ =~ filename)
|
||||
!!(/\A[a-zA-Z0-9\._\-]+\z/ =~ filename)
|
||||
end
|
||||
|
||||
def render_error(message_key)
|
||||
|
|
|
@ -7,9 +7,9 @@ class Admin::ReportsController < Admin::StaffController
|
|||
ApplicationRequest
|
||||
.req_types
|
||||
.keys
|
||||
.select { |r| r =~ /^page_view_/ && r !~ /mobile/ }
|
||||
.select { |r| r =~ /\Apage_view_/ && r !~ /mobile/ }
|
||||
.map { |r| r + "_reqs" } +
|
||||
Report.singleton_methods.grep(/^report_(?!about|storage_stats)/)
|
||||
Report.singleton_methods.grep(/\Areport_(?!about|storage_stats)/)
|
||||
|
||||
reports =
|
||||
reports_methods.map do |name|
|
||||
|
@ -61,7 +61,7 @@ class Admin::ReportsController < Admin::StaffController
|
|||
def show
|
||||
report_type = params[:type]
|
||||
|
||||
raise Discourse::NotFound unless report_type =~ /^[a-z0-9\_]+$/
|
||||
raise Discourse::NotFound unless report_type =~ /\A[a-z0-9\_]+\z/
|
||||
|
||||
args = parse_params(params)
|
||||
|
||||
|
|
|
@ -160,7 +160,7 @@ class Admin::SiteTextsController < Admin::AdminController
|
|||
{ id: key, value: value, locale: locale }
|
||||
end
|
||||
|
||||
PLURALIZED_REGEX = /(.*)\.(zero|one|two|few|many|other)$/
|
||||
PLURALIZED_REGEX = /(.*)\.(zero|one|two|few|many|other)\z/
|
||||
|
||||
def find_site_text(locale)
|
||||
if self.class.restricted_keys.include?(params[:id])
|
||||
|
|
|
@ -108,7 +108,7 @@ class Admin::ThemesController < Admin::AdminController
|
|||
render json: @theme, status: :created
|
||||
rescue RemoteTheme::ImportError => e
|
||||
if params[:force]
|
||||
theme_name = params[:remote].gsub(/.git$/, "").split("/").last
|
||||
theme_name = params[:remote].gsub(/.git\z/, "").split("/").last
|
||||
|
||||
remote_theme = RemoteTheme.new
|
||||
remote_theme.private_key = private_key
|
||||
|
|
|
@ -679,7 +679,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
DiscoursePluginRegistry.html_builders.each do |name, _|
|
||||
if name.start_with?("client:")
|
||||
data[name.sub(/^client:/, "")] = DiscoursePluginRegistry.build_html(name, self)
|
||||
data[name.sub(/\Aclient:/, "")] = DiscoursePluginRegistry.build_html(name, self)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -28,11 +28,11 @@ class EmbedController < ApplicationController
|
|||
end
|
||||
|
||||
if @embed_id = params[:discourse_embed_id]
|
||||
raise Discourse::InvalidParameters.new(:embed_id) unless @embed_id =~ /^de\-[a-zA-Z0-9]+$/
|
||||
raise Discourse::InvalidParameters.new(:embed_id) unless @embed_id =~ /\Ade\-[a-zA-Z0-9]+\z/
|
||||
end
|
||||
|
||||
if @embed_class = params[:embed_class]
|
||||
unless @embed_class =~ /^[a-zA-Z0-9\-_]+$/
|
||||
unless @embed_class =~ /\A[a-zA-Z0-9\-_]+\z/
|
||||
raise Discourse::InvalidParameters.new(:embed_class)
|
||||
end
|
||||
end
|
||||
|
@ -139,7 +139,7 @@ class EmbedController < ApplicationController
|
|||
by_url = {}
|
||||
|
||||
if embed_urls.present?
|
||||
urls = embed_urls.map { |u| u.sub(/#discourse-comments$/, "").sub(%r{/$}, "") }
|
||||
urls = embed_urls.map { |u| u.sub(/#discourse-comments\z/, "").sub(%r{/\z}, "") }
|
||||
topic_embeds = TopicEmbed.where(embed_url: urls).includes(:topic).references(:topic)
|
||||
|
||||
topic_embeds.each do |te|
|
||||
|
|
|
@ -71,6 +71,6 @@ class ExtraLocalesController < ApplicationController
|
|||
private
|
||||
|
||||
def valid_bundle?(bundle)
|
||||
bundle == OVERRIDES_BUNDLE || (bundle =~ /^(admin|wizard)$/ && current_user&.staff?)
|
||||
bundle == OVERRIDES_BUNDLE || (bundle =~ /\A(admin|wizard)\z/ && current_user&.staff?)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -203,7 +203,7 @@ class SessionController < ApplicationController
|
|||
end
|
||||
|
||||
# If it's not a relative URL check the host
|
||||
if return_path !~ %r{^/[^/]}
|
||||
if return_path !~ %r{\A/[^/]}
|
||||
begin
|
||||
uri = URI(return_path)
|
||||
if (uri.hostname == Discourse.current_hostname)
|
||||
|
|
|
@ -47,7 +47,7 @@ class ThemeJavascriptsController < ApplicationController
|
|||
|
||||
def show_tests
|
||||
digest = params[:digest]
|
||||
raise Discourse::NotFound if !digest.match?(/^\h{40}$/)
|
||||
raise Discourse::NotFound if !digest.match?(/\A\h{40}\z/)
|
||||
|
||||
theme = Theme.find_by(id: params[:theme_id])
|
||||
raise Discourse::NotFound if theme.blank?
|
||||
|
|
|
@ -83,7 +83,7 @@ class TopicsController < ApplicationController
|
|||
|
||||
# Special case: a slug with a number in front should look by slug first before looking
|
||||
# up that particular number
|
||||
if params[:id] && params[:id] =~ /^\d+[^\d\\]+$/
|
||||
if params[:id] && params[:id] =~ /\A\d+[^\d\\]+\z/
|
||||
topic = Topic.find_by_slug(params[:id])
|
||||
return redirect_to_correct_topic(topic, opts[:post_number]) if topic
|
||||
end
|
||||
|
|
|
@ -39,7 +39,7 @@ class UserAvatarsController < ApplicationController
|
|||
def show_proxy_letter
|
||||
is_asset_path
|
||||
|
||||
if SiteSetting.external_system_avatars_url !~ %r{^/letter_avatar_proxy}
|
||||
if SiteSetting.external_system_avatars_url !~ %r{\A/letter_avatar_proxy}
|
||||
raise Discourse::NotFound
|
||||
end
|
||||
|
||||
|
|
|
@ -473,7 +473,7 @@ class UsersController < ApplicationController
|
|||
end
|
||||
|
||||
def my_redirect
|
||||
raise Discourse::NotFound if params[:path] !~ %r{^[a-z_\-/]+$}
|
||||
raise Discourse::NotFound if params[:path] !~ %r{\A[a-z_\-/]+\z}
|
||||
|
||||
if current_user.blank?
|
||||
cookies[:destination_url] = path("/my/#{params[:path]}")
|
||||
|
|
|
@ -50,7 +50,7 @@ module ApplicationHelper
|
|||
|
||||
def google_universal_analytics_json(ua_domain_name = nil)
|
||||
result = {}
|
||||
result[:cookieDomain] = ua_domain_name.gsub(%r{^http(s)?://}, "") if ua_domain_name
|
||||
result[:cookieDomain] = ua_domain_name.gsub(%r{\Ahttp(s)?://}, "") if ua_domain_name
|
||||
result[:userId] = current_user.id if current_user.present?
|
||||
result[:allowLinker] = true if SiteSetting.ga_universal_auto_link_domains.present?
|
||||
result.to_json
|
||||
|
@ -117,9 +117,9 @@ module ApplicationHelper
|
|||
# seconds.
|
||||
if !script.start_with?("discourse/tests/")
|
||||
if is_brotli_req?
|
||||
path = path.gsub(/\.([^.]+)$/, '.br.\1')
|
||||
path = path.gsub(/\.([^.]+)\z/, '.br.\1')
|
||||
elsif is_gzip_req?
|
||||
path = path.gsub(/\.([^.]+)$/, '.gz.\1')
|
||||
path = path.gsub(/\.([^.]+)\z/, '.gz.\1')
|
||||
end
|
||||
end
|
||||
elsif GlobalSetting.cdn_url&.start_with?("https") && is_brotli_req? &&
|
||||
|
|
|
@ -20,8 +20,8 @@ module UserNotificationsHelper
|
|||
|
||||
def logo_url
|
||||
logo_url = SiteSetting.site_digest_logo_url
|
||||
logo_url = SiteSetting.site_logo_url if logo_url.blank? || logo_url =~ /\.svg$/i
|
||||
return nil if logo_url.blank? || logo_url =~ /\.svg$/i
|
||||
logo_url = SiteSetting.site_logo_url if logo_url.blank? || logo_url =~ /\.svg\z/i
|
||||
return nil if logo_url.blank? || logo_url =~ /\.svg\z/i
|
||||
logo_url
|
||||
end
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ module Jobs
|
|||
end
|
||||
|
||||
def self.num_email_retry_jobs
|
||||
Sidekiq::RetrySet.new.count { |job| job.klass =~ /Email$/ }
|
||||
Sidekiq::RetrySet.new.count { |job| job.klass =~ /Email\z/ }
|
||||
end
|
||||
|
||||
class Base
|
||||
|
|
|
@ -4,7 +4,7 @@ class Jobs::Onceoff < ::Jobs::Base
|
|||
sidekiq_options retry: false
|
||||
|
||||
def self.name_for(klass)
|
||||
klass.name.sub(/^Jobs\:\:/, "")
|
||||
klass.name.sub(/\AJobs\:\:/, "")
|
||||
end
|
||||
|
||||
def running_key_name
|
||||
|
|
|
@ -29,9 +29,9 @@ module Jobs
|
|||
@raw_quote_regex = /(\[quote\s*=\s*["'']?)#{@old_username}(\,?[^\]]*\])/i
|
||||
|
||||
cooked_username = PrettyText::Helpers.format_username(@old_username)
|
||||
@cooked_mention_username_regex = /^@#{cooked_username}$/i
|
||||
@cooked_mention_username_regex = /\A@#{cooked_username}\z/i
|
||||
@cooked_mention_user_path_regex =
|
||||
%r{^/u(?:sers)?/#{UrlHelper.encode_component(cooked_username)}$}i
|
||||
%r{\A/u(?:sers)?/#{UrlHelper.encode_component(cooked_username)}\z}i
|
||||
@cooked_quote_username_regex = /(?<=\s)#{cooked_username}(?=:)/i
|
||||
|
||||
update_posts
|
||||
|
|
|
@ -377,7 +377,7 @@ class AdminDashboardData
|
|||
end
|
||||
|
||||
def subfolder_ends_in_slash_check
|
||||
I18n.t("dashboard.subfolder_ends_in_slash") if Discourse.base_path =~ %r{/$}
|
||||
I18n.t("dashboard.subfolder_ends_in_slash") if Discourse.base_path =~ %r{/\z}
|
||||
end
|
||||
|
||||
def email_polling_errored_recently
|
||||
|
|
|
@ -421,7 +421,7 @@ class Category < ActiveRecord::Base
|
|||
end
|
||||
|
||||
# only allow to use category itself id.
|
||||
match_id = /^(\d+)-category/.match(self.slug)
|
||||
match_id = /\A(\d+)-category/.match(self.slug)
|
||||
if match_id.present?
|
||||
errors.add(:slug, :invalid) if new_record? || (match_id[1] != self.id.to_s)
|
||||
end
|
||||
|
@ -897,7 +897,7 @@ class Category < ActiveRecord::Base
|
|||
slug_path.inject(nil) do |parent_id, slug|
|
||||
category = Category.where(slug: slug, parent_category_id: parent_id)
|
||||
|
||||
if match_id = /^(\d+)-category/.match(slug).presence
|
||||
if match_id = /\A(\d+)-category/.match(slug).presence
|
||||
category = category.or(Category.where(id: match_id[1], parent_category_id: parent_id))
|
||||
end
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ module HasCustomFields
|
|||
|
||||
sorted_types = types.keys.select { |k| k.end_with?("*") }.sort_by(&:length).reverse
|
||||
|
||||
sorted_types.each { |t| return types[t] if key =~ /^#{t}/i }
|
||||
sorted_types.each { |t| return types[t] if key =~ /\A#{t}/i }
|
||||
|
||||
types[key]
|
||||
end
|
||||
|
|
|
@ -66,7 +66,7 @@ module Reports::TopUploads
|
|||
builder.where("up.created_at < :end_date", end_date: report.end_date)
|
||||
|
||||
if extension_filter
|
||||
builder.where("up.extension = :extension", extension: extension_filter.sub(/^\./, ""))
|
||||
builder.where("up.extension = :extension", extension: extension_filter.sub(/\A\./, ""))
|
||||
end
|
||||
|
||||
builder.query.each do |row|
|
||||
|
|
|
@ -6,8 +6,8 @@ class EmbeddableHost < ActiveRecord::Base
|
|||
after_destroy :reset_embedding_settings
|
||||
|
||||
before_validation do
|
||||
self.host.sub!(%r{^https?://}, "")
|
||||
self.host.sub!(%r{/.*$}, "")
|
||||
self.host.sub!(%r{\Ahttps?://}, "")
|
||||
self.host.sub!(%r{/.*\z}, "")
|
||||
end
|
||||
|
||||
# TODO(2021-07-23): Remove
|
||||
|
|
|
@ -173,7 +173,7 @@ class Emoji
|
|||
emojis.each do |name, url|
|
||||
result << Emoji.new.tap do |e|
|
||||
e.name = name
|
||||
url = (Discourse.base_path + url) if url[%r{^/[^/]}]
|
||||
url = (Discourse.base_path + url) if url[%r{\A/[^/]}]
|
||||
e.url = url
|
||||
e.group = group || DEFAULT_GROUP
|
||||
end
|
||||
|
|
|
@ -5,7 +5,7 @@ class GlobalSetting
|
|||
define_singleton_method(key) { provider.lookup(key, default) }
|
||||
end
|
||||
|
||||
VALID_SECRET_KEY ||= /^[0-9a-f]{128}$/
|
||||
VALID_SECRET_KEY ||= /\A[0-9a-f]{128}\z/
|
||||
# this is named SECRET_TOKEN as opposed to SECRET_KEY_BASE
|
||||
# for legacy reasons
|
||||
REDIS_SECRET_KEY ||= "SECRET_TOKEN"
|
||||
|
@ -251,7 +251,7 @@ class GlobalSetting
|
|||
class BaseProvider
|
||||
def self.coerce(setting)
|
||||
return setting == "true" if setting == "true" || setting == "false"
|
||||
return $1.to_i if setting.to_s.strip =~ /^([0-9]+)$/
|
||||
return $1.to_i if setting.to_s.strip =~ /\A([0-9]+)\z/
|
||||
setting
|
||||
end
|
||||
|
||||
|
@ -283,7 +283,7 @@ class GlobalSetting
|
|||
.result()
|
||||
.split("\n")
|
||||
.each do |line|
|
||||
if line =~ /^\s*([a-z_]+[a-z0-9_]*)\s*=\s*(\"([^\"]*)\"|\'([^\']*)\'|[^#]*)/
|
||||
if line =~ /\A\s*([a-z_]+[a-z0-9_]*)\s*=\s*(\"([^\"]*)\"|\'([^\']*)\'|[^#]*)/
|
||||
@data[$1.strip.to_sym] = ($4 || $3 || $2).strip
|
||||
end
|
||||
end
|
||||
|
@ -314,7 +314,7 @@ class GlobalSetting
|
|||
end
|
||||
|
||||
def keys
|
||||
ENV.keys.select { |k| k =~ /^DISCOURSE_/ }.map { |k| k[10..-1].downcase.to_sym }
|
||||
ENV.keys.select { |k| k =~ /\ADISCOURSE_/ }.map { |k| k[10..-1].downcase.to_sym }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1005,7 +1005,7 @@ class Group < ActiveRecord::Base
|
|||
user = email_username_user
|
||||
domain = email_username_domain
|
||||
if user.present? && domain.present?
|
||||
/^#{Regexp.escape(user)}(\+[^@]*)?@#{Regexp.escape(domain)}$/i
|
||||
/\A#{Regexp.escape(user)}(\+[^@]*)?@#{Regexp.escape(domain)}\z/i
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1160,8 +1160,8 @@ class Group < ActiveRecord::Base
|
|||
value
|
||||
.split("|")
|
||||
.each do |domain|
|
||||
domain.sub!(%r{^https?://}, "")
|
||||
domain.sub!(%r{/.*$}, "")
|
||||
domain.sub!(%r{\Ahttps?://}, "")
|
||||
domain.sub!(%r{/.*\z}, "")
|
||||
|
||||
if domain =~ Group::VALID_DOMAIN_REGEX
|
||||
valid_domains << domain
|
||||
|
|
|
@ -142,7 +142,7 @@ class OptimizedImage < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def local?
|
||||
!(url =~ %r{^(https?:)?//})
|
||||
!(url =~ %r{\A(https?:)?//})
|
||||
end
|
||||
|
||||
def calculate_filesize
|
||||
|
@ -337,7 +337,7 @@ class OptimizedImage < ActiveRecord::Base
|
|||
else
|
||||
error = +"Failed to optimize image:"
|
||||
|
||||
if e.message =~ /^convert:([^`]+)/
|
||||
if e.message =~ /\Aconvert:([^`]+)/
|
||||
error << $1
|
||||
else
|
||||
error << " unknown reason"
|
||||
|
|
|
@ -7,8 +7,8 @@ class PostActionType < ActiveRecord::Base
|
|||
include AnonCacheInvalidator
|
||||
|
||||
def expire_cache
|
||||
ApplicationSerializer.expire_cache_fragment!(/^post_action_types_/)
|
||||
ApplicationSerializer.expire_cache_fragment!(/^post_action_flag_types_/)
|
||||
ApplicationSerializer.expire_cache_fragment!(/\Apost_action_types_/)
|
||||
ApplicationSerializer.expire_cache_fragment!(/\Apost_action_flag_types_/)
|
||||
end
|
||||
|
||||
class << self
|
||||
|
|
|
@ -8,7 +8,7 @@ class PublishedPage < ActiveRecord::Base
|
|||
|
||||
validate :slug_format
|
||||
def slug_format
|
||||
if slug !~ /^[a-zA-Z\-\_0-9]+$/
|
||||
if slug !~ /\A[a-zA-Z\-\_0-9]+\z/
|
||||
errors.add(:slug, I18n.t("publish_page.slug_errors.invalid"))
|
||||
elsif %w[check-slug by-topic].include?(slug)
|
||||
errors.add(:slug, I18n.t("publish_page.slug_errors.unavailable"))
|
||||
|
|
|
@ -15,8 +15,8 @@ class RemoteTheme < ActiveRecord::Base
|
|||
|
||||
ALLOWED_FIELDS = %w[scss embedded_scss head_tag header after_header body_tag footer]
|
||||
|
||||
GITHUB_REGEXP = %r{^https?://github\.com/}
|
||||
GITHUB_SSH_REGEXP = %r{^ssh://git@github\.com:}
|
||||
GITHUB_REGEXP = %r{\Ahttps?://github\.com/}
|
||||
GITHUB_SSH_REGEXP = %r{\Assh://git@github\.com:}
|
||||
|
||||
has_one :theme, autosave: false
|
||||
scope :joined_remotes,
|
||||
|
@ -329,7 +329,7 @@ class RemoteTheme < ActiveRecord::Base
|
|||
|
||||
def github_diff_link
|
||||
if github_repo_url.present? && local_version != remote_version
|
||||
"#{github_repo_url.gsub(/\.git$/, "")}/compare/#{local_version}...#{remote_version}"
|
||||
"#{github_repo_url.gsub(/\.git\z/, "")}/compare/#{local_version}...#{remote_version}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -268,8 +268,8 @@ class Report
|
|||
wrap_slow_query do
|
||||
if respond_to?(report_method)
|
||||
public_send(report_method, report)
|
||||
elsif type =~ /_reqs$/
|
||||
req_report(report, type.split(/_reqs$/)[0].to_sym)
|
||||
elsif type =~ /_reqs\z/
|
||||
req_report(report, type.split(/_reqs\z/)[0].to_sym)
|
||||
else
|
||||
return nil
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ class Reviewable < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.valid_type?(type)
|
||||
return false unless type =~ /^Reviewable[A-Za-z]+$/
|
||||
return false unless type =~ /\AReviewable[A-Za-z]+\z/
|
||||
type.constantize <= Reviewable
|
||||
rescue NameError
|
||||
false
|
||||
|
|
|
@ -17,7 +17,7 @@ class ScreenedUrl < ActiveRecord::Base
|
|||
|
||||
def normalize
|
||||
self.url = ScreenedUrl.normalize_url(self.url) if self.url
|
||||
self.domain = self.domain.downcase.sub(/^www\./, "") if self.domain
|
||||
self.domain = self.domain.downcase.sub(/\Awww\./, "") if self.domain
|
||||
end
|
||||
|
||||
def self.watch(url, domain, opts = {})
|
||||
|
@ -30,8 +30,8 @@ class ScreenedUrl < ActiveRecord::Base
|
|||
|
||||
def self.normalize_url(url)
|
||||
normalized = url.gsub(%r{http(s?)://}i, "")
|
||||
normalized.gsub!(%r{(/)+$}, "") # trim trailing slashes
|
||||
normalized.gsub!(%r{^([^/]+)(?:/)?}) { |m| m.downcase } # downcase the domain part of the url
|
||||
normalized.gsub!(%r{(/)+\z}, "") # trim trailing slashes
|
||||
normalized.gsub!(%r{\A([^/]+)(?:/)?}) { |m| m.downcase } # downcase the domain part of the url
|
||||
normalized
|
||||
end
|
||||
end
|
||||
|
|
|
@ -94,7 +94,7 @@ class ThemeField < ActiveRecord::Base
|
|||
.css('script[type="text/x-handlebars"]')
|
||||
.each do |node|
|
||||
name = node["name"] || node["data-template-name"] || "broken"
|
||||
is_raw = name =~ /\.(raw|hbr)$/
|
||||
is_raw = name =~ /\.(raw|hbr)\z/
|
||||
hbs_template = node.inner_html
|
||||
|
||||
begin
|
||||
|
@ -523,63 +523,63 @@ class ThemeField < ActiveRecord::Base
|
|||
FILE_MATCHERS = [
|
||||
ThemeFileMatcher.new(
|
||||
regex:
|
||||
%r{^(?<target>(?:mobile|desktop|common))/(?<name>(?:head_tag|header|after_header|body_tag|footer))\.html$},
|
||||
%r{\A(?<target>(?:mobile|desktop|common))/(?<name>(?:head_tag|header|after_header|body_tag|footer))\.html\z},
|
||||
targets: %i[mobile desktop common],
|
||||
names: %w[head_tag header after_header body_tag footer],
|
||||
types: :html,
|
||||
canonical: ->(h) { "#{h[:target]}/#{h[:name]}.html" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^(?<target>(?:mobile|desktop|common))/(?:\k<target>)\.scss$},
|
||||
regex: %r{\A(?<target>(?:mobile|desktop|common))/(?:\k<target>)\.scss\z},
|
||||
targets: %i[mobile desktop common],
|
||||
names: "scss",
|
||||
types: :scss,
|
||||
canonical: ->(h) { "#{h[:target]}/#{h[:target]}.scss" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^common/embedded\.scss$},
|
||||
regex: %r{\Acommon/embedded\.scss\z},
|
||||
targets: :common,
|
||||
names: "embedded_scss",
|
||||
types: :scss,
|
||||
canonical: ->(h) { "common/embedded.scss" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^common/color_definitions\.scss$},
|
||||
regex: %r{\Acommon/color_definitions\.scss\z},
|
||||
targets: :common,
|
||||
names: "color_definitions",
|
||||
types: :scss,
|
||||
canonical: ->(h) { "common/color_definitions.scss" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^(?:scss|stylesheets)/(?<name>.+)\.scss$},
|
||||
regex: %r{\A(?:scss|stylesheets)/(?<name>.+)\.scss\z},
|
||||
targets: :extra_scss,
|
||||
names: nil,
|
||||
types: :scss,
|
||||
canonical: ->(h) { "stylesheets/#{h[:name]}.scss" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^javascripts/(?<name>.+)$},
|
||||
regex: %r{\Ajavascripts/(?<name>.+)\z},
|
||||
targets: :extra_js,
|
||||
names: nil,
|
||||
types: :js,
|
||||
canonical: ->(h) { "javascripts/#{h[:name]}" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^test/(?<name>.+)$},
|
||||
regex: %r{\Atest/(?<name>.+)\z},
|
||||
targets: :tests_js,
|
||||
names: nil,
|
||||
types: :js,
|
||||
canonical: ->(h) { "test/#{h[:name]}" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: /^settings\.ya?ml$/,
|
||||
regex: /\Asettings\.ya?ml\z/,
|
||||
names: "yaml",
|
||||
types: :yaml,
|
||||
targets: :settings,
|
||||
canonical: ->(h) { "settings.yml" },
|
||||
),
|
||||
ThemeFileMatcher.new(
|
||||
regex: %r{^locales/(?<name>(?:#{I18n.available_locales.join("|")}))\.yml$},
|
||||
regex: %r{\Alocales/(?<name>(?:#{I18n.available_locales.join("|")}))\.yml\z},
|
||||
names: I18n.available_locales.map(&:to_s),
|
||||
types: :yaml,
|
||||
targets: :translations,
|
||||
|
|
|
@ -1200,7 +1200,7 @@ class Topic < ActiveRecord::Base
|
|||
else
|
||||
!!invite_to_topic(invited_by, target_user, group_ids, guardian)
|
||||
end
|
||||
elsif username_or_email =~ /^.+@.+$/ && guardian.can_invite_via_email?(self)
|
||||
elsif username_or_email =~ /\A.+@.+\z/ && guardian.can_invite_via_email?(self)
|
||||
!!Invite.generate(
|
||||
invited_by,
|
||||
email: username_or_email,
|
||||
|
|
|
@ -25,7 +25,7 @@ class TopicEmbed < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.normalize_url(url)
|
||||
url.downcase.sub(%r{/$}, "").sub(/\-+/, "-").strip
|
||||
url.downcase.sub(%r{/\z}, "").sub(/\-+/, "-").strip
|
||||
end
|
||||
|
||||
def self.imported_from_html(url)
|
||||
|
@ -36,7 +36,7 @@ class TopicEmbed < ActiveRecord::Base
|
|||
|
||||
# Import an article from a source (RSS/Atom/Other)
|
||||
def self.import(user, url, title, contents, category_id: nil, cook_method: nil, tags: nil)
|
||||
return unless url =~ %r{^https?\://}
|
||||
return unless url =~ %r{\Ahttps?\://}
|
||||
|
||||
contents = first_paragraph_from(contents) if SiteSetting.embed_truncate && cook_method.nil?
|
||||
contents ||= ""
|
||||
|
@ -253,7 +253,7 @@ class TopicEmbed < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.topic_id_for_embed(embed_url)
|
||||
embed_url = normalize_url(embed_url).sub(%r{^https?\://}, "")
|
||||
embed_url = normalize_url(embed_url).sub(%r{\Ahttps?\://}, "")
|
||||
TopicEmbed.where("embed_url ~* ?", "^https?://#{Regexp.escape(embed_url)}$").pluck_first(
|
||||
:topic_id,
|
||||
)
|
||||
|
|
|
@ -175,7 +175,7 @@ class TopicLink < ActiveRecord::Base
|
|||
|
||||
lookup = {}
|
||||
results.each do |tl|
|
||||
normalized = tl.url.downcase.sub(%r{^https?://}, "").sub(%r{/$}, "")
|
||||
normalized = tl.url.downcase.sub(%r{\Ahttps?://}, "").sub(%r{/\z}, "")
|
||||
lookup[normalized] = {
|
||||
domain: tl.domain,
|
||||
username: tl.user.username_lower,
|
||||
|
|
|
@ -21,9 +21,9 @@ class TopicLinkClick < ActiveRecord::Base
|
|||
uri = UrlHelper.relaxed_parse(url)
|
||||
urls = Set.new
|
||||
urls << url
|
||||
if url =~ /^http/
|
||||
urls << url.sub(/^https/, "http")
|
||||
urls << url.sub(/^http:/, "https:")
|
||||
if url =~ /\Ahttp/
|
||||
urls << url.sub(/\Ahttps/, "http")
|
||||
urls << url.sub(/\Ahttp:/, "https:")
|
||||
urls << UrlHelper.schemaless(url)
|
||||
end
|
||||
urls << UrlHelper.absolute_without_cdn(url)
|
||||
|
@ -90,7 +90,7 @@ class TopicLinkClick < ActiveRecord::Base
|
|||
# If no link is found...
|
||||
unless link.present?
|
||||
# ... return the url for relative links or when using the same host
|
||||
return url if url =~ %r{^/[^/]} || uri.try(:host) == Discourse.current_hostname
|
||||
return url if url =~ %r{\A/[^/]} || uri.try(:host) == Discourse.current_hostname
|
||||
|
||||
# If we have it somewhere else on the site, just allow the redirect.
|
||||
# This is likely due to a onebox of another topic.
|
||||
|
|
|
@ -147,7 +147,7 @@ class TranslationOverride < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def transform_pluralized_key(key)
|
||||
match = key.match(/(.*)\.(zero|two|few|many)$/)
|
||||
match = key.match(/(.*)\.(zero|two|few|many)\z/)
|
||||
match ? match.to_a.second + ".other" : key
|
||||
end
|
||||
end
|
||||
|
|
|
@ -263,7 +263,7 @@ class Upload < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def local?
|
||||
!(url =~ %r{^(https?:)?//})
|
||||
!(url =~ %r{\A(https?:)?//})
|
||||
end
|
||||
|
||||
def fix_dimensions!
|
||||
|
@ -526,7 +526,7 @@ class Upload < ActiveRecord::Base
|
|||
# keep track of the url
|
||||
previous_url = upload.url.dup
|
||||
# where is the file currently stored?
|
||||
external = previous_url =~ %r{^//}
|
||||
external = previous_url =~ %r{\A//}
|
||||
# download if external
|
||||
if external
|
||||
url = SiteSetting.scheme + ":" + previous_url
|
||||
|
|
|
@ -396,7 +396,7 @@ class User < ActiveRecord::Base
|
|||
.reserved_usernames
|
||||
.unicode_normalize
|
||||
.split("|")
|
||||
.any? { |reserved| username.match?(/^#{Regexp.escape(reserved).gsub('\*', ".*")}$/) }
|
||||
.any? { |reserved| username.match?(/\A#{Regexp.escape(reserved).gsub('\*', ".*")}\z/) }
|
||||
end
|
||||
|
||||
def self.editable_user_custom_fields(by_staff: false)
|
||||
|
@ -1117,7 +1117,7 @@ class User < ActiveRecord::Base
|
|||
# TODO it may be worth caching this in a distributed cache, should be benched
|
||||
if SiteSetting.external_system_avatars_enabled
|
||||
url = SiteSetting.external_system_avatars_url.dup
|
||||
url = +"#{Discourse.base_path}#{url}" unless url =~ %r{^https?://}
|
||||
url = +"#{Discourse.base_path}#{url}" unless url =~ %r{\Ahttps?://}
|
||||
url.gsub! "{color}", letter_avatar_color(normalized_username)
|
||||
url.gsub! "{username}", UrlHelper.encode_component(username)
|
||||
url.gsub! "{first_letter}",
|
||||
|
|
|
@ -45,7 +45,7 @@ class UserProfile < ActiveRecord::Base
|
|||
|
||||
def bio_excerpt(length = 350, opts = {})
|
||||
return nil if bio_cooked.blank?
|
||||
excerpt = PrettyText.excerpt(bio_cooked, length, opts).sub(/<br>$/, "")
|
||||
excerpt = PrettyText.excerpt(bio_cooked, length, opts).sub(/<br>\z/, "")
|
||||
return excerpt if excerpt.blank? || (user.has_trust_level?(TrustLevel[1]) && !user.suspended?)
|
||||
PrettyText.strip_links(excerpt)
|
||||
end
|
||||
|
|
|
@ -40,13 +40,13 @@ class UsernameValidator
|
|||
errors.empty?
|
||||
end
|
||||
|
||||
CONFUSING_EXTENSIONS ||= /\.(js|json|css|htm|html|xml|jpg|jpeg|png|gif|bmp|ico|tif|tiff|woff)$/i
|
||||
CONFUSING_EXTENSIONS ||= /\.(js|json|css|htm|html|xml|jpg|jpeg|png|gif|bmp|ico|tif|tiff|woff)\z/i
|
||||
MAX_CHARS ||= 60
|
||||
|
||||
ASCII_INVALID_CHAR_PATTERN ||= /[^\w.-]/
|
||||
UNICODE_INVALID_CHAR_PATTERN ||= /[^\p{Alnum}\p{M}._-]/
|
||||
INVALID_LEADING_CHAR_PATTERN ||= /^[^\p{Alnum}\p{M}_]+/
|
||||
INVALID_TRAILING_CHAR_PATTERN ||= /[^\p{Alnum}\p{M}]+$/
|
||||
INVALID_LEADING_CHAR_PATTERN ||= /\A[^\p{Alnum}\p{M}_]+/
|
||||
INVALID_TRAILING_CHAR_PATTERN ||= /[^\p{Alnum}\p{M}]+\z/
|
||||
REPEATED_SPECIAL_CHAR_PATTERN ||= /[-_.]{2,}/
|
||||
|
||||
private
|
||||
|
|
|
@ -19,7 +19,7 @@ class WatchedWord < ActiveRecord::Base
|
|||
|
||||
before_validation do
|
||||
self.word = self.class.normalize_word(self.word)
|
||||
if self.action == WatchedWord.actions[:link] && !(self.replacement =~ %r{^https?://})
|
||||
if self.action == WatchedWord.actions[:link] && !(self.replacement =~ %r{\Ahttps?://})
|
||||
self.replacement =
|
||||
"#{Discourse.base_url}#{self.replacement&.starts_with?("/") ? "" : "/"}#{self.replacement}"
|
||||
end
|
||||
|
|
|
@ -113,7 +113,7 @@ class UserCardSerializer < BasicUserSerializer
|
|||
end
|
||||
|
||||
return if uri.nil? || uri.host.nil?
|
||||
uri.host.sub(/^www\./, "") + uri.path
|
||||
uri.host.sub(/\Awww\./, "") + uri.path
|
||||
end
|
||||
|
||||
def ignored
|
||||
|
|
|
@ -50,7 +50,7 @@ class SearchIndexer
|
|||
.reduce(additional_lexemes) do |array, (lexeme, _, positions)|
|
||||
count = 0
|
||||
|
||||
if lexeme !~ /^(\d+\.)?(\d+\.)*(\*|\d+)$/
|
||||
if lexeme !~ /\A(\d+\.)?(\d+\.)*(\*|\d+)\z/
|
||||
loop do
|
||||
count += 1
|
||||
break if count >= 10 # Safeguard here to prevent infinite loop when a term has many dots
|
||||
|
|
|
@ -347,6 +347,6 @@ class UserUpdater
|
|||
|
||||
def format_url(website)
|
||||
return nil if website.blank?
|
||||
website =~ /^http/ ? website : "http://#{website}"
|
||||
website =~ /\Ahttp/ ? website : "http://#{website}"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -50,7 +50,7 @@ class AdminUserIndexQuery
|
|||
|
||||
custom_order = params[:order]
|
||||
if custom_order.present? &&
|
||||
without_dir = SORTABLE_MAPPING[custom_order.downcase.sub(/ (asc|desc)$/, "")]
|
||||
without_dir = SORTABLE_MAPPING[custom_order.downcase.sub(/ (asc|desc)\z/, "")]
|
||||
order << "#{without_dir} #{custom_direction}"
|
||||
end
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ class Autospec::Manager
|
|||
filename, _ = failed_specs[0].split(":")
|
||||
if filename && File.exist?(filename) && !File.directory?(filename)
|
||||
spec = File.read(filename)
|
||||
start, _ = spec.split(/\S*#focus\S*$/)
|
||||
start, _ = spec.split(/\S*#focus\S*\z/)
|
||||
if start.length < spec.length
|
||||
line = start.scan(/\n/).length + 1
|
||||
puts "Found #focus tag on line #{line}!"
|
||||
|
@ -194,7 +194,7 @@ class Autospec::Manager
|
|||
def listen_for_changes
|
||||
puts "@@@@@@@@@@@@ listen_for_changes" if @debug
|
||||
|
||||
options = { ignore: %r{^lib/autospec} }
|
||||
options = { ignore: %r{\Alib/autospec} }
|
||||
|
||||
if @opts[:force_polling]
|
||||
options[:force_polling] = true
|
||||
|
@ -216,7 +216,7 @@ class Autospec::Manager
|
|||
# process_change can acquire a mutex and block
|
||||
# the acceptor
|
||||
Thread.new do
|
||||
if file =~ /(es6|js)$/
|
||||
if file =~ /(es6|js)\z/
|
||||
process_change([[file]])
|
||||
else
|
||||
process_change([[file, line]])
|
||||
|
|
|
@ -10,11 +10,11 @@ class Autospec::ReloadCss
|
|||
end
|
||||
|
||||
# css, scss, sass or handlebars
|
||||
watch(/\.css$/)
|
||||
watch(/\.ca?ss\.erb$/)
|
||||
watch(/\.s[ac]ss$/)
|
||||
watch(/\.hbs$/)
|
||||
watch(/\.hbr$/)
|
||||
watch(/\.css\z/)
|
||||
watch(/\.ca?ss\.erb\z/)
|
||||
watch(/\.s[ac]ss\z/)
|
||||
watch(/\.hbs\z/)
|
||||
watch(/\.hbr\z/)
|
||||
|
||||
def self.message_bus
|
||||
MessageBus::Instance.new.tap do |bus|
|
||||
|
@ -44,7 +44,7 @@ class Autospec::ReloadCss
|
|||
p = p.sub(/\.sass\.erb/, "")
|
||||
p = p.sub(/\.sass/, "")
|
||||
p = p.sub(/\.scss/, "")
|
||||
p = p.sub(%r{^app/assets/stylesheets}, "assets")
|
||||
p = p.sub(%r{\Aapp/assets/stylesheets}, "assets")
|
||||
{ name: p, hash: hash || SecureRandom.hex }
|
||||
end
|
||||
message_bus.publish "/file-change", paths
|
||||
|
|
|
@ -11,29 +11,31 @@ module Autospec
|
|||
end
|
||||
|
||||
# Discourse specific
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/components/#{m[1]}_spec.rb" }
|
||||
watch(%r{\Alib/(.+)\.rb\z}) { |m| "spec/components/#{m[1]}_spec.rb" }
|
||||
|
||||
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/(.+)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^spec/support/.+\.rb$}) { "spec" }
|
||||
watch(%r{\Aapp/(.+)\.rb\z}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(%r{\Aapp/(.+)(\.erb|\.haml)\z}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
||||
watch(%r{\Aspec/.+_spec\.rb\z})
|
||||
watch(%r{\Aspec/support/.+\.rb\z}) { "spec" }
|
||||
watch("app/controllers/application_controller.rb") { "spec/requests" }
|
||||
|
||||
watch(%r{app/controllers/(.+).rb}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
||||
|
||||
watch(%r{^app/views/(.+)/.+\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
||||
watch(%r{\Aapp/views/(.+)/.+\.(erb|haml)\z}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
||||
|
||||
watch(%r{^spec/fabricators/.+_fabricator\.rb$}) { "spec" }
|
||||
watch(%r{\Aspec/fabricators/.+_fabricator\.rb\z}) { "spec" }
|
||||
|
||||
watch(%r{^app/assets/javascripts/pretty-text/.*\.js\.es6$}) do
|
||||
watch(%r{\Aapp/assets/javascripts/pretty-text/.*\.js\.es6\z}) do
|
||||
"spec/components/pretty_text_spec.rb"
|
||||
end
|
||||
watch(%r{\Aplugins/.*/discourse-markdown/.*\.js\.es6\z}) do
|
||||
"spec/components/pretty_text_spec.rb"
|
||||
end
|
||||
watch(%r{^plugins/.*/discourse-markdown/.*\.js\.es6$}) { "spec/components/pretty_text_spec.rb" }
|
||||
|
||||
watch(%r{^plugins/.*/spec/.*\.rb})
|
||||
watch(%r{^(plugins/.*/)plugin\.rb}) { |m| "#{m[1]}spec" }
|
||||
watch(%r{^(plugins/.*)/(lib|app)}) { |m| "#{m[1]}/spec/integration" }
|
||||
watch(%r{^(plugins/.*)/lib/(.*)\.rb}) { |m| "#{m[1]}/spec/lib/#{m[2]}_spec.rb" }
|
||||
watch(%r{\Aplugins/.*/spec/.*\.rb})
|
||||
watch(%r{\A(plugins/.*/)plugin\.rb}) { |m| "#{m[1]}spec" }
|
||||
watch(%r{\A(plugins/.*)/(lib|app)}) { |m| "#{m[1]}/spec/integration" }
|
||||
watch(%r{\A(plugins/.*)/lib/(.*)\.rb}) { |m| "#{m[1]}/spec/lib/#{m[2]}_spec.rb" }
|
||||
|
||||
RELOADERS = Set.new
|
||||
def self.reload(pattern)
|
||||
|
|
|
@ -29,7 +29,7 @@ module Autospec
|
|||
# launch rspec
|
||||
Dir.chdir(Rails.root) do # rubocop:disable Discourse/NoChdir because this is not part of the app
|
||||
env = { "RAILS_ENV" => "test" }
|
||||
if specs.split(" ").any? { |s| s =~ %r{^(./)?plugins} }
|
||||
if specs.split(" ").any? { |s| s =~ %r{\A(./)?plugins} }
|
||||
env["LOAD_PLUGINS"] = "1"
|
||||
puts "Loading plugins while running specs"
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ module BackupRestore
|
|||
@filename = filename
|
||||
@current_db = current_db
|
||||
@root_tmp_directory = root_tmp_directory
|
||||
@is_archive = !(@filename =~ /\.sql\.gz$/)
|
||||
@is_archive = !(@filename =~ /\.sql\.gz\z/)
|
||||
@store_location = location
|
||||
end
|
||||
|
||||
|
|
|
@ -164,7 +164,7 @@ module BackupRestore
|
|||
|
||||
DatabaseRestorer.core_migration_files.each do |path|
|
||||
require path
|
||||
class_name = File.basename(path, ".rb").sub(/^\d+_/, "").camelize
|
||||
class_name = File.basename(path, ".rb").sub(/\A\d+_/, "").camelize
|
||||
migration_class = class_name.constantize
|
||||
|
||||
if migration_class.const_defined?(:DROPPED_TABLES)
|
||||
|
|
|
@ -173,7 +173,7 @@ module BackupRestore
|
|||
path = Regexp.quote(path)
|
||||
end
|
||||
|
||||
%r{^#{path}[^/]*\.t?gz$}i
|
||||
%r{\A#{path}[^/]*\.t?gz\z}i
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ class ComposerMessagesFinder
|
|||
end
|
||||
|
||||
def self.check_methods
|
||||
@check_methods ||= instance_methods.find_all { |m| m =~ /^check\_/ }
|
||||
@check_methods ||= instance_methods.find_all { |m| m =~ /\Acheck\_/ }
|
||||
end
|
||||
|
||||
def find
|
||||
|
|
|
@ -38,7 +38,7 @@ module Compression
|
|||
|
||||
def build_entry_path(dest_path, _, compressed_file_path)
|
||||
basename = File.basename(compressed_file_path)
|
||||
basename.gsub!(/#{Regexp.escape(extension)}$/, "")
|
||||
basename.gsub!(/#{Regexp.escape(extension)}\z/, "")
|
||||
File.join(dest_path, basename)
|
||||
end
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ class ContentSecurityPolicy
|
|||
|
||||
uri.query = nil # CSP should not include query part of url
|
||||
|
||||
uri_string = uri.to_s.sub(%r{^//}, "") # Protocol-less CSP should not have // at beginning of URL
|
||||
uri_string = uri.to_s.sub(%r{\A//}, "") # Protocol-less CSP should not have // at beginning of URL
|
||||
|
||||
auto_script_src_extension[:script_src] << uri_string
|
||||
rescue URI::Error
|
||||
|
|
|
@ -242,10 +242,10 @@ class CookedPostProcessor
|
|||
|
||||
if !cropped && upload.width && resized_w > upload.width
|
||||
cooked_url = UrlHelper.cook_url(upload.url, secure: @post.with_secure_uploads?)
|
||||
srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0$/, "")}x"
|
||||
srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0\z/, "")}x"
|
||||
elsif t = upload.thumbnail(resized_w, resized_h)
|
||||
cooked_url = UrlHelper.cook_url(t.url, secure: @post.with_secure_uploads?)
|
||||
srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0$/, "")}x"
|
||||
srcset << ", #{cooked_url} #{ratio.to_s.sub(/\.0\z/, "")}x"
|
||||
end
|
||||
|
||||
img[
|
||||
|
@ -295,7 +295,7 @@ class CookedPostProcessor
|
|||
|
||||
def get_filename(upload, src)
|
||||
return File.basename(src) unless upload
|
||||
return upload.original_filename unless upload.original_filename =~ /^blob(\.png)?$/i
|
||||
return upload.original_filename unless upload.original_filename =~ /\Ablob(\.png)?\z/i
|
||||
I18n.t("upload.pasted_image_filename")
|
||||
end
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ module CookedProcessorMixin
|
|||
return @size_cache[url] if @size_cache.has_key?(url)
|
||||
|
||||
absolute_url = url
|
||||
absolute_url = Discourse.base_url_no_prefix + absolute_url if absolute_url =~ %r{^/[^/]}
|
||||
absolute_url = Discourse.base_url_no_prefix + absolute_url if absolute_url =~ %r{\A/[^/]}
|
||||
|
||||
return unless absolute_url
|
||||
|
||||
|
|
|
@ -99,7 +99,7 @@ class DiscourseConnectBase
|
|||
end
|
||||
|
||||
decoded_hash.each do |k, v|
|
||||
if field = k[/^custom\.(.+)$/, 1]
|
||||
if field = k[/\Acustom\.(.+)\z/, 1]
|
||||
sso.custom_fields[field] = v
|
||||
end
|
||||
end
|
||||
|
|
|
@ -160,7 +160,7 @@ class DiscourseDiff
|
|||
while i < text.size
|
||||
if text[i] =~ /\w/
|
||||
t << text[i]
|
||||
elsif text[i] =~ /[ \t]/ && t.join =~ /^\w+$/
|
||||
elsif text[i] =~ /[ \t]/ && t.join =~ /\A\w+\z/
|
||||
begin
|
||||
t << text[i]
|
||||
i += 1
|
||||
|
|
|
@ -158,8 +158,8 @@ class DiscoursePluginRegistry
|
|||
end
|
||||
end
|
||||
|
||||
JS_REGEX = /\.js$|\.js\.erb$|\.js\.es6$/
|
||||
HANDLEBARS_REGEX = /\.(hb[rs]|js\.handlebars)$/
|
||||
JS_REGEX = /\.js$|\.js\.erb$|\.js\.es6\z/
|
||||
HANDLEBARS_REGEX = /\.(hb[rs]|js\.handlebars)\z/
|
||||
|
||||
def self.register_asset(asset, opts = nil, plugin_directory_name = nil)
|
||||
if asset =~ JS_REGEX
|
||||
|
@ -172,7 +172,7 @@ class DiscoursePluginRegistry
|
|||
else
|
||||
self.javascripts << asset
|
||||
end
|
||||
elsif asset =~ /\.css$|\.scss$/
|
||||
elsif asset =~ /\.css$|\.scss\z/
|
||||
if opts == :mobile
|
||||
self.mobile_stylesheets[plugin_directory_name] ||= Set.new
|
||||
self.mobile_stylesheets[plugin_directory_name] << asset
|
||||
|
|
|
@ -276,7 +276,7 @@ class DiscourseRedis
|
|||
def eval(redis, *args, **kwargs)
|
||||
redis.evalsha @sha1, *args, **kwargs
|
||||
rescue ::Redis::CommandError => e
|
||||
if e.to_s =~ /^NOSCRIPT/
|
||||
if e.to_s =~ /\ANOSCRIPT/
|
||||
redis.eval @script, *args, **kwargs
|
||||
else
|
||||
raise
|
||||
|
|
|
@ -136,7 +136,7 @@ module Email
|
|||
|
||||
def message_id_clean(message_id)
|
||||
if message_id.present? && is_message_id_rfc?(message_id)
|
||||
message_id.gsub(/^<|>$/, "")
|
||||
message_id.gsub(/\A<|>\z/, "")
|
||||
else
|
||||
message_id
|
||||
end
|
||||
|
|
|
@ -381,7 +381,7 @@ module Email
|
|||
@mail[:precedence].to_s[/list|junk|bulk|auto_reply/i] ||
|
||||
@mail[:from].to_s[/(mailer[\-_]?daemon|post[\-_]?master|no[\-_]?reply)@/i] ||
|
||||
@mail[:subject].to_s[
|
||||
/^\s*(Auto:|Automatic reply|Autosvar|Automatisk svar|Automatisch antwoord|Abwesenheitsnotiz|Risposta Non al computer|Automatisch antwoord|Auto Response|Respuesta automática|Fuori sede|Out of Office|Frånvaro|Réponse automatique)/i
|
||||
/\A\s*(Auto:|Automatic reply|Autosvar|Automatisk svar|Automatisch antwoord|Abwesenheitsnotiz|Risposta Non al computer|Automatisch antwoord|Auto Response|Respuesta automática|Fuori sede|Out of Office|Frånvaro|Réponse automatique)/i
|
||||
] ||
|
||||
@mail.header.to_s[
|
||||
/auto[\-_]?(response|submitted|replied|reply|generated|respond)|holidayreply|machinegenerated/i
|
||||
|
@ -393,7 +393,7 @@ module Email
|
|||
when "X-Spam-Flag"
|
||||
@mail[:x_spam_flag].to_s[/YES/i]
|
||||
when "X-Spam-Status"
|
||||
@mail[:x_spam_status].to_s[/^Yes, /i]
|
||||
@mail[:x_spam_status].to_s[/\AYes, /i]
|
||||
when "X-SES-Spam-Verdict"
|
||||
@mail[:x_ses_spam_verdict].to_s[/FAIL/i]
|
||||
else
|
||||
|
@ -639,7 +639,7 @@ module Email
|
|||
.uniq
|
||||
|
||||
@previous_replies_regex ||=
|
||||
/^--[- ]\n\*(?:#{strings.map { |x| Regexp.escape(x) }.join("|")})\*\n/im
|
||||
/\A--[- ]\n\*(?:#{strings.map { |x| Regexp.escape(x) }.join("|")})\*\n/im
|
||||
end
|
||||
|
||||
def reply_above_line_regex
|
||||
|
@ -747,12 +747,12 @@ module Email
|
|||
|
||||
if value[/<[^>]+>/]
|
||||
from_address = value[/<([^>]+)>/, 1]
|
||||
from_display_name = value[/^([^<]+)/, 1]
|
||||
from_display_name = value[/\A([^<]+)/, 1]
|
||||
end
|
||||
|
||||
if (from_address.blank? || !from_address["@"]) && value[/\[mailto:[^\]]+\]/]
|
||||
from_address = value[/\[mailto:([^\]]+)\]/, 1]
|
||||
from_display_name = value[/^([^\[]+)/, 1]
|
||||
from_display_name = value[/\A([^\[]+)/, 1]
|
||||
end
|
||||
|
||||
[from_address&.downcase, from_display_name&.strip]
|
||||
|
@ -1016,7 +1016,7 @@ module Email
|
|||
end
|
||||
|
||||
def has_been_forwarded?
|
||||
subject[/^[[:blank:]]*(fwd?|tr)[[:blank:]]?:/i] && embedded_email_raw.present?
|
||||
subject[/\A[[:blank:]]*(fwd?|tr)[[:blank:]]?:/i] && embedded_email_raw.present?
|
||||
end
|
||||
|
||||
def embedded_email_raw
|
||||
|
|
|
@ -84,9 +84,9 @@ module Email
|
|||
|
||||
if img["src"]
|
||||
# ensure all urls are absolute
|
||||
img["src"] = "#{Discourse.base_url}#{img["src"]}" if img["src"][%r{^/[^/]}]
|
||||
img["src"] = "#{Discourse.base_url}#{img["src"]}" if img["src"][%r{\A/[^/]}]
|
||||
# ensure no schemaless urls
|
||||
img["src"] = "#{uri.scheme}:#{img["src"]}" if img["src"][%r{^//}]
|
||||
img["src"] = "#{uri.scheme}:#{img["src"]}" if img["src"][%r{\A//}]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -110,7 +110,7 @@ module Email
|
|||
.css("a.attachment")
|
||||
.each do |a|
|
||||
# ensure all urls are absolute
|
||||
a["href"] = "#{Discourse.base_url}#{a["href"]}" if a["href"] =~ %r{^/[^/]}
|
||||
a["href"] = "#{Discourse.base_url}#{a["href"]}" if a["href"] =~ %r{\A/[^/]}
|
||||
|
||||
# ensure no schemaless urls
|
||||
a["href"] = "#{uri.scheme}:#{a["href"]}" if a["href"] && a["href"].starts_with?("//")
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
class EmailCook
|
||||
def self.raw_regexp
|
||||
@raw_regexp ||=
|
||||
%r{^\[plaintext\]$\n(.*)\n^\[/plaintext\]$(?:\s^\[attachments\]$\n(.*)\n^\[/attachments\]$)?(?:\s^\[elided\]$\n(.*)\n^\[/elided\]$)?}m
|
||||
%r{\A\[plaintext\]$\n(.*)\n^\[/plaintext\]$(?:\s^\[attachments\]$\n(.*)\n^\[/attachments\]$)?(?:\s^\[elided\]$\n(.*)\n^\[/elided\]$)?}m
|
||||
end
|
||||
|
||||
def initialize(raw)
|
||||
|
@ -14,7 +14,7 @@ class EmailCook
|
|||
|
||||
def add_quote(result, buffer)
|
||||
if buffer.present?
|
||||
return if buffer =~ /\A(<br>)+\z$/
|
||||
return if buffer =~ /\A(<br>)+\z\z/
|
||||
result << "<blockquote>#{buffer}</blockquote>"
|
||||
end
|
||||
end
|
||||
|
@ -22,7 +22,7 @@ class EmailCook
|
|||
def link_string!(line, unescaped_line)
|
||||
unescaped_line = unescaped_line.strip
|
||||
line.gsub!(/\S+/) do |str|
|
||||
if str.match?(%r{^(https?://)[\S]+$}i)
|
||||
if str.match?(%r{\A(https?://)[\S]+\z}i)
|
||||
begin
|
||||
url = URI.parse(str).to_s
|
||||
if unescaped_line == url
|
||||
|
@ -48,11 +48,11 @@ class EmailCook
|
|||
|
||||
text.each_line do |line|
|
||||
# replace indentation with non-breaking spaces
|
||||
line.sub!(/^\s{2,}/) { |s| "\u00A0" * s.length }
|
||||
line.sub!(/\A\s{2,}/) { |s| "\u00A0" * s.length }
|
||||
|
||||
if line =~ /^\s*>/
|
||||
if line =~ /\A\s*>/
|
||||
in_quote = true
|
||||
line.sub!(/^[\s>]*/, "")
|
||||
line.sub!(/\A[\s>]*/, "")
|
||||
|
||||
unescaped_line = line
|
||||
line = CGI.escapeHTML(line)
|
||||
|
|
|
@ -52,7 +52,7 @@ class FileHelper
|
|||
retain_on_max_file_size_exceeded: false
|
||||
)
|
||||
url = "https:" + url if url.start_with?("//")
|
||||
raise Discourse::InvalidParameters.new(:url) unless url =~ %r{^https?://}
|
||||
raise Discourse::InvalidParameters.new(:url) unless url =~ %r{\Ahttps?://}
|
||||
|
||||
tmp = nil
|
||||
|
||||
|
@ -175,26 +175,26 @@ class FileHelper
|
|||
end
|
||||
|
||||
def self.supported_video_regexp
|
||||
@@supported_video_regexp ||= /\.(#{supported_video.to_a.join("|")})$/i
|
||||
@@supported_video_regexp ||= /\.(#{supported_video.to_a.join("|")})\z/i
|
||||
end
|
||||
|
||||
def self.supported_audio_regexp
|
||||
@@supported_audio_regexp ||= /\.(#{supported_audio.to_a.join("|")})$/i
|
||||
@@supported_audio_regexp ||= /\.(#{supported_audio.to_a.join("|")})\z/i
|
||||
end
|
||||
|
||||
def self.supported_images_regexp
|
||||
@@supported_images_regexp ||= /\.(#{supported_images.to_a.join("|")})$/i
|
||||
@@supported_images_regexp ||= /\.(#{supported_images.to_a.join("|")})\z/i
|
||||
end
|
||||
|
||||
def self.inline_images_regexp
|
||||
@@inline_images_regexp ||= /\.(#{inline_images.to_a.join("|")})$/i
|
||||
@@inline_images_regexp ||= /\.(#{inline_images.to_a.join("|")})\z/i
|
||||
end
|
||||
|
||||
def self.supported_media_regexp
|
||||
@@supported_media_regexp ||=
|
||||
begin
|
||||
media = supported_images | supported_audio | supported_video
|
||||
/\.(#{media.to_a.join("|")})$/i
|
||||
/\.(#{media.to_a.join("|")})\z/i
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -202,7 +202,7 @@ class FileHelper
|
|||
@@supported_playable_media_regexp ||=
|
||||
begin
|
||||
media = supported_audio | supported_video
|
||||
/\.(#{media.to_a.join("|")})$/i
|
||||
/\.(#{media.to_a.join("|")})\z/i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -113,7 +113,7 @@ module FileStore
|
|||
end
|
||||
)
|
||||
|
||||
url = SiteSetting.scheme + ":" + url if url =~ %r{^//}
|
||||
url = SiteSetting.scheme + ":" + url if url =~ %r{\A//}
|
||||
file =
|
||||
FileHelper.download(
|
||||
url,
|
||||
|
|
|
@ -128,7 +128,7 @@ module FileStore
|
|||
count = 0
|
||||
model.find_each do |upload|
|
||||
# could be a remote image
|
||||
next unless upload.url =~ %r{^/[^/]}
|
||||
next unless upload.url =~ %r{\A/[^/]}
|
||||
|
||||
path = "#{public_dir}#{upload.url}"
|
||||
bad = true
|
||||
|
|
|
@ -216,7 +216,7 @@ module FileStore
|
|||
|
||||
def path_for(upload)
|
||||
url = upload&.url
|
||||
FileStore::LocalStore.new.path_for(upload) if url && url[%r{^/[^/]}]
|
||||
FileStore::LocalStore.new.path_for(upload) if url && url[%r{\A/[^/]}]
|
||||
end
|
||||
|
||||
def url_for(upload, force_download: false)
|
||||
|
@ -233,7 +233,7 @@ module FileStore
|
|||
|
||||
def cdn_url(url)
|
||||
return url if SiteSetting.Upload.s3_cdn_url.blank?
|
||||
schema = url[%r{^(https?:)?//}, 1]
|
||||
schema = url[%r{\A(https?:)?//}, 1]
|
||||
folder = s3_bucket_folder_path.nil? ? "" : "#{s3_bucket_folder_path}/"
|
||||
url.sub(
|
||||
File.join("#{schema}#{absolute_base_url}", folder),
|
||||
|
|
|
@ -39,7 +39,7 @@ module I18n
|
|||
|
||||
if @loaded_locales.empty?
|
||||
# load all rb files
|
||||
I18n.backend.load_translations(I18n.load_path.grep(/\.rb$/))
|
||||
I18n.backend.load_translations(I18n.load_path.grep(/\.rb\z/))
|
||||
|
||||
# load plural rules from plugins
|
||||
DiscoursePluginRegistry.locales.each do |plugin_locale, options|
|
||||
|
@ -50,14 +50,14 @@ module I18n
|
|||
end
|
||||
|
||||
# load it
|
||||
I18n.backend.load_translations(I18n.load_path.grep(/\.#{Regexp.escape locale}\.yml$/))
|
||||
I18n.backend.load_translations(I18n.load_path.grep(/\.#{Regexp.escape locale}\.yml\z/))
|
||||
|
||||
if Discourse.allow_dev_populate?
|
||||
I18n.backend.load_translations(
|
||||
I18n.load_path.grep(%r{.*faker.*/#{Regexp.escape locale}\.yml$}),
|
||||
I18n.load_path.grep(%r{.*faker.*/#{Regexp.escape locale}\.yml\z}),
|
||||
)
|
||||
I18n.backend.load_translations(
|
||||
I18n.load_path.grep(%r{.*faker.*/#{Regexp.escape locale}/.*\.yml$}),
|
||||
I18n.load_path.grep(%r{.*faker.*/#{Regexp.escape locale}/.*\.yml\z}),
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ module GitUrl
|
|||
end
|
||||
|
||||
if url.start_with?("https://github.com/") && !url.end_with?(".git")
|
||||
url = url.gsub(%r{/$}, "")
|
||||
url = url.gsub(%r{/\z}, "")
|
||||
url += ".git"
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ module GlobalPath
|
|||
def upload_cdn_path(p)
|
||||
p = Discourse.store.cdn_url(p) if SiteSetting.Upload.s3_cdn_url.present?
|
||||
|
||||
(p =~ /^http/ || p =~ %r{^//}) ? p : cdn_path(p)
|
||||
(p =~ /\Ahttp/ || p =~ %r{\A//}) ? p : cdn_path(p)
|
||||
end
|
||||
|
||||
def cdn_relative_path(path)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# Support for ensure_{blah}! methods.
|
||||
module EnsureMagic
|
||||
def method_missing(method, *args, &block)
|
||||
if method.to_s =~ /^ensure_(.*)\!$/
|
||||
if method.to_s =~ /\Aensure_(.*)\!\z/
|
||||
can_method = :"#{Regexp.last_match[1]}?"
|
||||
|
||||
if respond_to?(can_method)
|
||||
|
|
|
@ -249,8 +249,8 @@ class HtmlPrettify < String
|
|||
# Special case if the very first character is a quote followed by
|
||||
# punctuation at a non-word-break. Close the quotes by brute
|
||||
# force:
|
||||
str.gsub!(/^'(?=#{punct_class}\B)/, entity(:single_right_quote))
|
||||
str.gsub!(/^"(?=#{punct_class}\B)/, entity(:double_right_quote))
|
||||
str.gsub!(/\A'(?=#{punct_class}\B)/, entity(:single_right_quote))
|
||||
str.gsub!(/\A"(?=#{punct_class}\B)/, entity(:double_right_quote))
|
||||
|
||||
# Special case for double sets of quotes, e.g.:
|
||||
# <p>He said, "'Quoted' words in a larger quote."</p>
|
||||
|
|
|
@ -49,7 +49,7 @@ class LocaleFileChecker
|
|||
end
|
||||
|
||||
def reference_file(path)
|
||||
path = path.gsub(/\.\w{2,}\.yml$/, ".#{REFERENCE_LOCALE}.yml")
|
||||
path = path.gsub(/\.\w{2,}\.yml\z/, ".#{REFERENCE_LOCALE}.yml")
|
||||
path if File.exist?(path)
|
||||
end
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@ module Middleware
|
|||
def self.compile_key_builder
|
||||
method = +"def self.__compiled_key_builder(h)\n \""
|
||||
cache_key_segments.each do |k, v|
|
||||
raise "Invalid key name" unless k =~ /^[a-z]+$/
|
||||
raise "Invalid method name" unless v =~ /^key_[a-z_\?]+$/
|
||||
raise "Invalid key name" unless k =~ /\A[a-z]+\z/
|
||||
raise "Invalid method name" unless v =~ /\Akey_[a-z_\?]+\z/
|
||||
method << "|#{k}=#\{h.#{v}}"
|
||||
end
|
||||
method << "\"\nend"
|
||||
|
|
|
@ -11,7 +11,7 @@ module Middleware
|
|||
end
|
||||
|
||||
def call(env)
|
||||
if (env["REQUEST_PATH"] =~ %r{^/uploads/default/avatars})
|
||||
if (env["REQUEST_PATH"] =~ %r{\A/uploads/default/avatars})
|
||||
path = "#{Rails.root}/public#{env["REQUEST_PATH"]}"
|
||||
unless File.exist?(path)
|
||||
default_image = "#{Rails.root}/public/images/d-logo-sketch-small.png"
|
||||
|
|
|
@ -116,7 +116,7 @@ class Migration::SafeMigrate
|
|||
end
|
||||
|
||||
def self.protect!(sql)
|
||||
if sql =~ /^\s*(?:drop\s+table|alter\s+table.*rename\s+to)\s+/i
|
||||
if sql =~ /\A\s*(?:drop\s+table|alter\s+table.*rename\s+to)\s+/i
|
||||
$stdout.puts("", <<~TEXT)
|
||||
WARNING
|
||||
-------------------------------------------------------------------------------------
|
||||
|
@ -129,7 +129,7 @@ class Migration::SafeMigrate
|
|||
in use by live applications.
|
||||
TEXT
|
||||
raise Discourse::InvalidMigration, "Attempt was made to drop a table"
|
||||
elsif sql =~ /^\s*alter\s+table.*(?:rename|drop)\s+/i
|
||||
elsif sql =~ /\A\s*alter\s+table.*(?:rename|drop)\s+/i
|
||||
$stdout.puts("", <<~TEXT)
|
||||
WARNING
|
||||
-------------------------------------------------------------------------------------
|
||||
|
|
|
@ -7,7 +7,7 @@ module Onebox
|
|||
end
|
||||
|
||||
def self.engines
|
||||
constants.select { |constant| constant.to_s =~ /Onebox$/ }.sort.map(&method(:const_get))
|
||||
constants.select { |constant| constant.to_s =~ /Onebox\z/ }.sort.map(&method(:const_get))
|
||||
end
|
||||
|
||||
def self.all_iframe_origins
|
||||
|
|
|
@ -15,7 +15,7 @@ module Onebox
|
|||
@record = Onebox::Helpers.symbolize_keys(record)
|
||||
|
||||
# Fix any relative paths
|
||||
if @record[:image] && @record[:image] =~ %r{^/[^/]}
|
||||
if @record[:image] && @record[:image] =~ %r{\A/[^/]}
|
||||
@record[:image] = "#{uri.scheme}://#{uri.host}/#{@record[:image]}"
|
||||
end
|
||||
|
||||
|
@ -40,7 +40,7 @@ module Onebox
|
|||
link: record[:link],
|
||||
title: record[:title],
|
||||
favicon: record[:favicon],
|
||||
domain: record[:domain] || uri.host.to_s.sub(/^www\./, ""),
|
||||
domain: record[:domain] || uri.host.to_s.sub(/\Awww\./, ""),
|
||||
article_published_time: record[:article_published_time],
|
||||
article_published_time_title: record[:article_published_time_title],
|
||||
metadata_1_label: record[:metadata_1_label],
|
||||
|
|
|
@ -119,7 +119,7 @@ module Onebox
|
|||
a_lines = str.lines
|
||||
a_lines.each do |l|
|
||||
l = l.chomp("\n") # remove new line
|
||||
m = l.match(/^[ ]*/) # find leading spaces 0 or more
|
||||
m = l.match(/\A[ ]*/) # find leading spaces 0 or more
|
||||
unless m.nil? || l.size == m[0].size || l.size == 0 # no match | only spaces in line | empty line
|
||||
m_str_length = m[0].size
|
||||
if m_str_length <= 1 # minimum space is 1 or nothing we can break we found our minimum
|
||||
|
@ -166,7 +166,7 @@ module Onebox
|
|||
@file = m[:file]
|
||||
@lang = Onebox::FileTypeFinder.from_file_name(m[:file])
|
||||
|
||||
if @lang == "stl" && link.match?(%r{^https?://(www\.)?github\.com.*/blob/})
|
||||
if @lang == "stl" && link.match?(%r{\Ahttps?://(www\.)?github\.com.*/blob/})
|
||||
@model_file = @lang.dup
|
||||
@raw = "https://render.githubusercontent.com/view/solid?url=" + self.raw_template(m)
|
||||
else
|
||||
|
|
|
@ -32,8 +32,8 @@ module Onebox
|
|||
doc
|
||||
.css("meta")
|
||||
.each do |m|
|
||||
if (m["property"] && m["property"][/^(?:og|article|product):(.+)$/i]) ||
|
||||
(m["name"] && m["name"][/^(?:og|article|product):(.+)$/i])
|
||||
if (m["property"] && m["property"][/\A(?:og|article|product):(.+)\z/i]) ||
|
||||
(m["name"] && m["name"][/\A(?:og|article|product):(.+)\z/i])
|
||||
value = (m["content"] || m["value"]).to_s
|
||||
next if Onebox::Helpers.blank?(value)
|
||||
key = $1.tr("-:", "_").to_sym
|
||||
|
|
|
@ -58,7 +58,7 @@ module Onebox
|
|||
next unless env[:node_name] == "a"
|
||||
a_tag = env[:node]
|
||||
a_tag["href"] ||= "#"
|
||||
if a_tag["href"] =~ %r{^(?:[a-z]+:)?//}
|
||||
if a_tag["href"] =~ %r{\A(?:[a-z]+:)?//}
|
||||
a_tag["rel"] = "nofollow ugc noopener"
|
||||
else
|
||||
a_tag.remove_attribute("target")
|
||||
|
|
|
@ -6,8 +6,8 @@ Dir["#{Rails.root}/lib/onebox/engine/*_onebox.rb"].sort.each { |f| require f }
|
|||
|
||||
module Oneboxer
|
||||
ONEBOX_CSS_CLASS = "onebox"
|
||||
AUDIO_REGEX = /^\.(mp3|og[ga]|opus|wav|m4[abpr]|aac|flac)$/i
|
||||
VIDEO_REGEX = /^\.(mov|mp4|webm|m4v|3gp|ogv|avi|mpeg|ogv)$/i
|
||||
AUDIO_REGEX = /\A\.(mp3|og[ga]|opus|wav|m4[abpr]|aac|flac)\z/i
|
||||
VIDEO_REGEX = /\A\.(mov|mp4|webm|m4v|3gp|ogv|avi|mpeg|ogv)\z/i
|
||||
|
||||
# keep reloaders happy
|
||||
unless defined?(Oneboxer::Result)
|
||||
|
|
|
@ -100,7 +100,7 @@ class PlainTextToMarkdown
|
|||
|
||||
# @param line [Line]
|
||||
def remove_quote_level_indicators!(line)
|
||||
match_data = line.text.match(/^(?<indicators>>+)\s?(?<text>.*)/)
|
||||
match_data = line.text.match(/\A(?<indicators>>+)\s?(?<text>.*)/)
|
||||
|
||||
if match_data
|
||||
line.text = match_data[:text]
|
||||
|
@ -128,7 +128,7 @@ class PlainTextToMarkdown
|
|||
def classify_line_as_code!(line, previous_line)
|
||||
line.code_block = previous_line.code_block unless previous_line.nil? ||
|
||||
previous_line.valid_code_block?
|
||||
return unless line.text =~ /^\s{0,3}```/
|
||||
return unless line.text =~ /\A\s{0,3}```/
|
||||
|
||||
if line.code_block.present?
|
||||
line.code_block.end_line = line
|
||||
|
@ -173,7 +173,7 @@ class PlainTextToMarkdown
|
|||
end
|
||||
|
||||
def indent_with_non_breaking_spaces(text)
|
||||
text.sub(/^\s+/) do |s|
|
||||
text.sub(/\A\s+/) do |s|
|
||||
# replace tabs with 2 spaces
|
||||
s.gsub!("\t", " ")
|
||||
|
||||
|
|
|
@ -675,17 +675,17 @@ class Plugin::Instance
|
|||
DiscoursePluginRegistry.register_glob(admin_path, "hbr", admin: true)
|
||||
|
||||
DiscourseJsProcessor.plugin_transpile_paths << root_path.sub(Rails.root.to_s, "").sub(
|
||||
%r{^/*},
|
||||
%r{\A/*},
|
||||
"",
|
||||
)
|
||||
DiscourseJsProcessor.plugin_transpile_paths << admin_path.sub(Rails.root.to_s, "").sub(
|
||||
%r{^/*},
|
||||
%r{\A/*},
|
||||
"",
|
||||
)
|
||||
|
||||
test_path = "#{root_dir_name}/test/javascripts"
|
||||
DiscourseJsProcessor.plugin_transpile_paths << test_path.sub(Rails.root.to_s, "").sub(
|
||||
%r{^/*},
|
||||
%r{\A/*},
|
||||
"",
|
||||
)
|
||||
end
|
||||
|
@ -1299,7 +1299,7 @@ class Plugin::Instance
|
|||
private
|
||||
|
||||
def validate_directory_column_name(column_name)
|
||||
match = /^[_a-z]+$/.match(column_name)
|
||||
match = /\A[_a-z]+\z/.match(column_name)
|
||||
unless match
|
||||
raise "Invalid directory column name '#{column_name}'. Can only contain a-z and underscores"
|
||||
end
|
||||
|
|
|
@ -48,7 +48,7 @@ module PrettyText
|
|||
filename = find_file(root_path, part_name)
|
||||
if filename
|
||||
source = File.read("#{root_path}#{filename}")
|
||||
source = ERB.new(source).result(binding) if filename =~ /\.erb$/
|
||||
source = ERB.new(source).result(binding) if filename =~ /\.erb\z/
|
||||
|
||||
transpiler = DiscourseJsProcessor::Transpiler.new
|
||||
transpiled = transpiler.perform(source, "#{Rails.root}/app/assets/javascripts/", part_name)
|
||||
|
@ -64,7 +64,7 @@ module PrettyText
|
|||
def self.ctx_load_directory(ctx, path)
|
||||
root_path = "#{Rails.root}/app/assets/javascripts/"
|
||||
Dir["#{root_path}#{path}/**/*"].sort.each do |f|
|
||||
apply_es6_file(ctx, root_path, f.sub(root_path, "").sub(/\.js(.es6)?$/, ""))
|
||||
apply_es6_file(ctx, root_path, f.sub(root_path, "").sub(/\.js(.es6)?\z/, ""))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -116,9 +116,9 @@ module PrettyText
|
|||
to_load << a if File.file?(a) && a =~ /discourse-markdown/
|
||||
end
|
||||
to_load.uniq.each do |f|
|
||||
if f =~ %r{^.+assets/javascripts/}
|
||||
if f =~ %r{\A.+assets/javascripts/}
|
||||
root = Regexp.last_match[0]
|
||||
apply_es6_file(ctx, root, f.sub(root, "").sub(/\.js(\.es6)?$/, ""))
|
||||
apply_es6_file(ctx, root, f.sub(root, "").sub(/\.js(\.es6)?\z/, ""))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ module PrettyText
|
|||
# TODO (martin) Remove this when everything is using hashtag_lookup
|
||||
# after enable_experimental_hashtag_autocomplete is default.
|
||||
def category_tag_hashtag_lookup(text)
|
||||
is_tag = text =~ /#{TAG_HASHTAG_POSTFIX}$/
|
||||
is_tag = text =~ /#{TAG_HASHTAG_POSTFIX}\z/
|
||||
|
||||
if !is_tag && category = Category.query_from_hashtag_slug(text)
|
||||
[category.url, text]
|
||||
|
|
|
@ -14,7 +14,7 @@ module RequireDependencyBackwardCompatibility
|
|||
def require_dependency(filename)
|
||||
name = filename.to_s
|
||||
return if name == "jobs/base"
|
||||
return super(name.sub(%r{^lib/}, "")) if name.start_with?("lib/")
|
||||
return super(name.sub(%r{\Alib/}, "")) if name.start_with?("lib/")
|
||||
super
|
||||
end
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ module RetrieveTitle
|
|||
# A horrible hack - YouTube uses `document.title` to populate the title
|
||||
# for some reason. For any other site than YouTube this wouldn't be worth it.
|
||||
if title == "YouTube" && html =~ /document\.title *= *"(.*)";/
|
||||
title = Regexp.last_match[1].sub(/ - YouTube$/, "")
|
||||
title = Regexp.last_match[1].sub(/ - YouTube\z/, "")
|
||||
end
|
||||
|
||||
if !title && node = doc.at('meta[property="og:title"]')
|
||||
|
@ -53,11 +53,12 @@ module RetrieveTitle
|
|||
|
||||
def self.max_chunk_size(uri)
|
||||
# Exception for sites that leave the title until very late.
|
||||
if uri.host =~ /(^|\.)amazon\.(com|ca|co\.uk|es|fr|de|it|com\.au|com\.br|cn|in|co\.jp|com\.mx)$/
|
||||
if uri.host =~
|
||||
/(^|\.)amazon\.(com|ca|co\.uk|es|fr|de|it|com\.au|com\.br|cn|in|co\.jp|com\.mx)\z/
|
||||
return 500
|
||||
end
|
||||
return 300 if uri.host =~ /(^|\.)youtube\.com$/ || uri.host =~ /(^|\.)youtu\.be$/
|
||||
return 50 if uri.host =~ /(^|\.)github\.com$/
|
||||
return 300 if uri.host =~ /(^|\.)youtube\.com\z/ || uri.host =~ /(^|\.)youtu\.be\z/
|
||||
return 50 if uri.host =~ /(^|\.)github\.com\z/
|
||||
|
||||
# default is 20k
|
||||
20
|
||||
|
|
|
@ -46,7 +46,7 @@ class RouteMatcher
|
|||
return true if actions.nil? # actions are unrestricted
|
||||
|
||||
# message_bus is not a rails route, special handling
|
||||
return true if actions.include?("message_bus") && request.fullpath =~ %r{^/message-bus/.*/poll}
|
||||
return true if actions.include?("message_bus") && request.fullpath =~ %r{\A/message-bus/.*/poll}
|
||||
|
||||
path_params = path_params_from_request(request)
|
||||
actions.include? "#{path_params[:controller]}##{path_params[:action]}"
|
||||
|
|
|
@ -334,7 +334,7 @@ class S3Inventory
|
|||
objects = []
|
||||
|
||||
hive_path = File.join(inventory_path, bucket_name, inventory_id, "hive")
|
||||
@s3_helper.list(hive_path).each { |obj| objects << obj if obj.key.match?(/symlink\.txt$/i) }
|
||||
@s3_helper.list(hive_path).each { |obj| objects << obj if obj.key.match?(/symlink\.txt\z/i) }
|
||||
|
||||
objects
|
||||
rescue Aws::Errors::ServiceError => e
|
||||
|
|
108
lib/search.rb
108
lib/search.rb
|
@ -128,7 +128,7 @@ class Search
|
|||
end
|
||||
|
||||
data.gsub!(/\S+/) do |str|
|
||||
if str =~ %r{^["]?((https?://)[\S]+)["]?$}
|
||||
if str =~ %r{\A["]?((https?://)[\S]+)["]?\z}
|
||||
begin
|
||||
uri = URI.parse(Regexp.last_match[1])
|
||||
uri.query = nil
|
||||
|
@ -145,9 +145,9 @@ class Search
|
|||
end
|
||||
|
||||
def self.word_to_date(str)
|
||||
return Time.zone.now.beginning_of_day.days_ago(str.to_i) if str =~ /^[0-9]{1,3}$/
|
||||
return Time.zone.now.beginning_of_day.days_ago(str.to_i) if str =~ /\A[0-9]{1,3}\z/
|
||||
|
||||
if str =~ /^([12][0-9]{3})(-([0-1]?[0-9]))?(-([0-3]?[0-9]))?$/
|
||||
if str =~ /\A([12][0-9]{3})(-([0-1]?[0-9]))?(-([0-3]?[0-9]))?\z/
|
||||
year = $1.to_i
|
||||
month = $2 ? $3.to_i : 1
|
||||
day = $4 ? $5.to_i : 1
|
||||
|
@ -307,7 +307,7 @@ class Search
|
|||
|
||||
# If the term is a number or url to a topic, just include that topic
|
||||
if @opts[:search_for_id] && %w[topic private_messages all_topics].include?(@results.type_filter)
|
||||
if @term =~ /^\d+$/
|
||||
if @term =~ /\A\d+\z/
|
||||
single_topic(@term.to_i)
|
||||
else
|
||||
if route = Discourse.route_for(@term)
|
||||
|
@ -355,7 +355,7 @@ class Search
|
|||
Array.wrap(@custom_topic_eager_loads)
|
||||
end
|
||||
|
||||
advanced_filter(/^in:personal-direct$/i) do |posts|
|
||||
advanced_filter(/\Ain:personal-direct\z/i) do |posts|
|
||||
if @guardian.user
|
||||
posts.joins("LEFT JOIN topic_allowed_groups tg ON posts.topic_id = tg.topic_id").where(
|
||||
<<~SQL,
|
||||
|
@ -376,60 +376,60 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^in:all-pms$/i) { |posts| posts.private_posts if @guardian.is_admin? }
|
||||
advanced_filter(/\Ain:all-pms\z/i) { |posts| posts.private_posts if @guardian.is_admin? }
|
||||
|
||||
advanced_filter(/^in:tagged$/i) do |posts|
|
||||
advanced_filter(/\Ain:tagged\z/i) do |posts|
|
||||
posts.where("EXISTS (SELECT 1 FROM topic_tags WHERE topic_tags.topic_id = posts.topic_id)")
|
||||
end
|
||||
|
||||
advanced_filter(/^in:untagged$/i) do |posts|
|
||||
advanced_filter(/\Ain:untagged\z/i) do |posts|
|
||||
posts.joins(
|
||||
"LEFT JOIN topic_tags ON
|
||||
topic_tags.topic_id = posts.topic_id",
|
||||
).where("topic_tags.id IS NULL")
|
||||
end
|
||||
|
||||
advanced_filter(/^status:open$/i) do |posts|
|
||||
advanced_filter(/\Astatus:open\z/i) do |posts|
|
||||
posts.where("NOT topics.closed AND NOT topics.archived")
|
||||
end
|
||||
|
||||
advanced_filter(/^status:closed$/i) { |posts| posts.where("topics.closed") }
|
||||
advanced_filter(/\Astatus:closed\z/i) { |posts| posts.where("topics.closed") }
|
||||
|
||||
advanced_filter(/^status:public$/i) do |posts|
|
||||
advanced_filter(/\Astatus:public\z/i) do |posts|
|
||||
category_ids = Category.where(read_restricted: false).pluck(:id)
|
||||
|
||||
posts.where("topics.category_id in (?)", category_ids)
|
||||
end
|
||||
|
||||
advanced_filter(/^status:archived$/i) { |posts| posts.where("topics.archived") }
|
||||
advanced_filter(/\Astatus:archived\z/i) { |posts| posts.where("topics.archived") }
|
||||
|
||||
advanced_filter(/^status:noreplies$/i) { |posts| posts.where("topics.posts_count = 1") }
|
||||
advanced_filter(/\Astatus:noreplies\z/i) { |posts| posts.where("topics.posts_count = 1") }
|
||||
|
||||
advanced_filter(/^status:single_user$/i) { |posts| posts.where("topics.participant_count = 1") }
|
||||
advanced_filter(/\Astatus:single_user\z/i) { |posts| posts.where("topics.participant_count = 1") }
|
||||
|
||||
advanced_filter(/^posts_count:(\d+)$/i) do |posts, match|
|
||||
advanced_filter(/\Aposts_count:(\d+)\z/i) do |posts, match|
|
||||
posts.where("topics.posts_count = ?", match.to_i)
|
||||
end
|
||||
|
||||
advanced_filter(/^min_post_count:(\d+)$/i) do |posts, match|
|
||||
advanced_filter(/\Amin_post_count:(\d+)\z/i) do |posts, match|
|
||||
posts.where("topics.posts_count >= ?", match.to_i)
|
||||
end
|
||||
|
||||
advanced_filter(/^min_posts:(\d+)$/i) do |posts, match|
|
||||
advanced_filter(/\Amin_posts:(\d+)\z/i) do |posts, match|
|
||||
posts.where("topics.posts_count >= ?", match.to_i)
|
||||
end
|
||||
|
||||
advanced_filter(/^max_posts:(\d+)$/i) do |posts, match|
|
||||
advanced_filter(/\Amax_posts:(\d+)\z/i) do |posts, match|
|
||||
posts.where("topics.posts_count <= ?", match.to_i)
|
||||
end
|
||||
|
||||
advanced_filter(/^in:first|^f$/i) { |posts| posts.where("posts.post_number = 1") }
|
||||
advanced_filter(/\Ain:first|^f\z/i) { |posts| posts.where("posts.post_number = 1") }
|
||||
|
||||
advanced_filter(/^in:pinned$/i) { |posts| posts.where("topics.pinned_at IS NOT NULL") }
|
||||
advanced_filter(/\Ain:pinned\z/i) { |posts| posts.where("topics.pinned_at IS NOT NULL") }
|
||||
|
||||
advanced_filter(/^in:wiki$/i) { |posts, match| posts.where(wiki: true) }
|
||||
advanced_filter(/\Ain:wiki\z/i) { |posts, match| posts.where(wiki: true) }
|
||||
|
||||
advanced_filter(/^badge:(.*)$/i) do |posts, match|
|
||||
advanced_filter(/\Abadge:(.*)\z/i) do |posts, match|
|
||||
badge_id = Badge.where("name ilike ? OR id = ?", match, match.to_i).pluck_first(:id)
|
||||
if badge_id
|
||||
posts.where(
|
||||
|
@ -454,7 +454,7 @@ class Search
|
|||
)
|
||||
end
|
||||
|
||||
advanced_filter(/^in:(likes)$/i) do |posts, match|
|
||||
advanced_filter(/\Ain:(likes)\z/i) do |posts, match|
|
||||
post_action_type_filter(posts, PostActionType.types[:like]) if @guardian.user
|
||||
end
|
||||
|
||||
|
@ -462,7 +462,7 @@ class Search
|
|||
# this at some point, as it only acts on posts at the moment. On the other
|
||||
# hand, this may not be necessary, as the user bookmark list has advanced
|
||||
# search based on a RegisteredBookmarkable's #search_query method.
|
||||
advanced_filter(/^in:(bookmarks)$/i) do |posts, match|
|
||||
advanced_filter(/\Ain:(bookmarks)\z/i) do |posts, match|
|
||||
posts.where(<<~SQL, @guardian.user.id) if @guardian.user
|
||||
posts.id IN (
|
||||
SELECT bookmarkable_id FROM bookmarks
|
||||
|
@ -471,20 +471,20 @@ class Search
|
|||
SQL
|
||||
end
|
||||
|
||||
advanced_filter(/^in:posted$/i) do |posts|
|
||||
advanced_filter(/\Ain:posted\z/i) do |posts|
|
||||
posts.where("posts.user_id = ?", @guardian.user.id) if @guardian.user
|
||||
end
|
||||
|
||||
advanced_filter(/^in:(created|mine)$/i) do |posts|
|
||||
advanced_filter(/\Ain:(created|mine)\z/i) do |posts|
|
||||
posts.where(user_id: @guardian.user.id, post_number: 1) if @guardian.user
|
||||
end
|
||||
|
||||
advanced_filter(/^created:@(.*)$/i) do |posts, match|
|
||||
advanced_filter(/\Acreated:@(.*)\z/i) do |posts, match|
|
||||
user_id = User.where(username: match.downcase).pluck_first(:id)
|
||||
posts.where(user_id: user_id, post_number: 1)
|
||||
end
|
||||
|
||||
advanced_filter(/^in:(watching|tracking)$/i) do |posts, match|
|
||||
advanced_filter(/\Ain:(watching|tracking)\z/i) do |posts, match|
|
||||
if @guardian.user
|
||||
level = TopicUser.notification_levels[match.downcase.to_sym]
|
||||
posts.where(
|
||||
|
@ -499,7 +499,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^in:seen$/i) do |posts|
|
||||
advanced_filter(/\Ain:seen\z/i) do |posts|
|
||||
if @guardian.user
|
||||
posts.joins(
|
||||
"INNER JOIN post_timings ON
|
||||
|
@ -511,7 +511,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^in:unseen$/i) do |posts|
|
||||
advanced_filter(/\Ain:unseen\z/i) do |posts|
|
||||
if @guardian.user
|
||||
posts.joins(
|
||||
"LEFT JOIN post_timings ON
|
||||
|
@ -523,9 +523,9 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^with:images$/i) { |posts| posts.where("posts.image_upload_id IS NOT NULL") }
|
||||
advanced_filter(/\Awith:images\z/i) { |posts| posts.where("posts.image_upload_id IS NOT NULL") }
|
||||
|
||||
advanced_filter(/^category:(.+)$/i) do |posts, match|
|
||||
advanced_filter(/\Acategory:(.+)\z/i) do |posts, match|
|
||||
exact = false
|
||||
|
||||
if match[0] == "="
|
||||
|
@ -544,7 +544,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^\#([\p{L}\p{M}0-9\-:=]+)$/i) do |posts, match|
|
||||
advanced_filter(/\A\#([\p{L}\p{M}0-9\-:=]+)\z/i) do |posts, match|
|
||||
category_slug, subcategory_slug = match.to_s.split(":")
|
||||
next unless category_slug
|
||||
|
||||
|
@ -614,7 +614,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^group:(.+)$/i) do |posts, match|
|
||||
advanced_filter(/\Agroup:(.+)\z/i) do |posts, match|
|
||||
group_query =
|
||||
Group
|
||||
.visible_groups(@guardian.user)
|
||||
|
@ -637,7 +637,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^group_messages:(.+)$/i) do |posts, match|
|
||||
advanced_filter(/\Agroup_messages:(.+)\z/i) do |posts, match|
|
||||
group_id =
|
||||
Group
|
||||
.visible_groups(@guardian.user)
|
||||
|
@ -656,7 +656,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^user:(.+)$/i) do |posts, match|
|
||||
advanced_filter(/\Auser:(.+)\z/i) do |posts, match|
|
||||
user_id =
|
||||
User
|
||||
.where(staged: false)
|
||||
|
@ -669,7 +669,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^\@(\S+)$/i) do |posts, match|
|
||||
advanced_filter(/\A\@(\S+)\z/i) do |posts, match|
|
||||
username = User.normalize_username(match)
|
||||
|
||||
user_id = User.not_staged.where(username_lower: username).pluck_first(:id)
|
||||
|
@ -683,7 +683,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^before:(.*)$/i) do |posts, match|
|
||||
advanced_filter(/\Abefore:(.*)\z/i) do |posts, match|
|
||||
if date = Search.word_to_date(match)
|
||||
posts.where("posts.created_at < ?", date)
|
||||
else
|
||||
|
@ -691,7 +691,7 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^after:(.*)$/i) do |posts, match|
|
||||
advanced_filter(/\Aafter:(.*)\z/i) do |posts, match|
|
||||
if date = Search.word_to_date(match)
|
||||
posts.where("posts.created_at > ?", date)
|
||||
else
|
||||
|
@ -699,15 +699,15 @@ class Search
|
|||
end
|
||||
end
|
||||
|
||||
advanced_filter(/^tags?:([\p{L}\p{M}0-9,\-_+]+)$/i) do |posts, match|
|
||||
advanced_filter(/\Atags?:([\p{L}\p{M}0-9,\-_+]+)\z/i) do |posts, match|
|
||||
search_tags(posts, match, positive: true)
|
||||
end
|
||||
|
||||
advanced_filter(/^\-tags?:([\p{L}\p{M}0-9,\-_+]+)$/i) do |posts, match|
|
||||
advanced_filter(/\A\-tags?:([\p{L}\p{M}0-9,\-_+]+)\z/i) do |posts, match|
|
||||
search_tags(posts, match, positive: false)
|
||||
end
|
||||
|
||||
advanced_filter(/^filetypes?:([a-zA-Z0-9,\-_]+)$/i) do |posts, match|
|
||||
advanced_filter(/\Afiletypes?:([a-zA-Z0-9,\-_]+)\z/i) do |posts, match|
|
||||
file_extensions = match.split(",").map(&:downcase)
|
||||
posts.where(
|
||||
"posts.id IN (
|
||||
|
@ -726,11 +726,11 @@ class Search
|
|||
)
|
||||
end
|
||||
|
||||
advanced_filter(/^min_views:(\d+)$/i) do |posts, match|
|
||||
advanced_filter(/\Amin_views:(\d+)\z/i) do |posts, match|
|
||||
posts.where("topics.views >= ?", match.to_i)
|
||||
end
|
||||
|
||||
advanced_filter(/^max_views:(\d+)$/i) do |posts, match|
|
||||
advanced_filter(/\Amax_views:(\d+)\z/i) do |posts, match|
|
||||
posts.where("topics.views <= ?", match.to_i)
|
||||
end
|
||||
|
||||
|
@ -789,38 +789,38 @@ class Search
|
|||
if word == "l"
|
||||
@order = :latest
|
||||
nil
|
||||
elsif word =~ /^order:\w+$/i
|
||||
elsif word =~ /\Aorder:\w+\z/i
|
||||
@order = word.downcase.gsub("order:", "").to_sym
|
||||
nil
|
||||
elsif word =~ /^in:title$/i || word == "t"
|
||||
elsif word =~ /\Ain:title\z/i || word == "t"
|
||||
@in_title = true
|
||||
nil
|
||||
elsif word =~ /^topic:(\d+)$/i
|
||||
elsif word =~ /\Atopic:(\d+)\z/i
|
||||
topic_id = $1.to_i
|
||||
if topic_id > 1
|
||||
topic = Topic.find_by(id: topic_id)
|
||||
@search_context = topic if @guardian.can_see?(topic)
|
||||
end
|
||||
nil
|
||||
elsif word =~ /^in:all$/i
|
||||
elsif word =~ /\Ain:all\z/i
|
||||
@search_all_topics = true
|
||||
nil
|
||||
elsif word =~ /^in:personal$/i
|
||||
elsif word =~ /\Ain:personal\z/i
|
||||
@search_pms = true
|
||||
nil
|
||||
elsif word =~ /^in:messages$/i
|
||||
elsif word =~ /\Ain:messages\z/i
|
||||
@search_pms = true
|
||||
nil
|
||||
elsif word =~ /^in:personal-direct$/i
|
||||
elsif word =~ /\Ain:personal-direct\z/i
|
||||
@search_pms = true
|
||||
nil
|
||||
elsif word =~ /^in:all-pms$/i
|
||||
elsif word =~ /\Ain:all-pms\z/i
|
||||
@search_all_pms = true
|
||||
nil
|
||||
elsif word =~ /^group_messages:(.+)$/i
|
||||
elsif word =~ /\Agroup_messages:(.+)\z/i
|
||||
@search_pms = true
|
||||
nil
|
||||
elsif word =~ /^personal_messages:(.+)$/i
|
||||
elsif word =~ /\Apersonal_messages:(.+)\z/i
|
||||
if user = User.find_by_username($1)
|
||||
@search_pms = true
|
||||
@search_context = user
|
||||
|
|
|
@ -98,7 +98,7 @@ class ShrinkUploadedImage
|
|||
elsif !post.topic || post.topic.trashed?
|
||||
log "A deleted topic"
|
||||
elsif post.cooked.include?(original_upload.sha1)
|
||||
if post.raw.include?("#{Discourse.base_url.sub(%r{^https?://}i, "")}/t/")
|
||||
if post.raw.include?("#{Discourse.base_url.sub(%r{\Ahttps?://}i, "")}/t/")
|
||||
log "Updating a topic onebox"
|
||||
else
|
||||
log "Updating an external onebox"
|
||||
|
|
|
@ -243,7 +243,7 @@ module SiteSettings::Validations
|
|||
|
||||
def validate_cors_origins(new_val)
|
||||
return if new_val.blank?
|
||||
return unless new_val.split("|").any?(%r{/$})
|
||||
return unless new_val.split("|").any?(%r{/\z})
|
||||
validate_error :cors_origins_should_not_have_trailing_slash
|
||||
end
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ class Stylesheet::Manager
|
|||
|
||||
CACHE_PATH ||= "tmp/stylesheet-cache"
|
||||
MANIFEST_DIR ||= "#{Rails.root}/tmp/cache/assets/#{Rails.env}"
|
||||
THEME_REGEX ||= /_theme$/
|
||||
THEME_REGEX ||= /_theme\z/
|
||||
COLOR_SCHEME_STYLESHEET ||= "color_definitions"
|
||||
|
||||
@@lock = Mutex.new
|
||||
|
|
|
@ -35,7 +35,7 @@ class Stylesheet::Manager::Builder
|
|||
end
|
||||
end
|
||||
|
||||
rtl = @target.to_s =~ /_rtl$/
|
||||
rtl = @target.to_s =~ /_rtl\z/
|
||||
css, source_map =
|
||||
with_load_paths do |load_paths|
|
||||
Stylesheet::Compiler.compile_asset(
|
||||
|
|
|
@ -21,7 +21,7 @@ module Stylesheet
|
|||
@default_paths = ["app/assets/stylesheets"]
|
||||
Discourse.plugins.each do |plugin|
|
||||
if plugin.path.to_s.include?(Rails.root.to_s)
|
||||
@default_paths << File.dirname(plugin.path).sub(Rails.root.to_s, "").sub(%r{^/}, "")
|
||||
@default_paths << File.dirname(plugin.path).sub(Rails.root.to_s, "").sub(%r{\A/}, "")
|
||||
else
|
||||
# if plugin doesn’t seem to be in our app, consider it as outside of the app
|
||||
# and ignore it
|
||||
|
@ -41,7 +41,7 @@ module Stylesheet
|
|||
end
|
||||
end
|
||||
|
||||
listener_opts = { ignore: /xxxx/, only: /\.(css|scss)$/ }
|
||||
listener_opts = { ignore: /xxxx/, only: /\.(css|scss)\z/ }
|
||||
listener_opts[:force_polling] = true if ENV["FORCE_POLLING"]
|
||||
|
||||
Thread.new do
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue