Merge branch 'master' into fix_limited_search_results

This commit is contained in:
Neil Lalonde
2017-07-31 15:55:31 -04:00
committed by GitHub
2937 changed files with 30379 additions and 11967 deletions

View File

@@ -98,9 +98,7 @@ module ActiveRecord
if fallback_handler.master_down?
fallback_handler.verify_master
connection = postgresql_connection(config.dup.merge({
host: config[:replica_host], port: config[:replica_port]
}))
connection = postgresql_connection(config.dup.merge(host: config[:replica_host], port: config[:replica_port]))
verify_replica(connection)
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)

View File

@@ -2,7 +2,7 @@ require_dependency 'current_user'
class AdminConstraint
def initialize(options={})
def initialize(options = {})
@require_master = options[:require_master]
end

View File

@@ -4,7 +4,7 @@ class AdminUserIndexQuery
def initialize(params = {}, klass = User, trust_levels = TrustLevel.levels)
@params = params
@query = initialize_query_with_order(klass)
@query = initialize_query_with_order(klass).joins(:user_emails)
@trust_levels = trust_levels
end
@@ -24,10 +24,10 @@ class AdminUserIndexQuery
'read_time' => 'user_stats.time_read'
}
def find_users(limit=100)
def find_users(limit = 100)
page = params[:page].to_i - 1
if page < 0
page = 0
page = 0
end
find_users_query.limit(limit).offset(page * limit)
end
@@ -52,7 +52,7 @@ class AdminUserIndexQuery
if !custom_order.present?
if params[:query] == "active"
order << "COALESCE(last_seen_at, to_date('1970-01-01', 'YYYY-MM-DD')) DESC"
order << "COALESCE(users.last_seen_at, to_date('1970-01-01', 'YYYY-MM-DD')) DESC"
else
order << "users.created_at DESC"
end
@@ -81,22 +81,22 @@ class AdminUserIndexQuery
where_conds << "user_stats.posts_read_count <= 1 AND user_stats.topics_entered <= 1"
@query.activated
.references(:user_stats)
.includes(:user_profile)
.where("COALESCE(user_profiles.bio_raw, '') != ''")
.where('users.created_at <= ?', 1.day.ago)
.where(where_conds.map {|c| "(#{c})"}.join(" OR "))
.references(:user_stats)
.includes(:user_profile)
.where("COALESCE(user_profiles.bio_raw, '') != ''")
.where('users.created_at <= ?', 1.day.ago)
.where(where_conds.map { |c| "(#{c})" }.join(" OR "))
end
def filter_by_query_classification
case params[:query]
when 'staff' then @query.where("admin or moderator")
when 'admins' then @query.where(admin: true)
when 'moderators' then @query.where(moderator: true)
when 'blocked' then @query.blocked
when 'suspended' then @query.suspended
when 'pending' then @query.not_suspended.where(approved: false)
when 'suspect' then suspect_users
when 'staff' then @query.where("admin or moderator")
when 'admins' then @query.where(admin: true)
when 'moderators' then @query.where(moderator: true)
when 'blocked' then @query.blocked
when 'suspended' then @query.suspended
when 'pending' then @query.not_suspended.where(approved: false)
when 'suspect' then suspect_users
end
end
@@ -106,7 +106,7 @@ class AdminUserIndexQuery
if ip = IPAddr.new(params[:filter]) rescue nil
@query.where('ip_address <<= :ip OR registration_ip_address <<= :ip', ip: ip.to_cidr_s)
else
@query.where('username_lower ILIKE :filter OR email ILIKE :filter', filter: "%#{params[:filter]}%")
@query.where('username_lower ILIKE :filter OR user_emails.email ILIKE :filter', filter: "%#{params[:filter]}%")
end
end
end
@@ -119,7 +119,7 @@ class AdminUserIndexQuery
def filter_exclude
if params[:exclude].present?
@query.where('id != ?', params[:exclude])
@query.where('users.id != ?', params[:exclude])
end
end

View File

@@ -32,7 +32,7 @@ class Archetype
@archetypes.values
end
def self.register(name, options={})
def self.register(name, options = {})
@archetypes ||= {}
@archetypes[name] = Archetype.new(name, options)
end

View File

@@ -12,12 +12,12 @@ class Auth::CurrentUserProvider
end
# log on a user and set cookies and session etc.
def log_on_user(user,session,cookies)
def log_on_user(user, session, cookies)
raise NotImplementedError
end
# optional interface to be called to refresh cookies etc if needed
def refresh_session(user,session,cookies)
def refresh_session(user, session, cookies)
end
# api has special rights return true if api was detected
@@ -35,7 +35,6 @@ class Auth::CurrentUserProvider
raise NotImplementedError
end
def log_off_user(session, cookies)
raise NotImplementedError
end

View File

@@ -44,7 +44,7 @@ class Auth::DefaultCurrentUserProvider
current_user = nil
if auth_token && auth_token.length == 32
limiter = RateLimiter.new(nil, "cookie_auth_#{request.ip}", COOKIE_ATTEMPTS_PER_MIN ,60)
limiter = RateLimiter.new(nil, "cookie_auth_#{request.ip}", COOKIE_ATTEMPTS_PER_MIN , 60)
if limiter.can_perform?
@user_token = UserAuthToken.lookup(auth_token,
@@ -127,8 +127,8 @@ class Auth::DefaultCurrentUserProvider
if !@user_token.legacy && needs_rotation
if @user_token.rotate!(user_agent: @env['HTTP_USER_AGENT'],
client_ip: @request.ip,
path: @env['REQUEST_PATH'])
client_ip: @request.ip,
path: @env['REQUEST_PATH'])
cookies[TOKEN_COOKIE] = cookie_hash(@user_token.unhashed_auth_token)
end
elsif @user_token.legacy
@@ -200,7 +200,6 @@ class Auth::DefaultCurrentUserProvider
cookies.delete(TOKEN_COOKIE)
end
# api has special rights return true if api was detected
def is_api?
current_user

View File

@@ -52,8 +52,8 @@ class Auth::FacebookAuthenticator < Auth::Authenticator
def register_middleware(omniauth)
omniauth.provider :facebook,
:setup => lambda { |env|
strategy = env["omniauth.strategy"]
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.facebook_app_id
strategy.options[:client_secret] = SiteSetting.facebook_app_secret
strategy.options[:info_fields] = 'gender,email,name,about,first_name,link,last_name,website,location'
@@ -61,7 +61,7 @@ class Auth::FacebookAuthenticator < Auth::Authenticator
strategy.options[:scope] = 'email,user_about_me,user_location,user_website'
end
},
:scope => "email"
scope: "email"
end
protected

View File

@@ -47,10 +47,8 @@ class Auth::GithubAuthenticator < Auth::Authenticator
# Potentially use *any* of the emails from GitHub to find a match or
# register a new user, with preference given to the primary email.
all_emails = Array.new(auth_token[:extra][:all_emails])
all_emails.unshift({
:email => data[:email],
:verified => !!data[:email_verified]
})
all_emails.unshift(email: data[:email],
verified: !!data[:email_verified])
# Only consider verified emails to match an existing user. We don't want
# someone to be able to create a GitHub account with an unverified email
@@ -106,14 +104,13 @@ class Auth::GithubAuthenticator < Auth::Authenticator
)
end
def register_middleware(omniauth)
omniauth.provider :github,
:setup => lambda { |env|
strategy = env["omniauth.strategy"]
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.github_client_id
strategy.options[:client_secret] = SiteSetting.github_client_secret
},
:scope => "user:email"
scope: "user:email"
end
end

View File

@@ -21,7 +21,7 @@ class Auth::GoogleOAuth2Authenticator < Auth::Authenticator
if !result.user && !result.email.blank? && result.email_valid
result.user = User.find_by_email(result.email)
if result.user
::GoogleUserInfo.create({user_id: result.user.id}.merge(google_hash))
::GoogleUserInfo.create({ user_id: result.user.id }.merge(google_hash))
end
end
@@ -30,7 +30,7 @@ class Auth::GoogleOAuth2Authenticator < Auth::Authenticator
def after_create_account(user, auth)
data = auth[:extra_data]
GoogleUserInfo.create({user_id: user.id}.merge(data))
GoogleUserInfo.create({ user_id: user.id }.merge(data))
if auth[:email_valid].to_s == 'true'
EmailToken.confirm(user.email_tokens.first.token)
user.set_automatic_groups
@@ -41,8 +41,8 @@ class Auth::GoogleOAuth2Authenticator < Auth::Authenticator
# jwt encoding is causing auth to fail in quite a few conditions
# skipping
omniauth.provider :google_oauth2,
:setup => lambda { |env|
strategy = env["omniauth.strategy"]
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.google_oauth2_client_id
strategy.options[:client_secret] = SiteSetting.google_oauth2_client_secret
},

View File

@@ -39,8 +39,8 @@ class Auth::InstagramAuthenticator < Auth::Authenticator
def register_middleware(omniauth)
omniauth.provider :instagram,
:setup => lambda { |env|
strategy = env["omniauth.strategy"]
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:client_id] = SiteSetting.instagram_consumer_key
strategy.options[:client_secret] = SiteSetting.instagram_consumer_secret
}

View File

@@ -5,7 +5,7 @@ class Auth::OAuth2Authenticator < Auth::Authenticator
end
# only option at the moment is :trusted
def initialize(name, opts={})
def initialize(name, opts = {})
@name = name
@opts = opts
end

View File

@@ -49,15 +49,14 @@ class Auth::OpenIdAuthenticator < Auth::Authenticator
)
end
def register_middleware(omniauth)
omniauth.provider :open_id,
:setup => lambda { |env|
strategy = env["omniauth.strategy"]
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:store] = OpenID::Store::Redis.new($redis)
},
:name => name,
:identifier => identifier,
:require => "omniauth-openid"
name: name,
identifier: identifier,
require: "omniauth-openid"
end
end

View File

