mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
Merge branch 'master' into fix_limited_search_results
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -2,7 +2,7 @@ require_dependency 'current_user'
|
||||
|
||||
class AdminConstraint
|
||||
|
||||
def initialize(options={})
|
||||
def initialize(options = {})
|
||||
@require_master = options[:require_master]
|
||||
end
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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})
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
(
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
''
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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?)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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\/[^"]+)"([^>]*)>/, '')
|
||||
@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\/[^"]+)"([^>]*)>/, '')
|
||||
|
||||
@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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
6047
lib/emoji/groups.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -13,4 +13,3 @@ module Ember
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ module FreedomPatches
|
||||
rval = nil
|
||||
|
||||
time = Benchmark.measure do
|
||||
rval=super
|
||||
rval = super
|
||||
end
|
||||
|
||||
sql = <<SQL
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>…</tt>
|
||||
# <tt>:html_quote</tt> :: <tt>" </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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
72
lib/inline_oneboxer.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user