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