@@ -35,8 +35,8 @@ class Auth::Result
if user.suspended?
{
suspended: true,
suspended_message: I18n.t( user.suspend_reason ? "login.suspended_with_reason" : "login.suspended",
{date: I18n.l(user.suspended_till, format: :date_only), reason: user.suspend_reason} )
suspended_message: I18n.t(user.suspend_reason ? "login.suspended_with_reason" : "login.suspended",
date: I18n.l(user.suspended_till, format: :date_only), reason: user.suspend_reason)
}
else
{

View File

@@ -57,8 +57,8 @@ class Auth::TwitterAuthenticator < Auth::Authenticator
def register_middleware(omniauth)
omniauth.provider :twitter,
:setup => lambda { |env|
strategy = env["omniauth.strategy"]
setup: lambda { |env|
strategy = env["omniauth.strategy"]
strategy.options[:consumer_key] = SiteSetting.twitter_consumer_key
strategy.options[:consumer_secret] = SiteSetting.twitter_consumer_secret
}

View File

@@ -16,7 +16,7 @@ class Autospec::Formatter < RSpec::Core::Formatters::BaseTextFormatter
def start(example_count)
super
File.delete(RSPEC_RESULT) if File.exists?(RSPEC_RESULT)
@fail_file = File.open(RSPEC_RESULT,"w")
@fail_file = File.open(RSPEC_RESULT, "w")
end
def example_passed(_notification)

View File

@@ -9,7 +9,7 @@ module Autospec; end
class Autospec::Manager
def self.run(opts={})
def self.run(opts = {})
self.new(opts).run
end
@@ -66,10 +66,10 @@ class Autospec::Manager
Autospec::QunitRunner.new
end
def ensure_all_specs_will_run(current_runner=nil)
def ensure_all_specs_will_run(current_runner = nil)
puts "@@@@@@@@@@@@ ensure_all_specs_will_run" if @debug
@queue.reject!{|_,s,_| s == "spec"}
@queue.reject! { |_, s, _| s == "spec" }
if current_runner
@queue.concat [['spec', 'spec', current_runner]]
@@ -151,14 +151,14 @@ class Autospec::Manager
# try focus tag
if failed_specs.length > 0
filename,_ = failed_specs[0].split(":")
filename, _ = failed_specs[0].split(":")
if filename && File.exist?(filename) && !File.directory?(filename)
spec = File.read(filename)
start,_ = spec.split(/\S*#focus\S*$/)
start, _ = spec.split(/\S*#focus\S*$/)
if start.length < spec.length
line = start.scan(/\n/).length + 1
puts "Found #focus tag on line #{line}!"
failed_specs = ["#{filename}:#{line+1}"]
failed_specs = ["#{filename}:#{line + 1}"]
end
end
end
@@ -188,7 +188,7 @@ class Autospec::Manager
FileUtils.rm_f(socket_path)
server = SocketServer.new(socket_path)
server.start do |line|
file,line = line.split(' ')
file, line = line.split(' ')
file = file.sub(Rails.root.to_s << "/", "")
# process_change can aquire a mutex and block
# the acceptor
@@ -196,7 +196,7 @@ class Autospec::Manager
if file =~ /(es6|js)$/
process_change([[file]])
else
process_change([[file,line]])
process_change([[file, line]])
end
end
"OK"
@@ -213,7 +213,7 @@ class Autospec::Manager
listener = Listen.to("#{path}/#{watch}", options) do |modified, added, _|
paths = [modified, added].flatten
paths.compact!
paths.map!{|long| long[(path.length+1)..-1]}
paths.map! { |long| long[(path.length + 1)..-1] }
process_change(paths)
end
listener.start
@@ -246,7 +246,7 @@ class Autospec::Manager
end
end
# watchers
runner.watchers.each do |k,v|
runner.watchers.each do |k, v|
if m = k.match(file)
puts "@@@@@@@@@@@@ #{file} matched a watcher for #{runner}" if @debug
hit = true

View File

@@ -144,7 +144,7 @@ module Autospec
end
def try_to_find_module_name(file)
file,_ = file.split(/:\d+$/)
file, _ = file.split(/:\d+$/)
return unless File.exists?(file)
File.open(file, "r").each_line do |line|
if m = /module\(['"]([^'"]+)/i.match(line)

View File

@@ -19,8 +19,8 @@ module Autospec
watch(%r{^spec/fabricators/.+_fabricator\.rb$}) { "spec" }
watch(%r{^app/assets/javascripts/pretty-text/.*\.js\.es6$}) { "spec/components/pretty_text_spec.rb"}
watch(%r{^plugins/.*/discourse-markdown/.*\.js\.es6$}) { "spec/components/pretty_text_spec.rb"}
watch(%r{^app/assets/javascripts/pretty-text/.*\.js\.es6$}) { "spec/components/pretty_text_spec.rb" }
watch(%r{^plugins/.*/discourse-markdown/.*\.js\.es6$}) { "spec/components/pretty_text_spec.rb" }
watch(%r{^plugins/.*/spec/.*\.rb})

View File

@@ -13,8 +13,8 @@ module Autospec
"-f", "Autospec::Formatter", specs.split].flatten.join(" ")
# launch rspec
Dir.chdir(Rails.root) do
env = {"RAILS_ENV" => "test"}
if specs.split(' ').any?{|s| s =~ /^(.\/)?plugins/}
env = { "RAILS_ENV" => "test" }
if specs.split(' ').any? { |s| s =~ /^(.\/)?plugins/ }
env["LOAD_PLUGINS"] = "1"
puts "Loading plugins while running specs"
end

View File

@@ -30,7 +30,7 @@ module Autospec
def run(specs)
args = ["-r", "#{File.dirname(__FILE__)}/formatter.rb",
"-f", "Autospec::Formatter", specs.split].flatten
spork_service.run(args,$stderr,$stdout)
spork_service.run(args, $stderr, $stdout)
end
def reload
@@ -66,7 +66,7 @@ module Autospec
def write_pid_file(file, pid)
FileUtils.mkdir_p(Rails.root + "tmp/pids")
File.open(file,'w') do |f|
File.open(file, 'w') do |f|
f.write(pid)
end
end
@@ -95,7 +95,7 @@ module Autospec
sleep 1
end
@spork_pid = Process.spawn({'RAILS_ENV' => 'test'}, "bundle exec spork")
@spork_pid = Process.spawn({ 'RAILS_ENV' => 'test' }, "bundle exec spork")
write_pid_file(spork_pid_file, @spork_pid)
running = false

View File

@@ -1,6 +1,6 @@
class AvatarLookup
def initialize(user_ids=[])
def initialize(user_ids = [])
@user_ids = user_ids.tap(&:compact!).tap(&:uniq!).tap(&:flatten!)
end
@@ -12,7 +12,7 @@ class AvatarLookup
private
def self.lookup_columns
@lookup_columns ||= %i{id email username uploaded_avatar_id}
@lookup_columns ||= %i{id user_emails.email username uploaded_avatar_id}
end
def users
@@ -22,9 +22,10 @@ class AvatarLookup
def user_lookup_hash
# adding tap here is a personal taste thing
hash = {}
User.where(:id => @user_ids)
.select(AvatarLookup.lookup_columns)
.each{ |user| hash[user.id] = user }
User.joins(:user_emails)
.where(id: @user_ids)
.select(AvatarLookup.lookup_columns)
.each { |user| hash[user.id] = user }
hash
end
end

View File

@@ -11,11 +11,11 @@ module BackupRestore
METADATA_FILE = "meta.json"
LOGS_CHANNEL = "/admin/backups/logs"
def self.backup!(user_id, opts={})
def self.backup!(user_id, opts = {})
start! BackupRestore::Backuper.new(user_id, opts)
end
def self.restore!(user_id, opts={})
def self.restore!(user_id, opts = {})
start! BackupRestore::Restorer.new(user_id, opts)
end

View File

@@ -3,7 +3,7 @@ module BackupRestore
class Backuper
attr_reader :success
def initialize(user_id, opts={})
def initialize(user_id, opts = {})
@user_id = user_id
@client_id = opts[:client_id]
@publish_to_message_bus = opts[:publish_to_message_bus] || false

View File

@@ -8,7 +8,7 @@ module BackupRestore
class Restorer
attr_reader :success
def initialize(user_id, opts={})
def initialize(user_id, opts = {})
@user_id = user_id
@client_id = opts[:client_id]
@filename = opts[:filename]
@@ -400,7 +400,7 @@ module BackupRestore
end
def notify_user
if user = User.find_by(email: @user_info[:email])
if user = User.find_by_email(@user_info[:email])
log "Notifying '#{user.username}' of the end of the restore..."
status = @success ? :restore_succeeded : :restore_failed

View File

@@ -133,44 +133,44 @@ SQL
GROUP BY acting_user_id
SQL
def self.invite_badge(count,trust_level)
"
SELECT u.id user_id, current_timestamp granted_at
FROM users u
WHERE u.id IN (
SELECT invited_by_id
FROM invites i
JOIN users u2 ON u2.id = i.user_id
WHERE i.deleted_at IS NULL AND u2.active AND u2.trust_level >= #{trust_level.to_i} AND not u2.blocked
GROUP BY invited_by_id
HAVING COUNT(*) >= #{count.to_i}
) AND u.active AND NOT u.blocked AND u.id > 0 AND
(:backfill OR u.id IN (:user_ids) )
"
def self.invite_badge(count, trust_level)
"
SELECT u.id user_id, current_timestamp granted_at
FROM users u
WHERE u.id IN (
SELECT invited_by_id
FROM invites i
JOIN users u2 ON u2.id = i.user_id
WHERE i.deleted_at IS NULL AND u2.active AND u2.trust_level >= #{trust_level.to_i} AND not u2.blocked
GROUP BY invited_by_id
HAVING COUNT(*) >= #{count.to_i}
) AND u.active AND NOT u.blocked AND u.id > 0 AND
(:backfill OR u.id IN (:user_ids) )
"
end
def self.like_badge(count, is_topic)
# we can do better with dates, but its hard work
"
SELECT p.user_id, p.id post_id, p.updated_at granted_at
FROM badge_posts p
WHERE #{is_topic ? "p.post_number = 1" : "p.post_number > 1" } AND p.like_count >= #{count.to_i} AND
(:backfill OR p.id IN (:post_ids) )
"
"
SELECT p.user_id, p.id post_id, p.updated_at granted_at
FROM badge_posts p
WHERE #{is_topic ? "p.post_number = 1" : "p.post_number > 1" } AND p.like_count >= #{count.to_i} AND
(:backfill OR p.id IN (:post_ids) )
"
end
def self.trust_level(level)
# we can do better with dates, but its hard work figuring this out historically
"
SELECT u.id user_id, current_timestamp granted_at FROM users u
WHERE trust_level >= #{level.to_i} AND (
:backfill OR u.id IN (:user_ids)
)
"
"
SELECT u.id user_id, current_timestamp granted_at FROM users u
WHERE trust_level >= #{level.to_i} AND (
:backfill OR u.id IN (:user_ids)
)
"
end
def self.sharing_badge(count)
<<SQL
<<SQL
SELECT views.user_id, i2.post_id, current_timestamp granted_at
FROM
(

View File

@@ -27,7 +27,7 @@ class Cache < ActiveSupport::Cache::Store
end
end
def namespaced_key(key, opts=nil)
def namespaced_key(key, opts = nil)
"#{@namespace}:" << key
end

View File

@@ -10,11 +10,13 @@ module CategoryBadge
end
def self.inline_badge_wrapper_style
style = case (SiteSetting.category_style || :box).to_sym
when :bar then 'line-height: 1.25; margin-right: 5px;'
when :box then 'line-height: 1.5; margin-top: 5px; margin-right: 5px;'
when :bullet then 'line-height: 1; margin-right: 10px;'
end
style =
case (SiteSetting.category_style || :box).to_sym
when :bar then 'line-height: 1.25; margin-right: 5px;'
when :box then 'line-height: 1.5; margin-top: 5px; margin-right: 5px;'
when :bullet then 'line-height: 1; margin-right: 10px;'
end
" style='font-size: 0.857em; white-space: nowrap; display: inline-block; position: relative; #{style}'"
end
@@ -34,34 +36,41 @@ module CategoryBadge
# parent span
unless category.parent_category_id.nil? || opts[:hide_parent]
parent_category = Category.find_by(id: category.parent_category_id)
result << if opts[:inline_style]
case (SiteSetting.category_style || :box).to_sym
when :bar then inline_category_stripe(parent_category.color, 'display: inline-block; padding: 1px;', true)
when :box then inline_category_stripe(parent_category.color, 'display: block; position: absolute; width: 100%; height: 100%;')
when :bullet then inline_category_stripe(parent_category.color, 'display: inline-block; width: 5px; height: 10px; line-height: 1;')
result <<
if opts[:inline_style]
case (SiteSetting.category_style || :box).to_sym
when :bar
inline_category_stripe(parent_category.color, 'display: inline-block; padding: 1px;', true)
when :box
inline_category_stripe(parent_category.color, 'display: block; position: absolute; width: 100%; height: 100%;')
when :bullet
inline_category_stripe(parent_category.color, 'display: inline-block; width: 5px; height: 10px; line-height: 1;')
end
else
category_stripe(parent_category.color, 'badge-category-parent-bg')
end
else
category_stripe(parent_category.color, 'badge-category-parent-bg')
end
end
show_parent = category.parent_category_id && !opts[:hide_parent]
# sub parent or main category span
result << if opts[:inline_style]
case (SiteSetting.category_style || :box).to_sym
when :bar then inline_category_stripe(category.color, 'display: inline-block; padding: 1px;', true)
when :box
unless show_parent
inline_category_stripe(category.color, 'display: block; position: absolute; width: 100%; height: 100%;')
else
inline_category_stripe(category.color, 'left: 5px; display: block; position: absolute; width: calc(100% - 5px); height: 100%;')
result <<
if opts[:inline_style]
case (SiteSetting.category_style || :box).to_sym
when :bar
inline_category_stripe(category.color, 'display: inline-block; padding: 1px;', true)
when :box
unless show_parent
inline_category_stripe(category.color, 'display: block; position: absolute; width: 100%; height: 100%;')
else
inline_category_stripe(category.color, 'left: 5px; display: block; position: absolute; width: calc(100% - 5px); height: 100%;')
end
when :bullet
inline_category_stripe(category.color, "display: inline-block; width: #{category.parent_category_id.nil? ? 10 : 5}px; height: 10px;")
end
when :bullet then inline_category_stripe(category.color, "display: inline-block; width: #{category.parent_category_id.nil? ? 10 : 5}px; height: 10px;")
else
category_stripe(category.color, 'badge-category-bg')
end
else
category_stripe(category.color, 'badge-category-bg')
end
# category name
class_names = 'badge-category clear-badge'
@@ -69,11 +78,15 @@ module CategoryBadge
description = category.description_text ? "title='#{category.description_text.html_safe}'" : ''
category_url = opts[:absolute_url] ? "#{Discourse.base_url_no_prefix}#{category.url}" : category.url
extra_span_classes = if opts[:inline_style]
extra_span_classes =
if opts[:inline_style]
case (SiteSetting.category_style || :box).to_sym
when :bar then 'padding: 3px; color: #222222 !important; vertical-align: text-top; margin-top: -3px; display: inline-block;'
when :box then "#{show_parent ? 'margin-left: 5px; ' : ''} position: relative; padding: 0 5px; margin-top: 2px;"
when :bullet then 'color: #222222 !important; vertical-align: text-top; line-height: 1; margin-left: 4px; padding-left: 2px; display: inline;'
when :bar
'padding: 3px; color: #222222 !important; vertical-align: text-top; margin-top: -3px; display: inline-block;'
when :box
"#{show_parent ? 'margin-left: 5px; ' : ''} position: relative; padding: 0 5px; margin-top: 2px;"
when :bullet
'color: #222222 !important; vertical-align: text-top; line-height: 1; margin-left: 4px; padding-left: 2px; display: inline;'
end + 'max-width: 150px; overflow: hidden; text-overflow: ellipsis;'
else
''

View File

@@ -8,31 +8,67 @@ class ColumnDropper
delay ||= Rails.env.production? ? 60 : 0
sql = <<SQL
sql = <<~SQL
SELECT 1
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = 'public' AND
table_name = :table AND
column_name IN (:columns) AND
EXISTS (
SELECT 1
FROM schema_migration_details
WHERE name = :after_migration AND
created_at <= (current_timestamp at time zone 'UTC' - interval :delay)
)
table_name = :table AND
column_name IN (:columns) AND
EXISTS (
SELECT 1
FROM schema_migration_details
WHERE name = :after_migration AND
created_at <= (current_timestamp at time zone 'UTC' - interval :delay)
)
LIMIT 1
SQL
SQL
if ActiveRecord::Base.exec_sql(sql, table: table,
columns: columns,
delay: "#{delay.to_i || 0} seconds",
after_migration: after_migration).to_a.length > 0
on_drop&.call
on_drop&.call
columns.each do |column|
# safe cause it is protected on method entry, can not be passed in params
ActiveRecord::Base.exec_sql("ALTER TABLE #{table} DROP COLUMN IF EXISTS #{column}")
end
columns.each do |column|
# safe cause it is protected on method entry, can not be passed in params
ActiveRecord::Base.exec_sql("ALTER TABLE #{table} DROP COLUMN IF EXISTS #{column}")
ActiveRecord::Base.exec_sql <<~SQL
DROP FUNCTION IF EXISTS #{readonly_function_name(table, column)};
DROP TRIGGER IF EXISTS #{readonly_trigger_name(table, column)} ON #{table};
SQL
end
Discourse.reset_active_record_cache
end
end
def self.mark_readonly(table_name, column_name)
ActiveRecord::Base.exec_sql <<-SQL
CREATE OR REPLACE FUNCTION #{readonly_function_name(table_name, column_name)} RETURNS trigger AS $rcr$
BEGIN
RAISE EXCEPTION 'Discourse: #{column_name} in #{table_name} is readonly';
END
$rcr$ LANGUAGE plpgsql;
SQL
ActiveRecord::Base.exec_sql <<-SQL
CREATE TRIGGER #{readonly_trigger_name(table_name, column_name)}
BEFORE INSERT OR UPDATE OF #{column_name}
ON #{table_name}
FOR EACH ROW
WHEN (NEW.#{column_name} IS NOT NULL)
EXECUTE PROCEDURE #{readonly_function_name(table_name, column_name)};
SQL
end
private
def self.readonly_function_name(table_name, column_name)
"raise_#{table_name}_#{column_name}_readonly()"
end
def self.readonly_trigger_name(table_name, column_name)
"#{table_name}_#{column_name}_readonly"
end
end

View File

@@ -7,7 +7,7 @@ class ComposerMessagesFinder
end
def self.check_methods
@check_methods ||= instance_methods.find_all {|m| m =~ /^check\_/}
@check_methods ||= instance_methods.find_all { |m| m =~ /^check\_/ }
end
def find
@@ -70,7 +70,7 @@ class ComposerMessagesFinder
return if SiteSetting.disable_avatar_education_message || SiteSetting.sso_overrides_avatar || !SiteSetting.allow_uploaded_avatars
# If we got this far, log that we've nagged them about the avatar
UserHistory.create!(action: UserHistory.actions[:notified_about_avatar], target_user_id: @user.id )
UserHistory.create!(action: UserHistory.actions[:notified_about_avatar], target_user_id: @user.id)
# Return the message
{
@@ -86,19 +86,19 @@ class ComposerMessagesFinder
# Count the topics made by this user in the last day
recent_posts_user_ids = Post.where(topic_id: @details[:topic_id])
.where("created_at > ?", 1.day.ago)
.order('created_at desc')
.limit(SiteSetting.sequential_replies_threshold)
.pluck(:user_id)
.where("created_at > ?", 1.day.ago)
.order('created_at desc')
.limit(SiteSetting.sequential_replies_threshold)
.pluck(:user_id)
# Did we get back as many posts as we asked for, and are they all by the current user?
return if recent_posts_user_ids.size != SiteSetting.sequential_replies_threshold ||
recent_posts_user_ids.detect {|u| u != @user.id }
recent_posts_user_ids.detect { |u| u != @user.id }
# If we got this far, log that we've nagged them about the sequential replies
UserHistory.create!(action: UserHistory.actions[:notified_about_sequential_replies],
target_user_id: @user.id,
topic_id: @details[:topic_id] )
topic_id: @details[:topic_id])
{
id: 'sequential_replies',
@@ -149,7 +149,7 @@ class ComposerMessagesFinder
order('created_at desc').
limit(SiteSetting.get_a_room_threshold).
pluck(:reply_to_user_id).
find_all {|uid| uid != @user.id && uid == reply_to_user_id}
find_all { |uid| uid != @user.id && uid == reply_to_user_id }
return unless last_x_replies.size == SiteSetting.get_a_room_threshold
return unless @topic.posts.count('distinct user_id') >= min_users_posted

View File

@@ -35,7 +35,7 @@ class ContentBuffer
end
# fix last line
@lines[start_row] << @lines[finish_row][finish_col-1..-1]
@lines[start_row] << @lines[finish_row][finish_col - 1..-1]
end
if transform[:operation] == :insert

View File

@@ -9,7 +9,7 @@ class CookedPostProcessor
attr_reader :cooking_options
def initialize(post, opts={})
def initialize(post, opts = {})
@dirty = false
@opts = opts
@post = post
@@ -63,7 +63,7 @@ class CookedPostProcessor
upload_ids |= oneboxed_image_uploads.pluck(:id)
values = upload_ids.map{ |u| "(#{@post.id},#{u})" }.join(",")
values = upload_ids.map { |u| "(#{@post.id},#{u})" }.join(",")
PostUpload.transaction do
PostUpload.delete_all(post_id: @post.id)
if upload_ids.length > 0
@@ -80,8 +80,6 @@ class CookedPostProcessor
limit_size!(img)
convert_to_link!(img)
end
update_post_image
end
def extract_images
@@ -102,8 +100,6 @@ class CookedPostProcessor
@doc.css("img[src]") -
# minus, emojis
@doc.css("img.emoji") -
# minus, image inside oneboxes
oneboxed_images -
# minus, images inside quotes
@doc.css(".quote img")
end
@@ -142,11 +138,11 @@ class CookedPostProcessor
original_width, original_height = original_image_size.map(&:to_f)
if w > 0
ratio = w/original_width
[w.floor, (original_height*ratio).floor]
ratio = w / original_width
[w.floor, (original_height * ratio).floor]
else
ratio = h/original_height
[(original_width*ratio).floor, h.floor]
ratio = h / original_height
[(original_width * ratio).floor, h.floor]
end
end
end
@@ -238,7 +234,7 @@ class CookedPostProcessor
false
end
def add_lightbox!(img, original_width, original_height, upload=nil)
def add_lightbox!(img, original_width, original_height, upload = nil)
# first, create a div to hold our lightbox
lightbox = Nokogiri::XML::Node.new("div", @doc)
lightbox["class"] = "lightbox-wrapper"
@@ -283,7 +279,7 @@ class CookedPostProcessor
return I18n.t("upload.pasted_image_filename")
end
def create_span_node(klass, content=nil)
def create_span_node(klass, content = nil)
span = Nokogiri::XML::Node.new("span", @doc)
span.content = content if content
span["class"] = klass
@@ -292,6 +288,8 @@ class CookedPostProcessor
def update_post_image
img = extract_images_for_post.first
return if img.blank?
if img["src"].present?
@post.update_column(:image_url, img["src"][0...255]) # post
@post.topic.update_column(:image_url, img["src"][0...255]) if @post.is_first_post? # topic
@@ -310,6 +308,11 @@ class CookedPostProcessor
Oneboxer.onebox(url, args)
end
update_post_image
# make sure we grab dimensions for oneboxed images
oneboxed_images.each { |img| limit_size!(img) }
uploads = oneboxed_image_uploads.select(:url, :origin)
oneboxed_images.each do |img|
upload = uploads.detect { |u| u.origin == img["src"] }
@@ -374,7 +377,7 @@ class CookedPostProcessor
# log the site setting change
reason = I18n.t("disable_remote_images_download_reason")
staff_action_logger = StaffActionLogger.new(Discourse.system_user)
staff_action_logger.log_site_setting_change("download_remote_images_to_local", true, false, { details: reason })
staff_action_logger.log_site_setting_change("download_remote_images_to_local", true, false, details: reason)
# also send a private message to the site contact user
notify_about_low_disk_space

View File

@@ -8,19 +8,18 @@ module CurrentUser
Discourse.current_user_provider.new(env).current_user
end
# can be used to pretend current user does no exist, for CSRF attacks
def clear_current_user
@current_user_provider = Discourse.current_user_provider.new({})
end
def log_on_user(user)
current_user_provider.log_on_user(user,session,cookies)
current_user_provider.log_on_user(user, session, cookies)
user.logged_in
end
def log_off_user
current_user_provider.log_off_user(session,cookies)
current_user_provider.log_off_user(session, cookies)
end
def is_api?
@@ -36,7 +35,7 @@ module CurrentUser
end
def refresh_session(user)
current_user_provider.refresh_session(user,session,cookies)
current_user_provider.refresh_session(user, session, cookies)
end
private

View File

@@ -7,7 +7,7 @@ class Demon::Base
@demons
end
def self.start(count=1)
def self.start(count = 1)
@demons ||= {}
count.times do |i|
(@demons["#{prefix}_#{i}"] ||= new(i)).start
@@ -50,7 +50,7 @@ class Demon::Base
"#{Rails.root}/tmp/pids/#{self.class.prefix}_#{@index}.pid"
end
def alive?(pid=nil)
def alive?(pid = nil)
pid ||= @pid
if pid
Demon::Base.alive?(pid)
@@ -63,14 +63,14 @@ class Demon::Base
@started = false
if @pid
# TODO configurable stop signal
Process.kill("HUP",@pid)
Process.kill("HUP", @pid)
wait_for_stop = lambda {
timeout = @stop_timeout
while alive? && timeout > 0
timeout -= (@stop_timeout/10.0)
sleep(@stop_timeout/10.0)
timeout -= (@stop_timeout / 10.0)
sleep(@stop_timeout / 10.0)
Process.waitpid(@pid, Process::WNOHANG) rescue -1
end
@@ -86,7 +86,6 @@ class Demon::Base
wait_for_stop.call
@pid = nil
@started = false
end
@@ -116,7 +115,7 @@ class Demon::Base
if existing = already_running?
# should not happen ... so kill violently
STDERR.puts "Attempting to kill pid #{existing}"
Process.kill("TERM",existing)
Process.kill("TERM", existing)
end
@started = true
@@ -156,7 +155,7 @@ class Demon::Base
def write_pid_file
FileUtils.mkdir_p(Rails.root + "tmp/pids")
File.open(pid_file,'w') do |f|
File.open(pid_file, 'w') do |f|
f.write(@pid)
end
end
@@ -182,7 +181,6 @@ class Demon::Base
end
end
def suppress_stdout
true
end

View File

@@ -12,9 +12,9 @@ class Demon::RailsAutospec < Demon::Base
require "rack"
ENV["RAILS_ENV"] = "test"
Rack::Server.start(
:config => "config.ru",
:AccessLog => [],
:Port => ENV["TEST_SERVER_PORT"] || 60099,
config: "config.ru",
AccessLog: [],
Port: ENV["TEST_SERVER_PORT"] || 60099,
)
rescue => e
STDERR.puts e.message

View File

@@ -7,7 +7,7 @@ class Demon::Sidekiq < Demon::Base
end
def self.after_fork(&blk)
blk ? (@blk=blk) : @blk
blk ? (@blk = blk) : @blk
end
private

View File

@@ -2,7 +2,7 @@ module DirectoryHelper
def tmp_directory(prefix)
directory_cache[prefix] ||= begin
f = File.join( Rails.root, 'tmp', Time.now.strftime("#{prefix}%Y%m%d%H%M%S") )
f = File.join(Rails.root, 'tmp', Time.now.strftime("#{prefix}%Y%m%d%H%M%S"))
FileUtils.mkdir_p(f) unless Dir[f].present?
f
end

View File

@@ -63,7 +63,7 @@ module Discourse
# When they don't have permission to do something
class InvalidAccess < StandardError
attr_reader :obj
def initialize(msg=nil, obj=nil)
def initialize(msg = nil, obj = nil)
super(msg)
@obj = obj
end
@@ -115,7 +115,6 @@ module Discourse
set
end
def self.activate_plugins!
all_plugins = Plugin::Instance.find_all("#{Rails.root}/plugins")
@@ -144,11 +143,11 @@ module Discourse
end
def self.official_plugins
plugins.find_all{|p| p.metadata.official?}
plugins.find_all { |p| p.metadata.official? }
end
def self.unofficial_plugins
plugins.find_all{|p| !p.metadata.official?}
plugins.find_all { |p| !p.metadata.official? }
end
def self.assets_digest
@@ -214,6 +213,25 @@ module Discourse
base_url_no_prefix + base_uri
end
def self.route_for(uri)
uri = URI(uri) rescue nil unless (uri.is_a?(URI))
return unless uri
path = uri.path || ""
if (uri.host == Discourse.current_hostname &&
path.start_with?(Discourse.base_uri)) ||
!uri.host
path.slice!(Discourse.base_uri)
return Rails.application.routes.recognize_path(path)
end
nil
rescue ActionController::RoutingError
nil
end
READONLY_MODE_KEY_TTL ||= 60
READONLY_MODE_KEY ||= 'readonly_mode'.freeze
PG_READONLY_MODE_KEY ||= 'readonly_mode:postgres'.freeze
@@ -359,7 +377,7 @@ module Discourse
Rails.cache.reconnect
Logster.store.redis.reconnect
# shuts down all connections in the pool
Sidekiq.redis_pool.shutdown{|c| nil}
Sidekiq.redis_pool.shutdown { |c| nil }
# re-establish
Sidekiq.redis = sidekiq_redis_config
start_connection_reaper
@@ -383,7 +401,7 @@ module Discourse
sleep GlobalSetting.connection_reaper_interval
reap_connections(GlobalSetting.connection_reaper_age, GlobalSetting.connection_reaper_max_age)
rescue => e
Discourse.handle_exception(e, {message: "Error reaping connections"})
Discourse.handle_exception(e, message: "Error reaping connections")
end
end
end
@@ -391,7 +409,7 @@ module Discourse
def self.reap_connections(idle, max_age)
pools = []
ObjectSpace.each_object(ActiveRecord::ConnectionAdapters::ConnectionPool){|pool| pools << pool}
ObjectSpace.each_object(ActiveRecord::ConnectionAdapters::ConnectionPool) { |pool| pools << pool }
pools.each do |pool|
pool.drain(idle.seconds, max_age.seconds)
@@ -414,7 +432,7 @@ module Discourse
def self.reset_active_record_cache_if_needed(e)
last_cache_reset = Discourse.last_ar_cache_reset
if e && e.message =~ /UndefinedColumn/ && (last_cache_reset.nil? || last_cache_reset < 30.seconds.ago)
if e && e.message =~ /UndefinedColumn/ && (last_cache_reset.nil? || last_cache_reset < 30.seconds.ago)
Rails.logger.warn "Clear Active Record cache cause schema appears to have changed!"
Discourse.last_ar_cache_reset = Time.zone.now
Discourse.reset_active_record_cache
@@ -429,5 +447,4 @@ module Discourse
nil
end
end

View File

@@ -1,6 +1,6 @@
class ActionDispatch::Session::DiscourseCookieStore < ActionDispatch::Session::CookieStore
def initialize(app, options={})
super(app,options)
def initialize(app, options = {})
super(app, options)
end
private

View File

@@ -5,7 +5,7 @@ module DiscourseHub
STATS_FETCHED_AT_KEY = "stats_fetched_at"
def self.version_check_payload
default_payload = { installed_version: Discourse::VERSION::STRING }.merge!(Discourse.git_branch == "unknown" ? {} : {branch: Discourse.git_branch})
default_payload = { installed_version: Discourse::VERSION::STRING }.merge!(Discourse.git_branch == "unknown" ? {} : { branch: Discourse.git_branch })
default_payload.merge!(get_payload)
end
@@ -23,23 +23,23 @@ module DiscourseHub
SiteSetting.share_anonymized_statistics && stats_fetched_at < 7.days.ago ? About.fetch_cached_stats.symbolize_keys : {}
end
def self.get(rel_url, params={})
def self.get(rel_url, params = {})
singular_action :get, rel_url, params
end
def self.post(rel_url, params={})
def self.post(rel_url, params = {})
collection_action :post, rel_url, params
end
def self.put(rel_url, params={})
def self.put(rel_url, params = {})
collection_action :put, rel_url, params
end
def self.delete(rel_url, params={})
def self.delete(rel_url, params = {})
singular_action :delete, rel_url, params
end
def self.singular_action(action, rel_url, params={})
def self.singular_action(action, rel_url, params = {})
JSON.parse(Excon.send(action,
"#{hub_base_url}#{rel_url}",
headers: { 'Referer' => referer, 'Accept' => accepts.join(', ') },
@@ -48,7 +48,7 @@ module DiscourseHub
).body)
end
def self.collection_action(action, rel_url, params={})
def self.collection_action(action, rel_url, params = {})
JSON.parse(Excon.send(action,
"#{hub_base_url}#{rel_url}",
body: JSON[params],

View File

@@ -27,10 +27,10 @@ class DiscoursePlugin
# Find the modules defined in the plugin with "Mixin" in their name.
def self.mixins
constants.map { |const_name| const_get(const_name) }
.select { |const| const.class == Module && const.name["Mixin"] }
.select { |const| const.class == Module && const.name["Mixin"] }
end
def register_js(file, opts={})
def register_js(file, opts = {})
@registry.register_js(file, opts)
end
@@ -38,7 +38,7 @@ class DiscoursePlugin
@registry.register_css(file)
end
def register_archetype(name, options={})
def register_archetype(name, options = {})
@registry.register_archetype(name, options)
end
@@ -48,4 +48,3 @@ class DiscoursePlugin
end
end

View File

@@ -70,7 +70,7 @@ class DiscoursePluginRegistry
end
def register_js(filename, options={})
def register_js(filename, options = {})
# If we have a server side option, add that too.
self.class.javascripts << filename
end
@@ -79,15 +79,15 @@ class DiscoursePluginRegistry
self.class.stylesheets << filename
end
def register_archetype(name, options={})
def register_archetype(name, options = {})
Archetype.register(name, options)
end
def self.register_glob(root, extension, options=nil)
def self.register_glob(root, extension, options = nil)
self.asset_globs << [root, extension, options || {}]
end
def self.each_globbed_asset(each_options=nil)
def self.each_globbed_asset(each_options = nil)
each_options ||= {}
self.asset_globs.each do |g|
@@ -108,7 +108,7 @@ class DiscoursePluginRegistry
JS_REGEX = /\.js$|\.js\.erb$|\.js\.es6$/
HANDLEBARS_REGEX = /\.hbs$|\.js\.handlebars$/
def self.register_asset(asset, opts=nil)
def self.register_asset(asset, opts = nil)
if asset =~ JS_REGEX
if opts == :admin
self.admin_javascripts << asset
@@ -140,7 +140,7 @@ class DiscoursePluginRegistry
html_builders[name] = block
end
def self.build_html(name, ctx=nil)
def self.build_html(name, ctx = nil)
html_builders[name]&.call(ctx)
end

View File

@@ -125,10 +125,10 @@ class DiscourseRedis
end
def self.slave_config(options = config)
options.dup.merge!({ host: options[:slave_host], port: options[:slave_port] })
options.dup.merge!(host: options[:slave_host], port: options[:slave_port])
end
def initialize(config=nil)
def initialize(config = nil)
@config = config || DiscourseRedis.config
@redis = DiscourseRedis.raw_connection(@config)
end
@@ -146,7 +146,7 @@ class DiscourseRedis
yield
rescue Redis::CommandError => ex
if ex.message =~ /READONLY/
unless Discourse.recently_readonly?
unless Discourse.recently_readonly? || Rails.env.test?
STDERR.puts "WARN: Redis is in a readonly state. Performed a noop"
end
@@ -182,7 +182,7 @@ class DiscourseRedis
end
def mget(*args)
args.map!{|a| "#{namespace}:#{a}"}
args.map! { |a| "#{namespace}:#{a}" }
DiscourseRedis.ignore_readonly { @redis.mget(*args) }
end
@@ -193,10 +193,10 @@ class DiscourseRedis
end
end
def keys(pattern=nil)
def keys(pattern = nil)
DiscourseRedis.ignore_readonly do
len = namespace.length + 1
@redis.keys("#{namespace}:#{pattern || '*'}").map{
@redis.keys("#{namespace}:#{pattern || '*'}").map {
|k| k[len..-1]
}
end
@@ -210,7 +210,7 @@ class DiscourseRedis
def flushdb
DiscourseRedis.ignore_readonly do
keys.each{|k| del(k)}
keys.each { |k| del(k) }
end
end

View File

@@ -3,7 +3,6 @@ module DiscourseTagging
TAGS_FIELD_NAME = "tags"
TAGS_FILTER_REGEXP = /[\/\?#\[\]@!\$&'\(\)\*\+,;=\.%\\`^\s|\{\}"<>]+/ # /?#[]@!$&'()*+,;=.%\`^|{}"<>
def self.tag_topic_by_names(topic, guardian, tag_names_arg, append: false)
if SiteSetting.tagging_enabled
tag_names = DiscourseTagging.tags_for_saving(tag_names_arg, guardian) || []
@@ -33,11 +32,9 @@ module DiscourseTagging
# guardian is explicitly nil cause we don't want to strip all
# staff tags that already passed validation
tags = filter_allowed_tags(Tag.where(name: tag_names), nil, {
for_input: true,
category: category,
selected_tags: tag_names
}).to_a
tags = filter_allowed_tags(Tag.where(name: tag_names), nil, for_input: true,
category: category,
selected_tags: tag_names).to_a
if tags.size < tag_names.size && (category.nil? || category.tags.count == 0)
tag_names.each do |name|
@@ -51,7 +48,7 @@ module DiscourseTagging
else
topic.tags = []
end
topic.tags_changed=true
topic.tags_changed = true
end
true
end
@@ -61,7 +58,7 @@ module DiscourseTagging
# category: a Category to which the object being tagged belongs
# for_input: result is for an input field, so only show permitted tags
# selected_tags: an array of tag names that are in the current selection
def self.filter_allowed_tags(query, guardian, opts={})
def self.filter_allowed_tags(query, guardian, opts = {})
term = opts[:term]
if term.present?
term.gsub!("_", "\\_")
@@ -124,9 +121,9 @@ module DiscourseTagging
else
# One tag per group restriction
exclude_group_ids = TagGroup.where(one_per_topic: true)
.joins(:tag_group_memberships)
.where('tag_group_memberships.tag_id in (?)', selected_tag_ids)
.pluck(:id)
.joins(:tag_group_memberships)
.where('tag_group_memberships.tag_id in (?)', selected_tag_ids)
.pluck(:id)
if exclude_group_ids.empty?
sql = "tags.id NOT IN (#{select_sql} WHERE tg.parent_tag_id NOT IN (?))"
@@ -135,9 +132,9 @@ module DiscourseTagging
# It's possible that the selected tags violate some one-tag-per-group restrictions,
# so filter them out by picking one from each group.
limit_tag_ids = TagGroupMembership.select('distinct on (tag_group_id) tag_id')
.where(tag_id: selected_tag_ids)
.where(tag_group_id: exclude_group_ids)
.map(&:tag_id)
.where(tag_id: selected_tag_ids)
.where(tag_group_id: exclude_group_ids)
.map(&:tag_id)
sql = "(tags.id NOT IN (#{select_sql} WHERE (tg.parent_tag_id NOT IN (?) OR tg.id in (?))) OR tags.id IN (?))"
query = query.where(sql, selected_tag_ids, exclude_group_ids, limit_tag_ids)
end
@@ -149,8 +146,8 @@ module DiscourseTagging
def self.clean_tag(tag)
tag.downcase.strip
.gsub(/\s+/, '-').squeeze('-')
.gsub(TAGS_FILTER_REGEXP, '')[0...SiteSetting.max_tag_length]
.gsub(/\s+/, '-').squeeze('-')
.gsub(TAGS_FILTER_REGEXP, '')[0...SiteSetting.max_tag_length]
end
def self.staff_only_tags(tags)
@@ -164,7 +161,7 @@ module DiscourseTagging
tag_diff.present? ? tag_diff : nil
end
def self.tags_for_saving(tags_arg, guardian, opts={})
def self.tags_for_saving(tags_arg, guardian, opts = {})
return [] unless guardian.can_tag_topics? && tags_arg.present?
@@ -179,7 +176,7 @@ module DiscourseTagging
return opts[:unlimited] ? tag_names : tag_names[0...SiteSetting.max_tags_per_topic]
end
def self.add_or_create_tags_by_name(taggable, tag_names_arg, opts={})
def self.add_or_create_tags_by_name(taggable, tag_names_arg, opts = {})
tag_names = DiscourseTagging.tags_for_saving(tag_names_arg, Guardian.new(Discourse.system_user), opts) || []
if taggable.tags.pluck(:name).sort != tag_names.sort
taggable.tags = Tag.where(name: tag_names).all

View File

@@ -33,10 +33,10 @@ module DiscourseUpdates
# Handle cases when version check data is old so we report something that makes sense
if (version_info.updated_at.nil? or # never performed a version check
last_installed_version != Discourse::VERSION::STRING or # upgraded since the last version check
(version_info.missing_versions_count == 0 and version_info.latest_version != version_info.installed_version) or # old data
(version_info.missing_versions_count != 0 and version_info.latest_version == version_info.installed_version)) # old data
if (version_info.updated_at.nil? || # never performed a version check
last_installed_version != (Discourse::VERSION::STRING) || # upgraded since the last version check
(version_info.missing_versions_count == (0) && version_info.latest_version != (version_info.installed_version)) || # old data
(version_info.missing_versions_count != (0) && version_info.latest_version == (version_info.installed_version))) # old data
Jobs.enqueue(:version_check, all_sites: true)
version_info.version_check_pending = true
unless version_info.updated_at.nil?
@@ -92,7 +92,7 @@ module DiscourseUpdates
if versions.present?
# store the list in redis
version_keys = []
versions[0,5].each do |v|
versions[0, 5].each do |v|
key = "#{missing_versions_key_prefix}:#{v['version']}"
$redis.mapped_hmset key, v
version_keys << key
@@ -108,7 +108,6 @@ module DiscourseUpdates
keys.present? ? keys.map { |k| $redis.hgetall(k) } : []
end
private
def last_installed_version_key

View File

@@ -17,7 +17,7 @@ class DistributedCache
end
def self.process_message(message)
i = @subscribers.length-1
i = @subscribers.length - 1
payload = message.data
@@ -32,9 +32,9 @@ class DistributedCache
hash = current.hash(message.site_id)
case payload["op"]
when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"]
when "delete" then hash.delete(payload["key"])
when "clear" then hash.clear
when "set" then hash[payload["key"]] = payload["marshalled"] ? Marshal.load(Base64.decode64(payload["value"])) : payload["value"]
when "delete" then hash.delete(payload["key"])
when "clear" then hash.clear
end
rescue WeakRef::RefError
@@ -66,22 +66,22 @@ class DistributedCache
message[:origin] = hash.identity
message[:hash_key] = hash.key
message[:discourse_version] = Discourse.git_version
MessageBus.publish(channel_name, message, { user_ids: [-1] })
MessageBus.publish(channel_name, message, user_ids: [-1])
end
def self.set(hash, key, value)
# special support for set
marshal = (Set === value || Hash === value)
value = Base64.encode64(Marshal.dump(value)) if marshal
publish(hash, { op: :set, key: key, value: value, marshalled: marshal })
publish(hash, op: :set, key: key, value: value, marshalled: marshal)
end
def self.delete(hash, key)
publish(hash, { op: :delete, key: key })
publish(hash, op: :delete, key: key)
end
def self.clear(hash)
publish(hash, { op: :clear })
publish(hash, op: :clear)
end
def self.register(hash)
@@ -103,7 +103,7 @@ class DistributedCache
(@seed_id ||= SecureRandom.hex) + "#{Process.pid}"
end
def []=(k,v)
def []=(k, v)
k = k.to_s if Symbol === k
DistributedCache.set(self, k, v)
hash[k] = v

View File

@@ -19,7 +19,7 @@ class DistributedMemoizer
begin
while Time.new < start + MAX_WAIT && !got_lock
LOCK.synchronize do
got_lock = get_lock(redis,redis_lock_key)
got_lock = get_lock(redis, redis_lock_key)
end
sleep 0.001
end
@@ -38,7 +38,6 @@ class DistributedMemoizer
result
end
def self.redis_lock_key(key)
"memoize_lock_" << key
end

View File

@@ -1,11 +1,11 @@
# Cross-process locking using Redis.
class DistributedMutex
def self.synchronize(key, redis=nil, &blk)
def self.synchronize(key, redis = nil, &blk)
self.new(key, redis).synchronize(&blk)
end
def initialize(key, redis=nil)
def initialize(key, redis = nil)
@key = key
@redis = redis || $redis
@mutex = Mutex.new

View File

@@ -17,7 +17,7 @@ module Email
class MessageBuilder
attr_reader :template_args
def initialize(to, opts=nil)
def initialize(to, opts = nil)
@to = to
@opts = opts || {}
@@ -166,7 +166,6 @@ module Email
result
end
protected
def reply_key
@@ -195,11 +194,13 @@ module Email
@reply_by_email_address = SiteSetting.reply_by_email_address.dup
@reply_by_email_address.gsub!("%{reply_key}", reply_key)
@reply_by_email_address = if private_reply?
alias_email(@reply_by_email_address)
else
site_alias_email(@reply_by_email_address)
end
@reply_by_email_address =
if private_reply?
alias_email(@reply_by_email_address)
else
site_alias_email(@reply_by_email_address)
end
end
def alias_email(source)

View File

@@ -2,12 +2,12 @@ module Email
class Processor
def initialize(mail, retry_on_rate_limit=true)
def initialize(mail, retry_on_rate_limit = true)
@mail = mail
@retry_on_rate_limit = retry_on_rate_limit
end
def self.process!(mail, retry_on_rate_limit=true)
def self.process!(mail, retry_on_rate_limit = true)
Email::Processor.new(mail, retry_on_rate_limit).process!
end
@@ -35,23 +35,24 @@ module Email
def handle_failure(mail_string, e, incoming_email)
message_template = case e
when Email::Receiver::EmptyEmailError then :email_reject_empty
when Email::Receiver::NoBodyDetectedError then :email_reject_empty
when Email::Receiver::UserNotFoundError then :email_reject_user_not_found
when Email::Receiver::ScreenedEmailError then :email_reject_screened_email
when Email::Receiver::AutoGeneratedEmailError then :email_reject_auto_generated
when Email::Receiver::InactiveUserError then :email_reject_inactive_user
when Email::Receiver::BlockedUserError then :email_reject_blocked_user
when Email::Receiver::BadDestinationAddress then :email_reject_bad_destination_address
when Email::Receiver::StrangersNotAllowedError then :email_reject_strangers_not_allowed
when Email::Receiver::InsufficientTrustLevelError then :email_reject_insufficient_trust_level
when Email::Receiver::ReplyUserNotMatchingError then :email_reject_reply_user_not_matching
when Email::Receiver::TopicNotFoundError then :email_reject_topic_not_found
when Email::Receiver::TopicClosedError then :email_reject_topic_closed
when Email::Receiver::InvalidPost then :email_reject_invalid_post
when ActiveRecord::Rollback then :email_reject_invalid_post
when Email::Receiver::InvalidPostAction then :email_reject_invalid_post_action
when Discourse::InvalidAccess then :email_reject_invalid_access
when Email::Receiver::EmptyEmailError then :email_reject_empty
when Email::Receiver::NoBodyDetectedError then :email_reject_empty
when Email::Receiver::UserNotFoundError then :email_reject_user_not_found
when Email::Receiver::ScreenedEmailError then :email_reject_screened_email
when Email::Receiver::AutoGeneratedEmailError then :email_reject_auto_generated
when Email::Receiver::InactiveUserError then :email_reject_inactive_user
when Email::Receiver::BlockedUserError then :email_reject_blocked_user
when Email::Receiver::BadDestinationAddress then :email_reject_bad_destination_address
when Email::Receiver::StrangersNotAllowedError then :email_reject_strangers_not_allowed
when Email::Receiver::InsufficientTrustLevelError then :email_reject_insufficient_trust_level
when Email::Receiver::ReplyUserNotMatchingError then :email_reject_reply_user_not_matching
when Email::Receiver::TopicNotFoundError then :email_reject_topic_not_found
when Email::Receiver::TopicClosedError then :email_reject_topic_closed
when Email::Receiver::InvalidPost then :email_reject_invalid_post
when ActiveRecord::Rollback then :email_reject_invalid_post
when Email::Receiver::InvalidPostAction then :email_reject_invalid_post_action
when Discourse::InvalidAccess then :email_reject_invalid_access
else :email_reject_unrecognized_error
end
template_args = {}
@@ -63,6 +64,14 @@ module Email
template_args[:post_error] = e.message
end
if message_template == :email_reject_unrecognized_error
msg = "Unrecognized error type (#{e.class}: #{e.message}) when processing incoming email"
msg += "\n\nBacktrace:\n#{e.backtrace.map { |l| " #{l}" }.join("\n")}"
msg += "\n\nMail:\n#{mail_string}"
Rails.logger.error(msg)
end
if message_template
# inform the user about the rejection
message = Mail::Message.new(mail_string)
@@ -76,18 +85,14 @@ module Email
if can_send_rejection_email?(message.from, message_template)
Email::Sender.new(client_message, message_template).send
end
else
msg = "Unrecognized error type (#{e.class}: #{e.message}) when processing incoming email"
msg += "\n\nBacktrace:\n#{e.backtrace.map { |l| " #{l}" }.join("\n")}"
msg += "\n\nMail:\n#{mail_string}"
Rails.logger.error(msg)
end
client_message
end
def can_send_rejection_email?(email, type)
return true if type == :email_reject_unrecognized_error
key = "rejection_email:#{email}:#{type}:#{Date.today}"
if $redis.setnx(key, "1")

View File

@@ -153,7 +153,7 @@ module Email
if $redis.setnx(key, "1")
$redis.expire(key, 25.hours)
if user = User.find_by(email: email)
if user = User.find_by_email(email)
user.user_stat.bounce_score += score
user.user_stat.reset_bounce_score_after = SiteSetting.reset_bounce_score_after_days.days.from_now
user.user_stat.save
@@ -166,7 +166,7 @@ module Email
elsif bounce_score >= SiteSetting.bounce_score_threshold
# NOTE: we check bounce_score before sending emails, nothing to do
# here other than log it happened.
reason = I18n.t("user.email.revoked", { email: user.email, date: user.user_stat.reset_bounce_score_after })
reason = I18n.t("user.email.revoked", email: user.email, date: user.user_stat.reset_bounce_score_after)
StaffActionLogger.new(Discourse.system_user).log_revoke_email(user, reason)
end
end
@@ -466,7 +466,7 @@ module Email
true
end
def self.reply_by_email_address_regex(extract_reply_key=true)
def self.reply_by_email_address_regex(extract_reply_key = true)
reply_addresses = [SiteSetting.reply_by_email_address]
reply_addresses << (SiteSetting.alternative_reply_by_email_addresses.presence || "").split("|")
@@ -538,11 +538,11 @@ module Email
PostActionType.types[:like] if likes.include?(body.strip.downcase)
end
def create_topic(options={})
def create_topic(options = {})
create_post_with_attachments(options)
end
def create_reply(options={})
def create_reply(options = {})
raise TopicNotFoundError if options[:topic].nil? || options[:topic].trashed?
if post_action_type = post_action_for(options[:raw])
@@ -572,7 +572,7 @@ module Email
end
end
def create_post_with_attachments(options={})
def create_post_with_attachments(options = {})
# deal with attachments
attachments.each do |attachment|
tmp = Tempfile.new(["discourse-email-attachment", File.extname(attachment.filename)])
@@ -612,7 +612,7 @@ module Email
end
end
def create_post(options={})
def create_post(options = {})
options[:via_email] = true
options[:raw_email] = @raw_email
@@ -622,7 +622,7 @@ module Email
raise InvalidPost, "No post creation date found. Is the e-mail missing a Date: header?"
end
options[:created_at] = DateTime.now if options[:created_at] > DateTime.now
options[:created_at] = DateTime.now if options[:created_at] > DateTime.now
is_private_message = options[:archetype] == Archetype.private_message ||
options[:topic].try(:private_message?)

View File

@@ -3,7 +3,7 @@ require_dependency 'email/styles'
module Email
class Renderer
def initialize(message, opts=nil)
def initialize(message, opts = nil)
@message = message
@opts = opts || {}
end

View File

@@ -15,7 +15,7 @@ SMTP_CLIENT_ERRORS = [Net::SMTPFatalError, Net::SMTPSyntaxError]
module Email
class Sender
def initialize(message, email_type, user=nil)
def initialize(message, email_type, user = nil)
@message = message
@email_type = email_type
@user = user
@@ -55,8 +55,8 @@ module Email
# These are the links we add when a user uploads a file or image.
# Ideally we would parse general markdown into plain text, but that is almost an intractable problem.
url_prefix = Discourse.base_url
@message.parts[0].body = @message.parts[0].body.to_s.gsub(/<a class="attachment" href="(\/uploads\/default\/[^"]+)">([^<]*)<\/a>/, '[\2]('+url_prefix+'\1)')
@message.parts[0].body = @message.parts[0].body.to_s.gsub(/<img src="(\/uploads\/default\/[^"]+)"([^>]*)>/, '![]('+url_prefix+'\1)')
@message.parts[0].body = @message.parts[0].body.to_s.gsub(/<a class="attachment" href="(\/uploads\/default\/[^"]+)">([^<]*)<\/a>/, '[\2](' + url_prefix + '\1)')
@message.parts[0].body = @message.parts[0].body.to_s.gsub(/<img src="(\/uploads\/default\/[^"]+)"([^>]*)>/, '![](' + url_prefix + '\1)')
@message.text_part.content_type = 'text/plain; charset=UTF-8'
@@ -88,8 +88,8 @@ module Email
"<topic/#{topic_id}/#{post_id}@#{host}>"
referenced_posts = Post.includes(:incoming_email)
.where(id: PostReply.where(reply_id: post_id).select(:post_id))
.order(id: :desc)
.where(id: PostReply.where(reply_id: post_id).select(:post_id))
.order(id: :desc)
referenced_post_message_ids = referenced_posts.map do |post|
if post.incoming_email&.message_id.present?
@@ -165,9 +165,9 @@ module Email
when /\.mailjet\.com/
@message.header['X-MJ-CustomID'] = @message.message_id
when "smtp.mandrillapp.com"
merge_json_x_header('X-MC-Metadata', { message_id: @message.message_id })
merge_json_x_header('X-MC-Metadata', message_id: @message.message_id)
when "smtp.sparkpostmail.com"
merge_json_x_header('X-MSYS-API', { metadata: { message_id: @message.message_id } })
merge_json_x_header('X-MSYS-API', metadata: { message_id: @message.message_id })
end
# Suppress images from short emails

View File

@@ -10,7 +10,7 @@ module Email
delegate :css, to: :fragment
def initialize(html, opts=nil)
def initialize(html, opts = nil)
@html = html
@opts = opts || {}
@fragment = Nokogiri::HTML.fragment(@html)
@@ -41,7 +41,7 @@ module Email
img['width'] = img['height'] = 20
else
# use dimensions of original iPhone screen for 'too big, let device rescale'
if img['width'].to_i > 320 or img['height'].to_i > 480
if img['width'].to_i > (320) || img['height'].to_i > (480)
img['width'] = img['height'] = 'auto'
end
end
@@ -246,7 +246,7 @@ module Email
linknum = 0
element.css('a').each do |inner|
# we want the first footer link to be specially highlighted as IMPORTANT
if footernum == 0 and linknum == 0
if footernum == (0) && linknum == (0)
inner['style'] = "background-color: #006699; color:#ffffff; border-top: 4px solid #006699; border-right: 6px solid #006699; border-bottom: 4px solid #006699; border-left: 6px solid #006699; display: inline-block;"
else
inner['style'] = "color:#666;"
@@ -271,7 +271,7 @@ module Email
def style(selector, style, attribs = {})
@fragment.css(selector).each do |element|
add_styles(element, style) if style
attribs.each do |k,v|
attribs.each do |k, v|
element[k] = v
end
end

View File

@@ -7,12 +7,12 @@ class EmailUpdater
attr_reader :user
def initialize(guardian=nil, user=nil)
def initialize(guardian = nil, user = nil)
@guardian = guardian
@user = user
end
def self.human_attribute_name(name, options={})
def self.human_attribute_name(name, options = {})
User.human_attribute_name(name, options)
end
@@ -68,8 +68,8 @@ class EmailUpdater
@user = token.user
change_req = user.email_change_requests
.where('old_email_token_id = :token_id OR new_email_token_id = :token_id', { token_id: token.id})
.first
.where('old_email_token_id = :token_id OR new_email_token_id = :token_id', token_id: token.id)
.first
# Simple state machine
case change_req.try(:change_state)
@@ -81,7 +81,7 @@ class EmailUpdater
confirm_result = :authorizing_new
when EmailChangeRequest.states[:authorizing_new]
change_req.update_column(:change_state, EmailChangeRequest.states[:complete])
user.update_column(:email, token.email)
user.primary_email.update_column(:email, token.email)
confirm_result = :complete
end
else

View File

@@ -829,7 +829,7 @@
"name": "bowing_man"
},
{
"code": "1f926",
"code": "1f926-200d-2642-fe0f",
"name": "man_facepalming"
},
{
@@ -6142,7 +6142,23 @@
"business_suit_levitating",
"woman_juggling",
"man_juggling",
"sleeping_bed"
"sleeping_bed",
"child",
"adult",
"older_adult",
"woman_with_headscarf",
"bearded_person",
"breast_feeding",
"mage",
"fairy",
"vampire",
"merperson",
"elf",
"person_in_steamy_room",
"person_climbing",
"person_in_lotus_position",
"love_you_gesture",
"palms_up_together"
],
"aliases": {
"right_anger_bubble": [

6047
lib/emoji/groups.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -14,7 +14,7 @@ module Tilt
source = input[:data]
context = input[:environment].context_class.new(input)
result = new(filename){source}.render(context)
result = new(filename) { source }.render(context)
context.metadata.merge(data: result)
end
@@ -28,8 +28,8 @@ module Tilt
ctx = MiniRacer::Context.new(timeout: 15000)
ctx.eval("var self = this; #{File.read("#{Rails.root}/vendor/assets/javascripts/babel.js")}")
ctx.eval("module = {}; exports = {};");
ctx.attach("rails.logger.info", proc{|err| Rails.logger.info(err.to_s)})
ctx.attach("rails.logger.error", proc{|err| Rails.logger.error(err.to_s)})
ctx.attach("rails.logger.info", proc { |err| Rails.logger.info(err.to_s) })
ctx.attach("rails.logger.error", proc { |err| Rails.logger.error(err.to_s) })
ctx.eval <<JS
console = {
prefix: "",
@@ -41,6 +41,7 @@ JS
end
def self.reset_context
@ctx&.dispose
@ctx = nil
end
@@ -154,7 +155,7 @@ JS
@output
end
def babel_source(source, opts=nil)
def babel_source(source, opts = nil)
opts ||= {}
@@ -177,7 +178,7 @@ JS
if root_path =~ /(.*\/#{root_base}\/plugins\/[^\/]+)\//
plugin_path = "#{Regexp.last_match[1]}/plugin.rb"
plugin = Discourse.plugins.find {|p| p.path == plugin_path }
plugin = Discourse.plugins.find { |p| p.path == plugin_path }
path = "discourse/plugins/#{plugin.name}/#{logical_path.sub(/javascripts\//, '')}" if plugin
end

View File

@@ -4,7 +4,7 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
SPAN_REGEX = /<\s*span[^>]*class\s*=\s*['|"]excerpt['|"][^>]*>/
def initialize(length, options=nil)
def initialize(length, options = nil)
@length = length
@excerpt = ""
@current_length = 0
@@ -45,13 +45,13 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
end
def include_tag(name, attributes)
characters("<#{name} #{attributes.map{|k,v| "#{k}=\"#{escape_attribute(v)}\""}.join(' ')}>", false, false, false)
characters("<#{name} #{attributes.map { |k, v| "#{k}=\"#{escape_attribute(v)}\"" }.join(' ')}>", false, false, false)
end
def start_element(name, attributes=[])
def start_element(name, attributes = [])
case name
when "img"
attributes = Hash[*attributes.flatten]
when "img"
attributes = Hash[*attributes.flatten]
if attributes["class"] == 'emoji'
if @remap_emoji
@@ -78,28 +78,28 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
characters("(#{attributes['src']})") if @markdown_images
when "a"
unless @strip_links
include_tag(name, attributes)
@in_a = true
end
when "a"
unless @strip_links
include_tag(name, attributes)
@in_a = true
end
when "aside"
attributes = Hash[*attributes.flatten]
when "aside"
attributes = Hash[*attributes.flatten]
unless @keep_onebox_source && attributes['class'].include?('onebox')
@in_quote = true
end
when 'article'
if @keep_onebox_source && attributes.include?(['class', 'onebox-body'])
@in_quote = true
end
when "div", "span"
if attributes.include?(["class", "excerpt"])
@excerpt = ""
@current_length = 0
@start_excerpt = true
end
when 'article'
if @keep_onebox_source && attributes.include?(['class', 'onebox-body'])
@in_quote = true
end
when "div", "span"
if attributes.include?(["class", "excerpt"])
@excerpt = ""
@current_length = 0
@start_excerpt = true
end
# Preserve spoilers
if attributes.include?(["class", "spoiler"])
include_tag("span", attributes)
@@ -112,7 +112,7 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
case name
when "a"
unless @strip_links
characters("</a>",false, false, false)
characters("</a>", false, false, false)
@in_a = false
end
when "p", "br"
@@ -132,7 +132,7 @@ class ExcerptParser < Nokogiri::XML::SAX::Document
def characters(string, truncate = true, count_it = true, encode = true)
return if @in_quote
encode = encode ? lambda{|s| ERB::Util.html_escape(s)} : lambda {|s| s}
encode = encode ? lambda { |s| ERB::Util.html_escape(s) } : lambda { |s| s }
if count_it && @current_length + string.length > @length
length = [0, @length - @current_length - 1].max
@excerpt << encode.call(string[0..length]) if truncate

View File

@@ -48,14 +48,32 @@ class FileHelper
downloaded&.close
end
def self.optimize_image!(filename)
ImageOptim.new(
# GLOBAL
timeout: 15,
skip_missing_workers: true,
# PNG
optipng: { level: 2, strip: SiteSetting.strip_image_metadata },
advpng: false,
pngcrush: false,
pngout: false,
pngquant: false,
# JPG
jpegoptim: { strip: SiteSetting.strip_image_metadata ? "all" : "none" },
jpegtran: false,
jpegrecompress: false,
).optimize_image!(filename)
end
private
def self.images
@@images ||= Set.new %w{jpg jpeg png gif tif tiff bmp svg webp ico}
end
def self.images
@@images ||= Set.new %w{jpg jpeg png gif tif tiff bmp svg webp ico}
end
def self.images_regexp
@@images_regexp ||= /\.(#{images.to_a.join("|")})$/i
end
def self.images_regexp
@@images_regexp ||= /\.(#{images.to_a.join("|")})$/i
end
end

View File

@@ -95,7 +95,7 @@ module FileStore
end
def get_path_for_upload(upload)
get_path_for("original".freeze, upload.id, upload.sha1, upload.extension)
get_path_for("original".freeze, upload.id, upload.sha1, "." + upload.extension)
end
def get_path_for_optimized_image(optimized_image)

View File

@@ -9,7 +9,7 @@ module FileStore
class S3Store < BaseStore
TOMBSTONE_PREFIX ||= "tombstone/"
def initialize(s3_helper=nil)
def initialize(s3_helper = nil)
@s3_helper = s3_helper || S3Helper.new(s3_bucket, TOMBSTONE_PREFIX)
end
@@ -27,7 +27,7 @@ module FileStore
# - filename
# - content_type
# - cache_locally
def store_file(file, path, opts={})
def store_file(file, path, opts = {})
filename = opts[:filename].presence || File.basename(path)
# cache file locally when needed
cache_file(file, File.basename(path)) if opts[:cache_locally]

View File

@@ -2,26 +2,27 @@ class FilterBestPosts
attr_accessor :filtered_posts, :posts
def initialize(topic, filtered_posts, limit, options={})
def initialize(topic, filtered_posts, limit, options = {})
@filtered_posts = filtered_posts
@topic = topic
@limit = limit
options.each do |key, value|
self.instance_variable_set("@#{key}".to_sym, value)
self.instance_variable_set("@#{key}".to_sym, value)
end
filter
end
def filter
@posts = if @min_replies && @topic.posts_count < @min_replies + 1
[]
else
filter_posts_liked_by_moderators
setup_posts
filter_posts_based_on_trust_level
filter_posts_based_on_score
sort_posts
end
@posts =
if @min_replies && @topic.posts_count < @min_replies + 1
[]
else
filter_posts_liked_by_moderators
setup_posts
filter_posts_based_on_trust_level
filter_posts_based_on_score
sort_posts
end
end
private
@@ -39,24 +40,26 @@ class FilterBestPosts
end
def filter_posts_based_on_trust_level
return unless @min_trust_level.try('>',0)
@posts = if @bypass_trust_level_score.try('>',0)
@posts.where('COALESCE(users.trust_level,0) >= ? OR posts.score >= ?',
@min_trust_level,
@bypass_trust_level_score)
else
@posts.where('COALESCE(users.trust_level,0) >= ?', @min_trust_level)
end
return unless @min_trust_level.try('>', 0)
@posts =
if @bypass_trust_level_score.try('>', 0)
@posts.where('COALESCE(users.trust_level,0) >= ? OR posts.score >= ?',
@min_trust_level,
@bypass_trust_level_score
)
else
@posts.where('COALESCE(users.trust_level,0) >= ?', @min_trust_level)
end
end
def filter_posts_based_on_score
return unless @min_score.try('>',0)
return unless @min_score.try('>', 0)
@posts = @posts.where('posts.score >= ?', @min_score)
end
def sort_posts
@posts.to_a.sort!{|a,b| a.post_number <=> b.post_number}
@posts.to_a.sort! { |a, b| a.post_number <=> b.post_number }
end
end

View File

@@ -9,10 +9,11 @@ class FinalDestination
attr_reader :status
attr_reader :cookie
def initialize(url, opts=nil)
def initialize(url, opts = nil)
@url = url
@uri =
begin
URI(URI.escape(url)) if url
URI(escape_url) if @url
rescue URI::InvalidURIError
end
@@ -161,7 +162,7 @@ class FinalDestination
address = IPAddr.new(address_s)
if private_ranges.any? {|r| r === address }
if private_ranges.any? { |r| r === address }
@status = :invalid_address
return false
end
@@ -176,9 +177,13 @@ class FinalDestination
false
end
def escape_url
URI.escape(CGI.unescapeHTML(@url), Regexp.new("[^#{URI::PATTERN::UNRESERVED}#{URI::PATTERN::RESERVED}#]"))
end
def private_ranges
FinalDestination.standard_private_ranges +
SiteSetting.blacklist_ip_blocks.split('|').map {|r| IPAddr.new(r) rescue nil }.compact
SiteSetting.blacklist_ip_blocks.split('|').map { |r| IPAddr.new(r) rescue nil }.compact
end
def self.standard_private_ranges

View File

@@ -1,6 +1,6 @@
module FlagQuery
def self.flagged_posts_report(current_user, filter, offset=0, per_page=25)
def self.flagged_posts_report(current_user, filter, offset = 0, per_page = 25)
actions = flagged_post_actions(filter)
guardian = Guardian.new(current_user)
@@ -12,11 +12,11 @@ module FlagQuery
end
post_ids = actions.limit(per_page)
.offset(offset)
.group(:post_id)
.order('MIN(post_actions.created_at) DESC')
.pluck(:post_id)
.uniq
.offset(offset)
.group(:post_id)
.order('MIN(post_actions.created_at) DESC')
.pluck(:post_id)
.uniq
return nil if post_ids.blank?
@@ -47,8 +47,8 @@ module FlagQuery
end
post_actions = actions.order('post_actions.created_at DESC')
.includes(related_post: { topic: { ordered_posts: :user }})
.where(post_id: post_ids)
.includes(related_post: { topic: { ordered_posts: :user } })
.where(post_id: post_ids)
post_actions.each do |pa|
post = post_lookup[pa.post_id]
@@ -111,10 +111,10 @@ module FlagQuery
def self.flagged_post_actions(filter)
post_actions = PostAction.flags
.joins("INNER JOIN posts ON posts.id = post_actions.post_id")
.joins("INNER JOIN topics ON topics.id = posts.topic_id")
.joins("LEFT JOIN users ON users.id = posts.user_id")
.where("posts.user_id > 0")
.joins("INNER JOIN posts ON posts.id = post_actions.post_id")
.joins("INNER JOIN topics ON topics.id = posts.topic_id")
.joins("LEFT JOIN users ON users.id = posts.user_id")
.where("posts.user_id > 0")
if filter == "old"
post_actions.where("post_actions.disagreed_at IS NOT NULL OR
@@ -122,8 +122,8 @@ module FlagQuery
post_actions.agreed_at IS NOT NULL")
else
post_actions.active
.where("posts.deleted_at" => nil)
.where("topics.deleted_at" => nil)
.where("posts.deleted_at" => nil)
.where("topics.deleted_at" => nil)
end
end

View File

@@ -19,13 +19,12 @@ class ActiveRecord::Base
ActiveRecord::Base.exec_sql(*args)
end
# Executes the given block +retries+ times (or forever, if explicitly given nil),
# catching and retrying SQL Deadlock errors.
#
# Thanks to: http://stackoverflow.com/a/7427186/165668
#
def self.retry_lock_error(retries=5, &block)
def self.retry_lock_error(retries = 5, &block)
begin
yield
rescue ActiveRecord::StatementInvalid => e

View File

@@ -8,7 +8,7 @@ module ActiveModel
# This method is copied over verbatim from the AMS version, except for silently
# ignoring associations that cannot be embedded without a root instead of
# raising an exception.
def include!(name, options={})
def include!(name, options = {})
unique_values =
if hash = options[:hash]
if @options[:hash] == hash

View File

@@ -13,4 +13,3 @@ module Ember
end
end
end

View File

@@ -64,7 +64,7 @@ class ActiveRecord::Relation
columns_hash.key?(cn) ? arel_table[cn] : cn
}
conn.select_raw(relation, nil, relation.arel.bind_values + bind_values) do |result,_|
conn.select_raw(relation, nil, relation.arel.bind_values + bind_values) do |result, _|
result.type_map = SqlBuilder.pg_type_map
result.nfields == 1 ? result.column_values(0) : result.values
end

View File

@@ -23,7 +23,7 @@ module ActiveSupport
define_method(method_name) do |*args|
# this avoids recursive locks
found = true
data = cache.fetch(args){found = false}
data = cache.fetch(args) { found = false }
unless found
cache[args] = data = send(uncached, *args)
end
@@ -56,8 +56,3 @@ module ActiveSupport
end
end
end

View File

@@ -27,7 +27,7 @@ end
class ActiveRecord::ConnectionAdapters::ConnectionPool
# drain all idle connections
# if idle_time is specified only connections idle for N seconds will be drained
def drain(idle_time=nil, max_age=nil)
def drain(idle_time = nil, max_age = nil)
synchronize do
@available.clear
@connections.delete_if do |conn|

View File

@@ -4,7 +4,7 @@ class Rack::ETag
private
def digest_body(body)
parts = []
parts = []
has_body = false
body.each do |part|
@@ -28,15 +28,15 @@ end
class Rack::ConditionalGet
private
def to_rfc2822(since)
# shortest possible valid date is the obsolete: 1 Nov 97 09:55 A
# anything shorter is invalid, this avoids exceptions for common cases
# most common being the empty string
if since && since.length >= 16
# NOTE: there is no trivial way to write this in a non execption way
# _rfc2822 returns a hash but is not that usable
Time.rfc2822(since) rescue nil
else
nil
end
# shortest possible valid date is the obsolete: 1 Nov 97 09:55 A
# anything shorter is invalid, this avoids exceptions for common cases
# most common being the empty string
if since && since.length >= 16
# NOTE: there is no trivial way to write this in a non execption way
# _rfc2822 returns a hash but is not that usable
Time.rfc2822(since) rescue nil
else
nil
end
end
end

View File

@@ -1,4 +1,4 @@
# Sam: This has now forked of rails. Trouble is we would never like to use "about 1 month" ever, we only want months for 2 or more months.
# Sam: This has now forked of rails. Trouble is we would never like to use "about 1 month" ever, we only want months for 2 or more months.
#
# Backporting a fix to rails itself may get too complex
module FreedomPatches
@@ -6,7 +6,7 @@ module FreedomPatches
def self.distance_of_time_in_words(from_time, to_time = 0, include_seconds = false, options = {})
options = {
:scope => :'datetime.distance_in_words',
scope: :'datetime.distance_in_words',
}.merge!(options)
from_time = from_time.to_time if from_time.respond_to?(:to_time)
@@ -15,36 +15,36 @@ module FreedomPatches
distance_in_minutes = (distance / 60.0).round
distance_in_seconds = distance.round
I18n.with_options :locale => options[:locale], :scope => options[:scope] do |locale|
I18n.with_options locale: options[:locale], scope: options[:scope] do |locale|
case distance_in_minutes
when 0..1
return distance_in_minutes == 0 ?
locale.t(:less_than_x_minutes, :count => 1) :
locale.t(:x_minutes, :count => distance_in_minutes) unless include_seconds
when 0..1
return distance_in_minutes == 0 ?
locale.t(:less_than_x_minutes, count: 1) :
locale.t(:x_minutes, count: distance_in_minutes) unless include_seconds
case distance_in_seconds
when 0..4 then locale.t :less_than_x_seconds, :count => 5
when 5..9 then locale.t :less_than_x_seconds, :count => 10
when 10..19 then locale.t :less_than_x_seconds, :count => 20
when 20..39 then locale.t :half_a_minute
when 40..59 then locale.t :less_than_x_minutes, :count => 1
else locale.t :x_minutes, :count => 1
when 0..4 then locale.t :less_than_x_seconds, count: 5
when 5..9 then locale.t :less_than_x_seconds, count: 10
when 10..19 then locale.t :less_than_x_seconds, count: 20
when 20..39 then locale.t :half_a_minute
when 40..59 then locale.t :less_than_x_minutes, count: 1
else locale.t :x_minutes, count: 1
end
when 2..44 then locale.t :x_minutes, :count => distance_in_minutes
when 45..89 then locale.t :about_x_hours, :count => 1
when 90..1439 then locale.t :about_x_hours, :count => (distance_in_minutes.to_f / 60.0).round
when 1440..2519 then locale.t :x_days, :count => 1
when 2..44 then locale.t :x_minutes, count: distance_in_minutes
when 45..89 then locale.t :about_x_hours, count: 1
when 90..1439 then locale.t :about_x_hours, count: (distance_in_minutes.to_f / 60.0).round
when 1440..2519 then locale.t :x_days, count: 1
# this is were we diverge from Rails
when 2520..129599 then locale.t :x_days, :count => (distance_in_minutes.to_f / 1440.0).round
when 129600..525599 then locale.t :x_months, :count => (distance_in_minutes.to_f / 43200.0).round
when 2520..129599 then locale.t :x_days, count: (distance_in_minutes.to_f / 1440.0).round
when 129600..525599 then locale.t :x_months, count: (distance_in_minutes.to_f / 43200.0).round
else
fyear = from_time.year
fyear = from_time.year
fyear += 1 if from_time.month >= 3
tyear = to_time.year
tyear -= 1 if to_time.month < 3
leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count{|x| Date.leap?(x)}
leap_years = (fyear > tyear) ? 0 : (fyear..tyear).count { |x| Date.leap?(x) }
minute_offset_for_leap_year = leap_years * 1440
# Discount the leap year days when calculating year distance.
# e.g. if there are 20 leap year days between 2 dates having the same day
@@ -55,11 +55,11 @@ module FreedomPatches
remainder = (minutes_with_offset % 525600)
distance_in_years = (minutes_with_offset / 525600)
if remainder < 131400
locale.t(:about_x_years, :count => distance_in_years)
locale.t(:about_x_years, count: distance_in_years)
elsif remainder < 394200
locale.t(:over_x_years, :count => distance_in_years)
locale.t(:over_x_years, count: distance_in_years)
else
locale.t(:almost_x_years, :count => distance_in_years + 1)
locale.t(:almost_x_years, count: distance_in_years + 1)
end
end
end

View File

@@ -54,11 +54,11 @@ end
class Ember::Handlebars::Template
include Discourse::Ember::Handlebars::Helper
def precompile_handlebars(string, input=nil)
def precompile_handlebars(string, input = nil)
"requirejs('discourse-common/lib/raw-handlebars').template(#{Barber::Precompiler.compile(string)});"
end
def compile_handlebars(string, input=nil)
def compile_handlebars(string, input = nil)
"requirejs('discourse-common/lib/raw-handlebars').compile(#{indent(string).inspect});"
end

View File

@@ -4,7 +4,7 @@
# The alternative is a broken website when this happens
class ActiveSupport::SafeBuffer
def concat(value, raise_encoding_err=false)
def concat(value, raise_encoding_err = false)
if !html_safe? || value.html_safe?
super(value)
else
@@ -22,8 +22,8 @@ class ActiveSupport::SafeBuffer
self.force_encoding("UTF-8")
unless valid_encoding?
encode!("utf-16","utf-8",:invalid => :replace)
encode!("utf-8","utf-16")
encode!("utf-16", "utf-8", invalid: :replace)
encode!("utf-8", "utf-16")
end
Rails.logger.warn("Encountered a non UTF-8 string in SafeBuffer - #{self} - #{encoding_diags}")
end
@@ -36,7 +36,7 @@ class ActiveSupport::SafeBuffer
Rails.logger.warn("Attempted to concat a non UTF-8 string in SafeBuffer - #{value} - #{encoding_diags}")
end
concat(value,_raise=true)
concat(value, _raise = true)
end
end

View File

@@ -4,7 +4,7 @@ module FreedomPatches
rval = nil
time = Benchmark.measure do
rval=super
rval = super
end
sql = <<SQL

View File

@@ -1,13 +1,13 @@
class String
# A poor man's scrub, Ruby 2.1 has a much better implementation, but this will do
unless method_defined? :scrub
def scrub(replace_char=nil)
def scrub(replace_char = nil)
str = dup.force_encoding("utf-8")
unless str.valid_encoding?
# work around bust string with a double conversion
str.encode!("utf-16","utf-8",:invalid => :replace)
str.encode!("utf-8","utf-16")
str.encode!("utf-16", "utf-8", invalid: :replace)
str.encode!("utf-8", "utf-16")
end
str

View File

@@ -21,9 +21,9 @@ if Rails.env == "development"
end
if source[0] != ?/
# CODE REMOVED
# source = compute_asset_path(source, options)
source = "/assets/#{source}"
# CODE REMOVED
# source = compute_asset_path(source, options)
source = "/assets/#{source}"
end
relative_url_root = defined?(config.relative_url_root) && config.relative_url_root

View File

@@ -49,10 +49,10 @@ module I18n
end
def ensure_all_loaded!
backend.fallbacks(locale).each {|l| ensure_loaded!(l) }
backend.fallbacks(locale).each { |l| ensure_loaded!(l) }
end
def search(query, opts=nil)
def search(query, opts = nil)
locale = opts[:locale] || config.locale
load_locale(locale) unless @loaded_locales.include?(locale)
@@ -167,7 +167,7 @@ module I18n
alias_method :t, :translate
def exists?(key, locale=nil)
def exists?(key, locale = nil)
locale ||= config.locale
load_locale(locale) unless @loaded_locales.include?(locale)
exists_no_cache?(key, locale)

View File

@@ -23,7 +23,7 @@ class Gaps
end
def find_gaps
return if @subset.nil? or @original.nil?
return if @subset.nil? || @original.nil?
i = j = 0
gaps = {}
@@ -48,7 +48,7 @@ class Gaps
break if (i == @subset.size) || (j == @original.size)
end
@after[@subset[i-1]] = @original[j..-1] if j < @original.size
@after[@subset[i - 1]] = @original[j..-1] if j < @original.size
end
end

View File

@@ -34,7 +34,7 @@ class Guardian
attr_accessor :can_see_emails
def initialize(user=nil)
def initialize(user = nil)
@user = user.presence || AnonymousUser.new
end
@@ -91,7 +91,7 @@ class Guardian
end
end
def can_create?(klass, parent=nil)
def can_create?(klass, parent = nil)
return false unless authenticated? && klass
# If no parent is provided, we look for a can_create_klass?
@@ -155,8 +155,6 @@ class Guardian
true
end
# Can we impersonate this user?
def can_impersonate?(target)
target &&
@@ -233,7 +231,7 @@ class Guardian
is_me?(user)
end
def can_invite_to_forum?(groups=nil)
def can_invite_to_forum?(groups = nil)
authenticated? &&
(SiteSetting.max_invites_per_day.to_i > 0 || is_staff?) &&
!SiteSetting.enable_sso &&
@@ -242,16 +240,16 @@ class Guardian
(!SiteSetting.must_approve_users? && @user.has_trust_level?(TrustLevel[2])) ||
is_staff?
) &&
(groups.blank? || is_admin?)
(groups.blank? || is_admin? || groups.all? { |g| can_edit_group?(g) })
end
def can_invite_to?(object, group_ids=nil)
def can_invite_to?(object, groups = nil)
return false unless authenticated?
return true if is_admin?
return false unless SiteSetting.enable_private_messages?
return false if (SiteSetting.max_invites_per_day.to_i == 0 && !is_staff?)
return false unless can_see?(object)
return false if group_ids.present?
return false if groups.present?
if object.is_a?(Topic) && object.category
if object.category.groups.any?
@@ -322,7 +320,6 @@ class Guardian
end
end
private
def is_my_own?(obj)

View File

@@ -2,7 +2,7 @@
module CategoryGuardian
# Creating Method
def can_create_category?(parent=nil)
def can_create_category?(parent = nil)
is_admin? ||
(
SiteSetting.allow_moderators_to_create_categories &&
@@ -34,10 +34,10 @@ module CategoryGuardian
if category.topic_count != 0
oldest_topic = category.topics.where.not(id: category.topic_id).order('created_at ASC').limit(1).first
if oldest_topic
return I18n.t('category.cannot_delete.topic_exists', {count: category.topic_count, topic_link: "<a href=\"#{oldest_topic.url}\">#{oldest_topic.title}</a>"})
return I18n.t('category.cannot_delete.topic_exists', count: category.topic_count, topic_link: "<a href=\"#{oldest_topic.url}\">#{oldest_topic.title}</a>")
else
# This is a weird case, probably indicating a bug.
return I18n.t('category.cannot_delete.topic_exists_no_oldest', {count: category.topic_count})
return I18n.t('category.cannot_delete.topic_exists_no_oldest', count: category.topic_count)
end
end

View File

@@ -3,7 +3,7 @@ module PostGuardian
# Can the user act on the post in a particular way.
# taken_actions = the list of actions the user has already taken
def post_can_act?(post, action_key, opts={})
def post_can_act?(post, action_key, opts = {})
return false unless can_see_post?(post)
@@ -85,7 +85,7 @@ module PostGuardian
(!SpamRule::AutoBlock.block?(@user) || (!!parent.try(:private_message?) && parent.allowed_users.include?(@user))) && (
!parent ||
!parent.category ||
Category.post_create_allowed(self).where(:id => parent.category.id).count == 1
Category.post_create_allowed(self).where(id: parent.category.id).count == 1
)
end
@@ -186,8 +186,8 @@ module PostGuardian
can_see_post?(post)
end
def can_vote?(post, opts={})
post_can_act?(post,:vote, opts)
def can_vote?(post, opts = {})
post_can_act?(post, :vote, opts)
end
def can_change_post_owner?

View File

@@ -76,7 +76,7 @@ module TopicGuardian
is_staff?
end
def can_see_topic?(topic, hide_deleted=true)
def can_see_topic?(topic, hide_deleted = true)
return false unless topic
return true if is_admin?
return false if hide_deleted && topic.deleted_at && !can_see_deleted_topics?
@@ -107,6 +107,6 @@ module TopicGuardian
def can_edit_featured_link?(category_id)
return false unless SiteSetting.topic_featured_link_enabled
Category.where(id: category_id||SiteSetting.uncategorized_category_id, topic_featured_link_allowed: true).exists?
Category.where(id: category_id || SiteSetting.uncategorized_category_id, topic_featured_link_allowed: true).exists?
end
end

View File

@@ -51,7 +51,7 @@ class HtmlNormalize
Oga::XML::Text === node || !BLOCK.include?(node.name.downcase)
end
def dump_node(node, indent=0, buffer)
def dump_node(node, indent = 0, buffer)
if Oga::XML::Text === node
if node.parent&.name
@@ -70,7 +70,7 @@ class HtmlNormalize
attrs = node&.attributes
if (attrs && attrs.length > 0)
attrs.sort!{|x,y| x.name <=> y.name}
attrs.sort! { |x, y| x.name <=> y.name }
attrs.each do |a|
buffer << " "
buffer << a.name
@@ -94,20 +94,20 @@ class HtmlNormalize
children&.each do |child|
if block && inline?(child)
inline_buffer ||= String.new
dump_node(child, indent+1, inline_buffer)
dump_node(child, indent + 1, inline_buffer)
else
if inline_buffer
buffer << " " * (indent+1) * 2
buffer << " " * (indent + 1) * 2
buffer << inline_buffer.strip
inline_buffer = nil
else
dump_node(child, indent+1, buffer)
dump_node(child, indent + 1, buffer)
end
end
end
if inline_buffer
buffer << " " * (indent+1) * 2
buffer << " " * (indent + 1) * 2
buffer << inline_buffer.strip
inline_buffer = nil
end
@@ -146,5 +146,4 @@ class HtmlNormalize
nodes[start...finish]
end
end

View File

@@ -12,7 +12,7 @@ class HtmlPrettify < String
new(html).to_html
end
# Create a new RubyPants instance with the text in +string+.
# Create a new RubyPants instance with the text in +string+.
#
# Allowed elements in the options array:
#
@@ -50,7 +50,7 @@ class HtmlPrettify < String
# <tt>:ellipsis</tt> :: <tt>&#8230;</tt>
# <tt>:html_quote</tt> :: <tt>&quot; </tt>
#
def initialize(string, options=[2], entities = {})
def initialize(string, options = [2], entities = {})
super string
@options = [*options]
@@ -173,7 +173,6 @@ class HtmlPrettify < String
protected
# The string, with each instance of "<tt>--</tt>" translated to an
# em-dash HTML entity.
#
@@ -319,14 +318,14 @@ class HtmlPrettify < String
new_str = str.dup
{
:en_dash => '-',
:em_dash => '--',
:single_left_quote => "'",
:single_right_quote => "'",
:double_left_quote => '"',
:double_right_quote => '"',
:ellipsis => '...'
}.each do |k,v|
en_dash: '-',
em_dash: '--',
single_left_quote: "'",
single_right_quote: "'",
double_left_quote: '"',
double_right_quote: '"',
ellipsis: '...'
}.each do |k, v|
new_str.gsub!(/#{entity(k)}/, v)
end

View File

@@ -3,24 +3,23 @@ require "nokogiri"
class HtmlToMarkdown
class Block < Struct.new(:name, :head, :body, :opened, :markdown)
def initialize(name, head="", body="", opened=false, markdown=""); super; end
def initialize(name, head = "", body = "", opened = false, markdown = ""); super; end
end
def initialize(html, opts={})
def initialize(html, opts = {})
@opts = opts || {}
@doc = fix_span_elements(Nokogiri::HTML(html))
remove_whitespaces!
end
# If a `<div>` is within a `<span>` that's invalid, so let's hoist the `<div>` up
def fix_span_elements(node)
if node.name == 'span' && node.at('div')
node.swap(node.children)
end
node.children.each {|c| fix_span_elements(c)}
node.children.each { |c| fix_span_elements(c) }
node
end

View File

@@ -51,7 +51,7 @@ module I18n
protected
def find_results(regexp, results, translations, path=nil)
def find_results(regexp, results, translations, path = nil)
return results if translations.blank?
translations.each do |k_sym, v|

View File

@@ -4,10 +4,10 @@
require 'htmlentities'
module Import; end
module Import::Normalize
def self.normalize_code_blocks(code, lang=nil)
def self.normalize_code_blocks(code, lang = nil)
coder = HTMLEntities.new
code.gsub(/<pre>\s*<code>\n?(.*?)\n?<\/code>\s*<\/pre>/m) {
"\n```#{lang}\n#{coder.decode($1)}\n```\n"
"\n```#{lang}\n#{coder.decode($1)}\n```\n"
}
end
end

View File

@@ -22,15 +22,14 @@ module ImportExport
self
end
CATEGORY_ATTRS = [:id, :name, :color, :created_at, :user_id, :slug, :description, :text_color,
:auto_close_hours, :auto_close_based_on_last_post,
:topic_template, :suppress_from_homepage, :all_topics_wiki, :permissions_params]
def export_categories
@export_data[:category] = CATEGORY_ATTRS.inject({}) { |h,a| h[a] = @category.send(a); h }
@export_data[:category] = CATEGORY_ATTRS.inject({}) { |h, a| h[a] = @category.send(a); h }
@subcategories.find_each do |subcat|
@export_data[:subcategories] << CATEGORY_ATTRS.inject({}) { |h,a| h[a] = subcat.send(a); h }
@export_data[:subcategories] << CATEGORY_ATTRS.inject({}) { |h, a| h[a] = subcat.send(a); h }
end
# export groups that are mentioned in category permissions
@@ -49,7 +48,6 @@ module ImportExport
self
end
GROUP_ATTRS = [ :id, :name, :created_at, :alias_level, :visible,
:automatic_membership_email_domains, :automatic_membership_retroactive,
:primary_group, :title, :grant_trust_level, :incoming_email]
@@ -57,7 +55,7 @@ module ImportExport
def export_groups(group_names)
group_names.each do |name|
group = Group.find_by_name(name)
group_attrs = GROUP_ATTRS.inject({}) { |h,a| h[a] = group.send(a); h }
group_attrs = GROUP_ATTRS.inject({}) { |h, a| h[a] = group.send(a); h }
group_attrs[:user_ids] = group.users.pluck(:id)
@export_data[:groups] << group_attrs
end
@@ -75,7 +73,7 @@ module ImportExport
self
end
def save_to_file(filename=nil)
def save_to_file(filename = nil)
require 'json'
output_basename = filename || File.join("category-export-#{Time.now.strftime("%Y-%m-%d-%H%M%S")}.json")
File.open(output_basename, "w:UTF-8") do |f|

View File

@@ -28,7 +28,7 @@ module ImportExport
external_id = g.delete(:id)
new_group = Group.find_by_name(g[:name]) || Group.create!(g)
user_ids.each do |external_user_id|
new_group.add( User.find(@topic_importer.new_user_id(external_user_id)) ) rescue ActiveRecord::RecordNotUnique
new_group.add(User.find(@topic_importer.new_user_id(external_user_id))) rescue ActiveRecord::RecordNotUnique
end
end
end
@@ -47,7 +47,7 @@ module ImportExport
parent = Category.new(@export_data[:category])
parent.user_id = @topic_importer.new_user_id(@export_data[:category][:user_id]) # imported user's new id
parent.custom_fields["import_id"] = id
parent.permissions = permissions.present? ? permissions : {"everyone" => CategoryGroup.permission_types[:full]}
parent.permissions = permissions.present? ? permissions : { "everyone" => CategoryGroup.permission_types[:full] }
parent.save!
set_category_description(parent, @export_data[:category][:description])
end
@@ -62,7 +62,7 @@ module ImportExport
subcategory.parent_category_id = parent.id
subcategory.user_id = @topic_importer.new_user_id(cat_attrs[:user_id])
subcategory.custom_fields["import_id"] = id
subcategory.permissions = permissions.present? ? permissions : {"everyone" => CategoryGroup.permission_types[:full]}
subcategory.permissions = permissions.present? ? permissions : { "everyone" => CategoryGroup.permission_types[:full] }
subcategory.save!
set_category_description(subcategory, cat_attrs[:description])
end

View File

@@ -6,7 +6,7 @@ require "json"
module ImportExport
def self.export_category(category_id, filename=nil)
def self.export_category(category_id, filename = nil)
ImportExport::CategoryExporter.new(category_id).perform.save_to_file(filename)
end

View File

@@ -20,7 +20,6 @@ module ImportExport
self
end
USER_ATTRS = [:id, :email, :username, :name, :created_at, :trust_level, :active, :last_emailed_at]
def export_users
@@ -33,11 +32,9 @@ module ImportExport
u = post.user
unless @exported_user_ids.include?(u.id)
x = USER_ATTRS.inject({}) { |h, a| h[a] = u.send(a); h; }
@export_data[:users] << x.merge({
bio_raw: u.user_profile.bio_raw,
website: u.user_profile.website,
location: u.user_profile.location
})
@export_data[:users] << x.merge(bio_raw: u.user_profile.bio_raw,
website: u.user_profile.website,
location: u.user_profile.location)
@exported_user_ids << u.id
end
end
@@ -46,7 +43,6 @@ module ImportExport
self
end
def export_topics
@topic_ids.each do |topic_id|
t = Topic.find(topic_id)
@@ -56,7 +52,6 @@ module ImportExport
puts ""
end
TOPIC_ATTRS = [:id, :title, :created_at, :views, :category_id, :closed, :archived, :archetype]
POST_ATTRS = [:id, :user_id, :post_number, :raw, :created_at, :reply_to_post_number,
:hidden, :hidden_reason_id, :wiki]
@@ -81,8 +76,7 @@ module ImportExport
self
end
def save_to_file(filename=nil)
def save_to_file(filename = nil)
require 'json'
output_basename = filename || File.join("topic-export-#{Time.now.strftime("%Y-%m-%d-%H%M%S")}.json")
File.open(output_basename, "w:UTF-8") do |f|

View File

@@ -18,7 +18,7 @@ module ImportExport
def import_users
@export_data[:users].each do |u|
existing = User.where(email: u[:email]).first
existing = User.with_email(email: u[:email]).first
if existing
if existing.custom_fields["import_id"] != u[:id]
existing.custom_fields["import_id"] = u[:id]
@@ -36,14 +36,14 @@ module ImportExport
puts ""
print t[:title]
first_post_attrs = t[:posts].first.merge( t.slice(*(TopicExporter::TOPIC_ATTRS - [:id, :category_id])) )
first_post_attrs = t[:posts].first.merge(t.slice(*(TopicExporter::TOPIC_ATTRS - [:id, :category_id])))
first_post_attrs[:user_id] = new_user_id(first_post_attrs[:user_id])
first_post_attrs[:category] = new_category_id(t[:category_id])
first_post = PostCustomField.where(name: "import_id", value: first_post_attrs[:id]).first.try(:post)
unless first_post
first_post = create_post( first_post_attrs, first_post_attrs[:id] )
first_post = create_post(first_post_attrs, first_post_attrs[:id])
end
topic_id = first_post.topic_id
@@ -53,10 +53,8 @@ module ImportExport
print "."
existing = PostCustomField.where(name: "import_id", value: post_data[:id]).first.try(:post)
unless existing
create_post(post_data.merge({
topic_id: topic_id,
user_id: new_user_id(post_data[:user_id])
}), post_data[:id]) # see ImportScripts::Base
create_post(post_data.merge(topic_id: topic_id,
user_id: new_user_id(post_data[:user_id])), post_data[:id]) # see ImportScripts::Base
end
end
end

72
lib/inline_oneboxer.rb Normal file
View File

@@ -0,0 +1,72 @@
require_dependency 'retrieve_title'
class InlineOneboxer
def initialize(urls, opts = nil)
@urls = urls
@opts = opts || {}
end
def process
@urls.map { |url| InlineOneboxer.lookup(url, @opts) }.compact
end
def self.purge(url)
Rails.cache.delete(cache_key(url))
end
def self.cache_lookup(url)
Rails.cache.read(cache_key(url))
end
def self.lookup(url, opts = nil)
opts ||= {}
unless opts[:skip_cache]
cached = cache_lookup(url)
return cached if cached.present?
end
if route = Discourse.route_for(url)
if route[:controller] == "topics" &&
route[:action] == "show" &&
topic = (Topic.where(id: route[:topic_id].to_i).first rescue nil)
return onebox_for(url, topic.title, opts) if Guardian.new.can_see?(topic)
end
end
if whitelist = SiteSetting.inline_onebox_domains_whitelist
uri = URI(url) rescue nil
domains = whitelist.split('|')
if uri.present? &&
uri.hostname.present? &&
domains.include?(uri.hostname) &&
title = RetrieveTitle.crawl(url)
return onebox_for(url, title, opts)
end
end
nil
end
private
def self.onebox_for(url, title, opts)
onebox = {
url: url,
title: Emoji.gsub_emoji_to_unicode(title)
}
unless opts[:skip_cache]
Rails.cache.write(cache_key(url), onebox, expires_in: 1.day)
end
onebox
end
def self.cache_key(url)
"inline_onebox:#{url}"
end
end

View File

@@ -16,7 +16,7 @@ module JsLocaleHelper
end
end
def self.load_translations(locale, opts=nil)
def self.load_translations(locale, opts = nil)
opts ||= {}
@loaded_translations = nil if opts[:force]
@@ -149,7 +149,7 @@ module JsLocaleHelper
end
def self.generate_message_format(message_formats, locale_str)
formats = message_formats.map { |k,v| k.inspect << " : " << compile_message_format(locale_str, v) }.join(", ")
formats = message_formats.map { |k, v| k.inspect << " : " << compile_message_format(locale_str, v) }.join(", ")
filename = "#{Rails.root}/lib/javascripts/locale/#{locale_str}.js"
filename = "#{Rails.root}/lib/javascripts/locale/en.js" unless File.exists?(filename)
@@ -161,6 +161,7 @@ module JsLocaleHelper
end
def self.reset_context
@ctx&.dispose
@ctx = nil
end

View File

@@ -1,6 +1,6 @@
module JsonError
def create_errors_json(obj, type=nil)
def create_errors_json(obj, type = nil)
errors = create_errors_array obj
errors[:error_type] = type if type
errors

View File

@@ -89,7 +89,7 @@ class LetterAvatar
end
def to_rgb(color)
r,g,b = color
r, g, b = color
"rgb(#{r},#{g},#{b})"
end
@@ -108,7 +108,7 @@ class LetterAvatar
skip = File.basename(cache_path)
parent_path = File.dirname(cache_path)
Dir.entries(parent_path).each do |path|
unless ['.','..'].include?(path) || path == skip
unless ['.', '..'].include?(path) || path == skip
FileUtils.rm_rf(parent_path + "/" + path)
end
end
@@ -121,220 +121,220 @@ class LetterAvatar
# - H: 0 - 360
# - C: 0 - 2
# - L: 0.75 - 1.5
COLORS = [[198,125,40],
[61,155,243],
[74,243,75],
[238,89,166],
[52,240,224],
[177,156,155],
[240,120,145],
[111,154,78],
[237,179,245],
[237,101,95],
[89,239,155],
[43,254,70],
[163,212,245],
[65,152,142],
[165,135,246],
[181,166,38],
[187,229,206],
[77,164,25],
[179,246,101],
[234,93,37],
[225,155,115],
[142,140,188],
[223,120,140],
[249,174,27],
[244,117,225],
[137,141,102],
[75,191,146],
[188,239,142],
[164,199,145],
[173,120,149],
[59,195,89],
[222,198,220],
[68,145,187],
[236,204,179],
[159,195,72],
[188,121,189],
[166,160,85],
[181,233,37],
[236,177,85],
[121,147,160],
[234,218,110],
[241,157,191],
[62,200,234],
[133,243,34],
[88,149,110],
[59,228,248],
[183,119,118],
[251,195,45],
[113,196,122],
[197,115,70],
[80,175,187],
[103,231,238],
[240,72,133],
[228,149,241],
[180,188,159],
[172,132,85],
[180,135,251],
[236,194,58],
[217,176,109],
[88,244,199],
[186,157,239],
[113,230,96],
[206,115,165],
[244,178,163],
[230,139,26],
[241,125,89],
[83,160,66],
[107,190,166],
[197,161,210],
[198,203,245],
[238,117,19],
[228,119,116],
[131,156,41],
[145,178,168],
[139,170,220],
[233,95,125],
[87,178,230],
[157,200,119],
[237,140,76],
[229,185,186],
[144,206,212],
[236,209,158],
[185,189,79],
[34,208,66],
[84,238,129],
[133,140,134],
[67,157,94],
[168,179,25],
[140,145,240],
[151,241,125],
[67,162,107],
[200,156,21],
[169,173,189],
[226,116,189],
[133,231,191],
[194,161,63],
[241,77,99],
[241,217,53],
[123,204,105],
[210,201,119],
[229,108,155],
[240,91,72],
[187,115,210],
[240,163,100],
[178,217,57],
[179,135,116],
[204,211,24],
[186,135,57],
[223,176,135],
[204,148,151],
[116,223,50],
[95,195,46],
[123,160,236],
[181,172,131],
[142,220,202],
[240,140,112],
[172,145,164],
[228,124,45],
[135,151,243],
[42,205,125],
[192,233,116],
[119,170,114],
[158,138,26],
[73,190,183],
[185,229,243],
[227,107,55],
[196,205,202],
[132,143,60],
[233,192,237],
[62,150,220],
[205,201,141],
[106,140,190],
[161,131,205],
[135,134,158],
[198,139,81],
[115,171,32],
[101,181,67],
[149,137,119],
[37,142,183],
[183,130,175],
[168,125,133],
[124,142,87],
[236,156,171],
[232,194,91],
[219,200,69],
[144,219,34],
[219,95,187],
[145,154,217],
[165,185,100],
[127,238,163],
[224,178,198],
[119,153,120],
[124,212,92],
[172,161,105],
[231,155,135],
[157,132,101],
[122,185,146],
[53,166,51],
[70,163,90],
[150,190,213],
[210,107,60],
[166,152,185],
[159,194,159],
[39,141,222],
[202,176,161],
[95,140,229],
[168,142,87],
[93,170,203],
[159,142,54],
[14,168,39],
[94,150,149],
[187,206,136],
[157,224,166],
[235,158,208],
[109,232,216],
[141,201,87],
[208,124,118],
[142,125,214],
[19,237,174],
[72,219,41],
[234,102,111],
[168,142,79],
[188,135,35],
[95,155,143],
[148,173,116],
[223,112,95],
[228,128,236],
[206,114,54],
[195,119,88],
[235,140,94],
[235,202,125],
[233,155,153],
[214,214,238],
[246,200,35],
[151,125,171],
[132,145,172],
[131,142,118],
[199,126,150],
[61,162,123],
[58,176,151],
[215,141,69],
[225,154,220],
[220,77,167],
[233,161,64],
[130,221,137],
[81,191,129],
[169,162,140],
[174,177,222],
[236,174,47],
[233,188,180],
[69,222,172],
[71,232,93],
[118,211,238],
[157,224,83],
[218,105,73],
[126,169,36]]
COLORS = [[198, 125, 40],
[61, 155, 243],
[74, 243, 75],
[238, 89, 166],
[52, 240, 224],
[177, 156, 155],
[240, 120, 145],
[111, 154, 78],
[237, 179, 245],
[237, 101, 95],
[89, 239, 155],
[43, 254, 70],
[163, 212, 245],
[65, 152, 142],
[165, 135, 246],
[181, 166, 38],
[187, 229, 206],
[77, 164, 25],
[179, 246, 101],
[234, 93, 37],
[225, 155, 115],
[142, 140, 188],
[223, 120, 140],
[249, 174, 27],
[244, 117, 225],
[137, 141, 102],
[75, 191, 146],
[188, 239, 142],
[164, 199, 145],
[173, 120, 149],
[59, 195, 89],
[222, 198, 220],
[68, 145, 187],
[236, 204, 179],
[159, 195, 72],
[188, 121, 189],
[166, 160, 85],
[181, 233, 37],
[236, 177, 85],
[121, 147, 160],
[234, 218, 110],
[241, 157, 191],
[62, 200, 234],
[133, 243, 34],
[88, 149, 110],
[59, 228, 248],
[183, 119, 118],
[251, 195, 45],
[113, 196, 122],
[197, 115, 70],
[80, 175, 187],
[103, 231, 238],
[240, 72, 133],
[228, 149, 241],
[180, 188, 159],
[172, 132, 85],
[180, 135, 251],
[236, 194, 58],
[217, 176, 109],
[88, 244, 199],
[186, 157, 239],
[113, 230, 96],
[206, 115, 165],
[244, 178, 163],
[230, 139, 26],
[241, 125, 89],
[83, 160, 66],
[107, 190, 166],
[197, 161, 210],
[198, 203, 245],
[238, 117, 19],
[228, 119, 116],
[131, 156, 41],
[145, 178, 168],
[139, 170, 220],
[233, 95, 125],
[87, 178, 230],
[157, 200, 119],
[237, 140, 76],
[229, 185, 186],
[144, 206, 212],
[236, 209, 158],
[185, 189, 79],
[34, 208, 66],
[84, 238, 129],
[133, 140, 134],
[67, 157, 94],
[168, 179, 25],
[140, 145, 240],
[151, 241, 125],
[67, 162, 107],
[200, 156, 21],
[169, 173, 189],
[226, 116, 189],
[133, 231, 191],
[194, 161, 63],
[241, 77, 99],
[241, 217, 53],
[123, 204, 105],
[210, 201, 119],
[229, 108, 155],
[240, 91, 72],
[187, 115, 210],
[240, 163, 100],
[178, 217, 57],
[179, 135, 116],
[204, 211, 24],
[186, 135, 57],
[223, 176, 135],
[204, 148, 151],
[116, 223, 50],
[95, 195, 46],
[123, 160, 236],
[181, 172, 131],
[142, 220, 202],
[240, 140, 112],
[172, 145, 164],
[228, 124, 45],
[135, 151, 243],
[42, 205, 125],
[192, 233, 116],
[119, 170, 114],
[158, 138, 26],
[73, 190, 183],
[185, 229, 243],
[227, 107, 55],
[196, 205, 202],
[132, 143, 60],
[233, 192, 237],
[62, 150, 220],
[205, 201, 141],
[106, 140, 190],
[161, 131, 205],
[135, 134, 158],
[198, 139, 81],
[115, 171, 32],
[101, 181, 67],
[149, 137, 119],
[37, 142, 183],
[183, 130, 175],
[168, 125, 133],
[124, 142, 87],
[236, 156, 171],
[232, 194, 91],
[219, 200, 69],
[144, 219, 34],
[219, 95, 187],
[145, 154, 217],
[165, 185, 100],
[127, 238, 163],
[224, 178, 198],
[119, 153, 120],
[124, 212, 92],
[172, 161, 105],
[231, 155, 135],
[157, 132, 101],
[122, 185, 146],
[53, 166, 51],
[70, 163, 90],
[150, 190, 213],
[210, 107, 60],
[166, 152, 185],
[159, 194, 159],
[39, 141, 222],
[202, 176, 161],
[95, 140, 229],
[168, 142, 87],
[93, 170, 203],
[159, 142, 54],
[14, 168, 39],
[94, 150, 149],
[187, 206, 136],
[157, 224, 166],
[235, 158, 208],
[109, 232, 216],
[141, 201, 87],
[208, 124, 118],
[142, 125, 214],
[19, 237, 174],
[72, 219, 41],
[234, 102, 111],
[168, 142, 79],
[188, 135, 35],
[95, 155, 143],
[148, 173, 116],
[223, 112, 95],
[228, 128, 236],
[206, 114, 54],
[195, 119, 88],
[235, 140, 94],
[235, 202, 125],
[233, 155, 153],
[214, 214, 238],
[246, 200, 35],
[151, 125, 171],
[132, 145, 172],
[131, 142, 118],
[199, 126, 150],
[61, 162, 123],
[58, 176, 151],
[215, 141, 69],
[225, 154, 220],
[220, 77, 167],
[233, 161, 64],
[130, 221, 137],
[81, 191, 129],
[169, 162, 140],
[174, 177, 222],
[236, 174, 47],
[233, 188, 180],
[69, 222, 172],
[71, 232, 93],
[118, 211, 238],
[157, 224, 83],
[218, 105, 73],
[126, 169, 36]]
end

View File

@@ -17,7 +17,7 @@ class MarkdownLinker
def references
result = ""
(@rendered..@index-1).each do |i|
(@rendered..@index - 1).each do |i|
result << "[#{i}]: #{@markdown_links[i]}\n"
end
@rendered = @index

View File

@@ -4,7 +4,7 @@ module MemoryDiagnostics
File.exists?(snapshot_filename)
end
def self.compare(from=nil, to=nil)
def self.compare(from = nil, to = nil)
from ||= snapshot_filename
if !to
@@ -38,7 +38,7 @@ module MemoryDiagnostics
end
end
report << summary.sort{|a,b| b[1] <=> a[1]}[0..50].map{|k,v|
report << summary.sort { |a, b| b[1] <=> a[1] }[0..50].map { |k, v|
"#{k}: #{v}"
}.join("\n")
@@ -59,9 +59,9 @@ module MemoryDiagnostics
"#{snapshot_path}/#{Process.pid}.snapshot"
end
def self.snapshot_current_process(filename=nil)
def self.snapshot_current_process(filename = nil)
filename ||= snapshot_filename
pid=fork do
pid = fork do
snapshot(filename)
end
@@ -86,7 +86,7 @@ module MemoryDiagnostics
IO.binwrite(filename, Marshal::dump(object_ids))
end
def self.memory_report(opts={})
def self.memory_report(opts = {})
begin
# ruby 2.1
GC.start(full_mark: true)
@@ -94,7 +94,6 @@ module MemoryDiagnostics
GC.start
end
classes = {}
large_objects = []
@@ -113,11 +112,11 @@ module MemoryDiagnostics
classes[:unknown] += 1
end
end
classes = classes.sort{|a,b| b[1] <=> a[1]}[0..40].map{|klass, count| "#{klass}: #{count}"}
classes = classes.sort { |a, b| b[1] <=> a[1] }[0..40].map { |klass, count| "#{klass}: #{count}" }
classes << "\nLarge Objects (#{large_objects.length} larger than 200 bytes total size #{large_objects.map{|x,_| x}.sum}):\n"
classes << "\nLarge Objects (#{large_objects.length} larger than 200 bytes total size #{large_objects.map { |x, _| x }.sum}):\n"
classes += large_objects.sort{|a,b| b[0] <=> a[0]}[0..800].map do |size,object|
classes += large_objects.sort { |a, b| b[0] <=> a[0] }[0..800].map do |size, object|
rval = "#{object.class}: size #{size}"
rval << " " << object.to_s[0..500].gsub("\n", "") if (String === object) || (Regexp === object)
rval << "\n"
@@ -125,10 +124,8 @@ module MemoryDiagnostics
end
end
stats = GC.stat.map{|k,v| "#{k}: #{v}"}
counts = ObjectSpace.count_objects.sort{|a,b| b[1] <=> a[1] }.map{|k,v| "#{k}: #{v}"}
stats = GC.stat.map { |k, v| "#{k}: #{v}" }
counts = ObjectSpace.count_objects.sort { |a, b| b[1] <=> a[1] }.map { |k, v| "#{k}: #{v}" }
<<TEXT
#{`hostname`.strip} pid:#{Process.pid} #{`cat /proc/#{Process.pid}/cmdline`.strip.gsub(/[^a-z1-9\/]/i, ' ')}
@@ -149,7 +146,6 @@ TEXT
end
def self.full_gc
# gc start may not collect everything
GC.start while new_count = decreased_count(new_count)

View File

@@ -11,7 +11,7 @@ class MessageBusDiags
end
def self.establish_peer_names
MessageBus.publish "/server-name", {channel: "/server-name-reply/#{my_id}"}
MessageBus.publish "/server-name", channel: "/server-name-reply/#{my_id}"
end
def self.seen_hosts

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